Fix regex event matching
This is the prerequisite to #13371.
Closes #13375.
PiperOrigin-RevId: 369286187
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java b/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java
index 9728117..c9098a0 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java
@@ -195,6 +195,7 @@
import java.util.TreeMap;
import java.util.UUID;
import java.util.function.Predicate;
+import java.util.regex.Pattern;
import javax.annotation.Nullable;
import net.starlark.java.eval.StarlarkSemantics;
import org.junit.Before;
@@ -1212,6 +1213,31 @@
}
/**
+ * Check that configuration of the target named 'ruleName' in the specified BUILD file fails with
+ * an error message matching 'expectedErrorPattern'.
+ *
+ * @param packageName the package name of the generated BUILD file
+ * @param ruleName the rule name for the rule in the generated BUILD file
+ * @param expectedErrorPattern a regex that matches the expected error.
+ * @param lines the text of the rule.
+ * @return the found error.
+ */
+ protected Event checkError(
+ String packageName, String ruleName, Pattern expectedErrorPattern, String... lines)
+ throws Exception {
+ eventCollector.clear();
+ reporter.removeHandler(failFastHandler); // expect errors
+ ConfiguredTarget target = scratchConfiguredTarget(packageName, ruleName, lines);
+ if (target != null) {
+ assertWithMessage(
+ "Rule '" + "//" + packageName + ":" + ruleName + "' did not contain an error")
+ .that(view.hasErrors(target))
+ .isTrue();
+ }
+ return assertContainsEvent(expectedErrorPattern);
+ }
+
+ /**
* Check that configuration of the target named 'label' fails with an error message containing
* 'expectedErrorMessage'.
*
diff --git a/src/test/java/com/google/devtools/build/lib/buildtool/CustomRealFilesystemBuildIntegrationTest.java b/src/test/java/com/google/devtools/build/lib/buildtool/CustomRealFilesystemBuildIntegrationTest.java
index 84d31cb..f13093b 100644
--- a/src/test/java/com/google/devtools/build/lib/buildtool/CustomRealFilesystemBuildIntegrationTest.java
+++ b/src/test/java/com/google/devtools/build/lib/buildtool/CustomRealFilesystemBuildIntegrationTest.java
@@ -50,6 +50,7 @@
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import java.util.regex.Pattern;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -353,11 +354,12 @@
buildTarget("//hello:hello");
BuildFailedException e =
assertThrows(BuildFailedException.class, () -> buildTarget("//hello:hello"));
- MoreAsserts.assertContainsEventRegex(
+ MoreAsserts.assertContainsEvent(
events.collector(),
- "^ERROR.*Compiling hello/hello.cc failed: Unable to resolve hello/subdir/undeclared.h as an"
- + " artifact: no such package 'hello/subdir': IO errors while looking for BUILD file"
- + " reading .*hello/subdir/BUILD: nope");
+ Pattern.compile(
+ "^ERROR.*Compiling hello/hello.cc failed: Unable to resolve hello/subdir/undeclared.h"
+ + " as an artifact: no such package 'hello/subdir': IO errors while looking for"
+ + " BUILD file reading .*hello/subdir/BUILD: nope"));
assertThat(e.getDetailedExitCode().getFailureDetail())
.comparingExpectedFieldsOnly()
.isEqualTo(
@@ -382,12 +384,14 @@
customFileSystem.errorInsideStat(buildFile, 0);
BuildFailedException e =
assertThrows(BuildFailedException.class, () -> buildTarget("//hello:hello"));
- MoreAsserts.assertContainsEventRegex(
+ MoreAsserts.assertContainsEvent(
events.collector(),
- ".*Compiling hello/hello.cc failed: Unable to resolve hello/subdir/undeclared.h as an"
- + " artifact: Inconsistent filesystem operations. 'stat' said .*/hello/subdir/BUILD is"
- + " a file but then we later encountered error 'nope for .*/hello/subdir/BUILD' which"
- + " indicates that .*/hello/subdir/BUILD is no longer a file.*");
+ Pattern.compile(
+ ".*Compiling hello/hello.cc failed: Unable to resolve hello/subdir/undeclared.h as an"
+ + " artifact: Inconsistent filesystem operations. 'stat' said"
+ + " .*/hello/subdir/BUILD is a file but then we later encountered error 'nope for"
+ + " .*/hello/subdir/BUILD' which indicates that .*/hello/subdir/BUILD is no longer"
+ + " a file.*"));
events.assertContainsError("hello/subdir/BUILD ");
assertThat(e.getDetailedExitCode().getFailureDetail())
.comparingExpectedFieldsOnly()
@@ -529,14 +533,16 @@
@Test
public void ioExceptionInTopLevelSource_noKeepGoing() throws Exception {
runIoExceptionInTopLevelSource();
- MoreAsserts.assertContainsEventRegex(
+ MoreAsserts.assertContainsEvent(
events.collector(),
- ".*foo/BUILD:2:11: //foo:foo: (error reading file '//foo:error.in': nope|missing input file"
- + " '//foo:missing.in')");
- MoreAsserts.assertContainsEventRegex(
+ Pattern.compile(
+ ".*foo/BUILD:2:11: //foo:foo: (error reading file '//foo:error.in': nope|missing input"
+ + " file '//foo:missing.in')"));
+ MoreAsserts.assertContainsEvent(
events.collector(),
- ".*(1 input file\\(s\\) (are in error|do not exist)|2 input file\\(s\\) are in error or do"
- + " not exist)");
+ Pattern.compile(
+ ".*(1 input file\\(s\\) (are in error|do not exist)|2 input file\\(s\\) are in error"
+ + " or do not exist)"));
}
private void runMissingFileAndIoException() throws Exception {
@@ -565,14 +571,16 @@
@Test
public void missingFileAndIoException_noKeepGoing() throws Exception {
runMissingFileAndIoException();
- MoreAsserts.assertContainsEventRegex(
+ MoreAsserts.assertContainsEvent(
events.collector(),
- ".*foo/BUILD:1:8: Executing genrule //foo:foo failed: (error reading file '//foo:error.in':"
- + " nope|missing input file '//foo:missing.in')");
- MoreAsserts.assertContainsEventRegex(
+ Pattern.compile(
+ ".*foo/BUILD:1:8: Executing genrule //foo:foo failed: (error reading file"
+ + " '//foo:error.in': nope|missing input file '//foo:missing.in')"));
+ MoreAsserts.assertContainsEvent(
events.collector(),
- ".*(1 input file\\(s\\) (are in error|do not exist)|2 input file\\(s\\) are in error or do"
- + " not exist)");
+ Pattern.compile(
+ ".*(1 input file\\(s\\) (are in error|do not exist)|2 input file\\(s\\) are in error"
+ + " or do not exist)"));
}
private static class CustomRealFilesystem extends UnixFileSystem {
diff --git a/src/test/java/com/google/devtools/build/lib/events/util/EventCollectionApparatus.java b/src/test/java/com/google/devtools/build/lib/events/util/EventCollectionApparatus.java
index 6e036e6..8881537 100644
--- a/src/test/java/com/google/devtools/build/lib/events/util/EventCollectionApparatus.java
+++ b/src/test/java/com/google/devtools/build/lib/events/util/EventCollectionApparatus.java
@@ -25,6 +25,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
+import java.util.regex.Pattern;
/**
* An apparatus for reporting / collecting events.
@@ -175,8 +176,16 @@
}
/**
- * Utility method: Assert that the {@link #collector()} has received a
- * warning with the {@code expectedMessage}.
+ * Utility method: Assert that the {@link #collector()} has received an error that matches {@code
+ * expectedPattern}.
+ */
+ public Event assertContainsError(Pattern expectedPattern) {
+ return MoreAsserts.assertContainsEvent(eventCollector, expectedPattern, EventKind.ERROR);
+ }
+
+ /**
+ * Utility method: Assert that the {@link #collector()} has received a warning with the {@code
+ * expectedMessage}.
*/
public Event assertContainsWarning(String expectedMessage) {
return MoreAsserts.assertContainsEvent(eventCollector, expectedMessage, EventKind.WARNING);
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutorTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutorTest.java
index c8b91d6..e3a8fed 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutorTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutorTest.java
@@ -18,9 +18,7 @@
import static com.google.common.truth.Truth.assertWithMessage;
import static com.google.devtools.build.lib.actions.util.ActionCacheTestHelper.AMNESIAC_CACHE;
import static com.google.devtools.build.lib.actions.util.ActionsTestUtil.NULL_ACTION_OWNER;
-import static com.google.devtools.build.lib.testutil.MoreAsserts.assertContainsEventRegex;
import static com.google.devtools.build.lib.testutil.MoreAsserts.assertEventCount;
-import static com.google.devtools.build.lib.testutil.MoreAsserts.assertNotContainsEventRegex;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.fail;
@@ -160,6 +158,7 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
+import java.util.regex.Pattern;
import javax.annotation.Nullable;
import net.starlark.java.eval.EvalException;
import net.starlark.java.eval.Printer;
@@ -2274,9 +2273,10 @@
null,
null,
/* trustRemoteArtifacts= */ false);
- assertContainsEventRegex(eventCollector, ".*during scanning.*\n.*Scanning.*\n.*Test dir/top.*");
- assertNotContainsEventRegex(
- eventCollector, ".*after scanning.*\n.*Scanning.*\n.*Test dir/top.*");
+ MoreAsserts.assertContainsEvent(
+ eventCollector, Pattern.compile(".*during scanning.*\n.*Scanning.*\n.*Test dir/top.*"));
+ MoreAsserts.assertNotContainsEvent(
+ eventCollector, Pattern.compile(".*after scanning.*\n.*Scanning.*\n.*Test dir/top.*"));
}
private static AnalysisProtos.Artifact getArtifact(
diff --git a/src/test/java/com/google/devtools/build/lib/testutil/FoundationTestCase.java b/src/test/java/com/google/devtools/build/lib/testutil/FoundationTestCase.java
index 114e923..e6baee9 100644
--- a/src/test/java/com/google/devtools/build/lib/testutil/FoundationTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/testutil/FoundationTestCase.java
@@ -28,6 +28,7 @@
import com.google.devtools.build.lib.vfs.Root;
import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem;
import java.util.Set;
+import java.util.regex.Pattern;
import org.junit.After;
import org.junit.Before;
@@ -113,6 +114,10 @@
expectedMessage);
}
+ protected Event assertContainsEvent(Pattern expectedMessagePattern) {
+ return MoreAsserts.assertContainsEvent(eventCollector, expectedMessagePattern);
+ }
+
protected Event assertContainsEvent(String expectedMessage, Set<EventKind> kinds) {
return MoreAsserts.assertContainsEvent(eventCollector,
expectedMessage,
diff --git a/src/test/java/com/google/devtools/build/lib/testutil/MoreAsserts.java b/src/test/java/com/google/devtools/build/lib/testutil/MoreAsserts.java
index 7e11610..fcbb4a7 100644
--- a/src/test/java/com/google/devtools/build/lib/testutil/MoreAsserts.java
+++ b/src/test/java/com/google/devtools/build/lib/testutil/MoreAsserts.java
@@ -35,9 +35,9 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
+import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.regex.Pattern;
@@ -84,7 +84,7 @@
static final Predicate<Field> ALL_STRONG_REFS = Predicates.equalTo(NON_STRONG_REF);
private static boolean isRetained(Predicate<Object> predicate, Object start) {
- Map<Object, Object> visited = Maps.newIdentityHashMap();
+ IdentityHashMap<Object, Object> visited = Maps.newIdentityHashMap();
visited.put(start, start);
Queue<Object> toScan = new ArrayDeque<>();
toScan.add(start);
@@ -301,28 +301,45 @@
}
/**
- * If {@code eventCollector} does not contain an event which matches {@code expectedEventRegex},
+ * If {@code eventCollector} does not contain an event which matches {@code expectedEventPattern},
* fails with an informative assertion.
*/
- public static void assertContainsEventRegex(
- Iterable<Event> eventCollector, String expectedEventRegex) {
+ public static Event assertContainsEvent(
+ Iterable<Event> eventCollector, Pattern expectedEventPattern, EventKind... kinds) {
+ return assertContainsEvent(eventCollector, expectedEventPattern, ImmutableSet.copyOf(kinds));
+ }
+
+ /**
+ * If {@code eventCollector} does not contain an event which matches {@code expectedEventPattern},
+ * fails with an informative assertion.
+ */
+ public static Event assertContainsEvent(
+ Iterable<Event> eventCollector, Pattern expectedEventPattern, Set<EventKind> kinds) {
for (Event event : eventCollector) {
- if (event.toString().matches(expectedEventRegex)) {
- return;
+ // Does the event message match the expected regex?
+ if (!expectedEventPattern.matcher(event.toString()).find()) {
+ continue;
}
+ // Was an expected kind given, and does the event match?
+ if (!kinds.isEmpty() && !kinds.contains(event.getKind())) {
+ continue;
+ }
+ // Return the event, assertion successful
+ return event;
}
String eventsString = eventsToString(eventCollector);
- String failureMessage = "Event matching '" + expectedEventRegex + "' not found";
+ String failureMessage = "Event matching '" + expectedEventPattern + "' not found";
if (!eventsString.isEmpty()) {
failureMessage += "; found these though: " + eventsString;
}
fail(failureMessage);
+ return null; // unreachable
}
- public static void assertNotContainsEventRegex(
- Iterable<Event> eventCollector, String unexpectedEventRegex) {
+ public static void assertNotContainsEvent(
+ Iterable<Event> eventCollector, Pattern unexpectedEventPattern) {
for (Event event : eventCollector) {
- assertThat(event.toString()).doesNotMatch(unexpectedEventRegex);
+ assertThat(event.toString()).doesNotMatch(unexpectedEventPattern);
}
}
@@ -384,12 +401,12 @@
}
/**
- * If "expectedSublist" is not a sublist of "arguments", an informative
- * assertion is failed in the context of the specified TestCase.
+ * If "expectedSublist" is not a sublist of "arguments", an informative assertion is failed in the
+ * context of the specified TestCase.
*
* <p>Argument order mnemonic: assert(X)ContainsSublist(Y).
*/
- @SuppressWarnings({"unchecked", "varargs"})
+ @SuppressWarnings("varargs")
public static <T> void assertContainsSublist(List<T> arguments, T... expectedSublist) {
List<T> sublist = Arrays.asList(expectedSublist);
try {
@@ -400,12 +417,12 @@
}
/**
- * If "expectedSublist" is a sublist of "arguments", an informative
- * assertion is failed in the context of the specified TestCase.
+ * If "expectedSublist" is a sublist of "arguments", an informative assertion is failed in the
+ * context of the specified TestCase.
*
* <p>Argument order mnemonic: assert(X)DoesNotContainSublist(Y).
*/
- @SuppressWarnings({"unchecked", "varargs"})
+ @SuppressWarnings("varargs")
public static <T> void assertDoesNotContainSublist(List<T> arguments, T... expectedSublist) {
List<T> sublist = Arrays.asList(expectedSublist);
try {
@@ -442,7 +459,6 @@
* if the elements of the pair are equal by its lights.
* @return first element not in arguments in order, or null if success.
*/
- @SuppressWarnings({"unchecked"})
protected static <S, T> T containsSublistWithGapsAndEqualityChecker(List<S> arguments,
Function<Pair<S, T>, Boolean> equalityChecker, T... expectedSublist) {
Iterator<S> iter = arguments.iterator();