/** Created by frascuchon on 5/11/15. */ @Service public class AlbumsStoreImpl implements AlbumsStore { private ConcurrentMap<String, Album> albums = Maps.newConcurrentMap(); @Override public List<Album> getAll() { return Collections.unmodifiableList(new ArrayList<Album>(albums.values())); } @Override public Album findAlbumById(String albumId) { return (albums.containsKey(albumId)) ? albums.get(albumId) : null; } @Override public void addAlbum(Album entity) throws Exception { if (entity == null || StringUtils.isEmpty(entity.getAlbumId())) { throw new IllegalArgumentException(); } else { albums.putIfAbsent(entity.getAlbumId(), entity); } } @Override public List<Song> findAlbumSongsById(String albumId) { return null; } }
/** Builder of exception mapper statistics. */ static class Builder { private Map<Class<?>, Long> exceptionMapperExecutionCount = Maps.newHashMap(); private long successfulMappings; private long unsuccessfulMappings; private long totalMappings; private ExceptionMapperStatisticsImpl cached; /** * Add mappings. * * @param success True if mappings were successful. * @param count Number of mappings. */ void addMapping(final boolean success, final int count) { cached = null; totalMappings++; if (success) { successfulMappings += count; } else { unsuccessfulMappings += count; } } /** * Add an execution of exception mapper. * * @param mapper Exception mapper. * @param count Number of executions of the {@code mapper}. */ void addExceptionMapperExecution(final Class<?> mapper, final int count) { cached = null; Long cnt = exceptionMapperExecutionCount.get(mapper); cnt = cnt == null ? count : cnt + count; exceptionMapperExecutionCount.put(mapper, cnt); } /** * Build an instance of exception mapper statistics. * * @return New instance of exception mapper statistics. */ public ExceptionMapperStatisticsImpl build() { if (cached == null) { cached = new ExceptionMapperStatisticsImpl( Collections.unmodifiableMap(exceptionMapperExecutionCount), successfulMappings, unsuccessfulMappings, totalMappings); } return cached; } }
@Singleton private static class PersistenceUnitInjectionResolver implements InjectionResolver<PersistenceUnit> { private final Map<String, String> persistenceUnits = Maps.newHashMap(); @Inject private PersistenceUnitInjectionResolver(final ServiceLocator locator) { // Look for persistence units. final ServletConfig servletConfig = locator.getService(ServletConfig.class); for (final Enumeration parameterNames = servletConfig.getInitParameterNames(); parameterNames.hasMoreElements(); ) { final String key = (String) parameterNames.nextElement(); if (key.startsWith(PERSISTENCE_UNIT_PREFIX)) { persistenceUnits.put( key.substring(PERSISTENCE_UNIT_PREFIX.length()), "java:comp/env/" + servletConfig.getInitParameter(key)); } } } @Override public Object resolve(final Injectee injectee, final ServiceHandle<?> root) { if (!injectee.getRequiredType().equals(EntityManagerFactory.class)) { return null; } final PersistenceUnit annotation = injectee.getParent().getAnnotation(PersistenceUnit.class); final String unitName = annotation.unitName(); if (!persistenceUnits.containsKey(unitName)) { throw new ContainerException( LocalizationMessages.PERSISTENCE_UNIT_NOT_CONFIGURED(unitName)); } return Proxy.newProxyInstance( this.getClass().getClassLoader(), new Class[] {EntityManagerFactory.class}, new ThreadLocalNamedInvoker<EntityManagerFactory>(persistenceUnits.get(unitName))); } @Override public boolean isConstructorParameterIndicator() { return false; } @Override public boolean isMethodParameterIndicator() { return false; } }
/** * Build a new instance of {@link ResourceStatisticsImpl}. * * @return New instance of resource statistics. */ ResourceStatisticsImpl build() { final Map<ResourceMethod, ResourceMethodStatistics> resourceMethods = Maps.newHashMap(); for (Map.Entry<ResourceMethod, ResourceMethodStatisticsImpl.Builder> methodEntry : methodsBuilders.entrySet()) { resourceMethods.put(methodEntry.getKey(), methodEntry.getValue().build()); } return new ResourceStatisticsImpl( Collections.unmodifiableMap(resourceMethods), resourceExecutionStatisticsBuilder.build(), requestExecutionStatisticsBuilder.build()); }
private Map<String, Object> getConfigProperties( final Configuration config, final Set<String> propertyNames) { final Map<String, Object> properties = Maps.newHashMap(); for (final String propertyName : propertyNames) { final Object property = config.getProperty(propertyName); if (property != null) { properties.put(propertyName, property); } } return properties; }
private Map<String, Object> getProperties(final boolean forMarshaller) { final Map<String, Object> properties = Maps.newHashMap( forMarshaller ? getGlobalConfig().getMarshallerProperties() : getGlobalConfig().getUnmarshallerProperties()); final ContextResolver<MoxyJsonConfig> contextResolver = providers.getContextResolver(MoxyJsonConfig.class, MediaType.APPLICATION_JSON_TYPE); if (contextResolver != null) { final MoxyJsonConfig jsonConfiguration = contextResolver.getContext(MoxyJsonConfig.class); if (jsonConfiguration != null) { properties.putAll( forMarshaller ? jsonConfiguration.getMarshallerProperties() : jsonConfiguration.getUnmarshallerProperties()); } } return properties; }
@Override public void run() { try { if (log.get() == null) { log.compareAndSet( null, CorpLogFactory.of(co.kuznetsov.commando.monitoring.ErrorReportsOffloadTask.class)); } boolean reportingProblem = false; if (collector.hasReports()) { Map<String, ErrorReport> reports = collector.snapshot(); Map<String, ErrorReport> pushback = Maps.newHashMap(); for (ErrorReport er : reports.values()) { if (offloader.offload(er)) { info("Done uploading report: %s", er); } else { pushback.put(er.getExId(), er); reportingProblem = true; error("Unable to upload report, pushed it back: %s", er); } } collector.pushback(pushback); } else { debug("No error reports to upload"); } DateTime lhb = latestHeartbeat.get(); if (lhb == null || lhb.isBefore(DateTime.now().minus(HEARTBEAT_INTERVAL))) { if (offloader.heartbeat(reportingProblem)) { latestHeartbeat.set(DateTime.now()); } } } catch (Throwable e) { error("Unable to offload reports", e); } }
private List<RuntimeResource.Builder> getRuntimeResources(List<Resource> resources) { Map<String, List<Resource>> regexMap = Maps.newHashMap(); for (Resource resource : resources) { String path = resource.getPath(); String regex = null; if (path != null) { if (path.endsWith("/")) { path = path.substring(0, path.length() - 1); } regex = new PathTemplate(path).getPattern().getRegex(); } List<Resource> listFromMap = regexMap.get(regex); if (listFromMap == null) { listFromMap = Lists.newArrayList(); regexMap.put(regex, listFromMap); } listFromMap.add(resource); } List<RuntimeResource.Builder> runtimeResources = Lists.newArrayList(); for (Map.Entry<String, List<Resource>> entry : regexMap.entrySet()) { final List<Resource> resourcesWithSameRegex = entry.getValue(); List<Resource> childResources = Lists.newArrayList(); for (final Resource res : resourcesWithSameRegex) { childResources.addAll(res.getChildResources()); } List<RuntimeResource.Builder> childRuntimeResources = getRuntimeResources(childResources); runtimeResources.add( new RuntimeResource.Builder( resourcesWithSameRegex, childRuntimeResources, entry.getKey())); } return runtimeResources; }
public class PlayerRepositoryImpl implements PlayerRepository { private static final String resourceName = "/players.csv"; private Map<String, Player> playerById = Maps.newConcurrentMap(); private static Logger logger = LoggerFactory.getLogger(PlayerRepositoryImpl.class); private Player fromLine(String[] line) { Player m = new Player(); m.setName(line[0]); m.setEmail(line[1]); List<String> instruments = Splitter.on(',').splitToList(line[2]); for (String i : instruments) { Instrument instr = Instrument.valueOf(i); if (i != null) m.addPlayedInstrument(instr); } return m; } @Override @LogPerformances(layer = "domain", operation = "find_player_by_id") public Player find(String id) { return playerById.get(id); } @SuppressWarnings("resource") @LogPerformances(layer = "domain", operation = "loadFile") protected void loadFile() { try { URL resource = PlayerRepositoryImpl.class.getResource(resourceName); CSVReader reader = new CSVReader(new FileReader(resource.getFile()), ';'); String[] line; while ((line = reader.readNext()) != null) { logger.info("Loading record '{}'", Joiner.on("//").join(line)); Player m = fromLine(line); playerById.put(m.getId(), m); } } catch (IOException e) { throw new RuntimeException("Unable to read resource;" + resourceName); } } public PlayerRepositoryImpl() { loadFile(); } @Override @LogPerformances(layer = "domain", operation = "find_player_by_instrument") public List<Player> find(Instrument instrument) { List<Player> players = Lists.newArrayList(); for (Map.Entry<String, Player> entry : playerById.entrySet()) { if (entry.getValue().getInstruments().contains(instrument)) players.add(entry.getValue()); } return players; } @Override @LogPerformances(layer = "domain", operation = "find_player_by_instrument_category") public List<Player> find(Category instrumentCategory) { Set<Player> players = Sets.newHashSet(); for (Map.Entry<String, Player> entry : playerById.entrySet()) { for (Instrument inst : entry.getValue().getInstruments()) { if (inst.getCategory().equals(instrumentCategory)) players.add(entry.getValue()); } } return Lists.newArrayList(players); } @Override @LogPerformances(layer = "domain", operation = "find_all_players") public List<Player> list() { return ImmutableList.copyOf(playerById.values()); } }
/** Builder of resource statistics instances. */ static class Builder { private final ExecutionStatisticsImpl.Builder resourceExecutionStatisticsBuilder; private final ExecutionStatisticsImpl.Builder requestExecutionStatisticsBuilder; private final Map<ResourceMethod, ResourceMethodStatisticsImpl.Builder> methodsBuilders = Maps.newHashMap(); private final Map<String, ResourceMethodStatisticsImpl.Builder> stringToMethodsBuilders = Maps.newHashMap(); /** * Create a new builder. * * @param resource Resource for which the instance is created. */ Builder(Resource resource) { this(); for (ResourceMethod method : resource.getResourceMethods()) { getOrCreate(method); } } /** Create a new builder. */ Builder() { this.resourceExecutionStatisticsBuilder = new ExecutionStatisticsImpl.Builder(); this.requestExecutionStatisticsBuilder = new ExecutionStatisticsImpl.Builder(); } /** * Build a new instance of {@link ResourceStatisticsImpl}. * * @return New instance of resource statistics. */ ResourceStatisticsImpl build() { final Map<ResourceMethod, ResourceMethodStatistics> resourceMethods = Maps.newHashMap(); for (Map.Entry<ResourceMethod, ResourceMethodStatisticsImpl.Builder> methodEntry : methodsBuilders.entrySet()) { resourceMethods.put(methodEntry.getKey(), methodEntry.getValue().build()); } return new ResourceStatisticsImpl( Collections.unmodifiableMap(resourceMethods), resourceExecutionStatisticsBuilder.build(), requestExecutionStatisticsBuilder.build()); } /** * Add execution of a resource method in the resource. * * @param resourceMethod Resource method executed. * @param methodStartTime Time of execution of the resource method. * @param methodDuration Time spent on execution of resource method itself. * @param requestStartTime Time when the request matching to the executed resource method has * been received by Jersey. * @param requestDuration Time of whole request processing (from receiving the request until * writing the response). */ void addExecution( ResourceMethod resourceMethod, long methodStartTime, long methodDuration, long requestStartTime, long requestDuration) { resourceExecutionStatisticsBuilder.addExecution(methodStartTime, methodDuration); requestExecutionStatisticsBuilder.addExecution(requestStartTime, requestDuration); final ResourceMethodStatisticsImpl.Builder builder = getOrCreate(resourceMethod); builder.addResourceMethodExecution( methodStartTime, methodDuration, requestStartTime, requestDuration); } /** * Add a resource method to the statistics. * * @param resourceMethod Resource method. */ void addMethod(ResourceMethod resourceMethod) { getOrCreate(resourceMethod); } private ResourceMethodStatisticsImpl.Builder getOrCreate(ResourceMethod resourceMethod) { final String methodUniqueId = MonitoringUtils.getMethodUniqueId(resourceMethod); ResourceMethodStatisticsImpl.Builder methodBuilder = stringToMethodsBuilders.get(methodUniqueId); if (methodBuilder == null) { methodBuilder = new ResourceMethodStatisticsImpl.Builder(resourceMethod); methodsBuilders.put(resourceMethod, methodBuilder); stringToMethodsBuilders.put(methodUniqueId, methodBuilder); } return methodBuilder; } }
/** * Parent class for testing JAX-RS and Jersey-based applications using Jersey test framework. * * <p>At construction this class will obtain a {@link * org.glassfish.jersey.test.spi.TestContainerFactory test container factory} implementation. * * <p>Before each test method in an extending class is run the test container factory is used to * obtain a configured {@link org.glassfish.jersey.test.spi.TestContainer test container}. Then the * {@link TestContainer#start()} method is invoked on the configured test container. After each test * method has run, the {@link TestContainer#stop()} method is invoked on the test container. Stopped * test container generally shouldn't be again started for another test, rather a new test container * should be created. Every test method in the {@code JerseyTest} subclass can invoke the {@link * #client()} to obtain a JAX-RS {@link javax.ws.rs.client.Client}, from which {@link * javax.ws.rs.client.WebTarget} instances can be created to send arbitrary requests. Also, one of * the {@code target} methods ({@link #target()} or {@link #target(String)}) may be invoked to * obtain a JAX-RS {@link javax.ws.rs.client.WebTarget} instances from which requests can be sent to * and responses received from the Web application under test. * * <p>If a test container factory is not explicitly declared using the appropriate constructor (see * {@link #JerseyTest(TestContainerFactory)}) or by overriding the {@link * #getTestContainerFactory()} method, then a default test container factory will be obtained as * follows: * * <ol> * <li>If a system property <tt>{@value * org.glassfish.jersey.test.TestProperties#CONTAINER_FACTORY}</tt> is set and the value is a * fully qualified class name of a class that extends from {@code TestContainerFactory} then * the test container factory used by default will be an instance of that class. A {@link * TestContainerException} will be thrown if the class cannot be loaded or instantiated. * <li>Otherwise, {@code META-INF/services} locations on the class path will be scanned for * implementation providers of {@code TestContainerFactory} SPI. If a single implementation is * found, it will be used. If multiple implementations are found, the default <tt>{@value * org.glassfish.jersey.test.TestProperties#CONTAINER_FACTORY}</tt> implementation will be * selected if present, otherwise the first found implementation will be selected and a * warning message will be logged. * <li>If no {@code TestContainerFactory} has been selected in the steps above, Jersey test * framework will try to instantiate the default test container factory implementation ( * <tt>{@value org.glassfish.jersey.test.TestProperties#DEFAULT_CONTAINER_FACTORY}</tt>) * directly. A {@link TestContainerException} will be thrown if this class cannot be loaded or * instantiated. * </ol> * * <p>The test container is configured by a {@link DeploymentContext} that is either provided by * subclass or automatically created by {@code JerseyTest} based on the provided JAX-RS / Jersey * {@code Application} class or instance to be tested. A {@link TestContainerException} will be * thrown if the configured test container factory cannot support the deployment context type. Two * deployment context are provided: * * <ol> * <li>A basic deployment context, of type {@link DeploymentContext}, compatible with all test * containers that are not based on Servlet deployment model. * <li>A Servlet-based deployment context, of type {@link ServletDeploymentContext}, compatible * with Servlet-based test containers. * </ol> * * @author Paul Sandoz * @author Srinivas Bhimisetty * @author Pavel Bucek (pavel.bucek at oracle.com) * @author Michal Gajdos (michal.gajdos at oracle.com) * @author Marek Potociar (marek.potociar at oracle.com) */ @SuppressWarnings("UnusedDeclaration") public abstract class JerseyTest { private static final Logger LOGGER = Logger.getLogger(JerseyTest.class.getName()); /** * Holds the test container factory class to be used for running the tests by default (if * testContainerFactory has not been set). This static field is initialized in {@link * #getDefaultTestContainerFactory()} method and is reused by any instances of {@code JerseyTest} * that are subsequently run. This is done to optimize the number of TestContainerFactory service * provider look-ups and class loading. */ private static Class<? extends TestContainerFactory> defaultTestContainerFactoryClass; /** Configured deployment context for the tested application. */ private final DeploymentContext context; /** * The test container factory which creates an instance of the test container on which the tests * would be run. */ private TestContainerFactory testContainerFactory; /** The test container on which the tests would be run. */ private TestContainer testContainer; private final AtomicReference<Client> client = new AtomicReference<>(null); /** * JerseyTest property bag that can be used to configure the test behavior. These properties can * be overridden with a system property. */ private final Map<String, String> propertyMap = Maps.newHashMap(); /** * JerseyTest forced property bag that can be used to configure the test behavior. These property * cannot be overridden with a system property. */ private final Map<String, String> forcedPropertyMap = Maps.newHashMap(); private JerseyTestLogHandler logHandler; private final Map<Logger, Level> logLevelMap = Maps.newIdentityHashMap(); /** * Initialize JerseyTest instance. * * <p>This constructor can be used from an extending subclass. * * <p>When this constructor is used, the extending concrete subclass must implement one of the * {@link #configure()} or {@link #configureDeployment()} methods to provide the tested * application configuration and deployment context. */ public JerseyTest() { // Note: this must be the first call in the constructor to allow setting config // properties (especially around logging) in the configure() or configureDeployment() // method overridden in subclass, otherwise the properties set in the subclass would // not be set soon enough this.context = configureDeployment(); this.testContainerFactory = getTestContainerFactory(); } /** * Initialize JerseyTest instance and specify the test container factory to be used by this test. * * <p>This constructor can be used from an extending subclass. * * <p>When this constructor is used, the extending concrete subclass must implement one of the * {@link #configure()} or {@link #configureDeployment()} methods to provide the tested * application configuration and deployment context. * * @param testContainerFactory the test container factory to use for testing. */ public JerseyTest(final TestContainerFactory testContainerFactory) { // Note: this must be the first call in the constructor to allow setting config // properties (especially around logging) in the configure() or configureDeployment() // method overridden in subclass, otherwise the properties set in the subclass would // not be set soon enough this.context = configureDeployment(); this.testContainerFactory = testContainerFactory; } /** * Initialize JerseyTest instance. * * <p>This constructor can be used from an extending subclass. * * <p>When this constructor is used, the extending concrete subclass must implement one of the * {@link #configure()} or {@link #configureDeployment()} methods are ignored. * * <p>Please note that when this constructor is used, recording of startup logs as well as * configuring other {@code JerseyTest} properties and features may not work properly. While using * this constructor should generally be avoided, in certain scenarios it may be necessary to use * this constructor. (E.g. when running parameterized tests in which application is created based * on test parameters passed in by JUnit framework via test constructor - in such case it is not * possible to propagate the necessary information to one of the overridden {@code * JerseyTest.configure...} methods). * * @param jaxrsApplication tested application. */ public JerseyTest(final Application jaxrsApplication) { this.context = DeploymentContext.newInstance(jaxrsApplication); this.testContainerFactory = getTestContainerFactory(); } /** * Return currently used test container to run the tests in. This method can be overridden. * * @return a test container instance or {@code null} if the container is not set. */ /* package */ TestContainer getTestContainer() { return testContainer; } /** * Returns old test container used to run the tests in and set a new one. This method can be * overridden. * * @param testContainer a test container instance or {@code null} it the current test container * should be released. * @return old test container instance. */ /* package */ TestContainer setTestContainer(final TestContainer testContainer) { final TestContainer old = this.testContainer; this.testContainer = testContainer; return old; } private TestContainer createTestContainer(final DeploymentContext context) { return getTestContainerFactory().create(getBaseUri(), context); } /** * Programmatically enable a feature with a given name. Enabling of the feature may be overridden * via a system property. * * @param featureName name of the enabled feature. */ protected final void enable(final String featureName) { // TODO: perhaps we could reuse the resource config for the test properties? propertyMap.put(featureName, Boolean.TRUE.toString()); } /** * Programmatically disable a feature with a given name. Disabling of the feature may be * overridden via a system property. * * @param featureName name of the disabled feature. */ protected final void disable(final String featureName) { propertyMap.put(featureName, Boolean.FALSE.toString()); } /** * Programmatically force-enable a feature with a given name. Force-enabling of the feature cannot * be overridden via a system property. Use with care! * * @param featureName name of the force-enabled feature. */ protected final void forceEnable(final String featureName) { forcedPropertyMap.put(featureName, Boolean.TRUE.toString()); } /** * Programmatically force-disable a feature with a given name. Force-disabling of the feature * cannot be overridden via a system property. Use with care! * * @param featureName name of the force-disabled feature. */ protected final void forceDisable(final String featureName) { forcedPropertyMap.put(featureName, Boolean.FALSE.toString()); } /** * Programmatically set a value of a property with a given name. The property value may be * overridden via a system property. * * @param propertyName name of the property. * @param value property value. */ protected final void set(final String propertyName, final Object value) { set(propertyName, value.toString()); } /** * Programmatically set a value of a property with a given name. The property value may be * overridden via a system property. * * @param propertyName name of the property. * @param value property value. */ protected final void set(final String propertyName, final String value) { propertyMap.put(propertyName, value); } /** * Programmatically force-set a value of a property with a given name. The force-set property * value cannot be overridden via a system property. * * @param propertyName name of the property. * @param value property value. */ protected final void forceSet(final String propertyName, final String value) { forcedPropertyMap.put(propertyName, value); } /** * Check if the Jersey test boolean property (flag) has been set to {@code true}. * * @param propertyName name of the Jersey test boolean property. * @return {@code true} if the test property has been enabled, {@code false} otherwise. */ protected final boolean isEnabled(final String propertyName) { return Boolean.valueOf(getProperty(propertyName)); } private String getProperty(final String propertyName) { if (forcedPropertyMap.containsKey(propertyName)) { return forcedPropertyMap.get(propertyName); } final Properties systemProperties = AccessController.doPrivileged(PropertiesHelper.getSystemProperties()); if (systemProperties.containsKey(propertyName)) { return systemProperties.getProperty(propertyName); } if (propertyMap.containsKey(propertyName)) { return propertyMap.get(propertyName); } return null; } private static String getSystemProperty(final String propertyName) { final Properties systemProperties = AccessController.doPrivileged(PropertiesHelper.getSystemProperties()); return systemProperties.getProperty(propertyName); } /** * Create the tested JAX-RS /Jersey application. * * <p>This method may be overridden by subclasses to provide the configured JAX-RS /Jersey * application to be tested. The method may be also used to configure {@code JerseyTest} instance * properties. * * <p>Unless {@link #configureDeployment()} method is overridden in the subclass, the {@code * configure()} method is invoked by {@code configureDeployment()} to create default deployment * context for the tested application. As such, the method is invoked in the scope of one of the * {@code JerseyTest} constructors. Default implementation of this method throws {@link * UnsupportedOperationException}, so that construction of {@code JerseyTest} instance fails * unless one of the {@code configure()} or {@code configureDeployment()} methods is overridden in * the subclass. * * <p>Note that since the method is invoked from {@code JerseyTest} constructor, the overriding * implementation of the method must not depend on any subclass fields as those will not be * initialized yet when the method is invoked. * * <p>Also note that in case the {@link #JerseyTest(javax.ws.rs.core.Application)} constructor is * used, the method is never invoked. * * @return tested JAX-RS /Jersey application. */ protected Application configure() { throw new UnsupportedOperationException( "The configure method must be implemented by the extending class"); } /** * Create and configure deployment context for the tested application. * * <p>This method may be overridden by subclasses to provide custom test container deployment * context for the tested application. The method may be also used to configure {@code JerseyTest} * instance properties. * * <p>The method is invoked from {@code JerseyTest} constructors to provide deployment context for * the tested application. Default implementation of this method creates {@link * DeploymentContext#newInstance(javax.ws.rs.core.Application) new deployment context} using * JAX-RS application instance obtained by calling the {@link #configure()} method. * * <p>Note that since the method is invoked from {@code JerseyTest} constructor, the overriding * implementation of the method must not depend on any subclass fields as those will not be * initialized yet when the method is invoked. * * <p>Also note that in case the {@link #JerseyTest(javax.ws.rs.core.Application)} constructor is * used, the method is never invoked. * * @return configured deployment context for the tested application. * @since 2.8 */ protected DeploymentContext configureDeployment() { return DeploymentContext.builder(configure()).build(); } /** * Return an instance of {@link TestContainerFactory} class. * * <p>This method is used only once during {@code JerseyTest} instance construction to retrieve * the factory responsible for providing {@link org.glassfish.jersey.test.spi.TestContainer} that * will be used to deploy the tested application. * * <p>A default implementation first searches for the {@code TestContainerFactory} set via {@link * #JerseyTest(org.glassfish.jersey.test.spi.TestContainerFactory) constructor}, then it looks for * a {@code TestContainerFactory} implementation class name set via <tt>{@value * org.glassfish.jersey.test.TestProperties#CONTAINER_FACTORY}</tt> system property with a * fallback to searching for {@code TestContainerFactory} service providers on the class path. At * last, if no {@code TestContainerFactory} has been found, the method attempts to create new * default {@code TestContainerFactory} implementation instance (<tt>{@value * org.glassfish.jersey.test.TestProperties#DEFAULT_CONTAINER_FACTORY}</tt>). * * <p>Alternatively, this method may be overridden to directly provide a custom {@code * TestContainerFactory} instance. Note that since the method is invoked from {@code JerseyTest} * constructor, the overriding implementation of the method must not depend on any subclass fields * as those will not be initialized yet when the method is invoked. * * @return an instance of {@link TestContainerFactory} class. * @throws TestContainerException if the initialization of {@link TestContainerFactory} instance * is not successful. */ protected TestContainerFactory getTestContainerFactory() throws TestContainerException { if (testContainerFactory == null) { testContainerFactory = getDefaultTestContainerFactory(); } return testContainerFactory; } private static synchronized TestContainerFactory getDefaultTestContainerFactory() { if (defaultTestContainerFactoryClass == null) { final String factoryClassName = getSystemProperty(TestProperties.CONTAINER_FACTORY); if (factoryClassName != null) { LOGGER.log( Level.CONFIG, "Loading test container factory '{0}' specified in the '{1}' system property.", new Object[] {factoryClassName, TestProperties.CONTAINER_FACTORY}); defaultTestContainerFactoryClass = loadFactoryClass(factoryClassName); } else { final TestContainerFactory[] factories = ServiceFinder.find(TestContainerFactory.class).toArray(); if (factories.length > 0) { // if there is only one factory instance, just return it if (factories.length == 1) { // cache the class for future reuse defaultTestContainerFactoryClass = factories[0].getClass(); LOGGER.log( Level.CONFIG, "Using the single found TestContainerFactory service provider '{0}'", defaultTestContainerFactoryClass.getName()); return factories[0]; } // if default factory is present, use it. for (final TestContainerFactory tcf : factories) { if (TestProperties.DEFAULT_CONTAINER_FACTORY.equals(tcf.getClass().getName())) { // cache the class for future reuse defaultTestContainerFactoryClass = tcf.getClass(); LOGGER.log( Level.CONFIG, "Found multiple TestContainerFactory service providers, using the default found '{0}'", TestProperties.DEFAULT_CONTAINER_FACTORY); return tcf; } } // default factory is not in the list - log warning and return the first found factory // instance // cache the class for future reuse defaultTestContainerFactoryClass = factories[0].getClass(); LOGGER.log( Level.WARNING, "Found multiple TestContainerFactory service providers, using the first found '{0}'", defaultTestContainerFactoryClass.getName()); return factories[0]; } LOGGER.log( Level.CONFIG, "No TestContainerFactory configured, trying to load and instantiate the default implementation '{0}'", TestProperties.DEFAULT_CONTAINER_FACTORY); defaultTestContainerFactoryClass = loadFactoryClass(TestProperties.DEFAULT_CONTAINER_FACTORY); } } try { return defaultTestContainerFactoryClass.newInstance(); } catch (final Exception ex) { throw new TestContainerException( String.format( "Could not instantiate test container factory '%s'", defaultTestContainerFactoryClass.getName()), ex); } } private static Class<? extends TestContainerFactory> loadFactoryClass( final String factoryClassName) { Class<? extends TestContainerFactory> factoryClass; final Class<Object> loadedClass = AccessController.doPrivileged(ReflectionHelper.classForNamePA(factoryClassName, null)); if (loadedClass == null) { throw new TestContainerException( String.format("Test container factory class '%s' cannot be loaded", factoryClassName)); } try { return loadedClass.asSubclass(TestContainerFactory.class); } catch (final ClassCastException ex) { throw new TestContainerException( String.format( "Class '%s' does not implement TestContainerFactory SPI.", factoryClassName), ex); } } /** * Create a JAX-RS web target whose URI refers to the {@link #getBaseUri() base URI} the tested * JAX-RS / Jersey application is deployed at, plus the path specified in the {@code path} * argument. * * <p>This method is an equivalent of calling <tt>client().target(getBaseUri())</tt>. * * @return the created JAX-RS web target. */ public final WebTarget target() { return client().target(getTestContainer().getBaseUri()); } /** * Create a JAX-RS web target whose URI refers to the {@link #getBaseUri() base URI} the tested * JAX-RS / Jersey application is deployed at, plus the path specified in the {@code path} * argument. * * <p>This method is an equivalent of calling {@code target().path(path)}. * * @param path relative path (from tested application base URI) this web target should point to. * @return the created JAX-RS web target. */ public final WebTarget target(final String path) { return target().path(path); } /** * Get the JAX-RS test client that is {@link * #configureClient(org.glassfish.jersey.client.ClientConfig) pre-configured} for this test. * * @return the configured test client. */ public final Client client() { return getClient(); } /** * Set up the test by creating a test container instance, {@link TestContainer#start() starting} * it and by creating a new {@link #configureClient(org.glassfish.jersey.client.ClientConfig) * pre-configured} test client. The test container is obtained from the {@link * #getTestContainerFactory() test container factory}. * * @throws TestContainerException if the default test container factory cannot be obtained, or the * test application deployment context is not supported by the test container factory. * @throws Exception if an exception is thrown during setting up the test environment. */ @Before public void setUp() throws Exception { if (isLogRecordingEnabled()) { registerLogHandler(); } final TestContainer testContainer = createTestContainer(context); // Set current instance of test container and start it. setTestContainer(testContainer); testContainer.start(); // Create an set new client. setClient(getClient(testContainer.getClientConfig())); } /** * Tear down the test by {@link TestContainer#stop() stopping} the test container obtained from * the {@link #getTestContainerFactory() test container factory} and by {@link * javax.ws.rs.client.Client#close() closing} and discarding the {@link * #configureClient(org.glassfish.jersey.client.ClientConfig) pre-configured} test client that was * {@link #setUp() set up} for the test. * * @throws Exception if an exception is thrown during tearing down the test environment. */ @After public void tearDown() throws Exception { if (isLogRecordingEnabled()) { unregisterLogHandler(); } try { TestContainer oldContainer = setTestContainer(null); if (oldContainer != null) { oldContainer.stop(); } } finally { closeIfNotNull(setClient(null)); } } /** * Get the JAX-RS test client that is {@link * #configureClient(org.glassfish.jersey.client.ClientConfig) pre-configured} for this test. This * method can be overridden. * * @return the configured test client. */ protected Client getClient() { return client.get(); } /** * Get the old JAX-RS test client and set a new one. This method can be overridden. * * @param client the configured test client. * @return old configured test client. */ protected Client setClient(final Client client) { return this.client.getAndSet(client); } /** * Create an instance of test {@link Client} using the client configuration provided by the * configured {@link org.glassfish.jersey.test.spi.TestContainer}. * * <p>If the {@code TestContainer} does not provide any client configuration (passed {@code * clientConfig} is {@code null}), the default implementation of this method first creates an * empty new {@link org.glassfish.jersey.client.ClientConfig} instance. The client configuration * (provided by test container or created) is then passed to {@link * #configureClient(org.glassfish.jersey.client.ClientConfig)} which can be overridden in the * {@code JerseyTest} subclass to provide custom client configuration. At last, new JAX-RS {@link * Client} instance is created based on the resulting client configuration. * * @param clientConfig test client default configuration. May be {@code null}. * @return A Client instance. */ private Client getClient(ClientConfig clientConfig) { if (clientConfig == null) { clientConfig = new ClientConfig(); } // check if logging is required if (isEnabled(TestProperties.LOG_TRAFFIC)) { clientConfig.register(new LoggingFilter(LOGGER, isEnabled(TestProperties.DUMP_ENTITY))); } configureClient(clientConfig); return ClientBuilder.newClient(clientConfig); } /** * Configure the test client. * * <p>The method can be overridden by {@code JerseyTest} subclasses to conveniently configure the * test client instance used by Jersey test framework (either returned from {@link #client()} * method or used to create {@link javax.ws.rs.client.WebTarget} instances returned from one of * the {@code target} methods ({@link #target()} or {@link #target(String)}). * * <p>Prior to every test method run, a new client instance is configured and created using the * client configuration provided by the {@link org.glassfish.jersey.test.spi.TestContainer} as * well as any internal {@code JerseyTest} client configuration settings. * * <p>Before the actual client instance creation, Jersey test framework invokes this method in * order to allow the subclasses to further customize created client instance. * * <p>After each test method is run, the existing client instance is {@link * javax.ws.rs.client.Client#close() closed} and discarded. * * <p>Default implementation of the method is "no-op". * * @param config Jersey test client configuration that can be modified before the client is * created. */ protected void configureClient(final ClientConfig config) { // do nothing } /** * Returns the base URI of the tested application. * * @return the base URI of the tested application. */ // TODO make final protected URI getBaseUri() { final TestContainer container = getTestContainer(); if (container != null) { // called from outside of JerseyTest constructor return container.getBaseUri(); } // called from within JerseyTest constructor return UriBuilder.fromUri("http://localhost/").port(getPort()).build(); } /** * Get the port to be used for test application deployments. * * @return The HTTP port of the URI */ protected final int getPort() { final TestContainer container = getTestContainer(); if (container != null) { // called from outside of JerseyTest constructor return container.getBaseUri().getPort(); } // called from within JerseyTest constructor final String value = getProperty(TestProperties.CONTAINER_PORT); if (value != null) { try { final int i = Integer.parseInt(value); if (i < 0) { throw new NumberFormatException("Value not positive."); } return i; } catch (final NumberFormatException e) { LOGGER.log( Level.CONFIG, "Value of " + TestProperties.CONTAINER_PORT + " property is not a valid positive integer [" + value + "]." + " Reverting to default [" + TestProperties.DEFAULT_CONTAINER_PORT + "].", e); } } return TestProperties.DEFAULT_CONTAINER_PORT; } /** * Get stored {@link LogRecord log records} if enabled by setting {@link * TestProperties#RECORD_LOG_LEVEL} or an empty list. * * @return list of log records or an empty list. */ protected final List<LogRecord> getLoggedRecords() { return getLogHandler().getRecords(); } /** * Get last stored {@link LogRecord log record} if enabled by setting {@link * TestProperties#RECORD_LOG_LEVEL} or {@code null}. * * @return last stored {@link LogRecord log record} or {@code null}. */ protected final LogRecord getLastLoggedRecord() { final List<LogRecord> loggedRecords = getLoggedRecords(); return loggedRecords.isEmpty() ? null : loggedRecords.get(loggedRecords.size() - 1); } /** * Retrieves a list of root loggers. * * @return list of root loggers. */ private Set<Logger> getRootLoggers() { final LogManager logManager = LogManager.getLogManager(); final Enumeration<String> loggerNames = logManager.getLoggerNames(); final Set<Logger> rootLoggers = Sets.newHashSet(); while (loggerNames.hasMoreElements()) { Logger logger = logManager.getLogger(loggerNames.nextElement()); if (logger != null) { while (logger.getParent() != null) { logger = logger.getParent(); } rootLoggers.add(logger); } } return rootLoggers; } /** Register {@link Handler log handler} to the list of root loggers. */ private void registerLogHandler() { final String recordLogLevel = getProperty(TestProperties.RECORD_LOG_LEVEL); final int recordLogLevelInt = Integer.valueOf(recordLogLevel); final Level level = Level.parse(recordLogLevel); logLevelMap.clear(); for (final Logger root : getRootLoggers()) { logLevelMap.put(root, root.getLevel()); if (root.getLevel().intValue() > recordLogLevelInt) { root.setLevel(level); } root.addHandler(getLogHandler()); } } /** Un-register {@link Handler log handler} from the list of root loggers. */ private void unregisterLogHandler() { for (final Logger root : getRootLoggers()) { root.setLevel(logLevelMap.get(root)); root.removeHandler(getLogHandler()); } logHandler = null; } /** * Return {@code true} if log recoding is enabled. * * @return {@code true} if log recoding is enabled, {@code false} otherwise. */ private boolean isLogRecordingEnabled() { return getProperty(TestProperties.RECORD_LOG_LEVEL) != null; } /** * Retrieves {@link Handler log handler} capable of storing {@link LogRecord logged records}. * * @return log handler. */ private JerseyTestLogHandler getLogHandler() { if (logHandler == null) { logHandler = new JerseyTestLogHandler(); } return logHandler; } /** * Returns {@link TestProperties#ASYNC_TIMEOUT_MULTIPLIER} or {@code 1} if the property is not * defined. * * @return Multiplier of the async timeout for async test. */ protected int getAsyncTimeoutMultiplier() { final String property = getProperty(TestProperties.ASYNC_TIMEOUT_MULTIPLIER); Integer multi = 1; if (property != null) { multi = Integer.valueOf(property); if (multi <= 0) { throw new NumberFormatException( "Property " + TestProperties.ASYNC_TIMEOUT_MULTIPLIER + " must be a number greater than 0."); } } return multi; } /** * Utility method that safely closes a response without throwing an exception. * * @param responses responses to close. Each response may be {@code null}. * @since 2.5 */ public final void close(final Response... responses) { if (responses == null || responses.length == 0) { return; } for (final Response response : responses) { if (response == null) { continue; } try { response.close(); } catch (final Throwable t) { LOGGER.log(Level.WARNING, "Error closing a response.", t); } } } /** * Utility method that safely closes a client instance without throwing an exception. * * @param clients client instances to close. Each instance may be {@code null}. * @since 2.5 */ public static void closeIfNotNull(final Client... clients) { if (clients == null || clients.length == 0) { return; } for (final Client c : clients) { if (c == null) { continue; } try { c.close(); } catch (final Throwable t) { LOGGER.log(Level.WARNING, "Error closing a client instance.", t); } } } /** Custom logging handler used to store log records produces during an invocation of a test. */ private class JerseyTestLogHandler extends Handler { private final int logLevel; private final List<LogRecord> records; private JerseyTestLogHandler() { this.logLevel = Integer.parseInt(getProperty(TestProperties.RECORD_LOG_LEVEL)); this.records = new ArrayList<>(); } @Override public void publish(final LogRecord record) { final String loggerName = record.getLoggerName(); if (record.getLevel().intValue() >= logLevel && loggerName.startsWith("org.glassfish.jersey") && !loggerName.startsWith("org.glassfish.jersey.test")) { records.add(record); } } @Override public void flush() {} @Override public void close() throws SecurityException {} public List<LogRecord> getRecords() { return records; } } }
/** * Parent class for all tests written using Jersey test framework. * * @author Paul Sandoz (paul.sandoz at oracle.com) * @author Srinivas Bhimisetty * @author Pavel Bucek (pavel.bucek at oracle.com) * @author Michal Gajdos (michal.gajdos at oracle.com) */ @SuppressWarnings("UnusedDeclaration") public abstract class JerseyTest { private static final Logger LOGGER = Logger.getLogger(JerseyTest.class.getName()); /** Holds the default test container factory class to be used for running the tests. */ private static Class<? extends TestContainerFactory> testContainerFactoryClass; /** * The test container factory which creates an instance of the test container on which the tests * would be run. */ private TestContainerFactory testContainerFactory; /** The test container on which the tests would be run. */ private final TestContainer tc; private final ApplicationHandler application; private final AtomicReference<Client> client = new AtomicReference<Client>(null); /** * JerseyTest property bag that can be used to configure the test behavior. These properties can * be overridden with a system property. */ private final Map<String, String> propertyMap = Maps.newHashMap(); /** * JerseyTest forced property bag that can be used to configure the test behavior. These property * cannot be overridden with a system property. */ private final Map<String, String> forcedPropertyMap = Maps.newHashMap(); private Handler logHandler; private final List<LogRecord> loggedStartupRecords = Lists.newArrayList(); private final List<LogRecord> loggedRuntimeRecords = Lists.newArrayList(); private final Map<Logger, Level> logLevelMap = Maps.newIdentityHashMap(); /** * An extending class must implement the {@link #configure()} method to provide an application * descriptor. * * @throws TestContainerException if the default test container factory cannot be obtained, or the * application descriptor is not supported by the test container factory. */ public JerseyTest() throws TestContainerException { ResourceConfig config = getResourceConfig(configure()); config.register( new ServiceFinderBinder<TestContainerFactory>( TestContainerFactory.class, null, RuntimeType.SERVER)); if (isLogRecordingEnabled()) { registerLogHandler(); } this.application = new ApplicationHandler(config); this.tc = getContainer(application, getTestContainerFactory()); if (isLogRecordingEnabled()) { loggedStartupRecords.addAll(loggedRuntimeRecords); loggedRuntimeRecords.clear(); unregisterLogHandler(); } } /** * Construct a new instance with a test container factory. * * <p>An extending class must implement the {@link #configure()} method to provide an application * descriptor. * * @param testContainerFactory the test container factory to use for testing. * @throws TestContainerException if the application descriptor is not supported by the test * container factory. */ public JerseyTest(TestContainerFactory testContainerFactory) { setTestContainerFactory(testContainerFactory); ResourceConfig config = getResourceConfig(configure()); config.register( new ServiceFinderBinder<TestContainerFactory>( TestContainerFactory.class, null, RuntimeType.SERVER)); if (isLogRecordingEnabled()) { registerLogHandler(); } this.application = new ApplicationHandler(config); this.tc = getContainer(application, testContainerFactory); if (isLogRecordingEnabled()) { loggedStartupRecords.addAll(loggedRuntimeRecords); loggedRuntimeRecords.clear(); unregisterLogHandler(); } } /** * Construct a new instance with an application descriptor that defines how the test container is * configured. * * @param jaxrsApplication an application describing how to configure the test container. * @throws TestContainerException if the default test container factory cannot be obtained, or the * application descriptor is not supported by the test container factory. */ public JerseyTest(Application jaxrsApplication) throws TestContainerException { ResourceConfig config = getResourceConfig(jaxrsApplication); config.register( new ServiceFinderBinder<TestContainerFactory>( TestContainerFactory.class, null, RuntimeType.SERVER)); if (isLogRecordingEnabled()) { registerLogHandler(); } this.application = new ApplicationHandler(config); this.tc = getContainer(application, getTestContainerFactory()); if (isLogRecordingEnabled()) { loggedStartupRecords.addAll(loggedRuntimeRecords); loggedRuntimeRecords.clear(); unregisterLogHandler(); } } /** * Construct a new instance with an {@link Application} class. * * @param jaxrsApplicationClass an application describing how to configure the test container. * @throws TestContainerException if the default test container factory cannot be obtained, or the * application descriptor is not supported by the test container factory. */ public JerseyTest(Class<? extends Application> jaxrsApplicationClass) throws TestContainerException { ResourceConfig config = ResourceConfig.forApplicationClass(jaxrsApplicationClass); config.register( new ServiceFinderBinder<TestContainerFactory>( TestContainerFactory.class, null, RuntimeType.SERVER)); if (isLogRecordingEnabled()) { registerLogHandler(); } this.application = new ApplicationHandler(config); this.tc = getContainer(application, getTestContainerFactory()); if (isLogRecordingEnabled()) { loggedStartupRecords.addAll(loggedRuntimeRecords); loggedRuntimeRecords.clear(); unregisterLogHandler(); } } private ResourceConfig getResourceConfig(Application app) { return ResourceConfig.forApplication(app); } /** * Programmatically enable a feature with a given name. Enabling of the feature may be overridden * via a system property. * * @param featureName name of the enabled feature. */ protected final void enable(String featureName) { // TODO: perhaps we could reuse the resource config for the test properties? propertyMap.put(featureName, Boolean.TRUE.toString()); } /** * Programmatically disable a feature with a given name. Disabling of the feature may be * overridden via a system property. * * @param featureName name of the disabled feature. */ protected final void disable(String featureName) { propertyMap.put(featureName, Boolean.FALSE.toString()); } /** * Programmatically force-enable a feature with a given name. Force-enabling of the feature cannot * be overridden via a system property. Use with care! * * @param featureName name of the force-enabled feature. */ protected final void forceEnable(String featureName) { forcedPropertyMap.put(featureName, Boolean.TRUE.toString()); } /** * Programmatically force-disable a feature with a given name. Force-disabling of the feature * cannot be overridden via a system property. Use with care! * * @param featureName name of the force-disabled feature. */ protected final void forceDisable(String featureName) { forcedPropertyMap.put(featureName, Boolean.FALSE.toString()); } /** * Programmatically set a value of a property with a given name. The property value may be * overridden via a system property. * * @param propertyName name of the property. * @param value property value. */ protected final void set(String propertyName, Object value) { set(propertyName, value.toString()); } /** * Programmatically set a value of a property with a given name. The property value may be * overridden via a system property. * * @param propertyName name of the property. * @param value property value. */ protected final void set(String propertyName, String value) { propertyMap.put(propertyName, value); } /** * Programmatically force-set a value of a property with a given name. The force-set property * value cannot be overridden via a system property. * * @param propertyName name of the property. * @param value property value. */ protected final void forceSet(String propertyName, String value) { forcedPropertyMap.put(propertyName, value); } /** * Check if the Jersey test boolean property (flag) has been set to {@code true}. * * @param propertyName name of the Jersey test boolean property. * @return {@code true} if the test property has been enabled, {@code false} otherwise. */ protected final boolean isEnabled(String propertyName) { return Boolean.valueOf(getProperty(propertyName)); } private String getProperty(String propertyName) { if (forcedPropertyMap.containsKey(propertyName)) { return forcedPropertyMap.get(propertyName); } final Properties systemProperties = AccessController.doPrivileged(PropertiesHelper.getSystemProperties()); if (systemProperties.containsKey(propertyName)) { return systemProperties.getProperty(propertyName); } if (propertyMap.containsKey(propertyName)) { return propertyMap.get(propertyName); } return null; } /** * Return an JAX-RS application that defines how the application in the test container is * configured. * * <p>If a constructor is utilized that does not supply an application descriptor then this method * must be overridden to return an application descriptor, otherwise an {@link * UnsupportedOperationException} exception will be thrown. * * <p>If a constructor is utilized that does supply an application descriptor then this method * does not require to be overridden and will not be invoked. * * @return the application descriptor. */ protected Application configure() { throw new UnsupportedOperationException( "The configure method must be implemented by the extending class"); } /** * Sets the test container factory to to be used for testing. * * @param testContainerFactory the test container factory to to be used for testing. */ protected final void setTestContainerFactory(TestContainerFactory testContainerFactory) { this.testContainerFactory = testContainerFactory; } /** * Returns an instance of {@link TestContainerFactory} class. This instance can be set by a * constructor ({@link #JerseyTest(org.glassfish.jersey.test.spi.TestContainerFactory)}, as an * application {@link Providers Provider} or the {@link TestContainerFactory} class can be set as * a {@value org.glassfish.jersey.test.TestProperties#CONTAINER_FACTORY} property. * * @return an instance of {@link TestContainerFactory} class. * @throws TestContainerException if the initialization of {@link TestContainerFactory} instance * is not successful. */ protected TestContainerFactory getTestContainerFactory() throws TestContainerException { if (testContainerFactory == null) { if (testContainerFactoryClass == null) { final String tcfClassName = getProperty(TestProperties.CONTAINER_FACTORY); if ((tcfClassName == null)) { Set<TestContainerFactory> testContainerFactories = Providers.getProviders(application.getServiceLocator(), TestContainerFactory.class); if (testContainerFactories.size() >= 1) { // if default factory is present, use it. for (TestContainerFactory tcFactory : testContainerFactories) { if (tcFactory.getClass().getName().equals(TestProperties.DEFAULT_CONTAINER_FACTORY)) { LOGGER.log( Level.CONFIG, "Found multiple TestContainerFactory implementations, using default {0}", tcFactory.getClass().getName()); testContainerFactoryClass = tcFactory.getClass(); // is this necessary? return tcFactory; } } if (testContainerFactories.size() != 1) { LOGGER.log( Level.WARNING, "Found multiple TestContainerFactory implementations, using {0}", testContainerFactories.iterator().next().getClass().getName()); } testContainerFactoryClass = testContainerFactories.iterator().next().getClass(); return testContainerFactories.iterator().next(); } } else { final Class<Object> tfClass = AccessController.doPrivileged(ReflectionHelper.classForNamePA(tcfClassName, null)); if (tfClass == null) { throw new TestContainerException( "The default test container factory class name, " + tcfClassName + ", cannot be loaded"); } try { testContainerFactoryClass = tfClass.asSubclass(TestContainerFactory.class); } catch (ClassCastException ex) { throw new TestContainerException( "The default test container factory class, " + tcfClassName + ", is not an instance of TestContainerFactory", ex); } } } try { return testContainerFactoryClass.newInstance(); } catch (Exception ex) { throw new TestContainerException( "The default test container factory, " + testContainerFactoryClass + ", could not be instantiated", ex); } } return testContainerFactory; } /** * Create a web resource whose URI refers to the base URI the Web application is deployed at. * * @return the created web resource */ public WebTarget target() { return client().target(tc.getBaseUri()); } /** * Create a web resource whose URI refers to the base URI the Web application is deployed at plus * the path specified in the argument. * * <p>This method is an equivalent of calling {@code target().path(path)}. * * @param path Relative path (from base URI) this target should point to. * @return the created web resource */ public WebTarget target(String path) { return target().path(path); } /** * Get the client that is configured for this test. * * @return the configured client. */ public Client client() { return client.get(); } /** * Set up the test by invoking {@link TestContainer#start() } on the test container obtained from * the test container factory. * * @throws Exception if an exception is thrown during setting up the test environment. */ @Before public void setUp() throws Exception { if (isLogRecordingEnabled()) { loggedRuntimeRecords.clear(); registerLogHandler(); } tc.start(); Client old = client.getAndSet(getClient(tc, application)); close(old); } /** * Tear down the test by invoking {@link TestContainer#stop() } on the test container obtained * from the test container factory. * * @throws Exception if an exception is thrown during tearing down the test environment. */ @After public void tearDown() throws Exception { if (isLogRecordingEnabled()) { loggedRuntimeRecords.clear(); unregisterLogHandler(); } try { tc.stop(); } finally { Client old = client.getAndSet(null); close(old); } } private TestContainer getContainer(ApplicationHandler application, TestContainerFactory tcf) { if (application == null) { throw new IllegalArgumentException("The application cannot be null"); } return tcf.create(getBaseUri(), application); } /** * Creates an instance of {@link Client}. * * <p>Checks whether TestContainer provides ClientConfig instance and if not, empty new {@link * org.glassfish.jersey.client.ClientConfig} instance will be used to create new client instance. * * <p>This method is called exactly once when JerseyTest is created. * * @param tc instance of {@link TestContainer} * @param applicationHandler instance of {@link ApplicationHandler} * @return A Client instance. */ protected Client getClient(TestContainer tc, ApplicationHandler applicationHandler) { ClientConfig cc = tc.getClientConfig(); if (cc == null) { cc = new ClientConfig(); } // check if logging is required if (isEnabled(TestProperties.LOG_TRAFFIC)) { cc.register(new LoggingFilter(LOGGER, isEnabled(TestProperties.DUMP_ENTITY))); } configureClient(cc); return ClientBuilder.newClient(cc); } /** * Can be overridden by subclasses to conveniently configure the client instance used by the test. * * <p>Default implementation of the method is "no-op". * * @param config Jersey test client configuration that can be modified before the client is * created. */ protected void configureClient(ClientConfig config) { // nothing } /** * Returns the base URI of the application. * * @return The base URI of the application */ protected URI getBaseUri() { return UriBuilder.fromUri("http://localhost/").port(getPort()).build(); } /** * Get the port to be used for test application deployments. * * @return The HTTP port of the URI */ protected final int getPort() { final String value = getProperty(TestProperties.CONTAINER_PORT); if (value != null) { try { final int i = Integer.parseInt(value); if (i <= 0) { throw new NumberFormatException("Value not positive."); } return i; } catch (NumberFormatException e) { LOGGER.log( Level.CONFIG, "Value of " + TestProperties.CONTAINER_PORT + " property is not a valid positive integer [" + value + "]." + " Reverting to default [" + TestProperties.DEFAULT_CONTAINER_PORT + "].", e); } } return TestProperties.DEFAULT_CONTAINER_PORT; } /** * Get stored {@link LogRecord log records} if enabled by setting {@link * TestProperties#RECORD_LOG_LEVEL} or an empty list. * * @return list of log records or an empty list. */ protected List<LogRecord> getLoggedRecords() { final List<LogRecord> logRecords = Lists.newArrayList(); logRecords.addAll(loggedStartupRecords); logRecords.addAll(loggedRuntimeRecords); return logRecords; } /** * Get last stored {@link LogRecord log record} if enabled by setting {@link * TestProperties#RECORD_LOG_LEVEL} or {@code null}. * * @return last stored {@link LogRecord log record} or {@code null}. */ protected LogRecord getLastLoggedRecord() { final List<LogRecord> loggedRecords = getLoggedRecords(); return loggedRecords.isEmpty() ? null : loggedRecords.get(loggedRecords.size() - 1); } /** * Retrieves a list of root loggers. * * @return list of root loggers. */ private Set<Logger> getRootLoggers() { final LogManager logManager = LogManager.getLogManager(); final Enumeration<String> loggerNames = logManager.getLoggerNames(); final Set<Logger> rootLoggers = Sets.newHashSet(); while (loggerNames.hasMoreElements()) { Logger logger = logManager.getLogger(loggerNames.nextElement()); if (logger != null) { while (logger.getParent() != null) { logger = logger.getParent(); } rootLoggers.add(logger); } } return rootLoggers; } /** Register {@link Handler log handler} to the list of root loggers. */ private void registerLogHandler() { final String recordLogLevel = getProperty(TestProperties.RECORD_LOG_LEVEL); final int recordLogLevelInt = Integer.valueOf(recordLogLevel); final Level level = Level.parse(recordLogLevel); logLevelMap.clear(); for (final Logger root : getRootLoggers()) { logLevelMap.put(root, root.getLevel()); if (root.getLevel().intValue() > recordLogLevelInt) { root.setLevel(level); } root.addHandler(getLogHandler()); } } /** Un-register {@link Handler log handler} from the list of root loggers. */ private void unregisterLogHandler() { for (final Logger root : getRootLoggers()) { root.setLevel(logLevelMap.get(root)); root.removeHandler(getLogHandler()); } logHandler = null; } /** * Return {@code true} if log recoding is enabled. * * @return {@code true} if log recoding is enabled, {@code false} otherwise. */ private boolean isLogRecordingEnabled() { return getProperty(TestProperties.RECORD_LOG_LEVEL) != null; } /** * Retrieves {@link Handler log handler} capable of storing {@link LogRecord logged records}. * * @return log handler. */ private Handler getLogHandler() { if (logHandler == null) { final Integer logLevel = Integer.valueOf(getProperty(TestProperties.RECORD_LOG_LEVEL)); logHandler = new Handler() { @Override public void publish(LogRecord record) { final String loggerName = record.getLoggerName(); if (record.getLevel().intValue() >= logLevel && loggerName.startsWith("org.glassfish.jersey") && !loggerName.startsWith("org.glassfish.jersey.test")) { loggedRuntimeRecords.add(record); } } @Override public void flush() {} @Override public void close() throws SecurityException {} }; } return logHandler; } /** * Utility method that safely closes a response without throwing an exception. * * @param responses responses to close. Each response may be {@code null}. * @since 2.5 */ public final void close(final Response... responses) { if (responses == null || responses.length == 0) { return; } for (Response response : responses) { if (response == null) { continue; } try { response.close(); } catch (Throwable t) { LOGGER.log(Level.WARNING, "Error closing a response.", t); } } } /** * Utility method that safely closes a client instance without throwing an exception. * * @param clients client instances to close. Each instance may be {@code null}. * @since 2.5 */ public final void close(final Client... clients) { if (clients == null || clients.length == 0) { return; } for (Client c : clients) { if (c == null) { continue; } try { c.close(); } catch (Throwable t) { LOGGER.log(Level.WARNING, "Error closing a client instance.", t); } } } }