blob: c759d56ee72b0f72495c4356fed4bea599f4b197 [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{
Sasha Smundake3cf1ab2022-06-30 11:36:18 -070028 "artifacts": [
29 { "id": 1, "pathFragmentId": 1 },
30 { "id": 2, "pathFragmentId": 6 },
31 { "id": 3, "pathFragmentId": 8 },
32 { "id": 4, "pathFragmentId": 12 },
33 { "id": 5, "pathFragmentId": 19 },
34 { "id": 6, "pathFragmentId": 20 },
35 { "id": 7, "pathFragmentId": 21 }],
Chris Parsons4f069892021-01-15 12:22:41 -050036 "actions": [{
37 "targetId": 1,
38 "actionKey": "ab53f6ecbdc2ee8cb8812613b63205464f1f5083f6dca87081a0a398c0f1ecf7",
39 "mnemonic": "Genrule",
40 "configurationId": 1,
41 "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"],
42 "environmentVariables": [{
43 "key": "PATH",
44 "value": "/bin:/usr/bin:/usr/local/bin"
45 }],
46 "inputDepSetIds": [1],
47 "outputIds": [4],
48 "primaryOutputId": 4
49 }, {
50 "targetId": 2,
51 "actionKey": "9f4309ce165dac458498cb92811c18b0b7919782cc37b82a42d2141b8cc90826",
52 "mnemonic": "Genrule",
53 "configurationId": 1,
54 "arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py x86 ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-x86.S"],
55 "environmentVariables": [{
56 "key": "PATH",
57 "value": "/bin:/usr/bin:/usr/local/bin"
58 }],
59 "inputDepSetIds": [2],
60 "outputIds": [5],
61 "primaryOutputId": 5
62 }, {
63 "targetId": 3,
64 "actionKey": "50d6c586103ebeed3a218195540bcc30d329464eae36377eb82f8ce7c36ac342",
65 "mnemonic": "Genrule",
66 "configurationId": 1,
67 "arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py x86_64 ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-x86_64.S"],
68 "environmentVariables": [{
69 "key": "PATH",
70 "value": "/bin:/usr/bin:/usr/local/bin"
71 }],
72 "inputDepSetIds": [3],
73 "outputIds": [6],
74 "primaryOutputId": 6
75 }, {
76 "targetId": 4,
77 "actionKey": "f30cbe442f5216f4223cf16a39112cad4ec56f31f49290d85cff587e48647ffa",
78 "mnemonic": "Genrule",
79 "configurationId": 1,
80 "arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py arm64 ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-arm64.S"],
81 "environmentVariables": [{
82 "key": "PATH",
83 "value": "/bin:/usr/bin:/usr/local/bin"
84 }],
85 "inputDepSetIds": [4],
86 "outputIds": [7],
87 "primaryOutputId": 7
88 }],
Sasha Smundake3cf1ab2022-06-30 11:36:18 -070089 "targets": [
90 { "id": 1, "label": "@sourceroot//bionic/libc:syscalls-arm", "ruleClassId": 1 },
91 { "id": 2, "label": "@sourceroot//bionic/libc:syscalls-x86", "ruleClassId": 1 },
92 { "id": 3, "label": "@sourceroot//bionic/libc:syscalls-x86_64", "ruleClassId": 1 },
93 { "id": 4, "label": "@sourceroot//bionic/libc:syscalls-arm64", "ruleClassId": 1 }],
94 "depSetOfFiles": [
95 { "id": 1, "directArtifactIds": [1, 2, 3] },
96 { "id": 2, "directArtifactIds": [1, 2, 3] },
97 { "id": 3, "directArtifactIds": [1, 2, 3] },
98 { "id": 4, "directArtifactIds": [1, 2, 3] }],
Chris Parsons4f069892021-01-15 12:22:41 -050099 "configuration": [{
100 "id": 1,
101 "mnemonic": "k8-fastbuild",
102 "platformName": "k8",
103 "checksum": "485c362832c178e367d972177f68e69e0981e51e67ef1c160944473db53fe046"
104 }],
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700105 "ruleClasses": [{ "id": 1, "name": "genrule"}],
106 "pathFragments": [
107 { "id": 5, "label": ".." },
108 { "id": 4, "label": "sourceroot", "parentId": 5 },
109 { "id": 3, "label": "bionic", "parentId": 4 },
110 { "id": 2, "label": "libc", "parentId": 3 },
111 { "id": 1, "label": "SYSCALLS.TXT", "parentId": 2 },
112 { "id": 7, "label": "tools", "parentId": 2 },
113 { "id": 6, "label": "gensyscalls.py", "parentId": 7 },
114 { "id": 11, "label": "bazel_tools", "parentId": 5 },
115 { "id": 10, "label": "tools", "parentId": 11 },
116 { "id": 9, "label": "genrule", "parentId": 10 },
117 { "id": 8, "label": "genrule-setup.sh", "parentId": 9 },
118 { "id": 18, "label": "bazel-out" },
119 { "id": 17, "label": "sourceroot", "parentId": 18 },
120 { "id": 16, "label": "k8-fastbuild", "parentId": 17 },
121 { "id": 15, "label": "bin", "parentId": 16 },
122 { "id": 14, "label": "bionic", "parentId": 15 },
123 { "id": 13, "label": "libc", "parentId": 14 },
124 { "id": 12, "label": "syscalls-arm.S", "parentId": 13 },
125 { "id": 19, "label": "syscalls-x86.S", "parentId": 13 },
126 { "id": 20, "label": "syscalls-x86_64.S", "parentId": 13 },
127 { "id": 21, "label": "syscalls-arm64.S", "parentId": 13 }]
Chris Parsons4f069892021-01-15 12:22:41 -0500128}`
Chris Parsons1a7aca02022-04-25 22:35:15 -0400129 actualbuildStatements, actualDepsets, _ := AqueryBuildStatements([]byte(inputString))
Usta Shrestha16ac1352022-06-22 11:01:55 -0400130 var expectedBuildStatements []BuildStatement
Chris Parsons4f069892021-01-15 12:22:41 -0500131 for _, arch := range []string{"arm", "arm64", "x86", "x86_64"} {
132 expectedBuildStatements = append(expectedBuildStatements,
133 BuildStatement{
134 Command: fmt.Sprintf(
135 "/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'",
136 arch, arch),
137 OutputPaths: []string{
138 fmt.Sprintf("bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-%s.S", arch),
139 },
Chris Parsons4f069892021-01-15 12:22:41 -0500140 Env: []KeyValuePair{
Usta Shrestha16ac1352022-06-22 11:01:55 -0400141 {Key: "PATH", Value: "/bin:/usr/bin:/usr/local/bin"},
Chris Parsons4f069892021-01-15 12:22:41 -0500142 },
143 Mnemonic: "Genrule",
144 })
145 }
146 assertBuildStatements(t, expectedBuildStatements, actualbuildStatements)
Chris Parsons1a7aca02022-04-25 22:35:15 -0400147
148 expectedFlattenedInputs := []string{
149 "../sourceroot/bionic/libc/SYSCALLS.TXT",
150 "../sourceroot/bionic/libc/tools/gensyscalls.py",
Chris Parsons1a7aca02022-04-25 22:35:15 -0400151 }
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400152 // In this example, each depset should have the same expected inputs.
153 for _, actualDepset := range actualDepsets {
154 actualFlattenedInputs := flattenDepsets([]string{actualDepset.ContentHash}, actualDepsets)
155 if !reflect.DeepEqual(actualFlattenedInputs, expectedFlattenedInputs) {
156 t.Errorf("Expected flattened inputs %v, but got %v", expectedFlattenedInputs, actualFlattenedInputs)
157 }
Chris Parsons1a7aca02022-04-25 22:35:15 -0400158 }
Chris Parsons4f069892021-01-15 12:22:41 -0500159}
160
161func TestInvalidOutputId(t *testing.T) {
162 const inputString = `
163{
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700164 "artifacts": [
165 { "id": 1, "pathFragmentId": 1 },
166 { "id": 2, "pathFragmentId": 2 }],
Chris Parsons4f069892021-01-15 12:22:41 -0500167 "actions": [{
168 "targetId": 1,
169 "actionKey": "x",
170 "mnemonic": "x",
171 "arguments": ["touch", "foo"],
172 "inputDepSetIds": [1],
173 "outputIds": [3],
174 "primaryOutputId": 3
175 }],
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700176 "depSetOfFiles": [
177 { "id": 1, "directArtifactIds": [1, 2] }],
178 "pathFragments": [
179 { "id": 1, "label": "one" },
180 { "id": 2, "label": "two" }]
Chris Parsons4f069892021-01-15 12:22:41 -0500181}`
182
Chris Parsons1a7aca02022-04-25 22:35:15 -0400183 _, _, err := AqueryBuildStatements([]byte(inputString))
Chris Parsons4f069892021-01-15 12:22:41 -0500184 assertError(t, err, "undefined outputId 3")
185}
186
Chris Parsons1a7aca02022-04-25 22:35:15 -0400187func TestInvalidInputDepsetIdFromAction(t *testing.T) {
Chris Parsons4f069892021-01-15 12:22:41 -0500188 const inputString = `
189{
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700190 "artifacts": [
191 { "id": 1, "pathFragmentId": 1 },
192 { "id": 2, "pathFragmentId": 2 }],
Chris Parsons4f069892021-01-15 12:22:41 -0500193 "actions": [{
194 "targetId": 1,
195 "actionKey": "x",
196 "mnemonic": "x",
197 "arguments": ["touch", "foo"],
198 "inputDepSetIds": [2],
199 "outputIds": [1],
200 "primaryOutputId": 1
201 }],
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700202 "depSetOfFiles": [
203 { "id": 1, "directArtifactIds": [1, 2] }],
204 "pathFragments": [
205 { "id": 1, "label": "one" },
206 { "id": 2, "label": "two" }]
Chris Parsons4f069892021-01-15 12:22:41 -0500207}`
208
Chris Parsons1a7aca02022-04-25 22:35:15 -0400209 _, _, err := AqueryBuildStatements([]byte(inputString))
Chris Parsons4f069892021-01-15 12:22:41 -0500210 assertError(t, err, "undefined input depsetId 2")
211}
212
Chris Parsons1a7aca02022-04-25 22:35:15 -0400213func TestInvalidInputDepsetIdFromDepset(t *testing.T) {
214 const inputString = `
215{
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700216 "artifacts": [
217 { "id": 1, "pathFragmentId": 1 },
218 { "id": 2, "pathFragmentId": 2 }],
Chris Parsons1a7aca02022-04-25 22:35:15 -0400219 "actions": [{
220 "targetId": 1,
221 "actionKey": "x",
222 "mnemonic": "x",
223 "arguments": ["touch", "foo"],
224 "inputDepSetIds": [1],
225 "outputIds": [1],
226 "primaryOutputId": 1
227 }],
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700228 "depSetOfFiles": [
229 { "id": 1, "directArtifactIds": [1, 2], "transitiveDepSetIds": [42] }],
230 "pathFragments": [
231 { "id": 1, "label": "one"},
232 { "id": 2, "label": "two" }]
Chris Parsons1a7aca02022-04-25 22:35:15 -0400233}`
234
235 _, _, err := AqueryBuildStatements([]byte(inputString))
236 assertError(t, err, "undefined input depsetId 42 (referenced by depsetId 1)")
237}
238
Chris Parsons4f069892021-01-15 12:22:41 -0500239func TestInvalidInputArtifactId(t *testing.T) {
240 const inputString = `
241{
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700242 "artifacts": [
243 { "id": 1, "pathFragmentId": 1 },
244 { "id": 2, "pathFragmentId": 2 }],
Chris Parsons4f069892021-01-15 12:22:41 -0500245 "actions": [{
246 "targetId": 1,
247 "actionKey": "x",
248 "mnemonic": "x",
249 "arguments": ["touch", "foo"],
250 "inputDepSetIds": [1],
251 "outputIds": [1],
252 "primaryOutputId": 1
253 }],
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700254 "depSetOfFiles": [
255 { "id": 1, "directArtifactIds": [1, 3] }],
256 "pathFragments": [
257 { "id": 1, "label": "one" },
258 { "id": 2, "label": "two" }]
Chris Parsons4f069892021-01-15 12:22:41 -0500259}`
260
Chris Parsons1a7aca02022-04-25 22:35:15 -0400261 _, _, err := AqueryBuildStatements([]byte(inputString))
Chris Parsons4f069892021-01-15 12:22:41 -0500262 assertError(t, err, "undefined input artifactId 3")
263}
264
265func TestInvalidPathFragmentId(t *testing.T) {
266 const inputString = `
267{
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700268 "artifacts": [
269 { "id": 1, "pathFragmentId": 1 },
270 { "id": 2, "pathFragmentId": 2 }],
Chris Parsons4f069892021-01-15 12:22:41 -0500271 "actions": [{
272 "targetId": 1,
273 "actionKey": "x",
274 "mnemonic": "x",
275 "arguments": ["touch", "foo"],
276 "inputDepSetIds": [1],
277 "outputIds": [1],
278 "primaryOutputId": 1
279 }],
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700280 "depSetOfFiles": [
281 { "id": 1, "directArtifactIds": [1, 2] }],
282 "pathFragments": [
283 { "id": 1, "label": "one" },
284 { "id": 2, "label": "two", "parentId": 3 }]
Chris Parsons4f069892021-01-15 12:22:41 -0500285}`
286
Chris Parsons1a7aca02022-04-25 22:35:15 -0400287 _, _, err := AqueryBuildStatements([]byte(inputString))
Chris Parsons4f069892021-01-15 12:22:41 -0500288 assertError(t, err, "undefined path fragment id 3")
289}
290
Liz Kammerde116852021-03-25 16:42:37 -0400291func TestDepfiles(t *testing.T) {
292 const inputString = `
293{
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700294 "artifacts": [
295 { "id": 1, "pathFragmentId": 1 },
296 { "id": 2, "pathFragmentId": 2 },
297 { "id": 3, "pathFragmentId": 3 }],
Liz Kammerde116852021-03-25 16:42:37 -0400298 "actions": [{
299 "targetId": 1,
300 "actionKey": "x",
301 "mnemonic": "x",
302 "arguments": ["touch", "foo"],
303 "inputDepSetIds": [1],
304 "outputIds": [2, 3],
305 "primaryOutputId": 2
306 }],
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700307 "depSetOfFiles": [
308 { "id": 1, "directArtifactIds": [1, 2, 3] }],
309 "pathFragments": [
310 { "id": 1, "label": "one" },
311 { "id": 2, "label": "two" },
312 { "id": 3, "label": "two.d" }]
Liz Kammerde116852021-03-25 16:42:37 -0400313}`
314
Chris Parsons1a7aca02022-04-25 22:35:15 -0400315 actual, _, err := AqueryBuildStatements([]byte(inputString))
Liz Kammerde116852021-03-25 16:42:37 -0400316 if err != nil {
317 t.Errorf("Unexpected error %q", err)
318 }
319 if expected := 1; len(actual) != expected {
320 t.Fatalf("Expected %d build statements, got %d", expected, len(actual))
321 }
322
323 bs := actual[0]
324 expectedDepfile := "two.d"
325 if bs.Depfile == nil {
326 t.Errorf("Expected depfile %q, but there was none found", expectedDepfile)
327 } else if *bs.Depfile != expectedDepfile {
328 t.Errorf("Expected depfile %q, but got %q", expectedDepfile, *bs.Depfile)
329 }
330}
331
332func TestMultipleDepfiles(t *testing.T) {
333 const inputString = `
334{
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700335 "artifacts": [
336 { "id": 1, "pathFragmentId": 1 },
337 { "id": 2, "pathFragmentId": 2 },
338 { "id": 3, "pathFragmentId": 3 },
339 { "id": 4, "pathFragmentId": 4 }],
Liz Kammerde116852021-03-25 16:42:37 -0400340 "actions": [{
341 "targetId": 1,
342 "actionKey": "x",
343 "mnemonic": "x",
344 "arguments": ["touch", "foo"],
345 "inputDepSetIds": [1],
346 "outputIds": [2,3,4],
347 "primaryOutputId": 2
348 }],
349 "depSetOfFiles": [{
350 "id": 1,
351 "directArtifactIds": [1, 2, 3, 4]
352 }],
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700353 "pathFragments": [
354 { "id": 1, "label": "one" },
355 { "id": 2, "label": "two" },
356 { "id": 3, "label": "two.d" },
357 { "id": 4, "label": "other.d" }]
Liz Kammerde116852021-03-25 16:42:37 -0400358}`
359
Chris Parsons1a7aca02022-04-25 22:35:15 -0400360 _, _, err := AqueryBuildStatements([]byte(inputString))
Liz Kammerde116852021-03-25 16:42:37 -0400361 assertError(t, err, `found multiple potential depfiles "two.d", "other.d"`)
362}
363
Chris Parsons943f2432021-01-19 11:36:50 -0500364func TestTransitiveInputDepsets(t *testing.T) {
365 // The input aquery for this test comes from a proof-of-concept starlark rule which registers
366 // a single action with many inputs given via a deep depset.
367 const inputString = `
368{
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700369 "artifacts": [
370 { "id": 1, "pathFragmentId": 1 },
371 { "id": 2, "pathFragmentId": 7 },
372 { "id": 3, "pathFragmentId": 8 },
373 { "id": 4, "pathFragmentId": 9 },
374 { "id": 5, "pathFragmentId": 10 },
375 { "id": 6, "pathFragmentId": 11 },
376 { "id": 7, "pathFragmentId": 12 },
377 { "id": 8, "pathFragmentId": 13 },
378 { "id": 9, "pathFragmentId": 14 },
379 { "id": 10, "pathFragmentId": 15 },
380 { "id": 11, "pathFragmentId": 16 },
381 { "id": 12, "pathFragmentId": 17 },
382 { "id": 13, "pathFragmentId": 18 },
383 { "id": 14, "pathFragmentId": 19 },
384 { "id": 15, "pathFragmentId": 20 },
385 { "id": 16, "pathFragmentId": 21 },
386 { "id": 17, "pathFragmentId": 22 },
387 { "id": 18, "pathFragmentId": 23 },
388 { "id": 19, "pathFragmentId": 24 },
389 { "id": 20, "pathFragmentId": 25 },
390 { "id": 21, "pathFragmentId": 26 }],
Chris Parsons943f2432021-01-19 11:36:50 -0500391 "actions": [{
392 "targetId": 1,
393 "actionKey": "3b826d17fadbbbcd8313e456b90ec47c078c438088891dd45b4adbcd8889dc50",
394 "mnemonic": "Action",
395 "configurationId": 1,
396 "arguments": ["/bin/bash", "-c", "touch bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out"],
397 "inputDepSetIds": [1],
398 "outputIds": [21],
399 "primaryOutputId": 21
400 }],
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700401 "depSetOfFiles": [
402 { "id": 3, "directArtifactIds": [1, 2, 3, 4, 5] },
403 { "id": 4, "directArtifactIds": [6, 7, 8, 9, 10] },
404 { "id": 2, "transitiveDepSetIds": [3, 4], "directArtifactIds": [11, 12, 13, 14, 15] },
405 { "id": 5, "directArtifactIds": [16, 17, 18, 19] },
406 { "id": 1, "transitiveDepSetIds": [2, 5], "directArtifactIds": [20] }],
407 "pathFragments": [
408 { "id": 6, "label": "bazel-out" },
409 { "id": 5, "label": "sourceroot", "parentId": 6 },
410 { "id": 4, "label": "k8-fastbuild", "parentId": 5 },
411 { "id": 3, "label": "bin", "parentId": 4 },
412 { "id": 2, "label": "testpkg", "parentId": 3 },
413 { "id": 1, "label": "test_1", "parentId": 2 },
414 { "id": 7, "label": "test_2", "parentId": 2 },
415 { "id": 8, "label": "test_3", "parentId": 2 },
416 { "id": 9, "label": "test_4", "parentId": 2 },
417 { "id": 10, "label": "test_5", "parentId": 2 },
418 { "id": 11, "label": "test_6", "parentId": 2 },
419 { "id": 12, "label": "test_7", "parentId": 2 },
420 { "id": 13, "label": "test_8", "parentId": 2 },
421 { "id": 14, "label": "test_9", "parentId": 2 },
422 { "id": 15, "label": "test_10", "parentId": 2 },
423 { "id": 16, "label": "test_11", "parentId": 2 },
424 { "id": 17, "label": "test_12", "parentId": 2 },
425 { "id": 18, "label": "test_13", "parentId": 2 },
426 { "id": 19, "label": "test_14", "parentId": 2 },
427 { "id": 20, "label": "test_15", "parentId": 2 },
428 { "id": 21, "label": "test_16", "parentId": 2 },
429 { "id": 22, "label": "test_17", "parentId": 2 },
430 { "id": 23, "label": "test_18", "parentId": 2 },
431 { "id": 24, "label": "test_19", "parentId": 2 },
432 { "id": 25, "label": "test_root", "parentId": 2 },
433 { "id": 26,"label": "test_out", "parentId": 2 }]
Chris Parsons943f2432021-01-19 11:36:50 -0500434}`
435
Chris Parsons1a7aca02022-04-25 22:35:15 -0400436 actualbuildStatements, actualDepsets, _ := AqueryBuildStatements([]byte(inputString))
437
Chris Parsons943f2432021-01-19 11:36:50 -0500438 expectedBuildStatements := []BuildStatement{
Usta Shrestha16ac1352022-06-22 11:01:55 -0400439 {
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400440 Command: "/bin/bash -c 'touch bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out'",
441 OutputPaths: []string{"bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out"},
442 Mnemonic: "Action",
Chris Parsons943f2432021-01-19 11:36:50 -0500443 },
444 }
445 assertBuildStatements(t, expectedBuildStatements, actualbuildStatements)
Chris Parsons1a7aca02022-04-25 22:35:15 -0400446
447 // Inputs for the action are test_{i} from 1 to 20, and test_root. These inputs
448 // are given via a deep depset, but the depset is flattened when returned as a
449 // BuildStatement slice.
Usta Shrestha16ac1352022-06-22 11:01:55 -0400450 var expectedFlattenedInputs []string
Chris Parsons1a7aca02022-04-25 22:35:15 -0400451 for i := 1; i < 20; i++ {
452 expectedFlattenedInputs = append(expectedFlattenedInputs, fmt.Sprintf("bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_%d", i))
453 }
454 expectedFlattenedInputs = append(expectedFlattenedInputs, "bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_root")
455
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400456 actualDepsetHashes := actualbuildStatements[0].InputDepsetHashes
457 actualFlattenedInputs := flattenDepsets(actualDepsetHashes, actualDepsets)
Chris Parsons1a7aca02022-04-25 22:35:15 -0400458 if !reflect.DeepEqual(actualFlattenedInputs, expectedFlattenedInputs) {
459 t.Errorf("Expected flattened inputs %v, but got %v", expectedFlattenedInputs, actualFlattenedInputs)
460 }
Chris Parsons943f2432021-01-19 11:36:50 -0500461}
462
Usta Shresthaef922252022-06-02 14:23:02 -0400463func TestBazelOutRemovalFromInputDepsets(t *testing.T) {
464 const inputString = `{
465 "artifacts": [{
466 "id": 1,
467 "pathFragmentId": 10
468 }, {
469 "id": 2,
470 "pathFragmentId": 20
471 }, {
472 "id": 3,
473 "pathFragmentId": 30
474 }, {
475 "id": 4,
476 "pathFragmentId": 40
477 }],
478 "depSetOfFiles": [{
479 "id": 1111,
480 "directArtifactIds": [3 , 4]
481 }],
482 "actions": [{
483 "targetId": 100,
484 "actionKey": "x",
485 "inputDepSetIds": [1111],
486 "mnemonic": "x",
487 "arguments": ["bogus", "command"],
488 "outputIds": [2],
489 "primaryOutputId": 1
490 }],
491 "pathFragments": [{
492 "id": 10,
493 "label": "input"
494 }, {
495 "id": 20,
496 "label": "output"
497 }, {
498 "id": 30,
499 "label": "dep1",
500 "parentId": 50
501 }, {
502 "id": 40,
503 "label": "dep2",
504 "parentId": 60
505 }, {
506 "id": 50,
507 "label": "bazel_tools",
508 "parentId": 60
509 }, {
510 "id": 60,
511 "label": ".."
512 }]
513}`
514 actualBuildStatements, actualDepsets, _ := AqueryBuildStatements([]byte(inputString))
515 if len(actualDepsets) != 1 {
516 t.Errorf("expected 1 depset but found %#v", actualDepsets)
517 return
518 }
519 dep2Found := false
520 for _, dep := range flattenDepsets([]string{actualDepsets[0].ContentHash}, actualDepsets) {
521 if dep == "../bazel_tools/dep1" {
522 t.Errorf("dependency %s expected to be removed but still exists", dep)
523 } else if dep == "../dep2" {
524 dep2Found = true
525 }
526 }
527 if !dep2Found {
528 t.Errorf("dependency ../dep2 expected but not found")
529 }
530
531 expectedBuildStatement := BuildStatement{
532 Command: "bogus command",
533 OutputPaths: []string{"output"},
534 Mnemonic: "x",
535 }
536 buildStatementFound := false
537 for _, actualBuildStatement := range actualBuildStatements {
538 if buildStatementEquals(actualBuildStatement, expectedBuildStatement) == "" {
539 buildStatementFound = true
540 break
541 }
542 }
543 if !buildStatementFound {
544 t.Errorf("expected but missing %#v in %#v", expectedBuildStatement, actualBuildStatements)
545 return
546 }
547}
548
Chris Parsonsc4fb1332021-05-18 12:31:25 -0400549func TestMiddlemenAction(t *testing.T) {
550 const inputString = `
551{
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700552 "artifacts": [
553 { "id": 1, "pathFragmentId": 1 },
554 { "id": 2, "pathFragmentId": 2 },
555 { "id": 3, "pathFragmentId": 3 },
556 { "id": 4, "pathFragmentId": 4 },
557 { "id": 5, "pathFragmentId": 5 },
558 { "id": 6, "pathFragmentId": 6 }],
559 "pathFragments": [
560 { "id": 1, "label": "middleinput_one" },
561 { "id": 2, "label": "middleinput_two" },
562 { "id": 3, "label": "middleman_artifact" },
563 { "id": 4, "label": "maininput_one" },
564 { "id": 5, "label": "maininput_two" },
565 { "id": 6, "label": "output" }],
566 "depSetOfFiles": [
567 { "id": 1, "directArtifactIds": [1, 2] },
568 { "id": 2, "directArtifactIds": [3, 4, 5] }],
Chris Parsonsc4fb1332021-05-18 12:31:25 -0400569 "actions": [{
570 "targetId": 1,
571 "actionKey": "x",
572 "mnemonic": "Middleman",
573 "arguments": ["touch", "foo"],
574 "inputDepSetIds": [1],
575 "outputIds": [3],
576 "primaryOutputId": 3
577 }, {
578 "targetId": 2,
579 "actionKey": "y",
580 "mnemonic": "Main action",
581 "arguments": ["touch", "foo"],
582 "inputDepSetIds": [2],
583 "outputIds": [6],
584 "primaryOutputId": 6
585 }]
586}`
587
Chris Parsons1a7aca02022-04-25 22:35:15 -0400588 actualBuildStatements, actualDepsets, err := AqueryBuildStatements([]byte(inputString))
Chris Parsonsc4fb1332021-05-18 12:31:25 -0400589 if err != nil {
590 t.Errorf("Unexpected error %q", err)
591 }
Chris Parsons1a7aca02022-04-25 22:35:15 -0400592 if expected := 1; len(actualBuildStatements) != expected {
593 t.Fatalf("Expected %d build statements, got %d", expected, len(actualBuildStatements))
Chris Parsonsc4fb1332021-05-18 12:31:25 -0400594 }
595
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400596 expectedDepsetFiles := [][]string{
Usta Shrestha2ccdb422022-06-02 10:19:13 -0400597 {"middleinput_one", "middleinput_two", "maininput_one", "maininput_two"},
598 {"middleinput_one", "middleinput_two"},
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400599 }
600 assertFlattenedDepsets(t, actualDepsets, expectedDepsetFiles)
601
Chris Parsons1a7aca02022-04-25 22:35:15 -0400602 bs := actualBuildStatements[0]
603 if len(bs.InputPaths) > 0 {
604 t.Errorf("Expected main action raw inputs to be empty, but got %q", bs.InputPaths)
605 }
606
Chris Parsonsc4fb1332021-05-18 12:31:25 -0400607 expectedOutputs := []string{"output"}
608 if !reflect.DeepEqual(bs.OutputPaths, expectedOutputs) {
609 t.Errorf("Expected main action outputs %q, but got %q", expectedOutputs, bs.OutputPaths)
610 }
Chris Parsons1a7aca02022-04-25 22:35:15 -0400611
Chris Parsons1a7aca02022-04-25 22:35:15 -0400612 expectedFlattenedInputs := []string{"middleinput_one", "middleinput_two", "maininput_one", "maininput_two"}
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400613 actualFlattenedInputs := flattenDepsets(bs.InputDepsetHashes, actualDepsets)
Chris Parsons1a7aca02022-04-25 22:35:15 -0400614
615 if !reflect.DeepEqual(actualFlattenedInputs, expectedFlattenedInputs) {
616 t.Errorf("Expected flattened inputs %v, but got %v", expectedFlattenedInputs, actualFlattenedInputs)
617 }
618}
619
620// Returns the contents of given depsets in concatenated post order.
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400621func flattenDepsets(depsetHashesToFlatten []string, allDepsets []AqueryDepset) []string {
622 depsetsByHash := map[string]AqueryDepset{}
Chris Parsons1a7aca02022-04-25 22:35:15 -0400623 for _, depset := range allDepsets {
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400624 depsetsByHash[depset.ContentHash] = depset
Chris Parsons1a7aca02022-04-25 22:35:15 -0400625 }
Usta Shrestha16ac1352022-06-22 11:01:55 -0400626 var result []string
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400627 for _, depsetId := range depsetHashesToFlatten {
628 result = append(result, flattenDepset(depsetId, depsetsByHash)...)
Chris Parsons1a7aca02022-04-25 22:35:15 -0400629 }
630 return result
631}
632
633// Returns the contents of a given depset in post order.
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400634func flattenDepset(depsetHashToFlatten string, allDepsets map[string]AqueryDepset) []string {
635 depset := allDepsets[depsetHashToFlatten]
Usta Shrestha16ac1352022-06-22 11:01:55 -0400636 var result []string
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400637 for _, depsetId := range depset.TransitiveDepSetHashes {
Chris Parsons1a7aca02022-04-25 22:35:15 -0400638 result = append(result, flattenDepset(depsetId, allDepsets)...)
639 }
640 result = append(result, depset.DirectArtifacts...)
641 return result
Chris Parsonsc4fb1332021-05-18 12:31:25 -0400642}
643
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400644func assertFlattenedDepsets(t *testing.T, actualDepsets []AqueryDepset, expectedDepsetFiles [][]string) {
645 t.Helper()
646 if len(actualDepsets) != len(expectedDepsetFiles) {
Sasha Smundakf10c3ac2022-06-08 11:46:31 -0700647 t.Errorf("Expected %d depsets, but got %d depsets", len(expectedDepsetFiles), len(actualDepsets))
Chris Parsons0bfb1c02022-05-12 16:43:01 -0400648 }
649 for i, actualDepset := range actualDepsets {
650 actualFlattenedInputs := flattenDepsets([]string{actualDepset.ContentHash}, actualDepsets)
651 if !reflect.DeepEqual(actualFlattenedInputs, expectedDepsetFiles[i]) {
652 t.Errorf("Expected depset files: %v, but got %v", expectedDepsetFiles[i], actualFlattenedInputs)
653 }
654 }
655}
656
Liz Kammerc49e6822021-06-08 15:04:11 -0400657func TestSimpleSymlink(t *testing.T) {
658 const inputString = `
659{
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700660 "artifacts": [
661 { "id": 1, "pathFragmentId": 3 },
662 { "id": 2, "pathFragmentId": 5 }],
Liz Kammerc49e6822021-06-08 15:04:11 -0400663 "actions": [{
664 "targetId": 1,
665 "actionKey": "x",
666 "mnemonic": "Symlink",
667 "inputDepSetIds": [1],
668 "outputIds": [2],
669 "primaryOutputId": 2
670 }],
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700671 "depSetOfFiles": [
672 { "id": 1, "directArtifactIds": [1] }],
673 "pathFragments": [
674 { "id": 1, "label": "one" },
675 { "id": 2, "label": "file_subdir", "parentId": 1 },
676 { "id": 3, "label": "file", "parentId": 2 },
677 { "id": 4, "label": "symlink_subdir", "parentId": 1 },
678 { "id": 5, "label": "symlink", "parentId": 4 }]
Liz Kammerc49e6822021-06-08 15:04:11 -0400679}`
680
Chris Parsons1a7aca02022-04-25 22:35:15 -0400681 actual, _, err := AqueryBuildStatements([]byte(inputString))
Liz Kammerc49e6822021-06-08 15:04:11 -0400682
683 if err != nil {
684 t.Errorf("Unexpected error %q", err)
685 }
686
687 expectedBuildStatements := []BuildStatement{
Usta Shrestha16ac1352022-06-22 11:01:55 -0400688 {
Liz Kammerc49e6822021-06-08 15:04:11 -0400689 Command: "mkdir -p one/symlink_subdir && " +
690 "rm -f one/symlink_subdir/symlink && " +
Liz Kammerc7737782021-11-04 10:56:13 -0400691 "ln -sf $PWD/one/file_subdir/file one/symlink_subdir/symlink",
Liz Kammerc49e6822021-06-08 15:04:11 -0400692 InputPaths: []string{"one/file_subdir/file"},
693 OutputPaths: []string{"one/symlink_subdir/symlink"},
694 SymlinkPaths: []string{"one/symlink_subdir/symlink"},
695 Mnemonic: "Symlink",
696 },
697 }
698 assertBuildStatements(t, actual, expectedBuildStatements)
699}
700
701func TestSymlinkQuotesPaths(t *testing.T) {
702 const inputString = `
703{
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700704 "artifacts": [
705 { "id": 1, "pathFragmentId": 3 },
706 { "id": 2, "pathFragmentId": 5 }],
Liz Kammerc49e6822021-06-08 15:04:11 -0400707 "actions": [{
708 "targetId": 1,
709 "actionKey": "x",
710 "mnemonic": "SolibSymlink",
711 "inputDepSetIds": [1],
712 "outputIds": [2],
713 "primaryOutputId": 2
714 }],
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700715 "depSetOfFiles": [
716 { "id": 1, "directArtifactIds": [1] }],
717 "pathFragments": [
718 { "id": 1, "label": "one" },
719 { "id": 2, "label": "file subdir", "parentId": 1 },
720 { "id": 3, "label": "file", "parentId": 2 },
721 { "id": 4, "label": "symlink subdir", "parentId": 1 },
722 { "id": 5, "label": "symlink", "parentId": 4 }]
Liz Kammerc49e6822021-06-08 15:04:11 -0400723}`
724
Chris Parsons1a7aca02022-04-25 22:35:15 -0400725 actual, _, err := AqueryBuildStatements([]byte(inputString))
Liz Kammerc49e6822021-06-08 15:04:11 -0400726
727 if err != nil {
728 t.Errorf("Unexpected error %q", err)
729 }
730
731 expectedBuildStatements := []BuildStatement{
Usta Shrestha16ac1352022-06-22 11:01:55 -0400732 {
Liz Kammerc49e6822021-06-08 15:04:11 -0400733 Command: "mkdir -p 'one/symlink subdir' && " +
734 "rm -f 'one/symlink subdir/symlink' && " +
Liz Kammerc7737782021-11-04 10:56:13 -0400735 "ln -sf $PWD/'one/file subdir/file' 'one/symlink subdir/symlink'",
Liz Kammerc49e6822021-06-08 15:04:11 -0400736 InputPaths: []string{"one/file subdir/file"},
737 OutputPaths: []string{"one/symlink subdir/symlink"},
738 SymlinkPaths: []string{"one/symlink subdir/symlink"},
739 Mnemonic: "SolibSymlink",
740 },
741 }
Liz Kammerc7737782021-11-04 10:56:13 -0400742 assertBuildStatements(t, expectedBuildStatements, actual)
Liz Kammerc49e6822021-06-08 15:04:11 -0400743}
744
745func TestSymlinkMultipleInputs(t *testing.T) {
746 const inputString = `
747{
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700748 "artifacts": [
749 { "id": 1, "pathFragmentId": 1 },
750 { "id": 2, "pathFragmentId": 2 },
751 { "id": 3, "pathFragmentId": 3 }],
Liz Kammerc49e6822021-06-08 15:04:11 -0400752 "actions": [{
753 "targetId": 1,
754 "actionKey": "x",
755 "mnemonic": "Symlink",
756 "inputDepSetIds": [1],
757 "outputIds": [3],
758 "primaryOutputId": 3
759 }],
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700760 "depSetOfFiles": [{ "id": 1, "directArtifactIds": [1,2] }],
761 "pathFragments": [
762 { "id": 1, "label": "file" },
763 { "id": 2, "label": "other_file" },
764 { "id": 3, "label": "symlink" }]
Liz Kammerc49e6822021-06-08 15:04:11 -0400765}`
766
Chris Parsons1a7aca02022-04-25 22:35:15 -0400767 _, _, err := AqueryBuildStatements([]byte(inputString))
Liz Kammerc49e6822021-06-08 15:04:11 -0400768 assertError(t, err, `Expect 1 input and 1 output to symlink action, got: input ["file" "other_file"], output ["symlink"]`)
769}
770
771func TestSymlinkMultipleOutputs(t *testing.T) {
772 const inputString = `
773{
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700774 "artifacts": [
775 { "id": 1, "pathFragmentId": 1 },
776 { "id": 2, "pathFragmentId": 2 },
777 { "id": 3, "pathFragmentId": 3 }],
Liz Kammerc49e6822021-06-08 15:04:11 -0400778 "actions": [{
779 "targetId": 1,
780 "actionKey": "x",
781 "mnemonic": "Symlink",
782 "inputDepSetIds": [1],
783 "outputIds": [2,3],
784 "primaryOutputId": 2
785 }],
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700786 "depSetOfFiles": [
787 { "id": 1, "directArtifactIds": [1] }],
788 "pathFragments": [
789 { "id": 1, "label": "file" },
790 { "id": 2, "label": "symlink" },
791 { "id": 3, "label": "other_symlink" }]
Liz Kammerc49e6822021-06-08 15:04:11 -0400792}`
793
Chris Parsons1a7aca02022-04-25 22:35:15 -0400794 _, _, err := AqueryBuildStatements([]byte(inputString))
Liz Kammerc49e6822021-06-08 15:04:11 -0400795 assertError(t, err, `Expect 1 input and 1 output to symlink action, got: input ["file"], output ["symlink" "other_symlink"]`)
796}
797
Wei Li455ba832021-11-04 22:58:12 +0000798func TestTemplateExpandActionSubstitutions(t *testing.T) {
799 const inputString = `
800{
801 "artifacts": [{
802 "id": 1,
803 "pathFragmentId": 1
804 }],
805 "actions": [{
806 "targetId": 1,
807 "actionKey": "x",
808 "mnemonic": "TemplateExpand",
809 "configurationId": 1,
810 "outputIds": [1],
811 "primaryOutputId": 1,
812 "executionPlatform": "//build/bazel/platforms:linux_x86_64",
813 "templateContent": "Test template substitutions: %token1%, %python_binary%",
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700814 "substitutions": [
815 { "key": "%token1%", "value": "abcd" },
816 { "key": "%python_binary%", "value": "python3" }]
Wei Li455ba832021-11-04 22:58:12 +0000817 }],
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700818 "pathFragments": [
819 { "id": 1, "label": "template_file" }]
Wei Li455ba832021-11-04 22:58:12 +0000820}`
821
Chris Parsons1a7aca02022-04-25 22:35:15 -0400822 actual, _, err := AqueryBuildStatements([]byte(inputString))
Wei Li455ba832021-11-04 22:58:12 +0000823
824 if err != nil {
825 t.Errorf("Unexpected error %q", err)
826 }
827
828 expectedBuildStatements := []BuildStatement{
Usta Shrestha16ac1352022-06-22 11:01:55 -0400829 {
Wei Li455ba832021-11-04 22:58:12 +0000830 Command: "/bin/bash -c 'echo \"Test template substitutions: abcd, python3\" | sed \"s/\\\\\\\\n/\\\\n/g\" > template_file && " +
831 "chmod a+x template_file'",
832 OutputPaths: []string{"template_file"},
833 Mnemonic: "TemplateExpand",
834 },
835 }
836 assertBuildStatements(t, expectedBuildStatements, actual)
837}
838
839func TestTemplateExpandActionNoOutput(t *testing.T) {
840 const inputString = `
841{
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700842 "artifacts": [
843 { "id": 1, "pathFragmentId": 1 }],
Wei Li455ba832021-11-04 22:58:12 +0000844 "actions": [{
845 "targetId": 1,
846 "actionKey": "x",
847 "mnemonic": "TemplateExpand",
848 "configurationId": 1,
849 "primaryOutputId": 1,
850 "executionPlatform": "//build/bazel/platforms:linux_x86_64",
851 "templateContent": "Test template substitutions: %token1%, %python_binary%",
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700852 "substitutions": [
853 { "key": "%token1%", "value": "abcd" },
854 { "key": "%python_binary%", "value": "python3" }]
Wei Li455ba832021-11-04 22:58:12 +0000855 }],
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700856 "pathFragments": [
857 { "id": 1, "label": "template_file" }]
Wei Li455ba832021-11-04 22:58:12 +0000858}`
859
Chris Parsons1a7aca02022-04-25 22:35:15 -0400860 _, _, err := AqueryBuildStatements([]byte(inputString))
Wei Li455ba832021-11-04 22:58:12 +0000861 assertError(t, err, `Expect 1 output to template expand action, got: output []`)
862}
863
864func TestPythonZipperActionSuccess(t *testing.T) {
865 const inputString = `
866{
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700867 "artifacts": [
868 { "id": 1, "pathFragmentId": 1 },
869 { "id": 2, "pathFragmentId": 2 },
870 { "id": 3, "pathFragmentId": 3 },
871 { "id": 4, "pathFragmentId": 4 },
872 { "id": 5, "pathFragmentId": 10 },
873 { "id": 10, "pathFragmentId": 20 }],
Wei Li455ba832021-11-04 22:58:12 +0000874 "actions": [{
875 "targetId": 1,
876 "actionKey": "x",
877 "mnemonic": "TemplateExpand",
878 "configurationId": 1,
879 "outputIds": [1],
880 "primaryOutputId": 1,
881 "executionPlatform": "//build/bazel/platforms:linux_x86_64",
882 "templateContent": "Test template substitutions: %token1%, %python_binary%",
883 "substitutions": [{
884 "key": "%token1%",
885 "value": "abcd"
886 },{
887 "key": "%python_binary%",
888 "value": "python3"
889 }]
890 },{
891 "targetId": 1,
892 "actionKey": "x",
893 "mnemonic": "PythonZipper",
894 "configurationId": 1,
895 "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"],
896 "outputIds": [2],
897 "inputDepSetIds": [1],
898 "primaryOutputId": 2
899 }],
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700900 "depSetOfFiles": [
901 { "id": 1, "directArtifactIds": [4, 3, 5] }],
902 "pathFragments": [
903 { "id": 1, "label": "python_binary" },
904 { "id": 2, "label": "python_binary.zip" },
905 { "id": 3, "label": "python_binary.py" },
906 { "id": 9, "label": ".." },
907 { "id": 8, "label": "bazel_tools", "parentId": 9 },
908 { "id": 7, "label": "tools", "parentId": 8 },
909 { "id": 6, "label": "zip", "parentId": 7 },
910 { "id": 5, "label": "zipper", "parentId": 6 },
911 { "id": 4, "label": "zipper", "parentId": 5 },
912 { "id": 16, "label": "bazel-out" },
913 { "id": 15, "label": "bazel_tools", "parentId": 16 },
914 { "id": 14, "label": "k8-fastbuild", "parentId": 15 },
915 { "id": 13, "label": "bin", "parentId": 14 },
916 { "id": 12, "label": "tools", "parentId": 13 },
917 { "id": 11, "label": "python", "parentId": 12 },
918 { "id": 10, "label": "py3wrapper.sh", "parentId": 11 },
919 { "id": 20, "label": "python_binary" }]
Wei Li455ba832021-11-04 22:58:12 +0000920}`
Chris Parsons1a7aca02022-04-25 22:35:15 -0400921 actual, _, err := AqueryBuildStatements([]byte(inputString))
Wei Li455ba832021-11-04 22:58:12 +0000922
923 if err != nil {
924 t.Errorf("Unexpected error %q", err)
925 }
926
927 expectedBuildStatements := []BuildStatement{
Usta Shrestha16ac1352022-06-22 11:01:55 -0400928 {
Wei Li455ba832021-11-04 22:58:12 +0000929 Command: "/bin/bash -c 'echo \"Test template substitutions: abcd, python3\" | sed \"s/\\\\\\\\n/\\\\n/g\" > python_binary && " +
930 "chmod a+x python_binary'",
931 InputPaths: []string{"python_binary.zip"},
932 OutputPaths: []string{"python_binary"},
933 Mnemonic: "TemplateExpand",
934 },
Usta Shrestha16ac1352022-06-22 11:01:55 -0400935 {
Wei Li455ba832021-11-04 22:58:12 +0000936 Command: "../bazel_tools/tools/zip/zipper/zipper cC python_binary.zip __main__.py=bazel-out/k8-fastbuild/bin/python_binary.temp " +
937 "__init__.py= runfiles/__main__/__init__.py= runfiles/__main__/python_binary.py=python_binary.py && " +
938 "../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 -0400939 InputPaths: []string{"python_binary.py"},
Wei Li455ba832021-11-04 22:58:12 +0000940 OutputPaths: []string{"python_binary.zip"},
941 Mnemonic: "PythonZipper",
942 },
943 }
944 assertBuildStatements(t, expectedBuildStatements, actual)
945}
946
947func TestPythonZipperActionNoInput(t *testing.T) {
948 const inputString = `
949{
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700950 "artifacts": [
951 { "id": 1, "pathFragmentId": 1 },
952 { "id": 2, "pathFragmentId": 2 }],
Wei Li455ba832021-11-04 22:58:12 +0000953 "actions": [{
954 "targetId": 1,
955 "actionKey": "x",
956 "mnemonic": "PythonZipper",
957 "configurationId": 1,
958 "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"],
959 "outputIds": [2],
960 "primaryOutputId": 2
961 }],
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700962 "pathFragments": [
963 { "id": 1, "label": "python_binary" },
964 { "id": 2, "label": "python_binary.zip" }]
Wei Li455ba832021-11-04 22:58:12 +0000965}`
Chris Parsons1a7aca02022-04-25 22:35:15 -0400966 _, _, err := AqueryBuildStatements([]byte(inputString))
Wei Li455ba832021-11-04 22:58:12 +0000967 assertError(t, err, `Expect 1+ input and 1 output to python zipper action, got: input [], output ["python_binary.zip"]`)
968}
969
970func TestPythonZipperActionNoOutput(t *testing.T) {
971 const inputString = `
972{
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700973 "artifacts": [
974 { "id": 1, "pathFragmentId": 1 },
975 { "id": 2, "pathFragmentId": 2 },
976 { "id": 3, "pathFragmentId": 3 },
977 { "id": 4, "pathFragmentId": 4 },
978 { "id": 5, "pathFragmentId": 10 }],
Wei Li455ba832021-11-04 22:58:12 +0000979 "actions": [{
980 "targetId": 1,
981 "actionKey": "x",
982 "mnemonic": "PythonZipper",
983 "configurationId": 1,
984 "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"],
985 "inputDepSetIds": [1]
986 }],
Sasha Smundake3cf1ab2022-06-30 11:36:18 -0700987 "depSetOfFiles": [
988 { "id": 1, "directArtifactIds": [4, 3, 5]}],
989 "pathFragments": [
990 { "id": 1, "label": "python_binary" },
991 { "id": 2, "label": "python_binary.zip" },
992 { "id": 3, "label": "python_binary.py" },
993 { "id": 9, "label": ".." },
994 { "id": 8, "label": "bazel_tools", "parentId": 9 },
995 { "id": 7, "label": "tools", "parentId": 8 },
996 { "id": 6, "label": "zip", "parentId": 7 },
997 { "id": 5, "label": "zipper", "parentId": 6 },
998 { "id": 4, "label": "zipper", "parentId": 5 },
999 { "id": 16, "label": "bazel-out" },
1000 { "id": 15, "label": "bazel_tools", "parentId": 16 },
1001 { "id": 14, "label": "k8-fastbuild", "parentId": 15 },
1002 { "id": 13, "label": "bin", "parentId": 14 },
1003 { "id": 12, "label": "tools", "parentId": 13 },
1004 { "id": 11, "label": "python", "parentId": 12 },
1005 { "id": 10, "label": "py3wrapper.sh", "parentId": 11 }]
Wei Li455ba832021-11-04 22:58:12 +00001006}`
Chris Parsons1a7aca02022-04-25 22:35:15 -04001007 _, _, err := AqueryBuildStatements([]byte(inputString))
Usta Shresthaef922252022-06-02 14:23:02 -04001008 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 +00001009}
1010
Chris Parsons4f069892021-01-15 12:22:41 -05001011func assertError(t *testing.T, err error, expected string) {
Liz Kammerc49e6822021-06-08 15:04:11 -04001012 t.Helper()
Chris Parsons943f2432021-01-19 11:36:50 -05001013 if err == nil {
1014 t.Errorf("expected error '%s', but got no error", expected)
1015 } else if err.Error() != expected {
Liz Kammerc49e6822021-06-08 15:04:11 -04001016 t.Errorf("expected error:\n\t'%s', but got:\n\t'%s'", expected, err.Error())
Chris Parsons4f069892021-01-15 12:22:41 -05001017 }
1018}
1019
1020// Asserts that the given actual build statements match the given expected build statements.
1021// Build statement equivalence is determined using buildStatementEquals.
1022func assertBuildStatements(t *testing.T, expected []BuildStatement, actual []BuildStatement) {
Liz Kammerc49e6822021-06-08 15:04:11 -04001023 t.Helper()
Chris Parsons4f069892021-01-15 12:22:41 -05001024 if len(expected) != len(actual) {
Liz Kammerc3192992021-11-16 17:01:11 -05001025 t.Errorf("expected %d build statements, but got %d,\n expected: %#v,\n actual: %#v",
Chris Parsons4f069892021-01-15 12:22:41 -05001026 len(expected), len(actual), expected, actual)
1027 return
1028 }
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001029 type compareFn = func(i int, j int) bool
1030 byCommand := func(slice []BuildStatement) compareFn {
1031 return func(i int, j int) bool {
1032 return slice[i].Command < slice[j].Command
Chris Parsons4f069892021-01-15 12:22:41 -05001033 }
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001034 }
1035 sort.SliceStable(expected, byCommand(expected))
1036 sort.SliceStable(actual, byCommand(actual))
1037 for i, actualStatement := range actual {
1038 expectedStatement := expected[i]
1039 if differingField := buildStatementEquals(actualStatement, expectedStatement); differingField != "" {
1040 t.Errorf("%s differs\nunexpected build statement %#v.\nexpected: %#v",
Usta Shresthaef922252022-06-02 14:23:02 -04001041 differingField, actualStatement, expectedStatement)
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001042 return
1043 }
Chris Parsons4f069892021-01-15 12:22:41 -05001044 }
1045}
1046
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001047func buildStatementEquals(first BuildStatement, second BuildStatement) string {
Chris Parsons4f069892021-01-15 12:22:41 -05001048 if first.Mnemonic != second.Mnemonic {
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001049 return "Mnemonic"
Chris Parsons4f069892021-01-15 12:22:41 -05001050 }
1051 if first.Command != second.Command {
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001052 return "Command"
Chris Parsons4f069892021-01-15 12:22:41 -05001053 }
1054 // Ordering is significant for environment variables.
1055 if !reflect.DeepEqual(first.Env, second.Env) {
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001056 return "Env"
Chris Parsons4f069892021-01-15 12:22:41 -05001057 }
1058 // Ordering is irrelevant for input and output paths, so compare sets.
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001059 if !reflect.DeepEqual(sortedStrings(first.InputPaths), sortedStrings(second.InputPaths)) {
1060 return "InputPaths"
Chris Parsons4f069892021-01-15 12:22:41 -05001061 }
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001062 if !reflect.DeepEqual(sortedStrings(first.OutputPaths), sortedStrings(second.OutputPaths)) {
1063 return "OutputPaths"
Chris Parsons4f069892021-01-15 12:22:41 -05001064 }
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001065 if !reflect.DeepEqual(sortedStrings(first.SymlinkPaths), sortedStrings(second.SymlinkPaths)) {
1066 return "SymlinkPaths"
Liz Kammerc49e6822021-06-08 15:04:11 -04001067 }
1068 if first.Depfile != second.Depfile {
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001069 return "Depfile"
Liz Kammerc49e6822021-06-08 15:04:11 -04001070 }
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001071 return ""
Chris Parsons4f069892021-01-15 12:22:41 -05001072}
1073
Usta Shrestha1c4a3ea2022-06-23 16:09:32 -04001074func sortedStrings(stringSlice []string) []string {
1075 sorted := make([]string, len(stringSlice))
1076 copy(sorted, stringSlice)
1077 sort.Strings(sorted)
1078 return sorted
Chris Parsons4f069892021-01-15 12:22:41 -05001079}