Skip to content

Commit 13c297b

Browse files
authored
test: moves PITR backup tests (#956)
* test: moves PITR backup tests Since the backup tests are very expensive, here we exercise the PITR functionality along with the existing backup tests. We also remove the dedicated backup tests for PITR. * test: fixes tests * test: addresses PR comments
1 parent 39007f6 commit 13c297b

File tree

2 files changed

+121
-294
lines changed

2 files changed

+121
-294
lines changed

google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITBackupTest.java

Lines changed: 121 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,15 @@
3737
import com.google.cloud.spanner.ErrorCode;
3838
import com.google.cloud.spanner.Instance;
3939
import com.google.cloud.spanner.InstanceAdminClient;
40+
import com.google.cloud.spanner.InstanceId;
4041
import com.google.cloud.spanner.IntegrationTestEnv;
4142
import com.google.cloud.spanner.Mutation;
4243
import com.google.cloud.spanner.Options;
4344
import com.google.cloud.spanner.ParallelIntegrationTest;
45+
import com.google.cloud.spanner.ResultSet;
4446
import com.google.cloud.spanner.SpannerException;
4547
import com.google.cloud.spanner.SpannerExceptionFactory;
48+
import com.google.cloud.spanner.Statement;
4649
import com.google.cloud.spanner.testing.RemoteSpannerHelper;
4750
import com.google.common.base.Predicate;
4851
import com.google.common.base.Stopwatch;
@@ -92,6 +95,8 @@ public class ITBackupTest {
9295
private List<String> databases = new ArrayList<>();
9396
private List<String> backups = new ArrayList<>();
9497
private final Random random = new Random();
98+
private String projectId;
99+
private String instanceId;
95100

96101
@BeforeClass
97102
public static void doNotRunOnEmulator() {
@@ -105,6 +110,8 @@ public void setUp() {
105110
dbAdminClient = testHelper.getClient().getDatabaseAdminClient();
106111
instanceAdminClient = testHelper.getClient().getInstanceAdminClient();
107112
instance = instanceAdminClient.getInstance(testHelper.getInstanceId().getInstance());
113+
projectId = testHelper.getInstanceId().getProject();
114+
instanceId = testHelper.getInstanceId().getInstance();
108115
logger.info("Finished setup");
109116

110117
// Cancel any backup operation that has been started by this integration test if it has been
@@ -226,19 +233,25 @@ public void testBackups() throws InterruptedException, ExecutionException {
226233
String backupId1 = testHelper.getUniqueBackupId() + "_bck1";
227234
String backupId2 = testHelper.getUniqueBackupId() + "_bck2";
228235
Timestamp expireTime = afterDays(7);
236+
Timestamp versionTime = getCurrentTimestamp(client);
229237
logger.info(String.format("Creating backups %s and %s in parallel", backupId1, backupId2));
230-
OperationFuture<Backup, CreateBackupMetadata> op1 =
231-
dbAdminClient.createBackup(
232-
testHelper.getInstanceId().getInstance(),
233-
backupId1,
234-
db1.getId().getDatabase(),
235-
expireTime);
236-
OperationFuture<Backup, CreateBackupMetadata> op2 =
237-
dbAdminClient.createBackup(
238-
testHelper.getInstanceId().getInstance(),
239-
backupId2,
240-
db2.getId().getDatabase(),
241-
expireTime);
238+
// This backup has the version time specified as the server's current timestamp
239+
final Backup backupToCreate1 =
240+
dbAdminClient
241+
.newBackupBuilder(BackupId.of(projectId, instanceId, backupId1))
242+
.setDatabase(db1.getId())
243+
.setExpireTime(expireTime)
244+
.setVersionTime(versionTime)
245+
.build();
246+
// This backup has no version time specified
247+
final Backup backupToCreate2 =
248+
dbAdminClient
249+
.newBackupBuilder(BackupId.of(projectId, instanceId, backupId2))
250+
.setDatabase(db2.getId())
251+
.setExpireTime(expireTime)
252+
.build();
253+
OperationFuture<Backup, CreateBackupMetadata> op1 = dbAdminClient.createBackup(backupToCreate1);
254+
OperationFuture<Backup, CreateBackupMetadata> op2 = dbAdminClient.createBackup(backupToCreate2);
242255
backups.add(backupId1);
243256
backups.add(backupId2);
244257

@@ -274,9 +287,13 @@ public void testBackups() throws InterruptedException, ExecutionException {
274287
"Backup2 still not finished. Test is giving up waiting for it.");
275288
}
276289
logger.info("Long-running operations finished. Getting backups by id.");
277-
backup1 = dbAdminClient.getBackup(instance.getId().getInstance(), backupId1);
278-
backup2 = dbAdminClient.getBackup(instance.getId().getInstance(), backupId2);
290+
backup1 = dbAdminClient.getBackup(this.instance.getId().getInstance(), backupId1);
291+
backup2 = dbAdminClient.getBackup(this.instance.getId().getInstance(), backupId2);
279292
}
293+
294+
// Verifies that backup version time is the specified one
295+
testBackupVersionTime(backup1, versionTime);
296+
280297
// Insert some more data into db2 to get a timestamp from the server.
281298
Timestamp commitTs =
282299
client.writeAtLeastOnce(
@@ -291,54 +308,40 @@ public void testBackups() throws InterruptedException, ExecutionException {
291308
// Test listing operations.
292309
// List all backups.
293310
logger.info("Listing all backups");
294-
assertThat(instance.listBackups().iterateAll()).containsAtLeast(backup1, backup2);
311+
assertThat(this.instance.listBackups().iterateAll()).containsAtLeast(backup1, backup2);
295312
// List all backups whose names contain 'bck1'.
296313
logger.info("Listing backups with name bck1");
297314
assertThat(
298315
dbAdminClient
299316
.listBackups(
300-
testHelper.getInstanceId().getInstance(),
301-
Options.filter(String.format("name:%s", backup1.getId().getName())))
317+
instanceId, Options.filter(String.format("name:%s", backup1.getId().getName())))
302318
.iterateAll())
303319
.containsExactly(backup1);
304320
logger.info("Listing ready backups");
305321
Iterable<Backup> readyBackups =
306-
dbAdminClient
307-
.listBackups(testHelper.getInstanceId().getInstance(), Options.filter("state:READY"))
308-
.iterateAll();
322+
dbAdminClient.listBackups(instanceId, Options.filter("state:READY")).iterateAll();
309323
assertThat(readyBackups).containsAtLeast(backup1, backup2);
310324
// List all backups for databases whose names contain 'db1'.
311325
logger.info("Listing backups for database db1");
312326
assertThat(
313327
dbAdminClient
314328
.listBackups(
315-
testHelper.getInstanceId().getInstance(),
316-
Options.filter(String.format("database:%s", db1.getId().getName())))
329+
instanceId, Options.filter(String.format("database:%s", db1.getId().getName())))
317330
.iterateAll())
318331
.containsExactly(backup1);
319332
// List all backups that were created before a certain time.
320333
Timestamp ts = Timestamp.ofTimeSecondsAndNanos(commitTs.getSeconds(), 0);
321334
logger.info(String.format("Listing backups created before %s", ts));
322335
assertThat(
323336
dbAdminClient
324-
.listBackups(
325-
testHelper.getInstanceId().getInstance(),
326-
Options.filter(String.format("create_time<\"%s\"", ts)))
337+
.listBackups(instanceId, Options.filter(String.format("create_time<\"%s\"", ts)))
327338
.iterateAll())
328339
.containsAtLeast(backup1, backup2);
329340
// List all backups with a size > 0.
330341
logger.info("Listing backups with size>0");
331-
assertThat(
332-
dbAdminClient
333-
.listBackups(
334-
testHelper.getInstanceId().getInstance(), Options.filter("size_bytes>0"))
335-
.iterateAll())
342+
assertThat(dbAdminClient.listBackups(instanceId, Options.filter("size_bytes>0")).iterateAll())
336343
.contains(backup2);
337-
assertThat(
338-
dbAdminClient
339-
.listBackups(
340-
testHelper.getInstanceId().getInstance(), Options.filter("size_bytes>0"))
341-
.iterateAll())
344+
assertThat(dbAdminClient.listBackups(instanceId, Options.filter("size_bytes>0")).iterateAll())
342345
.doesNotContain(backup1);
343346

344347
// Test pagination.
@@ -349,14 +352,79 @@ public void testBackups() throws InterruptedException, ExecutionException {
349352
testGetBackup(db2, backupId2, expireTime);
350353
testUpdateBackup(backup1);
351354
testCreateInvalidExpirationDate(db1);
352-
testRestore(backup1, op1);
355+
testRestore(backup1, op1, versionTime);
353356

354357
testDelete(backupId2);
355358
testCancelBackupOperation(db1);
356359
// Finished all tests.
357360
logger.info("Finished all backup tests");
358361
}
359362

363+
@Test(expected = SpannerException.class)
364+
public void backupCreationWithVersionTimeTooFarInThePastFails() throws Exception {
365+
final Database testDatabase = testHelper.createTestDatabase();
366+
final DatabaseId databaseId = testDatabase.getId();
367+
final InstanceId instanceId = databaseId.getInstanceId();
368+
final String backupId = testHelper.getUniqueBackupId();
369+
final Timestamp expireTime = afterDays(7);
370+
final Timestamp versionTime = daysAgo(30);
371+
final Backup backupToCreate =
372+
dbAdminClient
373+
.newBackupBuilder(BackupId.of(instanceId, backupId))
374+
.setDatabase(databaseId)
375+
.setExpireTime(expireTime)
376+
.setVersionTime(versionTime)
377+
.build();
378+
379+
getOrThrow(dbAdminClient.createBackup(backupToCreate));
380+
}
381+
382+
@Test(expected = SpannerException.class)
383+
public void backupCreationWithVersionTimeInTheFutureFails() throws Exception {
384+
final Database testDatabase = testHelper.createTestDatabase();
385+
final DatabaseId databaseId = testDatabase.getId();
386+
final InstanceId instanceId = databaseId.getInstanceId();
387+
final String backupId = testHelper.getUniqueBackupId();
388+
final Timestamp expireTime = afterDays(7);
389+
final Timestamp versionTime = afterDays(1);
390+
final Backup backupToCreate =
391+
dbAdminClient
392+
.newBackupBuilder(BackupId.of(instanceId, backupId))
393+
.setDatabase(databaseId)
394+
.setExpireTime(expireTime)
395+
.setVersionTime(versionTime)
396+
.build();
397+
398+
getOrThrow(dbAdminClient.createBackup(backupToCreate));
399+
}
400+
401+
private <T> T getOrThrow(OperationFuture<T, ?> operation)
402+
throws InterruptedException, ExecutionException {
403+
try {
404+
return operation.get();
405+
} catch (ExecutionException e) {
406+
if (e.getCause() instanceof SpannerException) {
407+
throw (SpannerException) e.getCause();
408+
} else {
409+
throw e;
410+
}
411+
}
412+
}
413+
414+
private Timestamp getCurrentTimestamp(DatabaseClient client) {
415+
try (ResultSet resultSet =
416+
client.singleUse().executeQuery(Statement.of("SELECT CURRENT_TIMESTAMP()"))) {
417+
resultSet.next();
418+
return resultSet.getTimestamp(0);
419+
}
420+
}
421+
422+
private void testBackupVersionTime(Backup backup, Timestamp versionTime) {
423+
logger.info("Verifying backup version time for " + backup.getId());
424+
assertThat(backup.getVersionTime()).isEqualTo(versionTime);
425+
logger.info("Done verifying backup version time for " + backup.getId());
426+
}
427+
360428
private void testMetadata(
361429
OperationFuture<Backup, CreateBackupMetadata> op1,
362430
OperationFuture<Backup, CreateBackupMetadata> op2,
@@ -391,11 +459,7 @@ private void testCreateInvalidExpirationDate(Database db) throws InterruptedExce
391459
String backupId = testHelper.getUniqueBackupId();
392460
logger.info(String.format("Creating backup %s with invalid expiration date", backupId));
393461
OperationFuture<Backup, CreateBackupMetadata> op =
394-
dbAdminClient.createBackup(
395-
testHelper.getInstanceId().getInstance(),
396-
backupId,
397-
db.getId().getDatabase(),
398-
expireTime);
462+
dbAdminClient.createBackup(instanceId, backupId, db.getId().getDatabase(), expireTime);
399463
backups.add(backupId);
400464
try {
401465
op.get();
@@ -414,11 +478,7 @@ private void testCancelBackupOperation(Database db)
414478
String backupId = testHelper.getUniqueBackupId();
415479
logger.info(String.format("Starting to create backup %s", backupId));
416480
OperationFuture<Backup, CreateBackupMetadata> op =
417-
dbAdminClient.createBackup(
418-
testHelper.getInstanceId().getInstance(),
419-
backupId,
420-
db.getId().getDatabase(),
421-
expireTime);
481+
dbAdminClient.createBackup(instanceId, backupId, db.getId().getDatabase(), expireTime);
422482
backups.add(backupId);
423483
// Cancel the backup operation.
424484
logger.info(String.format("Cancelling the creation of backup %s", backupId));
@@ -428,8 +488,7 @@ private void testCancelBackupOperation(Database db)
428488
for (Operation operation :
429489
dbAdminClient
430490
.listBackupOperations(
431-
testHelper.getInstanceId().getInstance(),
432-
Options.filter(String.format("name:%s", op.getName())))
491+
instanceId, Options.filter(String.format("name:%s", op.getName())))
433492
.iterateAll()) {
434493
assertThat(operation.getError().getCode()).isEqualTo(Status.Code.CANCELLED.value());
435494
operationFound = true;
@@ -481,18 +540,15 @@ private void testPagination(int expectedMinimumTotalBackups) {
481540
logger.info("Listing backups using pagination");
482541
int numBackups = 0;
483542
logger.info("Fetching first page");
484-
Page<Backup> page =
485-
dbAdminClient.listBackups(testHelper.getInstanceId().getInstance(), Options.pageSize(1));
543+
Page<Backup> page = dbAdminClient.listBackups(instanceId, Options.pageSize(1));
486544
assertThat(page.getValues()).hasSize(1);
487545
numBackups++;
488546
assertThat(page.hasNextPage()).isTrue();
489547
while (page.hasNextPage()) {
490548
logger.info(String.format("Fetching page %d", numBackups + 1));
491549
page =
492550
dbAdminClient.listBackups(
493-
testHelper.getInstanceId().getInstance(),
494-
Options.pageToken(page.getNextPageToken()),
495-
Options.pageSize(1));
551+
instanceId, Options.pageToken(page.getNextPageToken()), Options.pageSize(1));
496552
assertThat(page.getValues()).hasSize(1);
497553
numBackups++;
498554
}
@@ -521,7 +577,8 @@ private void testDelete(String backupId) throws InterruptedException {
521577
logger.info("Finished delete tests");
522578
}
523579

524-
private void testRestore(Backup backup, OperationFuture<Backup, CreateBackupMetadata> backupOp)
580+
private void testRestore(
581+
Backup backup, OperationFuture<Backup, CreateBackupMetadata> backupOp, Timestamp versionTime)
525582
throws InterruptedException, ExecutionException {
526583
// Restore the backup to a new database.
527584
String restoredDb = testHelper.getUniqueDatabaseId();
@@ -565,6 +622,8 @@ private void testRestore(Backup backup, OperationFuture<Backup, CreateBackupMeta
565622
assertThat(metadata.getSourceType()).isEqualTo(RestoreSourceType.BACKUP);
566623
assertThat(metadata.getName())
567624
.isEqualTo(DatabaseId.of(testHelper.getInstanceId(), restoredDb).getName());
625+
assertThat(Timestamp.fromProto(metadata.getBackupInfo().getVersionTime()))
626+
.isEqualTo(versionTime);
568627

569628
// Ensure the operations show up in the right collections.
570629
// TODO: Re-enable when it is clear why this fails on the CI environment.
@@ -573,6 +632,14 @@ private void testRestore(Backup backup, OperationFuture<Backup, CreateBackupMeta
573632
// Wait until the restore operation has finished successfully.
574633
Database database = restoreOp.get();
575634
assertThat(database.getId().getDatabase()).isEqualTo(restoredDb);
635+
636+
// Reloads the database
637+
final Database reloadedDatabase = database.reload();
638+
assertThat(
639+
Timestamp.fromProto(
640+
reloadedDatabase.getProto().getRestoreInfo().getBackupInfo().getVersionTime()))
641+
.isEqualTo(versionTime);
642+
576643
// Restoring the backup to an existing database should fail.
577644
try {
578645
logger.info(

0 commit comments

Comments
 (0)