@Test public void withSpecifiedGradleUserHomeDirectoryBySystemProperty() { expectedGradleUserHome = testDir.file("home"); String propName = "gradle.user.home"; String propValue = expectedGradleUserHome.getAbsolutePath(); expectedSystemProperties = toMap(propName, propValue); checkConversion("-D", propName + "=" + propValue); }
@Test public void withSpecifiedProjectDirectory() { expectedProjectDir = testDir.file("project-dir"); checkConversion("-p", expectedProjectDir.getAbsolutePath()); expectedProjectDir = currentDir.file("project-dir"); checkConversion("-p", "project-dir"); }
@Test public void withSpecifiedGradleUserHomeDirectory() { expectedGradleUserHome = testDir.file("home"); checkConversion("-g", expectedGradleUserHome.getAbsolutePath()); expectedGradleUserHome = currentDir.file("home"); checkConversion("-g", "home"); }
@Test public void privilegeCmdLineOptionOverSystemPrefForGradleUserHome() { expectedGradleUserHome = testDir.file("home"); String propName = "gradle.user.home"; String propValue = "home2"; expectedSystemProperties = toMap(propName, propValue); checkConversion( "-D", propName + "=" + propValue, "-g", expectedGradleUserHome.getAbsolutePath()); }
@Test public void withSpecifiedBuildFileName() throws IOException { expectedBuildFile = testDir.file("somename"); expectedProjectDir = expectedBuildFile.getParentFile(); checkConversion("-b", expectedBuildFile.getAbsolutePath()); expectedBuildFile = currentDir.file("somename"); expectedProjectDir = expectedBuildFile.getParentFile(); checkConversion("-b", "somename"); }
@RunWith(JMock.class) public class WorkerProcessIntegrationTest { private final JUnit4Mockery context = new JUnit4Mockery(); private final TestListenerInterface listenerMock = context.mock(TestListenerInterface.class); private final MessagingServices messagingServices = new MessagingServices(getClass().getClassLoader()); private final MessagingServer server = messagingServices.get(MessagingServer.class); @Rule public final TestNameTestDirectoryProvider tmpDir = new TestNameTestDirectoryProvider(); private final ProcessMetaDataProvider metaDataProvider = new DefaultProcessMetaDataProvider( NativeServices.getInstance().get(ProcessEnvironment.class)); private final CacheFactory factory = new DefaultCacheFactory( new DefaultFileLockManager(metaDataProvider, new NoOpFileLockListener())) .create(); private final CacheRepository cacheRepository = new DefaultCacheRepository(tmpDir.getTestDirectory(), null, CacheUsage.ON, factory); private final ModuleRegistry moduleRegistry = new DefaultModuleRegistry(); private final ClassPathRegistry classPathRegistry = new DefaultClassPathRegistry( new DefaultClassPathProvider(moduleRegistry), new WorkerProcessClassPathProvider(cacheRepository, moduleRegistry)); private final DefaultWorkerProcessFactory workerFactory = new DefaultWorkerProcessFactory( LogLevel.INFO, server, classPathRegistry, TestFiles.resolver(tmpDir.getTestDirectory()), new LongIdGenerator()); private final ListenerBroadcast<TestListenerInterface> broadcast = new ListenerBroadcast<TestListenerInterface>(TestListenerInterface.class); private final RemoteExceptionListener exceptionListener = new RemoteExceptionListener(broadcast); @Before public void setUp() { broadcast.add(listenerMock); } @After public void tearDown() { messagingServices.stop(); } @Test public void workerProcessCanSendMessagesToThisProcess() throws Throwable { context.checking( new Expectations() { { Sequence sequence = context.sequence("sequence"); one(listenerMock).send("message 1", 1); inSequence(sequence); one(listenerMock).send("message 2", 2); inSequence(sequence); } }); execute(worker(new RemoteProcess())); } @Test public void thisProcessCanSendEventsToWorkerProcess() throws Throwable { execute( worker(new PingRemoteProcess()) .onServer( new Action<ObjectConnection>() { public void execute(ObjectConnection objectConnection) { TestListenerInterface listener = objectConnection.addOutgoing(TestListenerInterface.class); listener.send("1", 0); listener.send("1", 1); listener.send("1", 2); listener.send("stop", 3); } })); } @Test public void multipleWorkerProcessesCanSendMessagesToThisProcess() throws Throwable { context.checking( new Expectations() { { Sequence process1 = context.sequence("sequence1"); one(listenerMock).send("message 1", 1); inSequence(process1); one(listenerMock).send("message 2", 2); inSequence(process1); Sequence process2 = context.sequence("sequence2"); one(listenerMock).send("other 1", 1); inSequence(process2); one(listenerMock).send("other 2", 2); inSequence(process2); } }); execute(worker(new RemoteProcess()), worker(new OtherRemoteProcess())); } @Test public void handlesWorkerProcessWhichCrashes() throws Throwable { context.checking( new Expectations() { { atMost(1).of(listenerMock).send("message 1", 1); atMost(1).of(listenerMock).send("message 2", 2); } }); execute(worker(new CrashingRemoteProcess()).expectStopFailure()); } @Test public void handlesWorkerActionWhichThrowsException() throws Throwable { execute(worker(new BrokenRemoteProcess()).expectStopFailure()); } @Test public void handlesWorkerActionThatLeavesThreadsRunning() throws Throwable { context.checking( new Expectations() { { one(listenerMock).send("message 1", 1); one(listenerMock).send("message 2", 2); } }); execute(worker(new NoCleanUpRemoteProcess())); } @Test public void handlesWorkerProcessWhichNeverConnects() throws Throwable { execute(worker(new NoConnectRemoteProcess()).expectStartFailure()); } @Test public void handlesWorkerProcessWhenJvmFailsToStart() throws Throwable { execute(worker(Actions.doNothing()).jvmArgs("--broken").expectStartFailure()); } private ChildProcess worker(Action<? super WorkerProcessContext> action) { return new ChildProcess(action); } void execute(ChildProcess... processes) throws Throwable { for (ChildProcess process : processes) { process.start(); } for (ChildProcess process : processes) { process.waitForStop(); } messagingServices.stop(); exceptionListener.rethrow(); } private class ChildProcess { private boolean stopFails; private boolean startFails; private WorkerProcess proc; private Action<? super WorkerProcessContext> action; private List<String> jvmArgs = Collections.emptyList(); private Action<ObjectConnection> serverAction; public ChildProcess(Action<? super WorkerProcessContext> action) { this.action = action; } ChildProcess expectStopFailure() { stopFails = true; return this; } ChildProcess expectStartFailure() { startFails = true; return this; } public void start() { WorkerProcessBuilder builder = workerFactory.create(); builder.applicationClasspath(classPathRegistry.getClassPath("ANT").getAsFiles()); builder.sharedPackages("org.apache.tools.ant"); builder.getJavaCommand().systemProperty("test.system.property", "value"); builder.getJavaCommand().environment("TEST_ENV_VAR", "value"); builder.worker(action); builder.getJavaCommand().jvmArgs(jvmArgs); proc = builder.build(); try { proc.start(); assertFalse(startFails); } catch (ExecException e) { assertTrue(startFails); return; } proc.getConnection().addIncoming(TestListenerInterface.class, exceptionListener); if (serverAction != null) { serverAction.execute(proc.getConnection()); } } public void waitForStop() { if (startFails) { return; } try { proc.waitForStop(); assertFalse("Expected process to fail", stopFails); } catch (ExecException e) { assertTrue("Unexpected failure in worker process", stopFails); } } public ChildProcess onServer(Action<ObjectConnection> action) { this.serverAction = action; return this; } public ChildProcess jvmArgs(String... jvmArgs) { this.jvmArgs = Arrays.asList(jvmArgs); return this; } } public static class RemoteExceptionListener implements Dispatch<MethodInvocation> { Throwable ex; final Dispatch<MethodInvocation> dispatch; public RemoteExceptionListener(Dispatch<MethodInvocation> dispatch) { this.dispatch = dispatch; } public void dispatch(MethodInvocation message) { try { dispatch.dispatch(message); } catch (Throwable e) { ex = e; } } public void rethrow() throws Throwable { if (ex != null) { throw ex; } } } public static class RemoteProcess implements Action<WorkerProcessContext>, Serializable { public void execute(WorkerProcessContext workerProcessContext) { // Check environment assertThat(System.getProperty("test.system.property"), equalTo("value")); assertThat(System.getenv().get("TEST_ENV_VAR"), equalTo("value")); // Check ClassLoaders ClassLoader antClassLoader = Project.class.getClassLoader(); ClassLoader thisClassLoader = getClass().getClassLoader(); ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); assertThat(antClassLoader, not(sameInstance(systemClassLoader))); assertThat(thisClassLoader, not(sameInstance(systemClassLoader))); assertThat(antClassLoader.getParent(), equalTo(systemClassLoader.getParent())); try { assertThat( thisClassLoader.loadClass(Project.class.getName()), sameInstance((Object) Project.class)); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } // Send some messages TestListenerInterface sender = workerProcessContext.getServerConnection().addOutgoing(TestListenerInterface.class); sender.send("message 1", 1); sender.send("message 2", 2); } } public static class OtherRemoteProcess implements Action<WorkerProcessContext>, Serializable { public void execute(WorkerProcessContext workerProcessContext) { TestListenerInterface sender = workerProcessContext.getServerConnection().addOutgoing(TestListenerInterface.class); sender.send("other 1", 1); sender.send("other 2", 2); } } public static class NoCleanUpRemoteProcess implements Action<WorkerProcessContext>, Serializable { public void execute(WorkerProcessContext workerProcessContext) { final Lock lock = new ReentrantLock(); lock.lock(); new Thread( new Runnable() { public void run() { lock.lock(); } }) .start(); TestListenerInterface sender = workerProcessContext.getServerConnection().addOutgoing(TestListenerInterface.class); sender.send("message 1", 1); sender.send("message 2", 2); } } public static class PingRemoteProcess implements Action<WorkerProcessContext>, Serializable, TestListenerInterface { CountDownLatch stopReceived; int count; public void send(String message, int count) { assertEquals(this.count, count); this.count++; if (message.equals("stop")) { assertEquals(4, this.count); stopReceived.countDown(); } } public void execute(WorkerProcessContext workerProcessContext) { stopReceived = new CountDownLatch(1); workerProcessContext.getServerConnection().addIncoming(TestListenerInterface.class, this); try { stopReceived.await(); } catch (InterruptedException e) { throw new RuntimeException(e); } } } public static class CrashingRemoteProcess implements Action<WorkerProcessContext>, Serializable { public void execute(WorkerProcessContext workerProcessContext) { TestListenerInterface sender = workerProcessContext.getServerConnection().addOutgoing(TestListenerInterface.class); sender.send("message 1", 1); sender.send("message 2", 2); // crash Runtime.getRuntime().halt(1); } } public static class BrokenRemoteProcess implements Action<WorkerProcessContext>, Serializable { public void execute(WorkerProcessContext workerProcessContext) { throw new RuntimeException("broken"); } } public static class NoConnectRemoteProcess implements Action<WorkerProcessContext>, Serializable { private void readObject(ObjectInputStream instr) { System.exit(0); } public void execute(WorkerProcessContext workerProcessContext) { throw new UnsupportedOperationException(); } } public interface TestListenerInterface { public void send(String message, int count); } }
public class DefaultCommandLineConverterTest { @Rule public TestNameTestDirectoryProvider testDir = new TestNameTestDirectoryProvider(); private TestFile currentDir = testDir.file("current-dir"); private File expectedBuildFile; private File expectedGradleUserHome = StartParameter.DEFAULT_GRADLE_USER_HOME; private File expectedProjectDir = currentDir; private List<String> expectedTaskNames = toList(); private Set<String> expectedExcludedTasks = toSet(); private boolean buildProjectDependencies = true; private Map<String, String> expectedSystemProperties = new HashMap<String, String>(); private Map<String, String> expectedProjectProperties = new HashMap<String, String>(); private List<File> expectedInitScripts = new ArrayList<File>(); private CacheUsage expectedCacheUsage = CacheUsage.ON; private boolean expectedSearchUpwards = true; private boolean expectedDryRun; private ShowStacktrace expectedShowStackTrace = ShowStacktrace.INTERNAL_EXCEPTIONS; private LogLevel expectedLogLevel = LogLevel.LIFECYCLE; private boolean expectedColorOutput = true; private StartParameter actualStartParameter; private boolean expectedProfile; private File expectedProjectCacheDir; private boolean expectedRefreshDependencies; private boolean expectedRerunTasks; private final DefaultCommandLineConverter commandLineConverter = new DefaultCommandLineConverter(); private boolean expectedContinue; private boolean expectedOffline; private RefreshOptions expectedRefreshOptions = RefreshOptions.NONE; private boolean expectedRecompileScripts; private int expectedParallelExecutorCount; private boolean expectedConfigureOnDemand; @Test public void withoutAnyOptions() { checkConversion(); } private void checkConversion(String... args) { actualStartParameter = new StartParameter(); actualStartParameter.setCurrentDir(currentDir); commandLineConverter.convert(asList(args), actualStartParameter); // We check the params passed to the build factory checkStartParameter(actualStartParameter); } private void checkStartParameter(StartParameter startParameter) { assertEquals(expectedBuildFile, startParameter.getBuildFile()); assertEquals(expectedTaskNames, startParameter.getTaskNames()); assertEquals(buildProjectDependencies, startParameter.isBuildProjectDependencies()); assertEquals( expectedProjectDir.getAbsoluteFile(), startParameter.getCurrentDir().getAbsoluteFile()); assertEquals(expectedCacheUsage, startParameter.getCacheUsage()); assertEquals(expectedSearchUpwards, startParameter.isSearchUpwards()); assertEquals(expectedProjectProperties, startParameter.getProjectProperties()); assertEquals(expectedSystemProperties, startParameter.getSystemPropertiesArgs()); assertEquals( expectedGradleUserHome.getAbsoluteFile(), startParameter.getGradleUserHomeDir().getAbsoluteFile()); assertEquals(expectedLogLevel, startParameter.getLogLevel()); assertEquals(expectedColorOutput, startParameter.isColorOutput()); assertEquals(expectedDryRun, startParameter.isDryRun()); assertEquals(expectedShowStackTrace, startParameter.getShowStacktrace()); assertEquals(expectedExcludedTasks, startParameter.getExcludedTaskNames()); assertEquals(expectedInitScripts, startParameter.getInitScripts()); assertEquals(expectedProfile, startParameter.isProfile()); assertEquals(expectedContinue, startParameter.isContinueOnFailure()); assertEquals(expectedOffline, startParameter.isOffline()); assertEquals(expectedRecompileScripts, startParameter.isRecompileScripts()); assertEquals(expectedRerunTasks, startParameter.isRerunTasks()); assertEquals(expectedRefreshOptions, startParameter.getRefreshOptions()); assertEquals(expectedRefreshDependencies, startParameter.isRefreshDependencies()); assertEquals(expectedProjectCacheDir, startParameter.getProjectCacheDir()); assertEquals(expectedParallelExecutorCount, startParameter.getParallelThreadCount()); assertEquals(expectedConfigureOnDemand, startParameter.isConfigureOnDemand()); } @Test public void withSpecifiedGradleUserHomeDirectory() { expectedGradleUserHome = testDir.file("home"); checkConversion("-g", expectedGradleUserHome.getAbsolutePath()); expectedGradleUserHome = currentDir.file("home"); checkConversion("-g", "home"); } @Test public void withSpecifiedProjectCacheDir() { expectedProjectCacheDir = new File(currentDir, ".foo"); checkConversion("--project-cache-dir", ".foo"); } @Test public void withSpecifiedProjectDirectory() { expectedProjectDir = testDir.file("project-dir"); checkConversion("-p", expectedProjectDir.getAbsolutePath()); expectedProjectDir = currentDir.file("project-dir"); checkConversion("-p", "project-dir"); } @Test public void withSpecifiedBuildFileName() throws IOException { expectedBuildFile = testDir.file("somename"); expectedProjectDir = expectedBuildFile.getParentFile(); checkConversion("-b", expectedBuildFile.getAbsolutePath()); expectedBuildFile = currentDir.file("somename"); expectedProjectDir = expectedBuildFile.getParentFile(); checkConversion("-b", "somename"); } @Test public void withSpecifiedSettingsFileName() throws IOException { File expectedSettingsFile = currentDir.file("somesettings"); expectedProjectDir = expectedSettingsFile.getParentFile(); checkConversion("-c", "somesettings"); assertThat(actualStartParameter.getSettingsFile(), equalTo(expectedSettingsFile)); } @Test public void withInitScripts() { File script1 = currentDir.file("init1.gradle"); expectedInitScripts.add(script1); checkConversion("-Iinit1.gradle"); File script2 = currentDir.file("init2.gradle"); expectedInitScripts.add(script2); checkConversion("-Iinit1.gradle", "-Iinit2.gradle"); } @Test public void withSystemProperties() { final String prop1 = "gradle.prop1"; final String valueProp1 = "value1"; final String prop2 = "gradle.prop2"; final String valueProp2 = "value2"; expectedSystemProperties = toMap(prop1, valueProp1); expectedSystemProperties.put(prop2, valueProp2); checkConversion("-D", prop1 + "=" + valueProp1, "-D", prop2 + "=" + valueProp2); } @Test public void withSpecifiedGradleUserHomeDirectoryBySystemProperty() { expectedGradleUserHome = testDir.file("home"); String propName = "gradle.user.home"; String propValue = expectedGradleUserHome.getAbsolutePath(); expectedSystemProperties = toMap(propName, propValue); checkConversion("-D", propName + "=" + propValue); } @Test public void privilegeCmdLineOptionOverSystemPrefForGradleUserHome() { expectedGradleUserHome = testDir.file("home"); String propName = "gradle.user.home"; String propValue = "home2"; expectedSystemProperties = toMap(propName, propValue); checkConversion( "-D", propName + "=" + propValue, "-g", expectedGradleUserHome.getAbsolutePath()); } @Test public void withStartProperties() { final String prop1 = "prop1"; final String valueProp1 = "value1"; final String prop2 = "prop2"; final String valueProp2 = "value2"; expectedProjectProperties = toMap(prop1, valueProp1); expectedProjectProperties.put(prop2, valueProp2); checkConversion("-P", prop1 + "=" + valueProp1, "-P", prop2 + "=" + valueProp2); } @Test public void withTaskNames() { expectedTaskNames = toList("a", "b"); checkConversion("a", "b"); } @Test public void withRebuildCacheFlagSet() { expectedCacheUsage = CacheUsage.REBUILD; checkConversion("-C", "rebuild"); } @Test public void withCacheOnFlagSet() { checkConversion("-C", "on"); } @Test(expected = CommandLineArgumentException.class) public void withUnknownCacheFlags() { checkConversion("-C", "unknown"); } @Test public void withSearchUpwardsFlagSet() { expectedSearchUpwards = false; checkConversion("-u"); } @Test public void withShowFullStacktrace() { expectedShowStackTrace = ShowStacktrace.ALWAYS_FULL; checkConversion("-S"); } @Test public void withShowStacktrace() { expectedShowStackTrace = ShowStacktrace.ALWAYS; checkConversion("-s"); } @Test public void withRerunTasks() { expectedRerunTasks = true; checkConversion("--rerun-tasks"); } @Test(expected = CommandLineArgumentException.class) public void withShowStacktraceAndShowFullStacktraceShouldThrowCommandLineArgumentEx() { checkConversion("-sf"); } @Test public void withDryRunFlagSet() { expectedDryRun = true; checkConversion("-m"); } @Test public void withExcludeTask() { expectedExcludedTasks.add("excluded"); checkConversion("-x", "excluded"); expectedExcludedTasks.add("excluded2"); checkConversion("-x", "excluded", "-x", "excluded2"); } @Test(expected = CommandLineArgumentException.class) public void withEmbeddedScriptAndConflictingNoSearchUpwardsOption() { checkConversion("-e", "someScript", "-u", "clean"); } @Test(expected = CommandLineArgumentException.class) public void withEmbeddedScriptAndConflictingSpecifyBuildFileOption() { checkConversion("-e", "someScript", "-bsomeFile", "clean"); } @Test(expected = CommandLineArgumentException.class) public void withEmbeddedScriptAndConflictingSpecifySettingsFileOption() { checkConversion("-e", "someScript", "-csomeFile", "clean"); } @Test public void withNoProjectDependencyRebuild() { buildProjectDependencies = false; checkConversion("-a"); } @Test public void withQuietLoggingOptions() { expectedLogLevel = LogLevel.QUIET; checkConversion("-q"); } @Test public void withInfoLoggingOptions() { expectedLogLevel = LogLevel.INFO; checkConversion("-i"); } @Test public void withDebugLoggingOptions() { expectedLogLevel = LogLevel.DEBUG; checkConversion("-d"); } @Test public void withNoColor() { expectedColorOutput = false; checkConversion("--no-color"); } @Test(expected = CommandLineArgumentException.class) public void withLowerPParameterWithoutArgument() { checkConversion("-p"); } @Test(expected = CommandLineArgumentException.class) public void withAParameterWithoutArgument() { checkConversion("-A"); } @Test(expected = CommandLineArgumentException.class) public void withUpperAAndLowerAParameter() { checkConversion("-a", "-Atask1"); } @Test public void withProfile() { expectedProfile = true; checkConversion("--profile"); } @Test public void withContinue() { expectedContinue = true; checkConversion("--continue"); } @Test public void withOffline() { expectedOffline = true; checkConversion("--offline"); checkConversion("-offline"); } @Test public void withRefreshDependencies() { expectedRefreshDependencies = true; expectedRefreshOptions = new RefreshOptions(asList(RefreshOptions.Option.DEPENDENCIES)); checkConversion("--refresh-dependencies"); checkConversion("-refresh-dependencies"); } @Test public void withRecompileScripts() { expectedRecompileScripts = true; checkConversion("--recompile-scripts"); } @Test public void withRefreshDependenciesSet() { expectedRefreshDependencies = true; expectedRefreshOptions = new RefreshOptions(Arrays.asList(RefreshOptions.Option.DEPENDENCIES)); checkConversion("--refresh", "dependencies"); } @Test(expected = CommandLineArgumentException.class) public void withUnknownRefreshOption() { checkConversion("--refresh", "unknown"); } @Test(expected = CommandLineArgumentException.class) public void withUnknownOption() { checkConversion("--unknown"); } @Test public void withTaskAndTaskOption() { expectedTaskNames = toList("someTask", "--some-task-option"); checkConversion("someTask", "--some-task-option"); } @Test public void withParallelExecutor() { expectedParallelExecutorCount = -1; checkConversion("--parallel"); } @Test public void withParallelExecutorThreads() { expectedParallelExecutorCount = 5; checkConversion("--parallel-threads", "5"); } @Test(expected = CommandLineArgumentException.class) public void withInvalidParallelExecutorThreads() { checkConversion("--parallel-threads", "foo"); } @Test public void withConfigureOnDemand() { expectedConfigureOnDemand = true; checkConversion("--configure-on-demand"); } }