/*
* Copyright (c) 2013-2014 the original author or authors
*
* 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 io.werval.test;
import java.util.LinkedHashMap;
import java.util.Map;
import io.werval.api.Mode;
import io.werval.runtime.ApplicationInstance;
import io.werval.runtime.ConfigInstance;
import io.werval.runtime.ConfigKeys;
import io.werval.runtime.CryptoInstance;
import io.werval.runtime.routes.RoutesConfProvider;
import io.werval.runtime.routes.RoutesProvider;
import io.werval.server.netty.NettyServer;
import io.werval.spi.ApplicationSPI;
import io.werval.spi.server.HttpServer;
import io.werval.test.util.FreePortFinder;
import org.junit.After;
import org.junit.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static io.werval.runtime.ConfigKeys.WERVAL_HTTP_ADDRESS;
import static io.werval.runtime.ConfigKeys.WERVAL_HTTP_PORT;
import static io.werval.test.WervalTestHelper.setupRestAssuredDefaults;
/**
* Base Werval HTTP JUnit Test.
* <p>
* Activate/Passivate Werval Application and HTTP Server in test mode around each JUnit test method.
* <p>
* By default, configuration is loaded from the <code>application.conf</code> file.
* Override the {@link #configurationResourceName()} method to provide your own test configuration.
* <p>
* By default, routes are loaded from the <code>routes.conf</code> file.
* Override the {@link #routesProvider()} method to provide your own test routes.
*
* @navcomposed 1 - 1 ApplicationSPI
* @navcomposed 1 - 1 HttpServer
*/
public class WervalHttpTest
implements WervalHttpTestSupport
{
private static final Logger LOG = LoggerFactory.getLogger( WervalHttpTest.class );
private final String configurationResourceNameOverride;
private final RoutesProvider routesProviderOverride;
private HttpServer httpServer;
private ApplicationSPI app;
public WervalHttpTest()
{
this( null, null );
}
public WervalHttpTest( String configurationResourceNameOverride )
{
this( configurationResourceNameOverride, null );
}
public WervalHttpTest( RoutesProvider routesProviderOverride )
{
this( null, routesProviderOverride );
}
public WervalHttpTest( String configurationResourceNameOverride, RoutesProvider routesProviderOverride )
{
this.configurationResourceNameOverride = configurationResourceNameOverride;
this.routesProviderOverride = routesProviderOverride;
}
/**
* Activate HttpServer.
*/
@Before
public final void beforeEachTestMethod()
{
// Classloader
ClassLoader classLoader = getClass().getClassLoader();
// Configuration
String conf = configurationResourceNameOverride == null
? configurationResourceName()
: configurationResourceNameOverride;
ConfigInstance config = new ConfigInstance( classLoader, conf );
// Configuration overrides
Map<String, Object> overrides = new LinkedHashMap<>( 2 );
String address = config.string( WERVAL_HTTP_ADDRESS );
int freePort = FreePortFinder.findRandomOnInterfaceByName( address );
LOG.info( "Application will forcibly listen on {}:{} for test mode", address, freePort );
overrides.put( WERVAL_HTTP_PORT, freePort );
try
{
config.string( ConfigKeys.APP_SECRET );
}
catch( com.typesafe.config.ConfigException.Missing noAppSecret )
{
String secret = CryptoInstance.newWeaklyRandomSecret256BitsHex();
LOG.info( "Application has no 'app.secret', using a weakly random one for test mode: {}", secret );
overrides.put( "app.secret", secret );
}
config = new ConfigInstance( classLoader, conf, null, null, overrides );
// Routes
RoutesProvider routesProvider = routesProviderOverride == null
? routesProvider()
: routesProviderOverride;
// Application
app = new ApplicationInstance( Mode.TEST, config, classLoader, routesProvider );
// Server
httpServer = new NettyServer( app );
httpServer.activate();
// Final setups
setupRestAssuredDefaults( config );
}
/**
* Passivate HttpServer.
*/
@After
public final void afterEachTestMethod()
{
httpServer.passivate();
httpServer = null;
WervalTestHelper.printErrorsTrace( app.errors() );
app = null;
}
@Override
public final ApplicationSPI application()
{
return app;
}
@Override
public final String httpHost()
{
String httpHost = app.config().string( WERVAL_HTTP_ADDRESS );
if( "127.0.0.1".equals( httpHost ) )
{
httpHost = "localhost";
}
return httpHost;
}
@Override
public final int httpPort()
{
return app.config().intNumber( WERVAL_HTTP_PORT );
}
@Override
public final String baseHttpUrl()
{
return "http://" + httpHost() + ":" + httpPort();
}
/**
* Override to provide your own configuration.
*
* @return Configuration resource name
*/
protected String configurationResourceName()
{
return null;
}
/**
* Override to provide your own routes.
*
* @return Routes provider
*/
protected RoutesProvider routesProvider()
{
return new RoutesConfProvider();
}
}