package geniusweb.protocol.session.mopac2; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyLong; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.IOException; import java.util.Arrays; import java.util.Date; import java.util.List; import org.junit.Before; import org.junit.Test; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import geniusweb.actions.Action; import geniusweb.actions.Offer; import geniusweb.actions.PartyId; import geniusweb.inform.Inform; import geniusweb.protocol.partyconnection.ProtocolToPartyConn; import geniusweb.protocol.partyconnection.ProtocolToPartyConnFactory; import geniusweb.protocol.session.mopac2.phase.OfferPhase; import geniusweb.protocol.session.mopac2.phase.Phase; import geniusweb.protocol.session.mopac2.phase.VotingPhase; import tudelft.utilities.logging.Reporter; import tudelft.utilities.repository.NoResourcesNowException; public class MOPAC2Test { private final ObjectMapper jackson = new ObjectMapper(); private static final PartyId PARTY1ID = new PartyId("party1"); private static final PartyId PARTY2ID = new PartyId("party2"); private static final PartyId PARTY3ID = new PartyId("party3"); // don't try to mock settings, all parts are needed and mocking // makes the test unreadable. // notice, 3 parties, this differs from MopacSettingsTest output. private final String setstr = "{\"MOPAC2Settings\":{\"participants\":[" + "{\"TeamInfo\":{\"parties\":[ {\"party\":{\"partyref\":\"http://party1\",\"parameters\":{}},\"profile\":\"http://profile1\"} ]}}," + "{\"TeamInfo\":{\"parties\":[ {\"party\":{\"partyref\":\"http://party2\",\"parameters\":{}},\"profile\":\"http://profile2\"}]}}," + "{\"TeamInfo\":{\"parties\":[ {\"party\":{\"partyref\":\"http://party3\",\"parameters\":{}},\"profile\":\"http://profile3\"} ]}} ]," + "\"deadline\":{\"DeadlineTime\":{\"durationms\":100}},\"votingevaluator\":{\"LargestAgreementWithValue\":{}}}}"; // {"MOPAC2Settings":{"participants":[{"TeamInfo":{"parties":[{"party":{"partyref":"http://party1","parameters":{}},"profile":"http://profile1"}]}},{"TeamInfo":{"parties":[{"party":{"partyref":"http://party2","parameters":{}},"profile":"http://profile2"}]}}],"deadline":{"deadlinetime":{"durationms":100}},"votingevaluator":{"LargestAgreementWithValue":{}}}} private MOPAC2Settings settings; private Reporter logger = mock(Reporter.class); private MOPAC2 mopac; private final ProtocolToPartyConnFactory factory = mock( ProtocolToPartyConnFactory.class); private final ProtocolToPartyConn conn1 = mock(ProtocolToPartyConn.class), conn2 = mock(ProtocolToPartyConn.class), conn3 = mock(ProtocolToPartyConn.class); private List connections; @Before public void before() throws JsonParseException, JsonMappingException, IOException, NoResourcesNowException { settings = jackson.readValue(setstr, MOPAC2Settings.class); mopac = settings.getProtocol(logger); connections = Arrays.asList(conn1, conn2, conn3); when(factory.connect(any(List.class))).thenReturn(connections); // hack the state.with(connection) stuff simplistically when(conn1.getParty()).thenReturn(PARTY1ID); when(conn2.getParty()).thenReturn(PARTY2ID); when(conn3.getParty()).thenReturn(PARTY3ID); } @Test public void testSmoke() { } @Test public void testGetDescr() { assertNotNull(mopac.getDescription()); } @Test public void testInitialState() { MOPAC2State state = mopac.getState(); assertEquals(settings, state.getSettings()); assertTrue(state.getActions().isEmpty()); } @Test public void testProtocol() { assertEquals("MOPAC2", mopac.getRef().getURI().getPath()); } @Test public void testWorkingCheckDeadline() throws IOException, NoResourcesNowException, InterruptedException { mopac.start(factory); assertFalse(mopac.getState().isFinal(System.currentTimeMillis())); // we have deadline in 100ms so check Thread.sleep(200); assertTrue(mopac.getState().isFinal(System.currentTimeMillis())); } @Test public void testSubscribedToConnections() { mopac.start(factory); verify(conn1, times(1)).addListener(any()); verify(conn2, times(1)).addListener(any()); verify(conn3, times(1)).addListener(any()); } @Test public void testActionIsBroadcast() throws IOException, NoResourcesNowException, InterruptedException { mopac.start(factory); Action offer = mock(Offer.class); mopac.actionRequest(conn1, offer, 1l); // 1 time for YourTurn, one time for ActionDone. // but filtering ActionDone here (instead of Action) does not work, // maybe bug in Mockito? verify(conn1, times(2)).send(any(Inform.class)); } /** * Fatal error occurs, run should fail */ @Test(expected = RuntimeException.class) public void testPartyFailsConnect() throws IOException, NoResourcesNowException { ProtocolToPartyConnFactory factory1 = mock( ProtocolToPartyConnFactory.class); // irrecoverable fail test when(factory1.connect(any(List.class))) .thenThrow(new IOException("Failed to connect to parties")); mopac.start(factory1); } /** * Nonfatal error occurs, protocol should retry till success */ @Test public void testPartyFailsConnect2ndtimeOK() throws IOException, NoResourcesNowException { long now = System.currentTimeMillis(); ProtocolToPartyConnFactory factory1 = mock( ProtocolToPartyConnFactory.class); // recoverable fail, and then success. when(factory1.connect(any(List.class))) .thenThrow(new NoResourcesNowException("try again later", new Date(now + 100))) .thenReturn(connections); mopac.start(factory1); } /** * Test that in Offer phase, and party does action, the next phase is * entered. */ @Test public void testProceedsNextPhase() { // the state before the last party makes the offer MOPAC2State offerstate = mock(MOPAC2State.class); when(offerstate.getSettings()).thenReturn(settings); OfferPhase offerphase = mock(OfferPhase.class); when(offerphase.isFinal(anyLong())).thenReturn(false); when(offerstate.getPhase()).thenReturn(offerphase); // the phase where all parties placed an offer OfferPhase finalofferphase = mock(OfferPhase.class); when(finalofferphase.isFinal(anyLong())).thenReturn(true); MOPAC2State finalofferstate = mock(MOPAC2State.class); when(finalofferstate.getPhase()).thenReturn(finalofferphase); when(finalofferstate.finishPhase()).thenReturn(finalofferstate); when(offerstate.with(any(PartyId.class), any(Action.class), anyLong())) .thenReturn(finalofferstate); // the phase where all parties can start voting. // this is the state to be reached. long now = System.currentTimeMillis(); MOPAC2State votingstate = mock(MOPAC2State.class); Phase votingphase = mock(VotingPhase.class); PartyStates votingpartystates = mock(PartyStates.class); when(votingphase.getDeadline()).thenReturn(now + 100); when(votingphase.getPartyStates()).thenReturn(votingpartystates); when(votingstate.getPhase()).thenReturn(votingphase); when(finalofferstate.nextPhase(anyLong())).thenReturn(votingstate); mopac = new MOPAC2(offerstate, logger); Offer action = mock(Offer.class); mopac.actionRequest(conn3, action, now); // check that the action result in reaching the voting phase assertEquals(votingstate, mopac.getState()); } }