Merge branch 'stable-3.1'
* stable-3.1:
Fix mocks in ProjectVersionRefUpdateTest
Re-create global-refdb project versions when missing
Add unit-test for SubscriberMetrics
Silence exception when repository is not found
Generate project version logging for analyzing replication lag
Rely on replication for version ref propagation
Change-Id: I5f62e452339da023dba5794490c9555792440b86
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/Log4jProjectVersionLogger.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/Log4jProjectVersionLogger.java
new file mode 100644
index 0000000..c2c4b46
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/Log4jProjectVersionLogger.java
@@ -0,0 +1,48 @@
+// Copyright (C) 2020 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.multisite;
+
+import com.google.gerrit.entities.Project;
+import com.google.gerrit.server.util.SystemLog;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import org.apache.log4j.PatternLayout;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class Log4jProjectVersionLogger extends LibModuleLogFile implements ProjectVersionLogger {
+ private static final String LOG_NAME = "project_version_log";
+ private final Logger verLog;
+
+ @Inject
+ public Log4jProjectVersionLogger(SystemLog systemLog) {
+ super(systemLog, LOG_NAME, new PatternLayout("[%d{ISO8601}] [%t] %-5p : %m%n"));
+ this.verLog = LoggerFactory.getLogger(LOG_NAME);
+ }
+
+ @Override
+ public void log(Project.NameKey projectName, long currentVersion, long replicationLag) {
+ if (replicationLag > 0) {
+ verLog.warn(
+ "{ \"project\":\"{}\", \"version\":{}, \"lag\":{} }",
+ projectName,
+ currentVersion,
+ replicationLag);
+ } else {
+ verLog.info("{ \"project\":\"{}\", \"version\":{} }", projectName, currentVersion);
+ }
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/ProjectVersionLogger.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/ProjectVersionLogger.java
new file mode 100644
index 0000000..6ababb6
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/ProjectVersionLogger.java
@@ -0,0 +1,22 @@
+// Copyright (C) 2020 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.multisite;
+
+import com.google.gerrit.entities.Project;
+
+public interface ProjectVersionLogger {
+
+ public void log(Project.NameKey projectName, long currentVersion, long replicationLag);
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/consumer/SubscriberMetrics.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/consumer/SubscriberMetrics.java
index b4e5c94..4459859 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/consumer/SubscriberMetrics.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/consumer/SubscriberMetrics.java
@@ -25,6 +25,7 @@
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.googlesource.gerrit.plugins.multisite.MultiSiteMetrics;
+import com.googlesource.gerrit.plugins.multisite.ProjectVersionLogger;
import com.googlesource.gerrit.plugins.multisite.validation.ProjectVersionRefUpdate;
import com.googlesource.gerrit.plugins.replication.RefReplicatedEvent;
import com.googlesource.gerrit.plugins.replication.RefReplicationDoneEvent;
@@ -46,14 +47,18 @@
private final Counter1<String> subscriberSuccessCounter;
private final Counter1<String> subscriberFailureCounter;
+ private final ProjectVersionLogger verLogger;
- public Map<String, Long> replicationStatusPerProject = new HashMap<>();
+ private final Map<String, Long> replicationStatusPerProject = new HashMap<>();
+ private final Map<String, Long> localVersionPerProject = new HashMap<>();
private ProjectVersionRefUpdate projectVersionRefUpdate;
@Inject
public SubscriberMetrics(
- MetricMaker metricMaker, ProjectVersionRefUpdate projectVersionRefUpdate) {
+ MetricMaker metricMaker,
+ ProjectVersionRefUpdate projectVersionRefUpdate,
+ ProjectVersionLogger verLogger) {
this.projectVersionRefUpdate = projectVersionRefUpdate;
this.subscriberSuccessCounter =
@@ -81,6 +86,8 @@
}
return Collections.max(lags);
});
+
+ this.verLogger = verLogger;
}
public void incrementSubscriberConsumedMessage() {
@@ -115,10 +122,16 @@
Optional<Long> localVersion = projectVersionRefUpdate.getProjectLocalVersion(projectName.get());
if (remoteVersion.isPresent() && localVersion.isPresent()) {
long lag = remoteVersion.get() - localVersion.get();
- logger.atFine().log(
- "Published replication lag metric for project '%s' of %d sec(s) [local-ref=%d global-ref=%d]",
- projectName, lag, localVersion.get(), remoteVersion.get());
- replicationStatusPerProject.put(projectName.get(), lag);
+
+ if (!localVersion.get().equals(localVersionPerProject.get(projectName.get()))
+ || lag != replicationStatusPerProject.get(projectName.get())) {
+ logger.atFine().log(
+ "Published replication lag metric for project '%s' of %d sec(s) [local-ref=%d global-ref=%d]",
+ projectName, lag, localVersion.get(), remoteVersion.get());
+ replicationStatusPerProject.put(projectName.get(), lag);
+ localVersionPerProject.put(projectName.get(), localVersion.get());
+ verLogger.log(projectName, localVersion.get(), lag);
+ }
} else {
logger.atFine().log(
"Did not publish replication lag metric for %s because the %s version is not defined",
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 45d0806..bd910ad 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
@@ -27,16 +27,18 @@
import com.google.gerrit.server.events.Event;
import com.google.gerrit.server.events.EventListener;
import com.google.gerrit.server.events.RefUpdatedEvent;
+import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.notedb.IntBlob;
import com.google.inject.Inject;
import com.google.inject.Singleton;
+import com.googlesource.gerrit.plugins.multisite.ProjectVersionLogger;
import com.googlesource.gerrit.plugins.multisite.SharedRefDatabaseWrapper;
import com.googlesource.gerrit.plugins.multisite.forwarder.Context;
-import com.googlesource.gerrit.plugins.replication.RefReplicationDoneEvent;
import java.io.IOException;
import java.util.Optional;
import java.util.Set;
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdRef;
import org.eclipse.jgit.lib.ObjectInserter;
@@ -60,14 +62,21 @@
new ObjectIdRef.Unpeeled(Ref.Storage.NETWORK, MULTI_SITE_VERSIONING_REF, ObjectId.zeroId());
private final GitRepositoryManager gitRepositoryManager;
+ private final GitReferenceUpdated gitReferenceUpdated;
+ private final ProjectVersionLogger verLogger;
protected final SharedRefDatabaseWrapper sharedRefDb;
@Inject
public ProjectVersionRefUpdate(
- GitRepositoryManager gitRepositoryManager, SharedRefDatabaseWrapper sharedRefDb) {
+ GitRepositoryManager gitRepositoryManager,
+ SharedRefDatabaseWrapper sharedRefDb,
+ GitReferenceUpdated gitReferenceUpdated,
+ ProjectVersionLogger verLogger) {
this.gitRepositoryManager = gitRepositoryManager;
this.sharedRefDb = sharedRefDb;
+ this.gitReferenceUpdated = gitReferenceUpdated;
+ this.verLogger = verLogger;
}
@Override
@@ -77,34 +86,12 @@
if (!Context.isForwardedEvent() && event instanceof RefUpdatedEvent) {
updateProducerProjectVersionUpdate((RefUpdatedEvent) event);
}
-
- // Consumers of the Event use RefReplicationDoneEvent to trigger the version update
- if (Context.isForwardedEvent() && event instanceof RefReplicationDoneEvent) {
- updateConsumerProjectVersion((RefReplicationDoneEvent) event);
- }
- }
-
- private void updateConsumerProjectVersion(RefReplicationDoneEvent refReplicationDoneEvent) {
- Project.NameKey projectNameKey = refReplicationDoneEvent.getProjectNameKey();
- String refName = refReplicationDoneEvent.getRefName();
-
- if (isSpecialRefName(refName)) {
- logger.atFine().log(
- "Found a special ref name %s, skipping update for %s", refName, projectNameKey.get());
- return;
- }
- try {
- updateLocalProjectVersion(
- projectNameKey, getLastRefUpdatedTimestamp(projectNameKey, refName));
- } catch (LocalProjectVersionUpdateException e) {
- logger.atSevere().withCause(e).log(
- "Issue encountered when updating version for project " + projectNameKey);
- }
}
private boolean isSpecialRefName(String refName) {
return refName.startsWith(RefNames.REFS_SEQUENCES)
- || refName.startsWith(RefNames.REFS_STARRED_CHANGES);
+ || refName.startsWith(RefNames.REFS_STARRED_CHANGES)
+ || refName.equals(MULTI_SITE_VERSIONING_REF);
}
private void updateProducerProjectVersionUpdate(RefUpdatedEvent refUpdatedEvent) {
@@ -127,6 +114,8 @@
updateLocalProjectVersion(projectNameKey, lastRefUpdatedTimestamp);
if (newProjectVersionObjectId.isPresent()) {
+ verLogger.log(projectNameKey, lastRefUpdatedTimestamp.get(), 0L);
+
updateSharedProjectVersion(
projectNameKey,
currentProjectVersionRef,
@@ -211,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,
@@ -230,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);
}
@@ -256,6 +254,8 @@
logger.atFine().log("Local project '%s' has version %d", projectName, repoVersion);
return Optional.of(repoVersion);
}
+ } catch (RepositoryNotFoundException re) {
+ logger.atFine().log("Project '%s' not found", projectName);
} catch (IOException e) {
logger.atSevere().withCause(e).log("Cannot read local project '%s' version", projectName);
}
@@ -269,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));
@@ -324,6 +328,8 @@
logger.atSevere().log(message);
throw new LocalProjectVersionUpdateException(message);
}
+
+ gitReferenceUpdated.fire(projectNameKey, refUpdate, null);
return Optional.of(refUpdate.getNewObjectId());
} catch (IOException e) {
String message = "Cannot create versioning command for " + projectNameKey.get();
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/ValidationModule.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/ValidationModule.java
index 1719f38..481d288 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/ValidationModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/ValidationModule.java
@@ -21,7 +21,9 @@
import com.google.inject.Scopes;
import com.googlesource.gerrit.plugins.multisite.Configuration;
import com.googlesource.gerrit.plugins.multisite.LockWrapper;
+import com.googlesource.gerrit.plugins.multisite.Log4jProjectVersionLogger;
import com.googlesource.gerrit.plugins.multisite.Log4jSharedRefLogger;
+import com.googlesource.gerrit.plugins.multisite.ProjectVersionLogger;
import com.googlesource.gerrit.plugins.multisite.SharedRefDatabaseWrapper;
import com.googlesource.gerrit.plugins.multisite.SharedRefLogger;
import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.CustomSharedRefEnforcementByProject;
@@ -45,6 +47,7 @@
bind(SharedRefDatabaseWrapper.class).in(Scopes.SINGLETON);
bind(SharedRefLogger.class).to(Log4jSharedRefLogger.class);
+ bind(ProjectVersionLogger.class).to(Log4jProjectVersionLogger.class);
factory(LockWrapper.Factory.class);
factory(MultiSiteRepository.Factory.class);
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/consumer/SubscriberMetricsTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/consumer/SubscriberMetricsTest.java
new file mode 100644
index 0000000..99148fa
--- /dev/null
+++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/consumer/SubscriberMetricsTest.java
@@ -0,0 +1,98 @@
+// Copyright (C) 2020 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.multisite.consumer;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import com.gerritforge.gerrit.eventbroker.EventMessage;
+import com.google.common.base.Suppliers;
+import com.google.gerrit.entities.Project;
+import com.google.gerrit.metrics.MetricMaker;
+import com.google.gerrit.server.data.RefUpdateAttribute;
+import com.google.gerrit.server.events.RefUpdatedEvent;
+import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
+import com.googlesource.gerrit.plugins.multisite.ProjectVersionLogger;
+import com.googlesource.gerrit.plugins.multisite.SharedRefDatabaseWrapper;
+import com.googlesource.gerrit.plugins.multisite.validation.ProjectVersionRefUpdate;
+import java.util.Optional;
+import java.util.UUID;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class SubscriberMetricsTest {
+ private static final String A_TEST_PROJECT_NAME = "test-project";
+ private static final Project.NameKey A_TEST_PROJECT_NAME_KEY =
+ Project.nameKey(A_TEST_PROJECT_NAME);
+
+ @Mock private SharedRefDatabaseWrapper sharedRefDb;
+ @Mock private GitReferenceUpdated gitReferenceUpdated;
+ @Mock private MetricMaker metricMaker;
+ @Mock private ProjectVersionLogger verLogger;
+ @Mock private ProjectVersionRefUpdate projectVersionRefUpdate;
+ private SubscriberMetrics metrics;
+ private EventMessage.Header msgHeader;
+
+ @Before
+ public void setup() throws Exception {
+ msgHeader = new EventMessage.Header(UUID.randomUUID(), UUID.randomUUID());
+ metrics = new SubscriberMetrics(metricMaker, projectVersionRefUpdate, verLogger);
+ }
+
+ @Test
+ public void shouldLogProjectVersionWhenReceivingRefUpdatedEventWithoutLag() {
+ Optional<Long> globalRefDbVersion = Optional.of(System.currentTimeMillis() / 1000);
+ when(projectVersionRefUpdate.getProjectRemoteVersion(A_TEST_PROJECT_NAME))
+ .thenReturn(globalRefDbVersion);
+ when(projectVersionRefUpdate.getProjectLocalVersion(A_TEST_PROJECT_NAME))
+ .thenReturn(globalRefDbVersion);
+
+ EventMessage eventMessage = new EventMessage(msgHeader, newRefUpdateEvent());
+
+ metrics.updateReplicationStatusMetrics(eventMessage);
+
+ verify(verLogger).log(A_TEST_PROJECT_NAME_KEY, globalRefDbVersion.get(), 0);
+ }
+
+ @Test
+ public void shouldLogProjectVersionWhenReceivingRefUpdatedEventWithALag() {
+ Optional<Long> globalRefDbVersion = Optional.of(System.currentTimeMillis() / 1000);
+ long replicationLag = 60;
+ when(projectVersionRefUpdate.getProjectRemoteVersion(A_TEST_PROJECT_NAME))
+ .thenReturn(globalRefDbVersion.map(ts -> ts + replicationLag));
+ when(projectVersionRefUpdate.getProjectLocalVersion(A_TEST_PROJECT_NAME))
+ .thenReturn(globalRefDbVersion);
+
+ EventMessage eventMessage = new EventMessage(msgHeader, newRefUpdateEvent());
+
+ metrics.updateReplicationStatusMetrics(eventMessage);
+
+ verify(verLogger).log(A_TEST_PROJECT_NAME_KEY, globalRefDbVersion.get(), replicationLag);
+ }
+
+ private RefUpdatedEvent newRefUpdateEvent() {
+ RefUpdateAttribute refUpdate = new RefUpdateAttribute();
+ refUpdate.project = A_TEST_PROJECT_NAME;
+ refUpdate.refName = "refs/heads/foo";
+ refUpdate.newRev = "591727cfec5174368a7829f79741c41683d84c89";
+ RefUpdatedEvent refUpdateEvent = new RefUpdatedEvent();
+ refUpdateEvent.refUpdate = Suppliers.ofInstance(refUpdate);
+ return refUpdateEvent;
+ }
+}
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 9a4020d..20b49c1 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,22 +18,24 @@
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.never;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import com.google.gerrit.entities.Project;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.server.events.RefUpdatedEvent;
+import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.project.ProjectConfig;
import com.google.gerrit.testing.InMemoryRepositoryManager;
import com.google.gerrit.testing.InMemoryTestEnvironment;
import com.google.inject.Inject;
+import com.googlesource.gerrit.plugins.multisite.ProjectVersionLogger;
import com.googlesource.gerrit.plugins.multisite.SharedRefDatabaseWrapper;
import com.googlesource.gerrit.plugins.multisite.forwarder.Context;
import com.googlesource.gerrit.plugins.multisite.validation.dfsrefdb.RefFixture;
-import com.googlesource.gerrit.plugins.replication.RefReplicationDoneEvent;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
@@ -59,6 +61,8 @@
@Mock RefUpdatedEvent refUpdatedEvent;
@Mock SharedRefDatabaseWrapper sharedRefDb;
+ @Mock GitReferenceUpdated gitReferenceUpdated;
+ @Mock ProjectVersionLogger verLogger;
@Inject private ProjectConfig.Factory projectConfigFactory;
@Inject private InMemoryRepositoryManager repoManager;
@@ -84,12 +88,21 @@
@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);
- new ProjectVersionRefUpdate(repoManager, sharedRefDb).onEvent(refUpdatedEvent);
+ new ProjectVersionRefUpdate(repoManager, sharedRefDb, gitReferenceUpdated, verLogger)
+ .onEvent(refUpdatedEvent);
Ref ref = repo.getRepository().findRef(MULTI_SITE_VERSIONING_REF);
@@ -101,6 +114,43 @@
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 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), 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);
+
+ 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
@@ -122,10 +172,13 @@
when(refUpdatedEvent.getRefName()).thenReturn(magicRefName);
repo.branch(magicRefName).commit().create();
- new ProjectVersionRefUpdate(repoManager, sharedRefDb).onEvent(refUpdatedEvent);
+ new ProjectVersionRefUpdate(repoManager, sharedRefDb, gitReferenceUpdated, verLogger)
+ .onEvent(refUpdatedEvent);
Ref ref = repo.getRepository().findRef(MULTI_SITE_VERSIONING_REF);
assertThat(ref).isNull();
+
+ verifyZeroInteractions(verLogger);
}
@Test
@@ -134,57 +187,13 @@
when(refUpdatedEvent.getProjectNameKey()).thenReturn(Project.nameKey("aNonExistentProject"));
when(refUpdatedEvent.getRefName()).thenReturn(A_TEST_REF_NAME);
- new ProjectVersionRefUpdate(repoManager, sharedRefDb).onEvent(refUpdatedEvent);
+ new ProjectVersionRefUpdate(repoManager, sharedRefDb, gitReferenceUpdated, verLogger)
+ .onEvent(refUpdatedEvent);
Ref ref = repo.getRepository().findRef(MULTI_SITE_VERSIONING_REF);
assertThat(ref).isNull();
- }
- @Test
- public void consumerShouldUpdateProjectVersionUponRefReplicationDoneEvent() throws IOException {
- Context.setForwardedEvent(true);
- RefReplicationDoneEvent refReplicatedEvent =
- new RefReplicationDoneEvent(A_TEST_PROJECT_NAME, A_TEST_REF_NAME, 1);
-
- new ProjectVersionRefUpdate(repoManager, sharedRefDb).onEvent(refReplicatedEvent);
-
- Ref ref = repo.getRepository().findRef(MULTI_SITE_VERSIONING_REF);
- assertThat(ref).isNotNull();
-
- verify(sharedRefDb, never())
- .compareAndPut(any(Project.NameKey.class), any(Ref.class), any(ObjectId.class));
-
- ObjectLoader loader = repo.getRepository().open(ref.getObjectId());
- String storedVersion = IOUtils.toString(loader.openStream(), StandardCharsets.UTF_8.name());
- assertThat(Long.parseLong(storedVersion))
- .isEqualTo(Integer.toUnsignedLong(masterCommit.getCommitTime()));
- }
-
- @Test
- public void consumerShouldNotUpdateProjectVersionUponSequenceRefReplicationDoneEvent()
- throws Exception {
- consumerShouldNotUpdateProjectVersionUponMagicRefReplicationDoneEvent(RefNames.REFS_SEQUENCES);
- }
-
- @Test
- public void consumerShouldNotUpdateProjectVersionUponStarredChangesRefReplicationDoneEvent()
- throws Exception {
- consumerShouldNotUpdateProjectVersionUponMagicRefReplicationDoneEvent(
- RefNames.REFS_STARRED_CHANGES);
- }
-
- private void consumerShouldNotUpdateProjectVersionUponMagicRefReplicationDoneEvent(
- String magicRefPrefix) throws Exception {
- String magicRef = magicRefPrefix + "/foo";
- Context.setForwardedEvent(true);
- RefReplicationDoneEvent refReplicationDoneEvent =
- new RefReplicationDoneEvent(A_TEST_PROJECT_NAME, magicRef, 1);
- repo.branch(magicRef).commit().create();
-
- new ProjectVersionRefUpdate(repoManager, sharedRefDb).onEvent(refReplicationDoneEvent);
-
- Ref ref = repo.getRepository().findRef(MULTI_SITE_VERSIONING_REF);
- assertThat(ref).isNull();
+ verifyZeroInteractions(verLogger);
}
@Test
@@ -193,31 +202,10 @@
.thenReturn(Optional.of("123"));
Optional<Long> version =
- new ProjectVersionRefUpdate(repoManager, sharedRefDb)
+ new ProjectVersionRefUpdate(repoManager, sharedRefDb, gitReferenceUpdated, verLogger)
.getProjectRemoteVersion(A_TEST_PROJECT_NAME);
assertThat(version.isPresent()).isTrue();
assertThat(version.get()).isEqualTo(123L);
}
-
- @Test
- public void getLocalProjectVersionShouldReturnCorrectValue() throws IOException {
- updateLocalVersion();
- Ref ref = repo.getRepository().findRef(MULTI_SITE_VERSIONING_REF);
- assertThat(ref).isNotNull();
-
- Optional<Long> version =
- new ProjectVersionRefUpdate(repoManager, sharedRefDb)
- .getProjectLocalVersion(A_TEST_PROJECT_NAME);
-
- assertThat(version.isPresent()).isTrue();
- assertThat(version.get()).isEqualTo(masterCommit.getCommitTime());
- }
-
- private void updateLocalVersion() {
- Context.setForwardedEvent(true);
- RefReplicationDoneEvent refReplicatedEvent =
- new RefReplicationDoneEvent(A_TEST_PROJECT_NAME, A_TEST_REF_NAME, 1);
- new ProjectVersionRefUpdate(repoManager, sharedRefDb).onEvent(refReplicatedEvent);
- }
}