blob: 1da6340a53adeed928e6b0b59196d91d06bde7eb [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",
249 "../bazel_tools/tools/genrule/genrule-setup.sh",
250 }
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400251 // In this example, each depset should have the same expected inputs.
252 for _, actualDepset := range actualDepsets {
253 actualFlattenedInputs := flattenDepsets([]string{actualDepset.ContentHash}, actualDepsets)
254 if !reflect.DeepEqual(actualFlattenedInputs, expectedFlattenedInputs) {
255 t.Errorf("Expected flattened inputs %v, but got %v", expectedFlattenedInputs, actualFlattenedInputs)
256 }
Chris Parsons1a7aca02022-04-25 22:35:15 -0400257 }
Chris Parsons4f069892021-01-15 12:22:41 -0500258}
259
260func TestInvalidOutputId(t *testing.T) {
261 const inputString = `
262{
263 "artifacts": [{
264 "id": 1,
265 "pathFragmentId": 1
266 }, {
267 "id": 2,
268 "pathFragmentId": 2
269 }],
270 "actions": [{
271 "targetId": 1,
272 "actionKey": "x",
273 "mnemonic": "x",
274 "arguments": ["touch", "foo"],
275 "inputDepSetIds": [1],
276 "outputIds": [3],
277 "primaryOutputId": 3
278 }],
279 "depSetOfFiles": [{
280 "id": 1,
281 "directArtifactIds": [1, 2]
282 }],
283 "pathFragments": [{
284 "id": 1,
285 "label": "one"
286 }, {
287 "id": 2,
288 "label": "two"
289 }]
290}`
291
Chris Parsons1a7aca02022-04-25 22:35:15 -0400292 _, _, err := AqueryBuildStatements([]byte(inputString))
Chris Parsons4f069892021-01-15 12:22:41 -0500293 assertError(t, err, "undefined outputId 3")
294}
295
Chris Parsons1a7aca02022-04-25 22:35:15 -0400296func TestInvalidInputDepsetIdFromAction(t *testing.T) {
Chris Parsons4f069892021-01-15 12:22:41 -0500297 const inputString = `
298{
299 "artifacts": [{
300 "id": 1,
301 "pathFragmentId": 1
302 }, {
303 "id": 2,
304 "pathFragmentId": 2
305 }],
306 "actions": [{
307 "targetId": 1,
308 "actionKey": "x",
309 "mnemonic": "x",
310 "arguments": ["touch", "foo"],
311 "inputDepSetIds": [2],
312 "outputIds": [1],
313 "primaryOutputId": 1
314 }],
315 "depSetOfFiles": [{
316 "id": 1,
317 "directArtifactIds": [1, 2]
318 }],
319 "pathFragments": [{
320 "id": 1,
321 "label": "one"
322 }, {
323 "id": 2,
324 "label": "two"
325 }]
326}`
327
Chris Parsons1a7aca02022-04-25 22:35:15 -0400328 _, _, err := AqueryBuildStatements([]byte(inputString))
Chris Parsons4f069892021-01-15 12:22:41 -0500329 assertError(t, err, "undefined input depsetId 2")
330}
331
Chris Parsons1a7aca02022-04-25 22:35:15 -0400332func TestInvalidInputDepsetIdFromDepset(t *testing.T) {
333 const inputString = `
334{
335 "artifacts": [{
336 "id": 1,
337 "pathFragmentId": 1
338 }, {
339 "id": 2,
340 "pathFragmentId": 2
341 }],
342 "actions": [{
343 "targetId": 1,
344 "actionKey": "x",
345 "mnemonic": "x",
346 "arguments": ["touch", "foo"],
347 "inputDepSetIds": [1],
348 "outputIds": [1],
349 "primaryOutputId": 1
350 }],
351 "depSetOfFiles": [{
352 "id": 1,
353 "directArtifactIds": [1, 2],
354 "transitiveDepSetIds": [42]
355 }],
356 "pathFragments": [{
357 "id": 1,
358 "label": "one"
359 }, {
360 "id": 2,
361 "label": "two"
362 }]
363}`
364
365 _, _, err := AqueryBuildStatements([]byte(inputString))
366 assertError(t, err, "undefined input depsetId 42 (referenced by depsetId 1)")
367}
368
Chris Parsons4f069892021-01-15 12:22:41 -0500369func TestInvalidInputArtifactId(t *testing.T) {
370 const inputString = `
371{
372 "artifacts": [{
373 "id": 1,
374 "pathFragmentId": 1
375 }, {
376 "id": 2,
377 "pathFragmentId": 2
378 }],
379 "actions": [{
380 "targetId": 1,
381 "actionKey": "x",
382 "mnemonic": "x",
383 "arguments": ["touch", "foo"],
384 "inputDepSetIds": [1],
385 "outputIds": [1],
386 "primaryOutputId": 1
387 }],
388 "depSetOfFiles": [{
389 "id": 1,
390 "directArtifactIds": [1, 3]
391 }],
392 "pathFragments": [{
393 "id": 1,
394 "label": "one"
395 }, {
396 "id": 2,
397 "label": "two"
398 }]
399}`
400
Chris Parsons1a7aca02022-04-25 22:35:15 -0400401 _, _, err := AqueryBuildStatements([]byte(inputString))
Chris Parsons4f069892021-01-15 12:22:41 -0500402 assertError(t, err, "undefined input artifactId 3")
403}
404
405func TestInvalidPathFragmentId(t *testing.T) {
406 const inputString = `
407{
408 "artifacts": [{
409 "id": 1,
410 "pathFragmentId": 1
411 }, {
412 "id": 2,
413 "pathFragmentId": 2
414 }],
415 "actions": [{
416 "targetId": 1,
417 "actionKey": "x",
418 "mnemonic": "x",
419 "arguments": ["touch", "foo"],
420 "inputDepSetIds": [1],
421 "outputIds": [1],
422 "primaryOutputId": 1
423 }],
424 "depSetOfFiles": [{
425 "id": 1,
426 "directArtifactIds": [1, 2]
427 }],
428 "pathFragments": [{
429 "id": 1,
430 "label": "one"
431 }, {
432 "id": 2,
433 "label": "two",
434 "parentId": 3
435 }]
436}`
437
Chris Parsons1a7aca02022-04-25 22:35:15 -0400438 _, _, err := AqueryBuildStatements([]byte(inputString))
Chris Parsons4f069892021-01-15 12:22:41 -0500439 assertError(t, err, "undefined path fragment id 3")
440}
441
Liz Kammerde116852021-03-25 16:42:37 -0400442func TestDepfiles(t *testing.T) {
443 const inputString = `
444{
445 "artifacts": [{
446 "id": 1,
447 "pathFragmentId": 1
448 }, {
449 "id": 2,
450 "pathFragmentId": 2
451 }, {
452 "id": 3,
453 "pathFragmentId": 3
454 }],
455 "actions": [{
456 "targetId": 1,
457 "actionKey": "x",
458 "mnemonic": "x",
459 "arguments": ["touch", "foo"],
460 "inputDepSetIds": [1],
461 "outputIds": [2, 3],
462 "primaryOutputId": 2
463 }],
464 "depSetOfFiles": [{
465 "id": 1,
466 "directArtifactIds": [1, 2, 3]
467 }],
468 "pathFragments": [{
469 "id": 1,
470 "label": "one"
471 }, {
472 "id": 2,
473 "label": "two"
474 }, {
475 "id": 3,
476 "label": "two.d"
477 }]
478}`
479
Chris Parsons1a7aca02022-04-25 22:35:15 -0400480 actual, _, err := AqueryBuildStatements([]byte(inputString))
Liz Kammerde116852021-03-25 16:42:37 -0400481 if err != nil {
482 t.Errorf("Unexpected error %q", err)
483 }
484 if expected := 1; len(actual) != expected {
485 t.Fatalf("Expected %d build statements, got %d", expected, len(actual))
486 }
487
488 bs := actual[0]
489 expectedDepfile := "two.d"
490 if bs.Depfile == nil {
491 t.Errorf("Expected depfile %q, but there was none found", expectedDepfile)
492 } else if *bs.Depfile != expectedDepfile {
493 t.Errorf("Expected depfile %q, but got %q", expectedDepfile, *bs.Depfile)
494 }
495}
496
497func TestMultipleDepfiles(t *testing.T) {
498 const inputString = `
499{
500 "artifacts": [{
501 "id": 1,
502 "pathFragmentId": 1
503 }, {
504 "id": 2,
505 "pathFragmentId": 2
506 }, {
507 "id": 3,
508 "pathFragmentId": 3
509 }, {
510 "id": 4,
511 "pathFragmentId": 4
512 }],
513 "actions": [{
514 "targetId": 1,
515 "actionKey": "x",
516 "mnemonic": "x",
517 "arguments": ["touch", "foo"],
518 "inputDepSetIds": [1],
519 "outputIds": [2,3,4],
520 "primaryOutputId": 2
521 }],
522 "depSetOfFiles": [{
523 "id": 1,
524 "directArtifactIds": [1, 2, 3, 4]
525 }],
526 "pathFragments": [{
527 "id": 1,
528 "label": "one"
529 }, {
530 "id": 2,
531 "label": "two"
532 }, {
533 "id": 3,
534 "label": "two.d"
535 }, {
536 "id": 4,
537 "label": "other.d"
538 }]
539}`
540
Chris Parsons1a7aca02022-04-25 22:35:15 -0400541 _, _, err := AqueryBuildStatements([]byte(inputString))
Liz Kammerde116852021-03-25 16:42:37 -0400542 assertError(t, err, `found multiple potential depfiles "two.d", "other.d"`)
543}
544
Chris Parsons943f2432021-01-19 11:36:50 -0500545func TestTransitiveInputDepsets(t *testing.T) {
546 // The input aquery for this test comes from a proof-of-concept starlark rule which registers
547 // a single action with many inputs given via a deep depset.
548 const inputString = `
549{
550 "artifacts": [{
551 "id": 1,
552 "pathFragmentId": 1
553 }, {
554 "id": 2,
555 "pathFragmentId": 7
556 }, {
557 "id": 3,
558 "pathFragmentId": 8
559 }, {
560 "id": 4,
561 "pathFragmentId": 9
562 }, {
563 "id": 5,
564 "pathFragmentId": 10
565 }, {
566 "id": 6,
567 "pathFragmentId": 11
568 }, {
569 "id": 7,
570 "pathFragmentId": 12
571 }, {
572 "id": 8,
573 "pathFragmentId": 13
574 }, {
575 "id": 9,
576 "pathFragmentId": 14
577 }, {
578 "id": 10,
579 "pathFragmentId": 15
580 }, {
581 "id": 11,
582 "pathFragmentId": 16
583 }, {
584 "id": 12,
585 "pathFragmentId": 17
586 }, {
587 "id": 13,
588 "pathFragmentId": 18
589 }, {
590 "id": 14,
591 "pathFragmentId": 19
592 }, {
593 "id": 15,
594 "pathFragmentId": 20
595 }, {
596 "id": 16,
597 "pathFragmentId": 21
598 }, {
599 "id": 17,
600 "pathFragmentId": 22
601 }, {
602 "id": 18,
603 "pathFragmentId": 23
604 }, {
605 "id": 19,
606 "pathFragmentId": 24
607 }, {
608 "id": 20,
609 "pathFragmentId": 25
610 }, {
611 "id": 21,
612 "pathFragmentId": 26
613 }],
614 "actions": [{
615 "targetId": 1,
616 "actionKey": "3b826d17fadbbbcd8313e456b90ec47c078c438088891dd45b4adbcd8889dc50",
617 "mnemonic": "Action",
618 "configurationId": 1,
619 "arguments": ["/bin/bash", "-c", "touch bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out"],
620 "inputDepSetIds": [1],
621 "outputIds": [21],
622 "primaryOutputId": 21
623 }],
624 "depSetOfFiles": [{
625 "id": 3,
626 "directArtifactIds": [1, 2, 3, 4, 5]
627 }, {
628 "id": 4,
629 "directArtifactIds": [6, 7, 8, 9, 10]
630 }, {
631 "id": 2,
632 "transitiveDepSetIds": [3, 4],
633 "directArtifactIds": [11, 12, 13, 14, 15]
634 }, {
635 "id": 5,
636 "directArtifactIds": [16, 17, 18, 19]
637 }, {
638 "id": 1,
639 "transitiveDepSetIds": [2, 5],
640 "directArtifactIds": [20]
641 }],
642 "pathFragments": [{
643 "id": 6,
644 "label": "bazel-out"
645 }, {
646 "id": 5,
647 "label": "sourceroot",
648 "parentId": 6
649 }, {
650 "id": 4,
651 "label": "k8-fastbuild",
652 "parentId": 5
653 }, {
654 "id": 3,
655 "label": "bin",
656 "parentId": 4
657 }, {
658 "id": 2,
659 "label": "testpkg",
660 "parentId": 3
661 }, {
662 "id": 1,
663 "label": "test_1",
664 "parentId": 2
665 }, {
666 "id": 7,
667 "label": "test_2",
668 "parentId": 2
669 }, {
670 "id": 8,
671 "label": "test_3",
672 "parentId": 2
673 }, {
674 "id": 9,
675 "label": "test_4",
676 "parentId": 2
677 }, {
678 "id": 10,
679 "label": "test_5",
680 "parentId": 2
681 }, {
682 "id": 11,
683 "label": "test_6",
684 "parentId": 2
685 }, {
686 "id": 12,
687 "label": "test_7",
688 "parentId": 2
689 }, {
690 "id": 13,
691 "label": "test_8",
692 "parentId": 2
693 }, {
694 "id": 14,
695 "label": "test_9",
696 "parentId": 2
697 }, {
698 "id": 15,
699 "label": "test_10",
700 "parentId": 2
701 }, {
702 "id": 16,
703 "label": "test_11",
704 "parentId": 2
705 }, {
706 "id": 17,
707 "label": "test_12",
708 "parentId": 2
709 }, {
710 "id": 18,
711 "label": "test_13",
712 "parentId": 2
713 }, {
714 "id": 19,
715 "label": "test_14",
716 "parentId": 2
717 }, {
718 "id": 20,
719 "label": "test_15",
720 "parentId": 2
721 }, {
722 "id": 21,
723 "label": "test_16",
724 "parentId": 2
725 }, {
726 "id": 22,
727 "label": "test_17",
728 "parentId": 2
729 }, {
730 "id": 23,
731 "label": "test_18",
732 "parentId": 2
733 }, {
734 "id": 24,
735 "label": "test_19",
736 "parentId": 2
737 }, {
738 "id": 25,
739 "label": "test_root",
740 "parentId": 2
741 }, {
742 "id": 26,
743 "label": "test_out",
744 "parentId": 2
745 }]
746}`
747
Chris Parsons1a7aca02022-04-25 22:35:15 -0400748 actualbuildStatements, actualDepsets, _ := AqueryBuildStatements([]byte(inputString))
749
Chris Parsons943f2432021-01-19 11:36:50 -0500750 expectedBuildStatements := []BuildStatement{
Usta Shrestha16ac1352022-06-22 11:01:55 -0400751 {
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400752 Command: "/bin/bash -c 'touch bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out'",
753 OutputPaths: []string{"bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out"},
754 Mnemonic: "Action",
Chris Parsons943f2432021-01-19 11:36:50 -0500755 },
756 }
757 assertBuildStatements(t, expectedBuildStatements, actualbuildStatements)
Chris Parsons1a7aca02022-04-25 22:35:15 -0400758
759 // Inputs for the action are test_{i} from 1 to 20, and test_root. These inputs
760 // are given via a deep depset, but the depset is flattened when returned as a
761 // BuildStatement slice.
Usta Shrestha16ac1352022-06-22 11:01:55 -0400762 var expectedFlattenedInputs []string
Chris Parsons1a7aca02022-04-25 22:35:15 -0400763 for i := 1; i < 20; i++ {
764 expectedFlattenedInputs = append(expectedFlattenedInputs, fmt.Sprintf("bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_%d", i))
765 }
766 expectedFlattenedInputs = append(expectedFlattenedInputs, "bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_root")
767
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400768 actualDepsetHashes := actualbuildStatements[0].InputDepsetHashes
769 actualFlattenedInputs := flattenDepsets(actualDepsetHashes, actualDepsets)
Chris Parsons1a7aca02022-04-25 22:35:15 -0400770 if !reflect.DeepEqual(actualFlattenedInputs, expectedFlattenedInputs) {
771 t.Errorf("Expected flattened inputs %v, but got %v", expectedFlattenedInputs, actualFlattenedInputs)
772 }
Chris Parsons943f2432021-01-19 11:36:50 -0500773}
774
Chris Parsonsc4fb1332021-05-18 12:31:25 -0400775func TestMiddlemenAction(t *testing.T) {
776 const inputString = `
777{
778 "artifacts": [{
779 "id": 1,
780 "pathFragmentId": 1
781 }, {
782 "id": 2,
783 "pathFragmentId": 2
784 }, {
785 "id": 3,
786 "pathFragmentId": 3
787 }, {
788 "id": 4,
789 "pathFragmentId": 4
790 }, {
791 "id": 5,
792 "pathFragmentId": 5
793 }, {
794 "id": 6,
795 "pathFragmentId": 6
796 }],
797 "pathFragments": [{
798 "id": 1,
799 "label": "middleinput_one"
800 }, {
801 "id": 2,
802 "label": "middleinput_two"
803 }, {
804 "id": 3,
805 "label": "middleman_artifact"
806 }, {
807 "id": 4,
808 "label": "maininput_one"
809 }, {
810 "id": 5,
811 "label": "maininput_two"
812 }, {
813 "id": 6,
814 "label": "output"
815 }],
816 "depSetOfFiles": [{
817 "id": 1,
818 "directArtifactIds": [1, 2]
819 }, {
820 "id": 2,
821 "directArtifactIds": [3, 4, 5]
822 }],
823 "actions": [{
824 "targetId": 1,
825 "actionKey": "x",
826 "mnemonic": "Middleman",
827 "arguments": ["touch", "foo"],
828 "inputDepSetIds": [1],
829 "outputIds": [3],
830 "primaryOutputId": 3
831 }, {
832 "targetId": 2,
833 "actionKey": "y",
834 "mnemonic": "Main action",
835 "arguments": ["touch", "foo"],
836 "inputDepSetIds": [2],
837 "outputIds": [6],
838 "primaryOutputId": 6
839 }]
840}`
841
Chris Parsons1a7aca02022-04-25 22:35:15 -0400842 actualBuildStatements, actualDepsets, err := AqueryBuildStatements([]byte(inputString))
Chris Parsonsc4fb1332021-05-18 12:31:25 -0400843 if err != nil {
844 t.Errorf("Unexpected error %q", err)
845 }
Chris Parsons1a7aca02022-04-25 22:35:15 -0400846 if expected := 1; len(actualBuildStatements) != expected {
847 t.Fatalf("Expected %d build statements, got %d", expected, len(actualBuildStatements))
Chris Parsonsc4fb1332021-05-18 12:31:25 -0400848 }
849
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400850 expectedDepsetFiles := [][]string{
Usta Shrestha2ccdb422022-06-02 10:19:13 -0400851 {"middleinput_one", "middleinput_two", "maininput_one", "maininput_two"},
852 {"middleinput_one", "middleinput_two"},
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400853 }
854 assertFlattenedDepsets(t, actualDepsets, expectedDepsetFiles)
855
Chris Parsons1a7aca02022-04-25 22:35:15 -0400856 bs := actualBuildStatements[0]
857 if len(bs.InputPaths) > 0 {
858 t.Errorf("Expected main action raw inputs to be empty, but got %q", bs.InputPaths)
859 }
860
Chris Parsonsc4fb1332021-05-18 12:31:25 -0400861 expectedOutputs := []string{"output"}
862 if !reflect.DeepEqual(bs.OutputPaths, expectedOutputs) {
863 t.Errorf("Expected main action outputs %q, but got %q", expectedOutputs, bs.OutputPaths)
864 }
Chris Parsons1a7aca02022-04-25 22:35:15 -0400865
Chris Parsons1a7aca02022-04-25 22:35:15 -0400866 expectedFlattenedInputs := []string{"middleinput_one", "middleinput_two", "maininput_one", "maininput_two"}
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400867 actualFlattenedInputs := flattenDepsets(bs.InputDepsetHashes, actualDepsets)
Chris Parsons1a7aca02022-04-25 22:35:15 -0400868
869 if !reflect.DeepEqual(actualFlattenedInputs, expectedFlattenedInputs) {
870 t.Errorf("Expected flattened inputs %v, but got %v", expectedFlattenedInputs, actualFlattenedInputs)
871 }
872}
873
874// Returns the contents of given depsets in concatenated post order.
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400875func flattenDepsets(depsetHashesToFlatten []string, allDepsets []AqueryDepset) []string {
876 depsetsByHash := map[string]AqueryDepset{}
Chris Parsons1a7aca02022-04-25 22:35:15 -0400877 for _, depset := range allDepsets {
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400878 depsetsByHash[depset.ContentHash] = depset
Chris Parsons1a7aca02022-04-25 22:35:15 -0400879 }
Usta Shrestha16ac1352022-06-22 11:01:55 -0400880 var result []string
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400881 for _, depsetId := range depsetHashesToFlatten {
882 result = append(result, flattenDepset(depsetId, depsetsByHash)...)
Chris Parsons1a7aca02022-04-25 22:35:15 -0400883 }
884 return result
885}
886
887// Returns the contents of a given depset in post order.
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400888func flattenDepset(depsetHashToFlatten string, allDepsets map[string]AqueryDepset) []string {
889 depset := allDepsets[depsetHashToFlatten]
Usta Shrestha16ac1352022-06-22 11:01:55 -0400890 var result []string
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400891 for _, depsetId := range depset.TransitiveDepSetHashes {
Chris Parsons1a7aca02022-04-25 22:35:15 -0400892 result = append(result, flattenDepset(depsetId, allDepsets)...)
893 }
894 result = append(result, depset.DirectArtifacts...)
895 return result
Chris Parsonsc4fb1332021-05-18 12:31:25 -0400896}
897
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400898func assertFlattenedDepsets(t *testing.T, actualDepsets []AqueryDepset, expectedDepsetFiles [][]string) {
899 t.Helper()
900 if len(actualDepsets) != len(expectedDepsetFiles) {
Sasha Smundakf10c3ac2022-06-08 11:46:31 -0700901 t.Errorf("Expected %d depsets, but got %d depsets", len(expectedDepsetFiles), len(actualDepsets))
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400902 }
903 for i, actualDepset := range actualDepsets {
904 actualFlattenedInputs := flattenDepsets([]string{actualDepset.ContentHash}, actualDepsets)
905 if !reflect.DeepEqual(actualFlattenedInputs, expectedDepsetFiles[i]) {
906 t.Errorf("Expected depset files: %v, but got %v", expectedDepsetFiles[i], actualFlattenedInputs)
907 }
908 }
909}
910
Liz Kammerc49e6822021-06-08 15:04:11 -0400911func TestSimpleSymlink(t *testing.T) {
912 const inputString = `
913{
914 "artifacts": [{
915 "id": 1,
916 "pathFragmentId": 3
917 }, {
918 "id": 2,
919 "pathFragmentId": 5
920 }],
921 "actions": [{
922 "targetId": 1,
923 "actionKey": "x",
924 "mnemonic": "Symlink",
925 "inputDepSetIds": [1],
926 "outputIds": [2],
927 "primaryOutputId": 2
928 }],
929 "depSetOfFiles": [{
930 "id": 1,
931 "directArtifactIds": [1]
932 }],
933 "pathFragments": [{
934 "id": 1,
935 "label": "one"
936 }, {
937 "id": 2,
938 "label": "file_subdir",
939 "parentId": 1
940 }, {
941 "id": 3,
942 "label": "file",
943 "parentId": 2
944 }, {
945 "id": 4,
946 "label": "symlink_subdir",
947 "parentId": 1
948 }, {
949 "id": 5,
950 "label": "symlink",
951 "parentId": 4
952 }]
953}`
954
Chris Parsons1a7aca02022-04-25 22:35:15 -0400955 actual, _, err := AqueryBuildStatements([]byte(inputString))
Liz Kammerc49e6822021-06-08 15:04:11 -0400956
957 if err != nil {
958 t.Errorf("Unexpected error %q", err)
959 }
960
961 expectedBuildStatements := []BuildStatement{
Usta Shrestha16ac1352022-06-22 11:01:55 -0400962 {
Liz Kammerc49e6822021-06-08 15:04:11 -0400963 Command: "mkdir -p one/symlink_subdir && " +
964 "rm -f one/symlink_subdir/symlink && " +
Liz Kammerc7737782021-11-04 10:56:13 -0400965 "ln -sf $PWD/one/file_subdir/file one/symlink_subdir/symlink",
Liz Kammerc49e6822021-06-08 15:04:11 -0400966 InputPaths: []string{"one/file_subdir/file"},
967 OutputPaths: []string{"one/symlink_subdir/symlink"},
968 SymlinkPaths: []string{"one/symlink_subdir/symlink"},
969 Mnemonic: "Symlink",
970 },
971 }
972 assertBuildStatements(t, actual, expectedBuildStatements)
973}
974
975func TestSymlinkQuotesPaths(t *testing.T) {
976 const inputString = `
977{
978 "artifacts": [{
979 "id": 1,
980 "pathFragmentId": 3
981 }, {
982 "id": 2,
983 "pathFragmentId": 5
984 }],
985 "actions": [{
986 "targetId": 1,
987 "actionKey": "x",
988 "mnemonic": "SolibSymlink",
989 "inputDepSetIds": [1],
990 "outputIds": [2],
991 "primaryOutputId": 2
992 }],
993 "depSetOfFiles": [{
994 "id": 1,
995 "directArtifactIds": [1]
996 }],
997 "pathFragments": [{
998 "id": 1,
999 "label": "one"
1000 }, {
1001 "id": 2,
1002 "label": "file subdir",
1003 "parentId": 1
1004 }, {
1005 "id": 3,
1006 "label": "file",
1007 "parentId": 2
1008 }, {
1009 "id": 4,
1010 "label": "symlink subdir",
1011 "parentId": 1
1012 }, {
1013 "id": 5,
1014 "label": "symlink",
1015 "parentId": 4
1016 }]
1017}`
1018
Chris Parsons1a7aca02022-04-25 22:35:15 -04001019 actual, _, err := AqueryBuildStatements([]byte(inputString))
Liz Kammerc49e6822021-06-08 15:04:11 -04001020
1021 if err != nil {
1022 t.Errorf("Unexpected error %q", err)
1023 }
1024
1025 expectedBuildStatements := []BuildStatement{
Usta Shrestha16ac1352022-06-22 11:01:55 -04001026 {
Liz Kammerc49e6822021-06-08 15:04:11 -04001027 Command: "mkdir -p 'one/symlink subdir' && " +
1028 "rm -f 'one/symlink subdir/symlink' && " +
Liz Kammerc7737782021-11-04 10:56:13 -04001029 "ln -sf $PWD/'one/file subdir/file' 'one/symlink subdir/symlink'",
Liz Kammerc49e6822021-06-08 15:04:11 -04001030 InputPaths: []string{"one/file subdir/file"},
1031 OutputPaths: []string{"one/symlink subdir/symlink"},
1032 SymlinkPaths: []string{"one/symlink subdir/symlink"},
1033 Mnemonic: "SolibSymlink",
1034 },
1035 }
Liz Kammerc7737782021-11-04 10:56:13 -04001036 assertBuildStatements(t, expectedBuildStatements, actual)
Liz Kammerc49e6822021-06-08 15:04:11 -04001037}
1038
1039func TestSymlinkMultipleInputs(t *testing.T) {
1040 const inputString = `
1041{
1042 "artifacts": [{
1043 "id": 1,
1044 "pathFragmentId": 1
1045 }, {
1046 "id": 2,
1047 "pathFragmentId": 2
1048 }, {
1049 "id": 3,
1050 "pathFragmentId": 3
1051 }],
1052 "actions": [{
1053 "targetId": 1,
1054 "actionKey": "x",
1055 "mnemonic": "Symlink",
1056 "inputDepSetIds": [1],
1057 "outputIds": [3],
1058 "primaryOutputId": 3
1059 }],
1060 "depSetOfFiles": [{
1061 "id": 1,
1062 "directArtifactIds": [1,2]
1063 }],
1064 "pathFragments": [{
1065 "id": 1,
1066 "label": "file"
1067 }, {
1068 "id": 2,
1069 "label": "other_file"
1070 }, {
1071 "id": 3,
1072 "label": "symlink"
1073 }]
1074}`
1075
Chris Parsons1a7aca02022-04-25 22:35:15 -04001076 _, _, err := AqueryBuildStatements([]byte(inputString))
Liz Kammerc49e6822021-06-08 15:04:11 -04001077 assertError(t, err, `Expect 1 input and 1 output to symlink action, got: input ["file" "other_file"], output ["symlink"]`)
1078}
1079
1080func TestSymlinkMultipleOutputs(t *testing.T) {
1081 const inputString = `
1082{
1083 "artifacts": [{
1084 "id": 1,
1085 "pathFragmentId": 1
1086 }, {
1087 "id": 2,
1088 "pathFragmentId": 2
1089 }, {
1090 "id": 3,
1091 "pathFragmentId": 3
1092 }],
1093 "actions": [{
1094 "targetId": 1,
1095 "actionKey": "x",
1096 "mnemonic": "Symlink",
1097 "inputDepSetIds": [1],
1098 "outputIds": [2,3],
1099 "primaryOutputId": 2
1100 }],
1101 "depSetOfFiles": [{
1102 "id": 1,
1103 "directArtifactIds": [1]
1104 }],
1105 "pathFragments": [{
1106 "id": 1,
1107 "label": "file"
1108 }, {
1109 "id": 2,
1110 "label": "symlink"
1111 }, {
1112 "id": 3,
1113 "label": "other_symlink"
1114 }]
1115}`
1116
Chris Parsons1a7aca02022-04-25 22:35:15 -04001117 _, _, err := AqueryBuildStatements([]byte(inputString))
Liz Kammerc49e6822021-06-08 15:04:11 -04001118 assertError(t, err, `Expect 1 input and 1 output to symlink action, got: input ["file"], output ["symlink" "other_symlink"]`)
1119}
1120
Wei Li455ba832021-11-04 22:58:12 +00001121func TestTemplateExpandActionSubstitutions(t *testing.T) {
1122 const inputString = `
1123{
1124 "artifacts": [{
1125 "id": 1,
1126 "pathFragmentId": 1
1127 }],
1128 "actions": [{
1129 "targetId": 1,
1130 "actionKey": "x",
1131 "mnemonic": "TemplateExpand",
1132 "configurationId": 1,
1133 "outputIds": [1],
1134 "primaryOutputId": 1,
1135 "executionPlatform": "//build/bazel/platforms:linux_x86_64",
1136 "templateContent": "Test template substitutions: %token1%, %python_binary%",
1137 "substitutions": [{
1138 "key": "%token1%",
1139 "value": "abcd"
1140 },{
1141 "key": "%python_binary%",
1142 "value": "python3"
1143 }]
1144 }],
1145 "pathFragments": [{
1146 "id": 1,
1147 "label": "template_file"
1148 }]
1149}`
1150
Chris Parsons1a7aca02022-04-25 22:35:15 -04001151 actual, _, err := AqueryBuildStatements([]byte(inputString))
Wei Li455ba832021-11-04 22:58:12 +00001152
1153 if err != nil {
1154 t.Errorf("Unexpected error %q", err)
1155 }
1156
1157 expectedBuildStatements := []BuildStatement{
Usta Shrestha16ac1352022-06-22 11:01:55 -04001158 {
Wei Li455ba832021-11-04 22:58:12 +00001159 Command: "/bin/bash -c 'echo \"Test template substitutions: abcd, python3\" | sed \"s/\\\\\\\\n/\\\\n/g\" > template_file && " +
1160 "chmod a+x template_file'",
1161 OutputPaths: []string{"template_file"},
1162 Mnemonic: "TemplateExpand",
1163 },
1164 }
1165 assertBuildStatements(t, expectedBuildStatements, actual)
1166}
1167
1168func TestTemplateExpandActionNoOutput(t *testing.T) {
1169 const inputString = `
1170{
1171 "artifacts": [{
1172 "id": 1,
1173 "pathFragmentId": 1
1174 }],
1175 "actions": [{
1176 "targetId": 1,
1177 "actionKey": "x",
1178 "mnemonic": "TemplateExpand",
1179 "configurationId": 1,
1180 "primaryOutputId": 1,
1181 "executionPlatform": "//build/bazel/platforms:linux_x86_64",
1182 "templateContent": "Test template substitutions: %token1%, %python_binary%",
1183 "substitutions": [{
1184 "key": "%token1%",
1185 "value": "abcd"
1186 },{
1187 "key": "%python_binary%",
1188 "value": "python3"
1189 }]
1190 }],
1191 "pathFragments": [{
1192 "id": 1,
1193 "label": "template_file"
1194 }]
1195}`
1196
Chris Parsons1a7aca02022-04-25 22:35:15 -04001197 _, _, err := AqueryBuildStatements([]byte(inputString))
Wei Li455ba832021-11-04 22:58:12 +00001198 assertError(t, err, `Expect 1 output to template expand action, got: output []`)
1199}
1200
1201func TestPythonZipperActionSuccess(t *testing.T) {
1202 const inputString = `
1203{
1204 "artifacts": [{
1205 "id": 1,
1206 "pathFragmentId": 1
1207 },{
1208 "id": 2,
1209 "pathFragmentId": 2
1210 },{
1211 "id": 3,
1212 "pathFragmentId": 3
1213 },{
1214 "id": 4,
1215 "pathFragmentId": 4
1216 },{
1217 "id": 5,
1218 "pathFragmentId": 10
1219 },{
1220 "id": 10,
1221 "pathFragmentId": 20
1222 }],
1223 "actions": [{
1224 "targetId": 1,
1225 "actionKey": "x",
1226 "mnemonic": "TemplateExpand",
1227 "configurationId": 1,
1228 "outputIds": [1],
1229 "primaryOutputId": 1,
1230 "executionPlatform": "//build/bazel/platforms:linux_x86_64",
1231 "templateContent": "Test template substitutions: %token1%, %python_binary%",
1232 "substitutions": [{
1233 "key": "%token1%",
1234 "value": "abcd"
1235 },{
1236 "key": "%python_binary%",
1237 "value": "python3"
1238 }]
1239 },{
1240 "targetId": 1,
1241 "actionKey": "x",
1242 "mnemonic": "PythonZipper",
1243 "configurationId": 1,
1244 "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"],
1245 "outputIds": [2],
1246 "inputDepSetIds": [1],
1247 "primaryOutputId": 2
1248 }],
1249 "depSetOfFiles": [{
1250 "id": 1,
1251 "directArtifactIds": [4, 3, 5]
1252 }],
1253 "pathFragments": [{
1254 "id": 1,
1255 "label": "python_binary"
1256 },{
1257 "id": 2,
1258 "label": "python_binary.zip"
1259 },{
1260 "id": 3,
1261 "label": "python_binary.py"
1262 },{
1263 "id": 9,
1264 "label": ".."
1265 }, {
1266 "id": 8,
1267 "label": "bazel_tools",
1268 "parentId": 9
1269 }, {
1270 "id": 7,
1271 "label": "tools",
1272 "parentId": 8
1273 }, {
1274 "id": 6,
1275 "label": "zip",
1276 "parentId": 7
1277 }, {
1278 "id": 5,
1279 "label": "zipper",
1280 "parentId": 6
1281 }, {
1282 "id": 4,
1283 "label": "zipper",
1284 "parentId": 5
1285 },{
1286 "id": 16,
1287 "label": "bazel-out"
1288 },{
1289 "id": 15,
1290 "label": "bazel_tools",
1291 "parentId": 16
1292 }, {
1293 "id": 14,
1294 "label": "k8-fastbuild",
1295 "parentId": 15
1296 }, {
1297 "id": 13,
1298 "label": "bin",
1299 "parentId": 14
1300 }, {
1301 "id": 12,
1302 "label": "tools",
1303 "parentId": 13
1304 }, {
1305 "id": 11,
1306 "label": "python",
1307 "parentId": 12
1308 }, {
1309 "id": 10,
1310 "label": "py3wrapper.sh",
1311 "parentId": 11
1312 },{
1313 "id": 20,
1314 "label": "python_binary"
1315 }]
1316}`
Chris Parsons1a7aca02022-04-25 22:35:15 -04001317 actual, _, err := AqueryBuildStatements([]byte(inputString))
Wei Li455ba832021-11-04 22:58:12 +00001318
1319 if err != nil {
1320 t.Errorf("Unexpected error %q", err)
1321 }
1322
1323 expectedBuildStatements := []BuildStatement{
Usta Shrestha16ac1352022-06-22 11:01:55 -04001324 {
Wei Li455ba832021-11-04 22:58:12 +00001325 Command: "/bin/bash -c 'echo \"Test template substitutions: abcd, python3\" | sed \"s/\\\\\\\\n/\\\\n/g\" > python_binary && " +
1326 "chmod a+x python_binary'",
1327 InputPaths: []string{"python_binary.zip"},
1328 OutputPaths: []string{"python_binary"},
1329 Mnemonic: "TemplateExpand",
1330 },
Usta Shrestha16ac1352022-06-22 11:01:55 -04001331 {
Wei Li455ba832021-11-04 22:58:12 +00001332 Command: "../bazel_tools/tools/zip/zipper/zipper cC python_binary.zip __main__.py=bazel-out/k8-fastbuild/bin/python_binary.temp " +
1333 "__init__.py= runfiles/__main__/__init__.py= runfiles/__main__/python_binary.py=python_binary.py && " +
1334 "../bazel_tools/tools/zip/zipper/zipper x python_binary.zip -d python_binary.runfiles && ln -sf runfiles/__main__ python_binary.runfiles",
1335 InputPaths: []string{"../bazel_tools/tools/zip/zipper/zipper", "python_binary.py"},
1336 OutputPaths: []string{"python_binary.zip"},
1337 Mnemonic: "PythonZipper",
1338 },
1339 }
1340 assertBuildStatements(t, expectedBuildStatements, actual)
1341}
1342
1343func TestPythonZipperActionNoInput(t *testing.T) {
1344 const inputString = `
1345{
1346 "artifacts": [{
1347 "id": 1,
1348 "pathFragmentId": 1
1349 },{
1350 "id": 2,
1351 "pathFragmentId": 2
1352 }],
1353 "actions": [{
1354 "targetId": 1,
1355 "actionKey": "x",
1356 "mnemonic": "PythonZipper",
1357 "configurationId": 1,
1358 "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"],
1359 "outputIds": [2],
1360 "primaryOutputId": 2
1361 }],
1362 "pathFragments": [{
1363 "id": 1,
1364 "label": "python_binary"
1365 },{
1366 "id": 2,
1367 "label": "python_binary.zip"
1368 }]
1369}`
Chris Parsons1a7aca02022-04-25 22:35:15 -04001370 _, _, err := AqueryBuildStatements([]byte(inputString))
Wei Li455ba832021-11-04 22:58:12 +00001371 assertError(t, err, `Expect 1+ input and 1 output to python zipper action, got: input [], output ["python_binary.zip"]`)
1372}
1373
1374func TestPythonZipperActionNoOutput(t *testing.T) {
1375 const inputString = `
1376{
1377 "artifacts": [{
1378 "id": 1,
1379 "pathFragmentId": 1
1380 },{
1381 "id": 2,
1382 "pathFragmentId": 2
1383 },{
1384 "id": 3,
1385 "pathFragmentId": 3
1386 },{
1387 "id": 4,
1388 "pathFragmentId": 4
1389 },{
1390 "id": 5,
1391 "pathFragmentId": 10
1392 }],
1393 "actions": [{
1394 "targetId": 1,
1395 "actionKey": "x",
1396 "mnemonic": "PythonZipper",
1397 "configurationId": 1,
1398 "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"],
1399 "inputDepSetIds": [1]
1400 }],
1401 "depSetOfFiles": [{
1402 "id": 1,
1403 "directArtifactIds": [4, 3, 5]
1404 }],
1405 "pathFragments": [{
1406 "id": 1,
1407 "label": "python_binary"
1408 },{
1409 "id": 2,
1410 "label": "python_binary.zip"
1411 },{
1412 "id": 3,
1413 "label": "python_binary.py"
1414 },{
1415 "id": 9,
1416 "label": ".."
1417 }, {
1418 "id": 8,
1419 "label": "bazel_tools",
1420 "parentId": 9
1421 }, {
1422 "id": 7,
1423 "label": "tools",
1424 "parentId": 8
1425 }, {
1426 "id": 6,
1427 "label": "zip",
1428 "parentId": 7
1429 }, {
1430 "id": 5,
1431 "label": "zipper",
1432 "parentId": 6
1433 }, {
1434 "id": 4,
1435 "label": "zipper",
1436 "parentId": 5
1437 },{
1438 "id": 16,
1439 "label": "bazel-out"
1440 },{
1441 "id": 15,
1442 "label": "bazel_tools",
1443 "parentId": 16
1444 }, {
1445 "id": 14,
1446 "label": "k8-fastbuild",
1447 "parentId": 15
1448 }, {
1449 "id": 13,
1450 "label": "bin",
1451 "parentId": 14
1452 }, {
1453 "id": 12,
1454 "label": "tools",
1455 "parentId": 13
1456 }, {
1457 "id": 11,
1458 "label": "python",
1459 "parentId": 12
1460 }, {
1461 "id": 10,
1462 "label": "py3wrapper.sh",
1463 "parentId": 11
1464 }]
1465}`
Chris Parsons1a7aca02022-04-25 22:35:15 -04001466 _, _, err := AqueryBuildStatements([]byte(inputString))
Wei Li455ba832021-11-04 22:58:12 +00001467 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 []`)
1468}
1469
Chris Parsons4f069892021-01-15 12:22:41 -05001470func assertError(t *testing.T, err error, expected string) {
Liz Kammerc49e6822021-06-08 15:04:11 -04001471 t.Helper()
Chris Parsons943f2432021-01-19 11:36:50 -05001472 if err == nil {
1473 t.Errorf("expected error '%s', but got no error", expected)
1474 } else if err.Error() != expected {
Liz Kammerc49e6822021-06-08 15:04:11 -04001475 t.Errorf("expected error:\n\t'%s', but got:\n\t'%s'", expected, err.Error())
Chris Parsons4f069892021-01-15 12:22:41 -05001476 }
1477}
1478
1479// Asserts that the given actual build statements match the given expected build statements.
1480// Build statement equivalence is determined using buildStatementEquals.
1481func assertBuildStatements(t *testing.T, expected []BuildStatement, actual []BuildStatement) {
Liz Kammerc49e6822021-06-08 15:04:11 -04001482 t.Helper()
Chris Parsons4f069892021-01-15 12:22:41 -05001483 if len(expected) != len(actual) {
Liz Kammerc3192992021-11-16 17:01:11 -05001484 t.Errorf("expected %d build statements, but got %d,\n expected: %#v,\n actual: %#v",
Chris Parsons4f069892021-01-15 12:22:41 -05001485 len(expected), len(actual), expected, actual)
1486 return
1487 }
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001488 type compareFn = func(i int, j int) bool
1489 byCommand := func(slice []BuildStatement) compareFn {
1490 return func(i int, j int) bool {
1491 return slice[i].Command < slice[j].Command
Chris Parsons4f069892021-01-15 12:22:41 -05001492 }
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001493 }
1494 sort.SliceStable(expected, byCommand(expected))
1495 sort.SliceStable(actual, byCommand(actual))
1496 for i, actualStatement := range actual {
1497 expectedStatement := expected[i]
1498 if differingField := buildStatementEquals(actualStatement, expectedStatement); differingField != "" {
1499 t.Errorf("%s differs\nunexpected build statement %#v.\nexpected: %#v",
1500 differingField, actualStatement, expected)
1501 return
1502 }
Chris Parsons4f069892021-01-15 12:22:41 -05001503 }
1504}
1505
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001506func buildStatementEquals(first BuildStatement, second BuildStatement) string {
Chris Parsons4f069892021-01-15 12:22:41 -05001507 if first.Mnemonic != second.Mnemonic {
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001508 return "Mnemonic"
Chris Parsons4f069892021-01-15 12:22:41 -05001509 }
1510 if first.Command != second.Command {
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001511 return "Command"
Chris Parsons4f069892021-01-15 12:22:41 -05001512 }
1513 // Ordering is significant for environment variables.
1514 if !reflect.DeepEqual(first.Env, second.Env) {
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001515 return "Env"
Chris Parsons4f069892021-01-15 12:22:41 -05001516 }
1517 // Ordering is irrelevant for input and output paths, so compare sets.
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001518 if !reflect.DeepEqual(sortedStrings(first.InputPaths), sortedStrings(second.InputPaths)) {
1519 return "InputPaths"
Chris Parsons4f069892021-01-15 12:22:41 -05001520 }
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001521 if !reflect.DeepEqual(sortedStrings(first.OutputPaths), sortedStrings(second.OutputPaths)) {
1522 return "OutputPaths"
Chris Parsons4f069892021-01-15 12:22:41 -05001523 }
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001524 if !reflect.DeepEqual(sortedStrings(first.SymlinkPaths), sortedStrings(second.SymlinkPaths)) {
1525 return "SymlinkPaths"
Liz Kammerc49e6822021-06-08 15:04:11 -04001526 }
1527 if first.Depfile != second.Depfile {
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001528 return "Depfile"
Liz Kammerc49e6822021-06-08 15:04:11 -04001529 }
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001530 return ""
Chris Parsons4f069892021-01-15 12:22:41 -05001531}
1532
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001533func sortedStrings(stringSlice []string) []string {
1534 sorted := make([]string, len(stringSlice))
1535 copy(sorted, stringSlice)
1536 sort.Strings(sorted)
1537 return sorted
Chris Parsons4f069892021-01-15 12:22:41 -05001538}