source: protocol/src/test/java/geniusweb/protocol/session/saop/SAOPTest.java@ 52

Last change on this file since 52 was 52, checked in by ruud, 14 months ago

Fixed small issues in domaineditor.

File size: 15.0 KB
Line 
1package geniusweb.protocol.session.saop;
2
3import static org.junit.Assert.assertEquals;
4import static org.junit.Assert.assertNotNull;
5import static org.mockito.ArgumentMatchers.any;
6import static org.mockito.ArgumentMatchers.anyLong;
7import static org.mockito.ArgumentMatchers.eq;
8import static org.mockito.ArgumentMatchers.isA;
9import static org.mockito.Mockito.doThrow;
10import static org.mockito.Mockito.mock;
11import static org.mockito.Mockito.times;
12import static org.mockito.Mockito.verify;
13import static org.mockito.Mockito.when;
14
15import java.io.IOException;
16import java.net.URISyntaxException;
17import java.util.ArrayList;
18import java.util.Arrays;
19import java.util.Collections;
20import java.util.Date;
21import java.util.HashMap;
22import java.util.List;
23import java.util.Map;
24
25import org.junit.Before;
26import org.junit.Test;
27import org.mockito.ArgumentCaptor;
28
29import geniusweb.actions.Accept;
30import geniusweb.actions.EndNegotiation;
31import geniusweb.actions.Offer;
32import geniusweb.actions.PartyId;
33import geniusweb.deadline.Deadline;
34import geniusweb.deadline.DeadlineTime;
35import geniusweb.events.CurrentState;
36import geniusweb.events.ProtocolEvent;
37import geniusweb.inform.ActionDone;
38import geniusweb.inform.Agreements;
39import geniusweb.inform.Finished;
40import geniusweb.inform.Settings;
41import geniusweb.inform.YourTurn;
42import geniusweb.progress.Progress;
43import geniusweb.protocol.ProtocolException;
44import geniusweb.protocol.partyconnection.ProtocolToPartyConn;
45import geniusweb.protocol.partyconnection.ProtocolToPartyConnFactory;
46import geniusweb.protocol.partyconnection.ProtocolToPartyConnections;
47import geniusweb.protocol.session.TeamInfo;
48import geniusweb.references.Parameters;
49import geniusweb.references.PartyRef;
50import geniusweb.references.PartyWithParameters;
51import geniusweb.references.PartyWithProfile;
52import geniusweb.references.ProfileRef;
53import geniusweb.references.ProtocolRef;
54import tudelft.utilities.listener.Listener;
55import tudelft.utilities.logging.ReportToLogger;
56import tudelft.utilities.repository.NoResourcesNowException;
57
58/**
59 * This test tests inner workings of the SAOP protocol, AKA 'white box' testing.
60 * This adds brittleness to this test, because these internal workings may be
61 * modified as long as the public API remains working. This approach was
62 * necessary because fully testing the public API directly would lead to
63 * excessive amounts of mocking and unfocused tests. (with "focused test" we
64 * mean that a junit test should test a small part of the code and thus aid in
65 * locating the actual issue).
66 */
67public class SAOPTest {
68
69 private final SAOPState state = mock(SAOPState.class),
70 connectedstate = mock(SAOPState.class),
71 failstate = mock(SAOPState.class),
72 finalstate = mock(SAOPState.class);
73
74 private static final long DEADLINE = 1000l;
75 private ProtocolRef SAOPPROTOCOL;
76 private static final PartyId PARTY2ID = new PartyId("party2");
77 private static final PartyId PARTY1ID = new PartyId("party1");
78 private final PartyRef party1ref = mock(PartyRef.class);
79 private final PartyRef party2ref = mock(PartyRef.class);
80 private final SAOPSettings settings = mock(SAOPSettings.class);
81 private final TeamInfo team1 = mock(TeamInfo.class);
82 private final TeamInfo team2 = mock(TeamInfo.class);
83 private SAOP saop;
84 private ProtocolToPartyConnFactory factory;
85 private List<ProtocolToPartyConn> connections;
86 private ProtocolToPartyConn conn1 = mock(ProtocolToPartyConn.class),
87 conn2 = mock(ProtocolToPartyConn.class);
88 private Map<PartyId, TeamInfo> partyprofiles;
89 private Progress progress = mock(Progress.class);
90 private ProfileRef profile1;
91 private ProfileRef profile2;
92 private ProtocolToPartyConnections connectionswithparties;// = new
93 // ProtocolTmock(
94 // ProtocolToPartyConnections.class);;
95 @SuppressWarnings("unchecked")
96 private final Listener<ProtocolEvent> testlistener = mock(Listener.class);
97 private final Parameters parameters = new Parameters();
98
99// private final long NOW = 1000;
100 private final PartyWithParameters partywithparam1 = new PartyWithParameters(
101 party1ref, parameters);
102 private final PartyWithParameters partywithparam2 = new PartyWithParameters(
103 party2ref, parameters);
104
105 private final Deadline deadlinetime = mock(DeadlineTime.class);
106
107 private Map<PartyId, PartyWithProfile> pwpmap;
108
109 @Before
110 public void before()
111 throws URISyntaxException, IOException, NoResourcesNowException {
112 SAOPPROTOCOL = new ProtocolRef("SAOP");
113
114 profile1 = mock(ProfileRef.class);
115 profile2 = mock(ProfileRef.class);
116
117 PartyWithProfile pwp1 = new PartyWithProfile(partywithparam1, profile1);
118 PartyWithProfile pwp2 = new PartyWithProfile(partywithparam2, profile2);
119 when(team1.getParties()).thenReturn(Arrays.asList(pwp1));
120 when(team2.getParties()).thenReturn(Arrays.asList(pwp2));
121
122 partyprofiles = new HashMap<>();
123 partyprofiles.put(PARTY1ID, team1);
124 partyprofiles.put(PARTY2ID, team2);
125
126 pwpmap = new HashMap<>();
127 pwpmap.put(PARTY1ID, pwp1);
128 pwpmap.put(PARTY2ID, pwp2);
129
130 when(deadlinetime.getDuration()).thenReturn(DEADLINE);
131
132 List<TeamInfo> teams = new ArrayList<>();
133 teams.add(team1);
134 teams.add(team2);
135 when(settings.getTeams()).thenReturn(teams);
136 when(settings.getAllParties()).thenReturn(Arrays.asList(pwp1, pwp2));
137 when(settings.getDeadline()).thenReturn(deadlinetime);
138
139 factory = mock(ProtocolToPartyConnFactory.class);
140 // connections = mock(List.class);
141 connections = Arrays.asList(conn1, conn2);
142 when(factory.connect(any(List.class))).thenReturn(connections);
143
144 // hack the state.with(connection) stuff simplistically
145
146 when(conn1.getParty()).thenReturn(PARTY1ID);
147 when(conn2.getParty()).thenReturn(PARTY2ID);
148
149 mockState(connectedstate, "connected state", true);
150 mockState(state, "running state", true);
151 mockState(finalstate, "final state", true);
152 when(finalstate.isFinal(anyLong())).thenReturn(true);
153 mockState(failstate, "fail state", true);
154 when(failstate.isFinal(anyLong())).thenReturn(true);
155
156 connectionswithparties = new ProtocolToPartyConnections(
157 Arrays.asList(conn1, conn2));
158
159// when(connectionswithparties.get(eq(PARTY1ID))).thenReturn(conn1);
160// when(connectionswithparties.get(eq(PARTY2ID))).thenReturn(conn2);
161 // HACK thenReturn twice, so that 2nd call to iterator() returns new
162 // iterator instead of the old one
163// when(connectionswithparties.iterator())
164// .thenReturn(Arrays.asList(conn1, conn2).iterator())
165// .thenReturn(Arrays.asList(conn1, conn2).iterator());
166 Map<PartyId, PartyWithProfile> profilesmap = new HashMap<>();
167 profilesmap.put(PARTY1ID, pwp1);
168 profilesmap.put(PARTY2ID, pwp2);
169 when(state.getPartyProfiles()).thenReturn(profilesmap);
170
171 saop = new SAOP(state, new ReportToLogger("test"),
172 connectionswithparties);
173 saop.addListener(testlistener);
174
175 }
176
177 /**
178 * All states are more or less the same, but are slightly modified
179 *
180 * @param state the state to mock (must be already
181 * @param asText short name for the state, for debugging
182 * @param bool true if parties are connected
183 */
184 private void mockState(SAOPState state, String asText,
185 boolean isConnected) {
186 when(state.getSettings()).thenReturn(settings);
187 if (isConnected) {
188 when(state.getConnections())
189 .thenReturn(Arrays.asList(PARTY1ID, PARTY2ID));
190 } else {
191 when(state.getConnections()).thenReturn(Collections.emptyList());
192 }
193
194 when(state.getProgress()).thenReturn(progress);
195 when(state.with(any(PartyId.class), any(PartyWithProfile.class)))
196 .thenReturn(connectedstate);
197 when(state.getNextActor()).thenReturn(PARTY1ID);
198 when(state.with(any(PartyId.class), any(EndNegotiation.class)))
199 .thenReturn(finalstate);
200 when(state.with(any(PartyId.class), any(Accept.class)))
201 .thenReturn(state);
202 when(state.with(any(Progress.class))).thenReturn(state);
203 when(state.toString()).thenReturn(asText);
204 when(state.with(any(ProtocolException.class))).thenReturn(failstate);
205 when(state.getAgreements()).thenReturn(mock(Agreements.class));
206 when(state.getPartyProfiles()).thenReturn(pwpmap);
207 }
208
209 @Test
210 public void testConstructor() {
211 SAOPState state1 = mock(SAOPState.class);
212 Deadline dl = mock(Deadline.class);
213 SAOPSettings set = mock(SAOPSettings.class);
214 when(state1.getSettings()).thenReturn(set);
215 when(set.getDeadline()).thenReturn(dl);
216 when(dl.getDuration()).thenReturn(1000l);
217 new SAOP(state1, new ReportToLogger("test"), connectionswithparties);
218 verify(state1, times(0)).with(any(ProtocolException.class));
219 verify(testlistener, times(0)).notifyChange(any(CurrentState.class));
220 }
221
222 @Test
223 public void testConnect()
224 throws InterruptedException, IOException, NoResourcesNowException {
225 saop.connect(factory);
226
227 assertEquals(connectedstate, saop.getState());
228 verify(state, times(0)).with(any(ProtocolException.class));
229 verify(testlistener, times(0)).notifyChange(any(CurrentState.class));
230 }
231
232 @Test(expected = IOException.class)
233 public void testConnectFailingConnection()
234 throws InterruptedException, IOException, NoResourcesNowException {
235 // override the factory connect to throw IOException. This exception
236 // should boil up and cause the connect to fail.
237 when(factory.connect(any(List.class)))
238 .thenThrow(new IOException("Refusing connection"));
239 saop.connect(factory);
240 verify(state, times(0)).with(any(ProtocolException.class));
241 verify(testlistener, times(0)).notifyChange(any(CurrentState.class));
242 }
243
244 @Test
245 public void testConnectRetry()
246 throws InterruptedException, IOException, NoResourcesNowException {
247 // override the factory connect to throw NoResourcesNowException and
248 // then succeed 2nd time.
249 when(factory.connect(any(List.class)))
250 .thenThrow(new NoResourcesNowException("Refusing connection",
251 new Date(System.currentTimeMillis() + 500)))
252 .thenReturn(connections);
253 saop.connect(factory);
254
255 assertEquals(connectedstate, saop.getState());
256 verify(state, times(0)).with(any(ProtocolException.class));
257 verify(testlistener, times(0)).notifyChange(any(CurrentState.class));
258 }
259
260 @Test
261 public void testSetup() throws ProtocolException, IOException {
262
263 saop.setupParties();
264
265 // were the connections attached properly?
266 verify(conn1, times(1)).addListener(any(Listener.class));
267 verify(conn2, times(1)).addListener(any(Listener.class));
268
269 // were the settings send to each party?
270 verify(conn1, times(1)).send(any(Settings.class));
271 ArgumentCaptor<Settings> actualsettings = ArgumentCaptor
272 .forClass(Settings.class);
273 verify(conn1).send(actualsettings.capture());
274 assertEquals(new Settings(PARTY1ID, profile1, SAOPPROTOCOL, progress,
275 parameters), actualsettings.getValue());
276
277 verify(conn2, times(1)).send(any(Settings.class));
278 verify(conn2).send(actualsettings.capture());
279 assertEquals(new Settings(PARTY2ID, profile2, SAOPPROTOCOL, progress,
280 parameters), actualsettings.getValue());
281 verify(state, times(0)).with(any(ProtocolException.class));
282 verify(testlistener, times(0)).notifyChange(any(CurrentState.class));
283
284 }
285
286 @Test
287 public void testActionRequestWrongActor() {
288 saop.actionRequest(conn2, mock(EndNegotiation.class));
289
290 verify(state, times(1)).with(any(ProtocolException.class));
291 verify(testlistener, times(1)).notifyChange(any(CurrentState.class));
292 }
293
294 @Test
295 public void testActionRequest() throws IOException, ProtocolException {
296 saop.nextTurn();
297
298 when(state.getNextActor()).thenReturn(PARTY1ID);
299 when(state.with(any(PartyId.class), any(EndNegotiation.class)))
300 .thenReturn(finalstate);
301
302 saop.actionRequest(conn1, mock(EndNegotiation.class));
303
304 verify(state, times(0)).with(any(ProtocolException.class));
305 verify(state, times(1)).with(eq(PARTY1ID), isA((EndNegotiation.class)));
306 // verify broadcast
307 verify(conn1, times(1)).send(isA(ActionDone.class));
308 verify(conn2, times(1)).send(isA(ActionDone.class));
309
310 // state.getNextActor() is frozen to PARTY1 by our mocking
311 verify(conn1, times(1)).send(isA(YourTurn.class));
312 verify(conn2, times(0)).send(isA(YourTurn.class));
313 // listener should be informed about final state.
314 verify(testlistener, times(1)).notifyChange(any(CurrentState.class));
315 }
316
317 @Test
318 public void testFinalActionRequest() throws IOException, ProtocolException {
319 when(state.getNextActor()).thenReturn(PARTY1ID);
320 when(state.with(any(PartyId.class), any(EndNegotiation.class)))
321 .thenReturn(finalstate);
322 // when(finalstate.getAgreements()).thenReturn(mock(Agreements.class));
323
324 saop.nextTurn(); // ensure we send YourTurn to party1.
325 saop.actionRequest(conn1, mock(EndNegotiation.class));
326
327 verify(state, times(0)).with(any(ProtocolException.class));
328 verify(state, times(1)).with(eq(PARTY1ID), any(EndNegotiation.class));
329 // verify broadcast
330 verify(conn1, times(1)).send(isA(Finished.class));
331 verify(conn2, times(1)).send(isA(Finished.class));
332 verify(testlistener, times(1)).notifyChange(any(CurrentState.class));
333
334 verify(conn1, times(1)).send(isA(YourTurn.class));
335 verify(conn2, times(0)).send(isA(YourTurn.class));
336 }
337
338 @Test
339 public void testStart() {
340 saop.start(factory);
341 }
342
343 @Test
344 public void testActionFailNextYourturn() throws IOException {
345 doThrow(new IOException("fail sending yourturn")).when(conn1)
346 .send(any(YourTurn.class));
347 // CHECK is the state really final after an exception?
348 when(state.with(any(ProtocolException.class))).thenReturn(finalstate);
349 // when(state.getAgreements()).thenReturn(mock(Agreements.class));
350 saop.actionRequest(conn1, mock(Accept.class));
351
352 verify(state, times(1)).with(any(ProtocolException.class));
353 verify(testlistener, times(1)).notifyChange(any(CurrentState.class));
354 }
355
356 @Test
357 public void testActionNotTheTurn() throws IOException {
358 doThrow(new IOException("fail sending yourturn")).when(conn1)
359 .send(any(YourTurn.class));
360 // when(failstate.getAgreements()).thenReturn(mock(Agreements.class));
361 // not turn of conn2.
362 saop.actionRequest(conn2, mock(EndNegotiation.class));
363
364 verify(state, times(1)).with(any(ProtocolException.class));
365 verify(testlistener, times(1)).notifyChange(any(CurrentState.class));
366 }
367
368 @Test
369 public void testActionInFinalState() throws IOException {
370 saop = new SAOP(finalstate, new ReportToLogger("test"),
371 connectionswithparties);
372 // when(finalstate.getAgreements()).thenReturn(mock(Agreements.class));
373
374 saop.actionRequest(conn1, mock(Offer.class));
375
376 verify(finalstate, times(0)).with(any(ProtocolException.class));
377 verify(testlistener, times(0)).notifyChange(any());
378 }
379
380 @Test
381 public void testDescription() {
382 assertNotNull(saop.getDescription());
383 }
384
385 @Test(expected = IllegalStateException.class)
386 public void testAddParticipant() {
387 saop.addParticipant(null);
388 }
389
390 @Test
391 public void testDeadlineTimer() throws InterruptedException, IOException {
392 SAOPState unconnectedstate = mock(SAOPState.class);
393 mockState(unconnectedstate, "unconnected state", false);
394 SAOP saopempty = new SAOP(unconnectedstate, new ReportToLogger("test"),
395 new ProtocolToPartyConnections(Collections.emptyList()));
396 saopempty.addListener(testlistener);
397
398 saopempty.start(factory);
399 verify(testlistener, times(0)).notifyChange(any(CurrentState.class));
400 verify(conn1, times(1)).send(isA(YourTurn.class));
401 Thread.sleep(DEADLINE + SAOP.TIME_MARGIN + 100);
402 verify(testlistener, times(1)).notifyChange(any(CurrentState.class));
403 verify(conn1, times(1)).send(isA(Finished.class));
404 }
405
406}
Note: See TracBrowser for help on using the repository browser.