Ray Milkey
Committed by Gerrit Code Review

Unit tests for the distributed group store.

Change-Id: Ie8f00b9bbc1ba46a6f80e70f63d1fd853d64154b
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.store.cluster.messaging;
17 +
18 +import java.util.Set;
19 +import java.util.concurrent.CompletableFuture;
20 +import java.util.concurrent.Executor;
21 +import java.util.concurrent.ExecutorService;
22 +import java.util.function.Consumer;
23 +import java.util.function.Function;
24 +
25 +import org.onosproject.cluster.NodeId;
26 +
27 +/**
28 + * Testing adapter for the cluster communication service.
29 + */
30 +public class ClusterCommunicationServiceAdapter
31 + implements ClusterCommunicationService {
32 +
33 + @Override
34 + public void addSubscriber(MessageSubject subject,
35 + ClusterMessageHandler subscriber,
36 + ExecutorService executor) {
37 + }
38 +
39 + @Override
40 + public void removeSubscriber(MessageSubject subject) {}
41 +
42 + @Override
43 + public <M> void broadcast(M message, MessageSubject subject,
44 + Function<M, byte[]> encoder) {
45 + }
46 +
47 + @Override
48 + public <M> void broadcastIncludeSelf(M message,
49 + MessageSubject subject, Function<M, byte[]> encoder) {
50 + }
51 +
52 + @Override
53 + public <M> CompletableFuture<Void> unicast(M message, MessageSubject subject,
54 + Function<M, byte[]> encoder, NodeId toNodeId) {
55 + return null;
56 + }
57 +
58 + @Override
59 + public <M> void multicast(M message, MessageSubject subject,
60 + Function<M, byte[]> encoder, Set<NodeId> nodes) {
61 + }
62 +
63 + @Override
64 + public <M, R> CompletableFuture<R> sendAndReceive(M message,
65 + MessageSubject subject, Function<M, byte[]> encoder,
66 + Function<byte[], R> decoder, NodeId toNodeId) {
67 + return null;
68 + }
69 +
70 + @Override
71 + public <M, R> void addSubscriber(MessageSubject subject,
72 + Function<byte[], M> decoder, Function<M, R> handler,
73 + Function<R, byte[]> encoder, Executor executor) {
74 + }
75 +
76 + @Override
77 + public <M, R> void addSubscriber(MessageSubject subject,
78 + Function<byte[], M> decoder, Function<M, CompletableFuture<R>> handler,
79 + Function<R, byte[]> encoder) {
80 + }
81 +
82 + @Override
83 + public <M> void addSubscriber(MessageSubject subject,
84 + Function<byte[], M> decoder, Consumer<M> handler,
85 + Executor executor) {
86 +
87 + }
88 +}
...@@ -91,8 +91,10 @@ public final class TestEventuallyConsistentMap<K, V> extends EventuallyConsisten ...@@ -91,8 +91,10 @@ public final class TestEventuallyConsistentMap<K, V> extends EventuallyConsisten
91 EventuallyConsistentMapEvent<K, V> addEvent = 91 EventuallyConsistentMapEvent<K, V> addEvent =
92 new EventuallyConsistentMapEvent<>(mapName, PUT, key, value); 92 new EventuallyConsistentMapEvent<>(mapName, PUT, key, value);
93 notifyListeners(addEvent); 93 notifyListeners(addEvent);
94 + if (peerUpdateFunction != null) {
94 peerUpdateFunction.apply(key, value); 95 peerUpdateFunction.apply(key, value);
95 } 96 }
97 + }
96 98
97 @Override 99 @Override
98 public V remove(K key) { 100 public V remove(K key) {
......
...@@ -1014,7 +1014,7 @@ public class DistributedGroupStore ...@@ -1014,7 +1014,7 @@ public class DistributedGroupStore
1014 /** 1014 /**
1015 * Flattened map key to be used to store group entries. 1015 * Flattened map key to be used to store group entries.
1016 */ 1016 */
1017 - private class GroupStoreMapKey { 1017 + protected static class GroupStoreMapKey {
1018 private final DeviceId deviceId; 1018 private final DeviceId deviceId;
1019 1019
1020 public GroupStoreMapKey(DeviceId deviceId) { 1020 public GroupStoreMapKey(DeviceId deviceId) {
...@@ -1047,7 +1047,7 @@ public class DistributedGroupStore ...@@ -1047,7 +1047,7 @@ public class DistributedGroupStore
1047 } 1047 }
1048 } 1048 }
1049 1049
1050 - private class GroupStoreKeyMapKey extends GroupStoreMapKey { 1050 + protected static class GroupStoreKeyMapKey extends GroupStoreMapKey {
1051 private final GroupKey appCookie; 1051 private final GroupKey appCookie;
1052 public GroupStoreKeyMapKey(DeviceId deviceId, 1052 public GroupStoreKeyMapKey(DeviceId deviceId,
1053 GroupKey appCookie) { 1053 GroupKey appCookie) {
...@@ -1078,7 +1078,7 @@ public class DistributedGroupStore ...@@ -1078,7 +1078,7 @@ public class DistributedGroupStore
1078 } 1078 }
1079 } 1079 }
1080 1080
1081 - private class GroupStoreIdMapKey extends GroupStoreMapKey { 1081 + protected static class GroupStoreIdMapKey extends GroupStoreMapKey {
1082 private final GroupId groupId; 1082 private final GroupId groupId;
1083 public GroupStoreIdMapKey(DeviceId deviceId, 1083 public GroupStoreIdMapKey(DeviceId deviceId,
1084 GroupId groupId) { 1084 GroupId groupId) {
......
...@@ -15,10 +15,22 @@ ...@@ -15,10 +15,22 @@
15 */ 15 */
16 package org.onosproject.store.ecmap; 16 package org.onosproject.store.ecmap;
17 17
18 -import com.google.common.collect.ComparisonChain; 18 +import java.util.ArrayList;
19 -import com.google.common.collect.ImmutableList; 19 +import java.util.Collection;
20 -import com.google.common.collect.ImmutableSet; 20 +import java.util.HashMap;
21 -import com.google.common.util.concurrent.MoreExecutors; 21 +import java.util.HashSet;
22 +import java.util.List;
23 +import java.util.Map;
24 +import java.util.Objects;
25 +import java.util.Optional;
26 +import java.util.Set;
27 +import java.util.concurrent.CompletableFuture;
28 +import java.util.concurrent.CountDownLatch;
29 +import java.util.concurrent.Executor;
30 +import java.util.concurrent.TimeUnit;
31 +import java.util.concurrent.atomic.AtomicLong;
32 +import java.util.function.Consumer;
33 +import java.util.function.Function;
22 34
23 import org.junit.After; 35 import org.junit.After;
24 import org.junit.Before; 36 import org.junit.Before;
...@@ -32,38 +44,35 @@ import org.onosproject.cluster.NodeId; ...@@ -32,38 +44,35 @@ import org.onosproject.cluster.NodeId;
32 import org.onosproject.event.AbstractEvent; 44 import org.onosproject.event.AbstractEvent;
33 import org.onosproject.store.Timestamp; 45 import org.onosproject.store.Timestamp;
34 import org.onosproject.store.cluster.messaging.ClusterCommunicationService; 46 import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
35 -import org.onosproject.store.cluster.messaging.ClusterMessageHandler; 47 +import org.onosproject.store.cluster.messaging.ClusterCommunicationServiceAdapter;
36 import org.onosproject.store.cluster.messaging.MessageSubject; 48 import org.onosproject.store.cluster.messaging.MessageSubject;
37 import org.onosproject.store.impl.LogicalTimestamp; 49 import org.onosproject.store.impl.LogicalTimestamp;
38 -import org.onosproject.store.service.WallClockTimestamp;
39 import org.onosproject.store.serializers.KryoNamespaces; 50 import org.onosproject.store.serializers.KryoNamespaces;
40 import org.onosproject.store.serializers.KryoSerializer; 51 import org.onosproject.store.serializers.KryoSerializer;
41 import org.onosproject.store.service.EventuallyConsistentMap; 52 import org.onosproject.store.service.EventuallyConsistentMap;
42 import org.onosproject.store.service.EventuallyConsistentMapEvent; 53 import org.onosproject.store.service.EventuallyConsistentMapEvent;
43 import org.onosproject.store.service.EventuallyConsistentMapListener; 54 import org.onosproject.store.service.EventuallyConsistentMapListener;
55 +import org.onosproject.store.service.WallClockTimestamp;
44 56
45 -import java.util.ArrayList; 57 +import com.google.common.collect.ComparisonChain;
46 -import java.util.Collection; 58 +import com.google.common.collect.ImmutableList;
47 -import java.util.HashMap; 59 +import com.google.common.collect.ImmutableSet;
48 -import java.util.HashSet; 60 +import com.google.common.util.concurrent.MoreExecutors;
49 -import java.util.List;
50 -import java.util.Map;
51 -import java.util.Objects;
52 -import java.util.Optional;
53 -import java.util.Set;
54 -import java.util.concurrent.CompletableFuture;
55 -import java.util.concurrent.CountDownLatch;
56 -import java.util.concurrent.Executor;
57 -import java.util.concurrent.ExecutorService;
58 -import java.util.concurrent.TimeUnit;
59 -import java.util.concurrent.atomic.AtomicLong;
60 -import java.util.function.Consumer;
61 -import java.util.function.Function;
62 61
63 import static com.google.common.base.Preconditions.checkArgument; 62 import static com.google.common.base.Preconditions.checkArgument;
64 import static junit.framework.TestCase.assertFalse; 63 import static junit.framework.TestCase.assertFalse;
65 -import static org.easymock.EasyMock.*; 64 +import static org.easymock.EasyMock.anyObject;
66 -import static org.junit.Assert.*; 65 +import static org.easymock.EasyMock.createMock;
66 +import static org.easymock.EasyMock.eq;
67 +import static org.easymock.EasyMock.expect;
68 +import static org.easymock.EasyMock.expectLastCall;
69 +import static org.easymock.EasyMock.replay;
70 +import static org.easymock.EasyMock.reset;
71 +import static org.easymock.EasyMock.verify;
72 +import static org.junit.Assert.assertEquals;
73 +import static org.junit.Assert.assertNull;
74 +import static org.junit.Assert.assertTrue;
75 +import static org.junit.Assert.fail;
67 76
68 /** 77 /**
69 * Unit tests for EventuallyConsistentMapImpl. 78 * Unit tests for EventuallyConsistentMapImpl.
...@@ -697,7 +706,7 @@ public class EventuallyConsistentMapImplTest { ...@@ -697,7 +706,7 @@ public class EventuallyConsistentMapImplTest {
697 * Sets up a mock ClusterCommunicationService to expect a specific cluster 706 * Sets up a mock ClusterCommunicationService to expect a specific cluster
698 * message to be broadcast to the cluster. 707 * message to be broadcast to the cluster.
699 * 708 *
700 - * @param m message we expect to be sent 709 + * @param message message we expect to be sent
701 * @param clusterCommunicator a mock ClusterCommunicationService to set up 710 * @param clusterCommunicator a mock ClusterCommunicationService to set up
702 */ 711 */
703 //FIXME rename 712 //FIXME rename
...@@ -776,56 +785,7 @@ public class EventuallyConsistentMapImplTest { ...@@ -776,56 +785,7 @@ public class EventuallyConsistentMapImplTest {
776 * events coming in from other instances. 785 * events coming in from other instances.
777 */ 786 */
778 private final class TestClusterCommunicationService 787 private final class TestClusterCommunicationService
779 - implements ClusterCommunicationService { 788 + extends ClusterCommunicationServiceAdapter {
780 -
781 - @Override
782 - public void addSubscriber(MessageSubject subject,
783 - ClusterMessageHandler subscriber,
784 - ExecutorService executor) {
785 - }
786 -
787 - @Override
788 - public void removeSubscriber(MessageSubject subject) {}
789 -
790 - @Override
791 - public <M> void broadcast(M message, MessageSubject subject,
792 - Function<M, byte[]> encoder) {
793 - }
794 -
795 - @Override
796 - public <M> void broadcastIncludeSelf(M message,
797 - MessageSubject subject, Function<M, byte[]> encoder) {
798 - }
799 -
800 - @Override
801 - public <M> CompletableFuture<Void> unicast(M message, MessageSubject subject,
802 - Function<M, byte[]> encoder, NodeId toNodeId) {
803 - return null;
804 - }
805 -
806 - @Override
807 - public <M> void multicast(M message, MessageSubject subject,
808 - Function<M, byte[]> encoder, Set<NodeId> nodes) {
809 - }
810 -
811 - @Override
812 - public <M, R> CompletableFuture<R> sendAndReceive(M message,
813 - MessageSubject subject, Function<M, byte[]> encoder,
814 - Function<byte[], R> decoder, NodeId toNodeId) {
815 - return null;
816 - }
817 -
818 - @Override
819 - public <M, R> void addSubscriber(MessageSubject subject,
820 - Function<byte[], M> decoder, Function<M, R> handler,
821 - Function<R, byte[]> encoder, Executor executor) {
822 - }
823 -
824 - @Override
825 - public <M, R> void addSubscriber(MessageSubject subject,
826 - Function<byte[], M> decoder, Function<M, CompletableFuture<R>> handler,
827 - Function<R, byte[]> encoder) {
828 - }
829 789
830 @Override 790 @Override
831 public <M> void addSubscriber(MessageSubject subject, 791 public <M> void addSubscriber(MessageSubject subject,
......
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.store.group.impl;
17 +
18 +import java.util.ArrayList;
19 +import java.util.LinkedList;
20 +import java.util.List;
21 +
22 +import org.junit.After;
23 +import org.junit.Before;
24 +import org.junit.Test;
25 +import org.onlab.junit.TestUtils;
26 +import org.onosproject.core.DefaultGroupId;
27 +import org.onosproject.core.GroupId;
28 +import org.onosproject.mastership.MastershipServiceAdapter;
29 +import org.onosproject.net.DeviceId;
30 +import org.onosproject.net.MastershipRole;
31 +import org.onosproject.net.PortNumber;
32 +import org.onosproject.net.flow.DefaultTrafficTreatment;
33 +import org.onosproject.net.flow.TrafficTreatment;
34 +import org.onosproject.net.group.DefaultGroup;
35 +import org.onosproject.net.group.DefaultGroupBucket;
36 +import org.onosproject.net.group.DefaultGroupDescription;
37 +import org.onosproject.net.group.DefaultGroupKey;
38 +import org.onosproject.net.group.Group;
39 +import org.onosproject.net.group.GroupBucket;
40 +import org.onosproject.net.group.GroupBuckets;
41 +import org.onosproject.net.group.GroupDescription;
42 +import org.onosproject.net.group.GroupEvent;
43 +import org.onosproject.net.group.GroupKey;
44 +import org.onosproject.net.group.GroupOperation;
45 +import org.onosproject.net.group.GroupStore;
46 +import org.onosproject.net.group.GroupStoreDelegate;
47 +import org.onosproject.store.cluster.messaging.ClusterCommunicationServiceAdapter;
48 +import org.onosproject.store.service.EventuallyConsistentMap;
49 +import org.onosproject.store.service.TestStorageService;
50 +
51 +import com.google.common.collect.ImmutableList;
52 +import com.google.common.collect.Lists;
53 +import com.google.common.testing.EqualsTester;
54 +
55 +import static org.hamcrest.MatcherAssert.assertThat;
56 +import static org.hamcrest.Matchers.hasSize;
57 +import static org.hamcrest.Matchers.instanceOf;
58 +import static org.hamcrest.Matchers.is;
59 +import static org.hamcrest.Matchers.notNullValue;
60 +import static org.hamcrest.Matchers.nullValue;
61 +import static org.onosproject.net.NetTestTools.APP_ID;
62 +import static org.onosproject.net.NetTestTools.did;
63 +
64 +/**
65 + * Distributed group store test.
66 + */
67 +public class DistributedGroupStoreTest {
68 +
69 + DeviceId deviceId1 = did("dev1");
70 + DeviceId deviceId2 = did("dev2");
71 + GroupId groupId1 = new DefaultGroupId(1);
72 + GroupId groupId2 = new DefaultGroupId(2);
73 + GroupKey groupKey1 = new DefaultGroupKey("abc".getBytes());
74 + GroupKey groupKey2 = new DefaultGroupKey("def".getBytes());
75 +
76 + TrafficTreatment treatment =
77 + DefaultTrafficTreatment.emptyTreatment();
78 + GroupBucket selectGroupBucket =
79 + DefaultGroupBucket.createSelectGroupBucket(treatment);
80 + GroupBucket failoverGroupBucket =
81 + DefaultGroupBucket.createFailoverGroupBucket(treatment,
82 + PortNumber.IN_PORT, groupId1);
83 +
84 + GroupBuckets buckets = new GroupBuckets(ImmutableList.of(selectGroupBucket));
85 + GroupDescription groupDescription1 = new DefaultGroupDescription(
86 + deviceId1,
87 + GroupDescription.Type.INDIRECT,
88 + buckets,
89 + groupKey1,
90 + groupId1.id(),
91 + APP_ID);
92 + GroupDescription groupDescription2 = new DefaultGroupDescription(
93 + deviceId2,
94 + GroupDescription.Type.INDIRECT,
95 + buckets,
96 + groupKey2,
97 + groupId2.id(),
98 + APP_ID);
99 +
100 + DistributedGroupStore groupStoreImpl;
101 + GroupStore groupStore;
102 + EventuallyConsistentMap auditPendingReqQueue;
103 +
104 + static class MasterOfAll extends MastershipServiceAdapter {
105 + @Override
106 + public MastershipRole getLocalRole(DeviceId deviceId) {
107 + return MastershipRole.MASTER;
108 + }
109 + }
110 +
111 + @Before
112 + public void setUp() throws Exception {
113 + groupStoreImpl = new DistributedGroupStore();
114 + groupStoreImpl.storageService = new TestStorageService();
115 + groupStoreImpl.clusterCommunicator = new ClusterCommunicationServiceAdapter();
116 + groupStoreImpl.mastershipService = new MasterOfAll();
117 + groupStoreImpl.activate();
118 + groupStore = groupStoreImpl;
119 + auditPendingReqQueue =
120 + TestUtils.getField(groupStoreImpl, "auditPendingReqQueue");
121 + }
122 +
123 + @After
124 + public void tearDown() throws Exception {
125 + groupStoreImpl.deactivate();
126 + }
127 +
128 + /**
129 + * Tests the initial state of the store.
130 + */
131 + @Test
132 + public void testEmptyStore() {
133 + assertThat(groupStore.getGroupCount(deviceId1), is(0));
134 + assertThat(groupStore.getGroup(deviceId1, groupId1), nullValue());
135 + assertThat(groupStore.getGroup(deviceId1, groupKey1), nullValue());
136 + }
137 +
138 + /**
139 + * Tests adding a pending group.
140 + */
141 + @Test
142 + public void testAddPendingGroup() throws Exception {
143 + // Make sure the pending list starts out empty
144 + assertThat(auditPendingReqQueue.size(), is(0));
145 +
146 + // Add a new pending group. Make sure that the store remains empty
147 + groupStore.storeGroupDescription(groupDescription1);
148 + assertThat(groupStore.getGroupCount(deviceId1), is(0));
149 + assertThat(groupStore.getGroup(deviceId1, groupId1), nullValue());
150 + assertThat(groupStore.getGroup(deviceId1, groupKey1), nullValue());
151 +
152 + // Make sure the group is pending
153 + assertThat(auditPendingReqQueue.size(), is(1));
154 +
155 + groupStore.deviceInitialAuditCompleted(deviceId1, true);
156 +
157 + // Make sure the group isn't pending anymore
158 + assertThat(auditPendingReqQueue.size(), is(0));
159 + }
160 +
161 +
162 + /**
163 + * Tests adding and removing a group.
164 + */
165 + @Test
166 + public void testAddRemoveGroup() throws Exception {
167 + groupStore.deviceInitialAuditCompleted(deviceId1, true);
168 + assertThat(groupStore.deviceInitialAuditStatus(deviceId1), is(true));
169 +
170 + // Make sure the pending list starts out empty
171 + assertThat(auditPendingReqQueue.size(), is(0));
172 +
173 + groupStore.storeGroupDescription(groupDescription1);
174 + assertThat(groupStore.getGroupCount(deviceId1), is(1));
175 + assertThat(groupStore.getGroup(deviceId1, groupId1), notNullValue());
176 + assertThat(groupStore.getGroup(deviceId1, groupKey1), notNullValue());
177 +
178 + // Make sure that nothing is pending
179 + assertThat(auditPendingReqQueue.size(), is(0));
180 +
181 + Group groupById = groupStore.getGroup(deviceId1, groupId1);
182 + Group groupByKey = groupStore.getGroup(deviceId1, groupKey1);
183 + assertThat(groupById, notNullValue());
184 + assertThat(groupByKey, notNullValue());
185 + assertThat(groupById, is(groupByKey));
186 + assertThat(groupById.deviceId(), is(did("dev1")));
187 +
188 + groupStore.removeGroupEntry(groupById);
189 +
190 + assertThat(groupStore.getGroupCount(deviceId1), is(0));
191 + assertThat(groupStore.getGroup(deviceId1, groupId1), nullValue());
192 + assertThat(groupStore.getGroup(deviceId1, groupKey1), nullValue());
193 +
194 + // Make sure that nothing is pending
195 + assertThat(auditPendingReqQueue.size(), is(0));
196 + }
197 +
198 + /**
199 + * Tests adding and removing a group.
200 + */
201 + @Test
202 + public void testRemoveGroupDescription() throws Exception {
203 + groupStore.deviceInitialAuditCompleted(deviceId1, true);
204 +
205 + groupStore.storeGroupDescription(groupDescription1);
206 +
207 + groupStore.deleteGroupDescription(deviceId1, groupKey1);
208 +
209 + // Group should still be there, marked for removal
210 + assertThat(groupStore.getGroupCount(deviceId1), is(1));
211 + Group queriedGroup = groupStore.getGroup(deviceId1, groupId1);
212 + assertThat(queriedGroup.state(), is(Group.GroupState.PENDING_DELETE));
213 +
214 + }
215 +
216 + /**
217 + * Tests pushing group metrics.
218 + */
219 + @Test
220 + public void testPushGroupMetrics() {
221 + groupStore.deviceInitialAuditCompleted(deviceId1, true);
222 + groupStore.deviceInitialAuditCompleted(deviceId2, true);
223 +
224 + GroupDescription groupDescription3 = new DefaultGroupDescription(
225 + deviceId1,
226 + GroupDescription.Type.SELECT,
227 + buckets,
228 + new DefaultGroupKey("aaa".getBytes()),
229 + null,
230 + APP_ID);
231 +
232 + groupStore.storeGroupDescription(groupDescription1);
233 + groupStore.storeGroupDescription(groupDescription2);
234 + groupStore.storeGroupDescription(groupDescription3);
235 + Group group1 = groupStore.getGroup(deviceId1, groupId1);
236 +
237 + assertThat(group1, instanceOf(DefaultGroup.class));
238 + DefaultGroup defaultGroup1 = (DefaultGroup) group1;
239 + defaultGroup1.setPackets(55L);
240 + defaultGroup1.setBytes(66L);
241 + groupStore.pushGroupMetrics(deviceId1, ImmutableList.of(group1));
242 +
243 + // Make sure the group was updated.
244 +
245 + Group requeryGroup1 = groupStore.getGroup(deviceId1, groupId1);
246 + assertThat(requeryGroup1.packets(), is(55L));
247 + assertThat(requeryGroup1.bytes(), is(66L));
248 +
249 + }
250 +
251 + class TestDelegate implements GroupStoreDelegate {
252 + private List<GroupEvent> eventsSeen = new LinkedList<>();
253 + @Override
254 + public void notify(GroupEvent event) {
255 + eventsSeen.add(event);
256 + }
257 +
258 + public List<GroupEvent> eventsSeen() {
259 + return eventsSeen;
260 + }
261 +
262 + public void resetEvents() {
263 + eventsSeen.clear();
264 + }
265 + }
266 +
267 + /**
268 + * Tests group operation failed interface.
269 + */
270 + @Test
271 + public void testGroupOperationFailed() {
272 + TestDelegate delegate = new TestDelegate();
273 + groupStore.setDelegate(delegate);
274 + groupStore.deviceInitialAuditCompleted(deviceId1, true);
275 + groupStore.deviceInitialAuditCompleted(deviceId2, true);
276 +
277 + groupStore.storeGroupDescription(groupDescription1);
278 + groupStore.storeGroupDescription(groupDescription2);
279 +
280 + List<GroupEvent> eventsAfterAdds = delegate.eventsSeen();
281 + assertThat(eventsAfterAdds, hasSize(2));
282 + eventsAfterAdds.stream().forEach(event -> assertThat(event.type(), is(GroupEvent.Type.GROUP_ADD_REQUESTED)));
283 + delegate.resetEvents();
284 +
285 + GroupOperation opAdd =
286 + GroupOperation.createAddGroupOperation(groupId1,
287 + GroupDescription.Type.INDIRECT,
288 + buckets);
289 + groupStore.groupOperationFailed(deviceId1, opAdd);
290 +
291 + List<GroupEvent> eventsAfterAddFailed = delegate.eventsSeen();
292 + assertThat(eventsAfterAddFailed, hasSize(2));
293 + assertThat(eventsAfterAddFailed.get(0).type(),
294 + is(GroupEvent.Type.GROUP_ADD_FAILED));
295 + assertThat(eventsAfterAddFailed.get(1).type(),
296 + is(GroupEvent.Type.GROUP_REMOVED));
297 + delegate.resetEvents();
298 +
299 + GroupOperation opModify =
300 + GroupOperation.createModifyGroupOperation(groupId2,
301 + GroupDescription.Type.INDIRECT,
302 + buckets);
303 + groupStore.groupOperationFailed(deviceId2, opModify);
304 + List<GroupEvent> eventsAfterModifyFailed = delegate.eventsSeen();
305 + assertThat(eventsAfterModifyFailed, hasSize(1));
306 + assertThat(eventsAfterModifyFailed.get(0).type(),
307 + is(GroupEvent.Type.GROUP_UPDATE_FAILED));
308 + delegate.resetEvents();
309 +
310 + GroupOperation opDelete =
311 + GroupOperation.createDeleteGroupOperation(groupId2,
312 + GroupDescription.Type.INDIRECT);
313 + groupStore.groupOperationFailed(deviceId2, opDelete);
314 + List<GroupEvent> eventsAfterDeleteFailed = delegate.eventsSeen();
315 + assertThat(eventsAfterDeleteFailed, hasSize(1));
316 + assertThat(eventsAfterDeleteFailed.get(0).type(),
317 + is(GroupEvent.Type.GROUP_REMOVE_FAILED));
318 + delegate.resetEvents();
319 + }
320 +
321 + /**
322 + * Tests extraneous group operations.
323 + */
324 + @Test
325 + public void testExtraneousOperations() {
326 + ArrayList<Group> extraneous;
327 + groupStore.deviceInitialAuditCompleted(deviceId1, true);
328 +
329 + groupStore.storeGroupDescription(groupDescription1);
330 + Group group1 = groupStore.getGroup(deviceId1, groupId1);
331 +
332 + extraneous = Lists.newArrayList(groupStore.getExtraneousGroups(deviceId1));
333 + assertThat(extraneous, hasSize(0));
334 +
335 + groupStore.addOrUpdateExtraneousGroupEntry(group1);
336 + extraneous = Lists.newArrayList(groupStore.getExtraneousGroups(deviceId1));
337 + assertThat(extraneous, hasSize(1));
338 +
339 + groupStore.removeExtraneousGroupEntry(group1);
340 + extraneous = Lists.newArrayList(groupStore.getExtraneousGroups(deviceId1));
341 + assertThat(extraneous, hasSize(0));
342 + }
343 +
344 + /**
345 + * Tests updating of group descriptions.
346 + */
347 + @Test
348 + public void testUpdateGroupDescription() {
349 +
350 + GroupBuckets buckets =
351 + new GroupBuckets(ImmutableList.of(failoverGroupBucket));
352 +
353 + groupStore.deviceInitialAuditCompleted(deviceId1, true);
354 + groupStore.storeGroupDescription(groupDescription1);
355 +
356 + GroupKey newKey = new DefaultGroupKey("123".getBytes());
357 + groupStore.updateGroupDescription(deviceId1,
358 + groupKey1,
359 + GroupStore.UpdateType.ADD,
360 + buckets,
361 + newKey);
362 + Group group1 = groupStore.getGroup(deviceId1, groupId1);
363 + assertThat(group1.appCookie(), is(newKey));
364 + assertThat(group1.buckets().buckets(), hasSize(2));
365 + }
366 +
367 + @Test
368 + public void testEqualsGroupStoreIdMapKey() {
369 + DistributedGroupStore.GroupStoreIdMapKey key1 =
370 + new DistributedGroupStore.GroupStoreIdMapKey(deviceId1, groupId1);
371 + DistributedGroupStore.GroupStoreIdMapKey sameAsKey1 =
372 + new DistributedGroupStore.GroupStoreIdMapKey(deviceId1, groupId1);
373 + DistributedGroupStore.GroupStoreIdMapKey key2 =
374 + new DistributedGroupStore.GroupStoreIdMapKey(deviceId2, groupId1);
375 + DistributedGroupStore.GroupStoreIdMapKey key3 =
376 + new DistributedGroupStore.GroupStoreIdMapKey(deviceId1, groupId2);
377 +
378 + new EqualsTester()
379 + .addEqualityGroup(key1, sameAsKey1)
380 + .addEqualityGroup(key2)
381 + .addEqualityGroup(key3)
382 + .testEquals();
383 + }
384 +
385 + @Test
386 + public void testEqualsGroupStoreKeyMapKey() {
387 + DistributedGroupStore.GroupStoreKeyMapKey key1 =
388 + new DistributedGroupStore.GroupStoreKeyMapKey(deviceId1, groupKey1);
389 + DistributedGroupStore.GroupStoreKeyMapKey sameAsKey1 =
390 + new DistributedGroupStore.GroupStoreKeyMapKey(deviceId1, groupKey1);
391 + DistributedGroupStore.GroupStoreKeyMapKey key2 =
392 + new DistributedGroupStore.GroupStoreKeyMapKey(deviceId2, groupKey1);
393 + DistributedGroupStore.GroupStoreKeyMapKey key3 =
394 + new DistributedGroupStore.GroupStoreKeyMapKey(deviceId1, groupKey2);
395 +
396 + new EqualsTester()
397 + .addEqualityGroup(key1, sameAsKey1)
398 + .addEqualityGroup(key2)
399 + .addEqualityGroup(key3)
400 + .testEquals();
401 + }
402 +
403 + @Test
404 + public void testEqualsGroupStoreMapKey() {
405 + DistributedGroupStore.GroupStoreMapKey key1 =
406 + new DistributedGroupStore.GroupStoreMapKey(deviceId1);
407 + DistributedGroupStore.GroupStoreMapKey sameAsKey1 =
408 + new DistributedGroupStore.GroupStoreMapKey(deviceId1);
409 + DistributedGroupStore.GroupStoreMapKey key2 =
410 + new DistributedGroupStore.GroupStoreMapKey(deviceId2);
411 + DistributedGroupStore.GroupStoreMapKey key3 =
412 + new DistributedGroupStore.GroupStoreMapKey(did("dev3"));
413 +
414 + new EqualsTester()
415 + .addEqualityGroup(key1, sameAsKey1)
416 + .addEqualityGroup(key2)
417 + .addEqualityGroup(key3)
418 + .testEquals();
419 + }
420 +}