blob: c31846a0f568715bf742a41dd692ddc9c683b092 [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14package com.google.devtools.build.lib.skyframe;
15
Googlerdb4c5502024-08-08 11:03:51 -070016import com.google.devtools.build.lib.actions.ActionExecutionException;
17import com.google.devtools.build.lib.actions.ActionLookupData;
18import com.google.devtools.build.lib.actions.ActionLookupValue;
janakra4634cf2017-08-24 09:23:39 +020019import com.google.devtools.build.lib.actions.Artifact;
20import com.google.devtools.build.lib.analysis.ConfiguredTarget;
janakr876deaa2021-02-17 07:49:48 -080021import com.google.devtools.build.lib.analysis.ConfiguredTargetValue;
Googlerbfd4e242016-07-15 22:23:37 +000022import com.google.devtools.build.lib.analysis.TopLevelArtifactContext;
Googlerdb4c5502024-08-08 11:03:51 -070023import com.google.devtools.build.lib.analysis.test.TestAttempt;
janakra4634cf2017-08-24 09:23:39 +020024import com.google.devtools.build.lib.analysis.test.TestProvider;
Googlerdb4c5502024-08-08 11:03:51 -070025import com.google.devtools.build.lib.analysis.test.TestResult;
26import com.google.devtools.build.lib.analysis.test.TestRunnerAction;
Lukacs Berki6e91eb92015-09-21 09:12:37 +000027import com.google.devtools.build.lib.cmdline.Label;
Googlerdb4c5502024-08-08 11:03:51 -070028import com.google.devtools.build.lib.server.FailureDetails.Execution.Code;
29import com.google.devtools.build.lib.util.DetailedExitCode;
30import com.google.devtools.build.lib.util.ExitCode;
31import com.google.devtools.build.lib.view.test.TestStatus.BlazeTestStatus;
32import com.google.devtools.build.lib.view.test.TestStatus.TestResultData;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010033import com.google.devtools.build.skyframe.SkyFunction;
34import com.google.devtools.build.skyframe.SkyKey;
35import com.google.devtools.build.skyframe.SkyValue;
Googlerdb4c5502024-08-08 11:03:51 -070036import com.google.devtools.build.skyframe.SkyframeLookupResult;
37import java.util.List;
Googler5cc598c2022-07-06 03:29:45 -070038import javax.annotation.Nullable;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010039
40/**
Dmitry Lomove2033b12015-08-19 16:57:49 +000041 * TestCompletionFunction builds all relevant test artifacts of a {@link
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010042 * com.google.devtools.build.lib.analysis.ConfiguredTarget}. This includes test shards and repeated
43 * runs.
44 */
45public final class TestCompletionFunction implements SkyFunction {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010046 @Override
Googler5cc598c2022-07-06 03:29:45 -070047 @Nullable
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +000048 public SkyValue compute(SkyKey skyKey, Environment env) throws InterruptedException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010049 TestCompletionValue.TestCompletionKey key =
50 (TestCompletionValue.TestCompletionKey) skyKey.argument();
janakr573807d2018-01-11 14:02:35 -080051 ConfiguredTargetKey ctKey = key.configuredTargetKey();
Googlerbfd4e242016-07-15 22:23:37 +000052 TopLevelArtifactContext ctx = key.topLevelArtifactContext();
Googlerdb4c5502024-08-08 11:03:51 -070053 if (env.getValue(TargetCompletionValue.key(ctKey, ctx, /* willTest= */ true)) == null) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010054 return null;
55 }
janakra4634cf2017-08-24 09:23:39 +020056
Googler3c7d5712023-07-14 06:33:31 -070057 ConfiguredTargetValue ctValue = (ConfiguredTargetValue) env.getValue(ctKey);
janakra4634cf2017-08-24 09:23:39 +020058 if (ctValue == null) {
59 return null;
60 }
61
62 ConfiguredTarget ct = ctValue.getConfiguredTarget();
63 if (key.exclusiveTesting()) {
janakrb9d8d582018-06-13 21:57:19 -070064 // Request test execution iteratively if testing exclusively.
janakrefb3f152019-06-05 17:42:34 -070065 for (Artifact.DerivedArtifact testArtifact : TestProvider.getTestStatusArtifacts(ct)) {
66 env.getValue(testArtifact.getGeneratingActionKey());
janakrb9d8d582018-06-13 21:57:19 -070067 if (env.valuesMissing()) {
janakra4634cf2017-08-24 09:23:39 +020068 return null;
69 }
70 }
71 } else {
Googlerdb4c5502024-08-08 11:03:51 -070072 List<SkyKey> skyKeys = Artifact.keys(TestProvider.getTestStatusArtifacts(ct));
73 SkyframeLookupResult result = env.getValuesAndExceptions(skyKeys);
74 if (env.valuesMissing()) {
janakra4634cf2017-08-24 09:23:39 +020075 return null;
76 }
Googlerdb4c5502024-08-08 11:03:51 -070077 for (SkyKey actionKey : skyKeys) {
78 try {
79 if (result.getOrThrow(actionKey, ActionExecutionException.class) == null) {
80 return null;
81 }
82 } catch (ActionExecutionException e) {
83 DetailedExitCode detailedExitCode = e.getDetailedExitCode();
84 if (detailedExitCode.getExitCode().equals(ExitCode.BUILD_FAILURE)
85 && ctValue instanceof ActionLookupValue actionLookupValue) {
86 postTestResultEventsForUnbuildableTestInputs(
87 env, (ActionLookupData) actionKey, actionLookupValue, detailedExitCode);
88 } else {
89 return null;
90 }
91 }
92 }
janakra4634cf2017-08-24 09:23:39 +020093 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010094 return TestCompletionValue.TEST_COMPLETION_MARKER;
95 }
96
97 @Override
98 public String extractTag(SkyKey skyKey) {
janakrac2cd352017-12-20 13:37:13 -080099 return Label.print(((ConfiguredTargetKey) skyKey.argument()).getLabel());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100100 }
Googlerdb4c5502024-08-08 11:03:51 -0700101
102 /**
103 * Posts events for test actions that could not run because one or more exec-configuration inputs
104 * common to all tests failed to build.
105 *
106 * <p>When we run this SkyFunction we will have already built the test executable and its inputs,
107 * but we might fail to build the exec-configuration attributes providing inputs to the {@link
108 * TestRunnerAction} such as {@code $test_runtime}, {@code $test_wrapper}, {@code
109 * test_setup_script} and others (see {@link
110 * com.google.devtools.build.lib.analysis.BaseRuleClasses.TestBaseRule#build(com.google.devtools.build.lib.packages.RuleClass.Builder,
111 * com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment)} where all Test-type rules
112 * have additional attributes added).
113 *
114 * <p>When these exec-configuration inputs cannot be built, we do not get to use any {@code
115 * TestStrategy} that is responsible for posting {@link TestAttempt} and {@link TestResult}
116 * events. We need to handle this case here and post minimal events indicating the test {@link
117 * BlazeTestStatus.FAILED_TO_BUILD FAILED_TO_BUILD}.
118 */
119 private static void postTestResultEventsForUnbuildableTestInputs(
120 Environment env,
121 ActionLookupData actionKey,
122 ActionLookupValue actionLookupValue,
123 DetailedExitCode detailedExitCode) {
124 BlazeTestStatus status = BlazeTestStatus.FAILED_TO_BUILD;
125 if (detailedExitCode
126 .getFailureDetail()
127 .getExecution()
128 .getCode()
129 .equals(Code.ACTION_NOT_UP_TO_DATE)) {
130 status = BlazeTestStatus.NO_STATUS;
131 }
132 TestRunnerAction testRunnerAction =
133 (TestRunnerAction) actionLookupValue.getAction(actionKey.getActionIndex());
134 TestResultData testData = TestResultData.newBuilder().setStatus(status).build();
135 env.getListener().post(TestAttempt.forUnstartableTestResult(testRunnerAction, testData));
136 env.getListener()
137 .post(new TestResult(testRunnerAction, testData, /* cached= */ false, detailedExitCode));
138 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100139}