This is an automated email from the ASF dual-hosted git repository.
reuvenlax pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/beam.git
The following commit(s) were added to refs/heads/master by this push:
new de8d83c107d Merge pull request #40259 from
reuvenlax/improve_gcp_presubmit_speed
de8d83c107d is described below
commit de8d83c107d6af6df3cb24769650b537c98cf812
Author: Reuven Lax <[email protected]>
AuthorDate: Fri Sep 25 15:48:48 2026 -0700
Merge pull request #40259 from reuvenlax/improve_gcp_presubmit_speed
Speed up Beam presubmits
---
.../beam_PreCommit_Java_GCP_IO_Direct.yml | 48 ++++----
sdks/java/io/google-cloud-platform/build.gradle | 128 +++++++++++++--------
.../BigQueryIOWriteStorageApiBatchTest.java | 35 ++++++
.../BigQueryIOWriteStorageApiStreamTest.java | 35 ++++++
.../sdk/io/gcp/bigquery/BigQueryIOWriteTest.java | 9 +-
.../dofn/ReadChangeStreamPartitionDoFnTest.java | 14 ++-
.../beam/sdk/io/gcp/spanner/SpannerReadIT.java | 52 +++++----
.../beam/sdk/io/gcp/spanner/SpannerWriteIT.java | 57 +++++----
.../changestreams/it/IntegrationTestEnv.java | 80 +++++++------
9 files changed, 289 insertions(+), 169 deletions(-)
diff --git a/.github/workflows/beam_PreCommit_Java_GCP_IO_Direct.yml
b/.github/workflows/beam_PreCommit_Java_GCP_IO_Direct.yml
index 9ebb56b76d5..3e2c9c16248 100644
--- a/.github/workflows/beam_PreCommit_Java_GCP_IO_Direct.yml
+++ b/.github/workflows/beam_PreCommit_Java_GCP_IO_Direct.yml
@@ -82,9 +82,26 @@ jobs:
beam_PreCommit_Java_GCP_IO_Direct:
name: ${{ matrix.job_name }} (${{ matrix.job_phrase }})
strategy:
+ fail-fast: false
matrix:
- job_name: ["beam_PreCommit_Java_GCP_IO_Direct"]
- job_phrase: ["Run Java_GCP_IO_Direct PreCommit"]
+ include:
+ - job_name: "beam_PreCommit_Java_GCP_IO_Direct"
+ job_phrase: "Run Java_GCP_IO_Direct PreCommit"
+ gradle_command: |
+ :sdks:java:io:google-cloud-platform:build \
+ :sdks:java:io:google-cloud-platform:expansion-service:build \
+ extra_arguments: ""
+ is_build_job: true
+ - job_name: "beam_PreCommit_Java_GCP_IO_Direct_BigQuery"
+ job_phrase: "Run Java_GCP_IO_Direct PreCommit"
+ gradle_command:
":sdks:java:io:google-cloud-platform:postCommitBigQuery"
+ extra_arguments: "-x test"
+ is_build_job: false
+ - job_name: "beam_PreCommit_Java_GCP_IO_Direct_OtherGCP"
+ job_phrase: "Run Java_GCP_IO_Direct PreCommit"
+ gradle_command:
":sdks:java:io:google-cloud-platform:postCommitOtherGcp"
+ extra_arguments: "-x test"
+ is_build_job: false
timeout-minutes: 180
if: |
github.event_name == 'push' ||
@@ -108,19 +125,16 @@ jobs:
- name: run PreCommit Java GCP IO Direct script
uses: ./.github/actions/gradle-command-self-hosted-action
with:
- gradle-command: |
- :sdks:java:io:google-cloud-platform:build \
- :sdks:java:io:google-cloud-platform:expansion-service:build \
- :sdks:java:io:google-cloud-platform:postCommit \
+ gradle-command: ${{ matrix.gradle_command }}
arguments: |
-PdisableSpotlessCheck=true \
-PdisableCheckStyle=true \
- -PenableJacocoReport \
+ ${{ matrix.extra_arguments }}
- name: Archive JUnit Test Results
uses: actions/upload-artifact@v7
if: ${{ !success() }}
with:
- name: JUnit Test Results
+ name: JUnit Test Results (${{ matrix.job_name }})
path: "**/build/reports/tests/"
- name: Publish JUnit Test Results
uses: EnricoMi/publish-unit-test-result-action@v2
@@ -132,27 +146,13 @@ jobs:
large_files: true
- name: Archive SpotBugs Results
uses: actions/upload-artifact@v7
- if: always()
+ if: ${{ always() && matrix.is_build_job }}
with:
name: SpotBugs Results
path: '**/build/reports/spotbugs/*.html'
- name: Publish SpotBugs Results
uses: jwgmeligmeyling/[email protected]
- if: always()
+ if: ${{ always() && matrix.is_build_job }}
with:
name: Publish SpotBugs
path: '**/build/reports/spotbugs/*.html'
- - name: Set Jacoco report path
- id: jacoco_report_path
- run: |
- echo
"path=sdks/java/io/google-cloud-platform/build/reports/jacoco/test/jacocoTestReport.xml"
>> $GITHUB_OUTPUT
- - name: Archive Jacoco Results
- uses: actions/upload-artifact@v7
- with:
- name: Jacoco Results
- path: '**/build/jacoco/report/**'
- - name: Upload coverage reports to Codecov
- uses: codecov/codecov-action@v3
- with:
- file: ${{ steps.jacoco_report_path.outputs.path }}
- flags: java
diff --git a/sdks/java/io/google-cloud-platform/build.gradle
b/sdks/java/io/google-cloud-platform/build.gradle
index ff648b4f903..b1ad17c006d 100644
--- a/sdks/java/io/google-cloud-platform/build.gradle
+++ b/sdks/java/io/google-cloud-platform/build.gradle
@@ -33,6 +33,14 @@ ext.summary = "IO library to read and write Google Cloud
Platform systems from B
tasks.withType(Test).configureEach {
// Open java.nio for Apache Arrow direct memory access under Java 17+
jvmArgs '--add-opens=java.base/java.nio=ALL-UNNAMED'
+ maxParallelForks 4
+ jacoco.enabled = false
+}
+
+gradle.taskGraph.whenReady {
+ tasks.withType(Test).configureEach {
+ jacoco.enabled = false
+ }
}
dependencies {
@@ -328,62 +336,86 @@ task bigQueryEarlyRolloutIntegrationTest(type: Test,
dependsOn: processTestResou
testClassesDirs = sourceSets.test.output.classesDirs
}
-// path(s) for Cloud Spanner related classes
-def spannerIncludes = [
- '**/org/apache/beam/sdk/io/gcp/spanner/**',
-]
-
-// exclude auto-generated classes and integration tests
-def jacocoExcludes = [
- '**/AutoValue_*',
- '**/*IT*',
-]
-
-task spannerCodeCoverageReport(type: JacocoReport, dependsOn: test) {
- group = "Reporting"
- description = "Generates code coverage report for Cloud Spanner related
classes"
- classDirectories.setFrom(files(files(project.sourceSets.main.output).collect
{
- project.fileTree(
- dir: it,
- includes: spannerIncludes,
- excludes: jacocoExcludes)
- }))
- sourceDirectories.setFrom(files(project.sourceSets.main.allSource.srcDirs))
- executionData.setFrom(file("${buildDir}/jacoco/test.exec"))
- reports {
- html.getRequired().set(true)
- html.getOutputLocation().set(file("${buildDir}/reports/jacoco/spanner/"))
+task integrationTestBigQuery(type: Test, dependsOn: processTestResources) {
+ group = "Verification"
+ systemProperty "beamTestPipelineOptions",
integrationTest.systemProperties["beamTestPipelineOptions"]
+ outputs.upToDateWhen { false }
+ include '**/bigquery/**/*IT.class'
+ exclude '**/BigQueryIOIcebergManagedTableIT.class'
+ exclude '**/BigQueryIOReadIT.class'
+ exclude '**/BigQueryIOStorageQueryIT.class'
+ exclude '**/BigQueryIOStorageReadIT.class'
+ exclude '**/BigQueryIOStorageWriteIT.class'
+ exclude '**/BigQueryIODynamicQueryIT.class'
+ exclude '**/BigQueryIODynamicReadIT.class'
+ exclude '**/BigQueryToTableIT.class'
+ maxParallelForks 4
+ classpath = sourceSets.test.runtimeClasspath
+ testClassesDirs = sourceSets.test.output.classesDirs
+ useJUnit {
+ excludeCategories "org.apache.beam.sdk.testing.UsesKms"
+ }
+}
+
+task integrationTestBigQueryKms(type: Test, dependsOn: processTestResources) {
+ group = "Verification"
+ systemProperty "beamTestPipelineOptions",
integrationTestKms.systemProperties["beamTestPipelineOptions"]
+ outputs.upToDateWhen { false }
+ include '**/bigquery/**/*IT.class'
+ maxParallelForks 4
+ classpath = sourceSets.test.runtimeClasspath
+ testClassesDirs = sourceSets.test.output.classesDirs
+ useJUnit {
+ includeCategories "org.apache.beam.sdk.testing.UsesKms"
}
}
-task spannerCodeCoverageVerification(type: JacocoCoverageVerification,
dependsOn: spannerCodeCoverageReport) {
+task integrationTestOtherGcp(type: Test, dependsOn: processTestResources) {
group = "Verification"
- description = "Enforces code coverage verification for Cloud Spanner related
classes"
- classDirectories.setFrom(files(files(project.sourceSets.main.output).collect
{
- project.fileTree(
- dir: it,
- includes: spannerIncludes,
- excludes: jacocoExcludes)
- }))
- sourceDirectories.setFrom(files(project.sourceSets.main.allSource.srcDirs))
- executionData.setFrom(file("${buildDir}/jacoco/test.exec"))
- violationRules {
- failOnViolation = true
- rule {
- element = 'BUNDLE'
-
- limit {
- value = 'COVEREDRATIO'
- counter = 'INSTRUCTION'
- minimum = 0.60
- }
+ systemProperty "beamTestPipelineOptions",
integrationTest.systemProperties["beamTestPipelineOptions"]
+ outputs.upToDateWhen { false }
+ include '**/*IT.class'
+ exclude '**/bigquery/**/*IT.class'
+ maxParallelForks 4
+ classpath = sourceSets.test.runtimeClasspath
+ testClassesDirs = sourceSets.test.output.classesDirs
+ useJUnit {
+ excludeCategories "org.apache.beam.sdk.testing.UsesKms"
+ filter {
+ // https://github.com/apache/beam/issues/32071
+ excludeTestsMatching
'org.apache.beam.sdk.io.gcp.bigtable.BigtableReadIT.testE2EBigtableSegmentRead'
}
}
}
-// make the check task depend on spannerCodeCoverageVerification so that the
build
-// fails when the code coverage threshold is violated.
-project.check.dependsOn "spannerCodeCoverageVerification"
+task integrationTestOtherGcpKms(type: Test, dependsOn: processTestResources) {
+ group = "Verification"
+ systemProperty "beamTestPipelineOptions",
integrationTestKms.systemProperties["beamTestPipelineOptions"]
+ outputs.upToDateWhen { false }
+ include '**/*IT.class'
+ exclude '**/bigquery/**/*IT.class'
+ maxParallelForks 4
+ classpath = sourceSets.test.runtimeClasspath
+ testClassesDirs = sourceSets.test.output.classesDirs
+ useJUnit {
+ includeCategories "org.apache.beam.sdk.testing.UsesKms"
+ }
+}
+
+task postCommitBigQuery {
+ group = "Verification"
+ description = "Integration tests of BigQuery connectors using the
DirectRunner."
+ dependsOn integrationTestBigQuery
+ dependsOn integrationTestBigQueryKms
+ dependsOn bigQueryManagedIcebergIntegrationTest
+}
+
+task postCommitOtherGcp {
+ group = "Verification"
+ description = "Integration tests of non-BigQuery GCP connectors using the
DirectRunner."
+ dependsOn integrationTestOtherGcp
+ dependsOn integrationTestOtherGcpKms
+}
task postCommit {
group = "Verification"
diff --git
a/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryIOWriteStorageApiBatchTest.java
b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryIOWriteStorageApiBatchTest.java
new file mode 100644
index 00000000000..1fe6bd350fc
--- /dev/null
+++
b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryIOWriteStorageApiBatchTest.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.beam.sdk.io.gcp.bigquery;
+
+import
org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.collect.ImmutableList;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * Runs {@link BigQueryIOWriteTest} for Storage Write API batch mode in a
separate test class so
+ * Gradle {@code maxParallelForks} can execute it in parallel with other modes.
+ */
+@RunWith(Parameterized.class)
+public class BigQueryIOWriteStorageApiBatchTest extends BigQueryIOWriteTest {
+ @Parameters(name = "useStorageApi={0}, useStorageApiApproximate={1},
useStreaming={2}")
+ public static Iterable<Object[]> data() {
+ return ImmutableList.of(new Object[] {true, false, false});
+ }
+}
diff --git
a/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryIOWriteStorageApiStreamTest.java
b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryIOWriteStorageApiStreamTest.java
new file mode 100644
index 00000000000..3fff3bd31ae
--- /dev/null
+++
b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryIOWriteStorageApiStreamTest.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.beam.sdk.io.gcp.bigquery;
+
+import
org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.collect.ImmutableList;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * Runs {@link BigQueryIOWriteTest} for Storage Write API streaming modes in a
separate test class
+ * so Gradle {@code maxParallelForks} can execute them in parallel with other
modes.
+ */
+@RunWith(Parameterized.class)
+public class BigQueryIOWriteStorageApiStreamTest extends BigQueryIOWriteTest {
+ @Parameters(name = "useStorageApi={0}, useStorageApiApproximate={1},
useStreaming={2}")
+ public static Iterable<Object[]> data() {
+ return ImmutableList.of(new Object[] {true, false, true}, new Object[]
{true, true, true});
+ }
+}
diff --git
a/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryIOWriteTest.java
b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryIOWriteTest.java
index fdfd2699236..62e57ec848c 100644
---
a/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryIOWriteTest.java
+++
b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryIOWriteTest.java
@@ -229,14 +229,9 @@ public class BigQueryIOWriteTest implements Serializable {
private transient TemporaryFolder testFolder = new TemporaryFolder();
private transient TestPipeline p;
- @Parameters
+ @Parameters(name = "useStorageApi={0}, useStorageApiApproximate={1},
useStreaming={2}")
public static Iterable<Object[]> data() {
- return ImmutableList.of(
- new Object[] {false, false, false},
- new Object[] {false, false, true},
- new Object[] {true, false, false},
- new Object[] {true, false, true},
- new Object[] {true, true, true});
+ return ImmutableList.of(new Object[] {false, false, false}, new Object[]
{false, false, true});
}
@Parameter(0)
diff --git
a/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/bigtable/changestreams/dofn/ReadChangeStreamPartitionDoFnTest.java
b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/bigtable/changestreams/dofn/ReadChangeStreamPartitionDoFnTest.java
index 49540e20594..f157eea476a 100644
---
a/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/bigtable/changestreams/dofn/ReadChangeStreamPartitionDoFnTest.java
+++
b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/bigtable/changestreams/dofn/ReadChangeStreamPartitionDoFnTest.java
@@ -103,8 +103,13 @@ public class ReadChangeStreamPartitionDoFnTest {
@Test
public void testProcessElementAndGetSize() throws IOException,
InterruptedException {
+ Instant now = Instant.now();
+ doFn =
+ new ReadChangeStreamPartitionDoFn(
+ daoFactory, actionFactory, metrics, Duration.ZERO, () -> now);
+ doFn.setSizeEstimator(sizeEstimator);
long watermarkLag = 10;
- Instant tenSecondsAgo =
Instant.now().minus(Duration.standardSeconds(watermarkLag));
+ Instant tenSecondsAgo = now.minus(Duration.standardSeconds(watermarkLag));
Range.ByteStringRange partitionRange = Range.ByteStringRange.create("",
"");
ChangeStreamContinuationToken testToken =
ChangeStreamContinuationToken.create(partitionRange, "test");
@@ -115,7 +120,7 @@ public class ReadChangeStreamPartitionDoFnTest {
"uid-a",
tenSecondsAgo,
Collections.emptyList(),
- Instant.now().plus(Duration.standardSeconds(60)));
+ now.plus(Duration.standardSeconds(60)));
long mutationSize = 100L;
when(sizeEstimator.sizeOf(any())).thenReturn(mutationSize);
ReadChangeStreamPartitionProgressTracker restrictionTracker =
@@ -149,11 +154,10 @@ public class ReadChangeStreamPartitionDoFnTest {
doFn.processElement(partition, restrictionTracker, receiver,
watermarkEstimator);
double sizeEstimate =
doFn.getSize(
- new StreamProgress(
- testToken, tenSecondsAgo, BigDecimal.valueOf(20),
Instant.now(), false));
+ new StreamProgress(testToken, tenSecondsAgo,
BigDecimal.valueOf(20), now, false));
// we should have output 2 100B mutations in the past 10s
long bytesPerSecond = (mutationSize * 2) / 10;
- assertEquals(sizeEstimate, (double) (bytesPerSecond * watermarkLag), 10);
+ assertEquals((double) (bytesPerSecond * watermarkLag), sizeEstimate, 10);
verify(receiver, times(2)).outputWithTimestamp(KV.of(rowKey,
mockMutation), Instant.EPOCH);
}
diff --git
a/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/spanner/SpannerReadIT.java
b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/spanner/SpannerReadIT.java
index 247f403e252..988a56aa113 100644
---
a/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/spanner/SpannerReadIT.java
+++
b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/spanner/SpannerReadIT.java
@@ -51,8 +51,8 @@ import org.apache.beam.sdk.values.PCollectionView;
import org.apache.beam.sdk.values.TypeDescriptor;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.joda.time.Duration;
-import org.junit.After;
-import org.junit.Before;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
@@ -96,15 +96,15 @@ public class SpannerReadIT {
void setTable(String value);
}
- private Spanner spanner;
- private DatabaseAdminClient databaseAdminClient;
- private SpannerTestPipelineOptions options;
- private String databaseName;
- private String pgDatabaseName;
- private String project;
+ private static Spanner spanner;
+ private static DatabaseAdminClient databaseAdminClient;
+ private static SpannerTestPipelineOptions options;
+ private static String databaseName;
+ private static String pgDatabaseName;
+ private static String project;
- @Before
- public void setUp() throws Exception {
+ @BeforeClass
+ public static void setUpTestEnvironment() throws Exception {
PipelineOptionsFactory.register(SpannerTestPipelineOptions.class);
options =
TestPipeline.testingPipelineOptions().as(SpannerTestPipelineOptions.class);
@@ -142,16 +142,16 @@ public class SpannerReadIT {
+ " Key INT64,"
+ " Value STRING(MAX),"
+ ") PRIMARY KEY (Key)"));
- op.get();
// PG-dialect databases need 2-steps to create: Create DB then update DDL.
- databaseAdminClient
- .createDatabase(
+ OperationFuture<Database, CreateDatabaseMetadata> pgOp =
+ databaseAdminClient.createDatabase(
databaseAdminClient
.newDatabaseBuilder(DatabaseId.of(project,
options.getInstanceId(), pgDatabaseName))
.setDialect(Dialect.POSTGRESQL)
.build(),
- Collections.emptyList())
- .get();
+ Collections.emptyList());
+ op.get();
+ pgOp.get();
databaseAdminClient
.updateDatabaseDdl(
options.getInstanceId(),
@@ -461,7 +461,7 @@ public class SpannerReadIT {
p.run();
}
- private void makeTestData() {
+ private static void makeTestData() {
DatabaseClient databaseClient = getDatabaseClient();
DatabaseClient pgDatabaseClient = getPgDatabaseClient();
@@ -496,23 +496,27 @@ public class SpannerReadIT {
.withDatabaseId(pgDatabaseName));
}
- private DatabaseClient getDatabaseClient() {
+ private static DatabaseClient getDatabaseClient() {
return spanner.getDatabaseClient(DatabaseId.of(project,
options.getInstanceId(), databaseName));
}
- private DatabaseClient getPgDatabaseClient() {
+ private static DatabaseClient getPgDatabaseClient() {
return spanner.getDatabaseClient(
DatabaseId.of(project, options.getInstanceId(), pgDatabaseName));
}
- @After
- public void tearDown() throws Exception {
- databaseAdminClient.dropDatabase(options.getInstanceId(), databaseName);
- databaseAdminClient.dropDatabase(options.getInstanceId(), pgDatabaseName);
- spanner.close();
+ @AfterClass
+ public static void tearDown() throws Exception {
+ if (databaseAdminClient != null) {
+ databaseAdminClient.dropDatabase(options.getInstanceId(), databaseName);
+ databaseAdminClient.dropDatabase(options.getInstanceId(),
pgDatabaseName);
+ }
+ if (spanner != null) {
+ spanner.close();
+ }
}
- private String generateDatabaseName() {
+ private static String generateDatabaseName() {
String random =
RandomUtils.randomAlphaNumeric(
MAX_DB_NAME_LENGTH - 4 - options.getDatabaseIdPrefix().length());
diff --git
a/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/spanner/SpannerWriteIT.java
b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/spanner/SpannerWriteIT.java
index 89c2a194b93..318237e1118 100644
---
a/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/spanner/SpannerWriteIT.java
+++
b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/spanner/SpannerWriteIT.java
@@ -28,6 +28,7 @@ import com.google.cloud.spanner.Database;
import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.Dialect;
+import com.google.cloud.spanner.KeySet;
import com.google.cloud.spanner.Mutation;
import com.google.cloud.spanner.ResultSet;
import com.google.cloud.spanner.SessionPoolOptions;
@@ -61,8 +62,9 @@ import
org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.base.Predicate
import
org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.base.Throwables;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.hamcrest.TypeSafeMatcher;
-import org.junit.After;
+import org.junit.AfterClass;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
@@ -105,15 +107,15 @@ public class SpannerWriteIT {
void setTable(String value);
}
- private Spanner spanner;
- private DatabaseAdminClient databaseAdminClient;
- private SpannerTestPipelineOptions options;
- private String databaseName;
- private String pgDatabaseName;
- private String project;
+ private static Spanner spanner;
+ private static DatabaseAdminClient databaseAdminClient;
+ private static SpannerTestPipelineOptions options;
+ private static String databaseName;
+ private static String pgDatabaseName;
+ private static String project;
- @Before
- public void setUp() throws Exception {
+ @BeforeClass
+ public static void setUpTestEnvironment() throws Exception {
PipelineOptionsFactory.register(SpannerTestPipelineOptions.class);
options =
TestPipeline.testingPipelineOptions().as(SpannerTestPipelineOptions.class);
@@ -152,15 +154,15 @@ public class SpannerWriteIT {
+ " Key INT64,"
+ " Value STRING(MAX) NOT NULL,"
+ ") PRIMARY KEY (Key)"));
- op.get();
- databaseAdminClient
- .createDatabase(
+ OperationFuture<Database, CreateDatabaseMetadata> pgOp =
+ databaseAdminClient.createDatabase(
databaseAdminClient
.newDatabaseBuilder(DatabaseId.of(project,
options.getInstanceId(), pgDatabaseName))
.setDialect(Dialect.POSTGRESQL)
.build(),
- Collections.emptyList())
- .get();
+ Collections.emptyList());
+ op.get();
+ pgOp.get();
databaseAdminClient
.updateDatabaseDdl(
options.getInstanceId(),
@@ -176,7 +178,18 @@ public class SpannerWriteIT {
.get();
}
- private String generateDatabaseName() {
+ @Before
+ public void setUp() {
+ Mutation deleteAll = Mutation.delete(options.getTable(), KeySet.all());
+ spanner
+ .getDatabaseClient(DatabaseId.of(project, options.getInstanceId(),
databaseName))
+ .writeAtLeastOnce(Collections.singletonList(deleteAll));
+ spanner
+ .getDatabaseClient(DatabaseId.of(project, options.getInstanceId(),
pgDatabaseName))
+ .writeAtLeastOnce(Collections.singletonList(deleteAll));
+ }
+
+ private static String generateDatabaseName() {
String random =
RandomUtils.randomAlphaNumeric(
MAX_DB_NAME_LENGTH - 4 - options.getDatabaseIdPrefix().length());
@@ -390,11 +403,15 @@ public class SpannerWriteIT {
result.waitUntilFinish();
}
- @After
- public void tearDown() throws Exception {
- databaseAdminClient.dropDatabase(options.getInstanceId(), databaseName);
- databaseAdminClient.dropDatabase(options.getInstanceId(), pgDatabaseName);
- spanner.close();
+ @AfterClass
+ public static void tearDown() throws Exception {
+ if (databaseAdminClient != null) {
+ databaseAdminClient.dropDatabase(options.getInstanceId(), databaseName);
+ databaseAdminClient.dropDatabase(options.getInstanceId(),
pgDatabaseName);
+ }
+ if (spanner != null) {
+ spanner.close();
+ }
}
private static class GenerateMutations extends DoFn<Long, Mutation> {
diff --git
a/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/spanner/changestreams/it/IntegrationTestEnv.java
b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/spanner/changestreams/it/IntegrationTestEnv.java
index b00568f8d40..3571a417cf0 100644
---
a/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/spanner/changestreams/it/IntegrationTestEnv.java
+++
b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/spanner/changestreams/it/IntegrationTestEnv.java
@@ -119,52 +119,50 @@ public class IntegrationTestEnv extends ExternalResource {
@Override
protected void after() {
- for (String changeStream : changeStreams) {
- try {
- if (this.isPostgres) {
- databaseAdminClient
- .updateDatabaseDdl(
- instanceId,
- databaseId,
- Collections.singletonList("DROP CHANGE STREAM \"" +
changeStream + "\""),
- null)
- .get(TIMEOUT_MINUTES, TimeUnit.MINUTES);
- } else {
- databaseAdminClient
- .updateDatabaseDdl(
- instanceId,
- databaseId,
- Collections.singletonList("DROP CHANGE STREAM " +
changeStream),
- null)
- .get(TIMEOUT_MINUTES, TimeUnit.MINUTES);
+ if (isPlacementTable) {
+ for (String changeStream : changeStreams) {
+ try {
+ if (this.isPostgres) {
+ databaseAdminClient
+ .updateDatabaseDdl(
+ instanceId,
+ databaseId,
+ Collections.singletonList("DROP CHANGE STREAM \"" +
changeStream + "\""),
+ null)
+ .get(TIMEOUT_MINUTES, TimeUnit.MINUTES);
+ } else {
+ databaseAdminClient
+ .updateDatabaseDdl(
+ instanceId,
+ databaseId,
+ Collections.singletonList("DROP CHANGE STREAM " +
changeStream),
+ null)
+ .get(TIMEOUT_MINUTES, TimeUnit.MINUTES);
+ }
+ } catch (Exception e) {
+ LOG.error("Failed to drop change stream {}. Skipping...",
changeStream, e);
}
- } catch (Exception e) {
- LOG.error("Failed to drop change stream {}. Skipping...",
changeStream, e);
}
- }
- for (String table : tables) {
- try {
- if (this.isPostgres) {
- databaseAdminClient
- .updateDatabaseDdl(
- instanceId,
- databaseId,
- Collections.singletonList("DROP TABLE \"" + table + "\""),
- null)
- .get(TIMEOUT_MINUTES, TimeUnit.MINUTES);
- } else {
- databaseAdminClient
- .updateDatabaseDdl(
- instanceId, databaseId, Collections.singletonList("DROP
TABLE " + table), null)
- .get(TIMEOUT_MINUTES, TimeUnit.MINUTES);
- }
- } catch (Exception e) {
- if (isPlacementTable) {
+ for (String table : tables) {
+ try {
+ if (this.isPostgres) {
+ databaseAdminClient
+ .updateDatabaseDdl(
+ instanceId,
+ databaseId,
+ Collections.singletonList("DROP TABLE \"" + table + "\""),
+ null)
+ .get(TIMEOUT_MINUTES, TimeUnit.MINUTES);
+ } else {
+ databaseAdminClient
+ .updateDatabaseDdl(
+ instanceId, databaseId, Collections.singletonList("DROP
TABLE " + table), null)
+ .get(TIMEOUT_MINUTES, TimeUnit.MINUTES);
+ }
+ } catch (Exception e) {
// Drop placement table requires all rows deleted and garbage
collected.
LOG.info("Failed to drop table {}. Skipping...", table, e);
- } else {
- LOG.error("Failed to drop table {}. Skipping...", table, e);
}
}
}