/*
* Copyright 2013 NGDATA nv
* Copyright 2008 Outerthought bvba and Schaubroeck nv
*
* 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 org.lilyproject.runtime.testfw;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import junit.framework.TestCase;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.lilyproject.runtime.LilyRuntime;
import org.lilyproject.runtime.LilyRuntimeSettings;
import org.lilyproject.runtime.configuration.ConfManager;
import org.lilyproject.runtime.configuration.ConfManagerImpl;
import org.lilyproject.runtime.model.LilyRuntimeModel;
import org.lilyproject.runtime.rapi.Mode;
import org.lilyproject.runtime.repository.ArtifactNotFoundException;
import org.lilyproject.runtime.repository.ArtifactRepository;
import org.lilyproject.runtime.repository.Maven2StyleArtifactRepository;
import org.lilyproject.runtime.repository.RepoArtifactRef;
import org.lilyproject.runtime.repository.ResolvedArtifact;
import org.slf4j.bridge.SLF4JBridgeHandler;
public abstract class AbstractRuntimeTest extends TestCase {
protected ArtifactRepository dummyRepository = new ArtifactRepository() {
public File resolve(RepoArtifactRef artifactRef) throws ArtifactNotFoundException {
return resolve(artifactRef.getGroupId(), artifactRef.getArtifactId(), artifactRef.getClassifier(), artifactRef.getVersion());
}
public File resolve(String groupId, String artifactId, String classifier, String version) throws ArtifactNotFoundException {
throw new ArtifactNotFoundException(groupId, artifactId, classifier, version, Collections.<String>emptyList());
}
public ResolvedArtifact tryResolve(String groupId, String artifactId, String classifier, String version) throws ArtifactNotFoundException {
return new ResolvedArtifact(new File("/dummy"), Collections.<String>emptyList(), false);
}
};
protected static int HTTP_TEST_PORT = 40821;
protected ArtifactRepository localRepository;
// This localRepository property is set by Maven (or its test plugin)
{
String localRepositoryPath = System.getProperty("localRepository");
if (localRepositoryPath == null) {
localRepositoryPath = System.getProperty("user.home") + "/.m2/repository";
}
localRepository = new Maven2StyleArtifactRepository(new File(localRepositoryPath)) {
public ResolvedArtifact tryResolve(String groupId, String artifactId, String classifier, String version) throws ArtifactNotFoundException {
// If the artifact is the one of the project in which this test is running
// then the artifact won't be in the repository yet, so first try the target
// dir (we don't know the name of the current project, so try this for all
// artifacts)
String basedir = System.getProperty("basedir");
File file = new File(basedir + "/target/" + artifactId + "-" + version + ".jar");
if (file.exists()) {
return new ResolvedArtifact(file, Collections.singletonList(file.getAbsolutePath()), true);
}
//else
return super.tryResolve(groupId, artifactId, classifier, version);
}
};
}
protected String projectVersion = System.getProperty("project.version"); // This property should be explictly set via test plugin configuration
protected LilyRuntime runtime;
private Set<File> createdTempDirs = new HashSet<File>();
/**
* Creates a module layout in a temporary directory based on the contents of a package.
* This is a lightweight mechanism to create modules in testcases, to avoid the need
* to e.g. set up a maven project for each test module.
*/
public File createModule(String packageName) throws IOException {
File moduleDir = createTempDir();
String basedir = System.getProperty("basedir"); // This property is set by the Maven surefire:test goal
if (basedir == null) { // we are not running in maven, assume the current working dir is the basedir:
basedir = System.getProperty("user.dir");
}
String packageDir = packageName.replaceAll("\\.", "/");
File resourceDir = new File(basedir + "/src/test/modulesrc/" + packageDir);
copyChildren(resourceDir, moduleDir);
File classesDir = new File(basedir + "/target/test-classes/" + packageDir);
File classesDestDir = new File(moduleDir, packageDir);
copyChildren(classesDir, classesDestDir);
String commonClassesPath = "org/lilyproject/runtime/testmodules/common";
File commonClassesDir = new File(basedir + "/target/test-classes/" + commonClassesPath);
File commonClassesDestDir = new File(moduleDir, commonClassesPath);
copyChildren(commonClassesDir, commonClassesDestDir);
System.out.println("Temporary module created at " + moduleDir.getAbsolutePath());
return moduleDir;
}
public File createTempDir() {
String suffix = (System.currentTimeMillis() % 100000) + "" + (int)(Math.random() * 100000);
File dir;
while (true) {
String dirName = System.getProperty("java.io.tmpdir") + File.separator + ("lilytest_") + suffix;
dir = new File(dirName);
if (dir.exists()) {
System.out.println("Temporary test directory already exists, trying another location. Currenty tried: " + dirName);
continue;
}
boolean dirCreated = dir.mkdirs();
if (!dirCreated) {
throw new RuntimeException("Failed to created temporary test directory at " + dirName);
}
break;
}
dir.mkdirs();
dir.deleteOnExit();
createdTempDirs.add(dir);
return dir;
}
private void copyChildren(File srcDir, File destDir) throws IOException {
if (!srcDir.exists()) {
return;
}
if (!destDir.exists()) {
destDir.mkdirs();
}
File[] files = srcDir.listFiles();
for (File file : files) {
if (file.isDirectory()) {
File childDestDir = new File(destDir, file.getName());
childDestDir.mkdir();
copyChildren(file, childDestDir);
} else {
copyFile(file, new File(destDir, file.getName()));
}
}
}
private void copyFile(File src, File dest) throws IOException {
FileInputStream fis = new FileInputStream(src);
FileOutputStream fos = new FileOutputStream(dest);
byte[] buffer = new byte[8192];
int read;
while ((read = fis.read(buffer)) != -1) {
fos.write(buffer, 0, read);
}
fis.close();
fos.close();
}
/**
* Creates a configuration dir based on a package name.
*/
public File createConfDir(String confName) {
String basedir = System.getProperty("basedir"); // This property is set by the Maven surefire:test goal
if (basedir == null) { // we are not running in maven, assume the current working dir is the basedir:
basedir = System.getProperty("user.dir");
}
return new File(basedir + "/src/test/confs/" + confName);
}
protected LilyRuntimeModel getRuntimeModel() throws Exception {
return null;
}
protected Mode getMode() {
return Mode.getDefault();
}
protected boolean startRuntime() {
return true;
}
protected ConfManager getConfManager() throws Exception {
return new ConfManagerImpl(Collections.<File>emptyList());
}
protected void setUpLogging() {
// Forward JDK logging to SLF4J
java.util.logging.LogManager.getLogManager().reset();
java.util.logging.LogManager.getLogManager().getLogger("").addHandler(new SLF4JBridgeHandler());
java.util.logging.LogManager.getLogManager().getLogger("").setLevel(java.util.logging.Level.ALL);
// By passing these system properties, you can easily enable a certain level
// of debugging for a certain log category
String consoleLoggingLevel = System.getProperty("console-logging");
String consoleLogCategory = System.getProperty("console-log-category");
String appenderName = "abstract-runtime-test-console-appender";
Logger rootLogger = Logger.getRootLogger();
if (rootLogger.getAppender(appenderName) == null) {
ConsoleAppender consoleAppender = new ConsoleAppender();
consoleAppender.setName(appenderName);
consoleAppender.setLayout(new PatternLayout("[%t] %-5p %c - %m%n"));
consoleAppender.activateOptions();
rootLogger.addAppender(consoleAppender);
if (consoleLoggingLevel != null) {
Level level = null;
if (consoleLoggingLevel.equalsIgnoreCase("trace")) {
level = Level.TRACE;
} else if (consoleLoggingLevel.equalsIgnoreCase("debug")) {
level = Level.DEBUG;
} else if (consoleLoggingLevel.equalsIgnoreCase("info")) {
level = Level.INFO;
} else if (consoleLoggingLevel.equalsIgnoreCase("warn")) {
level = Level.WARN;
} else if (consoleLoggingLevel.equalsIgnoreCase("error")) {
level = Level.ERROR;
} else if (consoleLoggingLevel.equalsIgnoreCase("fatal")) {
level = Level.FATAL;
} else {
System.err.println("Unrecognized log level: " + consoleLoggingLevel);
}
if (level != null) {
System.out.println("Setting console output for log level " + level.toString() + " on category " + consoleLogCategory);
Logger logger = consoleLogCategory == null ? Logger.getRootLogger() : Logger.getLogger(consoleLogCategory);
logger.setLevel(level);
if (consoleLogCategory != null) {
rootLogger.setLevel(Level.WARN);
}
}
} else {
rootLogger.setLevel(Level.WARN);
}
}
}
protected void setUp() throws Exception {
setUpLogging();
LilyRuntimeModel model = getRuntimeModel();
if (model != null) {
LilyRuntimeSettings settings = new LilyRuntimeSettings();
settings.setModel(model);
settings.setRepository(localRepository);
settings.setConfManager(getConfManager());
runtime = new LilyRuntime(settings);
runtime.setMode(getMode());
if (startRuntime()) {
runtime.start();
}
}
}
protected void tearDown() throws Exception {
if (runtime != null) {
runtime.stop();
}
deleteTempModuleDirs();
}
private void deleteTempModuleDirs() {
for (File dir : createdTempDirs) {
deleteDir(dir);
}
}
protected void deleteDir(File file) {
if (file.isDirectory()) {
File[] children = file.listFiles();
if (children != null) {
for (File child : file.listFiles()) {
deleteDir(child);
}
}
}
file.delete();
}
}