Re-create global-refdb project versions when missing Do not fail if the global-refdb project versions are missing and create them again as brand-new entries, using the local version as initial value. Bug: Issue 12393 Change-Id: Ie772ef59eb3e602e42d8e775d85a3a8206c963fa
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/ProjectVersionRefUpdate.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/ProjectVersionRefUpdate.java index 84965c0..a8f344e 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/ProjectVersionRefUpdate.java +++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/ProjectVersionRefUpdate.java
@@ -200,15 +200,24 @@ "Updating shared project version for %s. Current value %s, new value: %s", projectNameKey.get(), currentRef.getObjectId(), newObjectId)); try { + if (!sharedRefDb.exists(projectNameKey, MULTI_SITE_VERSIONING_REF)) { + currentRef = + new ObjectIdRef.Unpeeled(Ref.Storage.NEW, MULTI_SITE_VERSIONING_REF, ObjectId.zeroId()); + } + if (!sharedRefDb.exists(projectNameKey, MULTI_SITE_VERSIONING_VALUE_REF)) { + currentVersion = Optional.empty(); + } + boolean success = sharedRefDb.compareAndPut(projectNameKey, currentRef, newObjectId); if (!success) { String message = String.format( "Project version blob update failed for %s. Current value %s, new value: %s", - projectNameKey.get(), currentRef.getObjectId(), newObjectId); + projectNameKey.get(), safeGetObjectId(currentRef), newObjectId); logger.atSevere().log(message); throw new SharedProjectVersionUpdateException(message); } + success = sharedRefDb.compareAndPut( projectNameKey, @@ -219,7 +228,7 @@ String message = String.format( "Project version update failed for %s. Current value %s, new value: %s", - projectNameKey.get(), currentRef.getObjectId(), newObjectId); + projectNameKey.get(), safeGetObjectId(currentRef), newObjectId); logger.atSevere().log(message); throw new SharedProjectVersionUpdateException(message); } @@ -260,6 +269,10 @@ return globalVersion.flatMap(longString -> getLongValueOf(longString)); } + private Object safeGetObjectId(Ref currentRef) { + return currentRef == null ? "null" : currentRef.getObjectId(); + } + private Optional<Long> getLongValueOf(String longString) { try { return Optional.ofNullable(Long.parseLong(longString));
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/ProjectVersionRefUpdateTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/ProjectVersionRefUpdateTest.java index 16dd545..da8c8a9 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/ProjectVersionRefUpdateTest.java +++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/ProjectVersionRefUpdateTest.java
@@ -18,6 +18,7 @@ import static com.googlesource.gerrit.plugins.multisite.validation.ProjectVersionRefUpdate.MULTI_SITE_VERSIONING_REF; import static com.googlesource.gerrit.plugins.multisite.validation.ProjectVersionRefUpdate.MULTI_SITE_VERSIONING_VALUE_REF; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.atMost; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; @@ -87,8 +88,16 @@ @Test public void producerShouldUpdateProjectVersionUponRefUpdatedEvent() throws IOException { Context.setForwardedEvent(false); + when(sharedRefDb.exists( + A_TEST_PROJECT_NAME_KEY, ProjectVersionRefUpdate.MULTI_SITE_VERSIONING_REF)) + .thenReturn(true); + when(sharedRefDb.exists( + A_TEST_PROJECT_NAME_KEY, ProjectVersionRefUpdate.MULTI_SITE_VERSIONING_VALUE_REF)) + .thenReturn(true); when(sharedRefDb.compareAndPut(any(Project.NameKey.class), any(Ref.class), any(ObjectId.class))) .thenReturn(true); + when(sharedRefDb.compareAndPut(any(Project.NameKey.class), any(String.class), any(), any())) + .thenReturn(true); when(refUpdatedEvent.getProjectNameKey()).thenReturn(A_TEST_PROJECT_NAME_KEY); when(refUpdatedEvent.getRefName()).thenReturn(A_TEST_REF_NAME); @@ -110,6 +119,41 @@ } @Test + public void producerShouldCreateNewProjectVersionWhenMissingUponRefUpdatedEvent() + throws IOException { + Context.setForwardedEvent(false); + when(sharedRefDb.exists( + A_TEST_PROJECT_NAME_KEY, ProjectVersionRefUpdate.MULTI_SITE_VERSIONING_REF)) + .thenReturn(false); + when(sharedRefDb.exists( + A_TEST_PROJECT_NAME_KEY, ProjectVersionRefUpdate.MULTI_SITE_VERSIONING_VALUE_REF)) + .thenReturn(false); + + when(sharedRefDb.compareAndPut(any(Project.NameKey.class), isNull(), any(ObjectId.class))) + .thenReturn(true); + when(sharedRefDb.compareAndPut(any(Project.NameKey.class), any(String.class), any(), any())) + .thenReturn(true); + when(refUpdatedEvent.getProjectNameKey()).thenReturn(A_TEST_PROJECT_NAME_KEY); + when(refUpdatedEvent.getRefName()).thenReturn(A_TEST_REF_NAME); + + new ProjectVersionRefUpdate(repoManager, sharedRefDb, gitReferenceUpdated, verLogger) + .onEvent(refUpdatedEvent); + + Ref ref = repo.getRepository().findRef(MULTI_SITE_VERSIONING_REF); + + verify(sharedRefDb, atMost(1)) + .compareAndPut(any(Project.NameKey.class), isNull(), any(ObjectId.class)); + + assertThat(ref).isNotNull(); + + ObjectLoader loader = repo.getRepository().open(ref.getObjectId()); + String storedVersion = IOUtils.toString(loader.openStream(), StandardCharsets.UTF_8.name()); + assertThat(Long.parseLong(storedVersion)).isEqualTo(masterCommit.getCommitTime()); + + verify(verLogger).log(A_TEST_PROJECT_NAME_KEY, masterCommit.getCommitTime(), 0); + } + + @Test public void producerShouldNotUpdateProjectVersionUponSequenceRefUpdatedEvent() throws Exception { producerShouldNotUpdateProjectVersionUponMagicRefUpdatedEvent(RefNames.REFS_SEQUENCES); }