Java tutorial
/** * 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.rest; import com.sun.jersey.api.container.httpserver.HttpServerFactory; import com.sun.jersey.api.core.ClassNamesResourceConfig; import com.sun.jersey.api.core.PackagesResourceConfig; import com.sun.jersey.api.core.ResourceConfig; import com.sun.net.httpserver.HttpServer; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.opencastproject.util.IoSupport; import org.opencastproject.util.UrlSupport; import org.opencastproject.util.data.Function; import org.opencastproject.util.data.Option; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URL; import java.net.URLConnection; import java.util.Random; import java.util.logging.ConsoleHandler; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; import static org.opencastproject.util.data.Collections.toArray; import static org.opencastproject.util.data.Monadics.mlist; import static org.opencastproject.util.data.Option.some; import static org.opencastproject.util.data.functions.Misc.chuck; /** * 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>. * <h3>Example Usage</h3> * <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 HttpServer hs; private final URL baseUrl; private final Option<? extends ResourceConfig> cfg; /** * 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(URL baseUrl, Option<? extends ResourceConfig> cfg) { this.baseUrl = baseUrl; this.cfg = cfg; // configure jersey logger to get some output in case of an error final Logger jerseyLogger = Logger.getLogger(com.sun.jersey.spi.inject.Errors.class.getName()); jerseyLogger.addHandler(new ConsoleHandler()); jerseyLogger.setLevel(Level.WARNING); } public static RestServiceTestEnv testEnvScanAllPackages(URL baseUrl) { return new RestServiceTestEnv(baseUrl, Option.<ResourceConfig>none()); } public static RestServiceTestEnv testEnvScanPackages(URL baseUrl, Package... servicePkgs) { return new RestServiceTestEnv(baseUrl, some(new PackagesResourceConfig(toArray(String.class, mlist(servicePkgs).map(pkgName).value())))); } public static RestServiceTestEnv testEnvForClasses(URL baseUrl, Class... restServices) { return new RestServiceTestEnv(baseUrl, some(new ClassNamesResourceConfig(restServices))); } public static RestServiceTestEnv testEnvForCustomConfig(String baseUrl, ResourceConfig cfg) { return new RestServiceTestEnv(UrlSupport.url(baseUrl), some(cfg)); } public static RestServiceTestEnv testEnvForCustomConfig(URL baseUrl, ResourceConfig cfg) { return new RestServiceTestEnv(baseUrl, some(cfg)); } /** * Return a localhost base URL with a random port between 8081 and 9000. * The method features a port usage detection to ensure it returns a free port. */ public static URL localhostRandomPort() { for (int tries = 100; tries > 0; tries--) { final URL url = UrlSupport.url("http", "localhost", 8081 + new Random(System.currentTimeMillis()).nextInt(919)); InputStream in = null; try { final URLConnection con = url.openConnection(); con.setConnectTimeout(1000); con.setReadTimeout(1000); con.getInputStream(); } catch (IOException e) { IoSupport.closeQuietly(in); return url; } } throw new RuntimeException("Cannot find free port. Giving up."); } /** Create a URL suitable for rest-assured's post(), get() e.al. methods. */ public String host(String path) { return UrlSupport.url(baseUrl, path).toString(); } /** Return the port the configured server is running on. */ public int getPort() { return baseUrl.getPort(); } /** Return the base URL of the HTTP server. <code>http://host:port</code> public URL getBaseUrl() { return baseUrl; } /** Call in {@link @BeforeClass} annotated method. */ public void setUpServer() { try { // cut of any base pathbasestUrl might have final URI host = new URL(baseUrl.getProtocol(), baseUrl.getHost(), baseUrl.getPort(), "/").toURI(); System.out.println("Start http server at " + host); if (cfg.isSome()) hs = HttpServerFactory.create(host, cfg.get()); else hs = HttpServerFactory.create(host); hs.start(); } catch (Exception e) { chuck(e); } } /** Call in {@link @AfterClass} annotated method. */ public void tearDownServer() { if (hs != null) { System.out.println("Stop http server"); hs.stop(0); } } private static final Function<Package, String> pkgName = new Function<Package, String>() { @Override public String apply(Package pkg) { return pkg.getName(); } }; // Hamcrest matcher public static class RegexMatcher extends BaseMatcher<String> { private final Pattern p; public RegexMatcher(String pattern) { p = Pattern.compile(pattern); } public static RegexMatcher regex(String pattern) { return new RegexMatcher(pattern); } @Override public boolean matches(Object item) { return item != null && p.matcher(item.toString()).matches(); } @Override public void describeTo(Description description) { description.appendText("regex [" + p.pattern() + "]"); } } }