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