diff options
author | Marcin Chrzanowski <marcin.j.chrzanowski@gmail.com> | 2020-01-09 18:16:28 +0100 |
---|---|---|
committer | Marcin Chrzanowski <marcin.j.chrzanowski@gmail.com> | 2020-01-09 18:16:28 +0100 |
commit | 4ba7fa9be088650dc32dbabaa1ef2ea47681ec81 (patch) | |
tree | b503340909c3202bd1ee11ff05cd199082547bd7 /src | |
parent | ce76dbc406da1a8fe839b1e311ed699f9d5c7498 (diff) |
Test gossip initialization
Diffstat (limited to 'src')
3 files changed, 168 insertions, 14 deletions
diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/GossipGirl.java b/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/GossipGirl.java index 01119bf..ccc7ee5 100644 --- a/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/GossipGirl.java +++ b/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/GossipGirl.java @@ -69,8 +69,8 @@ public class GossipGirl extends Module { "", 0, state.gossipId, - getZoneTimestamps(message.getZMI()), - getQueryTimestamps(message.getQueries()) + state.getZoneTimestampsToSend(), + state.getQueryTimestampsToSend() ); UDUPMessage udupMessage = new UDUPMessage("", 0, state.theirContact, hejka); sendMessage(udupMessage); @@ -96,13 +96,4 @@ public class GossipGirl extends Module { System.out.println("ERROR: GossipGirl got state for a nonexistent gossip"); } } - - public Map<PathName, ValueTime> getZoneTimestamps(ZMI root) { - return new HashMap(); - } - - public Map<Attribute, ValueTime> getQueryTimestamps(Map<Attribute, Entry<ValueQuery, ValueTime>> queries) { - return new HashMap(); - } - } diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/GossipGirlState.java b/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/GossipGirlState.java index 726a9b2..8ec8ed2 100644 --- a/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/GossipGirlState.java +++ b/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/GossipGirlState.java @@ -1,5 +1,7 @@ package pl.edu.mimuw.cloudatlas.agent.modules; +import java.util.HashMap; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -95,10 +97,63 @@ public class GossipGirlState { } } + public Map<PathName, ValueTime> getZoneTimestampsToSend() { + Map<PathName, ValueTime> timestamps = new HashMap(); + collectZoneTimestamps(timestamps, hierarchy, theirContact.getName()); + return timestamps; + } + + public Map<Attribute, ValueTime> getQueryTimestampsToSend() { + Map<Attribute, ValueTime> queryTimestamps= new HashMap(); + for (Entry<Attribute, Entry<ValueQuery, ValueTime>> query : queries.entrySet()) { + queryTimestamps.put(query.getKey(), query.getValue().getValue()); + } + + return queryTimestamps; + } + public List<ZMI> getZMIsToSend() { return new LinkedList(); } + public void collectZoneTimestamps(Map<PathName, ValueTime> timestamps, ZMI currentZMI, PathName recipientPath) { + for (ZMI zmi : currentZMI.getSons()) { + if (interestedIn(recipientPath, zmi.getPathName())) { + ValueTime timestamp = (ValueTime) zmi.getAttributes().getOrNull("timestamp"); + if (timestamp != null) { + timestamps.put(zmi.getPathName(), timestamp); + } else { + System.out.println("ERROR: collectZoneTimestamps encountered a zone with no timestamp"); + } + } else { + collectZoneTimestamps(timestamps, zmi, recipientPath); + } + } + } + + public boolean interestedIn(PathName recipientPath, PathName zmiPath) { + return isPrefix(zmiPath.levelUp(), recipientPath) && !isPrefix(zmiPath, recipientPath); + } + + public boolean isPrefix(PathName prefix, PathName path) { + List<String> prefixComponents = prefix.getComponents(); + List<String> pathComponents = path.getComponents(); + + if (prefixComponents.size() > pathComponents.size()) { + return false; + } + + Iterator<String> prefixIterator = prefixComponents.iterator(); + Iterator<String> pathIterator = pathComponents.iterator(); + + while (prefixIterator.hasNext()) { + if (!prefixIterator.next().equals(pathIterator.next())) { + return false; + } + } + return true; + } + public void sentInfo() { switch (state) { case SEND_INFO: diff --git a/src/test/java/pl/edu/mimuw/cloudatlas/agent/modules/GossipGirlTest.java b/src/test/java/pl/edu/mimuw/cloudatlas/agent/modules/GossipGirlTest.java index 0658b65..1d6496c 100644 --- a/src/test/java/pl/edu/mimuw/cloudatlas/agent/modules/GossipGirlTest.java +++ b/src/test/java/pl/edu/mimuw/cloudatlas/agent/modules/GossipGirlTest.java @@ -3,28 +3,109 @@ package pl.edu.mimuw.cloudatlas.agent.modules; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.*; +import static org.hamcrest.CoreMatchers.hasItems; + +import java.net.InetAddress; +import java.util.AbstractMap.SimpleImmutableEntry; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; import pl.edu.mimuw.cloudatlas.agent.MockExecutor; import pl.edu.mimuw.cloudatlas.agent.messages.AgentMessage; +import pl.edu.mimuw.cloudatlas.agent.messages.HejkaMessage; import pl.edu.mimuw.cloudatlas.agent.messages.GetStateMessage; import pl.edu.mimuw.cloudatlas.agent.messages.GossipGirlMessage; import pl.edu.mimuw.cloudatlas.agent.messages.InitiateGossipMessage; import pl.edu.mimuw.cloudatlas.agent.messages.StanikMessage; +import pl.edu.mimuw.cloudatlas.agent.messages.StateMessage; +import pl.edu.mimuw.cloudatlas.agent.messages.UDUPMessage; +import pl.edu.mimuw.cloudatlas.agent.modules.ModuleType; +import pl.edu.mimuw.cloudatlas.model.AttributesMap; +import pl.edu.mimuw.cloudatlas.model.Attribute; +import pl.edu.mimuw.cloudatlas.model.PathName; +import pl.edu.mimuw.cloudatlas.model.TestUtil; +import pl.edu.mimuw.cloudatlas.model.ValueContact; +import pl.edu.mimuw.cloudatlas.model.ValueInt; +import pl.edu.mimuw.cloudatlas.model.ValueQuery; +import pl.edu.mimuw.cloudatlas.model.ValueString; +import pl.edu.mimuw.cloudatlas.model.ValueTime; +import pl.edu.mimuw.cloudatlas.model.ValueUtils; +import pl.edu.mimuw.cloudatlas.model.ZMI; public class GossipGirlTest { private GossipGirl gossipGirl; private MockExecutor executor; + private final PathName ourPath = new PathName("/son/grand"); + private final PathName theirPath = new PathName("/son/bro"); + private ValueContact theirContact; + private InitiateGossipMessage initiateGossipMessage; + private ZMI initiatorHierarchy; + private ValueTime testTime; + private Map<Attribute, Entry<ValueQuery, ValueTime>> initiatorQueries; + private StateMessage initiatorStateMessage; @Before - public void setupLocals() { + public void setupLocals() throws Exception { gossipGirl = new GossipGirl(); executor = new MockExecutor(gossipGirl); + + theirContact = new ValueContact( + theirPath, + InetAddress.getByAddress("localhost", new byte[] { 127, 0, 0, 1 }) + ); + initiateGossipMessage = new InitiateGossipMessage( + "test_msg", + 0, + ourPath, + theirContact + ); + + testTime = ValueUtils.currentTime(); + setupHierarchy(); + setupQueries(); + initiatorStateMessage = new StateMessage("", ModuleType.GOSSIP, 0, 0, initiatorHierarchy, initiatorQueries); + } + + public void setupHierarchy() { + initiatorHierarchy = makeZMI(null, null, 13l, "hello", testTime); + ZMI son = makeZMI(initiatorHierarchy, "son", 42l, "world", testTime); + ZMI daughter = makeZMI(initiatorHierarchy, "daughter", 24l, "kebab", testTime); + ZMI grand = makeZMI(son, "grand", 1337l, "ok", testTime); + ZMI bro = makeZMI(son, "bro", 3451434l, "whazzup", testTime); + ZMI sis = makeZMI(son, "sis", 420l, "hey", testTime); + } + + public void setupQueries() throws Exception { + initiatorQueries = new HashMap(); + addQuery(initiatorQueries, "&one", "SELECT 1 AS one", testTime); + addQuery(initiatorQueries, "&query", "SELECT sum(foo) AS foo", testTime); + } + + public void addQuery(Map<Attribute, Entry<ValueQuery, ValueTime>> queries, String name, String query, ValueTime timestamp) throws Exception { + queries.put( + new Attribute(name), + new SimpleImmutableEntry(new ValueQuery(query), timestamp) + ); + } + + private ZMI makeZMI(ZMI parent, String name, Long foo, String bar, ValueTime timestamp) { + ZMI zmi = new ZMI(parent); + if (parent != null) { + parent.addSon(zmi); + } + AttributesMap attributes = zmi.getAttributes(); + attributes.add("name", new ValueString(name)); + attributes.add("foo", new ValueInt(foo)); + attributes.add("bar", new ValueString(bar)); + attributes.add("timestamp", timestamp); + return zmi; } @Test public void initiateGossipRequestsState() throws Exception { - InitiateGossipMessage message = new InitiateGossipMessage("test_msg", 0); - gossipGirl.handleTyped(message); + gossipGirl.handleTyped(initiateGossipMessage); AgentMessage receivedMessage = executor.messagesToPass.poll(); assertNotNull(receivedMessage); @@ -34,4 +115,31 @@ public class GossipGirlTest { GetStateMessage getStateMessage = (GetStateMessage) stanikMessage; assertEquals(ModuleType.GOSSIP, getStateMessage.getRequestingModule()); } + + @Test + public void initiatorSendsHejkaOnState() throws Exception { + gossipGirl.handleTyped(initiateGossipMessage); + executor.messagesToPass.take(); + gossipGirl.handleTyped(initiatorStateMessage); + + AgentMessage receivedMessage = executor.messagesToPass.poll(); + assertNotNull(receivedMessage); + assertEquals(ModuleType.UDP, receivedMessage.getDestinationModule()); + UDUPMessage udupMessage = (UDUPMessage) receivedMessage; + assertEquals(new PathName("/son/bro"), udupMessage.getContact().getName()); + assertEquals(ModuleType.GOSSIP, udupMessage.getContent().getDestinationModule()); + GossipGirlMessage gossipMessage = (GossipGirlMessage) udupMessage.getContent(); + + assertEquals(GossipGirlMessage.Type.HEJKA, gossipMessage.getType()); + HejkaMessage hejkaMessage = (HejkaMessage) gossipMessage; + assertEquals(0, hejkaMessage.getSenderGossipId()); + System.out.println(hejkaMessage.getZoneTimestamps().keySet()); + assertEquals(3, TestUtil.iterableSize(hejkaMessage.getZoneTimestamps().keySet())); + Set<PathName> zoneSet = hejkaMessage.getZoneTimestamps().keySet(); + assertThat(zoneSet, hasItems(new PathName("/daughter"))); + assertThat(zoneSet, hasItems(new PathName("/son/sis"))); + assertThat(zoneSet, hasItems(new PathName("/son/grand"))); + + assertEquals(2, TestUtil.iterableSize(hejkaMessage.getQueryTimestamps().keySet())); + } } |