diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml
new file mode 100644
index 000000000..a8497c94d
--- /dev/null
+++ b/.github/workflows/e2e.yml
@@ -0,0 +1,105 @@
+# Copyright © 2023 Cask Data, Inc.
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+# http://www.apache.org/licenses/LICENSE-2.0
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+# This workflow will build a Java project with Maven
+# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
+# Note: Any changes to this workflow would be used only after merging into develop
+name: Build e2e tests
+
+on:
+ push:
+ branches: [ develop ]
+ pull_request:
+ branches: [ develop ]
+ types: [ opened, synchronize, reopened, labeled ]
+ workflow_dispatch:
+
+jobs:
+ build:
+ runs-on: k8s-runner-e2e
+ # We allow builds:
+ # 1) When triggered manually
+ # 2) When it's a merge into a branch
+ # 3) For PRs that are labeled as build and
+ # - It's a code change
+ # - A build label was just added
+ # A bit complex, but prevents builds when other labels are manipulated
+ if: >
+ github.event_name == 'workflow_dispatch'
+ || github.event_name == 'push'
+ || (contains(github.event.pull_request.labels.*.name, 'build')
+ && (github.event.action != 'labeled' || github.event.label.name == 'build')
+ )
+ strategy:
+ matrix:
+ module: [wrangler-transform]
+ fail-fast: false
+
+ steps:
+ # Pinned 1.0.0 version
+ - uses: actions/checkout@v3
+ with:
+ path: plugin
+ submodules: 'recursive'
+ ref: ${{ github.event.workflow_run.head_sha }}
+
+ - uses: dorny/paths-filter@b2feaf19c27470162a626bd6fa8438ae5b263721
+ if: github.event_name != 'workflow_dispatch' && github.event_name != 'push'
+ id: filter
+ with:
+ working-directory: plugin
+ filters: |
+ e2e-test:
+ - '${{ matrix.module }}/**/e2e-test/**'
+
+ - name: Checkout e2e test repo
+ uses: actions/checkout@v3
+ with:
+ repository: cdapio/cdap-e2e-tests
+ path: e2e
+
+ - name: Cache
+ uses: actions/cache@v3
+ with:
+ path: ~/.m2/repository
+ key: ${{ runner.os }}-maven-${{ github.workflow }}-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-${{ github.workflow }}
+
+ - name: Run required e2e tests
+ if: github.event_name != 'workflow_dispatch' && github.event_name != 'push' && steps.filter.outputs.e2e-test == 'false'
+ run: python3 e2e/src/main/scripts/run_e2e_test.py --module ${{ matrix.module }} --testRunner TestRunnerRequired.java
+
+ - name: Run all e2e tests
+ if: github.event_name == 'workflow_dispatch' || github.event_name == 'push' || steps.filter.outputs.e2e-test == 'true'
+ run: python3 e2e/src/main/scripts/run_e2e_test.py --module ${{ matrix.module }}
+
+ - name: Upload report
+ uses: actions/upload-artifact@v3
+ if: always()
+ with:
+ name: Cucumber report - ${{ matrix.module }}
+ path: ./**/target/cucumber-reports
+
+ - name: Upload debug files
+ uses: actions/upload-artifact@v3
+ if: always()
+ with:
+ name: Debug files - ${{ matrix.module }}
+ path: ./**/target/e2e-debug
+
+ - name: Upload files to GCS
+ uses: google-github-actions/upload-cloud-storage@v0
+ if: always()
+ with:
+ path: ./plugin
+ destination: e2e-tests-cucumber-reports/${{ github.event.repository.name }}/${{ github.ref }}
+ glob: '**/target/cucumber-reports/**'
diff --git a/pom.xml b/pom.xml
index 0907f6871..b43b5c99d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -100,7 +100,7 @@
1.106.0
2.6.2
2.0.0
- 20.0
+ 31.0.1-jre
2.4.0
2.2
2.2.4
@@ -122,6 +122,7 @@
1.11
1.7.15
0.4
+ ${project.basedir}/src/test/java/
@@ -172,6 +173,7 @@
+ ${testSourceLocation}
@@ -186,7 +188,7 @@
org.apache.felix
maven-bundle-plugin
- 3.3.0
+ 3.5.0
true
@@ -397,7 +399,6 @@
releases
-
org.sonatype.plugins
nexus-staging-maven-plugin
@@ -429,6 +430,135 @@
+
+ e2e-tests
+
+ src/e2e-test/java
+ TestRunner.java
+
+
+
+
+ src/e2e-test/resources
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.18.1
+
+ true
+
+
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+ 3.0.0
+
+
+ org.apache.maven.surefire
+ surefire-junit47
+ 3.0.0
+
+
+
+
+ ${TEST_RUNNER}
+
+
+ classes
+ 2
+ 2
+ true
+
+
+
+ ${GOOGLE_APPLICATION_CREDENTIALS}
+
+
+ ${SERVICE_ACCOUNT_TYPE}
+
+
+ ${SERVICE_ACCOUNT_FILE_PATH}
+
+
+ ${SERVICE_ACCOUNT_JSON}
+
+
+
+
+
+
+ integration-test
+ verify
+
+
+
+
+
+
+ net.masterthought
+ maven-cucumber-reporting
+ 5.5.0
+
+
+
+ execution
+ verify
+
+ generate
+
+
+ Cucumber Reports
+ target/cucumber-reports/advanced-reports
+ 1
+ false
+ ${project.build.directory}/cucumber-reports
+
+ **/*.json
+
+ ${project.build.directory}/cucumber-reports
+ true
+
+
+
+
+
+
+
+
+
+ com.google.guava
+ guava
+ ${guava.version}
+
+
+
+
+
+
+ org.slf4j
+ slf4j-api
+ 1.7.15
+
+
+
+ io.cdap.tests.e2e
+ cdap-e2e-framework
+ 0.3.0-SNAPSHOT
+ test
+
+
+
+ ch.qos.logback
+ logback-classic
+ 1.2.8
+ runtime
+
+
+
+
-
diff --git a/wrangler-transform/pom.xml b/wrangler-transform/pom.xml
index c99f8e3d8..b09712c0d 100644
--- a/wrangler-transform/pom.xml
+++ b/wrangler-transform/pom.xml
@@ -215,5 +215,4 @@
-
diff --git a/wrangler-transform/src/e2e-test/features/Wrangler/Runtime.feature b/wrangler-transform/src/e2e-test/features/Wrangler/Runtime.feature
new file mode 100644
index 000000000..15d2c7add
--- /dev/null
+++ b/wrangler-transform/src/e2e-test/features/Wrangler/Runtime.feature
@@ -0,0 +1,43 @@
+# Copyright © 2023 Cask Data, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+@Wrangler
+Feature: Wrangler - Run time scenarios
+
+ @BQ_SOURCE_TEST @BQ_SINK_TEST
+ Scenario: To verify User is able to run a pipeline using wrangler and groupBy directive
+ Given Open Datafusion Project to configure pipeline
+ Then Click on the Plus Green Button to import the pipelines
+ Then Select the file for importing the pipeline for the plugin "Directive_GroupBy"
+ Then Navigate to the properties page of plugin: "BigQueryTable"
+ Then Replace input plugin property: "project" with value: "projectId"
+ Then Replace input plugin property: "dataset" with value: "dataset"
+ Then Replace input plugin property: "table" with value: "bqSourceTable"
+ Then Click on the Get Schema button
+ Then Click on the Validate button
+ Then Close the Plugin Properties page
+ Then Navigate to the properties page of plugin: "BigQuery2"
+ Then Replace input plugin property: "project" with value: "projectId"
+ Then Replace input plugin property: "table" with value: "bqTargetTable"
+ Then Replace input plugin property: "dataset" with value: "dataset"
+ Then Click on the Validate button
+ Then Close the Plugin Properties page
+ Then Rename the pipeline
+ Then Deploy the pipeline
+ Then Run the Pipeline in Runtime
+ Then Wait till pipeline is in running state
+ Then Open and capture logs
+ Then Verify the pipeline status is "Succeeded"
+ Then Close the pipeline logs
+ Then Validate The Data From BQ To BQ With Actual And Expected File for: "ExpectedDirective_GroupBy"
diff --git a/wrangler-transform/src/e2e-test/java/io/cdap/plugin/common/stepsdesign/TestSetupHooks.java b/wrangler-transform/src/e2e-test/java/io/cdap/plugin/common/stepsdesign/TestSetupHooks.java
new file mode 100644
index 000000000..46e18c50d
--- /dev/null
+++ b/wrangler-transform/src/e2e-test/java/io/cdap/plugin/common/stepsdesign/TestSetupHooks.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright © 2023 Cask Data, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package io.cdap.plugin.common.stepsdesign;
+
+import com.google.cloud.bigquery.BigQueryException;
+import com.google.cloud.storage.Blob;
+import com.google.cloud.storage.StorageException;
+import io.cdap.e2e.utils.BigQueryClient;
+import io.cdap.e2e.utils.PluginPropertyUtils;
+import io.cdap.e2e.utils.StorageClient;
+import io.cucumber.java.After;
+import io.cucumber.java.Before;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.junit.Assert;
+import stepsdesign.BeforeActions;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.sql.SQLException;
+import java.util.NoSuchElementException;
+import java.util.UUID;
+
+import static io.cdap.e2e.pages.locators.CdfGCSLocators.filePath;
+
+/**
+ * Setup BQ for Wrangler tests.
+ */
+public class TestSetupHooks {
+
+ @Before(order = 1, value = "@BQ_SINK_TEST")
+ public static void setTempTargetBQTableName() {
+ String bqTargetTableName = "E2E_TARGET_" + UUID.randomUUID().toString().replaceAll("-", "_");
+ PluginPropertyUtils.addPluginProp("bqTargetTable", bqTargetTableName);
+ BeforeActions.scenario.write("BQ Target table name - " + bqTargetTableName);
+ }
+
+ @After(order = 1, value = "@BQ_SINK_TEST")
+ public static void deleteTempTargetBQTable() throws IOException, InterruptedException {
+ String bqTargetTableName = PluginPropertyUtils.pluginProp("bqTargetTable");
+ try {
+ BigQueryClient.dropBqQuery(bqTargetTableName);
+ BeforeActions.scenario.write("BQ Target table - " + bqTargetTableName + " deleted successfully");
+ PluginPropertyUtils.removePluginProp("bqTargetTable");
+ } catch (BigQueryException e) {
+ if (e.getMessage().contains("Not found: Table")) {
+ BeforeActions.scenario.write("BQ Target Table " + bqTargetTableName + " does not exist");
+ } else {
+ Assert.fail(e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Create BigQuery table.
+ */
+ @Before(order = 1, value = "@BQ_SOURCE_TEST")
+ public static void createTempSourceBQTable() throws IOException, InterruptedException {
+ createSourceBQTableWithQueries(PluginPropertyUtils.pluginProp("CreateBQTableQueryFile"),
+ PluginPropertyUtils.pluginProp("InsertBQDataQueryFile"));
+ }
+
+ private static void createSourceBQTableWithQueries(String bqCreateTableQueryFile, String bqInsertDataQueryFile)
+ throws IOException, InterruptedException {
+ String bqSourceTable = "E2E_SOURCE_" + UUID.randomUUID().toString().substring(0, 5).replaceAll("-",
+ "_");
+
+ String createTableQuery = StringUtils.EMPTY;
+ try {
+ createTableQuery = new String(Files.readAllBytes(Paths.get(TestSetupHooks.class.getResource
+ ("/" + bqCreateTableQueryFile).toURI()))
+ , StandardCharsets.UTF_8);
+ createTableQuery = createTableQuery.replace("DATASET", PluginPropertyUtils.pluginProp("dataset"))
+ .replace("TABLE_NAME", bqSourceTable);
+ } catch (Exception e) {
+ BeforeActions.scenario.write("Exception in reading " + bqCreateTableQueryFile + " - " + e.getMessage());
+ Assert.fail("Exception in BigQuery testdata prerequisite setup " +
+ "- error in reading create table query file " + e.getMessage());
+ }
+
+ String insertDataQuery = StringUtils.EMPTY;
+ try {
+ insertDataQuery = new String(Files.readAllBytes(Paths.get(TestSetupHooks.class.getResource
+ ("/" + bqInsertDataQueryFile).toURI()))
+ , StandardCharsets.UTF_8);
+ insertDataQuery = insertDataQuery.replace("DATASET", PluginPropertyUtils.pluginProp("dataset"))
+ .replace("TABLE_NAME", bqSourceTable);
+ } catch (Exception e) {
+ BeforeActions.scenario.write("Exception in reading " + bqInsertDataQueryFile + " - " + e.getMessage());
+ Assert.fail("Exception in BigQuery testdata prerequisite setup " +
+ "- error in reading insert data query file " + e.getMessage());
+ }
+ BigQueryClient.getSoleQueryResult(createTableQuery);
+ try {
+ BigQueryClient.getSoleQueryResult(insertDataQuery);
+ } catch (NoSuchElementException e) {
+ // Insert query does not return any record.
+ // Iterator on TableResult values in getSoleQueryResult method throws NoSuchElementException
+ }
+ PluginPropertyUtils.addPluginProp("bqSourceTable", bqSourceTable);
+ BeforeActions.scenario.write("BQ Source Table " + bqSourceTable + " created successfully");
+ }
+}
diff --git a/wrangler-transform/src/e2e-test/java/io/cdap/plugin/common/stepsdesign/package-info.java b/wrangler-transform/src/e2e-test/java/io/cdap/plugin/common/stepsdesign/package-info.java
new file mode 100644
index 000000000..63f8efabc
--- /dev/null
+++ b/wrangler-transform/src/e2e-test/java/io/cdap/plugin/common/stepsdesign/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright © 2023 Cask Data, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+/**
+ * Package contains the stepDesign for common features.
+ */
+package io.cdap.plugin.common.stepsdesign;
diff --git a/wrangler-transform/src/e2e-test/java/io/cdap/plugin/wrangler/actions/ValidationHelper.java b/wrangler-transform/src/e2e-test/java/io/cdap/plugin/wrangler/actions/ValidationHelper.java
new file mode 100644
index 000000000..f35d6d311
--- /dev/null
+++ b/wrangler-transform/src/e2e-test/java/io/cdap/plugin/wrangler/actions/ValidationHelper.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright © 2023 Cask Data, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package io.cdap.plugin.wrangler.actions;
+
+import com.esotericsoftware.minlog.Log;
+import com.google.cloud.bigquery.FieldValueList;
+import com.google.cloud.bigquery.TableResult;
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import io.cdap.e2e.utils.BigQueryClient;
+import io.cdap.e2e.utils.PluginPropertyUtils;
+import io.cucumber.core.logging.Logger;
+import io.cucumber.core.logging.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Validation Helper.
+ */
+public class ValidationHelper {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ValidationHelper.class);
+ static Gson gson = new Gson();
+ public static boolean validateActualDataToExpectedData(String table, String fileName) throws IOException,
+ InterruptedException, URISyntaxException {
+ Map bigQueryMap = new HashMap<>();
+ Map fileMap = new HashMap<>();
+ Path importExpectedFile = Paths.get(ValidationHelper.class.getResource("/" + fileName).toURI());
+
+ getBigQueryTableData(table, bigQueryMap);
+ getFileData(importExpectedFile.toString(), fileMap);
+
+ boolean isMatched = bigQueryMap.equals(fileMap);
+
+ return isMatched;
+ }
+
+ public static void getFileData(String fileName, Map fileMap) {
+ try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {
+ String line;
+ while ((line = br.readLine()) != null) {
+ JsonObject json = gson.fromJson(line, JsonObject.class);
+ if (json.has("id")) { // Check if the JSON object has the "id" key
+ JsonElement idElement = json.get("id");
+ if (idElement.isJsonPrimitive()) {
+ String idKey = idElement.getAsString();
+ fileMap.put(idKey, json);
+ } else {
+ Log.error("ID key not found");
+ }
+ }
+ }
+ } catch (IOException e) {
+ System.err.println("Error reading the file: " + e.getMessage());
+ }
+ }
+
+ private static void getBigQueryTableData(String targetTable, Map bigQueryMap)
+ throws IOException, InterruptedException {
+ String dataset = PluginPropertyUtils.pluginProp("dataset");
+ String projectId = PluginPropertyUtils.pluginProp("projectId");
+ String selectQuery = "SELECT TO_JSON(t) FROM `" + projectId + "." + dataset + "." + targetTable + "` AS t";
+ TableResult result = BigQueryClient.getQueryResult(selectQuery);
+
+ for (FieldValueList row : result.iterateAll()) {
+ JsonObject json = gson.fromJson(row.get(0).getStringValue(), JsonObject.class);
+ if (json.has("id")) { // Check if the JSON object has the "id" key
+ JsonElement idElement = json.get("id");
+ if (idElement.isJsonPrimitive()) {
+ String idKey = idElement.getAsString();
+ bigQueryMap.put(idKey, json);
+ } else {
+ LOG.error("Data Mismatched");
+ }
+ } else {
+ LOG.error("ID Key not found in JSON object");
+ }
+ }
+ }
+}
diff --git a/wrangler-transform/src/e2e-test/java/io/cdap/plugin/wrangler/actions/package-info.java b/wrangler-transform/src/e2e-test/java/io/cdap/plugin/wrangler/actions/package-info.java
new file mode 100644
index 000000000..4d0f2be85
--- /dev/null
+++ b/wrangler-transform/src/e2e-test/java/io/cdap/plugin/wrangler/actions/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright © 2023 Cask Data, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+/**
+ * Package contains the actions for Wrangler features.
+ */
+package io.cdap.plugin.wrangler.actions;
diff --git a/wrangler-transform/src/e2e-test/java/io/cdap/plugin/wrangler/runners/TestRunner.java b/wrangler-transform/src/e2e-test/java/io/cdap/plugin/wrangler/runners/TestRunner.java
new file mode 100644
index 000000000..87b0d1aec
--- /dev/null
+++ b/wrangler-transform/src/e2e-test/java/io/cdap/plugin/wrangler/runners/TestRunner.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright © 2023 Cask Data, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package io.cdap.plugin.wrangler.runners;
+
+import io.cucumber.junit.Cucumber;
+import io.cucumber.junit.CucumberOptions;
+import org.junit.runner.RunWith;
+
+/**
+ * Test Runner to execute Wrangler plugin test cases.
+ */
+@RunWith(Cucumber.class)
+@CucumberOptions(
+ features = {"src/e2e-test/features"},
+ glue = {"stepsdesign", "io.cdap.plugin.common.stepsdesign", "io.cdap.plugin.wrangler.stepsdesign",
+ "io.cdap.plugin.wrangler.locators"},
+ tags = {"@Wrangler"},
+ plugin = {"pretty", "html:target/cucumber-html-report/wrangler-required",
+ "json:target/cucumber-reports/cucumber-wrangler-required.json",
+ "junit:target/cucumber-reports/cucumber-wrangler-required.xml"}
+)
+ public class TestRunner {
+}
diff --git a/wrangler-transform/src/e2e-test/java/io/cdap/plugin/wrangler/runners/TestRunnerRequired.java b/wrangler-transform/src/e2e-test/java/io/cdap/plugin/wrangler/runners/TestRunnerRequired.java
new file mode 100644
index 000000000..868e067ff
--- /dev/null
+++ b/wrangler-transform/src/e2e-test/java/io/cdap/plugin/wrangler/runners/TestRunnerRequired.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2023 Cask Data, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package io.cdap.plugin.wrangler.runners;
+
+import io.cucumber.junit.Cucumber;
+import io.cucumber.junit.CucumberOptions;
+import org.junit.runner.RunWith;
+
+/**
+ * Test Runner to execute Wrangler plugin test cases.
+ */
+@RunWith(Cucumber.class)
+@CucumberOptions(
+ features = {"src/e2e-test/features"},
+ glue = {"stepsdesign", "io.cdap.plugin.common.stepsdesign", "io.cdap.plugin.wrangler.stepsdesign"},
+ tags = {"@Wrangler_Required"},
+ plugin = {"pretty", "html:target/cucumber-html-report/wrangler-required",
+ "json:target/cucumber-reports/cucumber-wrangler-required.json",
+ "junit:target/cucumber-reports/cucumber-wrangler-required.xml"}
+)
+public class TestRunnerRequired {
+}
diff --git a/wrangler-transform/src/e2e-test/java/io/cdap/plugin/wrangler/runners/package-info.java b/wrangler-transform/src/e2e-test/java/io/cdap/plugin/wrangler/runners/package-info.java
new file mode 100644
index 000000000..b90a7504c
--- /dev/null
+++ b/wrangler-transform/src/e2e-test/java/io/cdap/plugin/wrangler/runners/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright © 2023 Cask Data, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+/**
+ * Package contains the runners for Wrangler features.
+ */
+package io.cdap.plugin.wrangler.runners;
diff --git a/wrangler-transform/src/e2e-test/java/io/cdap/plugin/wrangler/stepsdesign/Wrangler.java b/wrangler-transform/src/e2e-test/java/io/cdap/plugin/wrangler/stepsdesign/Wrangler.java
new file mode 100644
index 000000000..9d51ea34c
--- /dev/null
+++ b/wrangler-transform/src/e2e-test/java/io/cdap/plugin/wrangler/stepsdesign/Wrangler.java
@@ -0,0 +1,41 @@
+package io.cdap.plugin.wrangler.stepsdesign;
+/*
+ * Copyright © 2023 Cask Data, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+import io.cdap.e2e.utils.CdfHelper;
+import io.cdap.e2e.utils.PluginPropertyUtils;
+import io.cdap.plugin.wrangler.actions.ValidationHelper;
+import io.cucumber.java.en.Then;
+import org.junit.Assert;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+
+/**
+ * Step Design to execute Wrangler plugin test cases.
+ */
+
+public class Wrangler implements CdfHelper {
+
+ @Then("Validate The Data From BQ To BQ With Actual And Expected File for: {string}")
+ public void validateTheDataFromBQToBQWithActualAndExpectedFileFor(String expectedFile) throws IOException,
+ InterruptedException, URISyntaxException {
+ boolean recordsMatched = ValidationHelper.validateActualDataToExpectedData(
+ PluginPropertyUtils.pluginProp("bqTargetTable"),
+ PluginPropertyUtils.pluginProp(expectedFile));
+ Assert.assertTrue("Value of records in actual and expected file is equal", recordsMatched);
+ }
+}
diff --git a/wrangler-transform/src/e2e-test/java/io/cdap/plugin/wrangler/stepsdesign/package-info.java b/wrangler-transform/src/e2e-test/java/io/cdap/plugin/wrangler/stepsdesign/package-info.java
new file mode 100644
index 000000000..3e212c76c
--- /dev/null
+++ b/wrangler-transform/src/e2e-test/java/io/cdap/plugin/wrangler/stepsdesign/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright © 2023 Cask Data, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+/**
+ * Package contains the stepDesign for Wrangler features.
+ */
+package io.cdap.plugin.wrangler.stepsdesign;
diff --git a/wrangler-transform/src/e2e-test/resources/BQValidationExpectedFiles/Directive_wrangler_GroupBy b/wrangler-transform/src/e2e-test/resources/BQValidationExpectedFiles/Directive_wrangler_GroupBy
new file mode 100644
index 000000000..d02f42a93
--- /dev/null
+++ b/wrangler-transform/src/e2e-test/resources/BQValidationExpectedFiles/Directive_wrangler_GroupBy
@@ -0,0 +1,5 @@
+{"city":"San Jose","cityFirst":"San Jose","firstname":"DOUGLAS","id":"1","lastname":"Williams","state":"CA","zipcode":923564293}
+{"city":"Houston","cityFirst":"Houston","firstname":"DAVID","id":"2","lastname":"Johnson","state":"TX","zipcode":1738378970}
+{"city":"Manhattan","cityFirst":"Manhattan","firstname":"HUGH","id":"3","lastname":"Jackman","state":"NY","zipcode":-1863622247}
+{"city":"San Diego","cityFirst":"San Diego","firstname":"FRANK","id":"5","lastname":"Underwood","state":"CA","zipcode":-1317090526}
+{"city":"New York","cityFirst":"New York","firstname":"SARTHAK","id":"7","lastname":"Dash","state":"NY","zipcode":-1949601773}
\ No newline at end of file
diff --git a/wrangler-transform/src/e2e-test/resources/BQtesdata/BigQuery/BigQueryCreateTableQuery.txt b/wrangler-transform/src/e2e-test/resources/BQtesdata/BigQuery/BigQueryCreateTableQuery.txt
new file mode 100644
index 000000000..2ad22ced8
--- /dev/null
+++ b/wrangler-transform/src/e2e-test/resources/BQtesdata/BigQuery/BigQueryCreateTableQuery.txt
@@ -0,0 +1,2 @@
+create table `DATASET.TABLE_NAME` (id STRING, firstname STRING, lastname STRING, streetAddress STRING,
+city STRING, state STRING, zipcode BIGINT, phoneNumber BIGINT)
\ No newline at end of file
diff --git a/wrangler-transform/src/e2e-test/resources/BQtesdata/BigQuery/BigQueryInsertDataQuery.txt b/wrangler-transform/src/e2e-test/resources/BQtesdata/BigQuery/BigQueryInsertDataQuery.txt
new file mode 100644
index 000000000..ba7441f97
--- /dev/null
+++ b/wrangler-transform/src/e2e-test/resources/BQtesdata/BigQuery/BigQueryInsertDataQuery.txt
@@ -0,0 +1,10 @@
+INSERT INTO DATASET.TABLE_NAME (id, firstname, lastname, streetAddress, city, state, zipcode, phoneNumber)
+VALUES
+('5', 'Frank', 'Underwood', '1609 Far St.', 'San Diego', 'CA', 2977876770, 19061512345),
+('1', 'Douglas', 'Williams', '1 Vista Montana', 'San Jose', 'CA', 9513498885, 35834612345),
+('4', 'Walter', 'White', '3828 Piermont Dr', 'Orlando', 'FL', 7349864532, 7829812345),
+('3', 'Hugh', 'Jackman', '5, Cool Way', 'Manhattan', 'NY', 6726312345, 1695412345),
+('7', 'Sarthak', 'Dash', '123 Far St.', 'New York', 'NY', 2345365523, 1324812345),
+('6', 'Serena', 'Woods', '123 Far St.', 'Las Vegas', 'NV', 4533456734, 78919612345),
+('2', 'David', 'Johnson', '3 Baypointe Parkway', 'Houston', 'TX', 1738378970, 1451412345),
+('8', 'Rahul', 'Dash', '22 MG Road.', 'Bangalore', 'KA',NULL, 94864612345);
\ No newline at end of file
diff --git a/wrangler-transform/src/e2e-test/resources/pluginParameters.properties b/wrangler-transform/src/e2e-test/resources/pluginParameters.properties
new file mode 100644
index 000000000..5e96dd854
--- /dev/null
+++ b/wrangler-transform/src/e2e-test/resources/pluginParameters.properties
@@ -0,0 +1,15 @@
+#json file path
+Directive_GroupBy=testData/Wrangler/BQ2BQwithWrnglerNGrpby-cdap-data-pipeline (1).json
+bqSourceTable=dummy
+sourcePath=example/hello.csv
+gcsSourceBucket=dummy
+#bq queries file path
+CreateBQTableQueryFile=BQtesdata/BigQuery/BigQueryCreateTableQuery.txt
+InsertBQDataQueryFile=BQtesdata/BigQuery/BigQueryInsertDataQuery.txt
+
+#bq properties
+projectId=cdf-athena
+dataset=test_automation
+dataset2=Wrangler
+#expectedBQFiles
+ExpectedDirective_GroupBy=BQValidationExpectedFiles/Directive_wrangler_GroupBy
diff --git a/wrangler-transform/src/e2e-test/resources/testData/Wrangler/BQ2BQwithWrnglerNGrpby-cdap-data-pipeline (1).json b/wrangler-transform/src/e2e-test/resources/testData/Wrangler/BQ2BQwithWrnglerNGrpby-cdap-data-pipeline (1).json
new file mode 100644
index 000000000..2fb99c4f1
--- /dev/null
+++ b/wrangler-transform/src/e2e-test/resources/testData/Wrangler/BQ2BQwithWrnglerNGrpby-cdap-data-pipeline (1).json
@@ -0,0 +1,223 @@
+{
+ "name": "BQ2BQwithWrnglerNGrpby",
+ "description": "Data Pipeline Application",
+ "artifact": {
+ "name": "cdap-data-pipeline",
+ "version": "6.10.0-SNAPSHOT",
+ "scope": "SYSTEM"
+ },
+ "config": {
+ "resources": {
+ "memoryMB": 2048,
+ "virtualCores": 1
+ },
+ "driverResources": {
+ "memoryMB": 2048,
+ "virtualCores": 1
+ },
+ "connections": [
+ {
+ "from": "BigQueryTable",
+ "to": "Wrangler"
+ },
+ {
+ "from": "Wrangler",
+ "to": "Group By"
+ },
+ {
+ "from": "Group By",
+ "to": "BigQuery2"
+ }
+ ],
+ "postActions": [],
+ "properties": {},
+ "processTimingEnabled": true,
+ "stageLoggingEnabled": true,
+ "stages": [
+ {
+ "name": "BigQueryTable",
+ "plugin": {
+ "name": "BigQueryTable",
+ "type": "batchsource",
+ "label": "BigQueryTable",
+ "artifact": {
+ "name": "google-cloud",
+ "version": "0.23.0-SNAPSHOT",
+ "scope": "SYSTEM"
+ },
+ "properties": {
+ "useConnection": "false",
+ "dataset": "wrangler_ankit",
+ "table": "joinerTest",
+ "schema": "{\"type\":\"record\",\"name\":\"output\",\"fields\":[{\"name\":\"id\",\"type\":[\"string\",\"null\"]},{\"name\":\"firstname\",\"type\":[\"string\",\"null\"]},{\"name\":\"lastname\",\"type\":[\"string\",\"null\"]},{\"name\":\"streetAddress\",\"type\":[\"string\",\"null\"]},{\"name\":\"city\",\"type\":[\"string\",\"null\"]},{\"name\":\"state\",\"type\":[\"string\",\"null\"]},{\"name\":\"zipcode\",\"type\":[\"long\",\"null\"]},{\"name\":\"phoneNumber\",\"type\":[\"long\",\"null\"]}]}",
+ "enableQueryingViews": "false",
+ "project": "auto-detect",
+ "serviceAccountType": "filePath",
+ "serviceFilePath": "auto-detect"
+ }
+ },
+ "outputSchema": [
+ {
+ "name": "etlSchemaBody",
+ "schema": "{\"type\":\"record\",\"name\":\"output\",\"fields\":[{\"name\":\"id\",\"type\":[\"string\",\"null\"]},{\"name\":\"firstname\",\"type\":[\"string\",\"null\"]},{\"name\":\"lastname\",\"type\":[\"string\",\"null\"]},{\"name\":\"streetAddress\",\"type\":[\"string\",\"null\"]},{\"name\":\"city\",\"type\":[\"string\",\"null\"]},{\"name\":\"state\",\"type\":[\"string\",\"null\"]},{\"name\":\"zipcode\",\"type\":[\"long\",\"null\"]},{\"name\":\"phoneNumber\",\"type\":[\"long\",\"null\"]}]}"
+ }
+ ],
+ "id": "BigQueryTable",
+ "type": "batchsource",
+ "label": "BigQueryTable",
+ "icon": "fa-plug",
+ "$$hashKey": "object:1585",
+ "isPluginAvailable": true,
+ "_uiPosition": {
+ "left": "346px",
+ "top": "343px"
+ }
+ },
+ {
+ "name": "Wrangler",
+ "plugin": {
+ "name": "Wrangler",
+ "type": "transform",
+ "label": "Wrangler",
+ "artifact": {
+ "name": "wrangler-transform",
+ "version": "4.10.0-SNAPSHOT",
+ "scope": "SYSTEM"
+ },
+ "properties": {
+ "directives": "drop phonenumber\nuppercase :firstname\nset-type :zipcode integer \nfind-and-replace :streetAddress s/St./Street/Ig\nset-column :lastname_count string:length(lastname)\nfilter-rows-on regex-match lastname_count .*5.*\nfilter-rows-on condition-true zipcode == null || zipcode =~ \"^\\W*$\"",
+ "field": "*",
+ "precondition": "false",
+ "workspaceId": "fb521d04-7644-4ec4-b545-837980f402cf",
+ "schema": "{\"type\":\"record\",\"name\":\"record\",\"fields\":[{\"name\":\"id\",\"type\":[\"string\",\"null\"]},{\"name\":\"firstname\",\"type\":[\"string\",\"null\"]},{\"name\":\"lastname\",\"type\":[\"string\",\"null\"]},{\"name\":\"streetAddress\",\"type\":[\"string\",\"null\"]},{\"name\":\"city\",\"type\":[\"string\",\"null\"]},{\"name\":\"state\",\"type\":[\"string\",\"null\"]},{\"name\":\"zipcode\",\"type\":[\"int\",\"null\"]},{\"name\":\"lastname_count\",\"type\":[\"int\",\"null\"]}]}",
+ "on-error": "fail-pipeline"
+ }
+ },
+ "outputSchema": [
+ {
+ "name": "etlSchemaBody",
+ "schema": "{\"type\":\"record\",\"name\":\"record\",\"fields\":[{\"name\":\"id\",\"type\":[\"string\",\"null\"]},{\"name\":\"firstname\",\"type\":[\"string\",\"null\"]},{\"name\":\"lastname\",\"type\":[\"string\",\"null\"]},{\"name\":\"streetAddress\",\"type\":[\"string\",\"null\"]},{\"name\":\"city\",\"type\":[\"string\",\"null\"]},{\"name\":\"state\",\"type\":[\"string\",\"null\"]},{\"name\":\"zipcode\",\"type\":[\"int\",\"null\"]},{\"name\":\"lastname_count\",\"type\":[\"int\",\"null\"]}]}"
+ }
+ ],
+ "inputSchema": [
+ {
+ "name": "BigQueryTable",
+ "schema": "{\"type\":\"record\",\"name\":\"output\",\"fields\":[{\"name\":\"id\",\"type\":[\"string\",\"null\"]},{\"name\":\"firstname\",\"type\":[\"string\",\"null\"]},{\"name\":\"lastname\",\"type\":[\"string\",\"null\"]},{\"name\":\"streetAddress\",\"type\":[\"string\",\"null\"]},{\"name\":\"city\",\"type\":[\"string\",\"null\"]},{\"name\":\"state\",\"type\":[\"string\",\"null\"]},{\"name\":\"zipcode\",\"type\":[\"long\",\"null\"]},{\"name\":\"phoneNumber\",\"type\":[\"long\",\"null\"]}]}"
+ }
+ ],
+ "id": "Wrangler",
+ "type": "transform",
+ "label": "Wrangler",
+ "icon": "icon-DataPreparation",
+ "$$hashKey": "object:1586",
+ "isPluginAvailable": true,
+ "_uiPosition": {
+ "left": "646px",
+ "top": "343px"
+ }
+ },
+ {
+ "name": "Group By",
+ "plugin": {
+ "name": "GroupByAggregate",
+ "type": "batchaggregator",
+ "label": "Group By",
+ "artifact": {
+ "name": "core-plugins",
+ "version": "2.12.0-SNAPSHOT",
+ "scope": "SYSTEM"
+ },
+ "properties": {
+ "groupByFields": "city,firstname,lastname,state,zipcode,id",
+ "aggregates": "cityFirst:First(city)"
+ }
+ },
+ "outputSchema": [
+ {
+ "name": "etlSchemaBody",
+ "schema": "{\"type\":\"record\",\"name\":\"record.typeagg\",\"fields\":[{\"name\":\"city\",\"type\":[\"string\",\"null\"]},{\"name\":\"firstname\",\"type\":[\"string\",\"null\"]},{\"name\":\"lastname\",\"type\":[\"string\",\"null\"]},{\"name\":\"state\",\"type\":[\"string\",\"null\"]},{\"name\":\"zipcode\",\"type\":[\"int\",\"null\"]},{\"name\":\"id\",\"type\":[\"string\",\"null\"]},{\"name\":\"cityFirst\",\"type\":[\"string\",\"null\"]}]}"
+ }
+ ],
+ "inputSchema": [
+ {
+ "name": "Wrangler",
+ "schema": "{\"type\":\"record\",\"name\":\"record\",\"fields\":[{\"name\":\"id\",\"type\":[\"string\",\"null\"]},{\"name\":\"firstname\",\"type\":[\"string\",\"null\"]},{\"name\":\"lastname\",\"type\":[\"string\",\"null\"]},{\"name\":\"streetAddress\",\"type\":[\"string\",\"null\"]},{\"name\":\"city\",\"type\":[\"string\",\"null\"]},{\"name\":\"state\",\"type\":[\"string\",\"null\"]},{\"name\":\"zipcode\",\"type\":[\"int\",\"null\"]},{\"name\":\"lastname_count\",\"type\":[\"int\",\"null\"]}]}"
+ }
+ ],
+ "id": "Group-By",
+ "type": "batchaggregator",
+ "label": "Group By",
+ "icon": "icon-groupbyaggregate",
+ "$$hashKey": "object:1587",
+ "isPluginAvailable": true,
+ "_uiPosition": {
+ "left": "946px",
+ "top": "343px"
+ }
+ },
+ {
+ "name": "BigQuery2",
+ "plugin": {
+ "name": "BigQueryTable",
+ "type": "batchsink",
+ "label": "BigQuery2",
+ "artifact": {
+ "name": "google-cloud",
+ "version": "0.23.0-SNAPSHOT",
+ "scope": "SYSTEM"
+ },
+ "properties": {
+ "useConnection": "false",
+ "project": "auto-detect",
+ "serviceAccountType": "filePath",
+ "serviceFilePath": "auto-detect",
+ "dataset": "wrangler_ankit",
+ "table": "joinTestOutput",
+ "operation": "insert",
+ "truncateTable": "false",
+ "allowSchemaRelaxation": "false",
+ "location": "US",
+ "createPartitionedTable": "false",
+ "partitioningType": "TIME",
+ "partitionFilterRequired": "false",
+ "schema": "{\"type\":\"record\",\"name\":\"record.typeagg\",\"fields\":[{\"name\":\"city\",\"type\":[\"string\",\"null\"]},{\"name\":\"firstname\",\"type\":[\"string\",\"null\"]},{\"name\":\"lastname\",\"type\":[\"string\",\"null\"]},{\"name\":\"state\",\"type\":[\"string\",\"null\"]},{\"name\":\"zipcode\",\"type\":[\"int\",\"null\"]},{\"name\":\"id\",\"type\":[\"string\",\"null\"]},{\"name\":\"cityFirst\",\"type\":[\"string\",\"null\"]}]}"
+ }
+ },
+ "outputSchema": [
+ {
+ "name": "etlSchemaBody",
+ "schema": "{\"type\":\"record\",\"name\":\"record.typeagg\",\"fields\":[{\"name\":\"city\",\"type\":[\"string\",\"null\"]},{\"name\":\"firstname\",\"type\":[\"string\",\"null\"]},{\"name\":\"lastname\",\"type\":[\"string\",\"null\"]},{\"name\":\"state\",\"type\":[\"string\",\"null\"]},{\"name\":\"zipcode\",\"type\":[\"int\",\"null\"]},{\"name\":\"id\",\"type\":[\"string\",\"null\"]},{\"name\":\"cityFirst\",\"type\":[\"string\",\"null\"]}]}"
+ }
+ ],
+ "inputSchema": [
+ {
+ "name": "Group By",
+ "schema": "{\"type\":\"record\",\"name\":\"record.typeagg\",\"fields\":[{\"name\":\"city\",\"type\":[\"string\",\"null\"]},{\"name\":\"firstname\",\"type\":[\"string\",\"null\"]},{\"name\":\"lastname\",\"type\":[\"string\",\"null\"]},{\"name\":\"state\",\"type\":[\"string\",\"null\"]},{\"name\":\"zipcode\",\"type\":[\"int\",\"null\"]},{\"name\":\"id\",\"type\":[\"string\",\"null\"]},{\"name\":\"cityFirst\",\"type\":[\"string\",\"null\"]}]}"
+ }
+ ],
+ "id": "BigQuery2",
+ "type": "batchsink",
+ "label": "BigQuery2",
+ "icon": "fa-plug",
+ "$$hashKey": "object:1588",
+ "isPluginAvailable": true,
+ "_uiPosition": {
+ "left": "1246px",
+ "top": "343px"
+ }
+ }
+ ],
+ "schedule": "0 1 */1 * *",
+ "engine": "spark",
+ "numOfRecordsPreview": 100,
+ "rangeRecordsPreview": {
+ "min": 1,
+ "max": "5000"
+ },
+ "description": "Data Pipeline Application",
+ "maxConcurrentRuns": 1,
+ "pushdownEnabled": false,
+ "transformationPushdown": {}
+ },
+ "version": "714034ca-5154-11ee-9b22-000000505066"
+}
\ No newline at end of file