/** * Verifies that a client timeout will be detected by a Nailgun NGInputStream reading from a * blocking heartbeat stream. */ @Test(expected = InterruptedException.class) public void whenClientTimeoutDetectedThenMainThreadIsInterrupted() throws InterruptedException, IOException { final long timeoutMillis = 100; final long intervalMillis = timeoutMillis * 2; // Interval > timeout to trigger disconnection. final ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "exclusive_execution", tmp); workspace.setUp(); // Build an NGContext connected to an NGInputStream reading from a stream that will timeout. Thread.currentThread().setName("Test"); try (TestContext context = new TestContext( ImmutableMap.copyOf(System.getenv()), TestContext.createHeartBeatStream(intervalMillis), timeoutMillis)) { final Thread commandThread = Thread.currentThread(); context.addClientListener( new NGClientListener() { @Override public void clientDisconnected() throws InterruptedException { commandThread.interrupt(); } }); Thread.sleep(1000); fail("Should have been interrupted."); } }
/** * This verifies that a client disconnection will be detected by a Nailgun NGInputStream reading * from an empty heartbeat stream and that the generated InterruptedException will interrupt * command execution causing it to fail. */ @Test public void whenClientDisconnectionDetectedThenTestIsInterrupted() throws InterruptedException, IOException { // Sub process interruption not supported on Windows. assumeTrue(Platform.detect() != Platform.WINDOWS); final long timeoutMillis = 2000; // Stream timeout > test timeout. final long disconnectMillis = 100; // Disconnect before test timeout. final ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "exclusive_execution", tmp); workspace.setUp(); // Start with an input stream that sends heartbeats at a regular rate. final DelegatingInputStream inputStream = new DelegatingInputStream(TestContext.createHeartBeatStream(timeoutMillis / 10)); // Build an NGContext connected to an NGInputStream reading from stream that will timeout. try (TestContext context = new TestContext(ImmutableMap.copyOf(System.getenv()), inputStream, timeoutMillis)) { BuckEventListener listener = new BuckEventListener() { @Subscribe @SuppressWarnings("unused") public void onEvent(TestRunEvent.Started event) { // When tests start running, make the heartbeat stream simulate a disconnection. inputStream.setDelegate(TestContext.createDisconnectionStream(disconnectMillis)); } @Override public void outputTrace(BuildId buildId) throws InterruptedException { // do nothing } }; ProcessResult result = workspace.runBuckdCommand(context, listener, "test", "//:test"); result.assertFailure(); assertThat(result.getStderr(), containsString("InterruptedException")); } }
/** * This verifies that a client timeout will be detected by a Nailgun NGInputStream reading from an * empty heartbeat stream and that the generated InterruptedException will cause command execution * to fail after timeout. */ @Test public void whenClientTimeoutDetectedThenBuildIsInterrupted() throws InterruptedException, IOException { // Sub process interruption not supported on Windows. assumeTrue(Platform.detect() != Platform.WINDOWS); final long timeoutMillis = 100; final long intervalMillis = timeoutMillis * 2; // Interval > timeout to trigger disconnection. final ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "exclusive_execution", tmp); workspace.setUp(); // Build an NGContext connected to an NGInputStream reading from stream that will timeout. try (TestContext context = new TestContext( ImmutableMap.copyOf(System.getenv()), TestContext.createHeartBeatStream(intervalMillis), timeoutMillis)) { ProcessResult result = workspace.runBuckdCommand(context, "build", "//:sleep"); result.assertFailure(); assertThat(result.getStderr(), containsString("InterruptedException")); } }