blob: 2328411e136cc673da827355eec08fbce1358e7c [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}`
Chris Parsons1a7aca02022-04-25 22:35:15 -0400226 actualbuildStatements, actualDepsets, _ := AqueryBuildStatements([]byte(inputString))
Chris Parsons4f069892021-01-15 12:22:41 -0500227 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 },
Chris Parsons1a7aca02022-04-25 22:35:15 -0400237 InputDepsetIds: []int{1},
Chris Parsons4f069892021-01-15 12:22:41 -0500238 Env: []KeyValuePair{
239 KeyValuePair{Key: "PATH", Value: "/bin:/usr/bin:/usr/local/bin"},
240 },
241 Mnemonic: "Genrule",
242 })
243 }
244 assertBuildStatements(t, expectedBuildStatements, actualbuildStatements)
Chris Parsons1a7aca02022-04-25 22:35:15 -0400245
246 expectedFlattenedInputs := []string{
247 "../sourceroot/bionic/libc/SYSCALLS.TXT",
248 "../sourceroot/bionic/libc/tools/gensyscalls.py",
249 "../bazel_tools/tools/genrule/genrule-setup.sh",
250 }
251 actualFlattenedInputs := flattenDepsets([]int{1}, actualDepsets)
252 if !reflect.DeepEqual(actualFlattenedInputs, expectedFlattenedInputs) {
253 t.Errorf("Expected flattened inputs %v, but got %v", expectedFlattenedInputs, actualFlattenedInputs)
254 }
Chris Parsons4f069892021-01-15 12:22:41 -0500255}
256
257func TestInvalidOutputId(t *testing.T) {
258 const inputString = `
259{
260 "artifacts": [{
261 "id": 1,
262 "pathFragmentId": 1
263 }, {
264 "id": 2,
265 "pathFragmentId": 2
266 }],
267 "actions": [{
268 "targetId": 1,
269 "actionKey": "x",
270 "mnemonic": "x",
271 "arguments": ["touch", "foo"],
272 "inputDepSetIds": [1],
273 "outputIds": [3],
274 "primaryOutputId": 3
275 }],
276 "depSetOfFiles": [{
277 "id": 1,
278 "directArtifactIds": [1, 2]
279 }],
280 "pathFragments": [{
281 "id": 1,
282 "label": "one"
283 }, {
284 "id": 2,
285 "label": "two"
286 }]
287}`
288
Chris Parsons1a7aca02022-04-25 22:35:15 -0400289 _, _, err := AqueryBuildStatements([]byte(inputString))
Chris Parsons4f069892021-01-15 12:22:41 -0500290 assertError(t, err, "undefined outputId 3")
291}
292
Chris Parsons1a7aca02022-04-25 22:35:15 -0400293func TestInvalidInputDepsetIdFromAction(t *testing.T) {
Chris Parsons4f069892021-01-15 12:22:41 -0500294 const inputString = `
295{
296 "artifacts": [{
297 "id": 1,
298 "pathFragmentId": 1
299 }, {
300 "id": 2,
301 "pathFragmentId": 2
302 }],
303 "actions": [{
304 "targetId": 1,
305 "actionKey": "x",
306 "mnemonic": "x",
307 "arguments": ["touch", "foo"],
308 "inputDepSetIds": [2],
309 "outputIds": [1],
310 "primaryOutputId": 1
311 }],
312 "depSetOfFiles": [{
313 "id": 1,
314 "directArtifactIds": [1, 2]
315 }],
316 "pathFragments": [{
317 "id": 1,
318 "label": "one"
319 }, {
320 "id": 2,
321 "label": "two"
322 }]
323}`
324
Chris Parsons1a7aca02022-04-25 22:35:15 -0400325 _, _, err := AqueryBuildStatements([]byte(inputString))
Chris Parsons4f069892021-01-15 12:22:41 -0500326 assertError(t, err, "undefined input depsetId 2")
327}
328
Chris Parsons1a7aca02022-04-25 22:35:15 -0400329func TestInvalidInputDepsetIdFromDepset(t *testing.T) {
330 const inputString = `
331{
332 "artifacts": [{
333 "id": 1,
334 "pathFragmentId": 1
335 }, {
336 "id": 2,
337 "pathFragmentId": 2
338 }],
339 "actions": [{
340 "targetId": 1,
341 "actionKey": "x",
342 "mnemonic": "x",
343 "arguments": ["touch", "foo"],
344 "inputDepSetIds": [1],
345 "outputIds": [1],
346 "primaryOutputId": 1
347 }],
348 "depSetOfFiles": [{
349 "id": 1,
350 "directArtifactIds": [1, 2],
351 "transitiveDepSetIds": [42]
352 }],
353 "pathFragments": [{
354 "id": 1,
355 "label": "one"
356 }, {
357 "id": 2,
358 "label": "two"
359 }]
360}`
361
362 _, _, err := AqueryBuildStatements([]byte(inputString))
363 assertError(t, err, "undefined input depsetId 42 (referenced by depsetId 1)")
364}
365
Chris Parsons4f069892021-01-15 12:22:41 -0500366func TestInvalidInputArtifactId(t *testing.T) {
367 const inputString = `
368{
369 "artifacts": [{
370 "id": 1,
371 "pathFragmentId": 1
372 }, {
373 "id": 2,
374 "pathFragmentId": 2
375 }],
376 "actions": [{
377 "targetId": 1,
378 "actionKey": "x",
379 "mnemonic": "x",
380 "arguments": ["touch", "foo"],
381 "inputDepSetIds": [1],
382 "outputIds": [1],
383 "primaryOutputId": 1
384 }],
385 "depSetOfFiles": [{
386 "id": 1,
387 "directArtifactIds": [1, 3]
388 }],
389 "pathFragments": [{
390 "id": 1,
391 "label": "one"
392 }, {
393 "id": 2,
394 "label": "two"
395 }]
396}`
397
Chris Parsons1a7aca02022-04-25 22:35:15 -0400398 _, _, err := AqueryBuildStatements([]byte(inputString))
Chris Parsons4f069892021-01-15 12:22:41 -0500399 assertError(t, err, "undefined input artifactId 3")
400}
401
402func TestInvalidPathFragmentId(t *testing.T) {
403 const inputString = `
404{
405 "artifacts": [{
406 "id": 1,
407 "pathFragmentId": 1
408 }, {
409 "id": 2,
410 "pathFragmentId": 2
411 }],
412 "actions": [{
413 "targetId": 1,
414 "actionKey": "x",
415 "mnemonic": "x",
416 "arguments": ["touch", "foo"],
417 "inputDepSetIds": [1],
418 "outputIds": [1],
419 "primaryOutputId": 1
420 }],
421 "depSetOfFiles": [{
422 "id": 1,
423 "directArtifactIds": [1, 2]
424 }],
425 "pathFragments": [{
426 "id": 1,
427 "label": "one"
428 }, {
429 "id": 2,
430 "label": "two",
431 "parentId": 3
432 }]
433}`
434
Chris Parsons1a7aca02022-04-25 22:35:15 -0400435 _, _, err := AqueryBuildStatements([]byte(inputString))
Chris Parsons4f069892021-01-15 12:22:41 -0500436 assertError(t, err, "undefined path fragment id 3")
437}
438
Liz Kammerde116852021-03-25 16:42:37 -0400439func TestDepfiles(t *testing.T) {
440 const inputString = `
441{
442 "artifacts": [{
443 "id": 1,
444 "pathFragmentId": 1
445 }, {
446 "id": 2,
447 "pathFragmentId": 2
448 }, {
449 "id": 3,
450 "pathFragmentId": 3
451 }],
452 "actions": [{
453 "targetId": 1,
454 "actionKey": "x",
455 "mnemonic": "x",
456 "arguments": ["touch", "foo"],
457 "inputDepSetIds": [1],
458 "outputIds": [2, 3],
459 "primaryOutputId": 2
460 }],
461 "depSetOfFiles": [{
462 "id": 1,
463 "directArtifactIds": [1, 2, 3]
464 }],
465 "pathFragments": [{
466 "id": 1,
467 "label": "one"
468 }, {
469 "id": 2,
470 "label": "two"
471 }, {
472 "id": 3,
473 "label": "two.d"
474 }]
475}`
476
Chris Parsons1a7aca02022-04-25 22:35:15 -0400477 actual, _, err := AqueryBuildStatements([]byte(inputString))
Liz Kammerde116852021-03-25 16:42:37 -0400478 if err != nil {
479 t.Errorf("Unexpected error %q", err)
480 }
481 if expected := 1; len(actual) != expected {
482 t.Fatalf("Expected %d build statements, got %d", expected, len(actual))
483 }
484
485 bs := actual[0]
486 expectedDepfile := "two.d"
487 if bs.Depfile == nil {
488 t.Errorf("Expected depfile %q, but there was none found", expectedDepfile)
489 } else if *bs.Depfile != expectedDepfile {
490 t.Errorf("Expected depfile %q, but got %q", expectedDepfile, *bs.Depfile)
491 }
492}
493
494func TestMultipleDepfiles(t *testing.T) {
495 const inputString = `
496{
497 "artifacts": [{
498 "id": 1,
499 "pathFragmentId": 1
500 }, {
501 "id": 2,
502 "pathFragmentId": 2
503 }, {
504 "id": 3,
505 "pathFragmentId": 3
506 }, {
507 "id": 4,
508 "pathFragmentId": 4
509 }],
510 "actions": [{
511 "targetId": 1,
512 "actionKey": "x",
513 "mnemonic": "x",
514 "arguments": ["touch", "foo"],
515 "inputDepSetIds": [1],
516 "outputIds": [2,3,4],
517 "primaryOutputId": 2
518 }],
519 "depSetOfFiles": [{
520 "id": 1,
521 "directArtifactIds": [1, 2, 3, 4]
522 }],
523 "pathFragments": [{
524 "id": 1,
525 "label": "one"
526 }, {
527 "id": 2,
528 "label": "two"
529 }, {
530 "id": 3,
531 "label": "two.d"
532 }, {
533 "id": 4,
534 "label": "other.d"
535 }]
536}`
537
Chris Parsons1a7aca02022-04-25 22:35:15 -0400538 _, _, err := AqueryBuildStatements([]byte(inputString))
Liz Kammerde116852021-03-25 16:42:37 -0400539 assertError(t, err, `found multiple potential depfiles "two.d", "other.d"`)
540}
541
Chris Parsons943f2432021-01-19 11:36:50 -0500542func TestTransitiveInputDepsets(t *testing.T) {
543 // The input aquery for this test comes from a proof-of-concept starlark rule which registers
544 // a single action with many inputs given via a deep depset.
545 const inputString = `
546{
547 "artifacts": [{
548 "id": 1,
549 "pathFragmentId": 1
550 }, {
551 "id": 2,
552 "pathFragmentId": 7
553 }, {
554 "id": 3,
555 "pathFragmentId": 8
556 }, {
557 "id": 4,
558 "pathFragmentId": 9
559 }, {
560 "id": 5,
561 "pathFragmentId": 10
562 }, {
563 "id": 6,
564 "pathFragmentId": 11
565 }, {
566 "id": 7,
567 "pathFragmentId": 12
568 }, {
569 "id": 8,
570 "pathFragmentId": 13
571 }, {
572 "id": 9,
573 "pathFragmentId": 14
574 }, {
575 "id": 10,
576 "pathFragmentId": 15
577 }, {
578 "id": 11,
579 "pathFragmentId": 16
580 }, {
581 "id": 12,
582 "pathFragmentId": 17
583 }, {
584 "id": 13,
585 "pathFragmentId": 18
586 }, {
587 "id": 14,
588 "pathFragmentId": 19
589 }, {
590 "id": 15,
591 "pathFragmentId": 20
592 }, {
593 "id": 16,
594 "pathFragmentId": 21
595 }, {
596 "id": 17,
597 "pathFragmentId": 22
598 }, {
599 "id": 18,
600 "pathFragmentId": 23
601 }, {
602 "id": 19,
603 "pathFragmentId": 24
604 }, {
605 "id": 20,
606 "pathFragmentId": 25
607 }, {
608 "id": 21,
609 "pathFragmentId": 26
610 }],
611 "actions": [{
612 "targetId": 1,
613 "actionKey": "3b826d17fadbbbcd8313e456b90ec47c078c438088891dd45b4adbcd8889dc50",
614 "mnemonic": "Action",
615 "configurationId": 1,
616 "arguments": ["/bin/bash", "-c", "touch bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out"],
617 "inputDepSetIds": [1],
618 "outputIds": [21],
619 "primaryOutputId": 21
620 }],
621 "depSetOfFiles": [{
622 "id": 3,
623 "directArtifactIds": [1, 2, 3, 4, 5]
624 }, {
625 "id": 4,
626 "directArtifactIds": [6, 7, 8, 9, 10]
627 }, {
628 "id": 2,
629 "transitiveDepSetIds": [3, 4],
630 "directArtifactIds": [11, 12, 13, 14, 15]
631 }, {
632 "id": 5,
633 "directArtifactIds": [16, 17, 18, 19]
634 }, {
635 "id": 1,
636 "transitiveDepSetIds": [2, 5],
637 "directArtifactIds": [20]
638 }],
639 "pathFragments": [{
640 "id": 6,
641 "label": "bazel-out"
642 }, {
643 "id": 5,
644 "label": "sourceroot",
645 "parentId": 6
646 }, {
647 "id": 4,
648 "label": "k8-fastbuild",
649 "parentId": 5
650 }, {
651 "id": 3,
652 "label": "bin",
653 "parentId": 4
654 }, {
655 "id": 2,
656 "label": "testpkg",
657 "parentId": 3
658 }, {
659 "id": 1,
660 "label": "test_1",
661 "parentId": 2
662 }, {
663 "id": 7,
664 "label": "test_2",
665 "parentId": 2
666 }, {
667 "id": 8,
668 "label": "test_3",
669 "parentId": 2
670 }, {
671 "id": 9,
672 "label": "test_4",
673 "parentId": 2
674 }, {
675 "id": 10,
676 "label": "test_5",
677 "parentId": 2
678 }, {
679 "id": 11,
680 "label": "test_6",
681 "parentId": 2
682 }, {
683 "id": 12,
684 "label": "test_7",
685 "parentId": 2
686 }, {
687 "id": 13,
688 "label": "test_8",
689 "parentId": 2
690 }, {
691 "id": 14,
692 "label": "test_9",
693 "parentId": 2
694 }, {
695 "id": 15,
696 "label": "test_10",
697 "parentId": 2
698 }, {
699 "id": 16,
700 "label": "test_11",
701 "parentId": 2
702 }, {
703 "id": 17,
704 "label": "test_12",
705 "parentId": 2
706 }, {
707 "id": 18,
708 "label": "test_13",
709 "parentId": 2
710 }, {
711 "id": 19,
712 "label": "test_14",
713 "parentId": 2
714 }, {
715 "id": 20,
716 "label": "test_15",
717 "parentId": 2
718 }, {
719 "id": 21,
720 "label": "test_16",
721 "parentId": 2
722 }, {
723 "id": 22,
724 "label": "test_17",
725 "parentId": 2
726 }, {
727 "id": 23,
728 "label": "test_18",
729 "parentId": 2
730 }, {
731 "id": 24,
732 "label": "test_19",
733 "parentId": 2
734 }, {
735 "id": 25,
736 "label": "test_root",
737 "parentId": 2
738 }, {
739 "id": 26,
740 "label": "test_out",
741 "parentId": 2
742 }]
743}`
744
Chris Parsons1a7aca02022-04-25 22:35:15 -0400745 actualbuildStatements, actualDepsets, _ := AqueryBuildStatements([]byte(inputString))
746
Chris Parsons943f2432021-01-19 11:36:50 -0500747 expectedBuildStatements := []BuildStatement{
748 BuildStatement{
Chris Parsons1a7aca02022-04-25 22:35:15 -0400749 Command: "/bin/bash -c 'touch bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out'",
750 OutputPaths: []string{"bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out"},
751 InputDepsetIds: []int{1},
752 Mnemonic: "Action",
Chris Parsons943f2432021-01-19 11:36:50 -0500753 },
754 }
755 assertBuildStatements(t, expectedBuildStatements, actualbuildStatements)
Chris Parsons1a7aca02022-04-25 22:35:15 -0400756
757 // Inputs for the action are test_{i} from 1 to 20, and test_root. These inputs
758 // are given via a deep depset, but the depset is flattened when returned as a
759 // BuildStatement slice.
760 expectedFlattenedInputs := []string{}
761 for i := 1; i < 20; i++ {
762 expectedFlattenedInputs = append(expectedFlattenedInputs, fmt.Sprintf("bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_%d", i))
763 }
764 expectedFlattenedInputs = append(expectedFlattenedInputs, "bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_root")
765
766 actualFlattenedInputs := flattenDepsets([]int{1}, actualDepsets)
767 if !reflect.DeepEqual(actualFlattenedInputs, expectedFlattenedInputs) {
768 t.Errorf("Expected flattened inputs %v, but got %v", expectedFlattenedInputs, actualFlattenedInputs)
769 }
Chris Parsons943f2432021-01-19 11:36:50 -0500770}
771
Chris Parsonsc4fb1332021-05-18 12:31:25 -0400772func TestMiddlemenAction(t *testing.T) {
773 const inputString = `
774{
775 "artifacts": [{
776 "id": 1,
777 "pathFragmentId": 1
778 }, {
779 "id": 2,
780 "pathFragmentId": 2
781 }, {
782 "id": 3,
783 "pathFragmentId": 3
784 }, {
785 "id": 4,
786 "pathFragmentId": 4
787 }, {
788 "id": 5,
789 "pathFragmentId": 5
790 }, {
791 "id": 6,
792 "pathFragmentId": 6
793 }],
794 "pathFragments": [{
795 "id": 1,
796 "label": "middleinput_one"
797 }, {
798 "id": 2,
799 "label": "middleinput_two"
800 }, {
801 "id": 3,
802 "label": "middleman_artifact"
803 }, {
804 "id": 4,
805 "label": "maininput_one"
806 }, {
807 "id": 5,
808 "label": "maininput_two"
809 }, {
810 "id": 6,
811 "label": "output"
812 }],
813 "depSetOfFiles": [{
814 "id": 1,
815 "directArtifactIds": [1, 2]
816 }, {
817 "id": 2,
818 "directArtifactIds": [3, 4, 5]
819 }],
820 "actions": [{
821 "targetId": 1,
822 "actionKey": "x",
823 "mnemonic": "Middleman",
824 "arguments": ["touch", "foo"],
825 "inputDepSetIds": [1],
826 "outputIds": [3],
827 "primaryOutputId": 3
828 }, {
829 "targetId": 2,
830 "actionKey": "y",
831 "mnemonic": "Main action",
832 "arguments": ["touch", "foo"],
833 "inputDepSetIds": [2],
834 "outputIds": [6],
835 "primaryOutputId": 6
836 }]
837}`
838
Chris Parsons1a7aca02022-04-25 22:35:15 -0400839 actualBuildStatements, actualDepsets, err := AqueryBuildStatements([]byte(inputString))
Chris Parsonsc4fb1332021-05-18 12:31:25 -0400840 if err != nil {
841 t.Errorf("Unexpected error %q", err)
842 }
Chris Parsons1a7aca02022-04-25 22:35:15 -0400843 if expected := 1; len(actualBuildStatements) != expected {
844 t.Fatalf("Expected %d build statements, got %d", expected, len(actualBuildStatements))
Chris Parsonsc4fb1332021-05-18 12:31:25 -0400845 }
846
Chris Parsons1a7aca02022-04-25 22:35:15 -0400847 bs := actualBuildStatements[0]
848 if len(bs.InputPaths) > 0 {
849 t.Errorf("Expected main action raw inputs to be empty, but got %q", bs.InputPaths)
850 }
851
852 expectedInputDepsets := []int{2}
853 if !reflect.DeepEqual(bs.InputDepsetIds, expectedInputDepsets) {
854 t.Errorf("Expected main action depset IDs %v, but got %v", expectedInputDepsets, bs.InputDepsetIds)
Chris Parsonsc4fb1332021-05-18 12:31:25 -0400855 }
856
857 expectedOutputs := []string{"output"}
858 if !reflect.DeepEqual(bs.OutputPaths, expectedOutputs) {
859 t.Errorf("Expected main action outputs %q, but got %q", expectedOutputs, bs.OutputPaths)
860 }
Chris Parsons1a7aca02022-04-25 22:35:15 -0400861
862 expectedAllDepsets := []AqueryDepset{
863 {
864 Id: 1,
865 DirectArtifacts: []string{"middleinput_one", "middleinput_two"},
866 },
867 {
868 Id: 2,
869 DirectArtifacts: []string{"maininput_one", "maininput_two"},
870 TransitiveDepSetIds: []int{1},
871 },
872 }
873 if !reflect.DeepEqual(actualDepsets, expectedAllDepsets) {
874 t.Errorf("Expected depsets %v, but got %v", expectedAllDepsets, actualDepsets)
875 }
876
877 expectedFlattenedInputs := []string{"middleinput_one", "middleinput_two", "maininput_one", "maininput_two"}
878 actualFlattenedInputs := flattenDepsets(bs.InputDepsetIds, actualDepsets)
879
880 if !reflect.DeepEqual(actualFlattenedInputs, expectedFlattenedInputs) {
881 t.Errorf("Expected flattened inputs %v, but got %v", expectedFlattenedInputs, actualFlattenedInputs)
882 }
883}
884
885// Returns the contents of given depsets in concatenated post order.
886func flattenDepsets(depsetIdsToFlatten []int, allDepsets []AqueryDepset) []string {
887 depsetsById := map[int]AqueryDepset{}
888 for _, depset := range allDepsets {
889 depsetsById[depset.Id] = depset
890 }
891 result := []string{}
892 for _, depsetId := range depsetIdsToFlatten {
893 result = append(result, flattenDepset(depsetId, depsetsById)...)
894 }
895 return result
896}
897
898// Returns the contents of a given depset in post order.
899func flattenDepset(depsetIdToFlatten int, allDepsets map[int]AqueryDepset) []string {
900 depset := allDepsets[depsetIdToFlatten]
901 result := []string{}
902 for _, depsetId := range depset.TransitiveDepSetIds {
903 result = append(result, flattenDepset(depsetId, allDepsets)...)
904 }
905 result = append(result, depset.DirectArtifacts...)
906 return result
Chris Parsonsc4fb1332021-05-18 12:31:25 -0400907}
908
Liz Kammerc49e6822021-06-08 15:04:11 -0400909func TestSimpleSymlink(t *testing.T) {
910 const inputString = `
911{
912 "artifacts": [{
913 "id": 1,
914 "pathFragmentId": 3
915 }, {
916 "id": 2,
917 "pathFragmentId": 5
918 }],
919 "actions": [{
920 "targetId": 1,
921 "actionKey": "x",
922 "mnemonic": "Symlink",
923 "inputDepSetIds": [1],
924 "outputIds": [2],
925 "primaryOutputId": 2
926 }],
927 "depSetOfFiles": [{
928 "id": 1,
929 "directArtifactIds": [1]
930 }],
931 "pathFragments": [{
932 "id": 1,
933 "label": "one"
934 }, {
935 "id": 2,
936 "label": "file_subdir",
937 "parentId": 1
938 }, {
939 "id": 3,
940 "label": "file",
941 "parentId": 2
942 }, {
943 "id": 4,
944 "label": "symlink_subdir",
945 "parentId": 1
946 }, {
947 "id": 5,
948 "label": "symlink",
949 "parentId": 4
950 }]
951}`
952
Chris Parsons1a7aca02022-04-25 22:35:15 -0400953 actual, _, err := AqueryBuildStatements([]byte(inputString))
Liz Kammerc49e6822021-06-08 15:04:11 -0400954
955 if err != nil {
956 t.Errorf("Unexpected error %q", err)
957 }
958
959 expectedBuildStatements := []BuildStatement{
960 BuildStatement{
961 Command: "mkdir -p one/symlink_subdir && " +
962 "rm -f one/symlink_subdir/symlink && " +
Liz Kammerc7737782021-11-04 10:56:13 -0400963 "ln -sf $PWD/one/file_subdir/file one/symlink_subdir/symlink",
Liz Kammerc49e6822021-06-08 15:04:11 -0400964 InputPaths: []string{"one/file_subdir/file"},
965 OutputPaths: []string{"one/symlink_subdir/symlink"},
966 SymlinkPaths: []string{"one/symlink_subdir/symlink"},
967 Mnemonic: "Symlink",
968 },
969 }
970 assertBuildStatements(t, actual, expectedBuildStatements)
971}
972
973func TestSymlinkQuotesPaths(t *testing.T) {
974 const inputString = `
975{
976 "artifacts": [{
977 "id": 1,
978 "pathFragmentId": 3
979 }, {
980 "id": 2,
981 "pathFragmentId": 5
982 }],
983 "actions": [{
984 "targetId": 1,
985 "actionKey": "x",
986 "mnemonic": "SolibSymlink",
987 "inputDepSetIds": [1],
988 "outputIds": [2],
989 "primaryOutputId": 2
990 }],
991 "depSetOfFiles": [{
992 "id": 1,
993 "directArtifactIds": [1]
994 }],
995 "pathFragments": [{
996 "id": 1,
997 "label": "one"
998 }, {
999 "id": 2,
1000 "label": "file subdir",
1001 "parentId": 1
1002 }, {
1003 "id": 3,
1004 "label": "file",
1005 "parentId": 2
1006 }, {
1007 "id": 4,
1008 "label": "symlink subdir",
1009 "parentId": 1
1010 }, {
1011 "id": 5,
1012 "label": "symlink",
1013 "parentId": 4
1014 }]
1015}`
1016
Chris Parsons1a7aca02022-04-25 22:35:15 -04001017 actual, _, err := AqueryBuildStatements([]byte(inputString))
Liz Kammerc49e6822021-06-08 15:04:11 -04001018
1019 if err != nil {
1020 t.Errorf("Unexpected error %q", err)
1021 }
1022
1023 expectedBuildStatements := []BuildStatement{
1024 BuildStatement{
1025 Command: "mkdir -p 'one/symlink subdir' && " +
1026 "rm -f 'one/symlink subdir/symlink' && " +
Liz Kammerc7737782021-11-04 10:56:13 -04001027 "ln -sf $PWD/'one/file subdir/file' 'one/symlink subdir/symlink'",
Liz Kammerc49e6822021-06-08 15:04:11 -04001028 InputPaths: []string{"one/file subdir/file"},
1029 OutputPaths: []string{"one/symlink subdir/symlink"},
1030 SymlinkPaths: []string{"one/symlink subdir/symlink"},
1031 Mnemonic: "SolibSymlink",
1032 },
1033 }
Liz Kammerc7737782021-11-04 10:56:13 -04001034 assertBuildStatements(t, expectedBuildStatements, actual)
Liz Kammerc49e6822021-06-08 15:04:11 -04001035}
1036
1037func TestSymlinkMultipleInputs(t *testing.T) {
1038 const inputString = `
1039{
1040 "artifacts": [{
1041 "id": 1,
1042 "pathFragmentId": 1
1043 }, {
1044 "id": 2,
1045 "pathFragmentId": 2
1046 }, {
1047 "id": 3,
1048 "pathFragmentId": 3
1049 }],
1050 "actions": [{
1051 "targetId": 1,
1052 "actionKey": "x",
1053 "mnemonic": "Symlink",
1054 "inputDepSetIds": [1],
1055 "outputIds": [3],
1056 "primaryOutputId": 3
1057 }],
1058 "depSetOfFiles": [{
1059 "id": 1,
1060 "directArtifactIds": [1,2]
1061 }],
1062 "pathFragments": [{
1063 "id": 1,
1064 "label": "file"
1065 }, {
1066 "id": 2,
1067 "label": "other_file"
1068 }, {
1069 "id": 3,
1070 "label": "symlink"
1071 }]
1072}`
1073
Chris Parsons1a7aca02022-04-25 22:35:15 -04001074 _, _, err := AqueryBuildStatements([]byte(inputString))
Liz Kammerc49e6822021-06-08 15:04:11 -04001075 assertError(t, err, `Expect 1 input and 1 output to symlink action, got: input ["file" "other_file"], output ["symlink"]`)
1076}
1077
1078func TestSymlinkMultipleOutputs(t *testing.T) {
1079 const inputString = `
1080{
1081 "artifacts": [{
1082 "id": 1,
1083 "pathFragmentId": 1
1084 }, {
1085 "id": 2,
1086 "pathFragmentId": 2
1087 }, {
1088 "id": 3,
1089 "pathFragmentId": 3
1090 }],
1091 "actions": [{
1092 "targetId": 1,
1093 "actionKey": "x",
1094 "mnemonic": "Symlink",
1095 "inputDepSetIds": [1],
1096 "outputIds": [2,3],
1097 "primaryOutputId": 2
1098 }],
1099 "depSetOfFiles": [{
1100 "id": 1,
1101 "directArtifactIds": [1]
1102 }],
1103 "pathFragments": [{
1104 "id": 1,
1105 "label": "file"
1106 }, {
1107 "id": 2,
1108 "label": "symlink"
1109 }, {
1110 "id": 3,
1111 "label": "other_symlink"
1112 }]
1113}`
1114
Chris Parsons1a7aca02022-04-25 22:35:15 -04001115 _, _, err := AqueryBuildStatements([]byte(inputString))
Liz Kammerc49e6822021-06-08 15:04:11 -04001116 assertError(t, err, `Expect 1 input and 1 output to symlink action, got: input ["file"], output ["symlink" "other_symlink"]`)
1117}
1118
Wei Li455ba832021-11-04 22:58:12 +00001119func TestTemplateExpandActionSubstitutions(t *testing.T) {
1120 const inputString = `
1121{
1122 "artifacts": [{
1123 "id": 1,
1124 "pathFragmentId": 1
1125 }],
1126 "actions": [{
1127 "targetId": 1,
1128 "actionKey": "x",
1129 "mnemonic": "TemplateExpand",
1130 "configurationId": 1,
1131 "outputIds": [1],
1132 "primaryOutputId": 1,
1133 "executionPlatform": "//build/bazel/platforms:linux_x86_64",
1134 "templateContent": "Test template substitutions: %token1%, %python_binary%",
1135 "substitutions": [{
1136 "key": "%token1%",
1137 "value": "abcd"
1138 },{
1139 "key": "%python_binary%",
1140 "value": "python3"
1141 }]
1142 }],
1143 "pathFragments": [{
1144 "id": 1,
1145 "label": "template_file"
1146 }]
1147}`
1148
Chris Parsons1a7aca02022-04-25 22:35:15 -04001149 actual, _, err := AqueryBuildStatements([]byte(inputString))
Wei Li455ba832021-11-04 22:58:12 +00001150
1151 if err != nil {
1152 t.Errorf("Unexpected error %q", err)
1153 }
1154
1155 expectedBuildStatements := []BuildStatement{
1156 BuildStatement{
1157 Command: "/bin/bash -c 'echo \"Test template substitutions: abcd, python3\" | sed \"s/\\\\\\\\n/\\\\n/g\" > template_file && " +
1158 "chmod a+x template_file'",
1159 OutputPaths: []string{"template_file"},
1160 Mnemonic: "TemplateExpand",
1161 },
1162 }
1163 assertBuildStatements(t, expectedBuildStatements, actual)
1164}
1165
1166func TestTemplateExpandActionNoOutput(t *testing.T) {
1167 const inputString = `
1168{
1169 "artifacts": [{
1170 "id": 1,
1171 "pathFragmentId": 1
1172 }],
1173 "actions": [{
1174 "targetId": 1,
1175 "actionKey": "x",
1176 "mnemonic": "TemplateExpand",
1177 "configurationId": 1,
1178 "primaryOutputId": 1,
1179 "executionPlatform": "//build/bazel/platforms:linux_x86_64",
1180 "templateContent": "Test template substitutions: %token1%, %python_binary%",
1181 "substitutions": [{
1182 "key": "%token1%",
1183 "value": "abcd"
1184 },{
1185 "key": "%python_binary%",
1186 "value": "python3"
1187 }]
1188 }],
1189 "pathFragments": [{
1190 "id": 1,
1191 "label": "template_file"
1192 }]
1193}`
1194
Chris Parsons1a7aca02022-04-25 22:35:15 -04001195 _, _, err := AqueryBuildStatements([]byte(inputString))
Wei Li455ba832021-11-04 22:58:12 +00001196 assertError(t, err, `Expect 1 output to template expand action, got: output []`)
1197}
1198
1199func TestPythonZipperActionSuccess(t *testing.T) {
1200 const inputString = `
1201{
1202 "artifacts": [{
1203 "id": 1,
1204 "pathFragmentId": 1
1205 },{
1206 "id": 2,
1207 "pathFragmentId": 2
1208 },{
1209 "id": 3,
1210 "pathFragmentId": 3
1211 },{
1212 "id": 4,
1213 "pathFragmentId": 4
1214 },{
1215 "id": 5,
1216 "pathFragmentId": 10
1217 },{
1218 "id": 10,
1219 "pathFragmentId": 20
1220 }],
1221 "actions": [{
1222 "targetId": 1,
1223 "actionKey": "x",
1224 "mnemonic": "TemplateExpand",
1225 "configurationId": 1,
1226 "outputIds": [1],
1227 "primaryOutputId": 1,
1228 "executionPlatform": "//build/bazel/platforms:linux_x86_64",
1229 "templateContent": "Test template substitutions: %token1%, %python_binary%",
1230 "substitutions": [{
1231 "key": "%token1%",
1232 "value": "abcd"
1233 },{
1234 "key": "%python_binary%",
1235 "value": "python3"
1236 }]
1237 },{
1238 "targetId": 1,
1239 "actionKey": "x",
1240 "mnemonic": "PythonZipper",
1241 "configurationId": 1,
1242 "arguments": ["../bazel_tools/tools/zip/zipper/zipper", "cC", "python_binary.zip", "__main__.py\u003dbazel-out/k8-fastbuild/bin/python_binary.temp", "__init__.py\u003d", "runfiles/__main__/__init__.py\u003d", "runfiles/__main__/python_binary.py\u003dpython_binary.py", "runfiles/bazel_tools/tools/python/py3wrapper.sh\u003dbazel-out/bazel_tools/k8-fastbuild/bin/tools/python/py3wrapper.sh"],
1243 "outputIds": [2],
1244 "inputDepSetIds": [1],
1245 "primaryOutputId": 2
1246 }],
1247 "depSetOfFiles": [{
1248 "id": 1,
1249 "directArtifactIds": [4, 3, 5]
1250 }],
1251 "pathFragments": [{
1252 "id": 1,
1253 "label": "python_binary"
1254 },{
1255 "id": 2,
1256 "label": "python_binary.zip"
1257 },{
1258 "id": 3,
1259 "label": "python_binary.py"
1260 },{
1261 "id": 9,
1262 "label": ".."
1263 }, {
1264 "id": 8,
1265 "label": "bazel_tools",
1266 "parentId": 9
1267 }, {
1268 "id": 7,
1269 "label": "tools",
1270 "parentId": 8
1271 }, {
1272 "id": 6,
1273 "label": "zip",
1274 "parentId": 7
1275 }, {
1276 "id": 5,
1277 "label": "zipper",
1278 "parentId": 6
1279 }, {
1280 "id": 4,
1281 "label": "zipper",
1282 "parentId": 5
1283 },{
1284 "id": 16,
1285 "label": "bazel-out"
1286 },{
1287 "id": 15,
1288 "label": "bazel_tools",
1289 "parentId": 16
1290 }, {
1291 "id": 14,
1292 "label": "k8-fastbuild",
1293 "parentId": 15
1294 }, {
1295 "id": 13,
1296 "label": "bin",
1297 "parentId": 14
1298 }, {
1299 "id": 12,
1300 "label": "tools",
1301 "parentId": 13
1302 }, {
1303 "id": 11,
1304 "label": "python",
1305 "parentId": 12
1306 }, {
1307 "id": 10,
1308 "label": "py3wrapper.sh",
1309 "parentId": 11
1310 },{
1311 "id": 20,
1312 "label": "python_binary"
1313 }]
1314}`
Chris Parsons1a7aca02022-04-25 22:35:15 -04001315 actual, _, err := AqueryBuildStatements([]byte(inputString))
Wei Li455ba832021-11-04 22:58:12 +00001316
1317 if err != nil {
1318 t.Errorf("Unexpected error %q", err)
1319 }
1320
1321 expectedBuildStatements := []BuildStatement{
1322 BuildStatement{
1323 Command: "/bin/bash -c 'echo \"Test template substitutions: abcd, python3\" | sed \"s/\\\\\\\\n/\\\\n/g\" > python_binary && " +
1324 "chmod a+x python_binary'",
1325 InputPaths: []string{"python_binary.zip"},
1326 OutputPaths: []string{"python_binary"},
1327 Mnemonic: "TemplateExpand",
1328 },
1329 BuildStatement{
1330 Command: "../bazel_tools/tools/zip/zipper/zipper cC python_binary.zip __main__.py=bazel-out/k8-fastbuild/bin/python_binary.temp " +
1331 "__init__.py= runfiles/__main__/__init__.py= runfiles/__main__/python_binary.py=python_binary.py && " +
1332 "../bazel_tools/tools/zip/zipper/zipper x python_binary.zip -d python_binary.runfiles && ln -sf runfiles/__main__ python_binary.runfiles",
1333 InputPaths: []string{"../bazel_tools/tools/zip/zipper/zipper", "python_binary.py"},
1334 OutputPaths: []string{"python_binary.zip"},
1335 Mnemonic: "PythonZipper",
1336 },
1337 }
1338 assertBuildStatements(t, expectedBuildStatements, actual)
1339}
1340
1341func TestPythonZipperActionNoInput(t *testing.T) {
1342 const inputString = `
1343{
1344 "artifacts": [{
1345 "id": 1,
1346 "pathFragmentId": 1
1347 },{
1348 "id": 2,
1349 "pathFragmentId": 2
1350 }],
1351 "actions": [{
1352 "targetId": 1,
1353 "actionKey": "x",
1354 "mnemonic": "PythonZipper",
1355 "configurationId": 1,
1356 "arguments": ["../bazel_tools/tools/zip/zipper/zipper", "cC", "python_binary.zip", "__main__.py\u003dbazel-out/k8-fastbuild/bin/python_binary.temp", "__init__.py\u003d", "runfiles/__main__/__init__.py\u003d", "runfiles/__main__/python_binary.py\u003dpython_binary.py", "runfiles/bazel_tools/tools/python/py3wrapper.sh\u003dbazel-out/bazel_tools/k8-fastbuild/bin/tools/python/py3wrapper.sh"],
1357 "outputIds": [2],
1358 "primaryOutputId": 2
1359 }],
1360 "pathFragments": [{
1361 "id": 1,
1362 "label": "python_binary"
1363 },{
1364 "id": 2,
1365 "label": "python_binary.zip"
1366 }]
1367}`
Chris Parsons1a7aca02022-04-25 22:35:15 -04001368 _, _, err := AqueryBuildStatements([]byte(inputString))
Wei Li455ba832021-11-04 22:58:12 +00001369 assertError(t, err, `Expect 1+ input and 1 output to python zipper action, got: input [], output ["python_binary.zip"]`)
1370}
1371
1372func TestPythonZipperActionNoOutput(t *testing.T) {
1373 const inputString = `
1374{
1375 "artifacts": [{
1376 "id": 1,
1377 "pathFragmentId": 1
1378 },{
1379 "id": 2,
1380 "pathFragmentId": 2
1381 },{
1382 "id": 3,
1383 "pathFragmentId": 3
1384 },{
1385 "id": 4,
1386 "pathFragmentId": 4
1387 },{
1388 "id": 5,
1389 "pathFragmentId": 10
1390 }],
1391 "actions": [{
1392 "targetId": 1,
1393 "actionKey": "x",
1394 "mnemonic": "PythonZipper",
1395 "configurationId": 1,
1396 "arguments": ["../bazel_tools/tools/zip/zipper/zipper", "cC", "python_binary.zip", "__main__.py\u003dbazel-out/k8-fastbuild/bin/python_binary.temp", "__init__.py\u003d", "runfiles/__main__/__init__.py\u003d", "runfiles/__main__/python_binary.py\u003dpython_binary.py", "runfiles/bazel_tools/tools/python/py3wrapper.sh\u003dbazel-out/bazel_tools/k8-fastbuild/bin/tools/python/py3wrapper.sh"],
1397 "inputDepSetIds": [1]
1398 }],
1399 "depSetOfFiles": [{
1400 "id": 1,
1401 "directArtifactIds": [4, 3, 5]
1402 }],
1403 "pathFragments": [{
1404 "id": 1,
1405 "label": "python_binary"
1406 },{
1407 "id": 2,
1408 "label": "python_binary.zip"
1409 },{
1410 "id": 3,
1411 "label": "python_binary.py"
1412 },{
1413 "id": 9,
1414 "label": ".."
1415 }, {
1416 "id": 8,
1417 "label": "bazel_tools",
1418 "parentId": 9
1419 }, {
1420 "id": 7,
1421 "label": "tools",
1422 "parentId": 8
1423 }, {
1424 "id": 6,
1425 "label": "zip",
1426 "parentId": 7
1427 }, {
1428 "id": 5,
1429 "label": "zipper",
1430 "parentId": 6
1431 }, {
1432 "id": 4,
1433 "label": "zipper",
1434 "parentId": 5
1435 },{
1436 "id": 16,
1437 "label": "bazel-out"
1438 },{
1439 "id": 15,
1440 "label": "bazel_tools",
1441 "parentId": 16
1442 }, {
1443 "id": 14,
1444 "label": "k8-fastbuild",
1445 "parentId": 15
1446 }, {
1447 "id": 13,
1448 "label": "bin",
1449 "parentId": 14
1450 }, {
1451 "id": 12,
1452 "label": "tools",
1453 "parentId": 13
1454 }, {
1455 "id": 11,
1456 "label": "python",
1457 "parentId": 12
1458 }, {
1459 "id": 10,
1460 "label": "py3wrapper.sh",
1461 "parentId": 11
1462 }]
1463}`
Chris Parsons1a7aca02022-04-25 22:35:15 -04001464 _, _, err := AqueryBuildStatements([]byte(inputString))
Wei Li455ba832021-11-04 22:58:12 +00001465 assertError(t, err, `Expect 1+ input and 1 output to python zipper action, got: input ["../bazel_tools/tools/zip/zipper/zipper" "python_binary.py"], output []`)
1466}
1467
Chris Parsons4f069892021-01-15 12:22:41 -05001468func assertError(t *testing.T, err error, expected string) {
Liz Kammerc49e6822021-06-08 15:04:11 -04001469 t.Helper()
Chris Parsons943f2432021-01-19 11:36:50 -05001470 if err == nil {
1471 t.Errorf("expected error '%s', but got no error", expected)
1472 } else if err.Error() != expected {
Liz Kammerc49e6822021-06-08 15:04:11 -04001473 t.Errorf("expected error:\n\t'%s', but got:\n\t'%s'", expected, err.Error())
Chris Parsons4f069892021-01-15 12:22:41 -05001474 }
1475}
1476
1477// Asserts that the given actual build statements match the given expected build statements.
1478// Build statement equivalence is determined using buildStatementEquals.
1479func assertBuildStatements(t *testing.T, expected []BuildStatement, actual []BuildStatement) {
Liz Kammerc49e6822021-06-08 15:04:11 -04001480 t.Helper()
Chris Parsons4f069892021-01-15 12:22:41 -05001481 if len(expected) != len(actual) {
Liz Kammerc3192992021-11-16 17:01:11 -05001482 t.Errorf("expected %d build statements, but got %d,\n expected: %#v,\n actual: %#v",
Chris Parsons4f069892021-01-15 12:22:41 -05001483 len(expected), len(actual), expected, actual)
1484 return
1485 }
1486ACTUAL_LOOP:
1487 for _, actualStatement := range actual {
1488 for _, expectedStatement := range expected {
1489 if buildStatementEquals(actualStatement, expectedStatement) {
1490 continue ACTUAL_LOOP
1491 }
1492 }
Liz Kammerc3192992021-11-16 17:01:11 -05001493 t.Errorf("unexpected build statement %#v.\n expected: %#v",
Chris Parsons4f069892021-01-15 12:22:41 -05001494 actualStatement, expected)
1495 return
1496 }
1497}
1498
1499func buildStatementEquals(first BuildStatement, second BuildStatement) bool {
1500 if first.Mnemonic != second.Mnemonic {
1501 return false
1502 }
1503 if first.Command != second.Command {
1504 return false
1505 }
1506 // Ordering is significant for environment variables.
1507 if !reflect.DeepEqual(first.Env, second.Env) {
1508 return false
1509 }
1510 // Ordering is irrelevant for input and output paths, so compare sets.
1511 if !reflect.DeepEqual(stringSet(first.InputPaths), stringSet(second.InputPaths)) {
1512 return false
1513 }
1514 if !reflect.DeepEqual(stringSet(first.OutputPaths), stringSet(second.OutputPaths)) {
1515 return false
1516 }
Liz Kammerc49e6822021-06-08 15:04:11 -04001517 if !reflect.DeepEqual(stringSet(first.SymlinkPaths), stringSet(second.SymlinkPaths)) {
1518 return false
1519 }
1520 if first.Depfile != second.Depfile {
1521 return false
1522 }
Chris Parsons4f069892021-01-15 12:22:41 -05001523 return true
1524}
1525
1526func stringSet(stringSlice []string) map[string]struct{} {
1527 stringMap := make(map[string]struct{})
1528 for _, s := range stringSlice {
1529 stringMap[s] = struct{}{}
1530 }
1531 return stringMap
1532}