diff options
author | 2016-09-22 04:16:39 +0000 | |
---|---|---|
committer | 2016-09-22 09:57:49 +0000 | |
commit | 36395c417899bd4009efc3a6cda5ea838f3d98ef (patch) | |
tree | e8a5cfed427981772b70628a76995f0a2308e4b4 /src/java_tools/junitrunner | |
parent | ba80dfd9bb2aee3f45201f3d4e6c7a1b6dc4f228 (diff) |
Bazel to support external links integration. This is so that the tests can inject custom extra data (link, icons, etc) so that a test method can be associated with an external tool.
--
MOS_MIGRATED_REVID=133912980
Diffstat (limited to 'src/java_tools/junitrunner')
8 files changed, 279 insertions, 11 deletions
diff --git a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/model/TestCaseNode.java b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/model/TestCaseNode.java index 075f7f0b60..7c2567434f 100644 --- a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/model/TestCaseNode.java +++ b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/model/TestCaseNode.java @@ -17,6 +17,8 @@ package com.google.testing.junit.runner.model; import static com.google.testing.junit.runner.util.TestPropertyExporter.INITIAL_INDEX_FOR_REPEATED_PROPERTY; import com.google.testing.junit.runner.model.TestResult.Status; +import com.google.testing.junit.runner.util.TestIntegration; +import com.google.testing.junit.runner.util.TestIntegrationsExporter; import com.google.testing.junit.runner.util.TestPropertyExporter; import java.util.ArrayList; import java.util.Collections; @@ -24,22 +26,24 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Queue; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentMap; import javax.annotation.Nullable; import org.junit.runner.Description; -/** - * A leaf in the test suite model. - */ -class TestCaseNode extends TestNode implements TestPropertyExporter.Callback { +/** A leaf in the test suite model. */ +class TestCaseNode extends TestNode + implements TestPropertyExporter.Callback, TestIntegrationsExporter.Callback { private final TestSuiteNode parent; private final Map<String, String> properties = new ConcurrentHashMap<>(); private final Map<String, Integer> repeatedPropertyNamesToRepetitions = new HashMap<>(); private final Queue<Throwable> globalFailures = new ConcurrentLinkedQueue<>(); private final ConcurrentMap<Description, List<Throwable>> dynamicTestToFailures = new ConcurrentHashMap<>(); + private final Set<TestIntegration> integrations = + Collections.newSetFromMap(new ConcurrentHashMap<TestIntegration, Boolean>()); @Nullable private volatile TestInterval runTimeInterval = null; private volatile State state = State.INITIAL; @@ -86,6 +90,11 @@ class TestCaseNode extends TestNode implements TestPropertyExporter.Callback { } @Override + public void exportTestIntegration(TestIntegration testIntegration) { + integrations.add(testIntegration); + } + + @Override public void testSkipped(long now) { compareAndSetState(State.STARTED, State.SKIPPED, now); } @@ -207,6 +216,7 @@ class TestCaseNode extends TestNode implements TestPropertyExporter.Callback { .numTests(numTests) .numFailures(numFailures) .childResults(childResults) + .integrations(integrations) .build(); } @@ -229,6 +239,7 @@ class TestCaseNode extends TestNode implements TestPropertyExporter.Callback { .numTests(1) .numFailures(failed ? 1 : 0) .childResults(Collections.<TestResult>emptyList()) + .integrations(Collections.<TestIntegration>emptySet()) .build(); } diff --git a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/model/TestResult.java b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/model/TestResult.java index 047b769766..e931eb423b 100644 --- a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/model/TestResult.java +++ b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/model/TestResult.java @@ -14,13 +14,13 @@ package com.google.testing.junit.runner.model; +import com.google.testing.junit.runner.util.TestIntegration; import java.util.List; import java.util.Map; +import java.util.Set; import javax.annotation.Nullable; -/** - * Result of executing a test suite or test case. - */ +/** Result of executing a test suite or test case. */ final class TestResult { /** @@ -78,12 +78,15 @@ final class TestResult { } } - private final String name, className; + private final String name; + private final String className; private final Map<String, String> properties; private final List<Throwable> failures; @Nullable private final TestInterval runTime; + private final Set<TestIntegration> integrations; private final Status status; - private final int numTests, numFailures; + private final int numTests; + private final int numFailures; private final List<TestResult> childResults; private TestResult(Builder builder) { @@ -96,6 +99,7 @@ final class TestResult { numTests = checkNotNull(builder.numTests, "numTests not set"); numFailures = checkNotNull(builder.numFailures, "numFailures not set"); childResults = checkNotNull(builder.childResults, "childResults not set"); + integrations = checkNotNull(builder.integrations, "integrations not set"); } String getName() { @@ -114,6 +118,10 @@ final class TestResult { return failures; } + Set<TestIntegration> getIntegrations() { + return integrations; + } + @Nullable TestInterval getRunTimeInterval() { return runTime; @@ -152,6 +160,7 @@ final class TestResult { private Map<String, String> properties = null; private List<Throwable> failures = null; @Nullable private TestInterval runTime = null; + private Set<TestIntegration> integrations = null; private Status status = null; private Integer numTests = null; private Integer numFailures = null; @@ -174,6 +183,11 @@ final class TestResult { return this; } + Builder integrations(Set<TestIntegration> integrations) { + this.integrations = checkNullToNotNull(this.integrations, integrations, "integrations"); + return this; + } + Builder failures(List<Throwable> failures) { this.failures = checkNullToNotNull(this.failures, failures, "failures"); return this; diff --git a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/model/TestSuiteModel.java b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/model/TestSuiteModel.java index 350dbbf42c..92193460ad 100644 --- a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/model/TestSuiteModel.java +++ b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/model/TestSuiteModel.java @@ -19,6 +19,7 @@ import static java.util.concurrent.TimeUnit.NANOSECONDS; import com.google.testing.junit.junit4.runner.DynamicTestException; import com.google.testing.junit.runner.sharding.ShardingEnvironment; import com.google.testing.junit.runner.sharding.ShardingFilters; +import com.google.testing.junit.runner.util.TestIntegrationsRunnerIntegration; import com.google.testing.junit.runner.util.TestPropertyRunnerIntegration; import com.google.testing.junit.runner.util.Ticker; import java.io.IOException; @@ -106,6 +107,7 @@ public class TestSuiteModel { if (testCase != null) { testCase.started(currentMillis()); TestPropertyRunnerIntegration.setTestCaseForThread(testCase); + TestIntegrationsRunnerIntegration.setTestCaseForThread(testCase); } } @@ -341,4 +343,4 @@ public class TestSuiteModel { } return filteredAndConvertedTests; } -}
\ No newline at end of file +} diff --git a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/model/TestSuiteNode.java b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/model/TestSuiteNode.java index 2ebf6ae6e1..73996b15dd 100644 --- a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/model/TestSuiteNode.java +++ b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/model/TestSuiteNode.java @@ -15,6 +15,7 @@ package com.google.testing.junit.runner.model; import com.google.testing.junit.runner.model.TestResult.Status; +import com.google.testing.junit.runner.util.TestIntegration; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; @@ -88,7 +89,8 @@ class TestSuiteNode extends TestNode { @Override protected TestResult buildResult() { TestInterval runTime = null; - int numTests = 0, numFailures = 0; + int numTests = 0; + int numFailures = 0; LinkedList<TestResult> childResults = new LinkedList<>(); for (TestNode child : children) { @@ -118,6 +120,7 @@ class TestSuiteNode extends TestNode { .numTests(numTests) .numFailures(numFailures) .childResults(childResults) + .integrations(Collections.<TestIntegration>emptySet()) .build(); } } diff --git a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/util/BUILD b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/util/BUILD index a1a28b5406..ab65e19f9c 100644 --- a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/util/BUILD +++ b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/util/BUILD @@ -11,6 +11,7 @@ java_library( name = "util", srcs = glob(["*.java"]), deps = [ + "//third_party:auto_value", "//third_party:jsr305", "//third_party:junit4", ], diff --git a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/util/TestIntegration.java b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/util/TestIntegration.java new file mode 100644 index 0000000000..18dfc05414 --- /dev/null +++ b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/util/TestIntegration.java @@ -0,0 +1,110 @@ +// Copyright 2009 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.testing.junit.runner.util; + +import com.google.auto.value.AutoValue; +import java.util.EnumMap; +import java.util.Map; + +/** TestIntegration represents an external link that is integrated with the test results. */ +@AutoValue +public abstract class TestIntegration { + + /** Represents each available field for TestIntegration. */ + public enum ExternalLinkAttribute { + NAME, + URL, + CONTACT_EMAIL, + COMPONENT_ID, + DESCRIPTION, + ICON_NAME, + ICON_URL, + BACKGROUND_COLOR, + FOREGROUND_COLOR; + + /** Gets the string representation of the current enum. */ + public String getXmlAttributeName() { + return name().toLowerCase(); + } + } + + // Group or user name responsible for this external integration. + abstract String contactEmail(); + // Component id (numeric) for this external integration. + abstract String componentId(); + // Display name of this external integration. + abstract String name(); + // URL that will display more data about this test result or integration. + abstract String url(); + // Optional: URL or name of the icon to be displayed. + abstract String iconUrl(); + + abstract String iconName(); + // Optional: Textual description that shows up as tooltip. + abstract String description(); + // Optional: Foreground color. + abstract String foregroundColor(); + // Optional: Background color. + abstract String backgroundColor(); + + static Builder builder() { + return new AutoValue_TestIntegration.Builder() + .setIconName("") + .setIconUrl("") + .setDescription("") + .setForegroundColor("") + .setBackgroundColor(""); + } + + @AutoValue.Builder + abstract static class Builder { + public abstract Builder setContactEmail(String email); + + public abstract Builder setComponentId(String id); + + public abstract Builder setName(String name); + + public abstract Builder setUrl(String url); + + public abstract Builder setIconUrl(String iconUrl); + + public abstract Builder setIconName(String iconName); + + public abstract Builder setDescription(String description); + + public abstract Builder setForegroundColor(String foregroundColor); + + public abstract Builder setBackgroundColor(String backgroundColor); + + abstract TestIntegration build(); + } + + /* + * getAttributeValueMap returns all of this TestIntegration's values in a Map. + */ + public Map<ExternalLinkAttribute, String> getAttributeValueMap() { + Map<ExternalLinkAttribute, String> map = new EnumMap<>(ExternalLinkAttribute.class); + map.put(ExternalLinkAttribute.NAME, name()); + map.put(ExternalLinkAttribute.URL, url()); + map.put(ExternalLinkAttribute.CONTACT_EMAIL, contactEmail()); + map.put(ExternalLinkAttribute.COMPONENT_ID, componentId()); + map.put(ExternalLinkAttribute.DESCRIPTION, description()); + map.put(ExternalLinkAttribute.ICON_NAME, iconName()); + map.put(ExternalLinkAttribute.ICON_URL, iconUrl()); + map.put(ExternalLinkAttribute.BACKGROUND_COLOR, backgroundColor()); + map.put(ExternalLinkAttribute.FOREGROUND_COLOR, foregroundColor()); + return map; + } +} diff --git a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/util/TestIntegrationsExporter.java b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/util/TestIntegrationsExporter.java new file mode 100644 index 0000000000..486fba4242 --- /dev/null +++ b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/util/TestIntegrationsExporter.java @@ -0,0 +1,70 @@ +// Copyright 2016 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.testing.junit.runner.util; + +import static com.google.testing.junit.runner.util.TestIntegrationsRunnerIntegration.getCallbackForThread; + +/** Exports test TestIntegrations to the test XML. */ +public class TestIntegrationsExporter { + /* + * The global {@code TestIntegrationsExporter}, which writes the properties into + * the test XML if the test is running from the command line. + * + * <p>If you have test infrastructure that needs to export properties, consider + * injecting an instance of {@code TestIntegrationsExporter}. Your tests can + * use one of the static methods in this class to create a fake instance. + */ + public static final TestIntegrationsExporter INSTANCE = + new TestIntegrationsExporter(new DefaultCallback()); + + private final Callback callback; + + /** + * Creates a fake {@code TestIntegrationsExporter} instance, passing values to the passed-in + * callback. + * + * @param callback Callback to use when values are exported + * @return exporter instance + */ + public static TestIntegrationsExporter createFake(final Callback callback) { + return new TestIntegrationsExporter(callback); + } + + protected TestIntegrationsExporter(Callback callback) { + this.callback = callback; + } + + public void newTestIntegration(TestIntegration testIntegration) { + callback.exportTestIntegration(testIntegration); + } + + /** Callback that is used to store TestIntegration in the model. */ + public interface Callback { + /** Export the TestIntegration. */ + void exportTestIntegration(TestIntegration testIntegration); + } + + /** + * Default callback implementation. Calls the test runner model to write the external integrations + * to the XML. + */ + private static class DefaultCallback implements Callback { + + @Override + public void exportTestIntegration(TestIntegration testIntegration) { + getCallbackForThread().exportTestIntegration(testIntegration); + } + } +} diff --git a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/util/TestIntegrationsRunnerIntegration.java b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/util/TestIntegrationsRunnerIntegration.java new file mode 100644 index 0000000000..78a8894f9a --- /dev/null +++ b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/util/TestIntegrationsRunnerIntegration.java @@ -0,0 +1,57 @@ +// Copyright 2011 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.testing.junit.runner.util; + +import com.google.testing.junit.runner.util.TestIntegrationsExporter.Callback; +import javax.annotation.Nullable; + +/** JUnit runner integration code for TestIntegration. */ +public class TestIntegrationsRunnerIntegration { + private static final ThreadLocal<Callback> callbackForThread = + new ThreadLocal<Callback>() { + @Override + protected Callback initialValue() { + return NoOpCallback.INSTANCE; + } + }; + + /** + * Sets the per-thread callback. + * + * @param callback Callback + */ + public static Callback setTestCaseForThread(@Nullable Callback callback) { + Callback previousCallback = callbackForThread.get(); + if (callback == null) { + callbackForThread.remove(); + } else { + callbackForThread.set(callback); + } + return previousCallback; + } + + static Callback getCallbackForThread() { + // TODO(bazel-team): This won't work if the test is running in a different thread from the test + // runner. + return callbackForThread.get(); + } + + private static class NoOpCallback implements Callback { + private static final Callback INSTANCE = new NoOpCallback(); + + @Override + public void exportTestIntegration(TestIntegration testIntegration) {} + } +} |