/*
* Copyright (c) 2013-2017 Cinchapi Inc.
*
* 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 com.cinchapi.concourse.test;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import javax.annotation.Nullable;
import com.cinchapi.concourse.Concourse;
import org.junit.Rule;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.cinchapi.concourse.plugin.build.PluginBundleGenerator;
import com.cinchapi.concourse.server.ManagedConcourseServer;
import com.cinchapi.concourse.server.ManagedConcourseServer.LogLevel;
import com.cinchapi.concourse.util.ConcourseCodebase;
import com.google.common.base.Strings;
import com.google.common.base.Throwables;
/**
* A {@link ClientServerTest} is one that interacts with a Concourse server via
* the public client API. This base class handles boilerplate logic for creating
* a new server for each test and managing resources.
* <ul>
* <li>Specify the server version or custom installer file to test against using
* the {@link #getServerVersion()} method.</li>
* <li>Specify actions to take before each test using the
* {@link #beforeEachTest()} method.</li>
* <li>Specify actions to take after each test using the
* {@link #afterEachTest()} method.</li>
* </ul>
*
* @author jnelson
*/
public abstract class ClientServerTest {
// Initialization for all tests
static {
System.setProperty("test", "true");
}
/**
* A constant that indicates the latest version should be used in
* {@link #getServerVersion()}.
*/
public final static String LATEST_SNAPSHOT_VERSION = "latest";
/**
* The client allows the subclass to define tests that perform actions
* against the test {@link #server} using the public API.
*/
protected Concourse client = null;
/**
* A new server is created for every test. The subclass can perform
* lifecycle and management operations on the server using this variable and
* may also interact via the {@link #client} API.
*/
protected ManagedConcourseServer server = null;
/**
* This watcher clears previously registered {@link Variables} on startup
* and dumps them in the event of failure.
*/
@Rule
public final TestWatcher __watcher = new TestWatcher() {
@Override
protected void failed(Throwable t, Description description) {
System.err.println("TEST FAILURE in " + description.getMethodName()
+ ": " + t.getMessage());
System.err.println("---");
System.err.println(Variables.dump());
System.err.println("");
System.err.println("Printing relevant server logs...");
server.printLogs(LogLevel.ERROR, LogLevel.WARN, LogLevel.INFO,
LogLevel.DEBUG);
server.printLog("console");
if(PluginTest.class
.isAssignableFrom(ClientServerTest.this.getClass())) {
}
}
@Override
protected void finished(Description description) {
afterEachTest();
client.exit();
server.destroy();
client = null;
server = null;
}
@Override
protected void starting(Description description) {
Variables.clear();
if(Files.exists(Paths.get(getServerVersion()))) { // if
// #getServerVersion
// returns a valid
// path, then
// assume its an
// installer and
// pass the
// appropriate
// File for
// construction
server = ManagedConcourseServer
.manageNewServer(new File(getServerVersion()));
}
else if(getServerVersion()
.equalsIgnoreCase(LATEST_SNAPSHOT_VERSION)) {
ConcourseCodebase codebase = ConcourseCodebase
.cloneFromGithub();
try {
log.info(
"Creating an installer for the latest "
+ "version using the code in {}",
codebase.getPath());
String installer = codebase.buildInstaller();
if(!Strings.isNullOrEmpty(installer)) {
server = ManagedConcourseServer
.manageNewServer(new File(installer));
}
else {
throw new RuntimeException(
"An unknown error occurred when trying to build the installer");
}
}
catch (Exception e) {
throw Throwables.propagate(e);
}
}
else if(installerPath() == null) {
server = ManagedConcourseServer
.manageNewServer(getServerVersion());
}
else {
server = ManagedConcourseServer
.manageNewServer(installerPath());
}
Path pluginBundlePath = null;
if(PluginTest.class
.isAssignableFrom(ClientServerTest.this.getClass())) {
// Turn the current codebase into a plugin bundle and place it
// inside the install directory
log.info("Generating plugin to install in Concourse Server");
pluginBundlePath = PluginBundleGenerator.generateBundleZip();
}
server.start();
if(pluginBundlePath != null) {
server.installPlugin(pluginBundlePath);
}
client = server.connect();
beforeEachTest();
}
};
/**
* This method is provided for the subclass to specify additional behaviour
* to be run after each test is done. The subclass should define such logic
* in this method as opposed to a test watcher.
*/
protected void afterEachTest() {}
/**
* This method is provided for the subclass to specify additional behaviour
* to be run before each test begins. The subclass should define such logic
* in this method as opposed to a test watcher.
*/
protected void beforeEachTest() {}
/**
* This method is provided for the subclass to specify the appropriate
* release version number OR path to an installer file (i.e. an unreleased
* SNAPSHOT version) to test against.
*
* @return the version number
*/
protected abstract String getServerVersion();
/**
* This method is provided for the subclass to specify the path to a custom
* installer (i.e. testing against a SNAPSHOT version of the server). If
* this method returns a null or empty string, the default installer is
* used.
*
* @return the custom installer path
* @deprecated Return the path to the installer in
* {@link #getServerVersion()} instead
*/
@Nullable
@Deprecated
protected File installerPath() {
return null;
}
/**
* A {@link Logger} to print information about the test case.
*/
protected Logger log = LoggerFactory.getLogger(getClass());
}