From c2550e374246f7fa31dec077d3e398cd372f184b Mon Sep 17 00:00:00 2001 From: priyabhatnagar Date: Wed, 21 Jun 2023 22:25:25 +0530 Subject: [PATCH] wrangler e2e tests --- pom.xml | 4 +- .../features/Wrangler/DataTypeParsers.feature | 11 +- .../features/Wrangler/ParseAsCsv.feature | 8 +- .../features/Wrangler/ParseAsExcel.feature | 40 ++ .../Wrangler/ParseAsFixedLength.feature | 6 +- .../features/Wrangler/ParseAsHl7.feature | 9 +- .../features/Wrangler/ParseAsJson.feature | 43 ++ .../Wrangler/ParseAsXmlToJson.feature | 43 ++ .../common/stepsdesign/TestSetupHooks.java | 117 ++++- .../Directive_parse_DateTime | 6 +- .../Directive_parse_excel | 2 + .../Directive_parse_fixedlength | 4 +- .../Directive_parse_json | 3 + .../Directive_parse_xmltojson | 6 + .../BigQuery/BigQueryCreateTableQueryXml.txt | 1 + .../BigQuery/BigQueryInsertDataQueryXml.txt | 5 + .../BigQueryInsertDataQueryparsejson.txt | 6 + .../BigQuery/BigQuerycreateTableQueryjson.txt | 1 + .../resources/BQtesdata/BigQuery/test1.xlsx | Bin 0 -> 5228 bytes .../resources/errorMessage.properties | 1 + .../resources/pluginParameters.properties | 18 +- ...e_HL7_Wrangler-cdap-data-pipeline (1).json | 14 +- .../parse_csv_wrangle-cdap-data-pipeline.json | 14 +- ..._datetime_wrangler-cdap-data-pipeline.json | 167 +++++++ ...xcel_wrangler_copy-cdap-data-pipeline.json | 180 +++++++ ...edlength_wrangler-cdap-data-pipeline.json} | 64 +-- ...rse_json_wrangler1-cdap-data-pipeline.json | 467 ++++++++++++++++++ ..._timestamp_wrangle-cdap-data-pipeline.json | 14 +- ...json_wrangler-cdap-data-pipeline (1).json} | 60 ++- 29 files changed, 1162 insertions(+), 152 deletions(-) create mode 100644 wrangler-transform/src/e2e-test/features/Wrangler/ParseAsExcel.feature create mode 100644 wrangler-transform/src/e2e-test/features/Wrangler/ParseAsJson.feature create mode 100644 wrangler-transform/src/e2e-test/features/Wrangler/ParseAsXmlToJson.feature create mode 100644 wrangler-transform/src/e2e-test/resources/BQValidationExpectedFiles/Directive_parse_excel create mode 100644 wrangler-transform/src/e2e-test/resources/BQValidationExpectedFiles/Directive_parse_json create mode 100644 wrangler-transform/src/e2e-test/resources/BQValidationExpectedFiles/Directive_parse_xmltojson create mode 100644 wrangler-transform/src/e2e-test/resources/BQtesdata/BigQuery/BigQueryCreateTableQueryXml.txt create mode 100644 wrangler-transform/src/e2e-test/resources/BQtesdata/BigQuery/BigQueryInsertDataQueryXml.txt create mode 100644 wrangler-transform/src/e2e-test/resources/BQtesdata/BigQuery/BigQueryInsertDataQueryparsejson.txt create mode 100644 wrangler-transform/src/e2e-test/resources/BQtesdata/BigQuery/BigQuerycreateTableQueryjson.txt create mode 100644 wrangler-transform/src/e2e-test/resources/BQtesdata/BigQuery/test1.xlsx create mode 100644 wrangler-transform/src/e2e-test/resources/errorMessage.properties create mode 100644 wrangler-transform/src/e2e-test/resources/testData/Wrangler/parse_datetime_wrangler-cdap-data-pipeline.json create mode 100644 wrangler-transform/src/e2e-test/resources/testData/Wrangler/parse_excel_wrangler_copy-cdap-data-pipeline.json rename wrangler-transform/src/e2e-test/resources/testData/Wrangler/{parse_fixedlength_wrangle-cdap-data-pipeline.json => parse_fixedlength_wrangler-cdap-data-pipeline.json} (81%) create mode 100644 wrangler-transform/src/e2e-test/resources/testData/Wrangler/parse_json_wrangler1-cdap-data-pipeline.json rename wrangler-transform/src/e2e-test/resources/testData/Wrangler/{parse_datetime_wrangle-cdap-data-pipeline.json => parse_xmltojson_wrangler-cdap-data-pipeline (1).json} (71%) diff --git a/pom.xml b/pom.xml index 75561b6e0..18ea1fdfe 100644 --- a/pom.xml +++ b/pom.xml @@ -83,7 +83,7 @@ 1.11.133 0.10.2-hadoop2 1.56 - 6.10.0-SNAPSHOT + 6.10.0 1.1.5 1.6 2.5 @@ -547,7 +547,7 @@ io.cdap.tests.e2e cdap-e2e-framework - 0.3.0-SNAPSHOT + 0.4.0-SNAPSHOT test diff --git a/wrangler-transform/src/e2e-test/features/Wrangler/DataTypeParsers.feature b/wrangler-transform/src/e2e-test/features/Wrangler/DataTypeParsers.feature index dd27ebc83..b16465274 100644 --- a/wrangler-transform/src/e2e-test/features/Wrangler/DataTypeParsers.feature +++ b/wrangler-transform/src/e2e-test/features/Wrangler/DataTypeParsers.feature @@ -15,7 +15,7 @@ @Wrangler Feature: datatype parsers - @BQ_SOURCE_TS_TEST @BQ_SINK_TEST + @BQ_SOURCE_TS_TEST @BQ_SOURCE_TEST @BQ_SINK_TEST Scenario: To verify User is able to run a pipeline using parse timestamp directive Given Open Datafusion Project to configure pipeline Then Click on the Plus Green Button to import the pipelines @@ -25,13 +25,13 @@ Feature: datatype parsers 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 Validate "BigQueryTable" plugin properties 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 Validate "BigQuery2" plugin properties Then Close the Plugin Properties page Then Rename the pipeline Then Deploy the pipeline @@ -43,7 +43,7 @@ Feature: datatype parsers Then Validate The Data From BQ To BQ With Actual And Expected File for: "ExpectedDirective_parse_Timestamp" - @BQ_SOURCE_DATETIME_TEST @BQ_SINK_TEST + @BQ_SOURCE_DATETIME_TEST @BQ_SOURCE_TEST @BQ_SINK_TEST Scenario: To verify User is able to run a pipeline using parse datetime directive Given Open Datafusion Project to configure pipeline Then Click on the Plus Green Button to import the pipelines @@ -53,13 +53,14 @@ Feature: datatype parsers 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 Validate "BigQueryTable" plugin properties 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 Validate "BigQuery2" plugin properties Then Close the Plugin Properties page Then Rename the pipeline Then Deploy the pipeline diff --git a/wrangler-transform/src/e2e-test/features/Wrangler/ParseAsCsv.feature b/wrangler-transform/src/e2e-test/features/Wrangler/ParseAsCsv.feature index fa59cb54c..3cf923618 100644 --- a/wrangler-transform/src/e2e-test/features/Wrangler/ParseAsCsv.feature +++ b/wrangler-transform/src/e2e-test/features/Wrangler/ParseAsCsv.feature @@ -13,9 +13,9 @@ # the License. @Wrangler -Feature: Wrangler - Run time scenarios +Feature: Wrangler - Run time scenarios for parse csv - @BQ_SOURCE_CSV_TEST @BQ_SINK_TEST + @BQ_SOURCE_CSV_TEST @BQ_SOURCE_TEST @BQ_SINK_TEST Scenario: To verify User is able to run a pipeline using parse csv directive Given Open Datafusion Project to configure pipeline Then Click on the Plus Green Button to import the pipelines @@ -25,13 +25,13 @@ Feature: Wrangler - Run time scenarios 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 Validate "BigQueryTable" plugin properties 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 Validate "BigQuery2" plugin properties Then Close the Plugin Properties page Then Rename the pipeline Then Deploy the pipeline diff --git a/wrangler-transform/src/e2e-test/features/Wrangler/ParseAsExcel.feature b/wrangler-transform/src/e2e-test/features/Wrangler/ParseAsExcel.feature new file mode 100644 index 000000000..2a3d21acf --- /dev/null +++ b/wrangler-transform/src/e2e-test/features/Wrangler/ParseAsExcel.feature @@ -0,0 +1,40 @@ +# 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: Parse as excel + + @GCS_SOURCE_TEST @BQ_SINK_TEST + Scenario: To verify User is able to run a pipeline using parse Excel 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_parse_excel" + Then Navigate to the properties page of plugin: "GCSFile" + Then Replace input plugin property: "project" with value: "projectId" + Then Replace input plugin property: "path" with value: "gcsSourceBucket" + Then Close the Plugin Properties page + Then Navigate to the properties page of plugin: "BigQuery" + 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 Validate "BigQuery" plugin properties + 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_parse_excel" diff --git a/wrangler-transform/src/e2e-test/features/Wrangler/ParseAsFixedLength.feature b/wrangler-transform/src/e2e-test/features/Wrangler/ParseAsFixedLength.feature index 5ac20c0b7..cb2929120 100644 --- a/wrangler-transform/src/e2e-test/features/Wrangler/ParseAsFixedLength.feature +++ b/wrangler-transform/src/e2e-test/features/Wrangler/ParseAsFixedLength.feature @@ -15,7 +15,7 @@ @Wrangler Feature: parse as fixed length - @BQ_SOURCE_FXDLEN_TEST @BQ_SINK_TEST + @BQ_SOURCE_FXDLEN_TEST @BQ_SOURCE_TEST @BQ_SINK_TEST Scenario: To verify User is able to run a pipeline using parse fixedlength directive Given Open Datafusion Project to configure pipeline Then Click on the Plus Green Button to import the pipelines @@ -25,13 +25,13 @@ Feature: parse as fixed length 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 Validate "BigQueryTable" plugin properties 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 Validate "BigQuery2" plugin properties Then Close the Plugin Properties page Then Rename the pipeline Then Deploy the pipeline diff --git a/wrangler-transform/src/e2e-test/features/Wrangler/ParseAsHl7.feature b/wrangler-transform/src/e2e-test/features/Wrangler/ParseAsHl7.feature index c6c9e00df..15ac6000d 100644 --- a/wrangler-transform/src/e2e-test/features/Wrangler/ParseAsHl7.feature +++ b/wrangler-transform/src/e2e-test/features/Wrangler/ParseAsHl7.feature @@ -15,7 +15,7 @@ @Wrangler Feature: parse as HL7 - @BQ_SOURCE_HL7_TEST @BQ_SINK_TEST + @BQ_SOURCE_HL7_TEST @BQ_SOURCE_TEST @BQ_SINK_TEST Scenario: To verify User is able to run a pipeline using parse hl7 directive Given Open Datafusion Project to configure pipeline Then Click on the Plus Green Button to import the pipelines @@ -25,16 +25,15 @@ Feature: parse as HL7 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 Validate "BigQueryTable" plugin properties 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 Validate "BigQuery2" plugin properties Then Close the Plugin Properties page - Then Rename the pipeline - Then Deploy the pipeline + Then Save and Deploy Pipeline Then Run the Pipeline in Runtime Then Wait till pipeline is in running state Then Open and capture logs diff --git a/wrangler-transform/src/e2e-test/features/Wrangler/ParseAsJson.feature b/wrangler-transform/src/e2e-test/features/Wrangler/ParseAsJson.feature new file mode 100644 index 000000000..a7ba8f92d --- /dev/null +++ b/wrangler-transform/src/e2e-test/features/Wrangler/ParseAsJson.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: parse as Json + + @BQ_SOURCE_JSON_TEST @BQ_SOURCE_TEST @BQ_SINK_TEST + Scenario: To verify User is able to run a pipeline using parse Json 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_parse_json" + 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 Validate "BigQueryTable" plugin properties + 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 Validate "BigQuery2" plugin properties + 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_parse_json" diff --git a/wrangler-transform/src/e2e-test/features/Wrangler/ParseAsXmlToJson.feature b/wrangler-transform/src/e2e-test/features/Wrangler/ParseAsXmlToJson.feature new file mode 100644 index 000000000..a0f0b5a9a --- /dev/null +++ b/wrangler-transform/src/e2e-test/features/Wrangler/ParseAsXmlToJson.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: parse as XmlToJson + + @BQ_SOURCE_XML_TEST @BQ_SOURCE_TEST @BQ_SINK_TEST + Scenario: To verify User is able to run a pipeline using parse XmlToJson 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_parse_xml" + 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 Validate "BigQueryTable" plugin properties + 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 Validate "BigQuery2" plugin properties + 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_parse_xml" 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 index 0243dc4ed..b277ef375 100644 --- 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 @@ -17,8 +17,11 @@ 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.StringUtils; @@ -26,6 +29,7 @@ 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; @@ -37,12 +41,15 @@ */ public class TestSetupHooks { + public static String gcsSourceBucketName = StringUtils.EMPTY; + @Before(order = 1, value = "@BQ_SOURCE_CSV_TEST") public static void createTempSourceBQTable() throws IOException, InterruptedException { createSourceBQTableWithQueries(PluginPropertyUtils.pluginProp("CreateBQTableQueryFileCsv"), - PluginPropertyUtils.pluginProp("InsertBQDataQueryFileCsv")); + PluginPropertyUtils.pluginProp("InsertBQDataQueryFileCsv")); } - @Before(order = 1, value = "@BQ_SINK_TEST") + + @Before(order = 2, value = "@BQ_SINK_TEST") public static void setTempTargetBQTableName() { String bqTargetTableName = "E2E_TARGET_" + UUID.randomUUID().toString().replaceAll("-", "_"); PluginPropertyUtils.addPluginProp("bqTargetTable", bqTargetTableName); @@ -54,7 +61,8 @@ public static void deleteTempTargetBQTable() throws IOException, InterruptedExce String bqTargetTableName = PluginPropertyUtils.pluginProp("bqTargetTable"); try { BigQueryClient.dropBqQuery(bqTargetTableName); - BeforeActions.scenario.write("BQ Target table - " + bqTargetTableName + " deleted successfully"); + BeforeActions.scenario.write( + "BQ Target table - " + bqTargetTableName + " deleted successfully"); PluginPropertyUtils.removePluginProp("bqTargetTable"); } catch (BigQueryException e) { if (e.getMessage().contains("Not found: Table")) { @@ -66,30 +74,33 @@ public static void deleteTempTargetBQTable() throws IOException, InterruptedExce } /** - * Create BigQuery table. + * Create BigQuery table test. */ @Before(order = 1, value = "@BQ_SOURCE_FXDLEN_TEST") public static void createTempSourceBQTableFxdLen() throws IOException, InterruptedException { createSourceBQTableWithQueries(PluginPropertyUtils.pluginProp("CreateBQDataQueryFileFxdLen"), - PluginPropertyUtils.pluginProp("InsertBQDataQueryFileFxdLen")); + PluginPropertyUtils.pluginProp("InsertBQDataQueryFileFxdLen")); } + @Before(order = 1, value = "@BQ_SOURCE_HL7_TEST") public static void createTempSourceBQTableHl7() throws IOException, InterruptedException { createSourceBQTableWithQueries(PluginPropertyUtils.pluginProp("CreateBQDataQueryFileHl7"), - PluginPropertyUtils.pluginProp("InsertBQDataQueryFileHl7")); + PluginPropertyUtils.pluginProp("InsertBQDataQueryFileHl7")); } + @Before(order = 1, value = "@BQ_SOURCE_TS_TEST") public static void createTempSourceBQTableTimestamp() throws IOException, InterruptedException { createSourceBQTableWithQueries(PluginPropertyUtils.pluginProp("CreateBQDataQueryFileTimestamp"), - PluginPropertyUtils.pluginProp("InsertBQDataQueryFileTimestamp")); + PluginPropertyUtils.pluginProp("InsertBQDataQueryFileTimestamp")); } + @Before(order = 1, value = "@BQ_SOURCE_DATETIME_TEST") public static void createTempSourceBQTableDateTime() throws IOException, InterruptedException { createSourceBQTableWithQueries(PluginPropertyUtils.pluginProp("CreateBQDataQueryFileDatetime"), - PluginPropertyUtils.pluginProp("InsertBQDataQueryFileDatetime")); + PluginPropertyUtils.pluginProp("InsertBQDataQueryFileDatetime")); } - @After(order = 1, value = "@BQ_SOURCE_TEST") + @After(order = 2, value = "@BQ_SOURCE_TEST") public static void deleteTempSourceBQTable() throws IOException, InterruptedException { String bqSourceTable = PluginPropertyUtils.pluginProp("bqSourceTable"); BigQueryClient.dropBqQuery(bqSourceTable); @@ -97,35 +108,91 @@ public static void deleteTempSourceBQTable() throws IOException, InterruptedExce PluginPropertyUtils.removePluginProp("bqSourceTable"); } - private static void createSourceBQTableWithQueries(String bqCreateTableQueryFile, String bqInsertDataQueryFile) - throws IOException, InterruptedException { - String bqSourceTable = "E2E_SOURCE_" + UUID.randomUUID().toString().substring(0, 5).replaceAll("-", - "_"); + @Before(order = 1, value = "@BQ_SOURCE_JSON_TEST") + public static void createTempSourceBQTableJson() throws IOException, InterruptedException { + createSourceBQTableWithQueries(PluginPropertyUtils.pluginProp("CreateBQTableQueryFileJson"), + PluginPropertyUtils.pluginProp("InsertBQDataQueryFileJson")); + } + + @Before(order = 1, value = "@BQ_SOURCE_XML_TEST") + public static void createTempSourceBQTableXml() throws IOException, InterruptedException { + createSourceBQTableWithQueries(PluginPropertyUtils.pluginProp("CreateBQDataQueryFileXml"), + PluginPropertyUtils.pluginProp("InsertBQDataQueryFileXml")); + } + + @Before(order = 1, value = "@GCS_SOURCE_TEST") + public static void createBucketWithEXCELFile() throws IOException, URISyntaxException { + gcsSourceBucketName = createGCSBucketWithFile(PluginPropertyUtils.pluginProp("testFile")); + PluginPropertyUtils.addPluginProp("gcsSourceBucket", "gs://" + gcsSourceBucketName + "/" + + PluginPropertyUtils.pluginProp("testFile")); + BeforeActions.scenario.write("GCS source bucket1 name - " + gcsSourceBucketName); + } + + private static String createGCSBucketWithFile(String filePath) + throws IOException, URISyntaxException { + String bucketName = StorageClient.createBucket("e2e-test-" + UUID.randomUUID()).getName(); + StorageClient.uploadObject(bucketName, filePath, filePath); + return bucketName; + } + + @After(order = 1, value = "@GCS_SOURCE_TEST") + public static void deleteSourceBucketWithFile() { + deleteGCSBucket(gcsSourceBucketName); + gcsSourceBucketName = StringUtils.EMPTY; + } + + private static void deleteGCSBucket(String bucketName) { + try { + for (Blob blob : StorageClient.listObjects(bucketName).iterateAll()) { + StorageClient.deleteObject(bucketName, blob.getName()); + } + StorageClient.deleteBucket(bucketName); + BeforeActions.scenario.write("Deleted GCS Bucket " + bucketName); + } catch (StorageException | IOException e) { + if (e.getMessage().contains("The specified bucket does not exist")) { + BeforeActions.scenario.write("GCS Bucket " + bucketName + " does not exist."); + } else { + Assert.fail(e.getMessage()); + } + } + } + + + 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); + ("/" + 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()); + 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()); + "- 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); + ("/" + 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()); + 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()); + "- error in reading insert data query file " + e.getMessage()); } BigQueryClient.getSoleQueryResult(createTableQuery); try { diff --git a/wrangler-transform/src/e2e-test/resources/BQValidationExpectedFiles/Directive_parse_DateTime b/wrangler-transform/src/e2e-test/resources/BQValidationExpectedFiles/Directive_parse_DateTime index aa50c50d0..0af0511b3 100644 --- a/wrangler-transform/src/e2e-test/resources/BQValidationExpectedFiles/Directive_parse_DateTime +++ b/wrangler-transform/src/e2e-test/resources/BQValidationExpectedFiles/Directive_parse_DateTime @@ -1,3 +1,3 @@ -{"create_date":"2023","id":1,"timecolumn":"2006-03-18"} -{"create_date":"2023","id":2,"timecolumn":"2007-03-18"} -{"create_date":"2023","id":3,"timecolumn":"2008-04-19"} \ No newline at end of file +{"create_date":"2024","id":"1","timecolumn":"2006-03-18"} +{"create_date":"2024","id":"2","timecolumn":"2007-03-18"} +{"create_date":"2024","id":"3","timecolumn":"2008-04-19"} \ No newline at end of file diff --git a/wrangler-transform/src/e2e-test/resources/BQValidationExpectedFiles/Directive_parse_excel b/wrangler-transform/src/e2e-test/resources/BQValidationExpectedFiles/Directive_parse_excel new file mode 100644 index 000000000..3c3ae5154 --- /dev/null +++ b/wrangler-transform/src/e2e-test/resources/BQValidationExpectedFiles/Directive_parse_excel @@ -0,0 +1,2 @@ +{"copiedname":"very","id":0,"name":"very","phone":"8838.0","rollno":"3.0","uniquenum":"very,0"} +{"copiedname":"hello","id":2,"name":"hell","phone":"12345.0","rollno":"1.0","uniquenum":"hello,2"} \ No newline at end of file diff --git a/wrangler-transform/src/e2e-test/resources/BQValidationExpectedFiles/Directive_parse_fixedlength b/wrangler-transform/src/e2e-test/resources/BQValidationExpectedFiles/Directive_parse_fixedlength index 33010a877..591e939aa 100644 --- a/wrangler-transform/src/e2e-test/resources/BQValidationExpectedFiles/Directive_parse_fixedlength +++ b/wrangler-transform/src/e2e-test/resources/BQValidationExpectedFiles/Directive_parse_fixedlength @@ -1,2 +1,2 @@ -{"Url":"http://example.com:80/docs/books/tutorial/index.html?name=networking#DOWNLOADING","fixedlength":"21 10 ABCXYZ","fixedlength_1":"21","fixedlength_3":" ABC","fixedlength_4":"XYZ","fixedlength_encode_base32":"GIYSAIBRGAQCAQKCINMFSWQ=","fixedlength_encode_base32_decode_base32":"21 10 ABCXYZ","id":" 10","url_authority":"example.com:80","url_filename":"/docs/books/tutorial/index.html?name=networking","url_host":"example.com","url_path":"/docs/books/tutorial/index.html","url_port":80,"url_protocol":"http","url_query":"name=networking","url_query_1":"name","url_query_2":"networking"} -{"Url":"http://geeks.com:80/docs/chair/tutorial/index.html?name=networking#DOWNLOADING","fixedlength":"19 13 ABCXYZ","fixedlength_1":"19","fixedlength_3":" ABC","fixedlength_4":"XYZ","fixedlength_encode_base32":"GE4SAIBRGMQCAQKCINMFSWQ=","fixedlength_encode_base32_decode_base32":"19 13 ABCXYZ","id":" 13","url_authority":"geeks.com:80","url_filename":"/docs/chair/tutorial/index.html?name=networking","url_host":"geeks.com","url_path":"/docs/chair/tutorial/index.html","url_port":80,"url_protocol":"http","url_query":"name=networking","url_query_1":"name","url_query_2":"networking"} \ No newline at end of file +{"fixedlength":"21 10 ABCXYZ","fixedlength_1":"21","fixedlength_3":" ABC","fixedlength_4":"XYZ","fixedlength_encode_base32":"GIYSAIBRGAQCAQKCINMFSWQ=","fixedlength_encode_base32_decode_base32":"21 10 ABCXYZ","id":" 10","url":"http://example.com:80/docs/books/tutorial/index.html?name=networking#DOWNLOADING","url_authority":"example.com:80","url_filename":"/docs/books/tutorial/index.html?name=networking","url_host":"example.com","url_path":"/docs/books/tutorial/index.html","url_port":80,"url_protocol":"http","url_query":"name=networking","url_query_1":"name","url_query_2":"networking"} +{"fixedlength":"19 13 ABCXYZ","fixedlength_1":"19","fixedlength_3":" ABC","fixedlength_4":"XYZ","fixedlength_encode_base32":"GE4SAIBRGMQCAQKCINMFSWQ=","fixedlength_encode_base32_decode_base32":"19 13 ABCXYZ","id":" 13","url":"http://geeks.com:80/docs/chair/tutorial/index.html?name=networking#DOWNLOADING","url_authority":"geeks.com:80","url_filename":"/docs/chair/tutorial/index.html?name=networking","url_host":"geeks.com","url_path":"/docs/chair/tutorial/index.html","url_port":80,"url_protocol":"http","url_query":"name=networking","url_query_1":"name","url_query_2":"networking"} \ No newline at end of file diff --git a/wrangler-transform/src/e2e-test/resources/BQValidationExpectedFiles/Directive_parse_json b/wrangler-transform/src/e2e-test/resources/BQValidationExpectedFiles/Directive_parse_json new file mode 100644 index 000000000..881f21c3c --- /dev/null +++ b/wrangler-transform/src/e2e-test/resources/BQValidationExpectedFiles/Directive_parse_json @@ -0,0 +1,3 @@ +{"body":"hello abc","copied":{"first":"Root","last":"joy"},"desc":"nickhello abc","id":22,"json_age":"{\"json_id\":22,\"copied\":{\"first\":\"Root\",\"last\":\"joy\"},\"json_age\":1,\"json_name\":{\"first\":\"Root\",\"last\":\"joy\"},\"json_pet\":\"testing\",\"json_id_json_name\":\"22,{\\\"first\\\":\\\"Root\\\",\\\"last\\\":\\\"joy\\\"}\",\"body\":\"hello abc\",\"desc\":\"nickhello abc\"}","json_id_json_name":"22,{\"first\":\"Root\",\"last\":\"joy\"}","json_name":{"first":"Root","last":"joy"},"json_pet":"testing"} +{"body":"hello def","copied":{"first":"dded","last":"share"},"desc":"hellohello def","id":23,"json_age":"{\"json_id\":23,\"copied\":{\"first\":\"dded\",\"last\":\"share\"},\"json_age\":2,\"json_name\":{\"first\":\"dded\",\"last\":\"share\"},\"json_pet\":\"testing\",\"json_id_json_name\":\"23,{\\\"first\\\":\\\"dded\\\",\\\"last\\\":\\\"share\\\"}\",\"body\":\"hello def\",\"desc\":\"hellohello def\"}","json_id_json_name":"23,{\"first\":\"dded\",\"last\":\"share\"}","json_name":{"first":"dded","last":"share"},"json_pet":"testing"} +{"body":"hello ghi","copied":{"first":"Root","last":"Joltie"},"desc":"domshello ghi","id":24,"json_age":"{\"json_id\":24,\"copied\":{\"first\":\"Root\",\"last\":\"Joltie\"},\"json_age\":3,\"json_name\":{\"first\":\"Root\",\"last\":\"Joltie\"},\"json_pet\":\"testing\",\"json_id_json_name\":\"24,{\\\"first\\\":\\\"Root\\\",\\\"last\\\":\\\"Joltie\\\"}\",\"body\":\"hello ghi\",\"desc\":\"domshello ghi\"}","json_id_json_name":"24,{\"first\":\"Root\",\"last\":\"Joltie\"}","json_name":{"first":"Root","last":"Joltie"},"json_pet":"testing"} \ No newline at end of file diff --git a/wrangler-transform/src/e2e-test/resources/BQValidationExpectedFiles/Directive_parse_xmltojson b/wrangler-transform/src/e2e-test/resources/BQValidationExpectedFiles/Directive_parse_xmltojson new file mode 100644 index 000000000..4a72c0069 --- /dev/null +++ b/wrangler-transform/src/e2e-test/resources/BQValidationExpectedFiles/Directive_parse_xmltojson @@ -0,0 +1,6 @@ +{"distance":2.0,"distance2":0.3571428656578064,"email":"abc01@mail.com","email_domain":{"distance":2.0,"email_account":"abc01"},"email_porter":["abc","mail","com"],"id":"1","xmldata_note":{"body":"Dont forget me this week!","from":"Tani","heading":"Reminder","to":"Tove"}} +{"distance":2.0,"distance2":0.3571428656578064,"email":"def02@mail.com","email_domain":{"distance":2.0,"email_account":"def02"},"email_porter":["def","mail","com"],"id":"2","xmldata_note":{"body":"Dont forget us this holiday!","from":"joy","heading":"Reminder","to":"Tove"}} +{"distance":2.0,"distance2":0.3571428656578064,"email":"abc01@mail.com","email_domain":{"distance":2.0,"email_account":"abc01"},"email_porter":["abc","mail","com"],"id":"abc","xmldata_note":{"body":"Dont forget me this week!","from":"Tani","heading":"Reminder","to":"Tove"}} +{"distance":2.0,"distance2":0.3571428656578064,"email":"ghi03@mail.com","email_domain":{"distance":2.0,"email_account":"ghi03"},"email_porter":["ghi","mail","com"],"id":"3","xmldata_note":{"body":"Dont forget him this weekend!","from":"shree","heading":"Reminder","to":"Tove"}} +{"distance":2.0,"distance2":0.3571428656578064,"email":"def02@mail.com","email_domain":{"distance":2.0,"email_account":"def02"},"email_porter":["def","mail","com"],"id":"def","xmldata_note":{"body":"Dont forget us this holiday!","from":"joy","heading":"Reminder","to":"Tove"}} +{"distance":2.0,"distance2":0.3571428656578064,"email":"ghi03@mail.com","email_domain":{"distance":2.0,"email_account":"ghi03"},"email_porter":["ghi","mail","com"],"id":"ghi","xmldata_note":{"body":"Dont forget him this weekend!","from":"shree","heading":"Reminder","to":"Tove"}} \ No newline at end of file diff --git a/wrangler-transform/src/e2e-test/resources/BQtesdata/BigQuery/BigQueryCreateTableQueryXml.txt b/wrangler-transform/src/e2e-test/resources/BQtesdata/BigQuery/BigQueryCreateTableQueryXml.txt new file mode 100644 index 000000000..a711921e2 --- /dev/null +++ b/wrangler-transform/src/e2e-test/resources/BQtesdata/BigQuery/BigQueryCreateTableQueryXml.txt @@ -0,0 +1 @@ +create table `DATASET.TABLE_NAME` (email STRING, xmldata STRING) diff --git a/wrangler-transform/src/e2e-test/resources/BQtesdata/BigQuery/BigQueryInsertDataQueryXml.txt b/wrangler-transform/src/e2e-test/resources/BQtesdata/BigQuery/BigQueryInsertDataQueryXml.txt new file mode 100644 index 000000000..0dc9608ce --- /dev/null +++ b/wrangler-transform/src/e2e-test/resources/BQtesdata/BigQuery/BigQueryInsertDataQueryXml.txt @@ -0,0 +1,5 @@ +INSERT INTO DATASET.TABLE_NAME (email,xmldata) +VALUES +('abc01@mail.com',' Tove Tani Reminder Dont forget me this week! '), +('def02@mail.com',' Tove joy Reminder Dont forget us this holiday! '), +('ghi03@mail.com',' Tove shree Reminder Dont forget him this weekend! '); diff --git a/wrangler-transform/src/e2e-test/resources/BQtesdata/BigQuery/BigQueryInsertDataQueryparsejson.txt b/wrangler-transform/src/e2e-test/resources/BQtesdata/BigQuery/BigQueryInsertDataQueryparsejson.txt new file mode 100644 index 000000000..dc9fa7d17 --- /dev/null +++ b/wrangler-transform/src/e2e-test/resources/BQtesdata/BigQuery/BigQueryInsertDataQueryparsejson.txt @@ -0,0 +1,6 @@ +INSERT INTO DATASET.TABLE_NAME (body,json) +VALUES +(' hello abc', '{"id": 1, "name": {"first": "Root", "last": "joy"}, "age": 22, "pet": "nick", "height": 5.8}'), +('hello def', '{"id": 2, "name": {"first": "dded", "last": "share"}, "age": 23, "pet": "hello", "height": 6.8}'), +('hello ghi', '{"id": 3, "name": {"first": "Root", "last": "Joltie"}, "age": 24, "pet": "doms", "height": 7.8}'); + diff --git a/wrangler-transform/src/e2e-test/resources/BQtesdata/BigQuery/BigQuerycreateTableQueryjson.txt b/wrangler-transform/src/e2e-test/resources/BQtesdata/BigQuery/BigQuerycreateTableQueryjson.txt new file mode 100644 index 000000000..be6b585ea --- /dev/null +++ b/wrangler-transform/src/e2e-test/resources/BQtesdata/BigQuery/BigQuerycreateTableQueryjson.txt @@ -0,0 +1 @@ +create table `DATASET.TABLE_NAME` (body STRING, json STRING) \ No newline at end of file diff --git a/wrangler-transform/src/e2e-test/resources/BQtesdata/BigQuery/test1.xlsx b/wrangler-transform/src/e2e-test/resources/BQtesdata/BigQuery/test1.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..adaa5291b024baf3415f6081d3fdca5369b6bbb8 GIT binary patch literal 5228 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