blob: 9cd8d451deb53761a6fab2755a4eb7382221e128 [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"
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -040020 "sort"
Chris Parsons4f069892021-01-15 12:22:41 -050021 "testing"
22)
23
24func TestAqueryMultiArchGenrule(t *testing.T) {
25 // This input string is retrieved from a real build of bionic-related genrules.
26 const inputString = `
27{
28 "artifacts": [{
29 "id": 1,
30 "pathFragmentId": 1
31 }, {
32 "id": 2,
33 "pathFragmentId": 6
34 }, {
35 "id": 3,
36 "pathFragmentId": 8
37 }, {
38 "id": 4,
39 "pathFragmentId": 12
40 }, {
41 "id": 5,
42 "pathFragmentId": 19
43 }, {
44 "id": 6,
45 "pathFragmentId": 20
46 }, {
47 "id": 7,
48 "pathFragmentId": 21
49 }],
50 "actions": [{
51 "targetId": 1,
52 "actionKey": "ab53f6ecbdc2ee8cb8812613b63205464f1f5083f6dca87081a0a398c0f1ecf7",
53 "mnemonic": "Genrule",
54 "configurationId": 1,
55 "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"],
56 "environmentVariables": [{
57 "key": "PATH",
58 "value": "/bin:/usr/bin:/usr/local/bin"
59 }],
60 "inputDepSetIds": [1],
61 "outputIds": [4],
62 "primaryOutputId": 4
63 }, {
64 "targetId": 2,
65 "actionKey": "9f4309ce165dac458498cb92811c18b0b7919782cc37b82a42d2141b8cc90826",
66 "mnemonic": "Genrule",
67 "configurationId": 1,
68 "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"],
69 "environmentVariables": [{
70 "key": "PATH",
71 "value": "/bin:/usr/bin:/usr/local/bin"
72 }],
73 "inputDepSetIds": [2],
74 "outputIds": [5],
75 "primaryOutputId": 5
76 }, {
77 "targetId": 3,
78 "actionKey": "50d6c586103ebeed3a218195540bcc30d329464eae36377eb82f8ce7c36ac342",
79 "mnemonic": "Genrule",
80 "configurationId": 1,
81 "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"],
82 "environmentVariables": [{
83 "key": "PATH",
84 "value": "/bin:/usr/bin:/usr/local/bin"
85 }],
86 "inputDepSetIds": [3],
87 "outputIds": [6],
88 "primaryOutputId": 6
89 }, {
90 "targetId": 4,
91 "actionKey": "f30cbe442f5216f4223cf16a39112cad4ec56f31f49290d85cff587e48647ffa",
92 "mnemonic": "Genrule",
93 "configurationId": 1,
94 "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"],
95 "environmentVariables": [{
96 "key": "PATH",
97 "value": "/bin:/usr/bin:/usr/local/bin"
98 }],
99 "inputDepSetIds": [4],
100 "outputIds": [7],
101 "primaryOutputId": 7
102 }],
103 "targets": [{
104 "id": 1,
105 "label": "@sourceroot//bionic/libc:syscalls-arm",
106 "ruleClassId": 1
107 }, {
108 "id": 2,
109 "label": "@sourceroot//bionic/libc:syscalls-x86",
110 "ruleClassId": 1
111 }, {
112 "id": 3,
113 "label": "@sourceroot//bionic/libc:syscalls-x86_64",
114 "ruleClassId": 1
115 }, {
116 "id": 4,
117 "label": "@sourceroot//bionic/libc:syscalls-arm64",
118 "ruleClassId": 1
119 }],
120 "depSetOfFiles": [{
121 "id": 1,
122 "directArtifactIds": [1, 2, 3]
123 }, {
124 "id": 2,
125 "directArtifactIds": [1, 2, 3]
126 }, {
127 "id": 3,
128 "directArtifactIds": [1, 2, 3]
129 }, {
130 "id": 4,
131 "directArtifactIds": [1, 2, 3]
132 }],
133 "configuration": [{
134 "id": 1,
135 "mnemonic": "k8-fastbuild",
136 "platformName": "k8",
137 "checksum": "485c362832c178e367d972177f68e69e0981e51e67ef1c160944473db53fe046"
138 }],
139 "ruleClasses": [{
140 "id": 1,
141 "name": "genrule"
142 }],
143 "pathFragments": [{
144 "id": 5,
145 "label": ".."
146 }, {
147 "id": 4,
148 "label": "sourceroot",
149 "parentId": 5
150 }, {
151 "id": 3,
152 "label": "bionic",
153 "parentId": 4
154 }, {
155 "id": 2,
156 "label": "libc",
157 "parentId": 3
158 }, {
159 "id": 1,
160 "label": "SYSCALLS.TXT",
161 "parentId": 2
162 }, {
163 "id": 7,
164 "label": "tools",
165 "parentId": 2
166 }, {
167 "id": 6,
168 "label": "gensyscalls.py",
169 "parentId": 7
170 }, {
171 "id": 11,
172 "label": "bazel_tools",
173 "parentId": 5
174 }, {
175 "id": 10,
176 "label": "tools",
177 "parentId": 11
178 }, {
179 "id": 9,
180 "label": "genrule",
181 "parentId": 10
182 }, {
183 "id": 8,
184 "label": "genrule-setup.sh",
185 "parentId": 9
186 }, {
187 "id": 18,
188 "label": "bazel-out"
189 }, {
190 "id": 17,
191 "label": "sourceroot",
192 "parentId": 18
193 }, {
194 "id": 16,
195 "label": "k8-fastbuild",
196 "parentId": 17
197 }, {
198 "id": 15,
199 "label": "bin",
200 "parentId": 16
201 }, {
202 "id": 14,
203 "label": "bionic",
204 "parentId": 15
205 }, {
206 "id": 13,
207 "label": "libc",
208 "parentId": 14
209 }, {
210 "id": 12,
211 "label": "syscalls-arm.S",
212 "parentId": 13
213 }, {
214 "id": 19,
215 "label": "syscalls-x86.S",
216 "parentId": 13
217 }, {
218 "id": 20,
219 "label": "syscalls-x86_64.S",
220 "parentId": 13
221 }, {
222 "id": 21,
223 "label": "syscalls-arm64.S",
224 "parentId": 13
225 }]
226}`
Chris Parsons1a7aca02022-04-25 22:35:15 -0400227 actualbuildStatements, actualDepsets, _ := AqueryBuildStatements([]byte(inputString))
Usta Shrestha16ac1352022-06-22 11:01:55 -0400228 var expectedBuildStatements []BuildStatement
Chris Parsons4f069892021-01-15 12:22:41 -0500229 for _, arch := range []string{"arm", "arm64", "x86", "x86_64"} {
230 expectedBuildStatements = append(expectedBuildStatements,
231 BuildStatement{
232 Command: fmt.Sprintf(
233 "/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'",
234 arch, arch),
235 OutputPaths: []string{
236 fmt.Sprintf("bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-%s.S", arch),
237 },
Chris Parsons4f069892021-01-15 12:22:41 -0500238 Env: []KeyValuePair{
Usta Shrestha16ac1352022-06-22 11:01:55 -0400239 {Key: "PATH", Value: "/bin:/usr/bin:/usr/local/bin"},
Chris Parsons4f069892021-01-15 12:22:41 -0500240 },
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",
Chris Parsons1a7aca02022-04-25 22:35:15 -0400249 }
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
Usta Shresthaef922252022-06-02 14:23:02 -0400774func TestBazelOutRemovalFromInputDepsets(t *testing.T) {
775 const inputString = `{
776 "artifacts": [{
777 "id": 1,
778 "pathFragmentId": 10
779 }, {
780 "id": 2,
781 "pathFragmentId": 20
782 }, {
783 "id": 3,
784 "pathFragmentId": 30
785 }, {
786 "id": 4,
787 "pathFragmentId": 40
788 }],
789 "depSetOfFiles": [{
790 "id": 1111,
791 "directArtifactIds": [3 , 4]
792 }],
793 "actions": [{
794 "targetId": 100,
795 "actionKey": "x",
796 "inputDepSetIds": [1111],
797 "mnemonic": "x",
798 "arguments": ["bogus", "command"],
799 "outputIds": [2],
800 "primaryOutputId": 1
801 }],
802 "pathFragments": [{
803 "id": 10,
804 "label": "input"
805 }, {
806 "id": 20,
807 "label": "output"
808 }, {
809 "id": 30,
810 "label": "dep1",
811 "parentId": 50
812 }, {
813 "id": 40,
814 "label": "dep2",
815 "parentId": 60
816 }, {
817 "id": 50,
818 "label": "bazel_tools",
819 "parentId": 60
820 }, {
821 "id": 60,
822 "label": ".."
823 }]
824}`
825 actualBuildStatements, actualDepsets, _ := AqueryBuildStatements([]byte(inputString))
826 if len(actualDepsets) != 1 {
827 t.Errorf("expected 1 depset but found %#v", actualDepsets)
828 return
829 }
830 dep2Found := false
831 for _, dep := range flattenDepsets([]string{actualDepsets[0].ContentHash}, actualDepsets) {
832 if dep == "../bazel_tools/dep1" {
833 t.Errorf("dependency %s expected to be removed but still exists", dep)
834 } else if dep == "../dep2" {
835 dep2Found = true
836 }
837 }
838 if !dep2Found {
839 t.Errorf("dependency ../dep2 expected but not found")
840 }
841
842 expectedBuildStatement := BuildStatement{
843 Command: "bogus command",
844 OutputPaths: []string{"output"},
845 Mnemonic: "x",
846 }
847 buildStatementFound := false
848 for _, actualBuildStatement := range actualBuildStatements {
849 if buildStatementEquals(actualBuildStatement, expectedBuildStatement) == "" {
850 buildStatementFound = true
851 break
852 }
853 }
854 if !buildStatementFound {
855 t.Errorf("expected but missing %#v in %#v", expectedBuildStatement, actualBuildStatements)
856 return
857 }
858}
859
Chris Parsonsc4fb1332021-05-18 12:31:25 -0400860func TestMiddlemenAction(t *testing.T) {
861 const inputString = `
862{
863 "artifacts": [{
864 "id": 1,
865 "pathFragmentId": 1
866 }, {
867 "id": 2,
868 "pathFragmentId": 2
869 }, {
870 "id": 3,
871 "pathFragmentId": 3
872 }, {
873 "id": 4,
874 "pathFragmentId": 4
875 }, {
876 "id": 5,
877 "pathFragmentId": 5
878 }, {
879 "id": 6,
880 "pathFragmentId": 6
881 }],
882 "pathFragments": [{
883 "id": 1,
884 "label": "middleinput_one"
885 }, {
886 "id": 2,
887 "label": "middleinput_two"
888 }, {
889 "id": 3,
890 "label": "middleman_artifact"
891 }, {
892 "id": 4,
893 "label": "maininput_one"
894 }, {
895 "id": 5,
896 "label": "maininput_two"
897 }, {
898 "id": 6,
899 "label": "output"
900 }],
901 "depSetOfFiles": [{
902 "id": 1,
903 "directArtifactIds": [1, 2]
904 }, {
905 "id": 2,
906 "directArtifactIds": [3, 4, 5]
907 }],
908 "actions": [{
909 "targetId": 1,
910 "actionKey": "x",
911 "mnemonic": "Middleman",
912 "arguments": ["touch", "foo"],
913 "inputDepSetIds": [1],
914 "outputIds": [3],
915 "primaryOutputId": 3
916 }, {
917 "targetId": 2,
918 "actionKey": "y",
919 "mnemonic": "Main action",
920 "arguments": ["touch", "foo"],
921 "inputDepSetIds": [2],
922 "outputIds": [6],
923 "primaryOutputId": 6
924 }]
925}`
926
Chris Parsons1a7aca02022-04-25 22:35:15 -0400927 actualBuildStatements, actualDepsets, err := AqueryBuildStatements([]byte(inputString))
Chris Parsonsc4fb1332021-05-18 12:31:25 -0400928 if err != nil {
929 t.Errorf("Unexpected error %q", err)
930 }
Chris Parsons1a7aca02022-04-25 22:35:15 -0400931 if expected := 1; len(actualBuildStatements) != expected {
932 t.Fatalf("Expected %d build statements, got %d", expected, len(actualBuildStatements))
Chris Parsonsc4fb1332021-05-18 12:31:25 -0400933 }
934
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400935 expectedDepsetFiles := [][]string{
Usta Shrestha2ccdb422022-06-02 10:19:13 -0400936 {"middleinput_one", "middleinput_two", "maininput_one", "maininput_two"},
937 {"middleinput_one", "middleinput_two"},
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400938 }
939 assertFlattenedDepsets(t, actualDepsets, expectedDepsetFiles)
940
Chris Parsons1a7aca02022-04-25 22:35:15 -0400941 bs := actualBuildStatements[0]
942 if len(bs.InputPaths) > 0 {
943 t.Errorf("Expected main action raw inputs to be empty, but got %q", bs.InputPaths)
944 }
945
Chris Parsonsc4fb1332021-05-18 12:31:25 -0400946 expectedOutputs := []string{"output"}
947 if !reflect.DeepEqual(bs.OutputPaths, expectedOutputs) {
948 t.Errorf("Expected main action outputs %q, but got %q", expectedOutputs, bs.OutputPaths)
949 }
Chris Parsons1a7aca02022-04-25 22:35:15 -0400950
Chris Parsons1a7aca02022-04-25 22:35:15 -0400951 expectedFlattenedInputs := []string{"middleinput_one", "middleinput_two", "maininput_one", "maininput_two"}
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400952 actualFlattenedInputs := flattenDepsets(bs.InputDepsetHashes, actualDepsets)
Chris Parsons1a7aca02022-04-25 22:35:15 -0400953
954 if !reflect.DeepEqual(actualFlattenedInputs, expectedFlattenedInputs) {
955 t.Errorf("Expected flattened inputs %v, but got %v", expectedFlattenedInputs, actualFlattenedInputs)
956 }
957}
958
959// Returns the contents of given depsets in concatenated post order.
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400960func flattenDepsets(depsetHashesToFlatten []string, allDepsets []AqueryDepset) []string {
961 depsetsByHash := map[string]AqueryDepset{}
Chris Parsons1a7aca02022-04-25 22:35:15 -0400962 for _, depset := range allDepsets {
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400963 depsetsByHash[depset.ContentHash] = depset
Chris Parsons1a7aca02022-04-25 22:35:15 -0400964 }
Usta Shrestha16ac1352022-06-22 11:01:55 -0400965 var result []string
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400966 for _, depsetId := range depsetHashesToFlatten {
967 result = append(result, flattenDepset(depsetId, depsetsByHash)...)
Chris Parsons1a7aca02022-04-25 22:35:15 -0400968 }
969 return result
970}
971
972// Returns the contents of a given depset in post order.
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400973func flattenDepset(depsetHashToFlatten string, allDepsets map[string]AqueryDepset) []string {
974 depset := allDepsets[depsetHashToFlatten]
Usta Shrestha16ac1352022-06-22 11:01:55 -0400975 var result []string
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400976 for _, depsetId := range depset.TransitiveDepSetHashes {
Chris Parsons1a7aca02022-04-25 22:35:15 -0400977 result = append(result, flattenDepset(depsetId, allDepsets)...)
978 }
979 result = append(result, depset.DirectArtifacts...)
980 return result
Chris Parsonsc4fb1332021-05-18 12:31:25 -0400981}
982
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400983func assertFlattenedDepsets(t *testing.T, actualDepsets []AqueryDepset, expectedDepsetFiles [][]string) {
984 t.Helper()
985 if len(actualDepsets) != len(expectedDepsetFiles) {
Sasha Smundakf10c3ac2022-06-08 11:46:31 -0700986 t.Errorf("Expected %d depsets, but got %d depsets", len(expectedDepsetFiles), len(actualDepsets))
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400987 }
988 for i, actualDepset := range actualDepsets {
989 actualFlattenedInputs := flattenDepsets([]string{actualDepset.ContentHash}, actualDepsets)
990 if !reflect.DeepEqual(actualFlattenedInputs, expectedDepsetFiles[i]) {
991 t.Errorf("Expected depset files: %v, but got %v", expectedDepsetFiles[i], actualFlattenedInputs)
992 }
993 }
994}
995
Liz Kammerc49e6822021-06-08 15:04:11 -0400996func TestSimpleSymlink(t *testing.T) {
997 const inputString = `
998{
999 "artifacts": [{
1000 "id": 1,
1001 "pathFragmentId": 3
1002 }, {
1003 "id": 2,
1004 "pathFragmentId": 5
1005 }],
1006 "actions": [{
1007 "targetId": 1,
1008 "actionKey": "x",
1009 "mnemonic": "Symlink",
1010 "inputDepSetIds": [1],
1011 "outputIds": [2],
1012 "primaryOutputId": 2
1013 }],
1014 "depSetOfFiles": [{
1015 "id": 1,
1016 "directArtifactIds": [1]
1017 }],
1018 "pathFragments": [{
1019 "id": 1,
1020 "label": "one"
1021 }, {
1022 "id": 2,
1023 "label": "file_subdir",
1024 "parentId": 1
1025 }, {
1026 "id": 3,
1027 "label": "file",
1028 "parentId": 2
1029 }, {
1030 "id": 4,
1031 "label": "symlink_subdir",
1032 "parentId": 1
1033 }, {
1034 "id": 5,
1035 "label": "symlink",
1036 "parentId": 4
1037 }]
1038}`
1039
Chris Parsons1a7aca02022-04-25 22:35:15 -04001040 actual, _, err := AqueryBuildStatements([]byte(inputString))
Liz Kammerc49e6822021-06-08 15:04:11 -04001041
1042 if err != nil {
1043 t.Errorf("Unexpected error %q", err)
1044 }
1045
1046 expectedBuildStatements := []BuildStatement{
Usta Shrestha16ac1352022-06-22 11:01:55 -04001047 {
Liz Kammerc49e6822021-06-08 15:04:11 -04001048 Command: "mkdir -p one/symlink_subdir && " +
1049 "rm -f one/symlink_subdir/symlink && " +
Liz Kammerc7737782021-11-04 10:56:13 -04001050 "ln -sf $PWD/one/file_subdir/file one/symlink_subdir/symlink",
Liz Kammerc49e6822021-06-08 15:04:11 -04001051 InputPaths: []string{"one/file_subdir/file"},
1052 OutputPaths: []string{"one/symlink_subdir/symlink"},
1053 SymlinkPaths: []string{"one/symlink_subdir/symlink"},
1054 Mnemonic: "Symlink",
1055 },
1056 }
1057 assertBuildStatements(t, actual, expectedBuildStatements)
1058}
1059
1060func TestSymlinkQuotesPaths(t *testing.T) {
1061 const inputString = `
1062{
1063 "artifacts": [{
1064 "id": 1,
1065 "pathFragmentId": 3
1066 }, {
1067 "id": 2,
1068 "pathFragmentId": 5
1069 }],
1070 "actions": [{
1071 "targetId": 1,
1072 "actionKey": "x",
1073 "mnemonic": "SolibSymlink",
1074 "inputDepSetIds": [1],
1075 "outputIds": [2],
1076 "primaryOutputId": 2
1077 }],
1078 "depSetOfFiles": [{
1079 "id": 1,
1080 "directArtifactIds": [1]
1081 }],
1082 "pathFragments": [{
1083 "id": 1,
1084 "label": "one"
1085 }, {
1086 "id": 2,
1087 "label": "file subdir",
1088 "parentId": 1
1089 }, {
1090 "id": 3,
1091 "label": "file",
1092 "parentId": 2
1093 }, {
1094 "id": 4,
1095 "label": "symlink subdir",
1096 "parentId": 1
1097 }, {
1098 "id": 5,
1099 "label": "symlink",
1100 "parentId": 4
1101 }]
1102}`
1103
Chris Parsons1a7aca02022-04-25 22:35:15 -04001104 actual, _, err := AqueryBuildStatements([]byte(inputString))
Liz Kammerc49e6822021-06-08 15:04:11 -04001105
1106 if err != nil {
1107 t.Errorf("Unexpected error %q", err)
1108 }
1109
1110 expectedBuildStatements := []BuildStatement{
Usta Shrestha16ac1352022-06-22 11:01:55 -04001111 {
Liz Kammerc49e6822021-06-08 15:04:11 -04001112 Command: "mkdir -p 'one/symlink subdir' && " +
1113 "rm -f 'one/symlink subdir/symlink' && " +
Liz Kammerc7737782021-11-04 10:56:13 -04001114 "ln -sf $PWD/'one/file subdir/file' 'one/symlink subdir/symlink'",
Liz Kammerc49e6822021-06-08 15:04:11 -04001115 InputPaths: []string{"one/file subdir/file"},
1116 OutputPaths: []string{"one/symlink subdir/symlink"},
1117 SymlinkPaths: []string{"one/symlink subdir/symlink"},
1118 Mnemonic: "SolibSymlink",
1119 },
1120 }
Liz Kammerc7737782021-11-04 10:56:13 -04001121 assertBuildStatements(t, expectedBuildStatements, actual)
Liz Kammerc49e6822021-06-08 15:04:11 -04001122}
1123
1124func TestSymlinkMultipleInputs(t *testing.T) {
1125 const inputString = `
1126{
1127 "artifacts": [{
1128 "id": 1,
1129 "pathFragmentId": 1
1130 }, {
1131 "id": 2,
1132 "pathFragmentId": 2
1133 }, {
1134 "id": 3,
1135 "pathFragmentId": 3
1136 }],
1137 "actions": [{
1138 "targetId": 1,
1139 "actionKey": "x",
1140 "mnemonic": "Symlink",
1141 "inputDepSetIds": [1],
1142 "outputIds": [3],
1143 "primaryOutputId": 3
1144 }],
1145 "depSetOfFiles": [{
1146 "id": 1,
1147 "directArtifactIds": [1,2]
1148 }],
1149 "pathFragments": [{
1150 "id": 1,
1151 "label": "file"
1152 }, {
1153 "id": 2,
1154 "label": "other_file"
1155 }, {
1156 "id": 3,
1157 "label": "symlink"
1158 }]
1159}`
1160
Chris Parsons1a7aca02022-04-25 22:35:15 -04001161 _, _, err := AqueryBuildStatements([]byte(inputString))
Liz Kammerc49e6822021-06-08 15:04:11 -04001162 assertError(t, err, `Expect 1 input and 1 output to symlink action, got: input ["file" "other_file"], output ["symlink"]`)
1163}
1164
1165func TestSymlinkMultipleOutputs(t *testing.T) {
1166 const inputString = `
1167{
1168 "artifacts": [{
1169 "id": 1,
1170 "pathFragmentId": 1
1171 }, {
1172 "id": 2,
1173 "pathFragmentId": 2
1174 }, {
1175 "id": 3,
1176 "pathFragmentId": 3
1177 }],
1178 "actions": [{
1179 "targetId": 1,
1180 "actionKey": "x",
1181 "mnemonic": "Symlink",
1182 "inputDepSetIds": [1],
1183 "outputIds": [2,3],
1184 "primaryOutputId": 2
1185 }],
1186 "depSetOfFiles": [{
1187 "id": 1,
1188 "directArtifactIds": [1]
1189 }],
1190 "pathFragments": [{
1191 "id": 1,
1192 "label": "file"
1193 }, {
1194 "id": 2,
1195 "label": "symlink"
1196 }, {
1197 "id": 3,
1198 "label": "other_symlink"
1199 }]
1200}`
1201
Chris Parsons1a7aca02022-04-25 22:35:15 -04001202 _, _, err := AqueryBuildStatements([]byte(inputString))
Liz Kammerc49e6822021-06-08 15:04:11 -04001203 assertError(t, err, `Expect 1 input and 1 output to symlink action, got: input ["file"], output ["symlink" "other_symlink"]`)
1204}
1205
Wei Li455ba832021-11-04 22:58:12 +00001206func TestTemplateExpandActionSubstitutions(t *testing.T) {
1207 const inputString = `
1208{
1209 "artifacts": [{
1210 "id": 1,
1211 "pathFragmentId": 1
1212 }],
1213 "actions": [{
1214 "targetId": 1,
1215 "actionKey": "x",
1216 "mnemonic": "TemplateExpand",
1217 "configurationId": 1,
1218 "outputIds": [1],
1219 "primaryOutputId": 1,
1220 "executionPlatform": "//build/bazel/platforms:linux_x86_64",
1221 "templateContent": "Test template substitutions: %token1%, %python_binary%",
1222 "substitutions": [{
1223 "key": "%token1%",
1224 "value": "abcd"
1225 },{
1226 "key": "%python_binary%",
1227 "value": "python3"
1228 }]
1229 }],
1230 "pathFragments": [{
1231 "id": 1,
1232 "label": "template_file"
1233 }]
1234}`
1235
Chris Parsons1a7aca02022-04-25 22:35:15 -04001236 actual, _, err := AqueryBuildStatements([]byte(inputString))
Wei Li455ba832021-11-04 22:58:12 +00001237
1238 if err != nil {
1239 t.Errorf("Unexpected error %q", err)
1240 }
1241
1242 expectedBuildStatements := []BuildStatement{
Usta Shrestha16ac1352022-06-22 11:01:55 -04001243 {
Wei Li455ba832021-11-04 22:58:12 +00001244 Command: "/bin/bash -c 'echo \"Test template substitutions: abcd, python3\" | sed \"s/\\\\\\\\n/\\\\n/g\" > template_file && " +
1245 "chmod a+x template_file'",
1246 OutputPaths: []string{"template_file"},
1247 Mnemonic: "TemplateExpand",
1248 },
1249 }
1250 assertBuildStatements(t, expectedBuildStatements, actual)
1251}
1252
1253func TestTemplateExpandActionNoOutput(t *testing.T) {
1254 const inputString = `
1255{
1256 "artifacts": [{
1257 "id": 1,
1258 "pathFragmentId": 1
1259 }],
1260 "actions": [{
1261 "targetId": 1,
1262 "actionKey": "x",
1263 "mnemonic": "TemplateExpand",
1264 "configurationId": 1,
1265 "primaryOutputId": 1,
1266 "executionPlatform": "//build/bazel/platforms:linux_x86_64",
1267 "templateContent": "Test template substitutions: %token1%, %python_binary%",
1268 "substitutions": [{
1269 "key": "%token1%",
1270 "value": "abcd"
1271 },{
1272 "key": "%python_binary%",
1273 "value": "python3"
1274 }]
1275 }],
1276 "pathFragments": [{
1277 "id": 1,
1278 "label": "template_file"
1279 }]
1280}`
1281
Chris Parsons1a7aca02022-04-25 22:35:15 -04001282 _, _, err := AqueryBuildStatements([]byte(inputString))
Wei Li455ba832021-11-04 22:58:12 +00001283 assertError(t, err, `Expect 1 output to template expand action, got: output []`)
1284}
1285
1286func TestPythonZipperActionSuccess(t *testing.T) {
1287 const inputString = `
1288{
1289 "artifacts": [{
1290 "id": 1,
1291 "pathFragmentId": 1
1292 },{
1293 "id": 2,
1294 "pathFragmentId": 2
1295 },{
1296 "id": 3,
1297 "pathFragmentId": 3
1298 },{
1299 "id": 4,
1300 "pathFragmentId": 4
1301 },{
1302 "id": 5,
1303 "pathFragmentId": 10
1304 },{
1305 "id": 10,
1306 "pathFragmentId": 20
1307 }],
1308 "actions": [{
1309 "targetId": 1,
1310 "actionKey": "x",
1311 "mnemonic": "TemplateExpand",
1312 "configurationId": 1,
1313 "outputIds": [1],
1314 "primaryOutputId": 1,
1315 "executionPlatform": "//build/bazel/platforms:linux_x86_64",
1316 "templateContent": "Test template substitutions: %token1%, %python_binary%",
1317 "substitutions": [{
1318 "key": "%token1%",
1319 "value": "abcd"
1320 },{
1321 "key": "%python_binary%",
1322 "value": "python3"
1323 }]
1324 },{
1325 "targetId": 1,
1326 "actionKey": "x",
1327 "mnemonic": "PythonZipper",
1328 "configurationId": 1,
1329 "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"],
1330 "outputIds": [2],
1331 "inputDepSetIds": [1],
1332 "primaryOutputId": 2
1333 }],
1334 "depSetOfFiles": [{
1335 "id": 1,
1336 "directArtifactIds": [4, 3, 5]
1337 }],
1338 "pathFragments": [{
1339 "id": 1,
1340 "label": "python_binary"
1341 },{
1342 "id": 2,
1343 "label": "python_binary.zip"
1344 },{
1345 "id": 3,
1346 "label": "python_binary.py"
1347 },{
1348 "id": 9,
1349 "label": ".."
1350 }, {
1351 "id": 8,
1352 "label": "bazel_tools",
1353 "parentId": 9
1354 }, {
1355 "id": 7,
1356 "label": "tools",
1357 "parentId": 8
1358 }, {
1359 "id": 6,
1360 "label": "zip",
1361 "parentId": 7
1362 }, {
1363 "id": 5,
1364 "label": "zipper",
1365 "parentId": 6
1366 }, {
1367 "id": 4,
1368 "label": "zipper",
1369 "parentId": 5
1370 },{
1371 "id": 16,
1372 "label": "bazel-out"
1373 },{
1374 "id": 15,
1375 "label": "bazel_tools",
1376 "parentId": 16
1377 }, {
1378 "id": 14,
1379 "label": "k8-fastbuild",
1380 "parentId": 15
1381 }, {
1382 "id": 13,
1383 "label": "bin",
1384 "parentId": 14
1385 }, {
1386 "id": 12,
1387 "label": "tools",
1388 "parentId": 13
1389 }, {
1390 "id": 11,
1391 "label": "python",
1392 "parentId": 12
1393 }, {
1394 "id": 10,
1395 "label": "py3wrapper.sh",
1396 "parentId": 11
1397 },{
1398 "id": 20,
1399 "label": "python_binary"
1400 }]
1401}`
Chris Parsons1a7aca02022-04-25 22:35:15 -04001402 actual, _, err := AqueryBuildStatements([]byte(inputString))
Wei Li455ba832021-11-04 22:58:12 +00001403
1404 if err != nil {
1405 t.Errorf("Unexpected error %q", err)
1406 }
1407
1408 expectedBuildStatements := []BuildStatement{
Usta Shrestha16ac1352022-06-22 11:01:55 -04001409 {
Wei Li455ba832021-11-04 22:58:12 +00001410 Command: "/bin/bash -c 'echo \"Test template substitutions: abcd, python3\" | sed \"s/\\\\\\\\n/\\\\n/g\" > python_binary && " +
1411 "chmod a+x python_binary'",
1412 InputPaths: []string{"python_binary.zip"},
1413 OutputPaths: []string{"python_binary"},
1414 Mnemonic: "TemplateExpand",
1415 },
Usta Shrestha16ac1352022-06-22 11:01:55 -04001416 {
Wei Li455ba832021-11-04 22:58:12 +00001417 Command: "../bazel_tools/tools/zip/zipper/zipper cC python_binary.zip __main__.py=bazel-out/k8-fastbuild/bin/python_binary.temp " +
1418 "__init__.py= runfiles/__main__/__init__.py= runfiles/__main__/python_binary.py=python_binary.py && " +
1419 "../bazel_tools/tools/zip/zipper/zipper x python_binary.zip -d python_binary.runfiles && ln -sf runfiles/__main__ python_binary.runfiles",
Usta Shresthaef922252022-06-02 14:23:02 -04001420 InputPaths: []string{"python_binary.py"},
Wei Li455ba832021-11-04 22:58:12 +00001421 OutputPaths: []string{"python_binary.zip"},
1422 Mnemonic: "PythonZipper",
1423 },
1424 }
1425 assertBuildStatements(t, expectedBuildStatements, actual)
1426}
1427
1428func TestPythonZipperActionNoInput(t *testing.T) {
1429 const inputString = `
1430{
1431 "artifacts": [{
1432 "id": 1,
1433 "pathFragmentId": 1
1434 },{
1435 "id": 2,
1436 "pathFragmentId": 2
1437 }],
1438 "actions": [{
1439 "targetId": 1,
1440 "actionKey": "x",
1441 "mnemonic": "PythonZipper",
1442 "configurationId": 1,
1443 "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"],
1444 "outputIds": [2],
1445 "primaryOutputId": 2
1446 }],
1447 "pathFragments": [{
1448 "id": 1,
1449 "label": "python_binary"
1450 },{
1451 "id": 2,
1452 "label": "python_binary.zip"
1453 }]
1454}`
Chris Parsons1a7aca02022-04-25 22:35:15 -04001455 _, _, err := AqueryBuildStatements([]byte(inputString))
Wei Li455ba832021-11-04 22:58:12 +00001456 assertError(t, err, `Expect 1+ input and 1 output to python zipper action, got: input [], output ["python_binary.zip"]`)
1457}
1458
1459func TestPythonZipperActionNoOutput(t *testing.T) {
1460 const inputString = `
1461{
1462 "artifacts": [{
1463 "id": 1,
1464 "pathFragmentId": 1
1465 },{
1466 "id": 2,
1467 "pathFragmentId": 2
1468 },{
1469 "id": 3,
1470 "pathFragmentId": 3
1471 },{
1472 "id": 4,
1473 "pathFragmentId": 4
1474 },{
1475 "id": 5,
1476 "pathFragmentId": 10
1477 }],
1478 "actions": [{
1479 "targetId": 1,
1480 "actionKey": "x",
1481 "mnemonic": "PythonZipper",
1482 "configurationId": 1,
1483 "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"],
1484 "inputDepSetIds": [1]
1485 }],
1486 "depSetOfFiles": [{
1487 "id": 1,
1488 "directArtifactIds": [4, 3, 5]
1489 }],
1490 "pathFragments": [{
1491 "id": 1,
1492 "label": "python_binary"
1493 },{
1494 "id": 2,
1495 "label": "python_binary.zip"
1496 },{
1497 "id": 3,
1498 "label": "python_binary.py"
1499 },{
1500 "id": 9,
1501 "label": ".."
1502 }, {
1503 "id": 8,
1504 "label": "bazel_tools",
1505 "parentId": 9
1506 }, {
1507 "id": 7,
1508 "label": "tools",
1509 "parentId": 8
1510 }, {
1511 "id": 6,
1512 "label": "zip",
1513 "parentId": 7
1514 }, {
1515 "id": 5,
1516 "label": "zipper",
1517 "parentId": 6
1518 }, {
1519 "id": 4,
1520 "label": "zipper",
1521 "parentId": 5
1522 },{
1523 "id": 16,
1524 "label": "bazel-out"
1525 },{
1526 "id": 15,
1527 "label": "bazel_tools",
1528 "parentId": 16
1529 }, {
1530 "id": 14,
1531 "label": "k8-fastbuild",
1532 "parentId": 15
1533 }, {
1534 "id": 13,
1535 "label": "bin",
1536 "parentId": 14
1537 }, {
1538 "id": 12,
1539 "label": "tools",
1540 "parentId": 13
1541 }, {
1542 "id": 11,
1543 "label": "python",
1544 "parentId": 12
1545 }, {
1546 "id": 10,
1547 "label": "py3wrapper.sh",
1548 "parentId": 11
1549 }]
1550}`
Chris Parsons1a7aca02022-04-25 22:35:15 -04001551 _, _, err := AqueryBuildStatements([]byte(inputString))
Usta Shresthaef922252022-06-02 14:23:02 -04001552 assertError(t, err, `Expect 1+ input and 1 output to python zipper action, got: input ["python_binary.py"], output []`)
Wei Li455ba832021-11-04 22:58:12 +00001553}
1554
Chris Parsons4f069892021-01-15 12:22:41 -05001555func assertError(t *testing.T, err error, expected string) {
Liz Kammerc49e6822021-06-08 15:04:11 -04001556 t.Helper()
Chris Parsons943f2432021-01-19 11:36:50 -05001557 if err == nil {
1558 t.Errorf("expected error '%s', but got no error", expected)
1559 } else if err.Error() != expected {
Liz Kammerc49e6822021-06-08 15:04:11 -04001560 t.Errorf("expected error:\n\t'%s', but got:\n\t'%s'", expected, err.Error())
Chris Parsons4f069892021-01-15 12:22:41 -05001561 }
1562}
1563
1564// Asserts that the given actual build statements match the given expected build statements.
1565// Build statement equivalence is determined using buildStatementEquals.
1566func assertBuildStatements(t *testing.T, expected []BuildStatement, actual []BuildStatement) {
Liz Kammerc49e6822021-06-08 15:04:11 -04001567 t.Helper()
Chris Parsons4f069892021-01-15 12:22:41 -05001568 if len(expected) != len(actual) {
Liz Kammerc3192992021-11-16 17:01:11 -05001569 t.Errorf("expected %d build statements, but got %d,\n expected: %#v,\n actual: %#v",
Chris Parsons4f069892021-01-15 12:22:41 -05001570 len(expected), len(actual), expected, actual)
1571 return
1572 }
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001573 type compareFn = func(i int, j int) bool
1574 byCommand := func(slice []BuildStatement) compareFn {
1575 return func(i int, j int) bool {
1576 return slice[i].Command < slice[j].Command
Chris Parsons4f069892021-01-15 12:22:41 -05001577 }
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001578 }
1579 sort.SliceStable(expected, byCommand(expected))
1580 sort.SliceStable(actual, byCommand(actual))
1581 for i, actualStatement := range actual {
1582 expectedStatement := expected[i]
1583 if differingField := buildStatementEquals(actualStatement, expectedStatement); differingField != "" {
1584 t.Errorf("%s differs\nunexpected build statement %#v.\nexpected: %#v",
Usta Shresthaef922252022-06-02 14:23:02 -04001585 differingField, actualStatement, expectedStatement)
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001586 return
1587 }
Chris Parsons4f069892021-01-15 12:22:41 -05001588 }
1589}
1590
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001591func buildStatementEquals(first BuildStatement, second BuildStatement) string {
Chris Parsons4f069892021-01-15 12:22:41 -05001592 if first.Mnemonic != second.Mnemonic {
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001593 return "Mnemonic"
Chris Parsons4f069892021-01-15 12:22:41 -05001594 }
1595 if first.Command != second.Command {
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001596 return "Command"
Chris Parsons4f069892021-01-15 12:22:41 -05001597 }
1598 // Ordering is significant for environment variables.
1599 if !reflect.DeepEqual(first.Env, second.Env) {
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001600 return "Env"
Chris Parsons4f069892021-01-15 12:22:41 -05001601 }
1602 // Ordering is irrelevant for input and output paths, so compare sets.
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001603 if !reflect.DeepEqual(sortedStrings(first.InputPaths), sortedStrings(second.InputPaths)) {
1604 return "InputPaths"
Chris Parsons4f069892021-01-15 12:22:41 -05001605 }
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001606 if !reflect.DeepEqual(sortedStrings(first.OutputPaths), sortedStrings(second.OutputPaths)) {
1607 return "OutputPaths"
Chris Parsons4f069892021-01-15 12:22:41 -05001608 }
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001609 if !reflect.DeepEqual(sortedStrings(first.SymlinkPaths), sortedStrings(second.SymlinkPaths)) {
1610 return "SymlinkPaths"
Liz Kammerc49e6822021-06-08 15:04:11 -04001611 }
1612 if first.Depfile != second.Depfile {
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001613 return "Depfile"
Liz Kammerc49e6822021-06-08 15:04:11 -04001614 }
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001615 return ""
Chris Parsons4f069892021-01-15 12:22:41 -05001616}
1617
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001618func sortedStrings(stringSlice []string) []string {
1619 sorted := make([]string, len(stringSlice))
1620 copy(sorted, stringSlice)
1621 sort.Strings(sorted)
1622 return sorted
Chris Parsons4f069892021-01-15 12:22:41 -05001623}