Index change upon propagation When a change gets replicated from one master to another the change needs to be automatically reindexed on the destination instance. Feature: Issue 11616 Change-Id: I5373bb8149ce5096e3e4a34d214540cc9639ea89
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/FetchRefReplicatedEvent.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/FetchRefReplicatedEvent.java index eb825b8..cad6dfb 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/FetchRefReplicatedEvent.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/FetchRefReplicatedEvent.java
@@ -42,6 +42,10 @@ this.refUpdateResult = refUpdateResult; } + public String getStatus() { + return status; + } + @Override public int hashCode() { return Objects.hash(project, ref, status, refUpdateResult);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationModule.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationModule.java index 9add07c..816aaca 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationModule.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationModule.java
@@ -44,6 +44,7 @@ import com.googlesource.gerrit.plugins.replication.pull.client.FetchRestApiClient; import com.googlesource.gerrit.plugins.replication.pull.client.HttpClient; import com.googlesource.gerrit.plugins.replication.pull.client.SourceHttpClient; +import com.googlesource.gerrit.plugins.replication.pull.event.FetchRefReplicatedEventModule; import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -67,6 +68,8 @@ install(new PullReplicationApiModule()); + install(new FetchRefReplicatedEventModule()); + install( new FactoryModuleBuilder() .implement(HttpClient.class, SourceHttpClient.class)
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/event/FetchRefReplicatedEventHandler.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/event/FetchRefReplicatedEventHandler.java new file mode 100644 index 0000000..fc96394 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/event/FetchRefReplicatedEventHandler.java
@@ -0,0 +1,58 @@ +// Copyright (C) 2021 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.replication.pull.event; + +import com.google.common.flogger.FluentLogger; +import com.google.gerrit.entities.Change; +import com.google.gerrit.entities.Project; +import com.google.gerrit.server.events.Event; +import com.google.gerrit.server.events.EventListener; +import com.google.gerrit.server.index.change.ChangeIndexer; +import com.google.inject.Inject; +import com.googlesource.gerrit.plugins.replication.pull.FetchRefReplicatedEvent; +import com.googlesource.gerrit.plugins.replication.pull.ReplicationState; + +public class FetchRefReplicatedEventHandler implements EventListener { + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); + private ChangeIndexer changeIndexer; + + @Inject + FetchRefReplicatedEventHandler(ChangeIndexer changeIndexer) { + this.changeIndexer = changeIndexer; + } + + @Override + public void onEvent(Event event) { + if (event instanceof FetchRefReplicatedEvent) { + FetchRefReplicatedEvent fetchRefReplicatedEvent = (FetchRefReplicatedEvent) event; + Project.NameKey projectNameKey = fetchRefReplicatedEvent.getProjectNameKey(); + logger.atFine().log( + "Indexing ref '%s' for project %s", + fetchRefReplicatedEvent.getRefName(), projectNameKey.get()); + + Change.Id changeId = Change.Id.fromRef(fetchRefReplicatedEvent.getRefName()); + if (changeId != null + && fetchRefReplicatedEvent + .getStatus() + .equals(ReplicationState.RefFetchResult.SUCCEEDED.toString())) { + changeIndexer.index(projectNameKey, changeId); + } else { + logger.atWarning().log( + "Couldn't get changeId from refName. Skipping indexing of change %s for project %s", + fetchRefReplicatedEvent.getRefName(), projectNameKey.get()); + } + } + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/event/FetchRefReplicatedEventModule.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/event/FetchRefReplicatedEventModule.java new file mode 100644 index 0000000..675563a --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/event/FetchRefReplicatedEventModule.java
@@ -0,0 +1,27 @@ +// Copyright (C) 2021 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.replication.pull.event; + +import com.google.gerrit.extensions.registration.DynamicSet; +import com.google.gerrit.lifecycle.LifecycleModule; +import com.google.gerrit.server.events.EventListener; + +public class FetchRefReplicatedEventModule extends LifecycleModule { + + @Override + protected void configure() { + DynamicSet.bind(binder(), EventListener.class).to(FetchRefReplicatedEventHandler.class); + } +}
diff --git a/src/main/resources/Documentation/about.md b/src/main/resources/Documentation/about.md index d921e0b..22b52e7 100644 --- a/src/main/resources/Documentation/about.md +++ b/src/main/resources/Documentation/about.md
@@ -15,3 +15,8 @@ To be allowed to trigger pull replication a user must be a member of a group that is granted the 'Pull Replication' capability (provided by this plugin) or the 'Administrate Server' capability. + +Change Indexing +-------- + +Changes will be automatically indexed upon replication.
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/event/FetchRefReplicatedEventHandlerTest.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/event/FetchRefReplicatedEventHandlerTest.java new file mode 100644 index 0000000..1d87195 --- /dev/null +++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/event/FetchRefReplicatedEventHandlerTest.java
@@ -0,0 +1,97 @@ +// Copyright (C) 2021 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.replication.pull.event; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import com.google.gerrit.entities.Change; +import com.google.gerrit.entities.Project; +import com.google.gerrit.server.index.change.ChangeIndexer; +import com.googlesource.gerrit.plugins.replication.pull.FetchRefReplicatedEvent; +import com.googlesource.gerrit.plugins.replication.pull.ReplicationState; +import org.eclipse.jgit.lib.RefUpdate; +import org.junit.Before; +import org.junit.Test; + +public class FetchRefReplicatedEventHandlerTest { + private ChangeIndexer changeIndexerMock; + private FetchRefReplicatedEventHandler fetchRefReplicatedEventHandler; + + @Before + public void setUp() throws Exception { + changeIndexerMock = mock(ChangeIndexer.class); + fetchRefReplicatedEventHandler = new FetchRefReplicatedEventHandler(changeIndexerMock); + } + + @Test + public void onEventShouldIndexExistingChange() { + Project.NameKey projectNameKey = Project.nameKey("testProject"); + String ref = "refs/changes/41/41/meta"; + Change.Id changeId = Change.Id.fromRef(ref); + fetchRefReplicatedEventHandler.onEvent( + new FetchRefReplicatedEvent( + projectNameKey.get(), + ref, + "aSourceNode", + ReplicationState.RefFetchResult.SUCCEEDED, + RefUpdate.Result.FAST_FORWARD)); + verify(changeIndexerMock, times(1)).index(eq(projectNameKey), eq(changeId)); + } + + @Test + public void onEventShouldNotIndexMissingChange() { + fetchRefReplicatedEventHandler.onEvent( + new FetchRefReplicatedEvent( + Project.nameKey("testProject").get(), + "invalidRef", + "aSourceNode", + ReplicationState.RefFetchResult.SUCCEEDED, + RefUpdate.Result.FAST_FORWARD)); + verify(changeIndexerMock, never()).index(any(), any()); + } + + @Test + public void onEventShouldNotIndexFailingChange() { + Project.NameKey projectNameKey = Project.nameKey("testProject"); + String ref = "refs/changes/41/41/meta"; + fetchRefReplicatedEventHandler.onEvent( + new FetchRefReplicatedEvent( + projectNameKey.get(), + ref, + "aSourceNode", + ReplicationState.RefFetchResult.FAILED, + RefUpdate.Result.FAST_FORWARD)); + verify(changeIndexerMock, never()).index(any(), any()); + } + + @Test + public void onEventShouldNotIndexNotAttemptedChange() { + Project.NameKey projectNameKey = Project.nameKey("testProject"); + String ref = "refs/changes/41/41/meta"; + fetchRefReplicatedEventHandler.onEvent( + new FetchRefReplicatedEvent( + projectNameKey.get(), + ref, + "aSourceNode", + ReplicationState.RefFetchResult.NOT_ATTEMPTED, + RefUpdate.Result.FAST_FORWARD)); + verify(changeIndexerMock, never()).index(any(), any()); + } +}