...37 * https://github.com/junit-team/junit/issues/686. This test verifies that Buck honors this behavior38 * of JUnit with its custom {@link BuckBlockJUnit4ClassRunner}.39 * <p>40 * That said, this behavior of JUnit interacts badly with a default test timeout in41 * {@code .buckconfig} because it requires adding {@link org.junit.rules.Timeout} to the handful of42 * tests that exploit this behavior.43 */44public class TimeoutIntegrationTest {45 private static final String PATH_TO_TIMEOUT_BEHAVIOR_TEST = "TimeoutChangesBehaviorTest.java";46 @Rule47 public DebuggableTemporaryFolder temporaryFolder = new DebuggableTemporaryFolder();48 @Test49 public void testThatTimeoutsInTestsWorkAsExpected() throws IOException {50 ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(51 this, "timeouts", temporaryFolder);52 workspace.setUp();53 // ExceedsAnnotationTimeoutTest should fail.54 ProcessResult exceedsAnnotationTimeoutTestResult = workspace.runBuckCommand(55 "test", "//:ExceedsAnnotationTimeoutTest");56 exceedsAnnotationTimeoutTestResult.assertExitCode("Test should fail due to timeout", 1);57 assertThat(exceedsAnnotationTimeoutTestResult.getStderr(),58 containsString(59 "FAILURE testShouldFailDueToExpiredTimeout: test timed out after 1000 milliseconds"));60 // TimeoutChangesBehaviorTest should pass.61 ProcessResult timeoutTestWithoutTimeout = workspace.runBuckCommand(62 "test", "//:TimeoutChangesBehaviorTest");63 timeoutTestWithoutTimeout.assertExitCode(0);64 // TimeoutChangesBehaviorTest with @Test(timeout) specified should fail.65 // See https://github.com/junit-team/junit/issues/686 about why it fails.66 modifyTimeoutInTestAnnotation(PATH_TO_TIMEOUT_BEHAVIOR_TEST, /* addTimeout */ true);67 ProcessResult timeoutTestWithTimeoutOnAnnotation = workspace.runBuckCommand(68 "test", "//:TimeoutChangesBehaviorTest");69 timeoutTestWithTimeoutOnAnnotation.assertExitCode(1);70 assertThat(timeoutTestWithTimeoutOnAnnotation.getStderr(),71 containsString(72 "FAILURE testTimeoutDictatesTheSuccessOfThisTest: " +73 "Database should have an open transaction due to setUp()."));74 // TimeoutChangesBehaviorTest with @Rule(Timeout) should pass.75 modifyTimeoutInTestAnnotation(PATH_TO_TIMEOUT_BEHAVIOR_TEST, /* addTimeout */ false);76 insertTimeoutRule(PATH_TO_TIMEOUT_BEHAVIOR_TEST);77 ProcessResult timeoutTestWithTimeoutRule = workspace.runBuckCommand(78 "test", "//:TimeoutChangesBehaviorTest");79 timeoutTestWithTimeoutRule.assertExitCode(0);80 workspace.verify();81 }82 /**83 * Swaps all instances of {@code @Test} with {@code @Test(timeout = 10000)} in the specified Java84 * file, as determined by the value of {@code addTimeout}.85 */86 private void modifyTimeoutInTestAnnotation(String path, final boolean addTimeout)87 throws IOException {88 Function<String, String> transform = new Function<String, String>() {89 @Override public String apply(String line) {90 String original = addTimeout ? "@Test" : "@Test(timeout = 100000)";91 String replacement = addTimeout ? "@Test(timeout = 100000)" : "@Test";92 return line.replace(original, replacement) + '\n';93 }94 };95 rewriteFileWithTransform(path, transform);96 }97 /**98 * Inserts the following after the top-level class declaration:99 * <pre>100 * @org.junit.Rule101 * public org.junit.rules.Timeout timeoutForTests = new org.junit.rules.Timeout(10000);102 * </pre>103 */104 private void insertTimeoutRule(String path) throws IOException {105 Function<String, String> transform = new Function<String, String>() {106 @Override107 public String apply(String line) {108 if (line.startsWith("public class")) {109 return line + "\n\n" +110 " @org.junit.Rule\n" +111 " public org.junit.rules.Timeout timeoutForTests = " +112 "new org.junit.rules.Timeout(10000);\n";113 } else {114 return line + '\n';115 }116 }117 };118 rewriteFileWithTransform(path, transform);119 }120 /**121 * Finds the file at the specified path, transforms all of its lines using the specified122 * {@code transform} parameter, and writes the transformed lines back to the path.123 */124 private void rewriteFileWithTransform(String path, Function<String, String> transform)125 throws IOException {126 File javaFile = new File(temporaryFolder.getRoot(), path);...