Cover source code of high-availability plugin jgroups mode with tests
Feature: Issue 10020
Change-Id: Icc11d4287c64be10d3bcebed73c8bcb627886d85
diff --git a/BUILD b/BUILD
index 5975b31..9607415 100644
--- a/BUILD
+++ b/BUILD
@@ -47,5 +47,7 @@
":high-availability__plugin",
"@global-refdb//jar",
"@wiremock//jar",
+ "@jgroups//jar",
+ "@commons-net//jar"
],
)
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProvider.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProvider.java
index ce47390..0e3fdc0 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProvider.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProvider.java
@@ -16,6 +16,7 @@
import com.ericsson.gerrit.plugins.highavailability.Configuration;
import com.ericsson.gerrit.plugins.highavailability.peers.PeerInfo;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSet;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.events.LifecycleListener;
@@ -157,6 +158,16 @@
}
}
+ @VisibleForTesting
+ void setChannel(JChannel channel) {
+ this.channel = channel;
+ }
+
+ @VisibleForTesting
+ void setPeerInfo(Optional<PeerInfo> peerInfo) {
+ this.peerInfo = peerInfo;
+ }
+
@Override
public Set<PeerInfo> get() {
return peerInfo.isPresent() ? ImmutableSet.of(peerInfo.get()) : ImmutableSet.of();
@@ -178,4 +189,14 @@
peerInfo = Optional.empty();
peerAddress = null;
}
+
+ @VisibleForTesting
+ Address getPeerAddress() {
+ return peerAddress;
+ }
+
+ @VisibleForTesting
+ void setPeerAddress(Address peerAddress) {
+ this.peerAddress = peerAddress;
+ }
}
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/ChangeCheckerImplTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/ChangeCheckerImplTest.java
new file mode 100644
index 0000000..38f71e5
--- /dev/null
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/ChangeCheckerImplTest.java
@@ -0,0 +1,84 @@
+// Copyright (C) 2022 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.ericsson.gerrit.plugins.highavailability.index;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
+import com.ericsson.gerrit.plugins.highavailability.forwarder.IndexEvent;
+import com.google.gerrit.entities.Change;
+import com.google.gerrit.server.CommentsUtil;
+import com.google.gerrit.server.change.ChangeFinder;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.notedb.ChangeNotes;
+import com.google.gerrit.server.util.OneOffRequestContext;
+import java.io.IOException;
+import java.sql.Timestamp;
+import java.time.Instant;
+import java.util.Optional;
+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 ChangeCheckerImplTest {
+
+ @Mock private GitRepositoryManager gitRepoMgr;
+ @Mock private CommentsUtil commentsUtil;
+ @Mock private ChangeFinder changeFinder;
+ @Mock private OneOffRequestContext oneOffReqCtx;
+ @Mock private ChangeNotes testChangeNotes;
+ @Mock private Change testChange;
+
+ private final Instant testLastUpdatedOn = Instant.now();
+ private final String changeId = "1";
+ Optional<IndexEvent> event = Optional.empty();
+ private Optional<Long> computedChangeTs = Optional.empty();
+ private ChangeCheckerImpl changeChecker;
+
+ @Before
+ public void setUp() {
+ changeChecker =
+ new ChangeCheckerImpl(gitRepoMgr, commentsUtil, changeFinder, oneOffReqCtx, changeId);
+ }
+
+ @Test
+ public void testGetChangeNotes() {
+ when(changeFinder.findOne(changeId)).thenReturn(Optional.of(testChangeNotes));
+ assertThat(changeChecker.getChangeNotes()).isEqualTo(Optional.of(testChangeNotes));
+ }
+
+ @Test
+ public void testGetComputedChangeTs() {
+ long testTime = Timestamp.from(testLastUpdatedOn).getTime();
+ computedChangeTs = Optional.of(testTime / 1000);
+ when(changeChecker.getChangeNotes()).thenReturn(Optional.of(testChangeNotes));
+ when(testChangeNotes.getChange()).thenReturn(testChange);
+ when(testChange.getLastUpdatedOn()).thenReturn(testLastUpdatedOn);
+ assertThat(changeChecker.getComputedChangeTs()).isEqualTo(computedChangeTs);
+ }
+
+ @Test
+ public void testNewIndexEventWhenChangeTimeStampIsEmpty() throws IOException {
+ assertThat(changeChecker.newIndexEvent().isPresent()).isFalse();
+ }
+
+ @Test
+ public void testIsChangeUpToDateWhenComputedChangeTsIsNotPresent() throws IOException {
+ assertThat(changeChecker.isChangeUpToDate(event)).isFalse();
+ }
+}
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/InetAddressFinderTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/InetAddressFinderTest.java
index bfcffbb..c375345 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/InetAddressFinderTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/InetAddressFinderTest.java
@@ -16,10 +16,20 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Answers.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.ericsson.gerrit.plugins.highavailability.Configuration;
import com.google.common.collect.ImmutableList;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -32,11 +42,68 @@
@Mock(answer = RETURNS_DEEP_STUBS)
private Configuration configuration;
+ @Mock private NetworkInterface mockInterface;
+
private InetAddressFinder finder;
+ private List<NetworkInterface> testNetworkInterfaces;
@Before
public void setUp() {
finder = new InetAddressFinder(configuration);
+ testNetworkInterfaces = new ArrayList<>();
+ }
+
+ @Test
+ public void testNoSuitableInterfaceWhenFindFirstAppropriateAddress() throws SocketException {
+ when(mockInterface.isLoopback()).thenReturn(true);
+ when(configuration.jgroups().skipInterface()).thenReturn(ImmutableList.of("mockInterface1"));
+ testNetworkInterfaces.add(mockInterface);
+ assertThat(finder.findFirstAppropriateAddress(testNetworkInterfaces).isPresent()).isFalse();
+ }
+
+ @Test
+ public void testOptionalEmptyIsReturnedWhenFindFirstAppropriateAddress() throws SocketException {
+ setUpCustomMockInterfaceMocks();
+ when(configuration.jgroups().skipInterface()).thenReturn(ImmutableList.of());
+ testNetworkInterfaces.add(mockInterface);
+ Enumeration mockInetAddresses = mock(Enumeration.class);
+
+ when(mockInterface.getInetAddresses()).thenReturn(mockInetAddresses);
+ assertThat(finder.findFirstAppropriateAddress(testNetworkInterfaces))
+ .isEqualTo(Optional.empty());
+ }
+
+ @Test
+ public void testInet6AddressIsReturnedWhenFindFirstAppropriateAddress() throws SocketException {
+ setUpCustomMockInterfaceMocks();
+ when(configuration.jgroups().skipInterface()).thenReturn(ImmutableList.of());
+ testNetworkInterfaces.add(mockInterface);
+ Inet6Address mockInet6Address = mock(Inet6Address.class);
+ List<Inet6Address> mocklist = new ArrayList<>();
+ mocklist.add(mockInet6Address);
+ Enumeration mockInetAddresses = Collections.enumeration(mocklist);
+
+ when(mockInterface.getInetAddresses()).thenReturn(mockInetAddresses);
+ assertThat(finder.findFirstAppropriateAddress(testNetworkInterfaces))
+ .isEqualTo(Optional.of(mockInet6Address));
+ }
+
+ @Test
+ public void testInet4AddressIsReturnedWhenFindFirstAppropriateAddress() throws SocketException {
+ setUpCustomMockInterfaceMocks();
+ when(configuration.jgroups().skipInterface()).thenReturn(ImmutableList.of());
+ System.setProperty("java.net.preferIPv4Stack", "true");
+ testNetworkInterfaces.add(mockInterface);
+ Inet4Address mockInet4Address = mock(Inet4Address.class);
+ List<Inet4Address> mocklist = new ArrayList<>();
+ mocklist.add(mockInet4Address);
+
+ Enumeration mockInetAddresses = Collections.enumeration(mocklist);
+ when(mockInterface.getInetAddresses()).thenReturn(mockInetAddresses);
+
+ finder = new InetAddressFinder(configuration);
+ assertThat(finder.findFirstAppropriateAddress(testNetworkInterfaces))
+ .isEqualTo(Optional.of(mockInet4Address));
}
@Test
@@ -64,4 +131,10 @@
assertThat(finder.shouldSkip("foo1")).isTrue();
assertThat(finder.shouldSkip("bar")).isFalse();
}
+
+ private void setUpCustomMockInterfaceMocks() throws SocketException {
+ when(mockInterface.isLoopback()).thenReturn(false);
+ when(mockInterface.isUp()).thenReturn(true);
+ when(mockInterface.supportsMulticast()).thenReturn(true);
+ }
}
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProviderTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProviderTest.java
new file mode 100644
index 0000000..1110fc3
--- /dev/null
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProviderTest.java
@@ -0,0 +1,158 @@
+// Copyright (C) 2022 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.ericsson.gerrit.plugins.highavailability.peers.jgroups;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Answers.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.when;
+
+import com.ericsson.gerrit.plugins.highavailability.Configuration;
+import com.ericsson.gerrit.plugins.highavailability.peers.PeerInfo;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import org.jgroups.Address;
+import org.jgroups.JChannel;
+import org.jgroups.Message;
+import org.jgroups.View;
+import org.jgroups.stack.IpAddress;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.Test.None;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class JGroupsPeerInfoProviderTest {
+
+ @Mock(answer = RETURNS_DEEP_STUBS)
+ private Configuration pluginConfigurationMock;
+
+ private InetAddressFinder finder;
+ private JGroupsPeerInfoProvider jGroupsPeerInfoProvider;
+ private Optional<PeerInfo> peerInfo;
+ @Mock private JChannel channel;
+ @Mock private MyUrlProvider myUrlProviderTest;
+ @Mock private Message message;
+ @Mock private Address peerAddress;
+ @Mock private View view;
+ @Mock private List<Address> members;
+
+ @Before
+ public void setUp() throws Exception {
+ finder = new InetAddressFinder(pluginConfigurationMock);
+ jGroupsPeerInfoProvider =
+ new JGroupsPeerInfoProvider(pluginConfigurationMock, finder, myUrlProviderTest);
+ peerInfo = Optional.of(new PeerInfo("test message"));
+ channel.setName("testChannel");
+ }
+
+ @Test
+ public void testRecieveWhenPeerAddressIsNull() {
+ when(message.getSrc()).thenReturn(peerAddress);
+ when(message.getObject()).thenReturn("test message");
+
+ jGroupsPeerInfoProvider.receive(message);
+
+ assertThat(jGroupsPeerInfoProvider.getPeerAddress()).isEqualTo(peerAddress);
+ Set<PeerInfo> testPeerInfoSet = jGroupsPeerInfoProvider.get();
+ for (PeerInfo testPeerInfo : testPeerInfoSet) {
+ assertThat(testPeerInfo.getDirectUrl()).contains("test message");
+ }
+ assertThat(testPeerInfoSet.size()).isEqualTo(1);
+ }
+
+ @Test
+ public void testReceiveWhenPeerAddressIsNotNull() throws Exception {
+ jGroupsPeerInfoProvider.setPeerAddress(new IpAddress("checkAddress.com"));
+
+ jGroupsPeerInfoProvider.receive(message);
+
+ Set<PeerInfo> testPeerInfoSet = jGroupsPeerInfoProvider.get();
+ assertThat(testPeerInfoSet.isEmpty()).isTrue();
+ assertThat(testPeerInfoSet.size()).isEqualTo(0);
+ }
+
+ @Test(expected = None.class)
+ public void testViewAcceptedWithNoExceptionThrown() throws Exception {
+ when(view.getMembers()).thenReturn(members);
+ when(view.size()).thenReturn(3);
+ when(members.size()).thenReturn(3);
+ jGroupsPeerInfoProvider.setChannel(channel);
+ jGroupsPeerInfoProvider.viewAccepted(view);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testViewAcceptedWithExceptionThrown() throws Exception {
+ when(view.getMembers()).thenReturn(members);
+ when(view.size()).thenReturn(2);
+ when(members.size()).thenReturn(2);
+ jGroupsPeerInfoProvider.viewAccepted(view);
+ }
+
+ @Test
+ public void testViewAcceptedWhenPeerAddressIsNotNullAndIsNotMemberOfView() {
+ when(view.getMembers()).thenReturn(members);
+ when(view.size()).thenReturn(2);
+ when(members.size()).thenReturn(2);
+ when(members.contains(peerAddress)).thenReturn(false);
+ jGroupsPeerInfoProvider.setPeerAddress(peerAddress);
+ jGroupsPeerInfoProvider.setPeerInfo(peerInfo);
+ jGroupsPeerInfoProvider.setChannel(channel);
+ jGroupsPeerInfoProvider.viewAccepted(view);
+
+ assertThat(jGroupsPeerInfoProvider.getPeerAddress()).isEqualTo(null);
+ Set<PeerInfo> testPeerInfoSet = jGroupsPeerInfoProvider.get();
+ assertThat(testPeerInfoSet.isEmpty()).isTrue();
+ assertThat(testPeerInfoSet.size()).isEqualTo(0);
+ }
+
+ @Test
+ public void testConnect() throws NoSuchFieldException, IllegalAccessException {
+ jGroupsPeerInfoProvider.connect();
+ Set<PeerInfo> testPeerInfoSet = jGroupsPeerInfoProvider.get();
+ assertThat(testPeerInfoSet.isEmpty()).isTrue();
+ assertThat(testPeerInfoSet.size()).isEqualTo(0);
+ }
+
+ @Test
+ public void testGetWhenPeerInfoIsOptionalEmpty() {
+ Set<PeerInfo> testPeerInfoSet = jGroupsPeerInfoProvider.get();
+ assertThat(testPeerInfoSet.isEmpty()).isTrue();
+ assertThat(testPeerInfoSet.size()).isEqualTo(0);
+ }
+
+ @Test
+ public void testGetWhenPeerInfoIsPresent() {
+ jGroupsPeerInfoProvider.setPeerInfo(peerInfo);
+ Set<PeerInfo> testPeerInfoSet = jGroupsPeerInfoProvider.get();
+ for (PeerInfo testPeerInfo : testPeerInfoSet) {
+ assertThat(testPeerInfo.getDirectUrl()).contains("test message");
+ }
+ assertThat(testPeerInfoSet.size()).isEqualTo(1);
+ }
+
+ @Test
+ public void testStop() throws Exception {
+ jGroupsPeerInfoProvider.setPeerAddress(peerAddress);
+ jGroupsPeerInfoProvider.setPeerInfo(peerInfo);
+ jGroupsPeerInfoProvider.stop();
+ assertThat(jGroupsPeerInfoProvider.getPeerAddress()).isEqualTo(null);
+ Set<PeerInfo> testPeerInfoSet = jGroupsPeerInfoProvider.get();
+ assertThat(testPeerInfoSet.isEmpty()).isTrue();
+ assertThat(testPeerInfoSet.size()).isEqualTo(0);
+ }
+}
diff --git a/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 0000000..1f0955d
--- /dev/null
+++ b/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1 @@
+mock-maker-inline