blob: 3c2f0b64d4b62647ae99e517b30853a7d1397cf6 [file] [log] [blame]
John Cater77a49622019-04-19 07:23:33 -07001// Copyright 2019 The Bazel Authors. All rights reserved.
2//
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
16import static com.google.common.truth.Truth.assertThat;
jcater7052f3c2020-06-02 15:43:14 -070017import static com.google.devtools.build.lib.analysis.testing.ToolchainContextSubject.assertThat;
John Cater77a49622019-04-19 07:23:33 -070018import static com.google.devtools.build.skyframe.EvaluationResultSubjectFactory.assertThatEvaluationResult;
19
20import com.google.common.collect.ImmutableList;
21import com.google.devtools.build.lib.cmdline.Label;
22import com.google.devtools.build.lib.rules.platform.ToolchainTestCase;
23import com.google.devtools.build.lib.skyframe.ConstraintValueLookupUtil.InvalidConstraintValueException;
24import com.google.devtools.build.lib.skyframe.PlatformLookupUtil.InvalidPlatformException;
25import com.google.devtools.build.lib.skyframe.ToolchainResolutionFunction.NoMatchingPlatformException;
John Cater004099d2019-05-17 11:21:59 -070026import com.google.devtools.build.lib.skyframe.ToolchainTypeLookupUtil.InvalidToolchainTypeException;
John Cater77a49622019-04-19 07:23:33 -070027import com.google.devtools.build.lib.skyframe.util.SkyframeExecutorTestUtils;
28import com.google.devtools.build.skyframe.EvaluationResult;
29import com.google.devtools.build.skyframe.SkyKey;
30import org.junit.Test;
31import org.junit.runner.RunWith;
32import org.junit.runners.JUnit4;
33
34/** Tests for {@link UnloadedToolchainContext} and {@link ToolchainResolutionFunction}. */
35@RunWith(JUnit4.class)
36public class ToolchainResolutionFunctionTest extends ToolchainTestCase {
37
38 private EvaluationResult<UnloadedToolchainContext> invokeToolchainResolution(SkyKey key)
39 throws InterruptedException {
40 try {
41 getSkyframeExecutor().getSkyframeBuildView().enableAnalysis(true);
42 return SkyframeExecutorTestUtils.evaluate(
43 getSkyframeExecutor(), key, /*keepGoing=*/ false, reporter);
44 } finally {
45 getSkyframeExecutor().getSkyframeBuildView().enableAnalysis(false);
46 }
47 }
48
49 @Test
50 public void resolve() throws Exception {
51 // This should select platform mac, toolchain extra_toolchain_mac, because platform
52 // mac is listed first.
53 addToolchain(
54 "extra",
55 "extra_toolchain_linux",
56 ImmutableList.of("//constraints:linux"),
57 ImmutableList.of("//constraints:linux"),
58 "baz");
59 addToolchain(
60 "extra",
61 "extra_toolchain_mac",
62 ImmutableList.of("//constraints:mac"),
63 ImmutableList.of("//constraints:linux"),
64 "baz");
65 rewriteWorkspace(
66 "register_toolchains('//extra:extra_toolchain_linux', '//extra:extra_toolchain_mac')",
67 "register_execution_platforms('//platforms:mac', '//platforms:linux')");
68
69 useConfiguration("--platforms=//platforms:linux");
John Cater60837112020-05-12 06:31:02 -070070 ToolchainContextKey key =
71 ToolchainContextKey.key()
John Cater77a49622019-04-19 07:23:33 -070072 .configurationKey(targetConfigKey)
73 .requiredToolchainTypeLabels(testToolchainTypeLabel)
74 .build();
75
76 EvaluationResult<UnloadedToolchainContext> result = invokeToolchainResolution(key);
77
78 assertThatEvaluationResult(result).hasNoError();
79 UnloadedToolchainContext unloadedToolchainContext = result.get(key);
80 assertThat(unloadedToolchainContext).isNotNull();
81
jcater7052f3c2020-06-02 15:43:14 -070082 assertThat(unloadedToolchainContext).hasToolchainType(testToolchainTypeLabel);
83 assertThat(unloadedToolchainContext).hasResolvedToolchain("//extra:extra_toolchain_mac_impl");
84 assertThat(unloadedToolchainContext).hasExecutionPlatform("//platforms:mac");
85 assertThat(unloadedToolchainContext).hasTargetPlatform("//platforms:linux");
John Cater77a49622019-04-19 07:23:33 -070086 }
87
88 @Test
John Cater004099d2019-05-17 11:21:59 -070089 public void resolve_toolchainTypeAlias() throws Exception {
90 addToolchain(
91 "extra",
92 "extra_toolchain_linux",
93 ImmutableList.of("//constraints:linux"),
94 ImmutableList.of("//constraints:linux"),
95 "baz");
96 rewriteWorkspace(
97 "register_toolchains('//extra:extra_toolchain_linux')",
98 "register_execution_platforms('//platforms:linux')");
99
100 // Set up an alias for the toolchain type.
101 Label aliasedToolchainTypeLabel = makeLabel("//alias:toolchain_type");
102 scratch.file(
103 "alias/BUILD", "alias(name = 'toolchain_type', actual = '//toolchain:test_toolchain')");
104
105 useConfiguration("--platforms=//platforms:linux");
John Cater60837112020-05-12 06:31:02 -0700106 ToolchainContextKey key =
107 ToolchainContextKey.key()
John Cater004099d2019-05-17 11:21:59 -0700108 .configurationKey(targetConfigKey)
109 .requiredToolchainTypeLabels(aliasedToolchainTypeLabel)
110 .build();
111
112 EvaluationResult<UnloadedToolchainContext> result = invokeToolchainResolution(key);
113
114 assertThatEvaluationResult(result).hasNoError();
115 UnloadedToolchainContext unloadedToolchainContext = result.get(key);
116 assertThat(unloadedToolchainContext).isNotNull();
117
jcater7052f3c2020-06-02 15:43:14 -0700118 assertThat(unloadedToolchainContext).hasToolchainType(testToolchainTypeLabel);
119 assertThat(unloadedToolchainContext).hasResolvedToolchain("//extra:extra_toolchain_linux_impl");
120 assertThat(unloadedToolchainContext).hasExecutionPlatform("//platforms:linux");
121 assertThat(unloadedToolchainContext).hasTargetPlatform("//platforms:linux");
John Cater004099d2019-05-17 11:21:59 -0700122 }
123
124 @Test
John Cater77a49622019-04-19 07:23:33 -0700125 public void resolve_noToolchainType() throws Exception {
126 scratch.file("host/BUILD", "platform(name = 'host')");
127 rewriteWorkspace("register_execution_platforms('//platforms:mac', '//platforms:linux')");
128
129 useConfiguration("--host_platform=//host:host", "--platforms=//platforms:linux");
John Cater60837112020-05-12 06:31:02 -0700130 ToolchainContextKey key = ToolchainContextKey.key().configurationKey(targetConfigKey).build();
John Cater77a49622019-04-19 07:23:33 -0700131
132 EvaluationResult<UnloadedToolchainContext> result = invokeToolchainResolution(key);
133
134 assertThatEvaluationResult(result).hasNoError();
135 UnloadedToolchainContext unloadedToolchainContext = result.get(key);
136 assertThat(unloadedToolchainContext).isNotNull();
137
138 assertThat(unloadedToolchainContext.requiredToolchainTypes()).isEmpty();
John Caterba123212019-06-13 08:03:52 -0700139 // Even with no toolchains requested, should still select the first execution platform.
jcater7052f3c2020-06-02 15:43:14 -0700140 assertThat(unloadedToolchainContext).hasExecutionPlatform("//platforms:mac");
141 assertThat(unloadedToolchainContext).hasTargetPlatform("//platforms:linux");
John Cater77a49622019-04-19 07:23:33 -0700142 }
143
144 @Test
145 public void resolve_noToolchainType_hostNotAvailable() throws Exception {
146 scratch.file("host/BUILD", "platform(name = 'host')");
147 scratch.file(
148 "sample/BUILD",
149 "constraint_setting(name='demo')",
150 "constraint_value(name = 'demo_a', constraint_setting=':demo')",
151 "constraint_value(name = 'demo_b', constraint_setting=':demo')",
152 "platform(name = 'sample_a',",
153 " constraint_values = [':demo_a'],",
154 ")",
155 "platform(name = 'sample_b',",
156 " constraint_values = [':demo_b'],",
157 ")");
158 rewriteWorkspace(
159 "register_execution_platforms('//platforms:mac', '//platforms:linux',",
160 " '//sample:sample_a', '//sample:sample_b')");
161
162 useConfiguration("--host_platform=//host:host", "--platforms=//platforms:linux");
John Cater60837112020-05-12 06:31:02 -0700163 ToolchainContextKey key =
164 ToolchainContextKey.key()
John Cater77a49622019-04-19 07:23:33 -0700165 .configurationKey(targetConfigKey)
166 .execConstraintLabels(Label.parseAbsoluteUnchecked("//sample:demo_b"))
167 .build();
168
169 EvaluationResult<UnloadedToolchainContext> result = invokeToolchainResolution(key);
170
171 assertThatEvaluationResult(result).hasNoError();
172 UnloadedToolchainContext unloadedToolchainContext = result.get(key);
173 assertThat(unloadedToolchainContext).isNotNull();
174
175 assertThat(unloadedToolchainContext.requiredToolchainTypes()).isEmpty();
jcater7052f3c2020-06-02 15:43:14 -0700176 assertThat(unloadedToolchainContext).hasExecutionPlatform("//sample:sample_b");
177 assertThat(unloadedToolchainContext).hasTargetPlatform("//platforms:linux");
John Cater77a49622019-04-19 07:23:33 -0700178 }
179
180 @Test
181 public void resolve_unavailableToolchainType_single() throws Exception {
John Cater004099d2019-05-17 11:21:59 -0700182 scratch.file("fake/toolchain/BUILD", "");
John Cater77a49622019-04-19 07:23:33 -0700183 useConfiguration("--host_platform=//platforms:linux", "--platforms=//platforms:mac");
John Cater60837112020-05-12 06:31:02 -0700184 ToolchainContextKey key =
185 ToolchainContextKey.key()
John Cater77a49622019-04-19 07:23:33 -0700186 .configurationKey(targetConfigKey)
187 .requiredToolchainTypeLabels(
188 testToolchainTypeLabel, Label.parseAbsoluteUnchecked("//fake/toolchain:type_1"))
189 .build();
190
191 EvaluationResult<UnloadedToolchainContext> result = invokeToolchainResolution(key);
192
193 assertThatEvaluationResult(result)
194 .hasErrorEntryForKeyThat(key)
195 .hasExceptionThat()
John Cater004099d2019-05-17 11:21:59 -0700196 .isInstanceOf(InvalidToolchainTypeException.class);
John Cater77a49622019-04-19 07:23:33 -0700197 assertThatEvaluationResult(result)
198 .hasErrorEntryForKeyThat(key)
199 .hasExceptionThat()
200 .hasMessageThat()
John Cater004099d2019-05-17 11:21:59 -0700201 .contains("//fake/toolchain:type_1");
John Cater77a49622019-04-19 07:23:33 -0700202 }
203
204 @Test
205 public void resolve_unavailableToolchainType_multiple() throws Exception {
John Cater004099d2019-05-17 11:21:59 -0700206 scratch.file("fake/toolchain/BUILD", "");
John Cater77a49622019-04-19 07:23:33 -0700207 useConfiguration("--host_platform=//platforms:linux", "--platforms=//platforms:mac");
John Cater60837112020-05-12 06:31:02 -0700208 ToolchainContextKey key =
209 ToolchainContextKey.key()
John Cater77a49622019-04-19 07:23:33 -0700210 .configurationKey(targetConfigKey)
211 .requiredToolchainTypeLabels(
212 testToolchainTypeLabel,
213 Label.parseAbsoluteUnchecked("//fake/toolchain:type_1"),
214 Label.parseAbsoluteUnchecked("//fake/toolchain:type_2"))
215 .build();
216
217 EvaluationResult<UnloadedToolchainContext> result = invokeToolchainResolution(key);
218
219 assertThatEvaluationResult(result)
220 .hasErrorEntryForKeyThat(key)
221 .hasExceptionThat()
John Cater004099d2019-05-17 11:21:59 -0700222 .isInstanceOf(InvalidToolchainTypeException.class);
John Cater77a49622019-04-19 07:23:33 -0700223 // Only one of the missing types will be reported, so do not check the specific error message.
224 }
225
226 @Test
227 public void resolve_invalidTargetPlatform_badTarget() throws Exception {
228 scratch.file("invalid/BUILD", "filegroup(name = 'not_a_platform')");
229 useConfiguration("--platforms=//invalid:not_a_platform");
John Cater60837112020-05-12 06:31:02 -0700230 ToolchainContextKey key =
231 ToolchainContextKey.key()
John Cater77a49622019-04-19 07:23:33 -0700232 .configurationKey(targetConfigKey)
233 .requiredToolchainTypeLabels(testToolchainTypeLabel)
234 .build();
235
236 EvaluationResult<UnloadedToolchainContext> result = invokeToolchainResolution(key);
237
238 assertThatEvaluationResult(result).hasError();
239 assertThatEvaluationResult(result)
240 .hasErrorEntryForKeyThat(key)
241 .hasExceptionThat()
242 .isInstanceOf(InvalidPlatformException.class);
243 assertThatEvaluationResult(result)
244 .hasErrorEntryForKeyThat(key)
245 .hasExceptionThat()
246 .hasMessageThat()
247 .contains(
248 "//invalid:not_a_platform was referenced as a platform, "
249 + "but does not provide PlatformInfo");
250 }
251
252 @Test
253 public void resolve_invalidTargetPlatform_badPackage() throws Exception {
254 scratch.resolve("invalid").delete();
255 useConfiguration("--platforms=//invalid:not_a_platform");
John Cater60837112020-05-12 06:31:02 -0700256 ToolchainContextKey key =
257 ToolchainContextKey.key()
John Cater77a49622019-04-19 07:23:33 -0700258 .configurationKey(targetConfigKey)
259 .requiredToolchainTypeLabels(testToolchainTypeLabel)
260 .build();
261
262 EvaluationResult<UnloadedToolchainContext> result = invokeToolchainResolution(key);
263
264 assertThatEvaluationResult(result).hasError();
265 assertThatEvaluationResult(result)
266 .hasErrorEntryForKeyThat(key)
267 .hasExceptionThat()
268 .isInstanceOf(InvalidPlatformException.class);
269 assertThatEvaluationResult(result)
270 .hasErrorEntryForKeyThat(key)
271 .hasExceptionThat()
272 .hasMessageThat()
273 .contains("BUILD file not found");
274 }
275
276 @Test
277 public void resolve_invalidHostPlatform() throws Exception {
278 scratch.file("invalid/BUILD", "filegroup(name = 'not_a_platform')");
279 useConfiguration("--host_platform=//invalid:not_a_platform");
John Cater60837112020-05-12 06:31:02 -0700280 ToolchainContextKey key =
281 ToolchainContextKey.key()
John Cater77a49622019-04-19 07:23:33 -0700282 .configurationKey(targetConfigKey)
283 .requiredToolchainTypeLabels(testToolchainTypeLabel)
284 .build();
285
286 EvaluationResult<UnloadedToolchainContext> result = invokeToolchainResolution(key);
287
288 assertThatEvaluationResult(result).hasError();
289 assertThatEvaluationResult(result)
290 .hasErrorEntryForKeyThat(key)
291 .hasExceptionThat()
292 .isInstanceOf(InvalidPlatformException.class);
293 assertThatEvaluationResult(result)
294 .hasErrorEntryForKeyThat(key)
295 .hasExceptionThat()
296 .hasMessageThat()
297 .contains("//invalid:not_a_platform");
298 }
299
300 @Test
301 public void resolve_invalidExecutionPlatform() throws Exception {
302 scratch.file("invalid/BUILD", "filegroup(name = 'not_a_platform')");
303 useConfiguration("--extra_execution_platforms=//invalid:not_a_platform");
John Cater60837112020-05-12 06:31:02 -0700304 ToolchainContextKey key =
305 ToolchainContextKey.key()
John Cater77a49622019-04-19 07:23:33 -0700306 .configurationKey(targetConfigKey)
307 .requiredToolchainTypeLabels(testToolchainTypeLabel)
308 .build();
309
310 EvaluationResult<UnloadedToolchainContext> result = invokeToolchainResolution(key);
311
312 assertThatEvaluationResult(result).hasError();
313 assertThatEvaluationResult(result)
314 .hasErrorEntryForKeyThat(key)
315 .hasExceptionThat()
316 .isInstanceOf(InvalidPlatformException.class);
317 assertThatEvaluationResult(result)
318 .hasErrorEntryForKeyThat(key)
319 .hasExceptionThat()
320 .hasMessageThat()
321 .contains("//invalid:not_a_platform");
322 }
323
324 @Test
325 public void resolve_execConstraints() throws Exception {
326 // This should select platform linux, toolchain extra_toolchain_linux, due to extra constraints,
327 // even though platform mac is registered first.
328 addToolchain(
329 /* packageName= */ "extra",
330 /* toolchainName= */ "extra_toolchain_linux",
331 /* execConstraints= */ ImmutableList.of("//constraints:linux"),
332 /* targetConstraints= */ ImmutableList.of("//constraints:linux"),
333 /* data= */ "baz");
334 addToolchain(
335 /* packageName= */ "extra",
336 /* toolchainName= */ "extra_toolchain_mac",
337 /* execConstraints= */ ImmutableList.of("//constraints:mac"),
338 /* targetConstraints= */ ImmutableList.of("//constraints:linux"),
339 /* data= */ "baz");
340 rewriteWorkspace(
341 "register_toolchains('//extra:extra_toolchain_linux', '//extra:extra_toolchain_mac')",
342 "register_execution_platforms('//platforms:mac', '//platforms:linux')");
343
344 useConfiguration("--platforms=//platforms:linux");
John Cater60837112020-05-12 06:31:02 -0700345 ToolchainContextKey key =
346 ToolchainContextKey.key()
John Cater77a49622019-04-19 07:23:33 -0700347 .configurationKey(targetConfigKey)
348 .requiredToolchainTypeLabels(testToolchainTypeLabel)
349 .execConstraintLabels(Label.parseAbsoluteUnchecked("//constraints:linux"))
350 .build();
351
352 EvaluationResult<UnloadedToolchainContext> result = invokeToolchainResolution(key);
353
354 assertThatEvaluationResult(result).hasNoError();
355 UnloadedToolchainContext unloadedToolchainContext = result.get(key);
356 assertThat(unloadedToolchainContext).isNotNull();
357
jcater7052f3c2020-06-02 15:43:14 -0700358 assertThat(unloadedToolchainContext).hasToolchainType(testToolchainTypeLabel);
359 assertThat(unloadedToolchainContext).hasResolvedToolchain("//extra:extra_toolchain_linux_impl");
360 assertThat(unloadedToolchainContext).hasExecutionPlatform("//platforms:linux");
361 assertThat(unloadedToolchainContext).hasTargetPlatform("//platforms:linux");
John Cater77a49622019-04-19 07:23:33 -0700362 }
363
364 @Test
365 public void resolve_execConstraints_invalid() throws Exception {
John Cater60837112020-05-12 06:31:02 -0700366 ToolchainContextKey key =
367 ToolchainContextKey.key()
John Cater77a49622019-04-19 07:23:33 -0700368 .configurationKey(targetConfigKey)
369 .requiredToolchainTypeLabels(testToolchainTypeLabel)
370 .execConstraintLabels(Label.parseAbsoluteUnchecked("//platforms:linux"))
371 .build();
372
373 EvaluationResult<UnloadedToolchainContext> result = invokeToolchainResolution(key);
374
375 assertThatEvaluationResult(result).hasError();
376 assertThatEvaluationResult(result)
377 .hasErrorEntryForKeyThat(key)
378 .hasExceptionThat()
379 .isInstanceOf(InvalidConstraintValueException.class);
380 assertThatEvaluationResult(result)
381 .hasErrorEntryForKeyThat(key)
382 .hasExceptionThat()
383 .hasMessageThat()
384 .contains("//platforms:linux");
385 }
386
387 @Test
388 public void resolve_noMatchingPlatform() throws Exception {
389 // Write toolchain A, and a toolchain implementing it.
390 scratch.appendFile(
391 "a/BUILD",
392 "toolchain_type(name = 'toolchain_type_A')",
393 "toolchain(",
394 " name = 'toolchain',",
395 " toolchain_type = ':toolchain_type_A',",
396 " exec_compatible_with = ['//constraints:mac'],",
397 " target_compatible_with = [],",
398 " toolchain = ':toolchain_impl')",
399 "filegroup(name='toolchain_impl')");
400 // Write toolchain B, and a toolchain implementing it.
401 scratch.appendFile(
402 "b/BUILD",
403 "load('//toolchain:toolchain_def.bzl', 'test_toolchain')",
404 "toolchain_type(name = 'toolchain_type_B')",
405 "toolchain(",
406 " name = 'toolchain',",
407 " toolchain_type = ':toolchain_type_B',",
408 " exec_compatible_with = ['//constraints:linux'],",
409 " target_compatible_with = [],",
410 " toolchain = ':toolchain_impl')",
411 "filegroup(name='toolchain_impl')");
412
413 rewriteWorkspace(
414 "register_toolchains('//a:toolchain', '//b:toolchain')",
415 "register_execution_platforms('//platforms:mac', '//platforms:linux')");
416
417 useConfiguration("--platforms=//platforms:linux");
John Cater60837112020-05-12 06:31:02 -0700418 ToolchainContextKey key =
419 ToolchainContextKey.key()
John Cater77a49622019-04-19 07:23:33 -0700420 .configurationKey(targetConfigKey)
421 .requiredToolchainTypeLabels(
422 Label.parseAbsoluteUnchecked("//a:toolchain_type_A"),
423 Label.parseAbsoluteUnchecked("//b:toolchain_type_B"))
424 .build();
425
426 EvaluationResult<UnloadedToolchainContext> result = invokeToolchainResolution(key);
427 assertThatEvaluationResult(result).hasError();
428 assertThatEvaluationResult(result)
429 .hasErrorEntryForKeyThat(key)
430 .hasExceptionThat()
431 .isInstanceOf(NoMatchingPlatformException.class);
432 }
433}