/* * Copyright 2000-2010 JetBrains s.r.o. * * 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 jetbrains.buildServer.eclipse.agent.testing; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import jetbrains.buildServer.RunBuildException; import jetbrains.buildServer.agent.BuildRunnerContext; import jetbrains.buildServer.agent.runner.ProcessListener; import jetbrains.buildServer.agent.runner.ProgramCommandLine; import jetbrains.buildServer.agent.runner.SimpleProgramCommandLine; import jetbrains.buildServer.eclipse.EclipseConstants; import jetbrains.buildServer.eclipse.agent.EclipseBuilderFactory; import jetbrains.buildServer.eclipse.agent.IBuilder; import jetbrains.buildServer.eclipse.java.BuildDescriptor; import jetbrains.buildServer.eclipse.java.PlatformDescriptor; import jetbrains.buildServer.eclipse.java.PlatformDescriptor.IFeatureDescriptor; import jetbrains.buildServer.runner.JavaRunnerConstants; import jetbrains.buildServer.util.FileUtil; import org.apache.log4j.Logger; import org.jetbrains.annotations.NotNull; public class SWTBotTestingService extends EclipseBuilderFactory { private final static Logger LOG = Logger.getLogger(SWTBotTestingService.class); private File myOutputFolder; private File myWorkspace; private String myTestClassName; private String[] myJavaArguments; @Override public void afterInitialized() throws RunBuildException { final BuildRunnerContext context = getRunnerContext(); final PlatformDescriptor platform = getPlatform(context); LOG.debug(String.format("Eclipse platform exists: %s", platform)); final BuildDescriptor buildDescriptor = getBuildDescriptor(platform, context); LOG.debug(String.format("Created build descriptor: %s", buildDescriptor)); /** * Prepare */ myBuilder = new SWTBotTestRunner(getRunnerContext(), platform, buildDescriptor); LOG.debug(String.format("'%s' created", myBuilder.getName())); myBuilder.init(); } @Override public List getListeners() { return super.getListeners();//TODO: create own } /** * adds test artifacts & tests into target platform see@ * -Dorg.eclipse.equinox.p2.reconciler.dropins.directory=... * * @throws IOException */ protected LinkedList mountTestingBase(final @NotNull PlatformDescriptor platform, final @NotNull BuildDescriptor build, final @NotNull BuildRunnerContext context, final @NotNull LinkedList args) throws IOException { // C:/work/tc-test.eclipse/out/eclipse final File dropins = new File(context.getBuild().getBuildTempDirectory(), String.format("dropins-%s", System.currentTimeMillis())); dropins.mkdirs(); LOG.debug(String.format("Dropins for testing created: '%s'", dropins)); FileUtil.copyDir(build.getOutputFolder(), dropins, true);//run on clean copy: .svn? .cvs? ...? args.add(String.format("-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=%s", dropins.getAbsolutePath())); return args; } protected File getWorkspace() { if (myWorkspace == null) { final String outputParam = getRunnerContext().getRunnerParameters().get(EclipseConstants.SETTINGS_TESTS_WORKSPACE_PATH); if (outputParam == null || outputParam.trim().length() == 0) { //create temporary one myWorkspace = new File(getRunnerContext().getBuild().getBuildTempDirectory(), String.format(".workspace-%s", System.currentTimeMillis())); LOG.debug(String.format("Temporary workspace created: '%s'", myWorkspace)); } else if (new File(outputParam.trim()).isAbsolute()) { myWorkspace = new File(outputParam.trim()); LOG.debug(String.format("Absolute path to the worspace was set: '%s'", myWorkspace)); } else { myWorkspace = new File(getRunnerContext().getWorkingDirectory(), outputParam); LOG.debug(String.format("Relative path to the worspace was set: '%s'", myWorkspace)); } myWorkspace.mkdirs(); } return myWorkspace; } private String getTestClassName() { if (myTestClassName == null) { final String param = getRunnerContext().getRunnerParameters().get(EclipseConstants.SETTINGS_TESTS_CLASS_NAME); if (param != null && param.trim().length() > 0) { myTestClassName = param.trim(); } else { //let's default LOG.debug("Test class is not set. Use default one"); myTestClassName = "org.eclipse.swtbot.eclipse.finder.AllTests";//TODO: currently the class is lost } LOG.debug(String.format("Use test class '%s'", myTestClassName)); } return myTestClassName; } private String[] getJavaArguments() { if (myJavaArguments == null) { final String param = getRunnerContext().getRunnerParameters().get(JavaRunnerConstants.JVM_ARGS_KEY); if (param != null && param.trim().length() > 0) { myJavaArguments = param.split(" "); } else { myJavaArguments = new String[0]; } } return myJavaArguments; } class SWTBotTestRunner implements IBuilder { private final IFeatureDescriptor SWTBOT_HEADLESS_FEATURE_DESCRIPTOR = new IFeatureDescriptor() { public File[] plugins() { return new File[] { new File("org\\.eclipse\\.swtbot\\.eclipse\\.(.*)"), new File("org\\.eclipse\\.swtbot\\.ant\\.optional\\.(.*)"), new File("org\\.hamcrest\\.(.*)"), new File("org\\.junit(.*)\\.(.*)"), new File("org\\.apache\\.log4j") }; } public File[] features() { return new File[] { new File("org\\.eclipse\\.swtbot\\.eclipse\\.test\\.(.*)") }; } }; private final Logger LOG = Logger.getLogger(SWTBotTestRunner.class); private BuildRunnerContext myContext; private PlatformDescriptor myPlatform; private BuildDescriptor myBuild; SWTBotTestRunner(BuildRunnerContext context, PlatformDescriptor platform, BuildDescriptor build) { myContext = context; myPlatform = platform; myBuild = build; } public String getName() { return "SWTBot Test Runner"; } public void init() throws RunBuildException { validate(myPlatform); } public void destroy() { // TODO Auto-generated method stub } private void validate(@NotNull PlatformDescriptor platform) throws RunBuildException { final IFeatureDescriptor feature = platform.findFeature(SWTBOT_HEADLESS_FEATURE_DESCRIPTOR);//TODO!!!!! if (feature == null || feature.features().length == 0) { throw new RunBuildException(String.format("SWRBot is not found on the target platform: '%s'", feature)); } } protected File getTestOutputFolder() { if (myOutputFolder == null) { final String outputParam = myContext.getRunnerParameters().get(EclipseConstants.SETTINGS_TESTS_OUTPUT_PATH); myOutputFolder = new File(myContext.getWorkingDirectory(), outputParam);//TODO: check setting is absolute myOutputFolder.mkdirs(); } return myOutputFolder; } public ProgramCommandLine[] makeCommandLines() throws RunBuildException { try { final SimpleProgramCommandLine deployment = createDeployment(); final SimpleProgramCommandLine testing = createTesting(); //notify TeamCity to watch for a tests output final String smessage = String.format("##teamcity[importData type='%s' path='%s' verbose='true']", "junit", getOutputFile().getAbsolutePath()); myContext.getBuild().getBuildLogger().message(smessage); LOG.debug(String.format("Service Message sent: '%s'", smessage)); return new ProgramCommandLine[] { deployment, testing }; } catch (Exception e) { throw new RunBuildException(e); } } /* $ ECLIPSE_HOME=/path/to/your/application $ TEST_CLASS=com.yourcompany.product.test.AllTessts # see http://github.com/ketan/swtbot/blob/master/org.eclipse.swtbot.eclipse.finder.test/src/org/eclipse/swtbot/eclipse/finder/AllTests.java for an example $ TEST_APPLICATION_ID=com.yourcompany.example.application # the id of the application that needs to be tested $ WORKSPACE=/path/to/your/workspace $ TEST_PRODUCT_ID=com.yourcompany.product # optional, if you're not using a product, please do not add the -product argument in the command below $ TEST_PLUGIN_ID=com.yourcompany.product.test # the id of the plugin containing SWTBot tests $ OS=[macosx | win32 | linux] $ WS=[[cocoa|carbon] | gtk | win32] # for macosx, linux, and windows respectively. $ ARCH=[x86|x86_64] # for 32 bit and 64 bit swt binaries. $ $JAVA_HOME/bin/java \ -Xms256M -Xmx768M -XX:MaxPermSize=512M \ -classpath $ECLIPSE_HOME/plugins/org.eclipse.equinox.launcher_1.0.200.v20090128-1500.jar \ org.eclipse.core.launcher.Main \ -application org.eclipse.swtbot.eclipse.junit4.headless.swtbottestapplication \ #??? -testApplication $TEST_APPLICATION_ID #-product $TEST_PRODUCT_ID \ # optional, only if you're working with a product -data $WORKSPACE \ formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,$ECLIPSE_HOME/$TEST_CLASS.xml \ formatter=org.apache.tools.ant.taskdefs.optional.junit.PlainJUnitResultFormatter \ -testPluginName $TEST_PLUGIN_ID \ -className $TEST_CLASS \ -os $OS -ws $WS -arch $ARCH \ -consoleLog -debug !!!!This will run the test specified by TEST_CLASS and generate the test output in ECLIPSE_HOME/TEST_CLASS.xml. This output can be parsed using junitreport ant task. */ private SimpleProgramCommandLine createTesting() throws IOException { final String java_executable = EclipseBuilderFactory.getJavaExecutable(myContext); final String launcher = myPlatform.getEquinoxLauncherJar().getAbsolutePath(); final String application = getSwtbotApplication(); final String test_class_name = getTestClassName(); final String test_plugin_id = getTestPluginId(); final String workspace = getWorkspace().getAbsolutePath(); final LinkedList args = new LinkedList(); args.addAll(Arrays.asList(getJavaArguments())); mountTestingBase(myPlatform, myBuild, myContext, args);//it must be BEFOR launcher args.add("-jar"); args.add(launcher); args.add("-application"); args.add(application); args.add("-data"); args.add(workspace); args.addAll(Arrays.asList(getFormatters())); args.add("-testPluginName"); args.add(test_plugin_id); args.add("-className"); args.add(test_class_name); args.add("-os"); args.add(myPlatform.getOS()); args.add("-ws"); args.add(myPlatform.getWS()); args.add("-arch"); args.add(myPlatform.getARCH()); // args.add("-consoleLog"); // args.add("-debug"); // // LOG.debug(String.format("Run tests with arguments: '%s %s'", java_executable, args)); return new SimpleProgramCommandLine(myContext, java_executable, args); } private String getTestPluginId() { return myBuild.getTypeId()[0]; } private String[] getFormatters() { return new String[] { String.format("formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,%s", getOutputFile()), "formatter=org.apache.tools.ant.taskdefs.optional.junit.PlainJUnitResultFormatter" }; } private File getOutputFile() { return new File(getTestOutputFolder().getAbsoluteFile(), String.format("%s.xml", getTestClassName())); } private String getSwtbotApplication() { return "org.eclipse.swtbot.eclipse.junit4.headless.swtbottestapplication"; // TODO: junit3? other? maybe UI settings? } private SimpleProgramCommandLine createDeployment() { return new SimpleProgramCommandLine(myContext, "cmd", Arrays.asList(new String[] { "/C", "echo", "TODO: implement deployment" })); } } }