github.com/spinnaker/spin@v1.30.0/cmd/canary/canary-config/retro_test.go (about) 1 // Copyright (c) 2019, Waze, Inc. 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 canary_config 16 17 import ( 18 "io/ioutil" 19 "net/http" 20 "net/http/httptest" 21 "os" 22 "testing" 23 "time" 24 25 "github.com/spinnaker/spin/cmd" 26 "github.com/spinnaker/spin/cmd/canary" 27 "github.com/spinnaker/spin/util" 28 ) 29 30 func TestCanaryConfigRetro_file(t *testing.T) { 31 ts := gateServerRetroPass() 32 defer ts.Close() 33 34 tempFile := tempCanaryConfigFile(testCanaryConfigJsonStr) 35 if tempFile == nil { 36 t.Fatal("Could not create temp canary config file.") 37 } 38 defer os.Remove(tempFile.Name()) 39 40 rootCmd, rootOpts := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 41 canaryCmd, canaryOpts := canary.NewCanaryCmd(rootOpts) 42 canaryCmd.AddCommand(NewCanaryConfigCmd(canaryOpts)) 43 rootCmd.AddCommand(canaryCmd) 44 45 args := []string{ 46 "canary", "canary-config", "retro", 47 "--file", tempFile.Name(), 48 "--control-group", "control-v000", 49 "--control-location", "us-central1", 50 "--experiment-group", "experiment-v000", 51 "--experiment-location", "us-central1", 52 "--start", "2019-09-17T17:16:02.600Z", 53 "--end", "2019-09-17T18:16:02.600Z", 54 "--gate-endpoint", ts.URL, 55 } 56 rootCmd.SetArgs(args) 57 err := rootCmd.Execute() 58 if err != nil { 59 t.Fatalf("Command failed with: %s", err) 60 } 61 } 62 63 func TestCanaryConfigRetro_stdin(t *testing.T) { 64 ts := gateServerRetroPass() 65 defer ts.Close() 66 67 tempFile := tempCanaryConfigFile(testCanaryConfigJsonStr) 68 if tempFile == nil { 69 t.Fatal("Could not create temp canary config file.") 70 } 71 defer os.Remove(tempFile.Name()) 72 73 // Prepare Stdin for test reading. 74 tempFile.Seek(0, 0) 75 oldStdin := os.Stdin 76 defer func() { os.Stdin = oldStdin }() 77 os.Stdin = tempFile 78 79 rootCmd, rootOpts := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 80 canaryCmd, canaryOpts := canary.NewCanaryCmd(rootOpts) 81 canaryCmd.AddCommand(NewCanaryConfigCmd(canaryOpts)) 82 rootCmd.AddCommand(canaryCmd) 83 84 args := []string{ 85 "canary", "canary-config", "retro", 86 "--control-group", "control-v000", 87 "--control-location", "us-central1", 88 "--experiment-group", "experiment-v000", 89 "--experiment-location", "us-central1", 90 "--start", "2019-09-17T17:16:02.600Z", 91 "--end", "2019-09-17T18:16:02.600Z", 92 "--gate-endpoint", ts.URL, 93 } 94 rootCmd.SetArgs(args) 95 err := rootCmd.Execute() 96 if err != nil { 97 t.Fatalf("Command failed with: %s", err) 98 } 99 } 100 101 func TestCanaryConfigRetro_fail(t *testing.T) { 102 ts := testGateFail() 103 defer ts.Close() 104 105 tempFile := tempCanaryConfigFile(testCanaryConfigJsonStr) 106 if tempFile == nil { 107 t.Fatal("Could not create temp canary config file.") 108 } 109 defer os.Remove(tempFile.Name()) 110 111 rootCmd, rootOpts := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 112 canaryCmd, canaryOpts := canary.NewCanaryCmd(rootOpts) 113 canaryCmd.AddCommand(NewCanaryConfigCmd(canaryOpts)) 114 rootCmd.AddCommand(canaryCmd) 115 116 args := []string{ 117 "canary", "canary-config", "retro", 118 "--file", tempFile.Name(), 119 "--control-group", "control-v000", 120 "--control-location", "us-central1", 121 "--experiment-group", "experiment-v000", 122 "--experiment-location", "us-central1", 123 "--start", "2019-09-17T17:16:02.600Z", 124 "--end", "2019-09-17T18:16:02.600Z", 125 "--gate-endpoint", ts.URL, 126 } 127 rootCmd.SetArgs(args) 128 err := rootCmd.Execute() 129 if err == nil { 130 t.Fatalf("Command failed with: %s", err) 131 } 132 } 133 134 func TestCanaryConfigRetro_timeout(t *testing.T) { 135 retrySleepCycle = 1 * time.Millisecond 136 137 ts := gateServerExecHang() 138 defer ts.Close() 139 140 tempFile := tempCanaryConfigFile(testCanaryConfigJsonStr) 141 if tempFile == nil { 142 t.Fatal("Could not create temp canary config file.") 143 } 144 defer os.Remove(tempFile.Name()) 145 146 rootCmd, rootOpts := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 147 canaryCmd, canaryOpts := canary.NewCanaryCmd(rootOpts) 148 canaryCmd.AddCommand(NewCanaryConfigCmd(canaryOpts)) 149 rootCmd.AddCommand(canaryCmd) 150 151 args := []string{ 152 "canary", "canary-config", "retro", 153 "--file", tempFile.Name(), 154 "--control-group", "control-v000", 155 "--control-location", "us-central1", 156 "--experiment-group", "experiment-v000", 157 "--experiment-location", "us-central1", 158 "--start", "2019-09-17T17:16:02.600Z", 159 "--end", "2019-09-17T18:16:02.600Z", 160 "--gate-endpoint", ts.URL, 161 } 162 rootCmd.SetArgs(args) 163 err := rootCmd.Execute() 164 if err == nil { 165 t.Fatalf("Command failed with: %s", err) 166 } 167 } 168 169 func gateServerRetroPass() *httptest.Server { 170 mux := util.TestGateMuxWithVersionHandler() 171 mux.Handle("/v2/canaries/canary", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 172 w.Header().Add("content-type", "application/json") 173 w.Write([]byte(canaryExecRespJson)) 174 })) 175 176 mux.Handle("/v2/canaries/canary/executionId", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 177 w.Header().Add("content-type", "application/json") 178 w.Write([]byte(canaryFinishedPassJson)) 179 })) 180 return httptest.NewServer(mux) 181 } 182 183 func gateServerExecHang() *httptest.Server { 184 mux := util.TestGateMuxWithVersionHandler() 185 mux.Handle("/v2/canaries/canary", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 186 w.Header().Add("content-type", "application/json") 187 w.Write([]byte(canaryExecRespJson)) 188 })) 189 190 mux.Handle("/v2/canaries/canary/executionId", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 191 w.Header().Add("content-type", "application/json") 192 w.Write([]byte(canaryUnfinishedJson)) 193 })) 194 return httptest.NewServer(mux) 195 } 196 197 const canaryExecRespJson = ` 198 { 199 "canaryExecutionId": "executionId" 200 } 201 ` 202 203 const canaryUnfinishedJson = ` 204 { 205 "complete": false 206 } 207 ` 208 209 const canaryFinishedPassJson = ` 210 { 211 "complete": true, 212 "result": { 213 "judgeResult": { 214 "score": { 215 "classification": "PASS" 216 } 217 } 218 } 219 } 220 `