org.etlunit.BasicRuntimeSupport Maven / Gradle / Ivy
package org.etlunit;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.codehaus.jackson.JsonNode;
import org.etlunit.feature.Feature;
import org.etlunit.feature.RuntimeOption;
import org.etlunit.io.ApacheProcessExecutor;
import org.etlunit.io.FileBuilder;
import org.etlunit.json.validator.ClasspathSchemaResolver;
import org.etlunit.json.validator.JsonSchemaValidationException;
import org.etlunit.json.validator.JsonValidator;
import org.etlunit.parser.ETLTestValueObject;
import org.etlunit.util.Hex;
import org.etlunit.util.Incomplete;
import org.etlunit.util.NeedsTest;
import org.etlunit.util.StringUtils;
import javax.inject.Inject;
import javax.inject.Named;
import java.io.*;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.security.MessageDigest;
import java.util.*;
public class BasicRuntimeSupport implements RuntimeSupport
{
private final File root;
private final File tempDir;
private final File resourceDir;
private final File referenceDir;
private final File configDir;
private final File generatedSourcesDir;
private final File reportRootDir;
private Log applicationLog;
private Log userLog;
private ProcessExecutor processExecutor;
private final File srcRoot;
private final String projectName;
private final String projectVersion;
private final String projectUser;
private final File vendorBinaryDir;
private final String projectUid;
private final List featureList;
private final Map runtimeOptions = new HashMap();
public BasicRuntimeSupport()
{
this(getSystemTempDir());
}
public BasicRuntimeSupport(File proot)
{
featureList = Collections.EMPTY_LIST;
try
{
this.root = proot.getCanonicalFile();
}
catch (IOException e)
{
throw new RuntimeException(e);
}
this.tempDir = new File(root, "temp");
tempDir.mkdirs();
this.reportRootDir = new File(root, "reports");
reportRootDir.mkdirs();
vendorBinaryDir = tempDir;
this.resourceDir = new File(root, "resource");
resourceDir.mkdirs();
this.referenceDir = new File(root, "reference");
referenceDir.mkdirs();
configDir = new File(resourceDir, "config");
configDir.mkdirs();
generatedSourcesDir = new File(root, "build");
generatedSourcesDir.mkdirs();
projectName = "proj";
projectVersion = "1_0";
projectUser = "builduser";
// use the apache commons exec implementation by default
installProcessExecutor(new ApacheCommonsExecutor());
srcRoot = new File(this.root, "src");
projectUid = readProjectUid(System.getProperty("project.uid")).toLowerCase();
}
/*
public BasicRuntimeSupport(File root, File src, File temp, File rsrc, File cfg) {
this.root = root;
this.temp = temp;
this.srcRoot = src;
resourceDir = rsrc;
configDir = cfg;
// use the apache commons exec implementation by default
installProcessExecutor(new ApacheCommonsExecutor());
}
*/
public BasicRuntimeSupport(Configuration configuration, ETLTestVM vm)
{
featureList = vm.getFeatures();
// validate against the schema
JsonNode configJson = configuration.getRoot().getJsonNode();
try
{
JsonValidator vlad = new JsonValidator("org/etlunit/Configuration.jsonSchema", new ClasspathSchemaResolver(this));
vlad.validate(configJson);
}
catch (JsonSchemaValidationException e)
{
throw new RuntimeException("Configuration schema does not validate", e);
}
// configuration is valid - proceed
projectName = StringUtils.sanitize(configuration.query("project-name").getValueAsString(), '_').toLowerCase();
projectVersion = StringUtils.sanitize(configuration.query("project-version").getValueAsString(), '_').toLowerCase();
projectUser = StringUtils.sanitize(configuration.query("project-user").getValueAsString(), '_').toLowerCase();
try
{
root = new File(configuration.query("project-root-directory").getValueAsString()).getCanonicalFile();
srcRoot = new File(configuration.query("test-sources-directory").getValueAsString()).getCanonicalFile();
configDir = new File(configuration.query("configuration-directory").getValueAsString()).getCanonicalFile();
generatedSourcesDir =
new File(configuration.query("generated-source-directory").getValueAsString()).getCanonicalFile();
resourceDir = new File(configuration.query("resource-directory").getValueAsString()).getCanonicalFile();
referenceDir = new File(configuration.query("reference-directory").getValueAsString()).getCanonicalFile();
tempDir = new File(configuration.query("temp-directory").getValueAsString()).getCanonicalFile();
reportRootDir = new File(configuration.query("reports-directory").getValueAsString()).getCanonicalFile();
vendorBinaryDir = new File(configuration.query("vendor-binary-directory").getValueAsString()).getCanonicalFile();
}
catch (IOException e)
{
throw new IllegalArgumentException(e);
}
if (!tempDir.exists())
{
tempDir.mkdirs();
}
if (!vendorBinaryDir.exists())
{
vendorBinaryDir.mkdirs();
}
installProcessExecutor(new ApacheCommonsExecutor());
ETLTestValueObject query = configuration.query("project-uid");
projectUid = readProjectUid(query != null ? query.getValueAsString() : null);
ETLTestValueObject optionsNode = configuration.query("options");
Gson gson = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DASHES)
.create();
if (optionsNode != null)
{
Map map = optionsNode.getValueAsMap();
for (Map.Entry featureEntry : map.entrySet())
{
// at this level read the actual properties
String featureNasme = featureEntry.getKey();
ETLTestValueObject featureObject = featureEntry.getValue();
Map featureMap = featureObject.getValueAsMap();
for (Map.Entry optionEntry : featureMap.entrySet())
{
// at this level read the actual properties
String optionName = optionEntry.getKey();
ETLTestValueObject optionObject = optionEntry.getValue();
String json = optionObject.getJsonNode().toString();
RuntimeOption runtimeOption = gson.fromJson(json, RuntimeOption.class);
runtimeOption.setName(featureNasme + "." + optionName);
runtimeOptions.put(runtimeOption.getName(), runtimeOption);
}
}
}
}
private String readProjectUid(String uid)
{
if (uid != null)
{
return uid.toLowerCase();
}
try
{
StringBuffer
buffer =
new StringBuffer(root.getAbsolutePath()).append("|")
.append(projectName)
.append("|")
.append(projectVersion)
.append("|");
InetAddress inet = InetAddress.getLocalHost();
if (!inet.isLoopbackAddress())
{
NetworkInterface ni = NetworkInterface.getByInetAddress(inet);
String mac = Hex.hexEncode(ni.getHardwareAddress());
buffer.append(mac);
}
else
{
buffer.append(inet.getCanonicalHostName());
}
byte[] bytesOfMessage = buffer.toString().getBytes("UTF-8");
MessageDigest md = MessageDigest.getInstance("MD5");
String thedigest = Hex.hexEncode(md.digest(bytesOfMessage));
return thedigest.toLowerCase();
}
catch (Exception e)
{
throw new RuntimeException("Error reading local host information", e);
}
}
@Inject
public void setApplicationLogger(@Named("applicationLog") Log log)
{
this.applicationLog = log;
}
@Inject
public void setUserLogger(@Named("userLog") Log log)
{
this.userLog = log;
}
public static File getSystemTempDir()
{
return new File(System.getProperty("java.io.tmpdir"));
}
@Override
public File getTempDirectory()
{
return tempDir;
}
@Override
public File createTempFile(String name)
{
return new File(getTempDirectory(), name);
}
@Override
public File getGeneratedSourceDirectory(String feature)
{
return new FileBuilder(generatedSourcesDir).subdir(feature).mkdirs().file();
}
@Override
public File createGeneratedSourceFile(String feature, String name)
{
return new File(getGeneratedSourceDirectory(feature), name);
}
@Override
public File getFeatureSourceDirectory(String feature)
{
return new FileBuilder(resourceDir).subdir(feature).mkdirs().file();
}
@Override
public File getSourceDirectory()
{
return srcRoot;
}
@Override
public File getTestSourceDirectory()
{
return getTestSourceDirectory(null);
}
@Override
public File getTestSourceDirectory(String _package)
{
FileBuilder fb = new FileBuilder(getSourceDirectory());
if (_package != null)
{
fb = fb.subdir(_package);
}
return fb.file();
}
@Override
public File getReportDirectory(String type)
{
return new FileBuilder(reportRootDir).subdir(type + "-reports").mkdirs().file();
}
@Override
public String getProjectName()
{
return projectName;
}
@Override
public String getProjectVersion()
{
return projectVersion;
}
@Override
public String getProjectUser()
{
return projectUser;
}
@Override
public String getProjectUID()
{
return projectUid;
}
@Override
public File getFeatureConfigurationDirectory(String feature)
{
return new FileBuilder(configDir).subdir(feature).mkdirs().file();
}
@Override
public File getSourceDirectory(String package_)
{
if (package_ == null)
{
return getSourceDirectory();
}
return new FileBuilder(getSourceDirectory()).subdir(package_.replace('.', File.separatorChar)).mkdirs().file();
}
@Override
public ProcessExecutor getProcessExecutor()
{
return processExecutor;
}
@Override
public File createSourceFile(String feature, String name)
{
return new File(getSourceDirectory(feature), name);
}
@Override
public File getReferenceDirectory(String path_)
{
return new FileBuilder(referenceDir).subdir(path_).mkdirs().file();
}
@Override
public File getReferenceFile(String path_, String name)
{
return new File(getReferenceDirectory(path_), name);
}
@Incomplete
@NeedsTest
@Override
public void installProcessExecutor(ProcessExecutor od)
{
processExecutor = od;
}
@Incomplete
@NeedsTest
public ProcessFacade execute(final ProcessDescription pd) throws IOException
{
applicationLog.info("Executing process: " + pd.debugString());
File fi = pd.getOutputFile();
if (fi != null)
{
applicationLog.info("Logging process output to file: " + fi.getAbsolutePath());
}
if (processExecutor != null)
{
return processExecutor.execute(pd);
}
ProcessBuilder pb = new ProcessBuilder(pd.getCommand());
if (pd.hasArguments())
{
pb = pb.command(pd.getArguments());
}
pb.environment().putAll(pd.getEnvironment());
final Process proc = pb.start();
return new ProcessFacade()
{
@Override
public ProcessDescription getDescriptor()
{
return pd;
}
public Process getProcess()
{
return proc;
}
@Override
public void waitForCompletion()
{
try
{
proc.waitFor();
}
catch (InterruptedException e)
{
throw new IllegalStateException("Process interrupted");
}
}
@Override
public int getCompletionCode()
{
return proc.exitValue();
}
@Override
public void kill()
{
proc.destroy();
}
@Override
public void waitForStreams()
{
//these are always available
}
@Override
public Writer getWriter()
{
return new BufferedWriter(new OutputStreamWriter(getOutputStream()));
}
@Override
public BufferedReader getReader()
{
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public BufferedReader getErrorReader()
{
return new BufferedReader(new InputStreamReader(getErrorStream()));
}
@Override
public StringBuffer getInputBuffered() throws IOException
{
return buffer(getReader());
}
@Override
public StringBuffer getErrorBuffered() throws IOException
{
return buffer(getErrorReader());
}
private StringBuffer buffer(BufferedReader errorReader) throws IOException
{
StringBuffer stb = new StringBuffer();
String line = null;
int lineC = 0;
while ((line = errorReader.readLine()) != null)
{
if (lineC != 0)
{
stb.append('\n');
}
lineC++;
stb.append(line);
}
return stb;
}
@Override
public OutputStream getOutputStream()
{
return proc.getOutputStream();
}
@Override
public InputStream getInputStream()
{
return proc.getInputStream();
}
@Override
public InputStream getErrorStream()
{
return proc.getErrorStream();
}
};
}
@Override
public RuntimeOption getRuntimeOption(String qualifiedName)
{
return runtimeOptions.get(qualifiedName);
}
@Override
public List getRuntimeOptions(String featureName)
{
List options = new ArrayList();
for (Map.Entry entry : runtimeOptions.entrySet())
{
String key = entry.getKey();
RuntimeOption value = entry.getValue();
if (featureName == null || key.startsWith(featureName + "."))
{
options.add(value);
}
}
return options;
}
@Override
public List getRuntimeOptions()
{
return getRuntimeOptions(null);
}
private void getPackages(File root, final String prefix, final List packages, final PackageValidator validator)
{
root.listFiles(new FileFilter()
{
public boolean accept(File pathname)
{
if (pathname.isDirectory() && !pathname.getName().equals(".svn") && (validator == null
|| validator.packageNameValid(pathname.getName())))
{
String pack = (prefix != null ? (prefix + ".") : "") + pathname.getName();
packages.add(pack);
getPackages(pathname, pack, packages, validator);
}
return false;
}
});
}
@Override
public List getPackages(File root)
{
final List packages = new ArrayList();
// add a reference to the default package
packages.add(null);
getPackages(root, null, packages, null);
return packages;
}
@Override
public List getReferencePackages(String path)
{
File referenceDirectory = getReferenceDirectory(path);
return getPackages(referenceDirectory);
}
interface PackageValidator
{
boolean packageNameValid(String name);
}
@Override
public List getTestPackages()
{
final List packages = new ArrayList();
// add a reference to the default package
packages.add(null);
getPackages(getTestSourceDirectory(), null, packages, new TestPackageValidator());
return packages;
}
private class TestPackageValidator implements PackageValidator
{
private final Map nameMap = new HashMap();
TestPackageValidator()
{
for (Feature feature : featureList)
{
for (String dirName : feature.getTestSupportFolderNames())
{
nameMap.put(dirName, dirName);
}
}
}
@Override
public boolean packageNameValid(String name)
{
return !nameMap.containsKey(name);
}
}
}
/*This work is done here to more readily test apache commons exe
*/
@Incomplete
class ApacheCommonsExecutor implements ProcessExecutor
{
private final ApacheProcessExecutor apacheProcessExecutor = new ApacheProcessExecutor();
@Incomplete
@Override
public ProcessFacade execute(final ProcessDescription pd)
{
return apacheProcessExecutor.execute(pd);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy