blob: 1bd6e67539d117b717958044b26f97e1ecb8cbdd [file] [log] [blame]
Chris Parsons4f069892021-01-15 12:22:41 -05001// Copyright 2020 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package bazel
16
17import (
18 "fmt"
19 "reflect"
20 "testing"
21)
22
23func TestAqueryMultiArchGenrule(t *testing.T) {
24 // This input string is retrieved from a real build of bionic-related genrules.
25 const inputString = `
26{
27 "artifacts": [{
28 "id": 1,
29 "pathFragmentId": 1
30 }, {
31 "id": 2,
32 "pathFragmentId": 6
33 }, {
34 "id": 3,
35 "pathFragmentId": 8
36 }, {
37 "id": 4,
38 "pathFragmentId": 12
39 }, {
40 "id": 5,
41 "pathFragmentId": 19
42 }, {
43 "id": 6,
44 "pathFragmentId": 20
45 }, {
46 "id": 7,
47 "pathFragmentId": 21
48 }],
49 "actions": [{
50 "targetId": 1,
51 "actionKey": "ab53f6ecbdc2ee8cb8812613b63205464f1f5083f6dca87081a0a398c0f1ecf7",
52 "mnemonic": "Genrule",
53 "configurationId": 1,
54 "arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py arm ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-arm.S"],
55 "environmentVariables": [{
56 "key": "PATH",
57 "value": "/bin:/usr/bin:/usr/local/bin"
58 }],
59 "inputDepSetIds": [1],
60 "outputIds": [4],
61 "primaryOutputId": 4
62 }, {
63 "targetId": 2,
64 "actionKey": "9f4309ce165dac458498cb92811c18b0b7919782cc37b82a42d2141b8cc90826",
65 "mnemonic": "Genrule",
66 "configurationId": 1,
67 "arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py x86 ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-x86.S"],
68 "environmentVariables": [{
69 "key": "PATH",
70 "value": "/bin:/usr/bin:/usr/local/bin"
71 }],
72 "inputDepSetIds": [2],
73 "outputIds": [5],
74 "primaryOutputId": 5
75 }, {
76 "targetId": 3,
77 "actionKey": "50d6c586103ebeed3a218195540bcc30d329464eae36377eb82f8ce7c36ac342",
78 "mnemonic": "Genrule",
79 "configurationId": 1,
80 "arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py x86_64 ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-x86_64.S"],
81 "environmentVariables": [{
82 "key": "PATH",
83 "value": "/bin:/usr/bin:/usr/local/bin"
84 }],
85 "inputDepSetIds": [3],
86 "outputIds": [6],
87 "primaryOutputId": 6
88 }, {
89 "targetId": 4,
90 "actionKey": "f30cbe442f5216f4223cf16a39112cad4ec56f31f49290d85cff587e48647ffa",
91 "mnemonic": "Genrule",
92 "configurationId": 1,
93 "arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py arm64 ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-arm64.S"],
94 "environmentVariables": [{
95 "key": "PATH",
96 "value": "/bin:/usr/bin:/usr/local/bin"
97 }],
98 "inputDepSetIds": [4],
99 "outputIds": [7],
100 "primaryOutputId": 7
101 }],
102 "targets": [{
103 "id": 1,
104 "label": "@sourceroot//bionic/libc:syscalls-arm",
105 "ruleClassId": 1
106 }, {
107 "id": 2,
108 "label": "@sourceroot//bionic/libc:syscalls-x86",
109 "ruleClassId": 1
110 }, {
111 "id": 3,
112 "label": "@sourceroot//bionic/libc:syscalls-x86_64",
113 "ruleClassId": 1
114 }, {
115 "id": 4,
116 "label": "@sourceroot//bionic/libc:syscalls-arm64",
117 "ruleClassId": 1
118 }],
119 "depSetOfFiles": [{
120 "id": 1,
121 "directArtifactIds": [1, 2, 3]
122 }, {
123 "id": 2,
124 "directArtifactIds": [1, 2, 3]
125 }, {
126 "id": 3,
127 "directArtifactIds": [1, 2, 3]
128 }, {
129 "id": 4,
130 "directArtifactIds": [1, 2, 3]
131 }],
132 "configuration": [{
133 "id": 1,
134 "mnemonic": "k8-fastbuild",
135 "platformName": "k8",
136 "checksum": "485c362832c178e367d972177f68e69e0981e51e67ef1c160944473db53fe046"
137 }],
138 "ruleClasses": [{
139 "id": 1,
140 "name": "genrule"
141 }],
142 "pathFragments": [{
143 "id": 5,
144 "label": ".."
145 }, {
146 "id": 4,
147 "label": "sourceroot",
148 "parentId": 5
149 }, {
150 "id": 3,
151 "label": "bionic",
152 "parentId": 4
153 }, {
154 "id": 2,
155 "label": "libc",
156 "parentId": 3
157 }, {
158 "id": 1,
159 "label": "SYSCALLS.TXT",
160 "parentId": 2
161 }, {
162 "id": 7,
163 "label": "tools",
164 "parentId": 2
165 }, {
166 "id": 6,
167 "label": "gensyscalls.py",
168 "parentId": 7
169 }, {
170 "id": 11,
171 "label": "bazel_tools",
172 "parentId": 5
173 }, {
174 "id": 10,
175 "label": "tools",
176 "parentId": 11
177 }, {
178 "id": 9,
179 "label": "genrule",
180 "parentId": 10
181 }, {
182 "id": 8,
183 "label": "genrule-setup.sh",
184 "parentId": 9
185 }, {
186 "id": 18,
187 "label": "bazel-out"
188 }, {
189 "id": 17,
190 "label": "sourceroot",
191 "parentId": 18
192 }, {
193 "id": 16,
194 "label": "k8-fastbuild",
195 "parentId": 17
196 }, {
197 "id": 15,
198 "label": "bin",
199 "parentId": 16
200 }, {
201 "id": 14,
202 "label": "bionic",
203 "parentId": 15
204 }, {
205 "id": 13,
206 "label": "libc",
207 "parentId": 14
208 }, {
209 "id": 12,
210 "label": "syscalls-arm.S",
211 "parentId": 13
212 }, {
213 "id": 19,
214 "label": "syscalls-x86.S",
215 "parentId": 13
216 }, {
217 "id": 20,
218 "label": "syscalls-x86_64.S",
219 "parentId": 13
220 }, {
221 "id": 21,
222 "label": "syscalls-arm64.S",
223 "parentId": 13
224 }]
225}`
226 actualbuildStatements, _ := AqueryBuildStatements([]byte(inputString))
227 expectedBuildStatements := []BuildStatement{}
228 for _, arch := range []string{"arm", "arm64", "x86", "x86_64"} {
229 expectedBuildStatements = append(expectedBuildStatements,
230 BuildStatement{
231 Command: fmt.Sprintf(
232 "/bin/bash -c 'source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py %s ../sourceroot/bionic/libc/SYSCALLS.TXT > bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-%s.S'",
233 arch, arch),
234 OutputPaths: []string{
235 fmt.Sprintf("bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-%s.S", arch),
236 },
237 InputPaths: []string{
238 "../sourceroot/bionic/libc/SYSCALLS.TXT",
239 "../sourceroot/bionic/libc/tools/gensyscalls.py",
240 "../bazel_tools/tools/genrule/genrule-setup.sh",
241 },
242 Env: []KeyValuePair{
243 KeyValuePair{Key: "PATH", Value: "/bin:/usr/bin:/usr/local/bin"},
244 },
245 Mnemonic: "Genrule",
246 })
247 }
248 assertBuildStatements(t, expectedBuildStatements, actualbuildStatements)
249}
250
251func TestInvalidOutputId(t *testing.T) {
252 const inputString = `
253{
254 "artifacts": [{
255 "id": 1,
256 "pathFragmentId": 1
257 }, {
258 "id": 2,
259 "pathFragmentId": 2
260 }],
261 "actions": [{
262 "targetId": 1,
263 "actionKey": "x",
264 "mnemonic": "x",
265 "arguments": ["touch", "foo"],
266 "inputDepSetIds": [1],
267 "outputIds": [3],
268 "primaryOutputId": 3
269 }],
270 "depSetOfFiles": [{
271 "id": 1,
272 "directArtifactIds": [1, 2]
273 }],
274 "pathFragments": [{
275 "id": 1,
276 "label": "one"
277 }, {
278 "id": 2,
279 "label": "two"
280 }]
281}`
282
283 _, err := AqueryBuildStatements([]byte(inputString))
284 assertError(t, err, "undefined outputId 3")
285}
286
287func TestInvalidInputDepsetId(t *testing.T) {
288 const inputString = `
289{
290 "artifacts": [{
291 "id": 1,
292 "pathFragmentId": 1
293 }, {
294 "id": 2,
295 "pathFragmentId": 2
296 }],
297 "actions": [{
298 "targetId": 1,
299 "actionKey": "x",
300 "mnemonic": "x",
301 "arguments": ["touch", "foo"],
302 "inputDepSetIds": [2],
303 "outputIds": [1],
304 "primaryOutputId": 1
305 }],
306 "depSetOfFiles": [{
307 "id": 1,
308 "directArtifactIds": [1, 2]
309 }],
310 "pathFragments": [{
311 "id": 1,
312 "label": "one"
313 }, {
314 "id": 2,
315 "label": "two"
316 }]
317}`
318
319 _, err := AqueryBuildStatements([]byte(inputString))
320 assertError(t, err, "undefined input depsetId 2")
321}
322
323func TestInvalidInputArtifactId(t *testing.T) {
324 const inputString = `
325{
326 "artifacts": [{
327 "id": 1,
328 "pathFragmentId": 1
329 }, {
330 "id": 2,
331 "pathFragmentId": 2
332 }],
333 "actions": [{
334 "targetId": 1,
335 "actionKey": "x",
336 "mnemonic": "x",
337 "arguments": ["touch", "foo"],
338 "inputDepSetIds": [1],
339 "outputIds": [1],
340 "primaryOutputId": 1
341 }],
342 "depSetOfFiles": [{
343 "id": 1,
344 "directArtifactIds": [1, 3]
345 }],
346 "pathFragments": [{
347 "id": 1,
348 "label": "one"
349 }, {
350 "id": 2,
351 "label": "two"
352 }]
353}`
354
355 _, err := AqueryBuildStatements([]byte(inputString))
356 assertError(t, err, "undefined input artifactId 3")
357}
358
359func TestInvalidPathFragmentId(t *testing.T) {
360 const inputString = `
361{
362 "artifacts": [{
363 "id": 1,
364 "pathFragmentId": 1
365 }, {
366 "id": 2,
367 "pathFragmentId": 2
368 }],
369 "actions": [{
370 "targetId": 1,
371 "actionKey": "x",
372 "mnemonic": "x",
373 "arguments": ["touch", "foo"],
374 "inputDepSetIds": [1],
375 "outputIds": [1],
376 "primaryOutputId": 1
377 }],
378 "depSetOfFiles": [{
379 "id": 1,
380 "directArtifactIds": [1, 2]
381 }],
382 "pathFragments": [{
383 "id": 1,
384 "label": "one"
385 }, {
386 "id": 2,
387 "label": "two",
388 "parentId": 3
389 }]
390}`
391
392 _, err := AqueryBuildStatements([]byte(inputString))
393 assertError(t, err, "undefined path fragment id 3")
394}
395
396func assertError(t *testing.T, err error, expected string) {
397 if err == nil || err.Error() != expected {
398 t.Errorf("expected error '%s', but got: %s", expected, err)
399 }
400}
401
402// Asserts that the given actual build statements match the given expected build statements.
403// Build statement equivalence is determined using buildStatementEquals.
404func assertBuildStatements(t *testing.T, expected []BuildStatement, actual []BuildStatement) {
405 if len(expected) != len(actual) {
406 t.Errorf("expected %d build statements, but got %d,\n expected: %s,\n actual: %s",
407 len(expected), len(actual), expected, actual)
408 return
409 }
410ACTUAL_LOOP:
411 for _, actualStatement := range actual {
412 for _, expectedStatement := range expected {
413 if buildStatementEquals(actualStatement, expectedStatement) {
414 continue ACTUAL_LOOP
415 }
416 }
417 t.Errorf("unexpected build statement %s.\n expected: %s",
418 actualStatement, expected)
419 return
420 }
421}
422
423func buildStatementEquals(first BuildStatement, second BuildStatement) bool {
424 if first.Mnemonic != second.Mnemonic {
425 return false
426 }
427 if first.Command != second.Command {
428 return false
429 }
430 // Ordering is significant for environment variables.
431 if !reflect.DeepEqual(first.Env, second.Env) {
432 return false
433 }
434 // Ordering is irrelevant for input and output paths, so compare sets.
435 if !reflect.DeepEqual(stringSet(first.InputPaths), stringSet(second.InputPaths)) {
436 return false
437 }
438 if !reflect.DeepEqual(stringSet(first.OutputPaths), stringSet(second.OutputPaths)) {
439 return false
440 }
441 return true
442}
443
444func stringSet(stringSlice []string) map[string]struct{} {
445 stringMap := make(map[string]struct{})
446 for _, s := range stringSlice {
447 stringMap[s] = struct{}{}
448 }
449 return stringMap
450}