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);
}