/*
* Copyright 2016 higherfrequencytrading.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package net.openhft.chronicle.engine;
import net.openhft.chronicle.core.threads.ThreadDump;
import net.openhft.chronicle.engine.api.map.MapEvent;
import net.openhft.chronicle.engine.api.pubsub.InvalidSubscriberException;
import net.openhft.chronicle.engine.api.pubsub.Subscriber;
import net.openhft.chronicle.engine.api.pubsub.TopicPublisher;
import net.openhft.chronicle.engine.api.pubsub.TopicSubscriber;
import net.openhft.chronicle.engine.api.tree.Asset;
import net.openhft.chronicle.engine.api.tree.AssetNotFoundException;
import net.openhft.chronicle.engine.map.InsertedEvent;
import net.openhft.chronicle.engine.map.RemovedEvent;
import net.openhft.chronicle.engine.map.UpdatedEvent;
import org.jetbrains.annotations.NotNull;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;
import static net.openhft.chronicle.engine.Chassis.*;
import static net.openhft.chronicle.engine.api.tree.RequestContext.requestContext;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
/**
* Created by peter on 22/05/15.
*/
public class ChassisTest {
private ThreadDump threadDump;
@Before
public void threadDump() {
threadDump = new ThreadDump();
}
@After
public void checkThreadDump() {
threadDump.assertNoNewThreads();
}
@Before
public void setUp() {
resetChassis();
}
@Test
public void simpleGetMapView() {
@NotNull ConcurrentMap<String, String> map = acquireMap("map-name", String.class, String.class);
registerTopicSubscriber("map-name", String.class, String.class, (t, e) -> System.out.println("{ key: " + t + ", event: " + e + " }"));
map.put("Hello", "World");
@NotNull ConcurrentMap<String, String> map2 = acquireMap("map-name", String.class, String.class);
assertSame(map, map2);
map2.put("Bye", "soon");
map2.put("Bye", "now.");
}
@Test
public void subscription() throws InvalidSubscriberException {
@NotNull ConcurrentMap<String, String> map = acquireMap("map-name?putReturnsNull=true", String.class, String.class);
map.put("Key-1", "Value-1");
map.put("Key-2", "Value-2");
assertEquals(2, map.size());
// test the bootstrap finds old keys
Subscriber<String> subscriber = createMock(Subscriber.class);
subscriber.onMessage("Key-1");
subscriber.onMessage("Key-2");
replay(subscriber);
registerSubscriber("map-name?bootstrap=true", String.class, subscriber);
verify(subscriber);
reset(subscriber);
assertEquals(2, map.size());
// test the topic publish triggers events
subscriber.onMessage("Topic-1");
replay(subscriber);
@NotNull TopicPublisher<String, String> publisher = acquireTopicPublisher("map-name", String.class, String.class);
publisher.publish("Topic-1", "Message-1");
verify(subscriber);
reset(subscriber);
assertEquals(3, map.size());
subscriber.onMessage("Hello");
subscriber.onMessage("Bye");
subscriber.onMessage("Key-1");
replay(subscriber);
// test plain puts trigger events
map.put("Hello", "World");
map.put("Bye", "soon");
map.remove("Key-1");
verify(subscriber);
assertEquals(4, map.size());
// check the contents.
assertEquals("Topic-1=Message-1\n" +
"Key-2=Value-2\n" +
"Hello=World\n" +
"Bye=soon",
map.entrySet().stream()
.map(Object::toString)
.collect(Collectors.joining("\n")));
assertEquals("Topic-1, Key-2, Hello, Bye",
map.keySet().stream()
.collect(Collectors.joining(", ")));
assertEquals("Message-1, Value-2, World, soon",
map.values().stream()
.collect(Collectors.joining(", ")));
}
@Test
public void keySubscription() throws InvalidSubscriberException {
@NotNull ConcurrentMap<String, String> map = acquireMap("map-name?putReturnsNull=true", String.class, String.class);
map.put("Key-1", "Value-1");
map.put("Key-2", "Value-2");
assertEquals(2, map.size());
// test the bootstrap finds the old value
Subscriber<String> subscriber = createMock(Subscriber.class);
subscriber.onMessage("Value-1");
replay(subscriber);
registerSubscriber("map-name/Key-1?bootstrap=true", String.class, subscriber);
assertTrue(getAsset("map-name/Key-1").isSubAsset());
verify(subscriber);
reset(subscriber);
assertEquals(2, map.size());
// test the topic publish triggers events
subscriber.onMessage("Message-1");
replay(subscriber);
@NotNull TopicPublisher<String, String> publisher = acquireTopicPublisher("map-name", String.class, String.class);
publisher.publish("Key-1", "Message-1");
publisher.publish("Key-2", "Message-2");
verify(subscriber);
reset(subscriber);
subscriber.onMessage("Bye");
subscriber.onMessage(null);
replay(subscriber);
// test plain puts trigger events
map.put("Key-1", "Bye");
map.put("Key-3", "Another");
map.remove("Key-1");
verify(subscriber);
}
@Test
public void topicSubscription() throws InvalidSubscriberException {
@NotNull ConcurrentMap<String, String> map = acquireMap("map-name?putReturnsNull=true", String.class, String.class);
map.put("Key-1", "Value-1");
map.put("Key-2", "Value-2");
assertEquals(2, map.size());
// test the bootstrap finds old keys
TopicSubscriber<String, String> subscriber = createMock(TopicSubscriber.class);
subscriber.onMessage("Key-1", "Value-1");
subscriber.onMessage("Key-2", "Value-2");
replay(subscriber);
registerTopicSubscriber("map-name?bootstrap=true", String.class, String.class, subscriber);
verify(subscriber);
reset(subscriber);
assertEquals(2, map.size());
// test the topic publish triggers events
subscriber.onMessage("Topic-1", "Message-1");
replay(subscriber);
@NotNull TopicPublisher<String, String> publisher = acquireTopicPublisher("map-name", String.class, String.class);
publisher.publish("Topic-1", "Message-1");
verify(subscriber);
reset(subscriber);
assertEquals(3, map.size());
subscriber.onMessage("Hello", "World");
subscriber.onMessage("Bye", "soon");
subscriber.onMessage("Key-1", null);
replay(subscriber);
// test plain puts trigger events
map.put("Hello", "World");
map.put("Bye", "soon");
map.remove("Key-1");
verify(subscriber);
assertEquals(4, map.size());
// check the contents.
assertEquals("Topic-1=Message-1\n" +
"Key-2=Value-2\n" +
"Hello=World\n" +
"Bye=soon",
map.entrySet().stream()
.map(Object::toString)
.collect(Collectors.joining("\n")));
assertEquals("Topic-1, Key-2, Hello, Bye",
map.keySet().stream()
.collect(Collectors.joining(", ")));
assertEquals("Message-1, Value-2, World, soon",
map.values().stream()
.collect(Collectors.joining(", ")));
}
@Test
public void entrySubscription() throws InvalidSubscriberException {
@NotNull ConcurrentMap<String, String> map = acquireMap("map-name?putReturnsNull=true", String.class, String.class);
map.put("Key-1", "Value-1");
map.put("Key-2", "Value-2");
assertEquals(2, map.size());
// test the bootstrap finds old keys
Subscriber<MapEvent<String, String>> subscriber = createMock(Subscriber.class);
subscriber.onMessage(InsertedEvent.of("/map-name", "Key-1", "Value-1",false));
subscriber.onMessage(InsertedEvent.of("/map-name", "Key-2", "Value-2",false));
replay(subscriber);
registerSubscriber("map-name?bootstrap=true", MapEvent.class, (Subscriber) subscriber);
verify(subscriber);
reset(subscriber);
assertEquals(2, map.size());
// test the topic publish triggers events
subscriber.onMessage(UpdatedEvent.of("/map-name", "Key-1", "Value-1", "Message-1", false,
true));
subscriber.onMessage(InsertedEvent.of("/map-name", "Topic-1", "Message-1",false));
replay(subscriber);
@NotNull TopicPublisher<String, String> publisher = acquireTopicPublisher("map-name", String.class, String.class);
publisher.publish("Key-1", "Message-1");
publisher.publish("Topic-1", "Message-1");
verify(subscriber);
reset(subscriber);
assertEquals(3, map.size());
subscriber.onMessage(InsertedEvent.of("/map-name", "Hello", "World",false));
subscriber.onMessage(InsertedEvent.of("/map-name", "Bye", "soon",false));
subscriber.onMessage(RemovedEvent.of("/map-name", "Key-1", "Message-1",false));
replay(subscriber);
// test plain puts trigger events
map.put("Hello", "World");
map.put("Bye", "soon");
map.remove("Key-1");
verify(subscriber);
assertEquals(4, map.size());
}
@Test
public void testStringString() throws IOException, InterruptedException {
@NotNull final ConcurrentMap<String, String> mapProxy = Chassis.acquireMap("testStringString", String.class, String.class);
mapProxy.put("hello", "world");
Assert.assertEquals("world", mapProxy.get("hello"));
assertEquals(1, mapProxy.size());
}
@Test
public void newNode() {
@NotNull Asset group = acquireAsset("group");
@NotNull Asset subgroup = acquireAsset("group/sub-group");
assertEquals("/group/sub-group", subgroup.fullName());
@NotNull Asset group2 = acquireAsset("/group2/sub-group");
assertEquals("/group2/sub-group", group2.fullName());
}
@Test()
public void noAsset() {
registerTopicSubscriber("topic-name", String.class, String.class, (t, e) -> System.out.println("{ key: " + t + ", event: " + e + " }"));
@NotNull TopicPublisher<String, String> publisher = acquireTopicPublisher("topic-name", String.class, String.class);
publisher.publish("hi", "there");
// TODO should send a message.
}
@Test(expected = AssetNotFoundException.class)
public void noInterceptor() {
@NotNull Asset asset = acquireAsset("");
asset.acquireView(requestContext("").viewType(MyInterceptor.class));
}
@Test
public void generateInterceptor() {
@NotNull Asset asset = acquireAsset("");
asset.addLeafRule(MyInterceptor.class, "test", (context, asset2) -> {
assertEquals(MyInterceptor.class, context.viewType());
return new MyInterceptor();
});
@NotNull MyInterceptor mi = asset.acquireView(requestContext("").viewType(MyInterceptor.class));
@NotNull MyInterceptor mi2 = asset.acquireView(requestContext("").viewType(MyInterceptor.class));
assertNotNull(mi);
assertSame(mi, mi2);
}
static class MyInterceptor {
}
}