package io.eguan.rest.container;
/*
* #%L
* Project eguan
* %%
* Copyright (C) 2012 - 2017 Oodrive
* %%
* 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.
* #L%
*/
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import io.eguan.configuration.ConfigValidationException;
import io.eguan.configuration.MetaConfiguration;
import io.eguan.configuration.ValidConfigurationContext.ContextTestHelper;
import io.eguan.rest.container.JettyConfigurationContext;
import io.eguan.rest.container.RestResourceBaseConfigKey;
import io.eguan.rest.container.ServletServer;
import io.eguan.rest.container.ServletServer.State;
import io.eguan.rest.jaxrs.JaxRsConfiguredApplication;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.BindException;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runners.model.InitializationError;
/**
* Test for methods and uses of {@link ServletServer}.
*
* @author oodrive
* @author pwehrle
* @author ebredzinski
*
*/
public final class TestServletServer {
private static MetaConfiguration configuration;
private static ContextTestHelper<JettyConfigurationContext> contextTestHelper;
private static File contextFile;
private static final List<State> startStates = Arrays.asList(new State[] { State.STARTED, State.STARTING });
private static final List<State> stopStates = Arrays.asList(new State[] { State.STOPPED, State.STOPPING });
@BeforeClass
public static void setUpClass() throws InitializationError {
contextTestHelper = new TestJettyConfigurationContext().getTestHelper();
contextTestHelper.setUp();
try {
configuration = MetaConfiguration.newConfiguration(
ContextTestHelper.getPropertiesAsInputStream(contextTestHelper.getConfig()),
JettyConfigurationContext.getInstance());
}
catch (NullPointerException | IllegalArgumentException | IOException | ConfigValidationException e) {
e.printStackTrace();
throw new InitializationError(Arrays.asList(new Throwable[] { e }));
}
contextFile = new File("src/test/resources/testJaxRsContext.xml");
}
@AfterClass
public static void tearDownClass() throws InitializationError {
contextTestHelper.tearDown();
}
/**
* Pre-instantiated server for tests.
*/
private ServletServer testServer;
private JaxRsConfiguredApplication jettyApp;
@Before
public final void setUp() throws InitializationError {
try (FileInputStream contextInput = new FileInputStream(contextFile)) {
jettyApp = new JaxRsConfiguredApplication(contextInput);
}
catch (final IOException e) {
throw new InitializationError(e);
}
testServer = new ServletServer(configuration, jettyApp);
assertNotNull(testServer);
assertFalse(testServer.isInitialized());
assertFalse(testServer.isStarted());
}
@Test
public final void testInitServer() throws IOException {
testServer.init();
assertTrue(testServer.isInitialized());
assertFalse(testServer.isStarted());
// tests repeated initialization
testServer.init();
assertTrue(testServer.isInitialized());
assertFalse(testServer.isStarted());
}
@Test
public final void testInitServerWithoutResourceBase() throws IOException, NullPointerException,
IllegalArgumentException, ConfigValidationException {
final Properties customConfig = contextTestHelper.getConfig();
customConfig.remove(contextTestHelper.getContext().getPropertyKey(RestResourceBaseConfigKey.getInstance()));
final MetaConfiguration localConfiguration = MetaConfiguration.newConfiguration(
ContextTestHelper.getPropertiesAsInputStream(customConfig), JettyConfigurationContext.getInstance());
final ServletServer customServer = new ServletServer(localConfiguration, jettyApp);
customServer.init();
assertTrue(customServer.isInitialized());
assertFalse(customServer.isStarted());
customServer.fini();
assertFalse(customServer.isInitialized());
assertFalse(customServer.isStarted());
}
@Test
public final void testFiniServer() throws IOException {
testServer.init();
assertTrue(testServer.isInitialized());
assertFalse(testServer.isStarted());
testServer.fini();
assertFalse(testServer.isInitialized());
assertFalse(testServer.isStarted());
// tests repeated de-initialization
testServer.fini();
assertFalse(testServer.isInitialized());
assertFalse(testServer.isStarted());
}
@Test(expected = IllegalStateException.class)
public final void testFiniServerFailRunning() throws Exception {
testServer.init();
assertTrue(testServer.isInitialized());
assertFalse(testServer.isStarted());
testServer.start();
assertTrue(testServer.isStarted());
try {
testServer.fini();
}
finally {
testServer.stop();
}
}
@Test
public final void testStartStopServer() throws Exception {
testServer.init();
assertTrue(testServer.isInitialized());
assertFalse(testServer.isStarted());
assertEquals(State.STOPPED, testServer.getExecutionState());
try {
testServer.start();
assertTrue(startStates.contains(testServer.getExecutionState()));
assertTrue(testServer.isStarted());
}
finally {
testServer.stop();
assertTrue(stopStates.contains(testServer.getExecutionState()));
assertFalse(testServer.isStarted());
}
// tests repeated call to stop()
testServer.stop();
assertTrue(stopStates.contains(testServer.getExecutionState()));
assertFalse(testServer.isStarted());
}
@Test
public final void testStopServerNoInit() throws Exception {
assertFalse(testServer.isInitialized());
assertFalse(testServer.isStarted());
testServer.stop();
assertFalse(testServer.isStarted());
}
@Test(expected = IllegalStateException.class)
public final void testStartServerFailInit() throws Exception {
assertFalse(testServer.isInitialized());
assertFalse(testServer.isStarted());
testServer.start();
}
@Test(expected = BindException.class)
public final void testStartServerFailBindException() throws Exception {
testServer.init();
assertTrue(testServer.isInitialized());
assertFalse(testServer.isStarted());
assertEquals(State.STOPPED, testServer.getExecutionState());
final ServletServer failServer = new ServletServer(configuration, jettyApp);
try {
testServer.start();
assertTrue(startStates.contains(testServer.getExecutionState()));
assertTrue(testServer.isStarted());
// starts a second server with the same configuration, doomed to fail
failServer.init();
assertTrue(failServer.isInitialized());
assertFalse(failServer.isStarted());
failServer.start();
}
finally {
assertFalse(failServer.isStarted());
assertEquals(State.FAILED, failServer.getExecutionState());
testServer.stop();
assertTrue(stopStates.contains(testServer.getExecutionState()));
assertFalse(testServer.isStarted());
}
}
@Test
public final void testGetExecutionStateBeforeInit() {
assertFalse(testServer.isInitialized());
assertEquals(State.NOT_INITIALIZED, testServer.getExecutionState());
}
// TODO: generalize and refactor tests to allow arbitrary numbers of threads
@Test
public final void testJoinTwoThreads() {
testServer.init();
assertTrue(testServer.isInitialized());
assertFalse(testServer.isStarted());
assertEquals(State.STOPPED, testServer.getExecutionState());
final ExecutorService executor = Executors.newFixedThreadPool(2);
final CountDownLatch startedLatch = new CountDownLatch(1);
final CountDownLatch joinedLatch = new CountDownLatch(1);
final Future<Boolean> startStopTask = executor.submit(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
testServer.start();
assertTrue(testServer.isStarted());
startedLatch.countDown();
joinedLatch.await(10, TimeUnit.SECONDS);
Thread.sleep(2000);
testServer.stop();
assertFalse(testServer.isStarted());
return true;
}
});
final Future<Boolean> joinTask = executor.submit(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
startedLatch.await(10, TimeUnit.SECONDS);
assertTrue(testServer.isStarted());
joinedLatch.countDown();
testServer.join();
assertFalse(testServer.isStarted());
return true;
}
});
try {
assertTrue(startStopTask.get(20, TimeUnit.SECONDS));
assertTrue(joinTask.get(20, TimeUnit.SECONDS));
}
catch (InterruptedException | ExecutionException | TimeoutException e) {
// all exceptions end up here
throw new AssertionError(e);
}
executor.shutdown();
try {
assertTrue(executor.awaitTermination(20, TimeUnit.SECONDS));
}
catch (final InterruptedException e) {
assertTrue(executor.shutdownNow().isEmpty());
}
}
@Test
public final void testJoinStopped() {
testServer.init();
assertTrue(testServer.isInitialized());
assertFalse(testServer.isStarted());
assertEquals(State.STOPPED, testServer.getExecutionState());
final ExecutorService executor = Executors.newFixedThreadPool(1);
final Future<Boolean> joinTask = executor.submit(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
testServer.join();
return true;
}
});
try {
assertTrue(joinTask.get(10, TimeUnit.SECONDS));
}
catch (InterruptedException | ExecutionException | TimeoutException e) {
// all exceptions end up here
throw new AssertionError(e);
}
}
@Test(expected = IllegalStateException.class)
public final void testJoinFailNotInitialized() throws InterruptedException {
assertFalse(testServer.isInitialized());
testServer.join();
}
}