blob: a48e0834a12e08882acbe686fe520111528da953 [file] [log] [blame]
Chris Parsons4f069892021-01-15 12:22:41 -05001// Copyright 2020 Google Inc. 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.
14
15package bazel
16
17import (
18 "fmt"
19 "reflect"
20 "testing"
21)
22
23func TestAqueryMultiArchGenrule(t *testing.T) {
24 // This input string is retrieved from a real build of bionic-related genrules.
25 const inputString = `
26{
27 "artifacts": [{
28 "id": 1,
29 "pathFragmentId": 1
30 }, {
31 "id": 2,
32 "pathFragmentId": 6
33 }, {
34 "id": 3,
35 "pathFragmentId": 8
36 }, {
37 "id": 4,
38 "pathFragmentId": 12
39 }, {
40 "id": 5,
41 "pathFragmentId": 19
42 }, {
43 "id": 6,
44 "pathFragmentId": 20
45 }, {
46 "id": 7,
47 "pathFragmentId": 21
48 }],
49 "actions": [{
50 "targetId": 1,
51 "actionKey": "ab53f6ecbdc2ee8cb8812613b63205464f1f5083f6dca87081a0a398c0f1ecf7",
52 "mnemonic": "Genrule",
53 "configurationId": 1,
54 "arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py arm ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-arm.S"],
55 "environmentVariables": [{
56 "key": "PATH",
57 "value": "/bin:/usr/bin:/usr/local/bin"
58 }],
59 "inputDepSetIds": [1],
60 "outputIds": [4],
61 "primaryOutputId": 4
62 }, {
63 "targetId": 2,
64 "actionKey": "9f4309ce165dac458498cb92811c18b0b7919782cc37b82a42d2141b8cc90826",
65 "mnemonic": "Genrule",
66 "configurationId": 1,
67 "arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py x86 ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-x86.S"],
68 "environmentVariables": [{
69 "key": "PATH",
70 "value": "/bin:/usr/bin:/usr/local/bin"
71 }],
72 "inputDepSetIds": [2],
73 "outputIds": [5],
74 "primaryOutputId": 5
75 }, {
76 "targetId": 3,
77 "actionKey": "50d6c586103ebeed3a218195540bcc30d329464eae36377eb82f8ce7c36ac342",
78 "mnemonic": "Genrule",
79 "configurationId": 1,
80 "arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py x86_64 ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-x86_64.S"],
81 "environmentVariables": [{
82 "key": "PATH",
83 "value": "/bin:/usr/bin:/usr/local/bin"
84 }],
85 "inputDepSetIds": [3],
86 "outputIds": [6],
87 "primaryOutputId": 6
88 }, {
89 "targetId": 4,
90 "actionKey": "f30cbe442f5216f4223cf16a39112cad4ec56f31f49290d85cff587e48647ffa",
91 "mnemonic": "Genrule",
92 "configurationId": 1,
93 "arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py arm64 ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-arm64.S"],
94 "environmentVariables": [{
95 "key": "PATH",
96 "value": "/bin:/usr/bin:/usr/local/bin"
97 }],
98 "inputDepSetIds": [4],
99 "outputIds": [7],
100 "primaryOutputId": 7
101 }],
102 "targets": [{
103 "id": 1,
104 "label": "@sourceroot//bionic/libc:syscalls-arm",
105 "ruleClassId": 1
106 }, {
107 "id": 2,
108 "label": "@sourceroot//bionic/libc:syscalls-x86",
109 "ruleClassId": 1
110 }, {
111 "id": 3,
112 "label": "@sourceroot//bionic/libc:syscalls-x86_64",
113 "ruleClassId": 1
114 }, {
115 "id": 4,
116 "label": "@sourceroot//bionic/libc:syscalls-arm64",
117 "ruleClassId": 1
118 }],
119 "depSetOfFiles": [{
120 "id": 1,
121 "directArtifactIds": [1, 2, 3]
122 }, {
123 "id": 2,
124 "directArtifactIds": [1, 2, 3]
125 }, {
126 "id": 3,
127 "directArtifactIds": [1, 2, 3]
128 }, {
129 "id": 4,
130 "directArtifactIds": [1, 2, 3]
131 }],
132 "configuration": [{
133 "id": 1,
134 "mnemonic": "k8-fastbuild",
135 "platformName": "k8",
136 "checksum": "485c362832c178e367d972177f68e69e0981e51e67ef1c160944473db53fe046"
137 }],
138 "ruleClasses": [{
139 "id": 1,
140 "name": "genrule"
141 }],
142 "pathFragments": [{
143 "id": 5,
144 "label": ".."
145 }, {
146 "id": 4,
147 "label": "sourceroot",
148 "parentId": 5
149 }, {
150 "id": 3,
151 "label": "bionic",
152 "parentId": 4
153 }, {
154 "id": 2,
155 "label": "libc",
156 "parentId": 3
157 }, {
158 "id": 1,
159 "label": "SYSCALLS.TXT",
160 "parentId": 2
161 }, {
162 "id": 7,
163 "label": "tools",
164 "parentId": 2
165 }, {
166 "id": 6,
167 "label": "gensyscalls.py",
168 "parentId": 7
169 }, {
170 "id": 11,
171 "label": "bazel_tools",
172 "parentId": 5
173 }, {
174 "id": 10,
175 "label": "tools",
176 "parentId": 11
177 }, {
178 "id": 9,
179 "label": "genrule",
180 "parentId": 10
181 }, {
182 "id": 8,
183 "label": "genrule-setup.sh",
184 "parentId": 9
185 }, {
186 "id": 18,
187 "label": "bazel-out"
188 }, {
189 "id": 17,
190 "label": "sourceroot",
191 "parentId": 18
192 }, {
193 "id": 16,
194 "label": "k8-fastbuild",
195 "parentId": 17
196 }, {
197 "id": 15,
198 "label": "bin",
199 "parentId": 16
200 }, {
201 "id": 14,
202 "label": "bionic",
203 "parentId": 15
204 }, {
205 "id": 13,
206 "label": "libc",
207 "parentId": 14
208 }, {
209 "id": 12,
210 "label": "syscalls-arm.S",
211 "parentId": 13
212 }, {
213 "id": 19,
214 "label": "syscalls-x86.S",
215 "parentId": 13
216 }, {
217 "id": 20,
218 "label": "syscalls-x86_64.S",
219 "parentId": 13
220 }, {
221 "id": 21,
222 "label": "syscalls-arm64.S",
223 "parentId": 13
224 }]
225}`
226 actualbuildStatements, _ := AqueryBuildStatements([]byte(inputString))
227 expectedBuildStatements := []BuildStatement{}
228 for _, arch := range []string{"arm", "arm64", "x86", "x86_64"} {
229 expectedBuildStatements = append(expectedBuildStatements,
230 BuildStatement{
231 Command: fmt.Sprintf(
232 "/bin/bash -c 'source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py %s ../sourceroot/bionic/libc/SYSCALLS.TXT > bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-%s.S'",
233 arch, arch),
234 OutputPaths: []string{
235 fmt.Sprintf("bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-%s.S", arch),
236 },
237 InputPaths: []string{
238 "../sourceroot/bionic/libc/SYSCALLS.TXT",
239 "../sourceroot/bionic/libc/tools/gensyscalls.py",
240 "../bazel_tools/tools/genrule/genrule-setup.sh",
241 },
242 Env: []KeyValuePair{
243 KeyValuePair{Key: "PATH", Value: "/bin:/usr/bin:/usr/local/bin"},
244 },
245 Mnemonic: "Genrule",
246 })
247 }
248 assertBuildStatements(t, expectedBuildStatements, actualbuildStatements)
249}
250
251func TestInvalidOutputId(t *testing.T) {
252 const inputString = `
253{
254 "artifacts": [{
255 "id": 1,
256 "pathFragmentId": 1
257 }, {
258 "id": 2,
259 "pathFragmentId": 2
260 }],
261 "actions": [{
262 "targetId": 1,
263 "actionKey": "x",
264 "mnemonic": "x",
265 "arguments": ["touch", "foo"],
266 "inputDepSetIds": [1],
267 "outputIds": [3],
268 "primaryOutputId": 3
269 }],
270 "depSetOfFiles": [{
271 "id": 1,
272 "directArtifactIds": [1, 2]
273 }],
274 "pathFragments": [{
275 "id": 1,
276 "label": "one"
277 }, {
278 "id": 2,
279 "label": "two"
280 }]
281}`
282
283 _, err := AqueryBuildStatements([]byte(inputString))
284 assertError(t, err, "undefined outputId 3")
285}
286
287func TestInvalidInputDepsetId(t *testing.T) {
288 const inputString = `
289{
290 "artifacts": [{
291 "id": 1,
292 "pathFragmentId": 1
293 }, {
294 "id": 2,
295 "pathFragmentId": 2
296 }],
297 "actions": [{
298 "targetId": 1,
299 "actionKey": "x",
300 "mnemonic": "x",
301 "arguments": ["touch", "foo"],
302 "inputDepSetIds": [2],
303 "outputIds": [1],
304 "primaryOutputId": 1
305 }],
306 "depSetOfFiles": [{
307 "id": 1,
308 "directArtifactIds": [1, 2]
309 }],
310 "pathFragments": [{
311 "id": 1,
312 "label": "one"
313 }, {
314 "id": 2,
315 "label": "two"
316 }]
317}`
318
319 _, err := AqueryBuildStatements([]byte(inputString))
320 assertError(t, err, "undefined input depsetId 2")
321}
322
323func TestInvalidInputArtifactId(t *testing.T) {
324 const inputString = `
325{
326 "artifacts": [{
327 "id": 1,
328 "pathFragmentId": 1
329 }, {
330 "id": 2,
331 "pathFragmentId": 2
332 }],
333 "actions": [{
334 "targetId": 1,
335 "actionKey": "x",
336 "mnemonic": "x",
337 "arguments": ["touch", "foo"],
338 "inputDepSetIds": [1],
339 "outputIds": [1],
340 "primaryOutputId": 1
341 }],
342 "depSetOfFiles": [{
343 "id": 1,
344 "directArtifactIds": [1, 3]
345 }],
346 "pathFragments": [{
347 "id": 1,
348 "label": "one"
349 }, {
350 "id": 2,
351 "label": "two"
352 }]
353}`
354
355 _, err := AqueryBuildStatements([]byte(inputString))
356 assertError(t, err, "undefined input artifactId 3")
357}
358
359func TestInvalidPathFragmentId(t *testing.T) {
360 const inputString = `
361{
362 "artifacts": [{
363 "id": 1,
364 "pathFragmentId": 1
365 }, {
366 "id": 2,
367 "pathFragmentId": 2
368 }],
369 "actions": [{
370 "targetId": 1,
371 "actionKey": "x",
372 "mnemonic": "x",
373 "arguments": ["touch", "foo"],
374 "inputDepSetIds": [1],
375 "outputIds": [1],
376 "primaryOutputId": 1
377 }],
378 "depSetOfFiles": [{
379 "id": 1,
380 "directArtifactIds": [1, 2]
381 }],
382 "pathFragments": [{
383 "id": 1,
384 "label": "one"
385 }, {
386 "id": 2,
387 "label": "two",
388 "parentId": 3
389 }]
390}`
391
392 _, err := AqueryBuildStatements([]byte(inputString))
393 assertError(t, err, "undefined path fragment id 3")
394}
395
Chris Parsons943f2432021-01-19 11:36:50 -0500396func TestTransitiveInputDepsets(t *testing.T) {
397 // The input aquery for this test comes from a proof-of-concept starlark rule which registers
398 // a single action with many inputs given via a deep depset.
399 const inputString = `
400{
401 "artifacts": [{
402 "id": 1,
403 "pathFragmentId": 1
404 }, {
405 "id": 2,
406 "pathFragmentId": 7
407 }, {
408 "id": 3,
409 "pathFragmentId": 8
410 }, {
411 "id": 4,
412 "pathFragmentId": 9
413 }, {
414 "id": 5,
415 "pathFragmentId": 10
416 }, {
417 "id": 6,
418 "pathFragmentId": 11
419 }, {
420 "id": 7,
421 "pathFragmentId": 12
422 }, {
423 "id": 8,
424 "pathFragmentId": 13
425 }, {
426 "id": 9,
427 "pathFragmentId": 14
428 }, {
429 "id": 10,
430 "pathFragmentId": 15
431 }, {
432 "id": 11,
433 "pathFragmentId": 16
434 }, {
435 "id": 12,
436 "pathFragmentId": 17
437 }, {
438 "id": 13,
439 "pathFragmentId": 18
440 }, {
441 "id": 14,
442 "pathFragmentId": 19
443 }, {
444 "id": 15,
445 "pathFragmentId": 20
446 }, {
447 "id": 16,
448 "pathFragmentId": 21
449 }, {
450 "id": 17,
451 "pathFragmentId": 22
452 }, {
453 "id": 18,
454 "pathFragmentId": 23
455 }, {
456 "id": 19,
457 "pathFragmentId": 24
458 }, {
459 "id": 20,
460 "pathFragmentId": 25
461 }, {
462 "id": 21,
463 "pathFragmentId": 26
464 }],
465 "actions": [{
466 "targetId": 1,
467 "actionKey": "3b826d17fadbbbcd8313e456b90ec47c078c438088891dd45b4adbcd8889dc50",
468 "mnemonic": "Action",
469 "configurationId": 1,
470 "arguments": ["/bin/bash", "-c", "touch bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out"],
471 "inputDepSetIds": [1],
472 "outputIds": [21],
473 "primaryOutputId": 21
474 }],
475 "depSetOfFiles": [{
476 "id": 3,
477 "directArtifactIds": [1, 2, 3, 4, 5]
478 }, {
479 "id": 4,
480 "directArtifactIds": [6, 7, 8, 9, 10]
481 }, {
482 "id": 2,
483 "transitiveDepSetIds": [3, 4],
484 "directArtifactIds": [11, 12, 13, 14, 15]
485 }, {
486 "id": 5,
487 "directArtifactIds": [16, 17, 18, 19]
488 }, {
489 "id": 1,
490 "transitiveDepSetIds": [2, 5],
491 "directArtifactIds": [20]
492 }],
493 "pathFragments": [{
494 "id": 6,
495 "label": "bazel-out"
496 }, {
497 "id": 5,
498 "label": "sourceroot",
499 "parentId": 6
500 }, {
501 "id": 4,
502 "label": "k8-fastbuild",
503 "parentId": 5
504 }, {
505 "id": 3,
506 "label": "bin",
507 "parentId": 4
508 }, {
509 "id": 2,
510 "label": "testpkg",
511 "parentId": 3
512 }, {
513 "id": 1,
514 "label": "test_1",
515 "parentId": 2
516 }, {
517 "id": 7,
518 "label": "test_2",
519 "parentId": 2
520 }, {
521 "id": 8,
522 "label": "test_3",
523 "parentId": 2
524 }, {
525 "id": 9,
526 "label": "test_4",
527 "parentId": 2
528 }, {
529 "id": 10,
530 "label": "test_5",
531 "parentId": 2
532 }, {
533 "id": 11,
534 "label": "test_6",
535 "parentId": 2
536 }, {
537 "id": 12,
538 "label": "test_7",
539 "parentId": 2
540 }, {
541 "id": 13,
542 "label": "test_8",
543 "parentId": 2
544 }, {
545 "id": 14,
546 "label": "test_9",
547 "parentId": 2
548 }, {
549 "id": 15,
550 "label": "test_10",
551 "parentId": 2
552 }, {
553 "id": 16,
554 "label": "test_11",
555 "parentId": 2
556 }, {
557 "id": 17,
558 "label": "test_12",
559 "parentId": 2
560 }, {
561 "id": 18,
562 "label": "test_13",
563 "parentId": 2
564 }, {
565 "id": 19,
566 "label": "test_14",
567 "parentId": 2
568 }, {
569 "id": 20,
570 "label": "test_15",
571 "parentId": 2
572 }, {
573 "id": 21,
574 "label": "test_16",
575 "parentId": 2
576 }, {
577 "id": 22,
578 "label": "test_17",
579 "parentId": 2
580 }, {
581 "id": 23,
582 "label": "test_18",
583 "parentId": 2
584 }, {
585 "id": 24,
586 "label": "test_19",
587 "parentId": 2
588 }, {
589 "id": 25,
590 "label": "test_root",
591 "parentId": 2
592 }, {
593 "id": 26,
594 "label": "test_out",
595 "parentId": 2
596 }]
597}`
598
599 actualbuildStatements, _ := AqueryBuildStatements([]byte(inputString))
600 // Inputs for the action are test_{i} from 1 to 20, and test_root. These inputs
601 // are given via a deep depset, but the depset is flattened when returned as a
602 // BuildStatement slice.
603 inputPaths := []string{"bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_root"}
604 for i := 1; i < 20; i++ {
605 inputPaths = append(inputPaths, fmt.Sprintf("bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_%d", i))
606 }
607 expectedBuildStatements := []BuildStatement{
608 BuildStatement{
609 Command: "/bin/bash -c touch bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out",
610 OutputPaths: []string{"bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out"},
611 InputPaths: inputPaths,
612 Mnemonic: "Action",
613 },
614 }
615 assertBuildStatements(t, expectedBuildStatements, actualbuildStatements)
616}
617
Chris Parsons4f069892021-01-15 12:22:41 -0500618func assertError(t *testing.T, err error, expected string) {
Chris Parsons943f2432021-01-19 11:36:50 -0500619 if err == nil {
620 t.Errorf("expected error '%s', but got no error", expected)
621 } else if err.Error() != expected {
622 t.Errorf("expected error '%s', but got: %s", expected, err.Error())
Chris Parsons4f069892021-01-15 12:22:41 -0500623 }
624}
625
626// Asserts that the given actual build statements match the given expected build statements.
627// Build statement equivalence is determined using buildStatementEquals.
628func assertBuildStatements(t *testing.T, expected []BuildStatement, actual []BuildStatement) {
629 if len(expected) != len(actual) {
630 t.Errorf("expected %d build statements, but got %d,\n expected: %s,\n actual: %s",
631 len(expected), len(actual), expected, actual)
632 return
633 }
634ACTUAL_LOOP:
635 for _, actualStatement := range actual {
636 for _, expectedStatement := range expected {
637 if buildStatementEquals(actualStatement, expectedStatement) {
638 continue ACTUAL_LOOP
639 }
640 }
641 t.Errorf("unexpected build statement %s.\n expected: %s",
642 actualStatement, expected)
643 return
644 }
645}
646
647func buildStatementEquals(first BuildStatement, second BuildStatement) bool {
648 if first.Mnemonic != second.Mnemonic {
649 return false
650 }
651 if first.Command != second.Command {
652 return false
653 }
654 // Ordering is significant for environment variables.
655 if !reflect.DeepEqual(first.Env, second.Env) {
656 return false
657 }
658 // Ordering is irrelevant for input and output paths, so compare sets.
659 if !reflect.DeepEqual(stringSet(first.InputPaths), stringSet(second.InputPaths)) {
660 return false
661 }
662 if !reflect.DeepEqual(stringSet(first.OutputPaths), stringSet(second.OutputPaths)) {
663 return false
664 }
665 return true
666}
667
668func stringSet(stringSlice []string) map[string]struct{} {
669 stringMap := make(map[string]struct{})
670 for _, s := range stringSlice {
671 stringMap[s] = struct{}{}
672 }
673 return stringMap
674}