blob: 3f1a5e119c6187a3b1fca962726dd0b1777c5c8c [file] [log] [blame]
Dan Willemsen18490112018-05-25 16:30:04 -07001// Copyright 2018 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 main
16
17import (
18 "fmt"
19 "io/ioutil"
20 "os"
21 "path/filepath"
22 "testing"
23
24 "android/soong/ui/build/paths"
25)
26
27var tmpDir string
28var origPATH string
29
30func TestMain(m *testing.M) {
31 os.Exit(func() int {
32 var err error
33 tmpDir, err = ioutil.TempDir("", "interposer_test")
34 if err != nil {
35 panic(err)
36 }
37 defer os.RemoveAll(tmpDir)
38
39 origPATH = os.Getenv("PATH")
40 err = os.Setenv("PATH", "")
41 if err != nil {
42 panic(err)
43 }
44
45 return m.Run()
46 }())
47}
48
49func setup(t *testing.T) string {
50 f, err := ioutil.TempFile(tmpDir, "interposer")
51 if err != nil {
52 t.Fatal(err)
53 }
54 defer f.Close()
55
56 err = ioutil.WriteFile(f.Name()+"_origpath", []byte(origPATH), 0666)
57 if err != nil {
58 t.Fatal(err)
59 }
60 return f.Name()
61}
62
63func TestInterposer(t *testing.T) {
Colin Cross323dc602020-09-18 14:25:31 -070064 t.Parallel()
Dan Willemsen18490112018-05-25 16:30:04 -070065 interposer := setup(t)
66
67 logConfig := func(name string) paths.PathConfig {
68 if name == "true" {
69 return paths.PathConfig{
70 Log: false,
71 Error: false,
72 }
73 } else if name == "path_interposer_test_not_allowed" {
74 return paths.PathConfig{
75 Log: false,
76 Error: true,
77 }
78 }
79 return paths.PathConfig{
80 Log: true,
81 Error: false,
82 }
83 }
84
85 testCases := []struct {
86 name string
87 args []string
88
89 exitCode int
90 err error
91 logEntry string
92 }{
93 {
94 name: "direct call",
95 args: []string{interposer},
96
97 exitCode: 1,
98 err: usage,
99 },
100 {
101 name: "relative call",
102 args: []string{filepath.Base(interposer)},
103
104 exitCode: 1,
105 err: usage,
106 },
107 {
108 name: "true",
109 args: []string{"/my/path/true"},
110 },
111 {
112 name: "relative true",
113 args: []string{"true"},
114 },
115 {
116 name: "exit code",
117 args: []string{"bash", "-c", "exit 42"},
118
119 exitCode: 42,
120 logEntry: "bash",
121 },
122 {
123 name: "signal",
124 args: []string{"bash", "-c", "kill -9 $$"},
125
126 exitCode: 137,
127 logEntry: "bash",
128 },
129 {
130 name: "does not exist",
131 args: []string{"path_interposer_test_does_not_exist"},
132
133 exitCode: 1,
134 err: fmt.Errorf(`exec: "path_interposer_test_does_not_exist": executable file not found in $PATH`),
135 logEntry: "path_interposer_test_does_not_exist",
136 },
137 {
138 name: "not allowed",
139 args: []string{"path_interposer_test_not_allowed"},
140
141 exitCode: 1,
142 err: fmt.Errorf(`"path_interposer_test_not_allowed" is not allowed to be used. See https://android.googlesource.com/platform/build/+/master/Changes.md#PATH_Tools for more information.`),
143 logEntry: "path_interposer_test_not_allowed",
144 },
145 }
146
147 for _, testCase := range testCases {
148 t.Run(testCase.name, func(t *testing.T) {
149 logged := false
150 logFunc := func(logSocket string, entry *paths.LogEntry, done chan interface{}) {
151 defer close(done)
152
153 logged = true
154 if entry.Basename != testCase.logEntry {
155 t.Errorf("unexpected log entry:\nwant: %q\n got: %q", testCase.logEntry, entry.Basename)
156 }
157 }
158
159 exitCode, err := Main(ioutil.Discard, ioutil.Discard, interposer, testCase.args, mainOpts{
160 sendLog: logFunc,
161 config: logConfig,
162 })
163
164 errstr := func(err error) string {
165 if err == nil {
166 return ""
167 }
168 return err.Error()
169 }
170 if errstr(testCase.err) != errstr(err) {
171 t.Errorf("unexpected error:\nwant: %v\n got: %v", testCase.err, err)
172 }
173 if testCase.exitCode != exitCode {
174 t.Errorf("expected exit code %d, got %d", testCase.exitCode, exitCode)
175 }
176 if !logged && testCase.logEntry != "" {
177 t.Errorf("no log entry, but expected %q", testCase.logEntry)
178 }
179 })
180 }
181}
182
183func TestMissingPath(t *testing.T) {
Colin Cross323dc602020-09-18 14:25:31 -0700184 t.Parallel()
Dan Willemsen18490112018-05-25 16:30:04 -0700185 interposer := setup(t)
186 err := os.Remove(interposer + "_origpath")
187 if err != nil {
Colin Crossfe5a3b72018-07-13 21:25:15 -0700188 t.Fatal("Failed to remove:", err)
Dan Willemsen18490112018-05-25 16:30:04 -0700189 }
190
191 exitCode, err := Main(ioutil.Discard, ioutil.Discard, interposer, []string{"true"}, mainOpts{})
192 if err != usage {
193 t.Errorf("Unexpected error:\n got: %v\nwant: %v", err, usage)
194 }
195 if exitCode != 1 {
196 t.Errorf("expected exit code %d, got %d", 1, exitCode)
197 }
198}