Merge "Allow to run the tests using real spanner instance"
diff --git a/src/main/java/com/googlesource/gerrit/plugins/spannerrefdb/Module.java b/src/main/java/com/googlesource/gerrit/plugins/spannerrefdb/Module.java
index bffb112..9590546 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/spannerrefdb/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/spannerrefdb/Module.java
@@ -16,6 +16,7 @@
import com.gerritforge.gerrit.globalrefdb.GlobalRefDatabase;
import com.google.auth.oauth2.GoogleCredentials;
+import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.DatabaseClient;
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.SpannerOptions;
@@ -86,6 +87,12 @@
@Provides
@Singleton
+ public DatabaseAdminClient createDbAdminClient(SpannerOptions options) {
+ return options.getService().getDatabaseAdminClient();
+ }
+
+ @Provides
+ @Singleton
public DatabaseClient createDatabaseClient(Config cfg, SpannerOptions options) {
return options.getService().getDatabaseClient(createDatabaseId(cfg, options));
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/spannerrefdb/SpannerLifeCycleManager.java b/src/main/java/com/googlesource/gerrit/plugins/spannerrefdb/SpannerLifeCycleManager.java
index 5783857..f841ff7 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/spannerrefdb/SpannerLifeCycleManager.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/spannerrefdb/SpannerLifeCycleManager.java
@@ -20,7 +20,6 @@
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.ErrorCode;
import com.google.cloud.spanner.SpannerException;
-import com.google.cloud.spanner.SpannerOptions;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.inject.Inject;
@@ -36,8 +35,8 @@
private DatabaseId dbId;
@Inject
- SpannerLifeCycleManager(SpannerOptions options, DatabaseId dbId) {
- this.dbAdminClient = options.getService().getDatabaseAdminClient();
+ SpannerLifeCycleManager(DatabaseAdminClient dbAdminClient, DatabaseId dbId) {
+ this.dbAdminClient = dbAdminClient;
this.dbId = dbId;
}
diff --git a/src/main/resources/Documentation/build.md b/src/main/resources/Documentation/build.md
index 60dac2b..a816e2b 100644
--- a/src/main/resources/Documentation/build.md
+++ b/src/main/resources/Documentation/build.md
@@ -33,15 +33,47 @@
## Run tests
-To execute the tests run
+The tests require a spanner service where the refdb will be created. The spanner
+service may be a real spanner service in GCP or a locally running docker based
+emulator.
+
+### Running tests using a real spanner service
+
+In this case we have to provide an GCP service account key and the instance name
+under which the test refdb will be created. This is done by passing two
+environment variables `SERVICE_ACCOUNT_KEY_PATH` and `SPANNER_INSTANCE`:
```
-bazelisk test --test_tag_filters=@PLUGIN@ //...
+bazelisk test \
+ --test_env='SERVICE_ACCOUNT_KEY_PATH=/path/to/the/key.json' \
+ --test_env='SPANNER_INSTANCE=test-instance' \
+ --test_tag_filters=@PLUGIN@ //...
```
-or
+
+Note that instead of using the `--test_tag_filters=@PLUGIN@ //...` we can also
+pass a different test target `//plugins/@PLUGIN@/...`:
+
+```
+bazelisk test \
+ --test_env='SERVICE_ACCOUNT_KEY_PATH=/path/to/the/key.json' \
+ --test_env='SPANNER_INSTANCE=test-instance' \
+ //plugins/@PLUGIN@/...
+```
+
+### Running tests using a local docker based spanner emulator
+
+This use case requires docker to be installed and running on the machine running
+the tests. A container running spanner will be created automatically by the
+tests.
+
+The absence of the `SERVICE_ACCOUNT_KEY_PATH` env variable means that the tests
+will create local spanner emulator.
+
```
bazelisk test //plugins/@PLUGIN@/...
-```
+
+
+### MacOS specifics when using docker based spanner emulator
On MacOS you may need to access the docker daemon via TCP.
diff --git a/src/test/java/com/googlesource/gerrit/plugins/spannerrefdb/EmulatedSpannerRefDb.java b/src/test/java/com/googlesource/gerrit/plugins/spannerrefdb/EmulatedSpannerRefDb.java
index 4ed2b90..aa2dd6b 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/spannerrefdb/EmulatedSpannerRefDb.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/spannerrefdb/EmulatedSpannerRefDb.java
@@ -35,7 +35,7 @@
import org.testcontainers.utility.DockerImageName;
@Ignore
-public class EmulatedSpannerRefDb {
+public class EmulatedSpannerRefDb extends SpannerTestSystem {
public static final String PROJECT_ID = "test";
public static final String SPANNER_INSTANCE_ID = "spanner-instance";
public static final String SPANNER_DATABASE_ID = "global-refdb";
@@ -82,11 +82,22 @@
spannerRefDb = new SpannerRefDatabase(databaseClient, lockFactory);
}
- private void createSchema() {
- SpannerLifeCycleManager lcm = new SpannerLifeCycleManager(spannerOptions, dbId);
- lcm.start();
+ @Override
+ void reset() throws Exception {
+ // do nothing, a new container is created for each instance of this class
}
+ @Override
+ SpannerRefDatabase database() {
+ return spannerRefDb;
+ }
+
+ @Override
+ DatabaseClient dbClient() {
+ return databaseClient;
+ }
+
+ @Override
public void cleanup() {
heartbeatExecutor.shutdownNow();
try {
@@ -102,6 +113,12 @@
System.out.println("Spanner emulator container was stopped");
}
+ private void createSchema() {
+ SpannerLifeCycleManager lcm =
+ new SpannerLifeCycleManager(spannerOptions.getService().getDatabaseAdminClient(), dbId);
+ lcm.start();
+ }
+
public SpannerEmulatorContainer getContainer() {
return container;
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/spannerrefdb/LockTest.java b/src/test/java/com/googlesource/gerrit/plugins/spannerrefdb/LockTest.java
index 4f03f64..fb1eec5 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/spannerrefdb/LockTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/spannerrefdb/LockTest.java
@@ -35,7 +35,7 @@
import org.junit.Test;
public class LockTest implements RefFixture {
- private EmulatedSpannerRefDb emulator;
+ private SpannerTestSystem testSystem;
private SpannerRefDatabase refDb;
private DatabaseClient dbClient;
@@ -44,14 +44,14 @@
@Before
public void setUp() throws Exception {
- emulator = new EmulatedSpannerRefDb();
- refDb = emulator.getSpannerRefDatabase();
- dbClient = emulator.getDatabaseClient();
+ testSystem = SpannerTestSystem.create();
+ refDb = testSystem.database();
+ dbClient = testSystem.dbClient();
}
@After
public void tearDown() {
- emulator.cleanup();
+ testSystem.cleanup();
}
@Test
diff --git a/src/test/java/com/googlesource/gerrit/plugins/spannerrefdb/RealSpannerRefDb.java b/src/test/java/com/googlesource/gerrit/plugins/spannerrefdb/RealSpannerRefDb.java
new file mode 100644
index 0000000..6635ac6
--- /dev/null
+++ b/src/test/java/com/googlesource/gerrit/plugins/spannerrefdb/RealSpannerRefDb.java
@@ -0,0 +1,133 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// 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 com.googlesource.gerrit.plugins.spannerrefdb;
+
+import com.google.auth.oauth2.GoogleCredentials;
+import com.google.cloud.spanner.Database;
+import com.google.cloud.spanner.DatabaseAdminClient;
+import com.google.cloud.spanner.DatabaseClient;
+import com.google.cloud.spanner.DatabaseId;
+import com.google.cloud.spanner.KeySet;
+import com.google.cloud.spanner.Mutation;
+import com.google.cloud.spanner.SpannerOptions;
+import java.io.FileInputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import org.junit.Ignore;
+
+@Ignore
+public class RealSpannerRefDb extends SpannerTestSystem {
+
+ private static RealSpannerRefDb INSTANCE;
+
+ public static RealSpannerRefDb create() {
+ if (INSTANCE == null) {
+ String keyPath = System.getenv("SERVICE_ACCOUNT_KEY_PATH");
+ String instance = System.getenv("SPANNER_INSTANCE");
+ INSTANCE = new RealSpannerRefDb(keyPath, instance);
+ }
+ return INSTANCE;
+ }
+
+ private final String keyPath;
+ private final String instance;
+ private final String dbName;
+
+ private boolean dbInitialized;
+ private SpannerRefDatabase refdb;
+ private DatabaseClient dbClient;
+
+ private RealSpannerRefDb(String keyPath, String instance) {
+ this.keyPath = keyPath;
+ this.instance = instance;
+ this.dbName = "global-refdb-" + System.currentTimeMillis();
+ }
+
+ @Override
+ public void reset() throws Exception {
+ if (!dbInitialized) {
+ initialize();
+ dbInitialized = true;
+ } else {
+ deleteAllData();
+ }
+ }
+
+ @Override
+ SpannerRefDatabase database() {
+ return refdb;
+ }
+
+ @Override
+ DatabaseClient dbClient() {
+ return dbClient;
+ }
+
+ @Override
+ void cleanup() {
+ // do nothing
+ }
+
+ private void initialize() throws Exception {
+ GoogleCredentials credentials = GoogleCredentials.fromStream(new FileInputStream(keyPath));
+
+ SpannerOptions options = SpannerOptions.newBuilder().setCredentials(credentials).build();
+ DatabaseId dbId = DatabaseId.of(options.getProjectId(), instance, dbName);
+ DatabaseAdminClient dbAdminClient = options.getService().getDatabaseAdminClient();
+
+ // create empty database
+ Database database =
+ dbAdminClient
+ .createDatabase(dbId.getInstanceId().getInstance(), dbId.getDatabase(), List.of())
+ .get();
+
+ SpannerLifeCycleManager lifecycleManager = new SpannerLifeCycleManager(dbAdminClient, dbId);
+ lifecycleManager.start();
+ dbClient = options.getService().getDatabaseClient(dbId);
+ ScheduledExecutorService heartbeatExecutor = Executors.newScheduledThreadPool(2);
+ Lock.Factory lockFactory =
+ new Lock.Factory() {
+ @Override
+ public Lock create(String projectName, String refName) {
+ return new Lock(dbClient, "", heartbeatExecutor, projectName, refName);
+ }
+ };
+ refdb = new SpannerRefDatabase(dbClient, lockFactory);
+
+ // schedule heartbeat stop and database drop when JVM gets shutdown
+ Runtime.getRuntime()
+ .addShutdownHook(
+ new Thread(
+ () -> {
+ heartbeatExecutor.shutdownNow();
+ try {
+ heartbeatExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ database.drop();
+ }));
+ }
+
+ private void deleteAllData() {
+ List<Mutation> mutations = new ArrayList<>();
+ mutations.add(Mutation.delete("refs", KeySet.all()));
+ mutations.add(Mutation.delete("locks", KeySet.all()));
+ dbClient.write(mutations);
+ }
+}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/spannerrefdb/SpannerRefDatabaseTest.java b/src/test/java/com/googlesource/gerrit/plugins/spannerrefdb/SpannerRefDatabaseTest.java
index a43d2a5..3035b90 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/spannerrefdb/SpannerRefDatabaseTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/spannerrefdb/SpannerRefDatabaseTest.java
@@ -26,18 +26,18 @@
public class SpannerRefDatabaseTest implements RefFixture {
- private EmulatedSpannerRefDb emulator;
+ private SpannerTestSystem testSystem;
private SpannerRefDatabase refdb;
@Before
public void setUp() throws Exception {
- emulator = new EmulatedSpannerRefDb();
- refdb = emulator.getSpannerRefDatabase();
+ testSystem = SpannerTestSystem.create();
+ refdb = testSystem.database();
}
@After
public void tearDown() {
- emulator.cleanup();
+ testSystem.cleanup();
}
@Test
diff --git a/src/test/java/com/googlesource/gerrit/plugins/spannerrefdb/SpannerTestSystem.java b/src/test/java/com/googlesource/gerrit/plugins/spannerrefdb/SpannerTestSystem.java
new file mode 100644
index 0000000..aff7407
--- /dev/null
+++ b/src/test/java/com/googlesource/gerrit/plugins/spannerrefdb/SpannerTestSystem.java
@@ -0,0 +1,43 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// 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 com.googlesource.gerrit.plugins.spannerrefdb;
+
+import com.google.cloud.spanner.DatabaseClient;
+import org.junit.Ignore;
+
+@Ignore
+public abstract class SpannerTestSystem {
+
+ public static SpannerTestSystem create() throws Exception {
+ SpannerTestSystem testSystem;
+ if (System.getenv("SERVICE_ACCOUNT_KEY_PATH") == null) {
+ testSystem = new EmulatedSpannerRefDb();
+ } else {
+ testSystem = RealSpannerRefDb.create();
+ }
+ testSystem.reset();
+ return testSystem;
+ }
+
+ protected SpannerTestSystem() {}
+
+ abstract void reset() throws Exception;
+
+ abstract SpannerRefDatabase database();
+
+ abstract DatabaseClient dbClient();
+
+ abstract void cleanup();
+}