github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/runtimes/proctor/lib/lib.go (about) 1 // Copyright 2019 The gVisor Authors. 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 15 // Package lib contains proctor functions. 16 package lib 17 18 import ( 19 "fmt" 20 "os" 21 "os/exec" 22 "os/signal" 23 "path/filepath" 24 "regexp" 25 26 "golang.org/x/sys/unix" 27 ) 28 29 // TestRunner is an interface that must be implemented for each runtime 30 // integrated with proctor. 31 type TestRunner interface { 32 // ListTests returns a string slice of tests available to run. 33 ListTests() ([]string, error) 34 35 // TestCmds returns a slice of *exec.Cmd that will run the given tests. 36 // There is no correlation between the number of exec.Cmds returned and the 37 // number of tests. It could return one command to run all tests or a few 38 // commands that collectively run all. 39 TestCmds(tests []string) []*exec.Cmd 40 } 41 42 // TestRunnerForRuntime returns a new TestRunner for the given runtime. 43 func TestRunnerForRuntime(runtime string) (TestRunner, error) { 44 switch runtime { 45 case "go": 46 return goRunner{}, nil 47 case "java": 48 return javaRunner{}, nil 49 case "nodejs": 50 return nodejsRunner{}, nil 51 case "php": 52 return phpRunner{}, nil 53 case "python": 54 return pythonRunner{}, nil 55 } 56 return nil, fmt.Errorf("invalid runtime %q", runtime) 57 } 58 59 // PauseAndReap is like init. It runs forever and reaps any children. 60 func PauseAndReap() { 61 // Get notified of any new children. 62 ch := make(chan os.Signal, 1) 63 signal.Notify(ch, unix.SIGCHLD) 64 65 for { 66 if _, ok := <-ch; !ok { 67 // Channel closed. This should not happen. 68 panic("signal channel closed") 69 } 70 71 // Reap the child. 72 for { 73 if cpid, _ := unix.Wait4(-1, nil, unix.WNOHANG, nil); cpid < 1 { 74 break 75 } 76 } 77 } 78 } 79 80 // Search is a helper function to find tests in the given directory that match 81 // the regex. 82 func Search(root string, testFilter *regexp.Regexp) ([]string, error) { 83 var testSlice []string 84 85 err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { 86 if err != nil { 87 return err 88 } 89 90 name := filepath.Base(path) 91 92 if info.IsDir() || !testFilter.MatchString(name) { 93 return nil 94 } 95 96 relPath, err := filepath.Rel(root, path) 97 if err != nil { 98 return err 99 } 100 testSlice = append(testSlice, relPath) 101 return nil 102 }) 103 if err != nil { 104 return nil, fmt.Errorf("walking %q: %v", root, err) 105 } 106 107 return testSlice, nil 108 }