blob: c89d6231fc24f8f6bb633967e95d3f3a53dcedb6 [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) {
64 interposer := setup(t)
65
66 logConfig := func(name string) paths.PathConfig {
67 if name == "true" {
68 return paths.PathConfig{
69 Log: false,
70 Error: false,
71 }
72 } else if name == "path_interposer_test_not_allowed" {
73 return paths.PathConfig{
74 Log: false,
75 Error: true,
76 }
77 }
78 return paths.PathConfig{
79 Log: true,
80 Error: false,
81 }
82 }
83
84 testCases := []struct {
85 name string
86 args []string
87
88 exitCode int
89 err error
90 logEntry string
91 }{
92 {
93 name: "direct call",
94 args: []string{interposer},
95
96 exitCode: 1,
97 err: usage,
98 },
99 {
100 name: "relative call",
101 args: []string{filepath.Base(interposer)},
102
103 exitCode: 1,
104 err: usage,
105 },
106 {
107 name: "true",
108 args: []string{"/my/path/true"},
109 },
110 {
111 name: "relative true",
112 args: []string{"true"},
113 },
114 {
115 name: "exit code",
116 args: []string{"bash", "-c", "exit 42"},
117
118 exitCode: 42,
119 logEntry: "bash",
120 },
121 {
122 name: "signal",
123 args: []string{"bash", "-c", "kill -9 $$"},
124
125 exitCode: 137,
126 logEntry: "bash",
127 },
128 {
129 name: "does not exist",
130 args: []string{"path_interposer_test_does_not_exist"},
131
132 exitCode: 1,
133 err: fmt.Errorf(`exec: "path_interposer_test_does_not_exist": executable file not found in $PATH`),
134 logEntry: "path_interposer_test_does_not_exist",
135 },
136 {
137 name: "not allowed",
138 args: []string{"path_interposer_test_not_allowed"},
139
140 exitCode: 1,
141 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.`),
142 logEntry: "path_interposer_test_not_allowed",
143 },
144 }
145
146 for _, testCase := range testCases {
147 t.Run(testCase.name, func(t *testing.T) {
148 logged := false
149 logFunc := func(logSocket string, entry *paths.LogEntry, done chan interface{}) {
150 defer close(done)
151
152 logged = true
153 if entry.Basename != testCase.logEntry {
154 t.Errorf("unexpected log entry:\nwant: %q\n got: %q", testCase.logEntry, entry.Basename)
155 }
156 }
157
158 exitCode, err := Main(ioutil.Discard, ioutil.Discard, interposer, testCase.args, mainOpts{
159 sendLog: logFunc,
160 config: logConfig,
161 })
162
163 errstr := func(err error) string {
164 if err == nil {
165 return ""
166 }
167 return err.Error()
168 }
169 if errstr(testCase.err) != errstr(err) {
170 t.Errorf("unexpected error:\nwant: %v\n got: %v", testCase.err, err)
171 }
172 if testCase.exitCode != exitCode {
173 t.Errorf("expected exit code %d, got %d", testCase.exitCode, exitCode)
174 }
175 if !logged && testCase.logEntry != "" {
176 t.Errorf("no log entry, but expected %q", testCase.logEntry)
177 }
178 })
179 }
180}
181
182func TestMissingPath(t *testing.T) {
183 interposer := setup(t)
184 err := os.Remove(interposer + "_origpath")
185 if err != nil {
Colin Crossfe5a3b72018-07-13 21:25:15 -0700186 t.Fatal("Failed to remove:", err)
Dan Willemsen18490112018-05-25 16:30:04 -0700187 }
188
189 exitCode, err := Main(ioutil.Discard, ioutil.Discard, interposer, []string{"true"}, mainOpts{})
190 if err != usage {
191 t.Errorf("Unexpected error:\n got: %v\nwant: %v", err, usage)
192 }
193 if exitCode != 1 {
194 t.Errorf("expected exit code %d, got %d", 1, exitCode)
195 }
196}