aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test/java/com
diff options
context:
space:
mode:
authorGravatar Kristina Chodorow <kchodorow@google.com>2015-10-12 14:43:05 +0000
committerGravatar John Field <jfield@google.com>2015-10-13 01:00:40 +0000
commitaa8b1520c6c90ab9f0a489f996937fc6a355ca3c (patch)
tree8fa2a061391bd74a43d0eaef56991338ab8d757c /src/test/java/com
parent0d5d522bf9fc2ae42ab71ca60094c79eb988501c (diff)
Add timing info for tests and correct caching vs. run ratio
Now prints: //foo:bar (cached) PASSED in 0.1s instead of: //foo:bar (1/0 cached) PASSED Fixes #218. -- MOS_MIGRATED_REVID=105210302
Diffstat (limited to 'src/test/java/com')
-rw-r--r--src/test/java/com/google/devtools/build/lib/runtime/AbstractCommandTest.java118
-rw-r--r--src/test/java/com/google/devtools/build/lib/runtime/BlazeServerStartupOptionsTest.java39
-rw-r--r--src/test/java/com/google/devtools/build/lib/runtime/BlazeVersionInfoTest.java71
-rw-r--r--src/test/java/com/google/devtools/build/lib/runtime/InvocationPolicyEnforcerTest.java780
-rw-r--r--src/test/java/com/google/devtools/build/lib/runtime/TestResultAnalyzerTest.java137
-rw-r--r--src/test/java/com/google/devtools/build/lib/runtime/TestSummaryTest.java492
6 files changed, 1637 insertions, 0 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/runtime/AbstractCommandTest.java b/src/test/java/com/google/devtools/build/lib/runtime/AbstractCommandTest.java
new file mode 100644
index 0000000000..7abb490bfd
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/runtime/AbstractCommandTest.java
@@ -0,0 +1,118 @@
+// Copyright 2015 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.runtime;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
+import com.google.devtools.build.lib.testutil.MoreAsserts;
+import com.google.devtools.build.lib.util.ExitCode;
+import com.google.devtools.common.options.Option;
+import com.google.devtools.common.options.OptionsBase;
+import com.google.devtools.common.options.OptionsParser;
+import com.google.devtools.common.options.OptionsProvider;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link BlazeCommand}.
+ */
+@RunWith(JUnit4.class)
+public class AbstractCommandTest {
+
+ public static class FooOptions extends OptionsBase {
+ @Option(name = "foo", category = "one", defaultValue = "0")
+ public int foo;
+ }
+
+ public static class BarOptions extends OptionsBase {
+ @Option(name = "bar", category = "two", defaultValue = "42")
+ public int foo;
+
+ @Option(name = "baz", category = "one", defaultValue = "oops")
+ public String baz;
+ }
+
+ private static class ConcreteCommand implements BlazeCommand {
+ @Override
+ public ExitCode exec(CommandEnvironment env, OptionsProvider options) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void editOptions(CommandEnvironment env, OptionsParser optionsParser) {}
+ }
+
+ @Command(name = "test_name",
+ help = "Usage: some funny usage for %{command} ...;\n\n%{options}; end",
+ options = {FooOptions.class, BarOptions.class},
+ shortDescription = "a short description",
+ allowResidue = false)
+ private static class TestCommand extends ConcreteCommand {}
+
+ @Test
+ public void testGetNameYieldsAnnotatedName() {
+ assertEquals("test_name",
+ new TestCommand().getClass().getAnnotation(Command.class).name());
+ }
+
+ @Test
+ public void testGetOptionsYieldsAnnotatedOptions() {
+ ConfiguredRuleClassProvider ruleClassProvider = new ConfiguredRuleClassProvider.Builder()
+ .build();
+
+ MoreAsserts.assertSameContents(optionClassesWithDefault(FooOptions.class, BarOptions.class),
+ BlazeCommandUtils.getOptions(
+ TestCommand.class, ImmutableList.<BlazeModule>of(), ruleClassProvider));
+ }
+
+ /***************************************************************************
+ * The tests below test how a command interacts with the dispatcher except *
+ * for execution, which is tested in {@link BlazeCommandDispatcherTest}. *
+ ***************************************************************************/
+
+ @Command(name = "a", options = {FooOptions.class}, shortDescription = "", help = "")
+ private static class CommandA extends ConcreteCommand {}
+
+ @Command(name = "b", options = {BarOptions.class}, inherits = {CommandA.class},
+ shortDescription = "", help = "")
+ private static class CommandB extends ConcreteCommand {}
+
+ @Test
+ public void testOptionsAreInherited() {
+ ConfiguredRuleClassProvider ruleClassProvider = new ConfiguredRuleClassProvider.Builder()
+ .build();
+ MoreAsserts.assertSameContents(optionClassesWithDefault(FooOptions.class),
+ BlazeCommandUtils.getOptions(
+ CommandA.class, ImmutableList.<BlazeModule>of(), ruleClassProvider));
+ MoreAsserts.assertSameContents(optionClassesWithDefault(FooOptions.class, BarOptions.class),
+ BlazeCommandUtils.getOptions(
+ CommandB.class, ImmutableList.<BlazeModule>of(), ruleClassProvider));
+ }
+
+ private Collection<Class<?>> optionClassesWithDefault(Class<?>... optionClasses) {
+ List<Class<?>> result = new ArrayList<>();
+ Collections.addAll(result, optionClasses);
+ result.add(BlazeCommandEventHandler.Options.class);
+ result.add(CommonCommandOptions.class);
+ return result;
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/runtime/BlazeServerStartupOptionsTest.java b/src/test/java/com/google/devtools/build/lib/runtime/BlazeServerStartupOptionsTest.java
new file mode 100644
index 0000000000..44f48a1b55
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/runtime/BlazeServerStartupOptionsTest.java
@@ -0,0 +1,39 @@
+// Copyright 2015 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.runtime;
+
+import com.google.devtools.common.options.OptionsParser;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static org.junit.Assert.assertNull;
+
+/**
+ * A regression test for {@link BlazeServerStartupOptions}.
+ */
+@RunWith(JUnit4.class)
+public class BlazeServerStartupOptionsTest {
+
+ // A regression test to make sure that the output_base option is correctly parsed if no explicit
+ // value is provided.
+ @Test
+ public void testOutputBaseIsNullByDefault() throws Exception {
+ OptionsParser parser = OptionsParser.newOptionsParser(BlazeServerStartupOptions.class);
+ parser.parse();
+ BlazeServerStartupOptions result = parser.getOptions(BlazeServerStartupOptions.class);
+ assertNull(result.outputBase);
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/runtime/BlazeVersionInfoTest.java b/src/test/java/com/google/devtools/build/lib/runtime/BlazeVersionInfoTest.java
new file mode 100644
index 0000000000..3f3c5ca099
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/runtime/BlazeVersionInfoTest.java
@@ -0,0 +1,71 @@
+// Copyright 2015 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.runtime;
+
+import static java.util.Collections.singletonMap;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+
+import com.google.devtools.build.lib.analysis.BlazeVersionInfo;
+import com.google.devtools.build.lib.util.StringUtilities;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Tests {@link BlazeVersionInfo}.
+ */
+@RunWith(JUnit4.class)
+public class BlazeVersionInfoTest {
+
+ @Test
+ public void testEmptyVersionInfoMeansNotAvailable() {
+ BlazeVersionInfo info = new BlazeVersionInfo(Collections.<String, String>emptyMap());
+ assertFalse(info.isAvailable());
+ assertNull(info.getSummary());
+ assertEquals("development version", info.getReleaseName());
+ }
+
+ @Test
+ public void testReleaseNameIsDevelopmentIfBuildLabelIsNull() {
+ Map<String, String> data = singletonMap("Build label", "");
+ BlazeVersionInfo info = new BlazeVersionInfo(data);
+ assertEquals("development version", info.getReleaseName());
+ }
+
+ @Test
+ public void testReleaseNameIfBuildLabelIsPresent() {
+ Map<String, String> data = singletonMap("Build label", "3/4/2009 (gold)");
+ BlazeVersionInfo info = new BlazeVersionInfo(data);
+ assertEquals("release 3/4/2009 (gold)", info.getReleaseName());
+ }
+
+ @Test
+ public void testFancySummaryFormatting() {
+ Map<String, String> data = new HashMap<>();
+ data.put("Some entry", "foo");
+ data.put("Another entry", "bar");
+ data.put("And a third entry", "baz");
+ BlazeVersionInfo info = new BlazeVersionInfo(data);
+ Map<String, String> sortedData = new TreeMap<>(data);
+ assertEquals(StringUtilities.layoutTable(sortedData), info.getSummary());
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/runtime/InvocationPolicyEnforcerTest.java b/src/test/java/com/google/devtools/build/lib/runtime/InvocationPolicyEnforcerTest.java
new file mode 100644
index 0000000000..67bdd44036
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/runtime/InvocationPolicyEnforcerTest.java
@@ -0,0 +1,780 @@
+// Copyright 2015 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.runtime;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.google.common.io.BaseEncoding;
+import com.google.devtools.build.lib.runtime.proto.InvocationPolicyOuterClass.InvocationPolicy;
+import com.google.devtools.common.options.Option;
+import com.google.devtools.common.options.OptionsBase;
+import com.google.devtools.common.options.OptionsParser;
+import com.google.devtools.common.options.OptionsParsingException;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.ByteArrayOutputStream;
+import java.util.List;
+
+@RunWith(JUnit4.class)
+public class InvocationPolicyEnforcerTest {
+
+ private static final String STRING_FLAG_DEFAULT = "test string default";
+
+ public static class TestOptions extends OptionsBase {
+
+ /*
+ * Basic types
+ */
+
+ @Option(name = "test_string", defaultValue = STRING_FLAG_DEFAULT)
+ public String testString;
+
+ /*
+ * Repeated flags
+ */
+
+ @Option(
+ name = "test_multiple_string",
+ defaultValue = "", // default value is ignored when allowMultiple = true.
+ allowMultiple = true)
+ public List<String> testMultipleString;
+
+ /*
+ * Expansion flags
+ */
+
+ @Option(
+ name = "test_expansion",
+ defaultValue = "null",
+ expansion = {"--test_expansion_a", "--test_expansion_b", "--test_expansion_c"})
+ public Void testExpansion;
+
+ @Option(name = "test_expansion_a", defaultValue = "false")
+ public boolean testExpansionA;
+
+ @Option(name = "test_expansion_b", defaultValue = "false")
+ public boolean testExpansionB;
+
+ @Option(name = "test_expansion_c", defaultValue = "false")
+ public boolean testExpansionC;
+
+ /*
+ * Implicit requirement flags
+ */
+
+ @Option(
+ name = "test_implicit_requirement",
+ defaultValue = "test implicit requirement default",
+ implicitRequirements = {"--an_implicit_requirement=foo"})
+ public String testImplicitRequirement;
+
+ @Option(
+ name = "an_implicit_requirement",
+ defaultValue = "implicit default")
+ public String anImplicitRequirement;
+
+ }
+
+ private static InvocationPolicyEnforcer createOptionsPolicyEnforcer(
+ InvocationPolicy.Builder invocationPolicyBuilder) throws Exception {
+ InvocationPolicy policyProto = invocationPolicyBuilder.build();
+
+ // An OptionsPolicyEnforcer could be constructed in the test directly from the InvocationPolicy
+ // proto, however Blaze will actually take the policy as another flag with a Base64 encoded
+ // binary proto and parse that, so exercise that code path in the test.
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ policyProto.writeTo(out);
+ String policyBase64 = BaseEncoding.base64().encode(out.toByteArray());
+
+ OptionsParser startupOptionsParser = OptionsParser.newOptionsParser(
+ BlazeServerStartupOptions.class);
+ String policyOption = "--invocation_policy=" + policyBase64;
+ startupOptionsParser.parse(policyOption);
+
+ return InvocationPolicyEnforcer.create(startupOptionsParser);
+ }
+
+ private OptionsParser parser;
+
+ @Before
+ public void setUp() throws Exception {
+ parser = OptionsParser.newOptionsParser(TestOptions.class);
+ }
+
+ private TestOptions getTestOptions() {
+ return parser.getOptions(TestOptions.class);
+ }
+
+ /*************************************************************************************************
+ * Tests for SetValue
+ ************************************************************************************************/
+
+ /**
+ * Tests that policy overrides a value when that value is from the user.
+ */
+ @Test
+ public void testSetValueOverridesUser() throws Exception {
+ InvocationPolicy.Builder invocationPolicyBuilder = InvocationPolicy.newBuilder();
+ invocationPolicyBuilder.addFlagPoliciesBuilder()
+ .setFlagName("test_string")
+ .getSetValueBuilder()
+ .addFlagValue("policy value");
+
+ InvocationPolicyEnforcer enforcer = createOptionsPolicyEnforcer(invocationPolicyBuilder);
+ parser.parse("--test_string=user value");
+
+ TestOptions testOptions = getTestOptions();
+ assertEquals("user value", testOptions.testString);
+
+ enforcer.enforce(parser, "build");
+
+ // Get the options again after policy enforcement.
+ testOptions = getTestOptions();
+ assertEquals("policy value", testOptions.testString);
+ }
+
+ /**
+ * Tests that policy overrides a value when the user doesn't specify the value (i.e., the value
+ * is from the flag's default from its definition).
+ */
+ @Test
+ public void testSetValueOverridesDefault() throws Exception {
+ InvocationPolicy.Builder invocationPolicyBuilder = InvocationPolicy.newBuilder();
+ invocationPolicyBuilder.addFlagPoliciesBuilder()
+ .setFlagName("test_string")
+ .getSetValueBuilder()
+ .addFlagValue("policy value");
+
+ // No user value.
+ InvocationPolicyEnforcer enforcer = createOptionsPolicyEnforcer(invocationPolicyBuilder);
+
+ // All the flags should be their default value.
+ TestOptions testOptions = getTestOptions();
+ assertEquals(STRING_FLAG_DEFAULT, testOptions.testString);
+
+ enforcer.enforce(parser, "build");
+
+ // Get the options again after policy enforcement.
+ testOptions = getTestOptions();
+ assertEquals("policy value", testOptions.testString);
+ }
+
+ /**
+ * Tests that SetValue overrides the user's value when the flag allows multiple values.
+ */
+ @Test
+ public void testSetValueWithMultipleValuesOverridesUser() throws Exception {
+ InvocationPolicy.Builder invocationPolicyBuilder = InvocationPolicy.newBuilder();
+ invocationPolicyBuilder.addFlagPoliciesBuilder()
+ .setFlagName("test_multiple_string")
+ .getSetValueBuilder()
+ .addFlagValue("policy value 1")
+ .addFlagValue("policy value 2");
+
+ InvocationPolicyEnforcer enforcer = createOptionsPolicyEnforcer(invocationPolicyBuilder);
+ parser.parse("--test_multiple_string=user value 1", "--test_multiple_string=user value 2");
+
+ // Options should not be modified by running the parser through OptionsPolicyEnforcer.create().
+ TestOptions testOptions = getTestOptions();
+ assertThat(testOptions.testMultipleString)
+ .containsExactly("user value 1", "user value 2").inOrder();
+ //assertEquals(, testOptions.test_multiple_string);
+
+ enforcer.enforce(parser, "build");
+
+ // Get the options again after policy enforcement.
+ testOptions = getTestOptions();
+ assertThat(testOptions.testMultipleString)
+ .containsExactly("policy value 1", "policy value 2").inOrder();
+ }
+
+ /**
+ * Tests that policy overrides the default value when the flag allows multiple values and the user
+ * doesn't provide a value.
+ */
+ @Test
+ public void testSetValueWithMultipleValuesOverridesDefault() throws Exception {
+ InvocationPolicy.Builder invocationPolicyBuilder = InvocationPolicy.newBuilder();
+ invocationPolicyBuilder.addFlagPoliciesBuilder()
+ .setFlagName("test_multiple_string")
+ .getSetValueBuilder()
+ .addFlagValue("policy value 1")
+ .addFlagValue("policy value 2");
+
+ // No user value.
+ InvocationPolicyEnforcer enforcer = createOptionsPolicyEnforcer(invocationPolicyBuilder);
+
+ // Repeatable flags always default to the empty list.
+ TestOptions testOptions = getTestOptions();
+ assertThat(testOptions.testMultipleString).isEmpty();
+
+ enforcer.enforce(parser, "build");
+
+ // Options should now be the values from the policy.
+ testOptions = getTestOptions();
+ assertThat(testOptions.testMultipleString)
+ .containsExactly("policy value 1", "policy value 2").inOrder();
+ }
+
+ @Test
+ public void testSetValueHasMultipleValuesButFlagIsNotMultiple() throws Exception {
+ InvocationPolicy.Builder invocationPolicyBuilder = InvocationPolicy.newBuilder();
+ invocationPolicyBuilder.addFlagPoliciesBuilder()
+ .setFlagName("test_string") // Not repeatable flag.
+ .getSetValueBuilder()
+ .addFlagValue("policy value 1") // Has multiple values.
+ .addFlagValue("policy value 2");
+
+ InvocationPolicyEnforcer enforcer = createOptionsPolicyEnforcer(invocationPolicyBuilder);
+
+ try {
+ enforcer.enforce(parser, "build");
+ fail();
+ } catch (OptionsParsingException e) {
+ // expected.
+ }
+ }
+
+ @Test
+ public void testSetValueWithExpansionFlags() throws Exception {
+ InvocationPolicy.Builder invocationPolicyBuilder = InvocationPolicy.newBuilder();
+ invocationPolicyBuilder.addFlagPoliciesBuilder()
+ .setFlagName("test_expansion_b")
+ .getSetValueBuilder()
+ .addFlagValue("false");
+
+ InvocationPolicyEnforcer enforcer = createOptionsPolicyEnforcer(invocationPolicyBuilder);
+ parser.parse("--test_expansion");
+
+ // --test_expansion should turn on test_expansion a, b, and c
+ TestOptions testOptions = getTestOptions();
+ assertTrue(testOptions.testExpansionA);
+ assertTrue(testOptions.testExpansionB);
+ assertTrue(testOptions.testExpansionC);
+
+ enforcer.enforce(parser, "build");
+
+ // After policy enforcement, test_expansion_b should be set to false, but the
+ // other two should remain the same.
+ testOptions = getTestOptions();
+ assertTrue(testOptions.testExpansionA);
+ assertFalse(testOptions.testExpansionB);
+ assertTrue(testOptions.testExpansionC);
+ }
+
+ @Test
+ public void testSetValueWithImplicitlyRequiredFlags() throws Exception {
+ InvocationPolicy.Builder invocationPolicyBuilder = InvocationPolicy.newBuilder();
+ invocationPolicyBuilder.addFlagPoliciesBuilder()
+ .setFlagName("an_implicit_requirement")
+ .getSetValueBuilder()
+ .addFlagValue("policy value");
+
+ InvocationPolicyEnforcer enforcer = createOptionsPolicyEnforcer(invocationPolicyBuilder);
+ parser.parse("--test_implicit_requirement=user value");
+
+ // test_implicit_requirement sets an_implicit_requirement to "foo"
+ TestOptions testOptions = getTestOptions();
+ assertEquals("user value", testOptions.testImplicitRequirement);
+ assertEquals("foo", testOptions.anImplicitRequirement);
+
+ enforcer.enforce(parser, "build");
+
+ testOptions = getTestOptions();
+ assertEquals("user value", testOptions.testImplicitRequirement);
+ assertEquals("policy value", testOptions.anImplicitRequirement);
+ }
+
+ @Test
+ public void testSetValueOverridable() throws Exception {
+ InvocationPolicy.Builder invocationPolicyBuilder = InvocationPolicy.newBuilder();
+ invocationPolicyBuilder.addFlagPoliciesBuilder()
+ .setFlagName("test_string")
+ .getSetValueBuilder()
+ .addFlagValue("policy value")
+ .setOverridable(true);
+
+ InvocationPolicyEnforcer enforcer = createOptionsPolicyEnforcer(invocationPolicyBuilder);
+ parser.parse("--test_string=user value");
+
+ // Repeatable flags always default to the empty list.
+ TestOptions testOptions = getTestOptions();
+ assertEquals("user value", testOptions.testString);
+
+ enforcer.enforce(parser, "build");
+
+ // Even though the policy sets the value for test_string, the policy is overridable and the
+ // user set the value, so it should be the user's value.
+ testOptions = getTestOptions();
+ assertEquals("user value", testOptions.testString);
+ }
+
+ @Test
+ public void testSetValueWithNoValueThrows() throws Exception {
+ InvocationPolicy.Builder invocationPolicyBuilder = InvocationPolicy.newBuilder();
+ invocationPolicyBuilder.addFlagPoliciesBuilder()
+ .setFlagName("test_string")
+ .getSetValueBuilder(); // No value.
+
+ InvocationPolicyEnforcer enforcer = createOptionsPolicyEnforcer(invocationPolicyBuilder);
+ parser.parse("--test_string=user value");
+
+ // Repeatable flags always default to the empty list.
+ TestOptions testOptions = getTestOptions();
+ assertEquals("user value", testOptions.testString);
+
+ try {
+ enforcer.enforce(parser, "build");
+ fail();
+ } catch (OptionsParsingException e) {
+ // expected.
+ }
+ }
+
+ /*************************************************************************************************
+ * Tests for UseDefault
+ ************************************************************************************************/
+
+ @Test
+ public void testUseDefault() throws Exception {
+ InvocationPolicy.Builder invocationPolicyBuilder = InvocationPolicy.newBuilder();
+ invocationPolicyBuilder.addFlagPoliciesBuilder()
+ .setFlagName("test_string")
+ .getUseDefaultBuilder();
+
+ InvocationPolicyEnforcer enforcer = createOptionsPolicyEnforcer(invocationPolicyBuilder);
+ parser.parse("--test_string=user value");
+
+ // Options should be the user specified value before enforcing policy.
+ TestOptions testOptions = getTestOptions();
+ assertEquals("user value", testOptions.testString);
+
+ enforcer.enforce(parser, "build");
+
+ // Get the options again after policy enforcement: The flag should now be back to its default
+ // value
+ testOptions = getTestOptions();
+ assertEquals(STRING_FLAG_DEFAULT, testOptions.testString);
+ }
+
+ /**
+ * Tests UseDefault when the user never actually specified the flag.
+ */
+ @Test
+ public void testUseDefaultWhenFlagWasntSet() throws Exception {
+ InvocationPolicy.Builder invocationPolicyBuilder = InvocationPolicy.newBuilder();
+ invocationPolicyBuilder.addFlagPoliciesBuilder()
+ .setFlagName("test_string")
+ .getUseDefaultBuilder();
+
+ InvocationPolicyEnforcer enforcer = createOptionsPolicyEnforcer(invocationPolicyBuilder);
+
+ // Options should be the default since the user never specified it.
+ TestOptions testOptions = getTestOptions();
+ assertEquals(STRING_FLAG_DEFAULT, testOptions.testString);
+
+ enforcer.enforce(parser, "build");
+
+ // Still the default.
+ testOptions = getTestOptions();
+ assertEquals(STRING_FLAG_DEFAULT, testOptions.testString);
+ }
+
+ @Test
+ public void testUseDefaultWithExpansionFlags() throws Exception {
+ InvocationPolicy.Builder invocationPolicyBuilder = InvocationPolicy.newBuilder();
+ invocationPolicyBuilder.addFlagPoliciesBuilder()
+ .setFlagName("test_expansion_b")
+ .getUseDefaultBuilder();
+
+ InvocationPolicyEnforcer enforcer = createOptionsPolicyEnforcer(invocationPolicyBuilder);
+ parser.parse("--test_expansion");
+
+ // --test_expansion should turn on test_expansion a, b, and c
+ TestOptions testOptions = getTestOptions();
+ assertTrue(testOptions.testExpansionA);
+ assertTrue(testOptions.testExpansionB);
+ assertTrue(testOptions.testExpansionC);
+
+ enforcer.enforce(parser, "build");
+
+ // After policy enforcement, test_expansion_b should be back to its default (false), but the
+ // other two should remain the same.
+ testOptions = getTestOptions();
+ assertTrue(testOptions.testExpansionA);
+ assertFalse(testOptions.testExpansionB);
+ assertTrue(testOptions.testExpansionC);
+ }
+
+ @Test
+ public void testUseDefaultWithImplicitlyRequiredFlags() throws Exception {
+ InvocationPolicy.Builder invocationPolicyBuilder = InvocationPolicy.newBuilder();
+ invocationPolicyBuilder.addFlagPoliciesBuilder()
+ .setFlagName("an_implicit_requirement")
+ .getUseDefaultBuilder();
+
+ InvocationPolicyEnforcer enforcer = createOptionsPolicyEnforcer(invocationPolicyBuilder);
+ parser.parse("--test_implicit_requirement=user value",
+ "--an_implicit_requirement=implicit user value");
+
+ // test_implicit_requirement sets an_implicit_requirement to "foo", which ignores the user's
+ // value because the parser processes implicit values last.
+ TestOptions testOptions = getTestOptions();
+ assertEquals("user value", testOptions.testImplicitRequirement);
+ assertEquals("foo", testOptions.anImplicitRequirement);
+
+ // Then policy puts an_implicit_requirement back to its default.
+ enforcer.enforce(parser, "build");
+
+ testOptions = getTestOptions();
+ assertEquals("user value", testOptions.testImplicitRequirement);
+ assertEquals("implicit default", testOptions.anImplicitRequirement);
+ }
+
+ /*************************************************************************************************
+ * Tests for AllowValues
+ ************************************************************************************************/
+
+ /**
+ * Tests that AllowValues works in the normal case where the value the user specified is allowed
+ * by the policy.
+ */
+ @Test
+ public void testAllowValuesAllowsValue() throws Exception {
+ InvocationPolicy.Builder invocationPolicyBuilder = InvocationPolicy.newBuilder();
+ invocationPolicyBuilder.addFlagPoliciesBuilder()
+ .setFlagName("test_string")
+ .getAllowValuesBuilder()
+ .addAllowedValues(STRING_FLAG_DEFAULT)
+ .addAllowedValues("foo")
+ .addAllowedValues("bar");
+
+ InvocationPolicyEnforcer enforcer = createOptionsPolicyEnforcer(invocationPolicyBuilder);
+ parser.parse("--test_string=foo");
+
+ // Option should be "foo" as specified by the user.
+ TestOptions testOptions = getTestOptions();
+ assertEquals("foo", testOptions.testString);
+
+ enforcer.enforce(parser, "build");
+
+ // Still "foo" since "foo" is allowed by the policy.
+ testOptions = getTestOptions();
+ assertEquals("foo", testOptions.testString);
+ }
+
+ @Test
+ public void testAllowValuesDisallowsValue() throws Exception {
+ InvocationPolicy.Builder invocationPolicyBuilder = InvocationPolicy.newBuilder();
+ invocationPolicyBuilder.addFlagPoliciesBuilder()
+ .setFlagName("test_string")
+ .getAllowValuesBuilder()
+ // no foo!
+ .addAllowedValues(STRING_FLAG_DEFAULT)
+ .addAllowedValues("bar");
+
+ InvocationPolicyEnforcer enforcer = createOptionsPolicyEnforcer(invocationPolicyBuilder);
+ parser.parse("--test_string=foo");
+
+ // Option should be "foo" as specified by the user.
+ TestOptions testOptions = getTestOptions();
+ assertEquals("foo", testOptions.testString);
+
+ try {
+ // Should throw because "foo" is not allowed.
+ enforcer.enforce(parser, "build");
+ fail();
+ } catch (OptionsParsingException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testAllowValuesDisallowsMultipleValues() throws Exception {
+ InvocationPolicy.Builder invocationPolicyBuilder = InvocationPolicy.newBuilder();
+ invocationPolicyBuilder.addFlagPoliciesBuilder()
+ .setFlagName("test_multiple_string")
+ .getAllowValuesBuilder()
+ .addAllowedValues("foo")
+ .addAllowedValues("bar");
+
+ InvocationPolicyEnforcer enforcer = createOptionsPolicyEnforcer(invocationPolicyBuilder);
+ parser.parse("--test_multiple_string=baz", "--test_multiple_string=bar");
+
+ // Option should be "baz" and "bar" as specified by the user.
+ TestOptions testOptions = getTestOptions();
+ assertThat(testOptions.testMultipleString).containsExactly("baz", "bar").inOrder();
+
+ try {
+ enforcer.enforce(parser, "build");
+ fail();
+ } catch (OptionsParsingException e) {
+ // expected, since baz is not allowed.
+ }
+ }
+
+ /**
+ * Tests that AllowValues sets its default value when the user doesn't provide a value and the
+ * flag's default value is disallowed.
+ */
+ @Test
+ public void testAllowValuesSetsNewDefaultWhenFlagDefaultIsDisallowed() throws Exception {
+ InvocationPolicy.Builder invocationPolicyBuilder = InvocationPolicy.newBuilder();
+ invocationPolicyBuilder.addFlagPoliciesBuilder()
+ .setFlagName("test_string")
+ .getAllowValuesBuilder()
+ // default value from flag's definition is not allowed
+ .addAllowedValues("foo")
+ .addAllowedValues("bar")
+ .setNewDefaultValue("new default");
+
+ InvocationPolicyEnforcer enforcer = createOptionsPolicyEnforcer(invocationPolicyBuilder);
+
+ // Option should be its default
+ TestOptions testOptions = getTestOptions();
+ assertEquals(STRING_FLAG_DEFAULT, testOptions.testString);
+
+ enforcer.enforce(parser, "build");
+
+ // Flag's value should be the default value from the policy.
+ testOptions = getTestOptions();
+ assertEquals("new default", testOptions.testString);
+ }
+
+ @Test
+ public void testAllowValuesDisallowsFlagDefaultButNoPolicyDefault() throws Exception {
+ InvocationPolicy.Builder invocationPolicyBuilder = InvocationPolicy.newBuilder();
+ invocationPolicyBuilder.addFlagPoliciesBuilder()
+ .setFlagName("test_string")
+ .getAllowValuesBuilder()
+ // default value from flag's definition is not allowed, and no alternate default
+ // is given.
+ .addAllowedValues("foo")
+ .addAllowedValues("bar");
+
+ InvocationPolicyEnforcer enforcer = createOptionsPolicyEnforcer(invocationPolicyBuilder);
+
+ // Option should be its default
+ TestOptions testOptions = getTestOptions();
+ assertEquals(STRING_FLAG_DEFAULT, testOptions.testString);
+
+ try {
+ enforcer.enforce(parser, "build");
+ fail();
+ } catch (OptionsParsingException e) {
+ // expected.
+ }
+ }
+
+ /*************************************************************************************************
+ * Tests for DisallowValues
+ ************************************************************************************************/
+
+ @Test
+ public void testDisallowValuesAllowsValue() throws Exception {
+ InvocationPolicy.Builder invocationPolicyBuilder = InvocationPolicy.newBuilder();
+ invocationPolicyBuilder.addFlagPoliciesBuilder()
+ .setFlagName("test_string")
+ .getDisallowValuesBuilder()
+ .addDisallowedValues("foo")
+ .addDisallowedValues("bar");
+
+ InvocationPolicyEnforcer enforcer = createOptionsPolicyEnforcer(invocationPolicyBuilder);
+ parser.parse("--test_string=baz");
+
+ // Option should be "baz" as specified by the user.
+ TestOptions testOptions = getTestOptions();
+ assertEquals("baz", testOptions.testString);
+
+ enforcer.enforce(parser, "build");
+
+ // Still "baz" since "baz" is allowed by the policy.
+ testOptions = getTestOptions();
+ assertEquals("baz", testOptions.testString);
+ }
+
+ @Test
+ public void testDisallowValuesDisallowsValue() throws Exception {
+ InvocationPolicy.Builder invocationPolicyBuilder = InvocationPolicy.newBuilder();
+ invocationPolicyBuilder.addFlagPoliciesBuilder()
+ .setFlagName("test_string")
+ .getDisallowValuesBuilder()
+ .addDisallowedValues("foo")
+ .addDisallowedValues("bar");
+
+ InvocationPolicyEnforcer enforcer = createOptionsPolicyEnforcer(invocationPolicyBuilder);
+ parser.parse("--test_string=foo");
+
+ // Option should be "foo" as specified by the user.
+ TestOptions testOptions = getTestOptions();
+ assertEquals("foo", testOptions.testString);
+
+ try {
+ enforcer.enforce(parser, "build");
+ fail();
+ } catch (OptionsParsingException e) {
+ // expected, since foo is disallowed.
+ }
+ }
+
+ @Test
+ public void testDisallowValuesDisallowsMultipleValues() throws Exception {
+ InvocationPolicy.Builder invocationPolicyBuilder = InvocationPolicy.newBuilder();
+ invocationPolicyBuilder.addFlagPoliciesBuilder()
+ .setFlagName("test_multiple_string")
+ .getDisallowValuesBuilder()
+ .addDisallowedValues("foo")
+ .addDisallowedValues("bar");
+
+ InvocationPolicyEnforcer enforcer = createOptionsPolicyEnforcer(invocationPolicyBuilder);
+ parser.parse("--test_multiple_string=baz", "--test_multiple_string=bar");
+
+ // Option should be "baz" and "bar" as specified by the user.
+ TestOptions testOptions = getTestOptions();
+ assertThat(testOptions.testMultipleString).containsExactly("baz", "bar").inOrder();
+
+ try {
+ enforcer.enforce(parser, "build");
+ fail();
+ } catch (OptionsParsingException e) {
+ // expected, since bar is disallowed.
+ }
+ }
+
+ @Test
+ public void testDisallowValuesSetsNewDefaultWhenFlagDefaultIsDisallowed() throws Exception {
+ InvocationPolicy.Builder invocationPolicyBuilder = InvocationPolicy.newBuilder();
+ invocationPolicyBuilder.addFlagPoliciesBuilder()
+ .setFlagName("test_string")
+ .getDisallowValuesBuilder()
+ .addDisallowedValues(STRING_FLAG_DEFAULT)
+ .setNewDefaultValue("baz");
+
+ InvocationPolicyEnforcer enforcer = createOptionsPolicyEnforcer(invocationPolicyBuilder);
+
+ // Option should be the default since the use didn't specify a value.
+ TestOptions testOptions = getTestOptions();
+ assertEquals(STRING_FLAG_DEFAULT, testOptions.testString);
+
+ enforcer.enforce(parser, "build");
+
+ // Should now be "baz" because the policy set the new default to "baz"
+ testOptions = getTestOptions();
+ assertEquals("baz", testOptions.testString);
+ }
+
+ @Test
+ public void testDisallowValuesDisallowsFlagDefaultButNoPolicyDefault() throws Exception {
+ InvocationPolicy.Builder invocationPolicyBuilder = InvocationPolicy.newBuilder();
+ invocationPolicyBuilder.addFlagPoliciesBuilder()
+ .setFlagName("test_string")
+ .getDisallowValuesBuilder()
+ // No new default is set
+ .addDisallowedValues(STRING_FLAG_DEFAULT);
+
+ InvocationPolicyEnforcer enforcer = createOptionsPolicyEnforcer(invocationPolicyBuilder);
+
+ // Option should be the default since the use didn't specify a value.
+ TestOptions testOptions = getTestOptions();
+ assertEquals(STRING_FLAG_DEFAULT, testOptions.testString);
+
+ try {
+ enforcer.enforce(parser, "build");
+ fail();
+ } catch (OptionsParsingException e) {
+ // expected.
+ }
+ }
+
+ /*************************************************************************************************
+ * Other tests
+ ************************************************************************************************/
+
+ @Test
+ public void testFlagPolicyDoesNotApply() throws Exception {
+ InvocationPolicy.Builder invocationPolicyBuilder = InvocationPolicy.newBuilder();
+ invocationPolicyBuilder.addFlagPoliciesBuilder()
+ .setFlagName("test_string")
+ .addCommands("build")
+ .getSetValueBuilder()
+ .addFlagValue("policy value");
+
+ InvocationPolicyEnforcer enforcer = createOptionsPolicyEnforcer(invocationPolicyBuilder);
+ parser.parse("--test_string=user value");
+
+ TestOptions testOptions = getTestOptions();
+ assertEquals("user value", testOptions.testString);
+
+ enforcer.enforce(parser, "test");
+
+ // Still user value.
+ testOptions = getTestOptions();
+ assertEquals("user value", testOptions.testString);
+ }
+
+ @Test
+ public void testNonExistantFlagFromPolicy() throws Exception {
+ InvocationPolicy.Builder invocationPolicyBuilder = InvocationPolicy.newBuilder();
+ invocationPolicyBuilder.addFlagPoliciesBuilder()
+ .setFlagName("i_do_not_exist")
+ .getSetValueBuilder()
+ .addFlagValue("policy value 1");
+ invocationPolicyBuilder.addFlagPoliciesBuilder()
+ .setFlagName("test_string")
+ .getSetValueBuilder()
+ .addFlagValue("policy value 2");
+
+ InvocationPolicyEnforcer enforcer = createOptionsPolicyEnforcer(invocationPolicyBuilder);
+ parser.parse("--test_string=user value");
+
+ TestOptions testOptions = getTestOptions();
+ assertEquals("user value", testOptions.testString);
+
+ enforcer.enforce(parser, "test");
+
+ // Still user value.
+ testOptions = getTestOptions();
+ assertEquals("policy value 2", testOptions.testString);
+ }
+
+ @Test
+ public void testOperationNotSet() throws Exception {
+ InvocationPolicy.Builder invocationPolicyBuilder = InvocationPolicy.newBuilder();
+ invocationPolicyBuilder.addFlagPoliciesBuilder();
+ // No operations added to the flag policy
+
+ InvocationPolicyEnforcer enforcer = createOptionsPolicyEnforcer(invocationPolicyBuilder);
+ parser.parse("--test_string=user value");
+
+ TestOptions testOptions = getTestOptions();
+ assertEquals("user value", testOptions.testString);
+
+ // Shouldn't throw.
+ enforcer.enforce(parser, "test");
+
+ // Still user value.
+ testOptions = getTestOptions();
+ assertEquals("user value", testOptions.testString);
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/runtime/TestResultAnalyzerTest.java b/src/test/java/com/google/devtools/build/lib/runtime/TestResultAnalyzerTest.java
new file mode 100644
index 0000000000..05c94c1538
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/runtime/TestResultAnalyzerTest.java
@@ -0,0 +1,137 @@
+// Copyright 2015 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.runtime;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.eventbus.EventBus;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.exec.ExecutionOptions;
+import com.google.devtools.build.lib.packages.TestTimeout;
+import com.google.devtools.build.lib.rules.test.TestProvider;
+import com.google.devtools.build.lib.rules.test.TestProvider.TestParams;
+import com.google.devtools.build.lib.rules.test.TestResult;
+import com.google.devtools.build.lib.rules.test.TestRunnerAction;
+import com.google.devtools.build.lib.runtime.TerminalTestResultNotifier.TestSummaryOptions;
+import com.google.devtools.build.lib.testutil.Suite;
+import com.google.devtools.build.lib.testutil.TestSpec;
+import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.build.lib.view.test.TestStatus.BlazeTestStatus;
+import com.google.devtools.build.lib.view.test.TestStatus.TestResultData;
+import com.google.devtools.common.options.OptionsParser;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@TestSpec(size = Suite.SMALL_TESTS)
+@RunWith(JUnit4.class)
+public class TestResultAnalyzerTest {
+
+ private TestResultAnalyzer underTest;
+
+ @Before
+ public void setUp() {
+ Path mockPath = mock(Path.class);
+ OptionsParser testSpecificOptions = OptionsParser.newOptionsParser(
+ TestSummaryOptions.class, ExecutionOptions.class);
+ EventBus mockBus = mock(EventBus.class);
+ underTest = new TestResultAnalyzer(
+ mockPath,
+ testSpecificOptions.getOptions(TestSummaryOptions.class),
+ testSpecificOptions.getOptions(ExecutionOptions.class),
+ mockBus);
+ }
+
+ @Test
+ public void testIncrementalAnalyzeSetsActionRanTrueWhenThereAreNonCachedResults() {
+ TestSummary.Builder summaryBuilder = makeTestSummaryBuilder();
+ assertFalse(summaryBuilder.peek().actionRan());
+
+ TestResultData testResultData = TestResultData.newBuilder().setRemotelyCached(false).build();
+ TestResult result = new TestResult(
+ mock(TestRunnerAction.class),
+ testResultData,
+ /*cached=*/false);
+
+ TestSummary.Builder newSummaryBuilder = underTest.incrementalAnalyze(summaryBuilder, result);
+ assertTrue(newSummaryBuilder.peek().actionRan());
+ }
+
+ @Test
+ public void testIncrementalAnalyzeSetsActionRanFalseForLocallyCachedTests() {
+ TestSummary.Builder summaryBuilder = makeTestSummaryBuilder();
+ assertFalse(summaryBuilder.peek().actionRan());
+
+ TestResultData testResultData = TestResultData.newBuilder().setRemotelyCached(false).build();
+ TestResult result = new TestResult(
+ mock(TestRunnerAction.class),
+ testResultData,
+ /*cached=*/true);
+
+ TestSummary.Builder newSummaryBuilder = underTest.incrementalAnalyze(summaryBuilder, result);
+ assertFalse(newSummaryBuilder.peek().actionRan());
+ }
+
+ @Test
+ public void testIncrementalAnalyzeSetsActionRanFalseForRemotelyCachedTests() {
+ TestSummary.Builder summaryBuilder = makeTestSummaryBuilder();
+ assertFalse(summaryBuilder.peek().actionRan());
+
+ TestResultData testResultData = TestResultData.newBuilder().setRemotelyCached(true).build();
+ TestResult result = new TestResult(
+ mock(TestRunnerAction.class),
+ testResultData,
+ /*cached=*/false);
+
+ TestSummary.Builder newSummaryBuilder = underTest.incrementalAnalyze(summaryBuilder, result);
+ assertFalse(newSummaryBuilder.peek().actionRan());
+ }
+
+ @Test
+ public void testIncrementalAnalyzeKeepsActionRanTrueWhenAlreadyTrueAndNewCachedResults() {
+ TestSummary.Builder summaryBuilder = makeTestSummaryBuilder().setActionRan(true);
+
+ TestResultData testResultData = TestResultData.newBuilder().setRemotelyCached(true).build();
+ TestResult result = new TestResult(
+ mock(TestRunnerAction.class),
+ testResultData,
+ /*cached=*/true);
+
+ TestSummary.Builder newSummaryBuilder = underTest.incrementalAnalyze(summaryBuilder, result);
+ assertTrue(newSummaryBuilder.peek().actionRan());
+ }
+
+ private TestSummary.Builder makeTestSummaryBuilder() {
+ // a lot of mocks to mock out fetching the TestTimeout configuration needed by
+ // {@link TestResultAnalyzer#shouldEmitTestSizeWarningInSummary(...)
+ TestParams mockParams = mock(TestParams.class);
+ when(mockParams.getTimeout()).thenReturn(TestTimeout.LONG);
+ TestProvider testProvider = new TestProvider(mockParams, ImmutableList.<String>of());
+
+ ConfiguredTarget mockTarget = mock(ConfiguredTarget.class);
+ when(mockTarget.getProvider(TestProvider.class)).thenReturn(testProvider);
+
+ return TestSummary.newBuilder()
+ .setStatus(BlazeTestStatus.PASSED)
+ .setTarget(mockTarget);
+
+ }
+
+}
diff --git a/src/test/java/com/google/devtools/build/lib/runtime/TestSummaryTest.java b/src/test/java/com/google/devtools/build/lib/runtime/TestSummaryTest.java
new file mode 100644
index 0000000000..e08df35db2
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/runtime/TestSummaryTest.java
@@ -0,0 +1,492 @@
+// Copyright 2015 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.runtime;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.AdditionalMatchers.find;
+import static org.mockito.AdditionalMatchers.not;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Matchers.contains;
+import static org.mockito.Mockito.when;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.util.BlazeClock;
+import com.google.devtools.build.lib.util.io.AnsiTerminalPrinter;
+import com.google.devtools.build.lib.vfs.FileSystem;
+import com.google.devtools.build.lib.vfs.FileSystemUtils;
+import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem;
+import com.google.devtools.build.lib.view.test.TestStatus.BlazeTestStatus;
+import com.google.devtools.build.lib.view.test.TestStatus.FailedTestCasesStatus;
+import com.google.devtools.build.lib.view.test.TestStatus.TestCase;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.InOrder;
+import org.mockito.Mockito;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@RunWith(JUnit4.class)
+public class TestSummaryTest {
+
+ private static final String ANY_STRING = ".*?";
+ private static final String PATH = "package";
+ private static final String TARGET_NAME = "name";
+ private ConfiguredTarget stubTarget;
+ private static final List<Long> SMALL_TIMING = ImmutableList.of(1L, 2L, 3L, 4L);
+
+ private static final int CACHED = SMALL_TIMING.size();
+ private static final int NOT_CACHED = 0;
+
+ private FileSystem fs;
+ private TestSummary.Builder basicBuilder;
+
+ @Before
+ public void setUp() throws Exception {
+ fs = new InMemoryFileSystem(BlazeClock.instance());
+ stubTarget = stubTarget();
+ basicBuilder = getTemplateBuilder();
+ }
+
+ private TestSummary.Builder getTemplateBuilder() {
+ return TestSummary.newBuilder()
+ .setTarget(stubTarget)
+ .setStatus(BlazeTestStatus.PASSED)
+ .setNumCached(NOT_CACHED)
+ .setActionRan(true)
+ .setRanRemotely(false)
+ .setWasUnreportedWrongSize(false);
+ }
+
+ private List<Path> getPathList(String... names) {
+ List<Path> list = new ArrayList<>();
+ for (String name : names) {
+ list.add(fs.getPath(name));
+ }
+ return list;
+ }
+
+ @Test
+ public void testShouldProperlyTestLabels() throws Exception {
+ ConfiguredTarget target = target("somepath", "MyTarget");
+ String expectedString = ANY_STRING + "//somepath:MyTarget" + ANY_STRING;
+ AnsiTerminalPrinter terminalPrinter = Mockito.mock(AnsiTerminalPrinter.class);
+
+ TestSummary summaryStatus = createTestSummary(target, BlazeTestStatus.PASSED, CACHED);
+ TestSummaryPrinter.print(summaryStatus, terminalPrinter, true, false);
+ terminalPrinter.print(find(expectedString));
+ }
+
+ @Test
+ public void testShouldPrintPassedStatus() throws Exception {
+ String expectedString = ANY_STRING + "INFO" + ANY_STRING + BlazeTestStatus.PASSED + ANY_STRING;
+ AnsiTerminalPrinter terminalPrinter = Mockito.mock(AnsiTerminalPrinter.class);
+
+ TestSummary summary = createTestSummary(stubTarget, BlazeTestStatus.PASSED, NOT_CACHED);
+ TestSummaryPrinter.print(summary, terminalPrinter, true, false);
+
+ terminalPrinter.print(find(expectedString));
+ }
+
+ @Test
+ public void testShouldPrintFailedStatus() throws Exception {
+ String expectedString = ANY_STRING + "ERROR" + ANY_STRING + BlazeTestStatus.FAILED + ANY_STRING;
+ AnsiTerminalPrinter terminalPrinter = Mockito.mock(AnsiTerminalPrinter.class);
+
+ TestSummary summary = createTestSummary(stubTarget, BlazeTestStatus.FAILED, NOT_CACHED);
+
+ TestSummaryPrinter.print(summary, terminalPrinter, true, false);
+
+ terminalPrinter.print(find(expectedString));
+ }
+
+ @Test
+ public void testShouldPrintCachedStatus() throws Exception {
+ String expectedString = ANY_STRING + "\\(cached" + ANY_STRING;
+ AnsiTerminalPrinter terminalPrinter = Mockito.mock(AnsiTerminalPrinter.class);
+
+ TestSummary summary = createTestSummary(stubTarget, BlazeTestStatus.PASSED, CACHED);
+
+ TestSummaryPrinter.print(summary, terminalPrinter, true, false);
+
+ terminalPrinter.print(find(expectedString));
+ }
+
+ @Test
+ public void testPartialCachedStatus() throws Exception {
+ String expectedString = ANY_STRING + "\\(3/4 cached" + ANY_STRING;
+ AnsiTerminalPrinter terminalPrinter = Mockito.mock(AnsiTerminalPrinter.class);
+
+ TestSummary summary = createTestSummary(stubTarget, BlazeTestStatus.PASSED, CACHED - 1);
+ TestSummaryPrinter.print(summary, terminalPrinter, true, false);
+ terminalPrinter.print(find(expectedString));
+ }
+
+ @Test
+ public void testIncompleteCached() throws Exception {
+ AnsiTerminalPrinter terminalPrinter = Mockito.mock(AnsiTerminalPrinter.class);
+ TestSummary summary = createTestSummary(stubTarget, BlazeTestStatus.INCOMPLETE, CACHED - 1);
+ TestSummaryPrinter.print(summary, terminalPrinter, true, false);
+ verify(terminalPrinter).print(not(contains("cached")));
+ }
+
+ @Test
+ public void testShouldPrintUncachedStatus() throws Exception {
+ AnsiTerminalPrinter terminalPrinter = Mockito.mock(AnsiTerminalPrinter.class);
+ TestSummary summary = createTestSummary(stubTarget, BlazeTestStatus.PASSED, NOT_CACHED);
+ TestSummaryPrinter.print(summary, terminalPrinter, true, false);
+ verify(terminalPrinter).print(not(contains("cached")));
+ }
+
+ @Test
+ public void testNoTiming() throws Exception {
+ String expectedString = ANY_STRING + "INFO" + ANY_STRING + BlazeTestStatus.PASSED;
+ AnsiTerminalPrinter terminalPrinter = Mockito.mock(AnsiTerminalPrinter.class);
+
+ TestSummary summary = createTestSummary(stubTarget, BlazeTestStatus.PASSED, NOT_CACHED);
+
+ TestSummaryPrinter.print(summary, terminalPrinter, true, false);
+ terminalPrinter.print(find(expectedString));
+ }
+
+ @Test
+ public void testBuilder() throws Exception {
+ // No need to copy if built twice in a row; no direct setters on the object.
+ TestSummary summary = basicBuilder.build();
+ TestSummary sameSummary = basicBuilder.build();
+ assertSame(summary, sameSummary);
+
+ basicBuilder.addTestTimes(ImmutableList.of(40L));
+
+ TestSummary summaryCopy = basicBuilder.build();
+ assertEquals(summary.getTarget(), summaryCopy.getTarget());
+ assertEquals(summary.getStatus(), summaryCopy.getStatus());
+ assertEquals(summary.numCached(), summaryCopy.numCached());
+ assertNotSame(summary, summaryCopy);
+ assertEquals(0, summary.totalRuns());
+ assertEquals(1, summaryCopy.totalRuns());
+
+ // Check that the builder can add a new warning to the copy,
+ // despite the immutability of the original.
+ basicBuilder.addTestTimes(ImmutableList.of(60L));
+
+ TestSummary fiftyCached = basicBuilder.setNumCached(50).build();
+ assertEquals(summary.getStatus(), fiftyCached.getStatus());
+ assertEquals(50, fiftyCached.numCached());
+ assertEquals(2, fiftyCached.totalRuns());
+
+ TestSummary sixtyCached = basicBuilder.setNumCached(60).build();
+ assertEquals(60, sixtyCached.numCached());
+ assertEquals(50, fiftyCached.numCached());
+
+ TestSummary failedCacheTemplate = TestSummary.newBuilderFromExisting(fiftyCached)
+ .setStatus(BlazeTestStatus.FAILED)
+ .build();
+ assertEquals(50, failedCacheTemplate.numCached());
+ assertEquals(BlazeTestStatus.FAILED, failedCacheTemplate.getStatus());
+ }
+
+ @Test
+ public void testSingleTime() throws Exception {
+ String expectedString = ANY_STRING + "INFO" + ANY_STRING + BlazeTestStatus.PASSED + ANY_STRING +
+ "in 3.4s";
+ AnsiTerminalPrinter terminalPrinter = Mockito.mock(AnsiTerminalPrinter.class);
+
+ TestSummary summary = basicBuilder.addTestTimes(ImmutableList.of(3412L)).build();
+ TestSummaryPrinter.print(summary, terminalPrinter, true, false);
+ terminalPrinter.print(find(expectedString));
+ }
+
+ @Test
+ public void testNoTime() throws Exception {
+ // The last part matches anything not containing "in".
+ String expectedString = ANY_STRING + "INFO" + ANY_STRING + BlazeTestStatus.PASSED + "(?!in)*";
+ AnsiTerminalPrinter terminalPrinter = Mockito.mock(AnsiTerminalPrinter.class);
+
+ TestSummary summary = basicBuilder.addTestTimes(ImmutableList.of(3412L)).build();
+ TestSummaryPrinter.print(summary, terminalPrinter, false, false);
+ terminalPrinter.print(find(expectedString));
+ }
+
+ @Test
+ public void testMultipleTimes() throws Exception {
+ String expectedString = ANY_STRING + "INFO" + ANY_STRING + BlazeTestStatus.PASSED + ANY_STRING +
+ "\n Stats over 3 runs: max = 3.0s, min = 1.0s, " +
+ "avg = 2.0s, dev = 0.8s";
+ AnsiTerminalPrinter terminalPrinter = Mockito.mock(AnsiTerminalPrinter.class);
+ TestSummary summary = basicBuilder
+ .addTestTimes(ImmutableList.of(1000L, 2000L, 3000L))
+ .build();
+ TestSummaryPrinter.print(summary, terminalPrinter, true, false);
+ terminalPrinter.print(find(expectedString));
+ }
+
+ @Test
+ public void testCoverageDataReferences() throws Exception {
+ List<Path> paths = getPathList("/cov1.dat", "/cov2.dat", "/cov3.dat", "/cov4.dat");
+ FileSystemUtils.writeContentAsLatin1(paths.get(1), "something");
+ FileSystemUtils.writeContentAsLatin1(paths.get(3), "");
+ FileSystemUtils.writeContentAsLatin1(paths.get(3), "something else");
+ TestSummary summary = basicBuilder.addCoverageFiles(paths).build();
+
+ AnsiTerminalPrinter terminalPrinter = Mockito.mock(AnsiTerminalPrinter.class);
+ TestSummaryPrinter.print(summary, terminalPrinter, true, false);
+ verify(terminalPrinter).print(find(ANY_STRING + "INFO" + ANY_STRING + BlazeTestStatus.PASSED));
+ verify(terminalPrinter).print(find(" /cov2.dat"));
+ verify(terminalPrinter).print(find(" /cov4.dat"));
+ }
+
+ @Test
+ public void testFlakyAttempts() throws Exception {
+ String expectedString = ANY_STRING + "WARNING" + ANY_STRING + BlazeTestStatus.FLAKY +
+ ANY_STRING + ", failed in 2 out of 3";
+ AnsiTerminalPrinter terminalPrinter = Mockito.mock(AnsiTerminalPrinter.class);
+
+ TestSummary summary = basicBuilder
+ .setStatus(BlazeTestStatus.FLAKY)
+ .addPassedLogs(getPathList("/a"))
+ .addFailedLogs(getPathList("/b", "/c"))
+ .build();
+ TestSummaryPrinter.print(summary, terminalPrinter, true, false);
+ terminalPrinter.print(find(expectedString));
+ }
+
+ @Test
+ public void testNumberOfFailedRuns() throws Exception {
+ String expectedString = ANY_STRING + "ERROR" + ANY_STRING + BlazeTestStatus.FAILED +
+ ANY_STRING + "in 2 out of 3";
+ AnsiTerminalPrinter terminalPrinter = Mockito.mock(AnsiTerminalPrinter.class);
+
+ TestSummary summary = basicBuilder
+ .setStatus(BlazeTestStatus.FAILED)
+ .addPassedLogs(getPathList("/a"))
+ .addFailedLogs(getPathList("/b", "/c"))
+ .build();
+ TestSummaryPrinter.print(summary, terminalPrinter, true, false);
+ terminalPrinter.print(find(expectedString));
+ }
+
+ @Test
+ public void testFileNamesNotShown() throws Exception {
+ List<TestCase> emptyDetails = ImmutableList.of();
+ TestSummary summary = basicBuilder
+ .setStatus(BlazeTestStatus.FAILED)
+ .addPassedLogs(getPathList("/apple"))
+ .addFailedLogs(getPathList("/pear"))
+ .addCoverageFiles(getPathList("/maracuja"))
+ .addFailedTestCases(emptyDetails, FailedTestCasesStatus.FULL)
+ .build();
+
+ // Check that only //package:name is printed.
+ AnsiTerminalPrinter printer = Mockito.mock(AnsiTerminalPrinter.class);
+ TestSummaryPrinter.print(summary, printer, true, true);
+ verify(printer).print(contains("//package:name"));
+ }
+
+ @Test
+ public void testMessageShownWhenTestCasesMissing() throws Exception {
+ ImmutableList<TestCase> emptyList = ImmutableList.of();
+ TestSummary summary = createTestSummaryWithDetails(
+ BlazeTestStatus.FAILED, emptyList, FailedTestCasesStatus.NOT_AVAILABLE);
+
+ AnsiTerminalPrinter printer = Mockito.mock(AnsiTerminalPrinter.class);
+ TestSummaryPrinter.print(summary, printer, true, true);
+ verify(printer).print(contains("//package:name"));
+ verify(printer).print(contains("not available"));
+ }
+
+ @Test
+ public void testMessageShownForPartialResults() throws Exception {
+ ImmutableList<TestCase> testCases =
+ ImmutableList.of(newDetail("orange", TestCase.Status.FAILED, 1500L));
+ TestSummary summary = createTestSummaryWithDetails(BlazeTestStatus.FAILED, testCases,
+ FailedTestCasesStatus.PARTIAL);
+
+ AnsiTerminalPrinter printer = Mockito.mock(AnsiTerminalPrinter.class);
+ TestSummaryPrinter.print(summary, printer, true, true);
+ verify(printer).print(contains("//package:name"));
+ verify(printer).print(find("FAILED.*orange"));
+ verify(printer).print(contains("incomplete"));
+ }
+
+ private TestCase newDetail(String name, TestCase.Status status, long duration) {
+ return TestCase.newBuilder()
+ .setName(name)
+ .setStatus(status)
+ .setRunDurationMillis(duration).build();
+ }
+
+ @Test
+ public void testTestCaseNamesShownWhenNeeded() throws Exception {
+ TestCase detailPassed =
+ newDetail("strawberry", TestCase.Status.PASSED, 1000L);
+ TestCase detailFailed =
+ newDetail("orange", TestCase.Status.FAILED, 1500L);
+
+ TestSummary summaryPassed = createTestSummaryWithDetails(
+ BlazeTestStatus.PASSED, Arrays.asList(detailPassed));
+
+ TestSummary summaryFailed = createTestSummaryWithDetails(
+ BlazeTestStatus.FAILED, Arrays.asList(detailPassed, detailFailed));
+ assertEquals(BlazeTestStatus.FAILED, summaryFailed.getStatus());
+
+ AnsiTerminalPrinter printerPassed = Mockito.mock(AnsiTerminalPrinter.class);
+ TestSummaryPrinter.print(summaryPassed, printerPassed, true, true);
+ verify(printerPassed).print(contains("//package:name"));
+
+ AnsiTerminalPrinter printerFailed = Mockito.mock(AnsiTerminalPrinter.class);
+ TestSummaryPrinter.print(summaryFailed, printerFailed, true, true);
+ verify(printerFailed).print(contains("//package:name"));
+ verify(printerFailed).print(find("FAILED.*orange *\\(1\\.5"));
+ }
+
+ @Test
+ public void testTestCaseNamesOrdered() throws Exception {
+ TestCase[] details = {
+ newDetail("apple", TestCase.Status.FAILED, 1000L),
+ newDetail("banana", TestCase.Status.FAILED, 1000L),
+ newDetail("cranberry", TestCase.Status.FAILED, 1000L)
+ };
+
+ // The exceedingly dumb approach: writing all the permutations down manually
+ // is simply easier than any way of generating them.
+ int[][] permutations = {
+ { 0, 1, 2 },
+ { 0, 2, 1 },
+ { 1, 0, 2 },
+ { 1, 2, 0 },
+ { 2, 0, 1 },
+ { 2, 1, 0 }
+ };
+
+ for (int[] permutation : permutations) {
+ List<TestCase> permutatedDetails = new ArrayList<>();
+
+ for (int element : permutation) {
+ permutatedDetails.add(details[element]);
+ }
+
+ TestSummary summary = createTestSummaryWithDetails(BlazeTestStatus.FAILED, permutatedDetails);
+
+ // A mock that checks the ordering of method calls
+ AnsiTerminalPrinter printer = Mockito.mock(AnsiTerminalPrinter.class);
+ TestSummaryPrinter.print(summary, printer, true, true);
+ InOrder order = Mockito.inOrder(printer);
+ order.verify(printer).print(contains("//package:name"));
+ order.verify(printer).print(find("FAILED.*apple"));
+ order.verify(printer).print(find("FAILED.*banana"));
+ order.verify(printer).print(find("FAILED.*cranberry"));
+ }
+ }
+
+ @Test
+ public void testCachedResultsFirstInSort() throws Exception {
+ TestSummary summaryFailedCached = createTestSummary(BlazeTestStatus.FAILED, CACHED);
+ TestSummary summaryFailedNotCached = createTestSummary(BlazeTestStatus.FAILED, NOT_CACHED);
+ TestSummary summaryPassedCached = createTestSummary(BlazeTestStatus.PASSED, CACHED);
+ TestSummary summaryPassedNotCached = createTestSummary(BlazeTestStatus.PASSED, NOT_CACHED);
+
+ // This way we can make the test independent from the sort order of FAILEd
+ // and PASSED.
+
+ assertTrue(summaryFailedCached.compareTo(summaryPassedNotCached) < 0);
+ assertTrue(summaryPassedCached.compareTo(summaryFailedNotCached) < 0);
+ }
+
+ @Test
+ public void testCollectingFailedDetails() throws Exception {
+ TestCase rootCase = TestCase.newBuilder()
+ .setName("tests")
+ .setRunDurationMillis(5000L)
+ .addChild(newDetail("apple", TestCase.Status.FAILED, 1000L))
+ .addChild(newDetail("banana", TestCase.Status.PASSED, 1000L))
+ .addChild(newDetail("cherry", TestCase.Status.ERROR, 1000L))
+ .build();
+
+ TestSummary summary = getTemplateBuilder()
+ .collectFailedTests(rootCase)
+ .setStatus(BlazeTestStatus.FAILED)
+ .build();
+
+ AnsiTerminalPrinter printer = Mockito.mock(AnsiTerminalPrinter.class);
+ TestSummaryPrinter.print(summary, printer, true, true);
+ verify(printer).print(contains("//package:name"));
+ verify(printer).print(find("FAILED.*apple"));
+ verify(printer).print(find("ERROR.*cherry"));
+ }
+
+ private ConfiguredTarget target(String path, String targetName) throws Exception {
+ ConfiguredTarget target = Mockito.mock(ConfiguredTarget.class);
+ when(target.getLabel()).thenReturn(Label.create(path, targetName));
+ return target;
+ }
+
+ private ConfiguredTarget stubTarget() throws Exception {
+ return target(PATH, TARGET_NAME);
+ }
+
+ private TestSummary createTestSummaryWithDetails(BlazeTestStatus status,
+ List<TestCase> details) {
+ TestSummary summary = getTemplateBuilder()
+ .setStatus(status)
+ .addFailedTestCases(details, FailedTestCasesStatus.FULL)
+ .build();
+ return summary;
+ }
+
+ private TestSummary createTestSummaryWithDetails(
+ BlazeTestStatus status, List<TestCase> testCaseList,
+ FailedTestCasesStatus detailsStatus) {
+ TestSummary summary = getTemplateBuilder()
+ .setStatus(status)
+ .addFailedTestCases(testCaseList, detailsStatus)
+ .build();
+ return summary;
+ }
+
+ private static TestSummary createTestSummary(ConfiguredTarget target, BlazeTestStatus status,
+ int numCached) {
+ ImmutableList<TestCase> emptyList = ImmutableList.of();
+ TestSummary summary = TestSummary.newBuilder()
+ .setTarget(target)
+ .setStatus(status)
+ .setNumCached(numCached)
+ .setActionRan(true)
+ .setRanRemotely(false)
+ .setWasUnreportedWrongSize(false)
+ .addFailedTestCases(emptyList, FailedTestCasesStatus.FULL)
+ .addTestTimes(SMALL_TIMING)
+ .build();
+ return summary;
+ }
+
+ private TestSummary createTestSummary(BlazeTestStatus status, int numCached) {
+ TestSummary summary = getTemplateBuilder()
+ .setStatus(status)
+ .setNumCached(numCached)
+ .addTestTimes(SMALL_TIMING)
+ .build();
+ return summary;
+ }
+}