package com.workshare.msnos.core; import static com.workshare.msnos.core.CoreHelper.*; import static com.workshare.msnos.core.CoreHelper.newAgentIden; import static com.workshare.msnos.core.CoreHelper.newCloudIden; import static com.workshare.msnos.core.CoreHelper.synchronousCloudMulticaster; import static com.workshare.msnos.core.Message.Type.APP; import static com.workshare.msnos.core.MessagesHelper.newPingMessage; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.*; import java.io.IOException; import java.util.Collections; import java.util.Set; import java.util.UUID; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import com.workshare.msnos.core.Cloud.Internal; import com.workshare.msnos.core.cloud.IdentifiablesList; import com.workshare.msnos.core.cloud.MessageValidators; import com.workshare.msnos.core.cloud.Multicaster; import com.workshare.msnos.core.protocols.ip.Endpoint; import com.workshare.msnos.core.routing.Router; import com.workshare.msnos.core.security.KeysStore; import com.workshare.msnos.core.security.Signer; import com.workshare.msnos.soup.time.SystemTime; @SuppressWarnings("unused") // TODO move here all the receiver test from CloudTest public class ReceiverTest { private Router router; private Receiver receiver; private Cloud cloud; private Multicaster caster; private Gateway gate; private LocalAgent local; @Before public void before() { cloud = createMockCloud(); gate = mock(Gateway.class); local = newLocalAgent(); router = mock(Router.class); Set<Gateway> gates = asSet(gate); caster = mock(Multicaster.class); MessageValidators validators = new MessageValidators(cloud.internal()); receiver = new Receiver(cloud, gates, caster, router); } @After public void after() throws Exception { SystemTime.reset(); } @Test public void shouldInvokeRouterOnReceivedMessage() throws Exception { final Message message = newPingMessage(cloud); simulateMessageReceived(message); verify(router).forward(message); } @Test public void shouldInvokeCasterOnReceivedMessage() throws Exception { final Message message = newPingMessage(cloud); simulateMessageReceived(message); verify(caster).dispatch(message); } @Test public void shouldInvokeCloudProcessOnReceivedMessage() throws Exception { final Message message = newPingMessage(cloud); simulateMessageReceived(message); verify(cloud).postProcess(message); } @Test public void shouldStampMessageWithGateName() throws Exception { when(gate.name()).thenReturn("YOP"); final Message message = newPingMessage(cloud); simulateMessageReceived(message); assertEquals("YOP", lastMessageReceived().getReceivingGate()); } @Test public void shouldDiscardMessageFromAnotherCloud() throws Exception { Cloud other = createMockCloud(); final Message message = newPingMessage(other); simulateMessageReceived(message); verifyMessageDiscarded(); } @Test public void shouldDiscardMessageSentFromLocalAgent() throws Exception { final Message message = newPingMessage(local, cloud); simulateMessageReceived(message); verifyMessageDiscarded(); } @Test public void shouldNOTInvokeCloudOnMessageSentToRemoteAgent() throws Exception { RemoteAgent remote = newRemoteAgent(cloud); final Message message = newPingMessage(cloud, remote); simulateMessageReceived(message); verify(cloud, never()).postProcess(message); } @Test public void shouldNOTInvokeCasterOnMessageSentToARemoteAgent() throws Exception { RemoteAgent remote = newRemoteAgent(cloud); final Message message = newPingMessage(cloud, remote); simulateMessageReceived(message); verifyZeroInteractions(caster); } @Test public void shouldALWAYSInvokeRouterOnMessageSentToARemoteAgent() throws Exception { RemoteAgent remote = newRemoteAgent(cloud); final Message message = newPingMessage(cloud, remote); simulateMessageReceived(message); verify(router).forward(message); } @Test public void shouldDiscardMessagesSignedWithAnInvalidSignature() throws Exception { mockMessageSigning("sign-key", "correct-signature"); final Message message = newPingMessage(cloud, local).signed("sign-key", "this-is-an-invalid-signature"); simulateMessageReceived(message); verifyMessageDiscarded(); } @Test public void shouldDiscardMessagesAlreadyReceived() throws Exception { final Message message = newPingMessage(cloud, newRemoteAgent(cloud)); simulateMessageReceived(message); reset(caster, router); simulateMessageReceived(message); verifyZeroInteractions(caster, router); } @Test public void shouldDiscardMessagesWithOldTimestamps() throws Exception { fakeSystemTime(100000); Message message = newPingMessage(cloud, newRemoteAgent(cloud)); fakeSystemTime(9900000); simulateMessageReceived(message); verifyMessageDiscarded(); } private void verifyMessageDiscarded() { verifyZeroInteractions(caster, router); verify(cloud, never()).postProcess(any(Message.class)); } private void simulateMessageReceived(Message message) { ArgumentCaptor<Gateway.Listener> gateListener = ArgumentCaptor.forClass(Gateway.Listener.class); verify(gate).addListener(any(Cloud.class), gateListener.capture()); gateListener.getValue().onMessage(message); } private LocalAgent newLocalAgent() { final LocalAgent local = mock(LocalAgent.class); when(local.getIden()).thenReturn(newAgentIden()); when(local.getCloud()).thenReturn(cloud); cloud.internal().localAgents().add(local); return local; } private RemoteAgent newRemoteAgent(Cloud cloud) { final RemoteAgent remote = new RemoteAgent(UUID.randomUUID(), cloud, Collections.<Endpoint> emptySet()); cloud.internal().remoteAgents().add(remote); return remote; } private void mockMessageSigning(final String signKey, final String signVal) { when(cloud.internal().sign(any(Message.class))).thenAnswer(new Answer<Message>(){ @Override public Message answer(InvocationOnMock invocation) throws Throwable { final Message message = (Message) invocation.getArguments()[0]; return message.signed(signKey, signVal); }}); } private Message lastMessageReceived() { ArgumentCaptor<Message> received = ArgumentCaptor.forClass(Message.class); verify(router).forward(received.capture()); final Message lastReceived = received.getValue(); return lastReceived; } }