c31929962b
Bazel run shell actions begin `bin/bash -c <command>`, without escaping, the command can be treated as an argument to `bin/bash`. Test: build/bazel/mixed_droid.sh Change-Id: I423cb393da2e6ac97448ec77b2596f12670dfd31
1431 lines
32 KiB
Go
1431 lines
32 KiB
Go
// Copyright 2020 Google Inc. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package bazel
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
func TestAqueryMultiArchGenrule(t *testing.T) {
|
|
// This input string is retrieved from a real build of bionic-related genrules.
|
|
const inputString = `
|
|
{
|
|
"artifacts": [{
|
|
"id": 1,
|
|
"pathFragmentId": 1
|
|
}, {
|
|
"id": 2,
|
|
"pathFragmentId": 6
|
|
}, {
|
|
"id": 3,
|
|
"pathFragmentId": 8
|
|
}, {
|
|
"id": 4,
|
|
"pathFragmentId": 12
|
|
}, {
|
|
"id": 5,
|
|
"pathFragmentId": 19
|
|
}, {
|
|
"id": 6,
|
|
"pathFragmentId": 20
|
|
}, {
|
|
"id": 7,
|
|
"pathFragmentId": 21
|
|
}],
|
|
"actions": [{
|
|
"targetId": 1,
|
|
"actionKey": "ab53f6ecbdc2ee8cb8812613b63205464f1f5083f6dca87081a0a398c0f1ecf7",
|
|
"mnemonic": "Genrule",
|
|
"configurationId": 1,
|
|
"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"],
|
|
"environmentVariables": [{
|
|
"key": "PATH",
|
|
"value": "/bin:/usr/bin:/usr/local/bin"
|
|
}],
|
|
"inputDepSetIds": [1],
|
|
"outputIds": [4],
|
|
"primaryOutputId": 4
|
|
}, {
|
|
"targetId": 2,
|
|
"actionKey": "9f4309ce165dac458498cb92811c18b0b7919782cc37b82a42d2141b8cc90826",
|
|
"mnemonic": "Genrule",
|
|
"configurationId": 1,
|
|
"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"],
|
|
"environmentVariables": [{
|
|
"key": "PATH",
|
|
"value": "/bin:/usr/bin:/usr/local/bin"
|
|
}],
|
|
"inputDepSetIds": [2],
|
|
"outputIds": [5],
|
|
"primaryOutputId": 5
|
|
}, {
|
|
"targetId": 3,
|
|
"actionKey": "50d6c586103ebeed3a218195540bcc30d329464eae36377eb82f8ce7c36ac342",
|
|
"mnemonic": "Genrule",
|
|
"configurationId": 1,
|
|
"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"],
|
|
"environmentVariables": [{
|
|
"key": "PATH",
|
|
"value": "/bin:/usr/bin:/usr/local/bin"
|
|
}],
|
|
"inputDepSetIds": [3],
|
|
"outputIds": [6],
|
|
"primaryOutputId": 6
|
|
}, {
|
|
"targetId": 4,
|
|
"actionKey": "f30cbe442f5216f4223cf16a39112cad4ec56f31f49290d85cff587e48647ffa",
|
|
"mnemonic": "Genrule",
|
|
"configurationId": 1,
|
|
"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"],
|
|
"environmentVariables": [{
|
|
"key": "PATH",
|
|
"value": "/bin:/usr/bin:/usr/local/bin"
|
|
}],
|
|
"inputDepSetIds": [4],
|
|
"outputIds": [7],
|
|
"primaryOutputId": 7
|
|
}],
|
|
"targets": [{
|
|
"id": 1,
|
|
"label": "@sourceroot//bionic/libc:syscalls-arm",
|
|
"ruleClassId": 1
|
|
}, {
|
|
"id": 2,
|
|
"label": "@sourceroot//bionic/libc:syscalls-x86",
|
|
"ruleClassId": 1
|
|
}, {
|
|
"id": 3,
|
|
"label": "@sourceroot//bionic/libc:syscalls-x86_64",
|
|
"ruleClassId": 1
|
|
}, {
|
|
"id": 4,
|
|
"label": "@sourceroot//bionic/libc:syscalls-arm64",
|
|
"ruleClassId": 1
|
|
}],
|
|
"depSetOfFiles": [{
|
|
"id": 1,
|
|
"directArtifactIds": [1, 2, 3]
|
|
}, {
|
|
"id": 2,
|
|
"directArtifactIds": [1, 2, 3]
|
|
}, {
|
|
"id": 3,
|
|
"directArtifactIds": [1, 2, 3]
|
|
}, {
|
|
"id": 4,
|
|
"directArtifactIds": [1, 2, 3]
|
|
}],
|
|
"configuration": [{
|
|
"id": 1,
|
|
"mnemonic": "k8-fastbuild",
|
|
"platformName": "k8",
|
|
"checksum": "485c362832c178e367d972177f68e69e0981e51e67ef1c160944473db53fe046"
|
|
}],
|
|
"ruleClasses": [{
|
|
"id": 1,
|
|
"name": "genrule"
|
|
}],
|
|
"pathFragments": [{
|
|
"id": 5,
|
|
"label": ".."
|
|
}, {
|
|
"id": 4,
|
|
"label": "sourceroot",
|
|
"parentId": 5
|
|
}, {
|
|
"id": 3,
|
|
"label": "bionic",
|
|
"parentId": 4
|
|
}, {
|
|
"id": 2,
|
|
"label": "libc",
|
|
"parentId": 3
|
|
}, {
|
|
"id": 1,
|
|
"label": "SYSCALLS.TXT",
|
|
"parentId": 2
|
|
}, {
|
|
"id": 7,
|
|
"label": "tools",
|
|
"parentId": 2
|
|
}, {
|
|
"id": 6,
|
|
"label": "gensyscalls.py",
|
|
"parentId": 7
|
|
}, {
|
|
"id": 11,
|
|
"label": "bazel_tools",
|
|
"parentId": 5
|
|
}, {
|
|
"id": 10,
|
|
"label": "tools",
|
|
"parentId": 11
|
|
}, {
|
|
"id": 9,
|
|
"label": "genrule",
|
|
"parentId": 10
|
|
}, {
|
|
"id": 8,
|
|
"label": "genrule-setup.sh",
|
|
"parentId": 9
|
|
}, {
|
|
"id": 18,
|
|
"label": "bazel-out"
|
|
}, {
|
|
"id": 17,
|
|
"label": "sourceroot",
|
|
"parentId": 18
|
|
}, {
|
|
"id": 16,
|
|
"label": "k8-fastbuild",
|
|
"parentId": 17
|
|
}, {
|
|
"id": 15,
|
|
"label": "bin",
|
|
"parentId": 16
|
|
}, {
|
|
"id": 14,
|
|
"label": "bionic",
|
|
"parentId": 15
|
|
}, {
|
|
"id": 13,
|
|
"label": "libc",
|
|
"parentId": 14
|
|
}, {
|
|
"id": 12,
|
|
"label": "syscalls-arm.S",
|
|
"parentId": 13
|
|
}, {
|
|
"id": 19,
|
|
"label": "syscalls-x86.S",
|
|
"parentId": 13
|
|
}, {
|
|
"id": 20,
|
|
"label": "syscalls-x86_64.S",
|
|
"parentId": 13
|
|
}, {
|
|
"id": 21,
|
|
"label": "syscalls-arm64.S",
|
|
"parentId": 13
|
|
}]
|
|
}`
|
|
actualbuildStatements, _ := AqueryBuildStatements([]byte(inputString))
|
|
expectedBuildStatements := []BuildStatement{}
|
|
for _, arch := range []string{"arm", "arm64", "x86", "x86_64"} {
|
|
expectedBuildStatements = append(expectedBuildStatements,
|
|
BuildStatement{
|
|
Command: fmt.Sprintf(
|
|
"/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'",
|
|
arch, arch),
|
|
OutputPaths: []string{
|
|
fmt.Sprintf("bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-%s.S", arch),
|
|
},
|
|
InputPaths: []string{
|
|
"../sourceroot/bionic/libc/SYSCALLS.TXT",
|
|
"../sourceroot/bionic/libc/tools/gensyscalls.py",
|
|
"../bazel_tools/tools/genrule/genrule-setup.sh",
|
|
},
|
|
Env: []KeyValuePair{
|
|
KeyValuePair{Key: "PATH", Value: "/bin:/usr/bin:/usr/local/bin"},
|
|
},
|
|
Mnemonic: "Genrule",
|
|
})
|
|
}
|
|
assertBuildStatements(t, expectedBuildStatements, actualbuildStatements)
|
|
}
|
|
|
|
func TestInvalidOutputId(t *testing.T) {
|
|
const inputString = `
|
|
{
|
|
"artifacts": [{
|
|
"id": 1,
|
|
"pathFragmentId": 1
|
|
}, {
|
|
"id": 2,
|
|
"pathFragmentId": 2
|
|
}],
|
|
"actions": [{
|
|
"targetId": 1,
|
|
"actionKey": "x",
|
|
"mnemonic": "x",
|
|
"arguments": ["touch", "foo"],
|
|
"inputDepSetIds": [1],
|
|
"outputIds": [3],
|
|
"primaryOutputId": 3
|
|
}],
|
|
"depSetOfFiles": [{
|
|
"id": 1,
|
|
"directArtifactIds": [1, 2]
|
|
}],
|
|
"pathFragments": [{
|
|
"id": 1,
|
|
"label": "one"
|
|
}, {
|
|
"id": 2,
|
|
"label": "two"
|
|
}]
|
|
}`
|
|
|
|
_, err := AqueryBuildStatements([]byte(inputString))
|
|
assertError(t, err, "undefined outputId 3")
|
|
}
|
|
|
|
func TestInvalidInputDepsetId(t *testing.T) {
|
|
const inputString = `
|
|
{
|
|
"artifacts": [{
|
|
"id": 1,
|
|
"pathFragmentId": 1
|
|
}, {
|
|
"id": 2,
|
|
"pathFragmentId": 2
|
|
}],
|
|
"actions": [{
|
|
"targetId": 1,
|
|
"actionKey": "x",
|
|
"mnemonic": "x",
|
|
"arguments": ["touch", "foo"],
|
|
"inputDepSetIds": [2],
|
|
"outputIds": [1],
|
|
"primaryOutputId": 1
|
|
}],
|
|
"depSetOfFiles": [{
|
|
"id": 1,
|
|
"directArtifactIds": [1, 2]
|
|
}],
|
|
"pathFragments": [{
|
|
"id": 1,
|
|
"label": "one"
|
|
}, {
|
|
"id": 2,
|
|
"label": "two"
|
|
}]
|
|
}`
|
|
|
|
_, err := AqueryBuildStatements([]byte(inputString))
|
|
assertError(t, err, "undefined input depsetId 2")
|
|
}
|
|
|
|
func TestInvalidInputArtifactId(t *testing.T) {
|
|
const inputString = `
|
|
{
|
|
"artifacts": [{
|
|
"id": 1,
|
|
"pathFragmentId": 1
|
|
}, {
|
|
"id": 2,
|
|
"pathFragmentId": 2
|
|
}],
|
|
"actions": [{
|
|
"targetId": 1,
|
|
"actionKey": "x",
|
|
"mnemonic": "x",
|
|
"arguments": ["touch", "foo"],
|
|
"inputDepSetIds": [1],
|
|
"outputIds": [1],
|
|
"primaryOutputId": 1
|
|
}],
|
|
"depSetOfFiles": [{
|
|
"id": 1,
|
|
"directArtifactIds": [1, 3]
|
|
}],
|
|
"pathFragments": [{
|
|
"id": 1,
|
|
"label": "one"
|
|
}, {
|
|
"id": 2,
|
|
"label": "two"
|
|
}]
|
|
}`
|
|
|
|
_, err := AqueryBuildStatements([]byte(inputString))
|
|
assertError(t, err, "undefined input artifactId 3")
|
|
}
|
|
|
|
func TestInvalidPathFragmentId(t *testing.T) {
|
|
const inputString = `
|
|
{
|
|
"artifacts": [{
|
|
"id": 1,
|
|
"pathFragmentId": 1
|
|
}, {
|
|
"id": 2,
|
|
"pathFragmentId": 2
|
|
}],
|
|
"actions": [{
|
|
"targetId": 1,
|
|
"actionKey": "x",
|
|
"mnemonic": "x",
|
|
"arguments": ["touch", "foo"],
|
|
"inputDepSetIds": [1],
|
|
"outputIds": [1],
|
|
"primaryOutputId": 1
|
|
}],
|
|
"depSetOfFiles": [{
|
|
"id": 1,
|
|
"directArtifactIds": [1, 2]
|
|
}],
|
|
"pathFragments": [{
|
|
"id": 1,
|
|
"label": "one"
|
|
}, {
|
|
"id": 2,
|
|
"label": "two",
|
|
"parentId": 3
|
|
}]
|
|
}`
|
|
|
|
_, err := AqueryBuildStatements([]byte(inputString))
|
|
assertError(t, err, "undefined path fragment id 3")
|
|
}
|
|
|
|
func TestDepfiles(t *testing.T) {
|
|
const inputString = `
|
|
{
|
|
"artifacts": [{
|
|
"id": 1,
|
|
"pathFragmentId": 1
|
|
}, {
|
|
"id": 2,
|
|
"pathFragmentId": 2
|
|
}, {
|
|
"id": 3,
|
|
"pathFragmentId": 3
|
|
}],
|
|
"actions": [{
|
|
"targetId": 1,
|
|
"actionKey": "x",
|
|
"mnemonic": "x",
|
|
"arguments": ["touch", "foo"],
|
|
"inputDepSetIds": [1],
|
|
"outputIds": [2, 3],
|
|
"primaryOutputId": 2
|
|
}],
|
|
"depSetOfFiles": [{
|
|
"id": 1,
|
|
"directArtifactIds": [1, 2, 3]
|
|
}],
|
|
"pathFragments": [{
|
|
"id": 1,
|
|
"label": "one"
|
|
}, {
|
|
"id": 2,
|
|
"label": "two"
|
|
}, {
|
|
"id": 3,
|
|
"label": "two.d"
|
|
}]
|
|
}`
|
|
|
|
actual, err := AqueryBuildStatements([]byte(inputString))
|
|
if err != nil {
|
|
t.Errorf("Unexpected error %q", err)
|
|
}
|
|
if expected := 1; len(actual) != expected {
|
|
t.Fatalf("Expected %d build statements, got %d", expected, len(actual))
|
|
}
|
|
|
|
bs := actual[0]
|
|
expectedDepfile := "two.d"
|
|
if bs.Depfile == nil {
|
|
t.Errorf("Expected depfile %q, but there was none found", expectedDepfile)
|
|
} else if *bs.Depfile != expectedDepfile {
|
|
t.Errorf("Expected depfile %q, but got %q", expectedDepfile, *bs.Depfile)
|
|
}
|
|
}
|
|
|
|
func TestMultipleDepfiles(t *testing.T) {
|
|
const inputString = `
|
|
{
|
|
"artifacts": [{
|
|
"id": 1,
|
|
"pathFragmentId": 1
|
|
}, {
|
|
"id": 2,
|
|
"pathFragmentId": 2
|
|
}, {
|
|
"id": 3,
|
|
"pathFragmentId": 3
|
|
}, {
|
|
"id": 4,
|
|
"pathFragmentId": 4
|
|
}],
|
|
"actions": [{
|
|
"targetId": 1,
|
|
"actionKey": "x",
|
|
"mnemonic": "x",
|
|
"arguments": ["touch", "foo"],
|
|
"inputDepSetIds": [1],
|
|
"outputIds": [2,3,4],
|
|
"primaryOutputId": 2
|
|
}],
|
|
"depSetOfFiles": [{
|
|
"id": 1,
|
|
"directArtifactIds": [1, 2, 3, 4]
|
|
}],
|
|
"pathFragments": [{
|
|
"id": 1,
|
|
"label": "one"
|
|
}, {
|
|
"id": 2,
|
|
"label": "two"
|
|
}, {
|
|
"id": 3,
|
|
"label": "two.d"
|
|
}, {
|
|
"id": 4,
|
|
"label": "other.d"
|
|
}]
|
|
}`
|
|
|
|
_, err := AqueryBuildStatements([]byte(inputString))
|
|
assertError(t, err, `found multiple potential depfiles "two.d", "other.d"`)
|
|
}
|
|
|
|
func TestTransitiveInputDepsets(t *testing.T) {
|
|
// The input aquery for this test comes from a proof-of-concept starlark rule which registers
|
|
// a single action with many inputs given via a deep depset.
|
|
const inputString = `
|
|
{
|
|
"artifacts": [{
|
|
"id": 1,
|
|
"pathFragmentId": 1
|
|
}, {
|
|
"id": 2,
|
|
"pathFragmentId": 7
|
|
}, {
|
|
"id": 3,
|
|
"pathFragmentId": 8
|
|
}, {
|
|
"id": 4,
|
|
"pathFragmentId": 9
|
|
}, {
|
|
"id": 5,
|
|
"pathFragmentId": 10
|
|
}, {
|
|
"id": 6,
|
|
"pathFragmentId": 11
|
|
}, {
|
|
"id": 7,
|
|
"pathFragmentId": 12
|
|
}, {
|
|
"id": 8,
|
|
"pathFragmentId": 13
|
|
}, {
|
|
"id": 9,
|
|
"pathFragmentId": 14
|
|
}, {
|
|
"id": 10,
|
|
"pathFragmentId": 15
|
|
}, {
|
|
"id": 11,
|
|
"pathFragmentId": 16
|
|
}, {
|
|
"id": 12,
|
|
"pathFragmentId": 17
|
|
}, {
|
|
"id": 13,
|
|
"pathFragmentId": 18
|
|
}, {
|
|
"id": 14,
|
|
"pathFragmentId": 19
|
|
}, {
|
|
"id": 15,
|
|
"pathFragmentId": 20
|
|
}, {
|
|
"id": 16,
|
|
"pathFragmentId": 21
|
|
}, {
|
|
"id": 17,
|
|
"pathFragmentId": 22
|
|
}, {
|
|
"id": 18,
|
|
"pathFragmentId": 23
|
|
}, {
|
|
"id": 19,
|
|
"pathFragmentId": 24
|
|
}, {
|
|
"id": 20,
|
|
"pathFragmentId": 25
|
|
}, {
|
|
"id": 21,
|
|
"pathFragmentId": 26
|
|
}],
|
|
"actions": [{
|
|
"targetId": 1,
|
|
"actionKey": "3b826d17fadbbbcd8313e456b90ec47c078c438088891dd45b4adbcd8889dc50",
|
|
"mnemonic": "Action",
|
|
"configurationId": 1,
|
|
"arguments": ["/bin/bash", "-c", "touch bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out"],
|
|
"inputDepSetIds": [1],
|
|
"outputIds": [21],
|
|
"primaryOutputId": 21
|
|
}],
|
|
"depSetOfFiles": [{
|
|
"id": 3,
|
|
"directArtifactIds": [1, 2, 3, 4, 5]
|
|
}, {
|
|
"id": 4,
|
|
"directArtifactIds": [6, 7, 8, 9, 10]
|
|
}, {
|
|
"id": 2,
|
|
"transitiveDepSetIds": [3, 4],
|
|
"directArtifactIds": [11, 12, 13, 14, 15]
|
|
}, {
|
|
"id": 5,
|
|
"directArtifactIds": [16, 17, 18, 19]
|
|
}, {
|
|
"id": 1,
|
|
"transitiveDepSetIds": [2, 5],
|
|
"directArtifactIds": [20]
|
|
}],
|
|
"pathFragments": [{
|
|
"id": 6,
|
|
"label": "bazel-out"
|
|
}, {
|
|
"id": 5,
|
|
"label": "sourceroot",
|
|
"parentId": 6
|
|
}, {
|
|
"id": 4,
|
|
"label": "k8-fastbuild",
|
|
"parentId": 5
|
|
}, {
|
|
"id": 3,
|
|
"label": "bin",
|
|
"parentId": 4
|
|
}, {
|
|
"id": 2,
|
|
"label": "testpkg",
|
|
"parentId": 3
|
|
}, {
|
|
"id": 1,
|
|
"label": "test_1",
|
|
"parentId": 2
|
|
}, {
|
|
"id": 7,
|
|
"label": "test_2",
|
|
"parentId": 2
|
|
}, {
|
|
"id": 8,
|
|
"label": "test_3",
|
|
"parentId": 2
|
|
}, {
|
|
"id": 9,
|
|
"label": "test_4",
|
|
"parentId": 2
|
|
}, {
|
|
"id": 10,
|
|
"label": "test_5",
|
|
"parentId": 2
|
|
}, {
|
|
"id": 11,
|
|
"label": "test_6",
|
|
"parentId": 2
|
|
}, {
|
|
"id": 12,
|
|
"label": "test_7",
|
|
"parentId": 2
|
|
}, {
|
|
"id": 13,
|
|
"label": "test_8",
|
|
"parentId": 2
|
|
}, {
|
|
"id": 14,
|
|
"label": "test_9",
|
|
"parentId": 2
|
|
}, {
|
|
"id": 15,
|
|
"label": "test_10",
|
|
"parentId": 2
|
|
}, {
|
|
"id": 16,
|
|
"label": "test_11",
|
|
"parentId": 2
|
|
}, {
|
|
"id": 17,
|
|
"label": "test_12",
|
|
"parentId": 2
|
|
}, {
|
|
"id": 18,
|
|
"label": "test_13",
|
|
"parentId": 2
|
|
}, {
|
|
"id": 19,
|
|
"label": "test_14",
|
|
"parentId": 2
|
|
}, {
|
|
"id": 20,
|
|
"label": "test_15",
|
|
"parentId": 2
|
|
}, {
|
|
"id": 21,
|
|
"label": "test_16",
|
|
"parentId": 2
|
|
}, {
|
|
"id": 22,
|
|
"label": "test_17",
|
|
"parentId": 2
|
|
}, {
|
|
"id": 23,
|
|
"label": "test_18",
|
|
"parentId": 2
|
|
}, {
|
|
"id": 24,
|
|
"label": "test_19",
|
|
"parentId": 2
|
|
}, {
|
|
"id": 25,
|
|
"label": "test_root",
|
|
"parentId": 2
|
|
}, {
|
|
"id": 26,
|
|
"label": "test_out",
|
|
"parentId": 2
|
|
}]
|
|
}`
|
|
|
|
actualbuildStatements, _ := AqueryBuildStatements([]byte(inputString))
|
|
// Inputs for the action are test_{i} from 1 to 20, and test_root. These inputs
|
|
// are given via a deep depset, but the depset is flattened when returned as a
|
|
// BuildStatement slice.
|
|
inputPaths := []string{"bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_root"}
|
|
for i := 1; i < 20; i++ {
|
|
inputPaths = append(inputPaths, fmt.Sprintf("bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_%d", i))
|
|
}
|
|
expectedBuildStatements := []BuildStatement{
|
|
BuildStatement{
|
|
Command: "/bin/bash -c 'touch bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out'",
|
|
OutputPaths: []string{"bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out"},
|
|
InputPaths: inputPaths,
|
|
Mnemonic: "Action",
|
|
},
|
|
}
|
|
assertBuildStatements(t, expectedBuildStatements, actualbuildStatements)
|
|
}
|
|
|
|
func TestMiddlemenAction(t *testing.T) {
|
|
const inputString = `
|
|
{
|
|
"artifacts": [{
|
|
"id": 1,
|
|
"pathFragmentId": 1
|
|
}, {
|
|
"id": 2,
|
|
"pathFragmentId": 2
|
|
}, {
|
|
"id": 3,
|
|
"pathFragmentId": 3
|
|
}, {
|
|
"id": 4,
|
|
"pathFragmentId": 4
|
|
}, {
|
|
"id": 5,
|
|
"pathFragmentId": 5
|
|
}, {
|
|
"id": 6,
|
|
"pathFragmentId": 6
|
|
}],
|
|
"pathFragments": [{
|
|
"id": 1,
|
|
"label": "middleinput_one"
|
|
}, {
|
|
"id": 2,
|
|
"label": "middleinput_two"
|
|
}, {
|
|
"id": 3,
|
|
"label": "middleman_artifact"
|
|
}, {
|
|
"id": 4,
|
|
"label": "maininput_one"
|
|
}, {
|
|
"id": 5,
|
|
"label": "maininput_two"
|
|
}, {
|
|
"id": 6,
|
|
"label": "output"
|
|
}],
|
|
"depSetOfFiles": [{
|
|
"id": 1,
|
|
"directArtifactIds": [1, 2]
|
|
}, {
|
|
"id": 2,
|
|
"directArtifactIds": [3, 4, 5]
|
|
}],
|
|
"actions": [{
|
|
"targetId": 1,
|
|
"actionKey": "x",
|
|
"mnemonic": "Middleman",
|
|
"arguments": ["touch", "foo"],
|
|
"inputDepSetIds": [1],
|
|
"outputIds": [3],
|
|
"primaryOutputId": 3
|
|
}, {
|
|
"targetId": 2,
|
|
"actionKey": "y",
|
|
"mnemonic": "Main action",
|
|
"arguments": ["touch", "foo"],
|
|
"inputDepSetIds": [2],
|
|
"outputIds": [6],
|
|
"primaryOutputId": 6
|
|
}]
|
|
}`
|
|
|
|
actual, err := AqueryBuildStatements([]byte(inputString))
|
|
if err != nil {
|
|
t.Errorf("Unexpected error %q", err)
|
|
}
|
|
if expected := 1; len(actual) != expected {
|
|
t.Fatalf("Expected %d build statements, got %d", expected, len(actual))
|
|
}
|
|
|
|
bs := actual[0]
|
|
expectedInputs := []string{"middleinput_one", "middleinput_two", "maininput_one", "maininput_two"}
|
|
if !reflect.DeepEqual(bs.InputPaths, expectedInputs) {
|
|
t.Errorf("Expected main action inputs %q, but got %q", expectedInputs, bs.InputPaths)
|
|
}
|
|
|
|
expectedOutputs := []string{"output"}
|
|
if !reflect.DeepEqual(bs.OutputPaths, expectedOutputs) {
|
|
t.Errorf("Expected main action outputs %q, but got %q", expectedOutputs, bs.OutputPaths)
|
|
}
|
|
}
|
|
|
|
func TestSimpleSymlink(t *testing.T) {
|
|
const inputString = `
|
|
{
|
|
"artifacts": [{
|
|
"id": 1,
|
|
"pathFragmentId": 3
|
|
}, {
|
|
"id": 2,
|
|
"pathFragmentId": 5
|
|
}],
|
|
"actions": [{
|
|
"targetId": 1,
|
|
"actionKey": "x",
|
|
"mnemonic": "Symlink",
|
|
"inputDepSetIds": [1],
|
|
"outputIds": [2],
|
|
"primaryOutputId": 2
|
|
}],
|
|
"depSetOfFiles": [{
|
|
"id": 1,
|
|
"directArtifactIds": [1]
|
|
}],
|
|
"pathFragments": [{
|
|
"id": 1,
|
|
"label": "one"
|
|
}, {
|
|
"id": 2,
|
|
"label": "file_subdir",
|
|
"parentId": 1
|
|
}, {
|
|
"id": 3,
|
|
"label": "file",
|
|
"parentId": 2
|
|
}, {
|
|
"id": 4,
|
|
"label": "symlink_subdir",
|
|
"parentId": 1
|
|
}, {
|
|
"id": 5,
|
|
"label": "symlink",
|
|
"parentId": 4
|
|
}]
|
|
}`
|
|
|
|
actual, err := AqueryBuildStatements([]byte(inputString))
|
|
|
|
if err != nil {
|
|
t.Errorf("Unexpected error %q", err)
|
|
}
|
|
|
|
expectedBuildStatements := []BuildStatement{
|
|
BuildStatement{
|
|
Command: "mkdir -p one/symlink_subdir && " +
|
|
"rm -f one/symlink_subdir/symlink && " +
|
|
"ln -sf $PWD/one/file_subdir/file one/symlink_subdir/symlink",
|
|
InputPaths: []string{"one/file_subdir/file"},
|
|
OutputPaths: []string{"one/symlink_subdir/symlink"},
|
|
SymlinkPaths: []string{"one/symlink_subdir/symlink"},
|
|
Mnemonic: "Symlink",
|
|
},
|
|
}
|
|
assertBuildStatements(t, actual, expectedBuildStatements)
|
|
}
|
|
|
|
func TestSymlinkQuotesPaths(t *testing.T) {
|
|
const inputString = `
|
|
{
|
|
"artifacts": [{
|
|
"id": 1,
|
|
"pathFragmentId": 3
|
|
}, {
|
|
"id": 2,
|
|
"pathFragmentId": 5
|
|
}],
|
|
"actions": [{
|
|
"targetId": 1,
|
|
"actionKey": "x",
|
|
"mnemonic": "SolibSymlink",
|
|
"inputDepSetIds": [1],
|
|
"outputIds": [2],
|
|
"primaryOutputId": 2
|
|
}],
|
|
"depSetOfFiles": [{
|
|
"id": 1,
|
|
"directArtifactIds": [1]
|
|
}],
|
|
"pathFragments": [{
|
|
"id": 1,
|
|
"label": "one"
|
|
}, {
|
|
"id": 2,
|
|
"label": "file subdir",
|
|
"parentId": 1
|
|
}, {
|
|
"id": 3,
|
|
"label": "file",
|
|
"parentId": 2
|
|
}, {
|
|
"id": 4,
|
|
"label": "symlink subdir",
|
|
"parentId": 1
|
|
}, {
|
|
"id": 5,
|
|
"label": "symlink",
|
|
"parentId": 4
|
|
}]
|
|
}`
|
|
|
|
actual, err := AqueryBuildStatements([]byte(inputString))
|
|
|
|
if err != nil {
|
|
t.Errorf("Unexpected error %q", err)
|
|
}
|
|
|
|
expectedBuildStatements := []BuildStatement{
|
|
BuildStatement{
|
|
Command: "mkdir -p 'one/symlink subdir' && " +
|
|
"rm -f 'one/symlink subdir/symlink' && " +
|
|
"ln -sf $PWD/'one/file subdir/file' 'one/symlink subdir/symlink'",
|
|
InputPaths: []string{"one/file subdir/file"},
|
|
OutputPaths: []string{"one/symlink subdir/symlink"},
|
|
SymlinkPaths: []string{"one/symlink subdir/symlink"},
|
|
Mnemonic: "SolibSymlink",
|
|
},
|
|
}
|
|
assertBuildStatements(t, expectedBuildStatements, actual)
|
|
}
|
|
|
|
func TestSymlinkMultipleInputs(t *testing.T) {
|
|
const inputString = `
|
|
{
|
|
"artifacts": [{
|
|
"id": 1,
|
|
"pathFragmentId": 1
|
|
}, {
|
|
"id": 2,
|
|
"pathFragmentId": 2
|
|
}, {
|
|
"id": 3,
|
|
"pathFragmentId": 3
|
|
}],
|
|
"actions": [{
|
|
"targetId": 1,
|
|
"actionKey": "x",
|
|
"mnemonic": "Symlink",
|
|
"inputDepSetIds": [1],
|
|
"outputIds": [3],
|
|
"primaryOutputId": 3
|
|
}],
|
|
"depSetOfFiles": [{
|
|
"id": 1,
|
|
"directArtifactIds": [1,2]
|
|
}],
|
|
"pathFragments": [{
|
|
"id": 1,
|
|
"label": "file"
|
|
}, {
|
|
"id": 2,
|
|
"label": "other_file"
|
|
}, {
|
|
"id": 3,
|
|
"label": "symlink"
|
|
}]
|
|
}`
|
|
|
|
_, err := AqueryBuildStatements([]byte(inputString))
|
|
assertError(t, err, `Expect 1 input and 1 output to symlink action, got: input ["file" "other_file"], output ["symlink"]`)
|
|
}
|
|
|
|
func TestSymlinkMultipleOutputs(t *testing.T) {
|
|
const inputString = `
|
|
{
|
|
"artifacts": [{
|
|
"id": 1,
|
|
"pathFragmentId": 1
|
|
}, {
|
|
"id": 2,
|
|
"pathFragmentId": 2
|
|
}, {
|
|
"id": 3,
|
|
"pathFragmentId": 3
|
|
}],
|
|
"actions": [{
|
|
"targetId": 1,
|
|
"actionKey": "x",
|
|
"mnemonic": "Symlink",
|
|
"inputDepSetIds": [1],
|
|
"outputIds": [2,3],
|
|
"primaryOutputId": 2
|
|
}],
|
|
"depSetOfFiles": [{
|
|
"id": 1,
|
|
"directArtifactIds": [1]
|
|
}],
|
|
"pathFragments": [{
|
|
"id": 1,
|
|
"label": "file"
|
|
}, {
|
|
"id": 2,
|
|
"label": "symlink"
|
|
}, {
|
|
"id": 3,
|
|
"label": "other_symlink"
|
|
}]
|
|
}`
|
|
|
|
_, err := AqueryBuildStatements([]byte(inputString))
|
|
assertError(t, err, `Expect 1 input and 1 output to symlink action, got: input ["file"], output ["symlink" "other_symlink"]`)
|
|
}
|
|
|
|
func TestTemplateExpandActionSubstitutions(t *testing.T) {
|
|
const inputString = `
|
|
{
|
|
"artifacts": [{
|
|
"id": 1,
|
|
"pathFragmentId": 1
|
|
}],
|
|
"actions": [{
|
|
"targetId": 1,
|
|
"actionKey": "x",
|
|
"mnemonic": "TemplateExpand",
|
|
"configurationId": 1,
|
|
"outputIds": [1],
|
|
"primaryOutputId": 1,
|
|
"executionPlatform": "//build/bazel/platforms:linux_x86_64",
|
|
"templateContent": "Test template substitutions: %token1%, %python_binary%",
|
|
"substitutions": [{
|
|
"key": "%token1%",
|
|
"value": "abcd"
|
|
},{
|
|
"key": "%python_binary%",
|
|
"value": "python3"
|
|
}]
|
|
}],
|
|
"pathFragments": [{
|
|
"id": 1,
|
|
"label": "template_file"
|
|
}]
|
|
}`
|
|
|
|
actual, err := AqueryBuildStatements([]byte(inputString))
|
|
|
|
if err != nil {
|
|
t.Errorf("Unexpected error %q", err)
|
|
}
|
|
|
|
expectedBuildStatements := []BuildStatement{
|
|
BuildStatement{
|
|
Command: "/bin/bash -c 'echo \"Test template substitutions: abcd, python3\" | sed \"s/\\\\\\\\n/\\\\n/g\" > template_file && " +
|
|
"chmod a+x template_file'",
|
|
OutputPaths: []string{"template_file"},
|
|
Mnemonic: "TemplateExpand",
|
|
},
|
|
}
|
|
assertBuildStatements(t, expectedBuildStatements, actual)
|
|
}
|
|
|
|
func TestTemplateExpandActionNoOutput(t *testing.T) {
|
|
const inputString = `
|
|
{
|
|
"artifacts": [{
|
|
"id": 1,
|
|
"pathFragmentId": 1
|
|
}],
|
|
"actions": [{
|
|
"targetId": 1,
|
|
"actionKey": "x",
|
|
"mnemonic": "TemplateExpand",
|
|
"configurationId": 1,
|
|
"primaryOutputId": 1,
|
|
"executionPlatform": "//build/bazel/platforms:linux_x86_64",
|
|
"templateContent": "Test template substitutions: %token1%, %python_binary%",
|
|
"substitutions": [{
|
|
"key": "%token1%",
|
|
"value": "abcd"
|
|
},{
|
|
"key": "%python_binary%",
|
|
"value": "python3"
|
|
}]
|
|
}],
|
|
"pathFragments": [{
|
|
"id": 1,
|
|
"label": "template_file"
|
|
}]
|
|
}`
|
|
|
|
_, err := AqueryBuildStatements([]byte(inputString))
|
|
assertError(t, err, `Expect 1 output to template expand action, got: output []`)
|
|
}
|
|
|
|
func TestPythonZipperActionSuccess(t *testing.T) {
|
|
const inputString = `
|
|
{
|
|
"artifacts": [{
|
|
"id": 1,
|
|
"pathFragmentId": 1
|
|
},{
|
|
"id": 2,
|
|
"pathFragmentId": 2
|
|
},{
|
|
"id": 3,
|
|
"pathFragmentId": 3
|
|
},{
|
|
"id": 4,
|
|
"pathFragmentId": 4
|
|
},{
|
|
"id": 5,
|
|
"pathFragmentId": 10
|
|
},{
|
|
"id": 10,
|
|
"pathFragmentId": 20
|
|
}],
|
|
"actions": [{
|
|
"targetId": 1,
|
|
"actionKey": "x",
|
|
"mnemonic": "TemplateExpand",
|
|
"configurationId": 1,
|
|
"outputIds": [1],
|
|
"primaryOutputId": 1,
|
|
"executionPlatform": "//build/bazel/platforms:linux_x86_64",
|
|
"templateContent": "Test template substitutions: %token1%, %python_binary%",
|
|
"substitutions": [{
|
|
"key": "%token1%",
|
|
"value": "abcd"
|
|
},{
|
|
"key": "%python_binary%",
|
|
"value": "python3"
|
|
}]
|
|
},{
|
|
"targetId": 1,
|
|
"actionKey": "x",
|
|
"mnemonic": "PythonZipper",
|
|
"configurationId": 1,
|
|
"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"],
|
|
"outputIds": [2],
|
|
"inputDepSetIds": [1],
|
|
"primaryOutputId": 2
|
|
}],
|
|
"depSetOfFiles": [{
|
|
"id": 1,
|
|
"directArtifactIds": [4, 3, 5]
|
|
}],
|
|
"pathFragments": [{
|
|
"id": 1,
|
|
"label": "python_binary"
|
|
},{
|
|
"id": 2,
|
|
"label": "python_binary.zip"
|
|
},{
|
|
"id": 3,
|
|
"label": "python_binary.py"
|
|
},{
|
|
"id": 9,
|
|
"label": ".."
|
|
}, {
|
|
"id": 8,
|
|
"label": "bazel_tools",
|
|
"parentId": 9
|
|
}, {
|
|
"id": 7,
|
|
"label": "tools",
|
|
"parentId": 8
|
|
}, {
|
|
"id": 6,
|
|
"label": "zip",
|
|
"parentId": 7
|
|
}, {
|
|
"id": 5,
|
|
"label": "zipper",
|
|
"parentId": 6
|
|
}, {
|
|
"id": 4,
|
|
"label": "zipper",
|
|
"parentId": 5
|
|
},{
|
|
"id": 16,
|
|
"label": "bazel-out"
|
|
},{
|
|
"id": 15,
|
|
"label": "bazel_tools",
|
|
"parentId": 16
|
|
}, {
|
|
"id": 14,
|
|
"label": "k8-fastbuild",
|
|
"parentId": 15
|
|
}, {
|
|
"id": 13,
|
|
"label": "bin",
|
|
"parentId": 14
|
|
}, {
|
|
"id": 12,
|
|
"label": "tools",
|
|
"parentId": 13
|
|
}, {
|
|
"id": 11,
|
|
"label": "python",
|
|
"parentId": 12
|
|
}, {
|
|
"id": 10,
|
|
"label": "py3wrapper.sh",
|
|
"parentId": 11
|
|
},{
|
|
"id": 20,
|
|
"label": "python_binary"
|
|
}]
|
|
}`
|
|
actual, err := AqueryBuildStatements([]byte(inputString))
|
|
|
|
if err != nil {
|
|
t.Errorf("Unexpected error %q", err)
|
|
}
|
|
|
|
expectedBuildStatements := []BuildStatement{
|
|
BuildStatement{
|
|
Command: "/bin/bash -c 'echo \"Test template substitutions: abcd, python3\" | sed \"s/\\\\\\\\n/\\\\n/g\" > python_binary && " +
|
|
"chmod a+x python_binary'",
|
|
InputPaths: []string{"python_binary.zip"},
|
|
OutputPaths: []string{"python_binary"},
|
|
Mnemonic: "TemplateExpand",
|
|
},
|
|
BuildStatement{
|
|
Command: "../bazel_tools/tools/zip/zipper/zipper cC python_binary.zip __main__.py=bazel-out/k8-fastbuild/bin/python_binary.temp " +
|
|
"__init__.py= runfiles/__main__/__init__.py= runfiles/__main__/python_binary.py=python_binary.py && " +
|
|
"../bazel_tools/tools/zip/zipper/zipper x python_binary.zip -d python_binary.runfiles && ln -sf runfiles/__main__ python_binary.runfiles",
|
|
InputPaths: []string{"../bazel_tools/tools/zip/zipper/zipper", "python_binary.py"},
|
|
OutputPaths: []string{"python_binary.zip"},
|
|
Mnemonic: "PythonZipper",
|
|
},
|
|
}
|
|
assertBuildStatements(t, expectedBuildStatements, actual)
|
|
}
|
|
|
|
func TestPythonZipperActionNoInput(t *testing.T) {
|
|
const inputString = `
|
|
{
|
|
"artifacts": [{
|
|
"id": 1,
|
|
"pathFragmentId": 1
|
|
},{
|
|
"id": 2,
|
|
"pathFragmentId": 2
|
|
}],
|
|
"actions": [{
|
|
"targetId": 1,
|
|
"actionKey": "x",
|
|
"mnemonic": "PythonZipper",
|
|
"configurationId": 1,
|
|
"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"],
|
|
"outputIds": [2],
|
|
"primaryOutputId": 2
|
|
}],
|
|
"pathFragments": [{
|
|
"id": 1,
|
|
"label": "python_binary"
|
|
},{
|
|
"id": 2,
|
|
"label": "python_binary.zip"
|
|
}]
|
|
}`
|
|
_, err := AqueryBuildStatements([]byte(inputString))
|
|
assertError(t, err, `Expect 1+ input and 1 output to python zipper action, got: input [], output ["python_binary.zip"]`)
|
|
}
|
|
|
|
func TestPythonZipperActionNoOutput(t *testing.T) {
|
|
const inputString = `
|
|
{
|
|
"artifacts": [{
|
|
"id": 1,
|
|
"pathFragmentId": 1
|
|
},{
|
|
"id": 2,
|
|
"pathFragmentId": 2
|
|
},{
|
|
"id": 3,
|
|
"pathFragmentId": 3
|
|
},{
|
|
"id": 4,
|
|
"pathFragmentId": 4
|
|
},{
|
|
"id": 5,
|
|
"pathFragmentId": 10
|
|
}],
|
|
"actions": [{
|
|
"targetId": 1,
|
|
"actionKey": "x",
|
|
"mnemonic": "PythonZipper",
|
|
"configurationId": 1,
|
|
"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"],
|
|
"inputDepSetIds": [1]
|
|
}],
|
|
"depSetOfFiles": [{
|
|
"id": 1,
|
|
"directArtifactIds": [4, 3, 5]
|
|
}],
|
|
"pathFragments": [{
|
|
"id": 1,
|
|
"label": "python_binary"
|
|
},{
|
|
"id": 2,
|
|
"label": "python_binary.zip"
|
|
},{
|
|
"id": 3,
|
|
"label": "python_binary.py"
|
|
},{
|
|
"id": 9,
|
|
"label": ".."
|
|
}, {
|
|
"id": 8,
|
|
"label": "bazel_tools",
|
|
"parentId": 9
|
|
}, {
|
|
"id": 7,
|
|
"label": "tools",
|
|
"parentId": 8
|
|
}, {
|
|
"id": 6,
|
|
"label": "zip",
|
|
"parentId": 7
|
|
}, {
|
|
"id": 5,
|
|
"label": "zipper",
|
|
"parentId": 6
|
|
}, {
|
|
"id": 4,
|
|
"label": "zipper",
|
|
"parentId": 5
|
|
},{
|
|
"id": 16,
|
|
"label": "bazel-out"
|
|
},{
|
|
"id": 15,
|
|
"label": "bazel_tools",
|
|
"parentId": 16
|
|
}, {
|
|
"id": 14,
|
|
"label": "k8-fastbuild",
|
|
"parentId": 15
|
|
}, {
|
|
"id": 13,
|
|
"label": "bin",
|
|
"parentId": 14
|
|
}, {
|
|
"id": 12,
|
|
"label": "tools",
|
|
"parentId": 13
|
|
}, {
|
|
"id": 11,
|
|
"label": "python",
|
|
"parentId": 12
|
|
}, {
|
|
"id": 10,
|
|
"label": "py3wrapper.sh",
|
|
"parentId": 11
|
|
}]
|
|
}`
|
|
_, err := AqueryBuildStatements([]byte(inputString))
|
|
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 []`)
|
|
}
|
|
|
|
func assertError(t *testing.T, err error, expected string) {
|
|
t.Helper()
|
|
if err == nil {
|
|
t.Errorf("expected error '%s', but got no error", expected)
|
|
} else if err.Error() != expected {
|
|
t.Errorf("expected error:\n\t'%s', but got:\n\t'%s'", expected, err.Error())
|
|
}
|
|
}
|
|
|
|
// Asserts that the given actual build statements match the given expected build statements.
|
|
// Build statement equivalence is determined using buildStatementEquals.
|
|
func assertBuildStatements(t *testing.T, expected []BuildStatement, actual []BuildStatement) {
|
|
t.Helper()
|
|
if len(expected) != len(actual) {
|
|
t.Errorf("expected %d build statements, but got %d,\n expected: %#v,\n actual: %#v",
|
|
len(expected), len(actual), expected, actual)
|
|
return
|
|
}
|
|
ACTUAL_LOOP:
|
|
for _, actualStatement := range actual {
|
|
for _, expectedStatement := range expected {
|
|
if buildStatementEquals(actualStatement, expectedStatement) {
|
|
continue ACTUAL_LOOP
|
|
}
|
|
}
|
|
t.Errorf("unexpected build statement %#v.\n expected: %#v",
|
|
actualStatement, expected)
|
|
return
|
|
}
|
|
}
|
|
|
|
func buildStatementEquals(first BuildStatement, second BuildStatement) bool {
|
|
if first.Mnemonic != second.Mnemonic {
|
|
return false
|
|
}
|
|
if first.Command != second.Command {
|
|
return false
|
|
}
|
|
// Ordering is significant for environment variables.
|
|
if !reflect.DeepEqual(first.Env, second.Env) {
|
|
return false
|
|
}
|
|
// Ordering is irrelevant for input and output paths, so compare sets.
|
|
if !reflect.DeepEqual(stringSet(first.InputPaths), stringSet(second.InputPaths)) {
|
|
return false
|
|
}
|
|
if !reflect.DeepEqual(stringSet(first.OutputPaths), stringSet(second.OutputPaths)) {
|
|
return false
|
|
}
|
|
if !reflect.DeepEqual(stringSet(first.SymlinkPaths), stringSet(second.SymlinkPaths)) {
|
|
return false
|
|
}
|
|
if first.Depfile != second.Depfile {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func stringSet(stringSlice []string) map[string]struct{} {
|
|
stringMap := make(map[string]struct{})
|
|
for _, s := range stringSlice {
|
|
stringMap[s] = struct{}{}
|
|
}
|
|
return stringMap
|
|
}
|