1*333d2b36SAndroid Build Coastguard Worker// Copyright 2018 Google Inc. All rights reserved. 2*333d2b36SAndroid Build Coastguard Worker// 3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*333d2b36SAndroid Build Coastguard Worker// 7*333d2b36SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*333d2b36SAndroid Build Coastguard Worker// 9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*333d2b36SAndroid Build Coastguard Worker// limitations under the License. 14*333d2b36SAndroid Build Coastguard Worker 15*333d2b36SAndroid Build Coastguard Workerpackage main 16*333d2b36SAndroid Build Coastguard Worker 17*333d2b36SAndroid Build Coastguard Workerimport ( 18*333d2b36SAndroid Build Coastguard Worker "fmt" 19*333d2b36SAndroid Build Coastguard Worker "io/ioutil" 20*333d2b36SAndroid Build Coastguard Worker "os" 21*333d2b36SAndroid Build Coastguard Worker "path/filepath" 22*333d2b36SAndroid Build Coastguard Worker "testing" 23*333d2b36SAndroid Build Coastguard Worker 24*333d2b36SAndroid Build Coastguard Worker "android/soong/ui/build/paths" 25*333d2b36SAndroid Build Coastguard Worker) 26*333d2b36SAndroid Build Coastguard Worker 27*333d2b36SAndroid Build Coastguard Workervar tmpDir string 28*333d2b36SAndroid Build Coastguard Workervar origPATH string 29*333d2b36SAndroid Build Coastguard Worker 30*333d2b36SAndroid Build Coastguard Workerfunc TestMain(m *testing.M) { 31*333d2b36SAndroid Build Coastguard Worker os.Exit(func() int { 32*333d2b36SAndroid Build Coastguard Worker var err error 33*333d2b36SAndroid Build Coastguard Worker tmpDir, err = ioutil.TempDir("", "interposer_test") 34*333d2b36SAndroid Build Coastguard Worker if err != nil { 35*333d2b36SAndroid Build Coastguard Worker panic(err) 36*333d2b36SAndroid Build Coastguard Worker } 37*333d2b36SAndroid Build Coastguard Worker defer os.RemoveAll(tmpDir) 38*333d2b36SAndroid Build Coastguard Worker 39*333d2b36SAndroid Build Coastguard Worker origPATH = os.Getenv("PATH") 40*333d2b36SAndroid Build Coastguard Worker err = os.Setenv("PATH", "") 41*333d2b36SAndroid Build Coastguard Worker if err != nil { 42*333d2b36SAndroid Build Coastguard Worker panic(err) 43*333d2b36SAndroid Build Coastguard Worker } 44*333d2b36SAndroid Build Coastguard Worker 45*333d2b36SAndroid Build Coastguard Worker return m.Run() 46*333d2b36SAndroid Build Coastguard Worker }()) 47*333d2b36SAndroid Build Coastguard Worker} 48*333d2b36SAndroid Build Coastguard Worker 49*333d2b36SAndroid Build Coastguard Workerfunc setup(t *testing.T) string { 50*333d2b36SAndroid Build Coastguard Worker f, err := ioutil.TempFile(tmpDir, "interposer") 51*333d2b36SAndroid Build Coastguard Worker if err != nil { 52*333d2b36SAndroid Build Coastguard Worker t.Fatal(err) 53*333d2b36SAndroid Build Coastguard Worker } 54*333d2b36SAndroid Build Coastguard Worker defer f.Close() 55*333d2b36SAndroid Build Coastguard Worker 56*333d2b36SAndroid Build Coastguard Worker err = ioutil.WriteFile(f.Name()+"_origpath", []byte(origPATH), 0666) 57*333d2b36SAndroid Build Coastguard Worker if err != nil { 58*333d2b36SAndroid Build Coastguard Worker t.Fatal(err) 59*333d2b36SAndroid Build Coastguard Worker } 60*333d2b36SAndroid Build Coastguard Worker return f.Name() 61*333d2b36SAndroid Build Coastguard Worker} 62*333d2b36SAndroid Build Coastguard Worker 63*333d2b36SAndroid Build Coastguard Workerfunc TestInterposer(t *testing.T) { 64*333d2b36SAndroid Build Coastguard Worker interposer := setup(t) 65*333d2b36SAndroid Build Coastguard Worker 66*333d2b36SAndroid Build Coastguard Worker logConfig := func(name string) paths.PathConfig { 67*333d2b36SAndroid Build Coastguard Worker if name == "true" { 68*333d2b36SAndroid Build Coastguard Worker return paths.PathConfig{ 69*333d2b36SAndroid Build Coastguard Worker Log: false, 70*333d2b36SAndroid Build Coastguard Worker Error: false, 71*333d2b36SAndroid Build Coastguard Worker } 72*333d2b36SAndroid Build Coastguard Worker } else if name == "path_interposer_test_not_allowed" { 73*333d2b36SAndroid Build Coastguard Worker return paths.PathConfig{ 74*333d2b36SAndroid Build Coastguard Worker Log: false, 75*333d2b36SAndroid Build Coastguard Worker Error: true, 76*333d2b36SAndroid Build Coastguard Worker } 77*333d2b36SAndroid Build Coastguard Worker } 78*333d2b36SAndroid Build Coastguard Worker return paths.PathConfig{ 79*333d2b36SAndroid Build Coastguard Worker Log: true, 80*333d2b36SAndroid Build Coastguard Worker Error: false, 81*333d2b36SAndroid Build Coastguard Worker } 82*333d2b36SAndroid Build Coastguard Worker } 83*333d2b36SAndroid Build Coastguard Worker 84*333d2b36SAndroid Build Coastguard Worker testCases := []struct { 85*333d2b36SAndroid Build Coastguard Worker name string 86*333d2b36SAndroid Build Coastguard Worker args []string 87*333d2b36SAndroid Build Coastguard Worker 88*333d2b36SAndroid Build Coastguard Worker exitCode int 89*333d2b36SAndroid Build Coastguard Worker err error 90*333d2b36SAndroid Build Coastguard Worker logEntry string 91*333d2b36SAndroid Build Coastguard Worker }{ 92*333d2b36SAndroid Build Coastguard Worker { 93*333d2b36SAndroid Build Coastguard Worker name: "direct call", 94*333d2b36SAndroid Build Coastguard Worker args: []string{interposer}, 95*333d2b36SAndroid Build Coastguard Worker 96*333d2b36SAndroid Build Coastguard Worker exitCode: 1, 97*333d2b36SAndroid Build Coastguard Worker err: usage, 98*333d2b36SAndroid Build Coastguard Worker }, 99*333d2b36SAndroid Build Coastguard Worker { 100*333d2b36SAndroid Build Coastguard Worker name: "relative call", 101*333d2b36SAndroid Build Coastguard Worker args: []string{filepath.Base(interposer)}, 102*333d2b36SAndroid Build Coastguard Worker 103*333d2b36SAndroid Build Coastguard Worker exitCode: 1, 104*333d2b36SAndroid Build Coastguard Worker err: usage, 105*333d2b36SAndroid Build Coastguard Worker }, 106*333d2b36SAndroid Build Coastguard Worker { 107*333d2b36SAndroid Build Coastguard Worker name: "true", 108*333d2b36SAndroid Build Coastguard Worker args: []string{"/my/path/true"}, 109*333d2b36SAndroid Build Coastguard Worker }, 110*333d2b36SAndroid Build Coastguard Worker { 111*333d2b36SAndroid Build Coastguard Worker name: "relative true", 112*333d2b36SAndroid Build Coastguard Worker args: []string{"true"}, 113*333d2b36SAndroid Build Coastguard Worker }, 114*333d2b36SAndroid Build Coastguard Worker { 115*333d2b36SAndroid Build Coastguard Worker name: "exit code", 116*333d2b36SAndroid Build Coastguard Worker args: []string{"bash", "-c", "exit 42"}, 117*333d2b36SAndroid Build Coastguard Worker 118*333d2b36SAndroid Build Coastguard Worker exitCode: 42, 119*333d2b36SAndroid Build Coastguard Worker logEntry: "bash", 120*333d2b36SAndroid Build Coastguard Worker }, 121*333d2b36SAndroid Build Coastguard Worker { 122*333d2b36SAndroid Build Coastguard Worker name: "signal", 123*333d2b36SAndroid Build Coastguard Worker args: []string{"bash", "-c", "kill -9 $$"}, 124*333d2b36SAndroid Build Coastguard Worker 125*333d2b36SAndroid Build Coastguard Worker exitCode: 137, 126*333d2b36SAndroid Build Coastguard Worker logEntry: "bash", 127*333d2b36SAndroid Build Coastguard Worker }, 128*333d2b36SAndroid Build Coastguard Worker { 129*333d2b36SAndroid Build Coastguard Worker name: "does not exist", 130*333d2b36SAndroid Build Coastguard Worker args: []string{"path_interposer_test_does_not_exist"}, 131*333d2b36SAndroid Build Coastguard Worker 132*333d2b36SAndroid Build Coastguard Worker exitCode: 1, 133*333d2b36SAndroid Build Coastguard Worker err: fmt.Errorf(`exec: "path_interposer_test_does_not_exist": executable file not found in $PATH`), 134*333d2b36SAndroid Build Coastguard Worker logEntry: "path_interposer_test_does_not_exist", 135*333d2b36SAndroid Build Coastguard Worker }, 136*333d2b36SAndroid Build Coastguard Worker { 137*333d2b36SAndroid Build Coastguard Worker name: "not allowed", 138*333d2b36SAndroid Build Coastguard Worker args: []string{"path_interposer_test_not_allowed"}, 139*333d2b36SAndroid Build Coastguard Worker 140*333d2b36SAndroid Build Coastguard Worker exitCode: 1, 141*333d2b36SAndroid Build Coastguard Worker err: fmt.Errorf(`"path_interposer_test_not_allowed" is not allowed to be used. See https://android.googlesource.com/platform/build/+/main/Changes.md#PATH_Tools for more information.`), 142*333d2b36SAndroid Build Coastguard Worker logEntry: "path_interposer_test_not_allowed", 143*333d2b36SAndroid Build Coastguard Worker }, 144*333d2b36SAndroid Build Coastguard Worker } 145*333d2b36SAndroid Build Coastguard Worker 146*333d2b36SAndroid Build Coastguard Worker for _, testCase := range testCases { 147*333d2b36SAndroid Build Coastguard Worker t.Run(testCase.name, func(t *testing.T) { 148*333d2b36SAndroid Build Coastguard Worker logged := false 149*333d2b36SAndroid Build Coastguard Worker logFunc := func(logSocket string, entry *paths.LogEntry, done chan interface{}) { 150*333d2b36SAndroid Build Coastguard Worker defer close(done) 151*333d2b36SAndroid Build Coastguard Worker 152*333d2b36SAndroid Build Coastguard Worker logged = true 153*333d2b36SAndroid Build Coastguard Worker if entry.Basename != testCase.logEntry { 154*333d2b36SAndroid Build Coastguard Worker t.Errorf("unexpected log entry:\nwant: %q\n got: %q", testCase.logEntry, entry.Basename) 155*333d2b36SAndroid Build Coastguard Worker } 156*333d2b36SAndroid Build Coastguard Worker } 157*333d2b36SAndroid Build Coastguard Worker 158*333d2b36SAndroid Build Coastguard Worker exitCode, err := Main(ioutil.Discard, ioutil.Discard, interposer, testCase.args, mainOpts{ 159*333d2b36SAndroid Build Coastguard Worker sendLog: logFunc, 160*333d2b36SAndroid Build Coastguard Worker config: logConfig, 161*333d2b36SAndroid Build Coastguard Worker }) 162*333d2b36SAndroid Build Coastguard Worker 163*333d2b36SAndroid Build Coastguard Worker errstr := func(err error) string { 164*333d2b36SAndroid Build Coastguard Worker if err == nil { 165*333d2b36SAndroid Build Coastguard Worker return "" 166*333d2b36SAndroid Build Coastguard Worker } 167*333d2b36SAndroid Build Coastguard Worker return err.Error() 168*333d2b36SAndroid Build Coastguard Worker } 169*333d2b36SAndroid Build Coastguard Worker if errstr(testCase.err) != errstr(err) { 170*333d2b36SAndroid Build Coastguard Worker t.Errorf("unexpected error:\nwant: %v\n got: %v", testCase.err, err) 171*333d2b36SAndroid Build Coastguard Worker } 172*333d2b36SAndroid Build Coastguard Worker if testCase.exitCode != exitCode { 173*333d2b36SAndroid Build Coastguard Worker t.Errorf("expected exit code %d, got %d", testCase.exitCode, exitCode) 174*333d2b36SAndroid Build Coastguard Worker } 175*333d2b36SAndroid Build Coastguard Worker if !logged && testCase.logEntry != "" { 176*333d2b36SAndroid Build Coastguard Worker t.Errorf("no log entry, but expected %q", testCase.logEntry) 177*333d2b36SAndroid Build Coastguard Worker } 178*333d2b36SAndroid Build Coastguard Worker }) 179*333d2b36SAndroid Build Coastguard Worker } 180*333d2b36SAndroid Build Coastguard Worker} 181*333d2b36SAndroid Build Coastguard Worker 182*333d2b36SAndroid Build Coastguard Workerfunc TestMissingPath(t *testing.T) { 183*333d2b36SAndroid Build Coastguard Worker interposer := setup(t) 184*333d2b36SAndroid Build Coastguard Worker err := os.Remove(interposer + "_origpath") 185*333d2b36SAndroid Build Coastguard Worker if err != nil { 186*333d2b36SAndroid Build Coastguard Worker t.Fatal("Failed to remove:", err) 187*333d2b36SAndroid Build Coastguard Worker } 188*333d2b36SAndroid Build Coastguard Worker 189*333d2b36SAndroid Build Coastguard Worker exitCode, err := Main(ioutil.Discard, ioutil.Discard, interposer, []string{"true"}, mainOpts{}) 190*333d2b36SAndroid Build Coastguard Worker if err != usage { 191*333d2b36SAndroid Build Coastguard Worker t.Errorf("Unexpected error:\n got: %v\nwant: %v", err, usage) 192*333d2b36SAndroid Build Coastguard Worker } 193*333d2b36SAndroid Build Coastguard Worker if exitCode != 1 { 194*333d2b36SAndroid Build Coastguard Worker t.Errorf("expected exit code %d, got %d", 1, exitCode) 195*333d2b36SAndroid Build Coastguard Worker } 196*333d2b36SAndroid Build Coastguard Worker} 197