final FudgeContext fudgeContext = OpenGammaFudgeContext.getInstance();
final DefaultViewComputationCacheSource serverCacheSource = new DefaultViewComputationCacheSource(
new InMemoryIdentifierMap(), fudgeContext, createInMemoryFudgeMessageStoreFactory(fudgeContext));
final ViewComputationCacheServer server = new ViewComputationCacheServer(serverCacheSource);
server.getBinaryDataStore().setFindValueTimeout(Timeout.standardTimeoutMillis() * 5);
final DirectFudgeConnection conduit1 = new DirectFudgeConnection(fudgeContext);
conduit1.connectEnd1(server);
final DirectFudgeConnection conduit2 = new DirectFudgeConnection(fudgeContext);
conduit2.connectEnd1(server);
final DirectFudgeConnection conduit3 = new DirectFudgeConnection(fudgeContext);
conduit3.connectEnd1(server);
final RemoteViewComputationCacheSource remoteCacheSource1 = new RemoteViewComputationCacheSource(
new RemoteCacheClient(conduit1.getEnd2()), createInMemoryFudgeMessageStoreFactory(fudgeContext), _cacheManager);
final RemoteViewComputationCacheSource remoteCacheSource2 = new RemoteViewComputationCacheSource(
new RemoteCacheClient(conduit2.getEnd2()), createInMemoryFudgeMessageStoreFactory(fudgeContext), _cacheManager);
final RemoteViewComputationCacheSource remoteCacheSource3 = new RemoteViewComputationCacheSource(
new RemoteCacheClient(conduit3.getEnd2()), createInMemoryFudgeMessageStoreFactory(fudgeContext), _cacheManager);
// Populate the test caches
final ValueSpecification[] specs = createValueSpecifications(10);
UniqueId viewCycleId = UniqueId.of("Test", "ViewCycle");
final ViewComputationCache serverCache = serverCacheSource.getCache(viewCycleId, "Default");
final ViewComputationCache remoteCache1 = remoteCacheSource1.getCache(viewCycleId, "Default");
final ViewComputationCache remoteCache2 = remoteCacheSource2.getCache(viewCycleId, "Default");
final ViewComputationCache remoteCache3 = remoteCacheSource3.getCache(viewCycleId, "Default");
serverCache.putSharedValue(new ComputedValue(specs[0], "Zero"));
serverCache.putPrivateValue(new ComputedValue(specs[1], "One"));
remoteCache1.putPrivateValue(new ComputedValue(specs[2], "Two"));
remoteCache1.putPrivateValue(new ComputedValue(specs[3], "Three"));
remoteCache1.putPrivateValue(new ComputedValue(specs[4], "Four"));
remoteCache2.putPrivateValue(new ComputedValue(specs[3], "Three"));
remoteCache2.putPrivateValue(new ComputedValue(specs[5], "Five"));
remoteCache2.putPrivateValue(new ComputedValue(specs[6], "Six"));
remoteCache3.putPrivateValue(new ComputedValue(specs[7], "Seven"));
// Direct lookup on server
Object value = serverCache.getValue(specs[0]);
assertEquals("Zero", value);
value = serverCache.getValue(specs[1]);
assertEquals("One", value);
// Only identifier lookup messages expected
Thread.sleep(Timeout.standardTimeoutMillis());
assertEquals(3, conduit1.getAndResetMessages1To2());
assertEquals(3, conduit1.getAndResetMessages2To1());
assertEquals(3, conduit2.getAndResetMessages1To2());
assertEquals(3, conduit2.getAndResetMessages2To1());
assertEquals(1, conduit3.getAndResetMessages1To2());
assertEquals(1, conduit3.getAndResetMessages2To1());
// Query for a value elsewhere
value = serverCache.getValue(specs[2]);
assertEquals("Two", value);
// One message sent to each, 1 response (and ack) from client1
Thread.sleep(Timeout.standardTimeoutMillis());
assertEquals(2, conduit1.getAndResetMessages1To2());
assertEquals(1, conduit1.getAndResetMessages2To1());
assertEquals(1, conduit2.getAndResetMessages1To2());
assertEquals(0, conduit2.getAndResetMessages2To1());
assertEquals(1, conduit3.getAndResetMessages1To2());
assertEquals(0, conduit3.getAndResetMessages2To1());
// Query for a value duplicated on multiple nodes
value = serverCache.getValue(specs[3]);
assertEquals("Three", value);
// One message sent to each, 1 response (and ack) from client1 and client2
Thread.sleep(Timeout.standardTimeoutMillis());
assertRange(1, 2, conduit1.getAndResetMessages1To2());
assertRange(0, 1, conduit1.getAndResetMessages2To1());
assertRange(1, 2, conduit2.getAndResetMessages1To2());
assertRange(0, 1, conduit2.getAndResetMessages2To1());
assertEquals(1, conduit3.getAndResetMessages1To2());
assertEquals(0, conduit3.getAndResetMessages2To1());
// Query for a set of values on two different nodes
Collection<Pair<ValueSpecification, Object>> values = serverCache.getValues(Arrays.asList(specs[4], specs[5],
specs[6]));
assertEquals(3, values.size());
assertTrue(values.contains(Pair.of(specs[4], "Four")));
assertTrue(values.contains(Pair.of(specs[5], "Five")));
assertTrue(values.contains(Pair.of(specs[6], "Six")));
// One message sent to each, 1 response (and ack) from client1 and 2
Thread.sleep(Timeout.standardTimeoutMillis());
assertEquals(2, conduit1.getAndResetMessages1To2());
assertEquals(1, conduit1.getAndResetMessages2To1());
assertEquals(2, conduit2.getAndResetMessages1To2());
assertEquals(1, conduit2.getAndResetMessages2To1());
assertEquals(1, conduit3.getAndResetMessages1To2());
assertEquals(0, conduit3.getAndResetMessages2To1());
// Query for a non-existent single value
value = serverCache.getValue(specs[8]);
assertNull(value);
assertEquals(1, conduit3.getAndResetMessages1To2());
assertEquals(0, conduit3.getAndResetMessages2To1());
// Query for one existing and one non-existent value
values = serverCache.getValues(Arrays.asList(specs[7], specs[8]));
assertEquals(1, values.size());
assertTrue(values.contains(Pair.of(specs[7], "Seven")));
assertEquals(2, conduit3.getAndResetMessages1To2());
assertEquals(1, conduit3.getAndResetMessages2To1());
// Query for two non-existing values
values = serverCache.getValues(Arrays.asList(specs[8], specs[9]));
assertNotNull(values);
assertTrue(values.isEmpty());
assertEquals(1, conduit3.getAndResetMessages1To2());
assertEquals(0, conduit3.getAndResetMessages2To1());
}