/*
* Copyright (c) 2008-2017 the original author or authors.
*
* 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 org.cometd.server;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.cometd.bayeux.Message;
import org.cometd.bayeux.client.ClientSessionChannel;
import org.cometd.bayeux.server.BayeuxServer;
import org.cometd.bayeux.server.ConfigurableServerChannel;
import org.cometd.bayeux.server.LocalSession;
import org.cometd.bayeux.server.ServerChannel;
import org.cometd.bayeux.server.ServerMessage;
import org.cometd.bayeux.server.ServerSession;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class BayeuxServerTest {
private final Queue<Object> _events = new ConcurrentLinkedQueue<>();
private final BayeuxServerImpl _bayeux = new BayeuxServerImpl();
private ServerSessionImpl newServerSession() {
ServerSessionImpl session = _bayeux.newServerSession();
_bayeux.addServerSession(session, _bayeux.newMessage());
session.handshake();
session.connected();
return session;
}
@Before
public void init() throws Exception {
_bayeux.start();
}
@After
public void destroy() throws Exception {
_bayeux.stop();
_events.clear();
}
@Test
public void testListeners() throws Exception {
_bayeux.addListener(new SubListener());
_bayeux.addListener(new SessListener());
_bayeux.addListener(new CListener());
String channelName = "/foo/bar";
ServerChannelImpl foobar = (ServerChannelImpl)_bayeux.createChannelIfAbsent(channelName).getReference();
channelName = "/foo/*";
ServerChannelImpl foostar = (ServerChannelImpl)_bayeux.createChannelIfAbsent(channelName).getReference();
channelName = "/**";
ServerChannelImpl starstar = (ServerChannelImpl)_bayeux.createChannelIfAbsent(channelName).getReference();
channelName = "/foo/bob";
ServerChannelImpl foobob = (ServerChannelImpl)_bayeux.createChannelIfAbsent(channelName).getReference();
channelName = "/wibble";
ServerChannelImpl wibble = (ServerChannelImpl)_bayeux.createChannelIfAbsent(channelName).getReference();
Assert.assertEquals("channelAdded", _events.poll());
Assert.assertEquals(foobar, _events.poll());
Assert.assertEquals("channelAdded", _events.poll());
Assert.assertEquals(foostar, _events.poll());
Assert.assertEquals("channelAdded", _events.poll());
Assert.assertEquals(starstar, _events.poll());
Assert.assertEquals("channelAdded", _events.poll());
Assert.assertEquals(foobob, _events.poll());
Assert.assertEquals("channelAdded", _events.poll());
Assert.assertEquals(wibble, _events.poll());
wibble.remove();
Assert.assertEquals("channelRemoved", _events.poll());
Assert.assertEquals(wibble.getId(), _events.poll());
ServerSessionImpl session0 = newServerSession();
ServerSessionImpl session1 = newServerSession();
ServerSessionImpl session2 = newServerSession();
Assert.assertEquals("sessionAdded", _events.poll());
Assert.assertEquals(session0, _events.poll());
Assert.assertEquals("sessionAdded", _events.poll());
Assert.assertEquals(session1, _events.poll());
Assert.assertEquals("sessionAdded", _events.poll());
Assert.assertEquals(session2, _events.poll());
foobar.subscribe(session0);
foobar.unsubscribe(session0);
Assert.assertEquals("subscribed", _events.poll());
Assert.assertEquals(session0, _events.poll());
Assert.assertEquals(foobar, _events.poll());
Assert.assertEquals("unsubscribed", _events.poll());
Assert.assertEquals(session0, _events.poll());
Assert.assertEquals(foobar, _events.poll());
}
@Test
public void testSessionAttributes() throws Exception {
LocalSession local = _bayeux.newLocalSession("s0");
local.handshake();
ServerSession session = local.getServerSession();
local.setAttribute("foo", "bar");
Assert.assertEquals("bar", local.getAttribute("foo"));
Assert.assertEquals(null, session.getAttribute("foo"));
session.setAttribute("bar", "foo");
Assert.assertEquals(null, local.getAttribute("bar"));
Assert.assertEquals("foo", session.getAttribute("bar"));
Assert.assertTrue(local.getAttributeNames().contains("foo"));
Assert.assertFalse(local.getAttributeNames().contains("bar"));
Assert.assertFalse(session.getAttributeNames().contains("foo"));
Assert.assertTrue(session.getAttributeNames().contains("bar"));
Assert.assertEquals("bar", local.removeAttribute("foo"));
Assert.assertEquals(null, local.removeAttribute("foo"));
Assert.assertEquals("foo", session.removeAttribute("bar"));
Assert.assertEquals(null, local.removeAttribute("bar"));
}
@Test
public void testLocalSessions() throws Exception {
LocalSession session0 = _bayeux.newLocalSession("s0");
Assert.assertEquals("L:s0_<disconnected>", session0.toString());
session0.handshake();
Assert.assertNotEquals("L:s0_", session0.toString());
Assert.assertTrue(session0.toString().startsWith("L:s0_"));
final LocalSession session1 = _bayeux.newLocalSession("s1");
session1.handshake();
final LocalSession session2 = _bayeux.newLocalSession("s2");
session2.handshake();
final Queue<String> events = new ConcurrentLinkedQueue<>();
ClientSessionChannel.MessageListener listener = new ClientSessionChannel.MessageListener() {
@Override
public void onMessage(ClientSessionChannel channel, Message message) {
events.add(channel.getSession().getId());
events.add(message.getData().toString());
}
};
session0.getChannel("/foo/bar").subscribe(listener);
session0.getChannel("/foo/bar").subscribe(listener);
session1.getChannel("/foo/bar").subscribe(listener);
session2.getChannel("/foo/bar").subscribe(listener);
Assert.assertEquals(3, _bayeux.getChannel("/foo/bar").getSubscribers().size());
session0.getChannel("/foo/bar").unsubscribe(listener);
Assert.assertEquals(3, _bayeux.getChannel("/foo/bar").getSubscribers().size());
session0.getChannel("/foo/bar").unsubscribe(listener);
Assert.assertEquals(2, _bayeux.getChannel("/foo/bar").getSubscribers().size());
ClientSessionChannel foobar0 = session0.getChannel("/foo/bar");
foobar0.subscribe(listener);
foobar0.subscribe(listener);
ClientSessionChannel foostar0 = session0.getChannel("/foo/*");
foostar0.subscribe(listener);
Assert.assertEquals(3, _bayeux.getChannel("/foo/bar").getSubscribers().size());
Assert.assertEquals(session0, foobar0.getSession());
Assert.assertEquals("/foo/bar", foobar0.getId());
Assert.assertEquals(false, foobar0.isDeepWild());
Assert.assertEquals(false, foobar0.isWild());
Assert.assertEquals(false, foobar0.isMeta());
Assert.assertEquals(false, foobar0.isService());
foobar0.publish("hello");
Assert.assertEquals(session0.getId(), events.poll());
Assert.assertEquals("hello", events.poll());
Assert.assertEquals(session0.getId(), events.poll());
Assert.assertEquals("hello", events.poll());
Assert.assertEquals(session0.getId(), events.poll());
Assert.assertEquals("hello", events.poll());
Assert.assertEquals(session1.getId(), events.poll());
Assert.assertEquals("hello", events.poll());
Assert.assertEquals(session2.getId(), events.poll());
Assert.assertEquals("hello", events.poll());
foostar0.unsubscribe(listener);
session1.batch(new Runnable() {
@Override
public void run() {
ClientSessionChannel foobar1 = session1.getChannel("/foo/bar");
foobar1.publish("part1");
Assert.assertEquals(null, events.poll());
foobar1.publish("part2");
}
});
Assert.assertEquals(session1.getId(), events.poll());
Assert.assertEquals("part1", events.poll());
Assert.assertEquals(session2.getId(), events.poll());
Assert.assertEquals("part1", events.poll());
Assert.assertEquals(session0.getId(), events.poll());
Assert.assertEquals("part1", events.poll());
Assert.assertEquals(session0.getId(), events.poll());
Assert.assertEquals("part1", events.poll());
Assert.assertEquals(session1.getId(), events.poll());
Assert.assertEquals("part2", events.poll());
Assert.assertEquals(session2.getId(), events.poll());
Assert.assertEquals("part2", events.poll());
Assert.assertEquals(session0.getId(), events.poll());
Assert.assertEquals("part2", events.poll());
Assert.assertEquals(session0.getId(), events.poll());
Assert.assertEquals("part2", events.poll());
foobar0.unsubscribe();
Assert.assertEquals(2, _bayeux.getChannel("/foo/bar").getSubscribers().size());
Assert.assertTrue(session0.isConnected());
Assert.assertTrue(session1.isConnected());
Assert.assertTrue(session2.isConnected());
ServerSession ss0 = session0.getServerSession();
ServerSession ss1 = session1.getServerSession();
ServerSession ss2 = session2.getServerSession();
Assert.assertTrue(ss0.isConnected());
Assert.assertTrue(ss1.isConnected());
Assert.assertTrue(ss2.isConnected());
session0.disconnect();
Assert.assertFalse(session0.isConnected());
Assert.assertFalse(ss0.isConnected());
session1.getServerSession().disconnect();
Assert.assertFalse(session1.isConnected());
Assert.assertFalse(ss1.isConnected());
session2.getServerSession().disconnect();
Assert.assertFalse(session2.isConnected());
Assert.assertFalse(ss2.isConnected());
}
class CListener implements BayeuxServer.ChannelListener {
@Override
public void configureChannel(ConfigurableServerChannel channel) {
}
@Override
public void channelAdded(ServerChannel channel) {
_events.add("channelAdded");
_events.add(channel);
}
@Override
public void channelRemoved(String channelId) {
_events.add("channelRemoved");
_events.add(channelId);
}
}
class SessListener implements BayeuxServer.SessionListener {
@Override
public void sessionAdded(ServerSession session, ServerMessage message) {
_events.add("sessionAdded");
_events.add(session);
}
@Override
public void sessionRemoved(ServerSession session, boolean timedout) {
_events.add("sessionRemoved");
_events.add(session);
_events.add(timedout);
}
}
class SubListener implements BayeuxServer.SubscriptionListener {
@Override
public void subscribed(ServerSession session, ServerChannel channel, ServerMessage message) {
_events.add("subscribed");
_events.add(session);
_events.add(channel);
}
@Override
public void unsubscribed(ServerSession session, ServerChannel channel, ServerMessage message) {
_events.add("unsubscribed");
_events.add(session);
_events.add(channel);
}
}
}