RestServiceTestEnv.java
/*
* Licensed to The Apereo Foundation under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
*
* The Apereo Foundation licenses this file to you under the Educational
* Community 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://opensource.org/licenses/ecl2.txt
*
* 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.opencastproject.test.rest;
import static org.opencastproject.util.data.functions.Misc.chuck;
import org.opencastproject.util.UrlSupport;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.ThreadLocalRandom;
/**
* Helper environment for creating REST service unit tests.
* <p>
* The REST endpoint to test needs a no-arg constructor in order to be created by the framework.
* <p>
* Write REST unit tests using <a href="http://code.google.com/p/rest-assured/">rest assured</a>.
* <h2>Example Usage</h2>
*
* <pre>
* import static com.jayway.restassured.RestAssured.*;
* import static com.jayway.restassured.matcher.RestAssuredMatchers.*;
* import static org.hamcrest.Matchers.*;
* import static org.opencastproject.rest.RestServiceTestEnv.*
*
* public class RestEndpointTest {
* // create a local environment running on some random port
* // use rt.host("/path/to/service") to wrap all URL creations for HTTP request methods
* private static final RestServiceTestEnv rt = testEnvScanAllPackages(localhostRandomPort());
*
* \@BeforeClass public static void oneTimeSetUp() {
* env.setUpServer();
* }
*
* \@AfterClass public static void oneTimeTearDown() {
* env.tearDownServer();
* }
* }
* </pre>
*
* Add the following dependencies to your pom
*
* <pre>
* <dependency>
* <groupId>com.jayway.restassured</groupId>
* <artifactId>rest-assured</artifactId>
* <version>1.7.2</version>
* <scope>test</scope>
* </dependency>
* <dependency>
* <groupId>org.apache.httpcomponents</groupId>
* <artifactId>httpcore</artifactId>
* <version>4.2.4</version>
* <scope>test</scope>
* </dependency>
* </pre>
*/
public final class RestServiceTestEnv {
private Server server;
private URL baseUrl = null;
private final ResourceConfig cfg;
private static final Logger logger = LoggerFactory.getLogger(RestServiceTestEnv.class);
/**
* Create an environment for <code>baseUrl</code>. The base URL should be the URL where the service to test is
* mounted, e.g. http://localhost:8090/test
*/
private RestServiceTestEnv(ResourceConfig cfg) {
this.cfg = cfg;
}
public static RestServiceTestEnv testEnvForClasses(Class<?>... restServices) {
return new RestServiceTestEnv(new ResourceConfig(restServices));
}
/** Create a URL suitable for rest-assured's post(), get() e.al. methods. */
public String host(String path) {
if (baseUrl == null) {
throw new RuntimeException("Server not yet started");
}
return UrlSupport.url(baseUrl, path).toString();
}
/**
* Return the base URL of the HTTP server. <code>http://host:port</code> public URL getBaseUrl() { return baseUrl; }
*
* Call in @BeforeClass annotated method.
*/
public void setUpServer() {
int port = -1;
int maxRetries = 100;
try {
ServletContainer servletContainer = new ServletContainer(cfg);
ServletHolder jerseyServlet = new ServletHolder(servletContainer);
for (int tries = maxRetries; tries > 0; tries--) {
try {
port = 3000 + tries + ThreadLocalRandom.current().nextInt(62000);
logger.info("Starting http server at port {}", port);
server = new Server(port);
ServletContextHandler context = new ServletContextHandler(server, "/");
context.addServlet(jerseyServlet, "/*");
server.start();
baseUrl = UrlSupport.url("http", "127.0.0.1", port);
return;
} catch (IOException e) {
logger.error("Couldn't bind server to port {}. Retrying with new port...", port, e);
// Rethrow exception after last try
if (tries == 1) {
logger.error("Couldn't start server after {} tries.", maxRetries);
throw e;
}
Thread.sleep(100);
}
}
} catch (Exception e) {
logger.error("Unexpected Exception occurred while setting up http server");
chuck(e);
}
}
/** Call in @AfterClass annotated method. */
public void tearDownServer() {
if (server != null) {
logger.info("Stop http server");
try {
server.stop();
} catch (Exception e) {
logger.warn("Stop http server - failed {}", e.getMessage());
}
}
}
}