/** * JBoss, Home of Professional Open Source * Copyright Red Hat, Inc., and individual contributors. * * 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.jboss.aerogear.simplepush.server.netty; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.jboss.aerogear.io.netty.handler.codec.sockjs.SockJsSessionContext; import org.jboss.aerogear.simplepush.protocol.impl.HelloMessageImpl; import org.jboss.aerogear.simplepush.protocol.impl.RegisterMessageImpl; import org.jboss.aerogear.simplepush.server.DefaultSimplePushConfig; import org.jboss.aerogear.simplepush.server.DefaultSimplePushServer; import org.jboss.aerogear.simplepush.server.SimplePushServer; import org.jboss.aerogear.simplepush.server.SimplePushServerConfig; import org.jboss.aerogear.simplepush.server.datastore.DataStore; import org.jboss.aerogear.simplepush.server.datastore.InMemoryDataStore; import org.jboss.aerogear.simplepush.util.UUIDUtil; import org.junit.Before; import org.junit.Test; public class UserAgentReaperTest { @Before public void clearUserAgents() { UserAgents.getInstance().all().clear(); } @Test public void reapActiveUserAgent() throws InterruptedException { final String uaid = UUIDUtil.newUAID(); final SimplePushServer simplePushServer = simplePushServer(); final SockJsSessionContext sessionContext = newSessionContext(true); doRegister(uaid, simplePushServer); addUserAgent(uaid, sessionContext); exceute(new UserAgentReaper(simplePushServer)); verify(sessionContext, never()).close(); assertThat(UserAgents.getInstance().get(uaid), is(notNullValue())); } @Test(expected = IllegalStateException.class) public void reapInactiveUserAgent() throws InterruptedException { final String uaid = UUIDUtil.newUAID(); final SimplePushServer simplePushServer = simplePushServer(); final SockJsSessionContext sessionContext = newSessionContext(false); doRegister(uaid, simplePushServer); addUserAgent(uaid, sessionContext); exceute(new UserAgentReaper(simplePushServer)); verify(sessionContext).close(); UserAgents.getInstance().get(uaid); } private SockJsSessionContext newSessionContext(final boolean active) { final Channel channel = mock(Channel.class); when(channel.isActive()).thenReturn(active); when(channel.isRegistered()).thenReturn(active); final ChannelHandlerContext ctx = mock(ChannelHandlerContext.class); when(ctx.channel()).thenReturn(channel); final SockJsSessionContext sessionContext = mock(SockJsSessionContext.class); when(sessionContext.getContext()).thenReturn(ctx); return sessionContext; } private void doRegister(final String uaid, final SimplePushServer server) { server.handleHandshake(new HelloMessageImpl(uaid.toString())); server.handleRegister(new RegisterMessageImpl(uaid.toString()), uaid); } private void addUserAgent(final String uaid, final SockJsSessionContext sessionContext) throws InterruptedException { UserAgents.getInstance().add(uaid, sessionContext); // When a UserAgent is added a timestap will be added. We need to allow for some time to pass to simulate // an inactive client. Thread.sleep(1000); } private void exceute(final UserAgentReaper reaper) throws InterruptedException { final ExecutorService executorService = Executors.newSingleThreadExecutor(); executorService.execute(reaper); executorService.awaitTermination(500, TimeUnit.MILLISECONDS); } private SimplePushServer simplePushServer() { final SimplePushServerConfig config = DefaultSimplePushConfig.create() .userAgentReaperTimeout(20L) .password("test") .build(); final DataStore store = new InMemoryDataStore(); final byte[] privateKey = DefaultSimplePushServer.generateAndStorePrivateKey(store, config); return new DefaultSimplePushServer(store, config, privateKey); } }