You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@beam.apache.org by pa...@apache.org on 2022/06/15 22:13:06 UTC

[beam] branch master updated: Add Spanner Integration tests to verify exception handling

This is an automated email from the ASF dual-hosted git repository.

pabloem 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 dbb8f99e8b1 Add Spanner Integration tests to verify exception handling
     new ac9a662aab5 Merge pull request #21748 from Add Spanner Integration tests to verify exception handling
dbb8f99e8b1 is described below

commit dbb8f99e8b14560efd3d1dfd7483c42b430b9004
Author: Niel Markwick <ni...@google.com>
AuthorDate: Wed Jun 8 17:06:34 2022 +0200

    Add Spanner Integration tests to verify exception handling
    
    Exceptions during read should abort the pipeline.
    Added 2 integration test cases.
    
    issue #21564
---
 .../beam/sdk/io/gcp/spanner/SpannerReadIT.java     | 77 +++++++++++++++++++++-
 1 file changed, 76 insertions(+), 1 deletion(-)

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 7740bc44558..e1ba6a43c0c 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
@@ -18,6 +18,7 @@
 package org.apache.beam.sdk.io.gcp.spanner;
 
 import com.google.api.gax.longrunning.OperationFuture;
+import com.google.cloud.spanner.BatchClient;
 import com.google.cloud.spanner.Database;
 import com.google.cloud.spanner.DatabaseAdminClient;
 import com.google.cloud.spanner.DatabaseClient;
@@ -40,8 +41,12 @@ import org.apache.beam.sdk.testing.PAssert;
 import org.apache.beam.sdk.testing.TestPipeline;
 import org.apache.beam.sdk.testing.TestPipelineOptions;
 import org.apache.beam.sdk.transforms.Count;
+import org.apache.beam.sdk.transforms.Create;
 import org.apache.beam.sdk.transforms.MapElements;
+import org.apache.beam.sdk.transforms.ParDo;
 import org.apache.beam.sdk.transforms.SerializableFunction;
+import org.apache.beam.sdk.transforms.SimpleFunction;
+import org.apache.beam.sdk.transforms.View;
 import org.apache.beam.sdk.values.PCollection;
 import org.apache.beam.sdk.values.PCollectionView;
 import org.apache.beam.sdk.values.TypeDescriptor;
@@ -50,6 +55,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
@@ -60,6 +66,7 @@ public class SpannerReadIT {
   private static final int MAX_DB_NAME_LENGTH = 30;
 
   @Rule public final transient TestPipeline p = TestPipeline.create();
+  @Rule public transient ExpectedException thrown = ExpectedException.none();
 
   /** Pipeline options for this test. */
   public interface SpannerTestPipelineOptions extends TestPipelineOptions {
@@ -129,6 +136,7 @@ public class SpannerReadIT {
                     + "  Value         STRING(MAX),"
                     + ") PRIMARY KEY (Key)"));
     op.get();
+    // PG-dialect databases need 2-steps to create: Create DB then update DDL.
     databaseAdminClient
         .createDatabase(
             databaseAdminClient
@@ -175,7 +183,74 @@ public class SpannerReadIT {
                 .withTransaction(tx));
     PAssert.thatSingleton(output.apply("Count rows", Count.<Struct>globally())).isEqualTo(5L);
 
-    p.run();
+    p.run().waitUntilFinish();
+  }
+
+  @Test
+  public void testReadFailsBadTable() throws Exception {
+
+    thrown.expect(new SpannerWriteIT.StackTraceContainsString("SpannerException"));
+    thrown.expect(new SpannerWriteIT.StackTraceContainsString("NOT_FOUND: Table not found"));
+
+    SpannerConfig spannerConfig = createSpannerConfig();
+
+    PCollectionView<Transaction> tx =
+        p.apply(
+            "Create tx",
+            SpannerIO.createTransaction()
+                .withSpannerConfig(spannerConfig)
+                .withTimestampBound(TimestampBound.strong()));
+    p.apply(
+        "read db",
+        SpannerIO.read()
+            .withSpannerConfig(spannerConfig)
+            .withTable("IncorrectTableName")
+            .withColumns("Key", "Value")
+            .withTransaction(tx));
+    p.run().waitUntilFinish();
+  }
+
+  private static class CloseTransactionFn extends SimpleFunction<Transaction, Transaction> {
+    private final SpannerConfig spannerConfig;
+
+    private CloseTransactionFn(SpannerConfig spannerConfig) {
+      this.spannerConfig = spannerConfig;
+    }
+
+    @Override
+    public Transaction apply(Transaction tx) {
+      BatchClient batchClient = SpannerAccessor.getOrCreate(spannerConfig).getBatchClient();
+      batchClient.batchReadOnlyTransaction(tx.transactionId()).cleanup();
+      return tx;
+    }
+  }
+
+  @Test
+  public void testReadFailsBadSession() throws Exception {
+
+    thrown.expect(new SpannerWriteIT.StackTraceContainsString("SpannerException"));
+    thrown.expect(new SpannerWriteIT.StackTraceContainsString("NOT_FOUND: Session not found"));
+
+    SpannerConfig spannerConfig = createSpannerConfig();
+
+    // This creates a transaction then closes the session.
+    // The (closed) transaction is then passed to SpannerIO.read() and should
+    // raise SessionNotFound errors.
+    PCollectionView<Transaction> tx =
+        p.apply("Transaction seed", Create.of(1))
+            .apply(
+                "Create transaction",
+                ParDo.of(new CreateTransactionFn(spannerConfig, TimestampBound.strong())))
+            .apply("Close Transaction", MapElements.via(new CloseTransactionFn(spannerConfig)))
+            .apply("As PCollectionView", View.asSingleton());
+    p.apply(
+        "read db",
+        SpannerIO.read()
+            .withSpannerConfig(spannerConfig)
+            .withTable(options.getTable())
+            .withColumns("Key", "Value")
+            .withTransaction(tx));
+    p.run().waitUntilFinish();
   }
 
   @Test