/* * Copyright 2015 Nokia Solutions and Networks * Licensed under the Apache License, Version 2.0, * see license.txt file for details. */ package org.robotframework.ide.eclipse.main.plugin.project; import static org.robotframework.ide.eclipse.main.plugin.RedPlugin.newCoreException; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import org.rf.ide.core.dryrun.RobotDryRunEventListener; import org.rf.ide.core.dryrun.RobotDryRunHandler; import org.rf.ide.core.dryrun.RobotDryRunKeywordSourceCollector; import org.rf.ide.core.dryrun.RobotDryRunLibraryImportCollector; import org.rf.ide.core.execution.TestsMode; import org.rf.ide.core.execution.server.AgentConnectionServer; import org.rf.ide.core.execution.server.AgentServerKeepAlive; import org.rf.ide.core.execution.server.AgentServerTestsStarter; import org.rf.ide.core.executor.EnvironmentSearchPaths; import org.rf.ide.core.executor.RobotRuntimeEnvironment; import org.rf.ide.core.executor.RunCommandLineCallBuilder; import org.rf.ide.core.executor.RunCommandLineCallBuilder.RunCommandLine; import org.robotframework.ide.eclipse.main.plugin.launch.AgentConnectionServerJob; import org.robotframework.ide.eclipse.main.plugin.model.RobotProject; /** * @author bembenek */ public abstract class AbstractAutoDiscoverer { private static final AtomicBoolean IS_DRY_RUN_RUNNING = new AtomicBoolean(false); final RobotProject robotProject; final RobotDryRunLibraryImportCollector dryRunLibraryImportCollector; final RobotDryRunKeywordSourceCollector dryRunLKeywordSourceCollector; final RobotDryRunHandler dryRunHandler; final List<IResource> suiteFiles; AbstractAutoDiscoverer(final RobotProject robotProject, final Collection<? extends IResource> suiteFiles) { this.robotProject = robotProject; this.dryRunLibraryImportCollector = new RobotDryRunLibraryImportCollector( robotProject.getStandardLibraries().keySet()); this.dryRunLKeywordSourceCollector = new RobotDryRunKeywordSourceCollector(); this.dryRunHandler = new RobotDryRunHandler(); this.suiteFiles = new ArrayList<IResource>(suiteFiles); } public void start() { final IWorkbench workbench = PlatformUI.getWorkbench(); final IWorkbenchWindow workbenchWindow = workbench.getActiveWorkbenchWindow(); final Shell parent = workbenchWindow != null ? workbenchWindow.getShell() : null; start(parent); } abstract void start(final Shell parent); final boolean lockDryRun() { return IS_DRY_RUN_RUNNING.compareAndSet(false, true); } final void unlockDryRun() { IS_DRY_RUN_RUNNING.set(false); } void startDiscovering(final IProgressMonitor monitor, final IDryRunTargetsCollector dryRunTargetsCollector) throws InvocationTargetException, InterruptedException { final SubMonitor subMonitor = SubMonitor.convert(monitor); subMonitor.subTask("Preparing Robot dry run execution..."); subMonitor.setWorkRemaining(4); try { final LibrariesSourcesCollector librariesSourcesCollector = new LibrariesSourcesCollector(robotProject); librariesSourcesCollector.collectPythonAndJavaLibrariesSources(); subMonitor.worked(1); dryRunTargetsCollector.collectSuiteNamesAndAdditionalProjectsLocations(); subMonitor.worked(1); final int port = AgentConnectionServer.findFreePort(); final RunCommandLine dryRunCommandLine = createDryRunCommandLine(librariesSourcesCollector, dryRunTargetsCollector, port); subMonitor.worked(1); subMonitor.subTask("Executing Robot dry run..."); if (!subMonitor.isCanceled()) { executeDryRun(dryRunCommandLine, port, suiteName -> subMonitor.subTask("Executing Robot dry run on suite: " + suiteName)); } subMonitor.worked(1); } catch (final CoreException | IOException e) { throw new InvocationTargetException(e); } finally { subMonitor.done(); } } private RunCommandLine createDryRunCommandLine(final LibrariesSourcesCollector librariesSourcesCollector, final IDryRunTargetsCollector dryRunTargetsCollector, final int port) throws CoreException, IOException { final RobotRuntimeEnvironment runtimeEnvironment = robotProject.getRuntimeEnvironment(); if (runtimeEnvironment == null) { throw newCoreException( "There is no active runtime environment for project '" + robotProject.getName() + "'"); } final EnvironmentSearchPaths searchPaths = librariesSourcesCollector.getEnvironmentSearchPaths(); return RunCommandLineCallBuilder.forEnvironment(runtimeEnvironment, port) .useArgumentFile(true) .suitesToRun(dryRunTargetsCollector.getSuiteNames()) .addLocationsToPythonPath(searchPaths.getExtendedPythonPaths(runtimeEnvironment.getInterpreter())) .addLocationsToClassPath(searchPaths.getClassPaths()) .enableDryRun() .withProject(getProjectLocationFile()) .withAdditionalProjectsLocations(dryRunTargetsCollector.getAdditionalProjectsLocations()) .build(); } private void executeDryRun(final RunCommandLine dryRunCommandLine, final int port, final Consumer<String> startSuiteHandler) throws InvocationTargetException, InterruptedException { final RobotDryRunEventListener dryRunEventListener = new RobotDryRunEventListener(dryRunLibraryImportCollector, dryRunLKeywordSourceCollector, startSuiteHandler); final AgentServerTestsStarter testsStarter = new AgentServerTestsStarter(TestsMode.RUN); final AgentConnectionServerJob serverJob = AgentConnectionServerJob .setupServerAt(AgentConnectionServer.DEFAULT_CONNECTION_HOST, port) .withConnectionTimeout(AgentConnectionServer.DEFAULT_CONNECTION_TIMEOUT, TimeUnit.SECONDS) .agentEventsListenedBy(testsStarter) .agentEventsListenedBy(dryRunEventListener) .agentEventsListenedBy(new AgentServerKeepAlive()) .start() .waitForServer(); testsStarter.allowClientTestsStart(); dryRunHandler.executeDryRunProcess(dryRunCommandLine, getProjectLocationFile()); serverJob.join(); } private File getProjectLocationFile() { final IPath projectLocation = robotProject.getProject().getLocation(); return projectLocation != null ? projectLocation.toFile() : null; } public interface IDryRunTargetsCollector { void collectSuiteNamesAndAdditionalProjectsLocations(); List<String> getSuiteNames(); List<File> getAdditionalProjectsLocations(); } public static class AutoDiscovererException extends RuntimeException { private static final long serialVersionUID = 1L; public AutoDiscovererException(final String message, final Throwable cause) { super(message, cause); } } }