Index: protocol/src/test/java/geniusweb/protocol/session/DefaultSessionStateTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/session/DefaultSessionStateTest.java	(revision 30)
+++ 	(revision )
@@ -1,151 +1,0 @@
-package geniusweb.protocol.session;
-
-import static org.junit.Assert.assertEquals;
-
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import geniusweb.actions.Action;
-import geniusweb.actions.EndNegotiation;
-import geniusweb.actions.PartyId;
-import geniusweb.deadline.DeadlineTime;
-import geniusweb.inform.Agreements;
-import geniusweb.progress.Progress;
-import geniusweb.progress.ProgressTime;
-import geniusweb.protocol.ProtocolException;
-import geniusweb.protocol.partyconnection.ProtocolToPartyConnections;
-import geniusweb.protocol.session.saop.SAOPSettings;
-import geniusweb.references.Parameters;
-import geniusweb.references.PartyRef;
-import geniusweb.references.PartyWithParameters;
-import geniusweb.references.PartyWithProfile;
-import geniusweb.references.ProfileRef;
-import tudelft.utilities.junit.GeneralTests;
-
-public class DefaultSessionStateTest extends GeneralTests<DefaultSessionState> {
-	private final ObjectMapper jackson = new ObjectMapper();
-	private DefaultSessionState1 state1, state1a, stateA, stateE, stateF;
-	// The 1 is because we are testing an instance, not the abstract class
-	private String state1string = "{\"DefaultSessionState1\":{\"actions\":[],\"progress\":{\"time\":{\"duration\":1000,\"start\":1000}},\"settings\":{\"SAOPSettings\":{\"participants\":[{\"TeamInfo\":{\"parties\":[{\"party\":{\"partyref\":\"party1\",\"parameters\":{}},\"profile\":\"profile1\"}]}},{\"TeamInfo\":{\"parties\":[{\"party\":{\"partyref\":\"party2\",\"parameters\":{}},\"profile\":\"profile2\"}]}}],\"deadline\":{\"deadlinetime\":{\"durationms\":1000}}}},\"error\":null,\"partyprofiles\":{\"party1\":{\"party\":{\"partyref\":\"party1\",\"parameters\":{}},\"profile\":\"profile1\"}}}}";
-	private ProgressTime progr;
-	private final Date start = new Date(1000l);
-
-	@Before
-	public void before() throws URISyntaxException {
-		List<Action> actions = new LinkedList<>();
-		PartyId party1 = new PartyId("party1");
-		actions.add(new EndNegotiation(party1));
-		ProtocolToPartyConnections conns = new ProtocolToPartyConnections(
-				Collections.EMPTY_LIST);
-		DeadlineTime deadline = new DeadlineTime(1000);
-		progr = new ProgressTime(deadline.getDuration(), start);
-		PartyWithParameters party1ref = new PartyWithParameters(
-				new PartyRef("party1"), new Parameters());
-		ProfileRef profile1 = new ProfileRef("profile1");
-		PartyWithParameters party2ref = new PartyWithParameters(
-				new PartyRef("party2"), new Parameters());
-		ProfileRef profile2 = new ProfileRef("profile2");
-		List<TeamInfo> participants = Arrays.asList(
-				new TeamInfo(party1ref, profile1),
-				new TeamInfo(party2ref, profile2));
-		SessionSettings settings = new SAOPSettings(participants, deadline);
-		ProtocolException e = new ProtocolException("test protocol error",
-				party1);
-		HashMap<PartyId, PartyWithProfile> partyprofiles = new HashMap<PartyId, PartyWithProfile>();
-		partyprofiles.put(party1, new PartyWithProfile(party1ref, profile1));
-		state1 = new DefaultSessionState1(Collections.EMPTY_LIST, null, progr,
-				settings, partyprofiles, null);
-		state1a = new DefaultSessionState1(Collections.EMPTY_LIST, null, progr,
-				settings, partyprofiles, null);
-
-		stateA = new DefaultSessionState1(actions, conns, progr, settings,
-				partyprofiles, null);
-
-		stateE = new DefaultSessionState1(Collections.EMPTY_LIST, conns, progr,
-				settings, partyprofiles, e);
-		stateF = new DefaultSessionState1(Collections.EMPTY_LIST, conns, progr,
-				settings, null, e);
-
-	}
-
-	@Override
-	public List<List<DefaultSessionState>> getGeneralTestData() {
-
-		return Arrays.asList(Arrays.asList(state1, state1a),
-				Arrays.asList(stateA), Arrays.asList(stateE),
-				Arrays.asList(stateF));
-	}
-
-	@Override
-	public List<String> getGeneralTestStrings() {
-		return Arrays.asList(
-				"DefaultSessionState1.*\\[\\].*ProgressTime.*1000ms.*SAOPSettings.*party1.*party2.*,null]",
-				"DefaultSessionState1.*\\[.*EndNegotiation.*party1.*\\].*,.*,ProgressTime.*1000ms.*SAOPSettings.*party1.*party2.*,null]",
-				"DefaultSessionState1.*\\[\\],.*,ProgressTime.*1000ms.*,SAOPSettings.*party1.*party2.*,.*ProtocolException: party1:test protocol error.*",
-				"DefaultSessionState1.*\\[\\],.*,ProgressTime.*1000ms.*,SAOPSettings.*party1.*party2.*,.*ProtocolException: party1:test protocol error.*");
-	}
-
-	@Test
-	public void serializeTest() throws JsonProcessingException {
-		System.out.println(jackson.writeValueAsString(state1));
-		assertEquals(state1string, jackson.writeValueAsString(state1));
-	}
-
-	@Test
-	public void deserializeTest() throws IOException {
-		// note, we don't use DefaultSessionState because we can't add the
-		// annotation nor tell jackson dynamically about the test class.
-		DefaultSessionState state = jackson.readValue(state1string,
-				DefaultSessionState1.class);
-		// compare fields, as sessionended is a derived/new inner class
-		assertEquals(progr, state.getProgress());
-	}
-}
-
-/**
- * We need to implement a few things because we can not instantiate an abstract
- * class.
- */
-class DefaultSessionState1 extends DefaultSessionState {
-
-	private DefaultSessionState1() {
-		super();
-	}
-
-	public DefaultSessionState1(List<Action> actions,
-			ProtocolToPartyConnections conns, Progress progr,
-			SessionSettings settings,
-			Map<PartyId, PartyWithProfile> partyprofiles, ProtocolException e) {
-		super(actions, conns, progr, settings, partyprofiles, e);
-	}
-
-	@Override
-	public SessionResult getResult() {
-
-		Map<PartyId, Double> emptymap = getPartyProfiles().keySet().stream()
-				.collect(Collectors.toMap(pid -> pid, pid -> 0d));
-		return new SessionResult(getPartyProfiles(), getAgreements(), emptymap,
-				getError());
-
-	}
-
-	@Override
-	public Agreements getAgreements() {
-		return new Agreements();
-	}
-
-}
Index: protocol/src/test/java/geniusweb/protocol/session/learn/LearnSettingsTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/session/learn/LearnSettingsTest.java	(revision 31)
+++ protocol/src/test/java/geniusweb/protocol/session/learn/LearnSettingsTest.java	(revision 31)
@@ -0,0 +1,222 @@
+package geniusweb.protocol.session.learn;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import geniusweb.deadline.Deadline;
+import geniusweb.deadline.DeadlineRounds;
+import geniusweb.protocol.session.SessionSettings;
+import geniusweb.protocol.session.TeamInfo;
+import geniusweb.references.Parameters;
+import geniusweb.references.PartyRef;
+import geniusweb.references.PartyWithParameters;
+import geniusweb.references.PartyWithProfile;
+import geniusweb.references.ProfileRef;
+import tudelft.utilities.junit.GeneralTests;
+import tudelft.utilities.logging.Reporter;
+
+public class LearnSettingsTest extends GeneralTests<LearnSettings> {
+	private final ObjectMapper jackson = new ObjectMapper();
+	LearnSettings settings1, settings1a, settings2, settings3;
+	private DeadlineRounds deadline;
+	private List<TeamInfo> participants, participants2;
+	private Parameters params;
+
+	private final String serialized = "{\"LearnSettings\":{\"participants\":[{\"TeamInfo\":{\"parties\":[{\"party\":{\"partyref\":\"party1\",\"parameters\":{\"persistentstate\":\"6bb5f909-0079-43ac-a8ac-a31794391074\",\"negotiationdata\":[\"12b5f909-0079-43ac-a8ac-a31794391012\"]}},\"profile\":\"http://prof1\"}]}}],\"deadline\":{\"deadlinerounds\":{\"rounds\":10,\"durationms\":10000}}}}";
+
+	@Before
+	public void before() throws URISyntaxException, JsonProcessingException {
+
+		params = new Parameters();
+		params = params.with("persistentstate",
+				"6bb5f909-0079-43ac-a8ac-a31794391074");
+		params = params.with("negotiationdata",
+				Arrays.asList(("12b5f909-0079-43ac-a8ac-a31794391012")));
+
+		// define participants
+		participants = createTeam(params, 1);
+
+		// participants2
+//		ProfileRef profile2 = new ProfileRef("http://prof2");
+//		PartyWithProfile partywithp2 = new PartyWithProfile(party1, profile2);
+//		List<PartyWithProfile> team2pp = Arrays.asList(partywithp2);
+//		TeamInfo team2 = new TeamInfo(team2pp);
+		participants2 = createTeam(params, 2);
+
+		deadline = new DeadlineRounds(10, 10000);
+		Deadline deadline2 = new DeadlineRounds(20, 10000);
+
+		settings1 = new LearnSettings(participants, deadline);
+		settings1a = new LearnSettings(participants, deadline);
+		settings2 = new LearnSettings(participants2, deadline);
+		settings3 = new LearnSettings(participants, deadline2);
+
+	}
+
+	/**
+	 * 
+	 * @param params  the parameters for the party
+	 * @param partynr the serialnr for the party, eg 1 or 2.
+	 * @return a List of TeamInfo with just 1 team.
+	 */
+	private List<TeamInfo> createTeam(Parameters params, int partynr)
+			throws URISyntaxException {
+		PartyRef party1ref = new PartyRef("party" + partynr);
+		PartyWithParameters party1 = new PartyWithParameters(party1ref, params);
+		ProfileRef profile1 = new ProfileRef("http://prof" + partynr);
+		PartyWithProfile partywithp1 = new PartyWithProfile(party1, profile1);
+		List<PartyWithProfile> team1pp = Arrays.asList(partywithp1);
+		TeamInfo team1 = new TeamInfo(team1pp);
+		return Arrays.asList(team1);
+
+	}
+
+	@Override
+	public List<List<LearnSettings>> getGeneralTestData() {
+		return Arrays.asList(Arrays.asList(settings1, settings1a),
+				Arrays.asList(settings2), Arrays.asList(settings3));
+	}
+
+	@Override
+	public List<String> getGeneralTestStrings() {
+		return Arrays.asList(
+				"LearnSettings.TeamInfo.*PartyWithProfile.*PartyRef.*party1.*persistentstate=6b.*, negotiationdata=\\[12.*..*ProfileRef.*prof1.*,DeadlineRounds.*10,10000.*",
+				"LearnSettings.TeamInfo.*PartyWithProfile.*PartyRef.*party2.*persistentstate=6b.*, negotiationdata=\\[12.*..*ProfileRef.*prof2.*,DeadlineRounds.*10,10000.*",
+				"LearnSettings.TeamInfo.*PartyWithProfile.*PartyRef.*party1.*persistentstate=6b.*, negotiationdata=\\[12.*..*ProfileRef.*prof1.*,DeadlineRounds.*20,10000.*");
+	}
+
+	@SuppressWarnings("unused")
+	@Test(expected = IllegalArgumentException.class)
+	public void testNullParticipants() {
+		new LearnSettings(null, deadline);
+	}
+
+	@SuppressWarnings("unused")
+	@Test(expected = IllegalArgumentException.class)
+	public void testNullDeadline() {
+		new LearnSettings(participants, null);
+	}
+
+	@Test
+	public void getMaxRuntimeTest() {
+		assertEquals(10d, settings1.getMaxRunTime(), 0.00000001);
+	}
+
+	@SuppressWarnings("unused")
+	@Test
+	public void getProtocolTest() {
+		// this will throw if not Learn protocol or another problem.
+		Learn protocol = (Learn) settings1.getProtocol(mock(Reporter.class));
+	}
+
+	@SuppressWarnings("unused")
+	@Test(expected = IllegalArgumentException.class)
+	public void badPersistentTest() throws URISyntaxException {
+		// hack. #1933.
+		Parameters newparams = params.with("persistentstate",
+				"\"notproperUUID\"");
+		participants = createTeam(newparams, 1);
+
+		new LearnSettings(participants, deadline);
+	}
+
+	@SuppressWarnings("unused")
+	@Test(expected = IllegalArgumentException.class)
+	public void persistentNotStringTest() throws URISyntaxException {
+		Parameters newparams = params.with("persistentstate", 32);
+		participants = createTeam(newparams, 1);
+
+		new LearnSettings(participants, deadline);
+	}
+
+	@SuppressWarnings("unused")
+	@Test
+	public void persistentWithoutQuotesTest() throws URISyntaxException {
+		Parameters newparams = params.with("persistentstate",
+				"6bb5f909-0079-43ac-a8ac-a31794391074");
+		participants = createTeam(newparams, 1);
+
+		new LearnSettings(participants, deadline);
+	}
+
+	@SuppressWarnings("unused")
+	@Test(expected = IllegalArgumentException.class)
+	public void persistentExtraQuoteTest() throws URISyntaxException {
+		Parameters newparams = params.with("persistentstate",
+				"\"6bb5f909-0079-43ac-a8ac-a31794391074\"");
+		participants = createTeam(newparams, 1);
+
+		new LearnSettings(participants, deadline);
+	}
+
+	@SuppressWarnings("unused")
+	@Test(expected = IllegalArgumentException.class)
+	public void negotiationDataNotList() throws URISyntaxException {
+		Parameters newparams = params.with("negotiationdata",
+				"\"12b5f909-0079-43ac-a8ac-a31794391012\"");
+		participants = createTeam(newparams, 1);
+		new LearnSettings(participants, deadline);
+	}
+
+	@SuppressWarnings("unused")
+	@Test(expected = IllegalArgumentException.class)
+	public void negotiationDataBadContents() throws URISyntaxException {
+		Parameters newparams = params.with("negotiationdata", "\"bad\"");
+		participants = createTeam(newparams, 1);
+		new LearnSettings(participants, deadline);
+	}
+
+	@SuppressWarnings("unused")
+	@Test(expected = IllegalArgumentException.class)
+	public void negotiationDataNotString() throws URISyntaxException {
+		Parameters newparams = params.with("negotiationdata", 12);
+		participants = createTeam(newparams, 1);
+		new LearnSettings(participants, deadline);
+	}
+
+	@Test
+	public void getTeamsTest() {
+		assertEquals(participants, settings1.getTeams());
+		assertEquals((Integer) 1, settings1.getTeamSize());
+	}
+
+	@Test
+	public void getDeadlineTest() {
+		assertEquals(deadline, settings1.getDeadline());
+	}
+
+	@Test
+	public void withTeamTest() {
+		SessionSettings newset = settings1.with(participants2.get(0));
+		assertEquals(2, newset.getTeams().size());
+	}
+
+	@Test
+	public void testDeserialize() throws IOException {
+		SessionSettings obj = jackson.readValue(serialized,
+				SessionSettings.class);
+		System.out.println(obj);
+		assertEquals(settings1, obj);
+	}
+
+	@Test
+	public void testSerialize()
+			throws JsonProcessingException, URISyntaxException {
+
+		String string = jackson.writeValueAsString(settings1);
+		System.out.println(string);
+		assertEquals(serialized, string);
+	}
+
+}
Index: protocol/src/test/java/geniusweb/protocol/session/learn/LearnStateTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/session/learn/LearnStateTest.java	(revision 31)
+++ protocol/src/test/java/geniusweb/protocol/session/learn/LearnStateTest.java	(revision 31)
@@ -0,0 +1,162 @@
+package geniusweb.protocol.session.learn;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import geniusweb.actions.EndNegotiation;
+import geniusweb.actions.LearningDone;
+import geniusweb.actions.PartyId;
+import geniusweb.deadline.Deadline;
+import geniusweb.deadline.DeadlineTime;
+import geniusweb.inform.Agreements;
+import geniusweb.progress.Progress;
+import geniusweb.protocol.ProtocolException;
+import geniusweb.protocol.session.SessionResult;
+import geniusweb.protocol.session.TeamInfo;
+import geniusweb.references.Parameters;
+import geniusweb.references.PartyRef;
+import geniusweb.references.PartyWithParameters;
+import geniusweb.references.PartyWithProfile;
+import geniusweb.references.ProfileRef;
+
+public class LearnStateTest {
+
+	private static final String PARTY2 = "party2";
+	private static final String PARTY1 = "party1";
+	private static final PartyId party1id = new PartyId(PARTY1);
+	private static final PartyId party2id = new PartyId(PARTY2);
+	private LearnState state;
+	private final Deadline deadline = new DeadlineTime(10000);
+	private Parameters params;
+	private PartyWithProfile partyprofile1 = mock(PartyWithProfile.class);
+	private PartyWithProfile partyprofile2 = mock(PartyWithProfile.class);
+	private LearnState connectedstate;
+	private final Progress progressnotdone = mock(Progress.class);
+	private final Progress progressdone = mock(Progress.class);
+
+	@Before
+	public void before() throws URISyntaxException {
+		TeamInfo team1, team2;
+		params = new Parameters();
+		params = params.with("persistentstate",
+				"6bb5f909-0079-43ac-a8ac-a31794391074");
+		params = params.with("negotiationdata",
+				Arrays.asList("12b5f909-0079-43ac-a8ac-a31794391012"));
+
+		when(progressnotdone.isPastDeadline(any())).thenReturn(false);
+		when(progressdone.isPastDeadline(any())).thenReturn(true);
+
+		// define team1
+		PartyRef party1ref = new PartyRef(PARTY1);
+		PartyWithParameters party1 = new PartyWithParameters(party1ref, params);
+		ProfileRef profile1 = new ProfileRef("http://prof1");
+		PartyWithProfile partywithp1 = new PartyWithProfile(party1, profile1);
+		List<PartyWithProfile> team1pp = Arrays.asList(partywithp1);
+		team1 = new TeamInfo(team1pp);
+
+		// define team2
+		PartyRef party2ref = new PartyRef(PARTY2);
+		PartyWithParameters party2 = new PartyWithParameters(party1ref, params);
+		ProfileRef profile2 = new ProfileRef("http://prof2");
+		PartyWithProfile partywithp2 = new PartyWithProfile(party2, profile2);
+		List<PartyWithProfile> team2pp = Arrays.asList(partywithp2);
+		team2 = new TeamInfo(team1pp);
+
+		List<TeamInfo> participants = Arrays.asList(team1, team2);
+		LearnSettings settings = new LearnSettings(participants, deadline);
+		this.state = new LearnState(settings);
+
+		this.connectedstate = state.with(party1id, partyprofile1)
+				.with(party2id, partyprofile2).with(progressnotdone);
+
+	}
+
+	@SuppressWarnings("unused")
+	@Test(expected = IllegalArgumentException.class)
+	public void smokeTestNull() {
+		new LearnState(null);
+	}
+
+	@SuppressWarnings("unused")
+	@Test
+	public void smokeTest() {
+		LearnSettings settings = mock(LearnSettings.class);
+		new LearnState(settings);
+	}
+
+	@Test
+	public void getAgreementsTest() {
+		assertEquals(new Agreements(), state.getAgreements());
+	}
+
+	@Test
+	public void isFinalTest() {
+		// initial state is false, because we check
+		// that there are no learningDone reports
+		assertFalse(state.isFinal(0));
+		// not final because there are connected parties not yet done.
+		assertFalse(connectedstate.isFinal(0));
+		LearnState finalstate = connectedstate.with(progressdone);
+		assertTrue(finalstate.isFinal(0));
+
+		LearnState errorstate = connectedstate
+				.with(new ProtocolException("test", party1id));
+		assertTrue(errorstate.isFinal(0));
+	}
+
+	@Test
+	public void checkActionTest() {
+		// check basic illegal actions in Learning
+		assertNotNull(connectedstate.checkAction(party1id, null));
+		assertNotNull(connectedstate.checkAction(new PartyId("unknown"), null));
+		assertNotNull(connectedstate.checkAction(party1id,
+				new EndNegotiation(party1id)));
+		assertNotNull(connectedstate.checkAction(party1id,
+				new LearningDone(party2id)));
+
+		// check a good action is allowed
+		assertNull(connectedstate.checkAction(party1id,
+				new LearningDone(party1id)));
+
+		// no learning twice not ok
+		LearnState learned = connectedstate.with(party1id,
+				new LearningDone(party1id));
+		assertNotNull(
+				learned.checkAction(party1id, new LearningDone(party1id)));
+	}
+
+	@SuppressWarnings("unused")
+	@Test
+	public void LearnDoneActionTest() {
+		LearnState learned = connectedstate.with(party1id,
+				new LearningDone(party1id));
+	}
+
+	@SuppressWarnings("unused")
+	@Test
+	public void isFinalWhenAllLearned() {
+		LearnState learned = connectedstate
+				.with(party1id, new LearningDone(party1id))
+				.with(party2id, new LearningDone(party2id));
+		assertTrue(learned.isFinal(0));
+	}
+
+	@Test
+	public void getResultTest() {
+		SessionResult res = connectedstate.getResult();
+		assertTrue(res.getAgreements().getMap().isEmpty());
+	}
+}
Index: protocol/src/test/java/geniusweb/protocol/session/learn/LearnTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/session/learn/LearnTest.java	(revision 31)
+++ protocol/src/test/java/geniusweb/protocol/session/learn/LearnTest.java	(revision 31)
@@ -0,0 +1,177 @@
+package geniusweb.protocol.session.learn;
+
+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.isA;
+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.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import geniusweb.actions.EndNegotiation;
+import geniusweb.actions.LearningDone;
+import geniusweb.actions.PartyId;
+import geniusweb.deadline.Deadline;
+import geniusweb.deadline.DeadlineTime;
+import geniusweb.inform.Finished;
+import geniusweb.protocol.partyconnection.ProtocolToPartyConn;
+import geniusweb.protocol.partyconnection.ProtocolToPartyConnFactory;
+import geniusweb.protocol.session.TeamInfo;
+import geniusweb.references.Parameters;
+import geniusweb.references.PartyRef;
+import geniusweb.references.PartyWithParameters;
+import geniusweb.references.PartyWithProfile;
+import geniusweb.references.ProfileRef;
+import tudelft.utilities.logging.Reporter;
+import tudelft.utilities.repository.NoResourcesNowException;
+
+public class LearnTest {
+
+	private final Reporter reporter = mock(Reporter.class);
+	private Parameters params = new Parameters();
+	private Deadline deadline = new DeadlineTime(1800);
+	private PartyId party1id = new PartyId("party1");;
+	private PartyId party2id = new PartyId("party2");;
+	private final ProtocolToPartyConn conn1 = mock(ProtocolToPartyConn.class),
+			conn2 = mock(ProtocolToPartyConn.class);
+
+	@Before
+	public void before() {
+		params = params.with("persistentstate",
+				"6bb5f909-0079-43ac-a8ac-a31794391074");
+		params = params.with("negotiationdata",
+				Arrays.asList("12b5f909-0079-43ac-a8ac-a31794391012"));
+
+	}
+
+	@SuppressWarnings("unused")
+	@Test
+	public void smokeTest() {
+		new Learn(mock(LearnState.class), mock(Reporter.class));
+	}
+
+	@Test
+	public void getDescrTest() {
+		Learn l = new Learn(mock(LearnState.class), mock(Reporter.class));
+
+		assertNotNull(l.getDescription());
+	}
+
+	@Test
+	public void getStateTest() {
+		LearnState state = mock(LearnState.class);
+		Learn l = new Learn(state, mock(Reporter.class));
+		assertEquals(state, l.getState());
+	}
+
+	@Test
+	public void getRefTest() {
+		Learn l = new Learn(mock(LearnState.class), mock(Reporter.class));
+		assertEquals("Learn", l.getRef().getURI().getPath().toString());
+	}
+
+	@Test
+	public void finalStateNotificationTest() {
+		// check that listeners get notified when session ends.
+
+	}
+
+	@Test
+	public void testStartStopBasic() throws IOException,
+			NoResourcesNowException, InterruptedException, URISyntaxException {
+		Learn learn = createBasicLearn();
+		ProtocolToPartyConnFactory factory = createFactory();
+		learn.start(factory);
+		assertFalse(learn.getState().isFinal(System.currentTimeMillis()));
+		Thread.sleep(2000);
+		assertTrue(learn.getState().isFinal(System.currentTimeMillis()));
+	}
+
+	@Test
+	public void testStartStopLearn() throws IOException,
+			NoResourcesNowException, InterruptedException, URISyntaxException {
+		Learn learn = createBasicLearn();
+		ProtocolToPartyConnFactory factory = createFactory();
+		learn.start(factory);
+		assertFalse(learn.getState().isFinal(System.currentTimeMillis()));
+
+		// Instead of mocking connectin we call actionRequest directly
+		learn.actionRequest(conn1, new LearningDone(party1id));
+		assertFalse(learn.getState().isFinal(System.currentTimeMillis()));
+		learn.actionRequest(conn2, new LearningDone(party2id));
+		assertTrue(learn.getState().isFinal(System.currentTimeMillis()));
+	}
+
+	@Test(expected = IllegalStateException.class)
+	public void testAddParty() {
+		Learn l = new Learn(mock(LearnState.class), mock(Reporter.class));
+		l.addParticipant(mock(PartyWithProfile.class));
+	}
+
+	@Test
+	public void isFinishSentNormally()
+			throws URISyntaxException, IOException, NoResourcesNowException {
+		Learn learn = createBasicLearn();
+		ProtocolToPartyConnFactory factory = createFactory();
+		learn.start(factory);
+		learn.actionRequest(conn1, new LearningDone(party1id));
+		learn.actionRequest(conn2, new LearningDone(party2id));
+		verify(conn1, times(1)).send(isA(Finished.class));
+		verify(conn2, times(1)).send(isA(Finished.class));
+	}
+
+	@Test
+	public void isFinishSentInError()
+			throws URISyntaxException, IOException, NoResourcesNowException {
+		Learn learn = createBasicLearn();
+		ProtocolToPartyConnFactory factory = createFactory();
+		learn.start(factory);
+		learn.actionRequest(conn1, new EndNegotiation(party1id));
+		verify(conn1, times(1)).send(isA(Finished.class));
+		verify(conn2, times(1)).send(isA(Finished.class));
+	}
+
+	private Learn createBasicLearn() throws URISyntaxException {
+		TeamInfo team1 = createTeam(1);
+		TeamInfo team2 = createTeam(2);
+		LearnSettings settings = new LearnSettings(Arrays.asList(team1, team2),
+				deadline);
+		return (Learn) settings.getProtocol(reporter);
+
+	}
+
+	private TeamInfo createTeam(int nr) throws URISyntaxException {
+		PartyRef party1ref = new PartyRef("party" + nr);
+		PartyWithParameters party1 = new PartyWithParameters(party1ref, params);
+		ProfileRef profile1 = new ProfileRef("prof" + nr);
+		PartyWithProfile partywithp1 = new PartyWithProfile(party1, profile1);
+		List<PartyWithProfile> team1pp = Arrays.asList(partywithp1);
+		TeamInfo team = new TeamInfo(team1pp);
+		return team;
+	}
+
+	private ProtocolToPartyConnFactory createFactory()
+			throws IOException, NoResourcesNowException {
+		when(conn1.getParty()).thenReturn(party1id);
+		when(conn2.getParty()).thenReturn(party2id);
+
+		ProtocolToPartyConnFactory factory = mock(
+				ProtocolToPartyConnFactory.class);
+		// connections = mock(List.class);
+		List<ProtocolToPartyConn> connections = Arrays.asList(conn1, conn2);
+		when(factory.connect(any(List.class))).thenReturn(connections);
+		return factory;
+	}
+
+}
Index: protocol/src/test/java/geniusweb/protocol/session/mopac/MOPACStateTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/session/mopac/MOPACStateTest.java	(revision 30)
+++ protocol/src/test/java/geniusweb/protocol/session/mopac/MOPACStateTest.java	(revision 31)
@@ -79,5 +79,5 @@
 	public void before()
 			throws JsonParseException, JsonMappingException, IOException {
-		params1.put("power", 2);
+		params1 = params1.with("power", 2);
 		when(partyparams1.getParameters()).thenReturn(params1);
 
Index: protocol/src/test/java/geniusweb/protocol/session/mopac2/MOPAC2StateTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/session/mopac2/MOPAC2StateTest.java	(revision 30)
+++ protocol/src/test/java/geniusweb/protocol/session/mopac2/MOPAC2StateTest.java	(revision 31)
@@ -83,5 +83,5 @@
 	public void before()
 			throws JsonParseException, JsonMappingException, IOException {
-		params1.put("power", 2);
+		params1 = params1.with("power", 2);
 		when(partyparams1.getParameters()).thenReturn(params1);
 
Index: protocol/src/test/java/geniusweb/protocol/session/saop/SAOPStateTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/session/saop/SAOPStateTest.java	(revision 30)
+++ protocol/src/test/java/geniusweb/protocol/session/saop/SAOPStateTest.java	(revision 31)
@@ -28,6 +28,5 @@
 import geniusweb.protocol.ProtocolException;
 import geniusweb.protocol.partyconnection.ProtocolToPartyConn;
-import geniusweb.protocol.partyconnection.ProtocolToPartyConnections;
-import geniusweb.protocol.session.SessionSettings;
+import geniusweb.references.PartyWithProfile;
 import tudelft.utilities.junit.GeneralTests;
 
@@ -46,15 +45,12 @@
 	private ProtocolToPartyConn party3conn = mock(ProtocolToPartyConn.class);
 
-	private ProtocolToPartyConnections connections = new ProtocolToPartyConnections(
-			Arrays.asList(party1conn, party2conn));
-	private ProtocolToPartyConnections connections2 = new ProtocolToPartyConnections(
-			Arrays.asList(party1conn, party3conn));
-	private ProtocolToPartyConnections connections3 = new ProtocolToPartyConnections(
-			Arrays.asList(party1conn, party2conn, party3conn));
+	private List<PartyId> connections = Arrays.asList(party1, party2);
+	private List<PartyId> connections2 = Arrays.asList(party1, party3);
+	private List<PartyId> connections3 = Arrays.asList(party1, party2, party3);
 
 	private Progress progresstime = mock(ProgressTime.class);
 	private ProgressRounds progressrounds = mock(ProgressRounds.class);
 	private ProgressRounds progressrounds1 = mock(ProgressRounds.class);
-	private SessionSettings settings = mock(SAOPSettings.class);
+	private SAOPSettings settings = mock(SAOPSettings.class);
 	private SAOPState state1, state1a, state2, state3, state4;
 
@@ -106,14 +102,14 @@
 	public List<String> getGeneralTestStrings() {
 		return Arrays.asList(
-				"SAOPState.*\\[\\].*ConnectionWithParties.*conn1.*conn2.*ProgressTime.*",
-				"SAOPState.*\\[act1\\].*ConnectionWithParties.*conn1.*conn2.*ProgressTime.*",
-				"SAOPState.*ConnectionWithParties.*conn1.*conn3.*ProgressTime.*",
-				"SAOPState.*ConnectionWithParties.*conn1.*conn2.*ProgressRounds.*");
+				"SAOPState.*\\[\\].*party1.*party2.*ProgressTime.*",
+				"SAOPState.*\\[act1\\].*party1.*party2.*ProgressTime.*",
+				"SAOPState.*party1.*party3.*ProgressTime.*",
+				"SAOPState.*party1.*party2.*ProgressRounds.*");
 	}
 
 	@Test
 	public void constructWith0Connection() {
-		new SAOPState(actions, new ProtocolToPartyConnections(Arrays.asList()),
-				progresstime, settings, null, null);
+		new SAOPState(actions, Arrays.asList(), progresstime, settings, null,
+				null);
 	}
 
@@ -132,6 +128,5 @@
 	@Test
 	public void testNextActor2() {
-		ProtocolToPartyConnections conns = new ProtocolToPartyConnections(
-				Arrays.asList(party2conn, party3conn));
+		List<PartyId> conns = Arrays.asList(party2, party3);
 		SAOPState state = new SAOPState(actions, conns, progresstime, settings,
 				null, null);
@@ -237,5 +232,5 @@
 	@Test
 	public void withConnectionTest() {
-		SAOPState state = state1.with(party3conn, null);
+		SAOPState state = state1.with(party3, (PartyWithProfile) null);
 		assertEquals(3, state.getConnections().size());
 	}
@@ -274,8 +269,4 @@
 
 		state.with(party1, offer1);
-//		assertTrue(state.isFinal(NOW));
-//		assertEquals(
-//				"geniusweb.protocol.ProtocolException: party1:Party does not have the turn ",
-//				state.getError().toString());
 	}
 
@@ -297,5 +288,5 @@
 				settings, null, null);
 
-		state = state.with(party2, null);
+		state = state.with(party2, (Action) null);
 	}
 
Index: protocol/src/test/java/geniusweb/protocol/session/saop/SAOPTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/session/saop/SAOPTest.java	(revision 30)
+++ protocol/src/test/java/geniusweb/protocol/session/saop/SAOPTest.java	(revision 31)
@@ -6,4 +6,5 @@
 import static org.mockito.Matchers.anyLong;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isA;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
@@ -34,7 +35,7 @@
 import geniusweb.events.CurrentState;
 import geniusweb.events.ProtocolEvent;
+import geniusweb.inform.ActionDone;
 import geniusweb.inform.Agreements;
 import geniusweb.inform.Finished;
-import geniusweb.inform.Inform;
 import geniusweb.inform.Settings;
 import geniusweb.inform.YourTurn;
@@ -80,5 +81,5 @@
 	private SAOP saop;
 	private ProtocolToPartyConnFactory factory;
-	private List connections;
+	private List<ProtocolToPartyConn> connections;
 	private ProtocolToPartyConn conn1 = mock(ProtocolToPartyConn.class),
 			conn2 = mock(ProtocolToPartyConn.class);
@@ -87,6 +88,7 @@
 	private ProfileRef profile1;
 	private ProfileRef profile2;
-	private ProtocolToPartyConnections connectionswithparties = mock(
-			ProtocolToPartyConnections.class);;
+	private ProtocolToPartyConnections connectionswithparties;// = new
+																// ProtocolTmock(
+																// ProtocolToPartyConnections.class);;
 	@SuppressWarnings("unchecked")
 	private final Listener<ProtocolEvent> testlistener = mock(Listener.class);
@@ -128,5 +130,6 @@
 
 		factory = mock(ProtocolToPartyConnFactory.class);
-		connections = mock(List.class);
+		// connections = mock(List.class);
+		connections = Arrays.asList(conn1, conn2);
 		when(factory.connect(any(List.class))).thenReturn(connections);
 
@@ -143,18 +146,22 @@
 		when(failstate.isFinal(anyLong())).thenReturn(true);
 
-		when(connectionswithparties.get(eq(PARTY1ID))).thenReturn(conn1);
-		when(connectionswithparties.get(eq(PARTY2ID))).thenReturn(conn2);
+		connectionswithparties = new ProtocolToPartyConnections(
+				Arrays.asList(conn1, conn2));
+
+//		when(connectionswithparties.get(eq(PARTY1ID))).thenReturn(conn1);
+//		when(connectionswithparties.get(eq(PARTY2ID))).thenReturn(conn2);
 		// HACK thenReturn twice, so that 2nd call to iterator() returns new
 		// iterator instead of the old one
-		when(connectionswithparties.iterator())
-				.thenReturn(Arrays.asList(conn1, conn2).iterator())
-				.thenReturn(Arrays.asList(conn1, conn2).iterator());
-		saop = new SAOP(state, new ReportToLogger("test"));
-		saop.addListener(testlistener);
-
+//		when(connectionswithparties.iterator())
+//				.thenReturn(Arrays.asList(conn1, conn2).iterator())
+//				.thenReturn(Arrays.asList(conn1, conn2).iterator());
 		Map<PartyId, PartyWithProfile> profilesmap = new HashMap<>();
 		profilesmap.put(PARTY1ID, pwp1);
 		profilesmap.put(PARTY2ID, pwp2);
 		when(state.getPartyProfiles()).thenReturn(profilesmap);
+
+		saop = new SAOP(state, new ReportToLogger("test"),
+				connectionswithparties);
+		saop.addListener(testlistener);
 
 	}
@@ -168,9 +175,13 @@
 	private void mockState(SAOPState state, String asText) {
 		when(state.getSettings()).thenReturn(settings);
-		when(state.getConnections()).thenReturn(connectionswithparties);
+		when(state.getConnections())
+				.thenReturn(Arrays.asList(PARTY1ID, PARTY2ID));
+		// when(state.getConnections()).thenReturn(connectionswithparties);
 
 		when(state.getProgress()).thenReturn(progress);
-		when(state.with(any(ProtocolToPartyConn.class),
-				any(PartyWithProfile.class))).thenReturn(connectedstate);
+		when(state.with(any(PartyId.class), any(PartyWithProfile.class)))
+				.thenReturn(connectedstate);
+//		when(state.with(any(ProtocolToPartyConn.class),
+//				any(PartyWithProfile.class))).thenReturn(connectedstate);
 		when(state.getNextActor()).thenReturn(PARTY1ID);
 		when(state.with(any(PartyId.class), any(EndNegotiation.class)))
@@ -192,5 +203,5 @@
 		when(set.getDeadline()).thenReturn(dl);
 		when(dl.getDuration()).thenReturn(1000l);
-		new SAOP(state1, new ReportToLogger("test"));
+		new SAOP(state1, new ReportToLogger("test"), connectionswithparties);
 		verify(state1, times(0)).with(any(ProtocolException.class));
 		verify(testlistener, times(0)).notifyChange(any(CurrentState.class));
@@ -281,14 +292,16 @@
 		verify(state, times(0)).with(any(ProtocolException.class));
 		verify(state, times(1)).with(eq(PARTY1ID), any(EndNegotiation.class));
-		verify(connectionswithparties, times(1)).broadcast(any(Inform.class));
+		// verify broadcast
+		verify(conn1, times(1)).send(isA(ActionDone.class));
+		verify(conn2, times(1)).send(isA(ActionDone.class));
 
 		// state.getNextActor() is frozen to PARTY1 by our mocking
-		verify(conn1, times(1)).send(any(YourTurn.class));
-		verify(conn2, times(0)).send(any(YourTurn.class));
-		verify(testlistener, times(0)).notifyChange(any(CurrentState.class));
-	}
-
-	@Test
-	public void testFinalActionRequest() throws IOException {
+		verify(conn1, times(1)).send(isA(YourTurn.class));
+		verify(conn2, times(0)).send(isA(YourTurn.class));
+		verify(testlistener, times(0)).notifyChange(any(CurrentState.class));
+	}
+
+	@Test
+	public void testFinalActionRequest() throws IOException, ProtocolException {
 		when(state.getNextActor()).thenReturn(PARTY1ID);
 		when(state.with(any(PartyId.class), any(EndNegotiation.class)))
@@ -296,13 +309,16 @@
 		// when(finalstate.getAgreements()).thenReturn(mock(Agreements.class));
 
+		saop.nextTurn(); // ensure we send YourTurn to party1.
 		saop.actionRequest(conn1, mock(EndNegotiation.class));
 
 		verify(state, times(0)).with(any(ProtocolException.class));
 		verify(state, times(1)).with(eq(PARTY1ID), any(EndNegotiation.class));
-		verify(connectionswithparties, times(1)).broadcast(any(Finished.class));
+		// verify broadcast
+		verify(conn1, times(1)).send(isA(Finished.class));
+		verify(conn2, times(1)).send(isA(Finished.class));
 		verify(testlistener, times(1)).notifyChange(any(CurrentState.class));
 
-		verify(conn1, times(1)).send(any(YourTurn.class));
-		verify(conn2, times(1)).send(any(YourTurn.class));
+		verify(conn1, times(1)).send(isA(YourTurn.class));
+		verify(conn2, times(0)).send(isA(YourTurn.class));
 	}
 
@@ -339,5 +355,6 @@
 	@Test
 	public void testActionInFinalState() throws IOException {
-		saop = new SAOP(finalstate, new ReportToLogger("test"));
+		saop = new SAOP(finalstate, new ReportToLogger("test"),
+				connectionswithparties);
 		// when(finalstate.getAgreements()).thenReturn(mock(Agreements.class));
 
Index: protocol/src/test/java/geniusweb/protocol/session/saop/SaopPartyWithProfileTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/session/saop/SaopPartyWithProfileTest.java	(revision 30)
+++ protocol/src/test/java/geniusweb/protocol/session/saop/SaopPartyWithProfileTest.java	(revision 31)
@@ -43,6 +43,5 @@
 
 		Parameters settings1 = new Parameters();
-		Parameters settings2 = new Parameters();
-		settings2.put("a", 1);
+		Parameters settings2 = new Parameters().with("a", 1);
 
 		PartyWithParameters party1withparams1 = new PartyWithParameters(party1,
Index: protocol/src/test/java/geniusweb/protocol/tournament/allpermutations/AllPermutationsSettingsTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/tournament/allpermutations/AllPermutationsSettingsTest.java	(revision 30)
+++ protocol/src/test/java/geniusweb/protocol/tournament/allpermutations/AllPermutationsSettingsTest.java	(revision 31)
@@ -19,4 +19,6 @@
 import geniusweb.protocol.NegoSettings;
 import geniusweb.protocol.session.saop.SAOPSettings;
+import geniusweb.protocol.tournament.ProfileList;
+import geniusweb.protocol.tournament.Team;
 import geniusweb.protocol.tournament.TournamentSettings;
 import geniusweb.references.Parameters;
Index: protocol/src/test/java/geniusweb/protocol/tournament/allpermutationslearn/AllPermutationsLearnProtocolTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/tournament/allpermutationslearn/AllPermutationsLearnProtocolTest.java	(revision 31)
+++ protocol/src/test/java/geniusweb/protocol/tournament/allpermutationslearn/AllPermutationsLearnProtocolTest.java	(revision 31)
@@ -0,0 +1,184 @@
+package geniusweb.protocol.tournament.allpermutationslearn;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+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.math.BigInteger;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import geniusweb.events.ProtocolEvent;
+import geniusweb.inform.Agreements;
+import geniusweb.protocol.CurrentNegoState;
+import geniusweb.protocol.NegoState;
+import geniusweb.protocol.partyconnection.ProtocolToPartyConnFactory;
+import geniusweb.protocol.session.SessionProtocol;
+import geniusweb.protocol.session.SessionResult;
+import geniusweb.protocol.session.SessionSettings;
+import geniusweb.protocol.session.SessionState;
+import geniusweb.references.PartyWithProfile;
+import geniusweb.references.ProtocolRef;
+import tudelft.utilities.listener.Listener;
+import tudelft.utilities.logging.ReportToLogger;
+
+public class AllPermutationsLearnProtocolTest {
+
+	private final AllPermutationsLearnState state = mock(
+			AllPermutationsLearnState.class),
+			newstate = mock(AllPermutationsLearnState.class);
+	private final ReportToLogger log = new ReportToLogger("test");
+	private final AllPermutationsLearnProtocol app = new AllPermutationsLearnProtocol(
+			state, log);
+	private final ProtocolToPartyConnFactory factory = mock(
+			ProtocolToPartyConnFactory.class);
+	private final SessionSettings settings = mock(SessionSettings.class);
+	private final SessionState finalsessionstate = mock(SessionState.class);
+	private Agreements agreement = mock(Agreements.class);
+	private final long NOW = 1000;
+	private SessionResult finalstate = mock(SessionResult.class);
+
+	@Before
+	public void before() {
+		when(state.getSize()).thenReturn(BigInteger.ZERO);
+		when(finalsessionstate.isFinal(anyLong())).thenReturn(true);
+		when(finalsessionstate.getSettings()).thenReturn(settings);
+		when(finalsessionstate.getAgreements()).thenReturn(agreement);
+		when(finalsessionstate.getResult()).thenReturn(finalstate);
+		when(finalstate.getAgreements()).thenReturn(agreement);
+		when(state.with(any())).thenReturn(newstate);
+	}
+
+	@Test
+	public void smokeTest() {
+	}
+
+	@Test
+	public void startTestNoSessions() {
+		AllPermutationsLearnProtocol app = new AllPermutationsLearnProtocol(
+				state, log);
+		app.start(factory);
+
+	}
+
+	@Test
+	public void getDescrTest() {
+		assertNotNull(app.getDescription());
+	}
+
+	@Test
+	public void getStateTest() {
+		assertEquals(state, app.getState());
+	}
+
+	@Test
+	public void getRefTest() {
+		assertEquals("APPLearn", app.getRef().getURI().toString());
+	}
+
+	@Test
+	public void runOneSessionTest() throws InterruptedException {
+		MockSessionProtocol sessionprotocol = startSession();
+		sessionprotocol.getListener();
+	}
+
+	@Test
+	public void runOneSessionAndUnhandledEvent() throws InterruptedException {
+		MockSessionProtocol sessionprotocol = startSession();
+		sessionprotocol.getListener().notifyChange(mock(ProtocolEvent.class));
+		verify(state, times(0)).with(any());
+	}
+
+	/**
+	 * Check that a started session correctly handles a session event.
+	 */
+	@Test
+	public void CurrentNegoStateEventTest() throws InterruptedException {
+		MockSessionProtocol sessionprotocol = startSession();
+
+		CurrentNegoState evt = mock(CurrentNegoState.class);
+		when(evt.getState()).thenReturn(finalsessionstate);
+		sessionprotocol.getListener().notifyChange(evt);
+
+		ArgumentCaptor<SessionResult> argument = ArgumentCaptor
+				.forClass(SessionResult.class);
+		verify(state, times(1)).with(argument.capture());
+		assertEquals(agreement, argument.getValue().getAgreements());
+		assertNull(argument.getValue().getError());
+	}
+
+	private MockSessionProtocol startSession() throws InterruptedException {
+		SessionSettings setting = mock(SessionSettings.class);
+		MockSessionProtocol sessionprotocol = new MockSessionProtocol();
+		when(setting.getProtocol(log)).thenReturn(sessionprotocol);
+		when(state.getNextSettings()).thenReturn(setting);
+
+		app.start(factory);
+		Thread.sleep(500); // allow app to start session
+		// this call should return fine, and have listener registered to our
+		// protocol. app now waits for a notification
+		return sessionprotocol;
+	}
+
+}
+
+/**
+ * 
+ * The protocol needs to record the listners, we need a listener to trigger
+ * further protocol actions. Mockito can't handle this, we mneed our own mock...
+ *
+ */
+class MockSessionProtocol implements SessionProtocol {
+	private final List<Listener<ProtocolEvent>> listeners = new LinkedList<>();
+
+	@Override
+	public void start(ProtocolToPartyConnFactory connectionfactory) {
+
+	}
+
+	@Override
+	public String getDescription() {
+		return null;
+	}
+
+	@Override
+	public NegoState getState() {
+		return null;
+	}
+
+	@Override
+	public ProtocolRef getRef() {
+		return null;
+	}
+
+	@Override
+	public void addParticipant(PartyWithProfile party) {
+	}
+
+	@Override
+	public void addListener(Listener<ProtocolEvent> l) {
+		listeners.add(l);
+	}
+
+	@Override
+	public void removeListener(Listener<ProtocolEvent> l) {
+	}
+
+	public Listener<ProtocolEvent> getListener() {
+		if (listeners.size() != 1) {
+			throw new IllegalStateException("Not having exactly 1 listener");
+		}
+		return listeners.get(0);
+	}
+
+}
Index: protocol/src/test/java/geniusweb/protocol/tournament/allpermutationslearn/AllPermutationsLearnSettingsTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/tournament/allpermutationslearn/AllPermutationsLearnSettingsTest.java	(revision 31)
+++ protocol/src/test/java/geniusweb/protocol/tournament/allpermutationslearn/AllPermutationsLearnSettingsTest.java	(revision 31)
@@ -0,0 +1,251 @@
+package geniusweb.protocol.tournament.allpermutationslearn;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import geniusweb.deadline.DeadlineTime;
+import geniusweb.protocol.NegoSettings;
+import geniusweb.protocol.session.SessionSettings;
+import geniusweb.protocol.session.learn.LearnSettings;
+import geniusweb.protocol.session.saop.SAOPSettings;
+import geniusweb.protocol.tournament.ProfileList;
+import geniusweb.protocol.tournament.Team;
+import geniusweb.protocol.tournament.TournamentSettings;
+import geniusweb.references.Parameters;
+import geniusweb.references.PartyRef;
+import geniusweb.references.PartyWithParameters;
+import geniusweb.references.ProfileRef;
+import tudelft.utilities.immutablelist.ImmutableList;
+import tudelft.utilities.junit.GeneralTests;
+import tudelft.utilities.logging.ReportToLogger;
+
+public class AllPermutationsLearnSettingsTest
+		extends GeneralTests<AllPermutationsLearnSettings> {
+
+	private final ObjectMapper jackson = new ObjectMapper();
+
+	private final String serialized = "{\"AllPermutationsLearnSettings\":{\"teams\":[{\"Team\":[{\"partyref\":\"party1\",\"parameters\":{\"persistentstate\":\"a48b8bc9-4275-4a4e-bee9-6c0a734dc99a\",\"negotiationdata\":[]}}]},{\"Team\":[{\"partyref\":\"party2\",\"parameters\":{\"persistentstate\":\"12b6af6c-b8a0-4731-8b37-0454cafeb7f4\",\"negotiationdata\":[]}}]}],\"profileslists\":[{\"ProfileList\":[\"profile1\"]},{\"ProfileList\":[\"profile2\"]},{\"ProfileList\":[\"profile3\"]}],\"reuseTeams\":false,\"teamsPerSession\":2,\"sessionsettings\":{\"SAOPSettings\":{\"participants\":[],\"deadline\":{\"deadlinetime\":{\"durationms\":10000}}}},\"numberTournaments\":1,\"learnSettings\":{\"LearnSettings\":{\"participants\":[],\"deadline\":{\"deadlinetime\":{\"durationms\":99000}}}}}}";
+	private AllPermutationsLearnSettings settings, settings1a, settings2,
+			settings3, settings4, settings5;
+
+	// use directly because there is some hard coding currently.
+	private SAOPSettings saopsettings;
+
+	private ProfileRef profile1, profile2, profile3;
+	private ProfileList profiles1, profiles2, profiles3;
+	private List<Team> parties, parties3;
+
+	private LearnSettings learnsettings;
+
+	private List<ProfileList> profiles;
+
+	@Before
+	public void before() throws URISyntaxException {
+
+		PartyRef partyref1 = new PartyRef("party1");
+		PartyRef partyref2 = new PartyRef("party2");
+		PartyRef partyref3 = new PartyRef("party3");
+
+		Parameters params1 = new Parameters()
+				.with("persistentstate", "a48b8bc9-4275-4a4e-bee9-6c0a734dc99a")
+				.with("negotiationdata", Collections.emptyList());
+		Parameters params2 = new Parameters()
+				.with("persistentstate", "12b6af6c-b8a0-4731-8b37-0454cafeb7f4")
+				.with("negotiationdata", Collections.emptyList());
+		Parameters params3 = new Parameters()
+				.with("persistentstate", "2b9488ed-c06b-4027-826b-4528254558f1")
+				.with("negotiationdata", Collections.emptyList());
+
+		PartyWithParameters pwithp1 = new PartyWithParameters(partyref1,
+				params1);
+		PartyWithParameters pwithp2 = new PartyWithParameters(partyref2,
+				params2);
+		PartyWithParameters pwithp3 = new PartyWithParameters(partyref3,
+				params3);
+		Team partywithparams1 = new Team(Arrays.asList(pwithp1));
+		Team partywithparams2 = new Team(Arrays.asList(pwithp2));
+		Team partywithparams3 = new Team(Arrays.asList(pwithp3));
+
+		parties = Arrays.asList(partywithparams1, partywithparams2);
+		parties3 = Arrays.asList(partywithparams1, partywithparams2,
+				partywithparams3);
+		DeadlineTime deadline = new DeadlineTime(10000);
+
+		saopsettings = new SAOPSettings(Collections.emptyList(), deadline);
+
+		profile1 = new ProfileRef("profile1");
+		profile2 = new ProfileRef("profile2");
+		profile3 = new ProfileRef("profile3");
+		profiles1 = new ProfileList(Arrays.asList(profile1));
+		profiles2 = new ProfileList(Arrays.asList(profile2));
+		profiles3 = new ProfileList(Arrays.asList(profile3));
+
+		learnsettings = new LearnSettings(Collections.emptyList(),
+				new DeadlineTime(99000));
+
+		profiles = Arrays.asList(profiles1, profiles2, profiles3);
+
+		settings = new AllPermutationsLearnSettings(parties, profiles, false, 2,
+				saopsettings, 1, learnsettings);
+
+		settings1a = new AllPermutationsLearnSettings(parties, profiles, false,
+				2, saopsettings, 1, learnsettings);
+
+		settings2 = new AllPermutationsLearnSettings(
+				Arrays.asList(partywithparams1, partywithparams2,
+						partywithparams3),
+				profiles, false, 2, saopsettings, 1, learnsettings);
+
+		settings3 = new AllPermutationsLearnSettings(parties, profiles, true, 2,
+				saopsettings, 1, learnsettings);
+
+		settings4 = new AllPermutationsLearnSettings(parties,
+				Arrays.asList(profiles1, profiles2, profiles3, profiles1),
+				false, 2, saopsettings, 1, learnsettings);
+
+		settings5 = new AllPermutationsLearnSettings(parties, profiles, false,
+				2, saopsettings, 2, learnsettings);
+
+	}
+
+	@Override
+	public List<List<AllPermutationsLearnSettings>> getGeneralTestData() {
+		return Arrays.asList(Arrays.asList(settings, settings1a),
+				Arrays.asList(settings2), Arrays.asList(settings3),
+				Arrays.asList(settings4), Arrays.asList(settings5));
+	}
+
+	@Override
+	public List<String> getGeneralTestStrings() {
+		return Arrays.asList(
+				"AllPermutationsLearnSettings.*party1.*party2.*,false,.*profile1.*profile2.*profile3.*,2,SAOPSettings.*1.*",
+				"AllPermutationsLearnSettings.*party1.*party2.*party3.*,false,.*profile1.*profile2.*profile3.*,2,SAOPSettings.*1.*",
+				"AllPermutationsLearnSettings.*party1.*party2.*,true,.*profile1.*profile2.*profile3.*,2,SAOPSettings.*1.*",
+				"AllPermutationsLearnSettings.*party1.*party2.*,false,.*profile1.*profile2.*profile3.*profile1.*,2,SAOPSettings.*1.*",
+				"AllPermutationsLearnSettings.*party1.*party2.*,false,.*profile1.*profile2.*profile3.*,2,SAOPSettings.*2.*");
+	}
+
+	@Test
+	public void getProtocolTest() {
+		assertEquals("APPLearn",
+				settings.getProtocol(new ReportToLogger("test")).getRef()
+						.getURI().toString());
+	}
+
+	@Test
+	public void testDeserialize() throws IOException {
+		TournamentSettings obj = (TournamentSettings) jackson
+				.readValue(serialized, NegoSettings.class);
+		System.out.println(obj);
+		assertEquals(settings, obj);
+	}
+
+	@Test
+	public void testSerialize()
+			throws JsonProcessingException, URISyntaxException {
+
+		String string = jackson.writeValueAsString(settings);
+		System.out.println(string);
+		assertEquals(serialized, string);
+	}
+
+	@SuppressWarnings("unused")
+	@Test(expected = IllegalArgumentException.class)
+	public void testNullParties() {
+		new AllPermutationsLearnSettings(null,
+				Arrays.asList(profiles1, profiles2, profiles3, profiles1), true,
+				2, saopsettings, 1, learnsettings);
+
+	}
+
+	@SuppressWarnings("unused")
+	@Test(expected = IllegalArgumentException.class)
+	public void testNoParties() {
+		new AllPermutationsLearnSettings(Collections.emptyList(),
+				Arrays.asList(profiles1, profiles2, profiles3, profiles1), true,
+				2, saopsettings, 1, learnsettings);
+
+	}
+
+	@SuppressWarnings("unused")
+	@Test(expected = IllegalArgumentException.class)
+	public void testNullProfiles() {
+		new AllPermutationsLearnSettings(parties, null, true, 2, saopsettings,
+				1, learnsettings);
+
+	}
+
+	@SuppressWarnings("unused")
+	@Test(expected = IllegalArgumentException.class)
+	public void testInsufficientProfiles() {
+		new AllPermutationsLearnSettings(parties,
+				Arrays.asList(profiles1, profiles2, profiles3, profiles1), true,
+				4, saopsettings, 1, learnsettings);
+
+	}
+
+	@SuppressWarnings("unused")
+	@Test(expected = IllegalArgumentException.class)
+	public void testNullSessionSettings() {
+		new AllPermutationsLearnSettings(parties,
+				Arrays.asList(profiles1, profiles2, profiles3, profiles1), true,
+				4, null, 1, learnsettings);
+
+	}
+
+	@SuppressWarnings("unused")
+	@Test(expected = IllegalArgumentException.class)
+	public void testOnePartyPerSession() {
+		new AllPermutationsLearnSettings(parties,
+				Arrays.asList(profiles1, profiles2, profiles3, profiles1), true,
+				1, saopsettings, 1, learnsettings);
+
+	}
+
+	@Test
+	public void getPermutationsTest() {
+		// #permutations + 1 training session
+		assertEquals(7, settings.permutations().size().intValue());
+	}
+
+	/**
+	 * Test the learn session
+	 */
+	@Test
+	public void testGetlearnSessions() {
+		// particularly we want to test where numparties does not match
+		// numteamspersession
+		AllPermutationsLearnSettings settings3parties = new AllPermutationsLearnSettings(
+				parties3, profiles, false, 2, saopsettings, 2, learnsettings);
+		ImmutableList<SessionSettings> perms = settings3parties.permutations();
+		// 3 parties, 3 profiles, 2 parties per session, 2 tournaments = 2*18
+		assertEquals(37, perms.size().intValue());
+		LearnSettings learnsetting = (LearnSettings) perms
+				.get(BigInteger.valueOf(36));
+		assertEquals(3, learnsetting.getAllParties().size());
+		Parameters party1params = learnsetting.getAllParties().get(0).getParty()
+				.getParameters();
+		assertEquals("a48b8bc9-4275-4a4e-bee9-6c0a734dc99a",
+				party1params.get("persistentstate").toString());
+		List negodata = (List) party1params.get("negotiationdata");
+		assertEquals(24, negodata.size());
+	}
+
+	@Test
+	public void getMaxRuntimeTest() {
+		assertEquals((Double) (6d * (10 + 2) + 99d), settings.getMaxRunTime());
+	}
+
+}
Index: protocol/src/test/java/geniusweb/protocol/tournament/allpermutationslearn/AllPermutationsLearnStateTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/tournament/allpermutationslearn/AllPermutationsLearnStateTest.java	(revision 31)
+++ protocol/src/test/java/geniusweb/protocol/tournament/allpermutationslearn/AllPermutationsLearnStateTest.java	(revision 31)
@@ -0,0 +1,102 @@
+package geniusweb.protocol.tournament.allpermutationslearn;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Test;
+
+import geniusweb.actions.PartyId;
+import geniusweb.protocol.session.SessionResult;
+import geniusweb.protocol.session.SessionSettings;
+import geniusweb.references.PartyWithProfile;
+import tudelft.utilities.immutablelist.ImmutableList;
+
+public class AllPermutationsLearnStateTest {
+
+	private final AllPermutationsLearnSettings toursettings = mock(
+			AllPermutationsLearnSettings.class);;
+	@SuppressWarnings("unchecked")
+	private final List<SessionResult> results = mock(List.class);
+	@SuppressWarnings("unchecked")
+	private final ImmutableList<SessionSettings> settings = mock(
+			ImmutableList.class);
+	private final AllPermutationsLearnState state = new AllPermutationsLearnState(
+			toursettings, settings, results);
+	private final SessionSettings session7settings = mock(
+			SessionSettings.class);
+	private final long NOW = 1000;
+	private PartyWithProfile pp1 = mock(PartyWithProfile.class);
+	private PartyWithProfile pp2 = mock(PartyWithProfile.class);
+
+	@SuppressWarnings("unchecked")
+	private final List<PartyWithProfile> participants = Arrays.asList(pp1, pp2);
+
+	@Test
+	public void getResultsTest() {
+		assertEquals(results, state.getResults());
+	}
+
+	@Test
+	public void isFinalTestFalse() {
+		when(settings.size()).thenReturn(BigInteger.TEN);
+		when(results.size()).thenReturn(7);
+		assertFalse(state.isFinal(NOW));
+	}
+
+	@Test
+	public void isFinalTestTrue() {
+		when(settings.size()).thenReturn(BigInteger.TEN);
+		when(results.size()).thenReturn(10);
+		assertTrue(state.isFinal(NOW));
+	}
+
+	@Test
+	public void getNextSetting() {
+		prepareNextSettings();
+		assertEquals(session7settings, state.getNextSettings());
+	}
+
+	private void prepareNextSettings() {
+		when(results.size()).thenReturn(7); // result 0..6
+		when(settings.size()).thenReturn(BigInteger.TEN);
+		// when(session7settings.getTeams()).thenReturn(participants);
+		when(session7settings.getAllParties()).thenReturn(participants);
+		when(settings.get(BigInteger.valueOf(7))).thenReturn(session7settings);
+
+	}
+
+	@Test
+	public void withTest() {
+		prepareNextSettings();
+		ArrayList<SessionResult> results1 = new ArrayList<>();
+		for (int n = 0; n < 7; n++) {
+			results1.add(mock(SessionResult.class));
+		}
+		// use state with "real" results... to allow array copy in with
+		AllPermutationsLearnState state0 = new AllPermutationsLearnState(
+				toursettings, settings, results1);
+
+		when(settings.size()).thenReturn(BigInteger.TEN);
+		when(settings.get(BigInteger.valueOf(7))).thenReturn(session7settings);
+
+		SessionResult result = mock(SessionResult.class);
+
+		Map<PartyId, PartyWithProfile> participants3 = mock(Map.class);
+		when(participants3.values()).thenReturn(participants);
+		when(result.getParticipants()).thenReturn(participants3);
+		AllPermutationsLearnState state1 = state0.with(result);
+
+		assertEquals(8, state1.getResults().size());
+		assertEquals(toursettings, state1.getSettings());
+
+	}
+}
