github.com/stripe/stripe-go/v76@v76.25.0/scripts/test_with_stripe_mock/main.go (about) 1 // A script that wraps the run of the project test suite and starts stripe-mock 2 // with a custom OpenAPI + fixtures bundle if one was found in the appropriate 3 // spot (see `pathSpec` below). 4 // 5 // The script passes all its arguments to a Go's test command, and defaults to 6 // `./...`. For example, both of the following are valid invocations: 7 // 8 // go run test_with_stripe_mock/main.go 9 // go run test_with_stripe_mock/main.go ./charge 10 // 11 // The reason that we need a separate script for this is because Go's testing 12 // infrastructure doesn't provide any kind of global hook that we can use to do 13 // this work in only one place before any tests are run. 14 package main 15 16 import ( 17 "bytes" 18 "fmt" 19 "os" 20 "os/exec" 21 "regexp" 22 "time" 23 ) 24 25 const ( 26 defaultStripeMockPort = "12112" 27 28 pathSpec = "./testing/openapi/spec3.json" 29 pathFixtures = "./testing/openapi/fixtures3.json" 30 ) 31 32 var portMatch = regexp.MustCompile(` port: (\d+)`) 33 34 func main() { 35 var stripeMockProcess *os.Process 36 autostart := true 37 38 port := os.Getenv("STRIPE_MOCK_PORT") 39 if port == "" { 40 port = defaultStripeMockPort 41 } 42 43 // 44 // Maybe start stripe-mock 45 // 46 47 autostartEnv := os.Getenv("STRIPE_MOCK_AUTOSTART") 48 if autostartEnv == "0" || autostartEnv == "false" { 49 fmt.Printf("STRIPE_MOCK_AUTOSTART=%s, "+ 50 "assuming stripe-mock is already running on port %s\n", autostartEnv, port) 51 autostart = false 52 } else if _, err := os.Stat(pathSpec); os.IsNotExist(err) { 53 fmt.Printf("No custom spec file found, "+ 54 "assuming stripe-mock is already running on port %s\n", port) 55 autostart = false 56 } 57 58 if autostart { 59 var err error 60 port, stripeMockProcess, err = startStripeMock() 61 if err != nil { 62 exitWithError(err) 63 } 64 } 65 66 // 67 // Run tests 68 // 69 70 err := runTests(port) 71 if err != nil { 72 stopStripeMock(stripeMockProcess) 73 exitWithError(err) 74 } 75 76 // 77 // Stop stripe-mock 78 // 79 80 // Try to cleanly stop stripe-mock, but in case we don't, it'll die anyway 81 // because it's executing as a subprocess. 82 stopStripeMock(stripeMockProcess) 83 } 84 85 // 86 // Private functions 87 // 88 89 func exitWithError(err error) { 90 fmt.Fprintf(os.Stderr, "%v", err) 91 os.Exit(1) 92 } 93 94 func runTests(port string) error { 95 args := append([]string{"test"}, os.Args[1:]...) 96 97 // Defaults to `./...`, but also allows a specific package (or other CLI 98 // flags like `-test.v`) to be passed. 99 if len(args) == 1 { 100 args = append(args, "./...") 101 } 102 103 cmd := exec.Command("go", args...) 104 105 // Inherit this script's environment so that it's still possible to pass 106 // the test package flags like `GOCACHE=off`. 107 cmd.Env = append( 108 os.Environ(), 109 "STRIPE_MOCK_PORT="+port, 110 ) 111 112 cmd.Stderr = os.Stderr 113 cmd.Stdout = os.Stdout 114 115 err := cmd.Run() 116 if err != nil { 117 return fmt.Errorf("Error running tests: %v", err) 118 } 119 120 return nil 121 } 122 123 func startStripeMock() (string, *os.Process, error) { 124 fmt.Printf("Starting stripe-mock...\n") 125 126 cmd := exec.Command( 127 "stripe-mock", 128 "-https-port", "0", // stripe-mock will select a port 129 "-spec", pathSpec, 130 "-fixtures", pathFixtures, 131 ) 132 133 cmd.Stderr = os.Stderr 134 135 stdout, err := cmd.StdoutPipe() 136 if err != nil { 137 return "", nil, fmt.Errorf("Error starting stripe-mock: %v", err) 138 } 139 140 err = cmd.Start() 141 if err != nil { 142 return "", nil, fmt.Errorf("Error starting stripe-mock: %v", err) 143 } 144 145 b := make([]byte, 1024) 146 var port string 147 148 // We store the entire captured output because the string we're looking for 149 // may have appeared across a read boundary. 150 var stdoutBuffer bytes.Buffer 151 152 for { 153 n, err := stdout.Read(b) 154 if err != nil { 155 return "", nil, err 156 } 157 stdoutBuffer.Write(b[0:n]) 158 159 // Look for port in "Listening for HTTP on port: 50602" 160 matches := portMatch.FindStringSubmatch(stdoutBuffer.String()) 161 if len(matches) > 0 { 162 port = matches[1] 163 break 164 } 165 166 time.Sleep(100 * time.Millisecond) 167 } 168 169 fmt.Printf("Started stripe-mock; PID = %v, port = %v\n", cmd.Process.Pid, port) 170 return port, cmd.Process, nil 171 } 172 173 func stopStripeMock(process *os.Process) { 174 if process == nil { 175 return 176 } 177 178 fmt.Printf("Stopping stripe-mock...\n") 179 process.Signal(os.Interrupt) 180 process.Wait() 181 fmt.Printf("Stopped stripe-mock\n") 182 }