github.com/saucelabs/saucectl@v0.175.1/internal/http/testcomposer_test.go (about) 1 package http 2 3 import ( 4 "context" 5 "encoding/json" 6 "net/http" 7 "net/http/httptest" 8 "reflect" 9 "testing" 10 "time" 11 12 "github.com/saucelabs/saucectl/internal/framework" 13 "github.com/saucelabs/saucectl/internal/iam" 14 ) 15 16 func TestTestComposer_GetSlackToken(t *testing.T) { 17 type fields struct { 18 HTTPClient *http.Client 19 URL string 20 Credentials iam.Credentials 21 } 22 tests := []struct { 23 name string 24 fields fields 25 want string 26 wantErr bool 27 serverFunc func(w http.ResponseWriter, r *http.Request) 28 }{ 29 { 30 name: "token exists", 31 want: "user token", 32 wantErr: false, 33 serverFunc: func(w http.ResponseWriter, r *http.Request) { 34 w.WriteHeader(200) 35 err := json.NewEncoder(w).Encode(TokenResponse{ 36 Token: "user token", 37 }) 38 if err != nil { 39 t.Errorf("failed to encode json response: %v", err) 40 } 41 }, 42 }, 43 { 44 name: "token validation error", 45 want: "", 46 wantErr: true, 47 serverFunc: func(w http.ResponseWriter, r *http.Request) { 48 w.WriteHeader(422) 49 }, 50 }, 51 { 52 name: "token does not exists", 53 want: "", 54 wantErr: true, 55 serverFunc: func(w http.ResponseWriter, r *http.Request) { 56 w.WriteHeader(404) 57 }, 58 }, 59 } 60 for _, tt := range tests { 61 t.Run(tt.name, func(t *testing.T) { 62 server := httptest.NewServer(http.HandlerFunc(tt.serverFunc)) 63 defer server.Close() 64 65 c := &TestComposer{ 66 HTTPClient: server.Client(), 67 URL: server.URL, 68 Credentials: tt.fields.Credentials, 69 } 70 71 got, err := c.GetSlackToken(context.Background()) 72 if (err != nil) != tt.wantErr { 73 t.Errorf("GetSlackToken error = %v, wantErr %v", err, tt.wantErr) 74 return 75 } 76 if !reflect.DeepEqual(got, tt.want) { 77 t.Errorf("GetSlackToken got = %v, want %v", got, tt.want) 78 } 79 }) 80 } 81 } 82 83 func TestTestComposer_UploadAsset(t *testing.T) { 84 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 85 var err error 86 switch r.URL.Path { 87 case "/v1/testcomposer/jobs/1/assets": 88 w.WriteHeader(http.StatusOK) 89 _, err = w.Write([]byte("{\"uploaded\":null}")) 90 case "/v1/testcomposer/jobs/2/assets": 91 w.WriteHeader(http.StatusOK) 92 _, err = w.Write([]byte("{\"uploaded\":null,\"errors\":[\"failed to upload config.yml: content-type not allowed\"]}")) 93 case "/v1/testcomposer/jobs/3/assets": 94 w.WriteHeader(http.StatusNotFound) 95 default: 96 w.WriteHeader(http.StatusInternalServerError) 97 } 98 99 if err != nil { 100 t.Errorf("failed to respond: %v", err) 101 } 102 })) 103 defer ts.Close() 104 // timeout := 3 * time.Second 105 106 type args struct { 107 jobID string 108 fileName string 109 contentType string 110 content []byte 111 } 112 tests := []struct { 113 client TestComposer 114 name string 115 args args 116 wantErr bool 117 }{ 118 { 119 name: "Valid case", 120 client: TestComposer{ 121 HTTPClient: ts.Client(), 122 URL: ts.URL, 123 Credentials: iam.Credentials{Username: "test", AccessKey: "123"}, 124 }, 125 args: args{ 126 jobID: "1", 127 fileName: "config.yml", 128 contentType: "text/plain", 129 content: []byte("dummy-content"), 130 }, 131 wantErr: false, 132 }, 133 { 134 name: "invalid case - 400", 135 client: TestComposer{ 136 HTTPClient: ts.Client(), 137 URL: ts.URL, 138 Credentials: iam.Credentials{Username: "test", AccessKey: "123"}, 139 }, 140 args: args{ 141 jobID: "2", 142 fileName: "config.yml", 143 contentType: "text/plain", 144 content: []byte("dummy-content"), 145 }, 146 wantErr: true, 147 }, 148 { 149 name: "invalid 404", 150 client: TestComposer{ 151 HTTPClient: ts.Client(), 152 URL: ts.URL, 153 Credentials: iam.Credentials{Username: "test", AccessKey: "123"}, 154 }, 155 args: args{ 156 jobID: "3", 157 fileName: "config.yml", 158 contentType: "text/plain", 159 content: []byte("dummy-content"), 160 }, 161 wantErr: true, 162 }, 163 } 164 for _, tt := range tests { 165 t.Run(tt.name, func(t *testing.T) { 166 if err := tt.client.UploadAsset(tt.args.jobID, false, tt.args.fileName, tt.args.contentType, tt.args.content); (err != nil) != tt.wantErr { 167 t.Errorf("UploadAsset() error = %v, wantErr %v", err, tt.wantErr) 168 } 169 }) 170 } 171 } 172 173 func TestTestComposer_Frameworks(t *testing.T) { 174 tests := []struct { 175 name string 176 body string 177 httpCode int 178 want []string 179 wantErr bool 180 }{ 181 { 182 name: "HTTP - 200", 183 body: `[{"name":"cypress","version":"12.6.0"},{"name":"cypress","version":"12.3.0"},{"name":"playwright","version":"1.31.1"},{"name":"playwright","version":"1.29.2"},{"name":"puppeteer-replay","version":"0.8.0"},{"name":"puppeteer-replay","version":"0.7.0"},{"name":"testcafe","version":"2.1.0"},{"name":"testcafe","version":"2.0.1"}]`, 184 httpCode: 200, 185 want: []string{ 186 "cypress", 187 "playwright", 188 "puppeteer-replay", 189 "testcafe", 190 }, 191 wantErr: false, 192 }, 193 { 194 name: "HTTP - 500", 195 body: ``, 196 httpCode: 500, 197 want: []string{}, 198 wantErr: true, 199 }, 200 } 201 for _, tt := range tests { 202 t.Run(tt.name, func(t *testing.T) { 203 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 204 var err error 205 switch r.URL.Path { 206 case "/v2/testcomposer/frameworks": 207 w.WriteHeader(tt.httpCode) 208 _, err = w.Write([]byte(tt.body)) 209 default: 210 w.WriteHeader(http.StatusInternalServerError) 211 } 212 if err != nil { 213 t.Errorf("failed to respond: %v", err) 214 } 215 })) 216 c := &TestComposer{ 217 HTTPClient: http.DefaultClient, 218 URL: ts.URL, 219 Credentials: iam.Credentials{Username: "test", AccessKey: "123"}, 220 } 221 got, err := c.Frameworks(context.Background()) 222 if (err != nil) != tt.wantErr { 223 t.Errorf("Frameworks() error = %v, wantErr %v", err, tt.wantErr) 224 return 225 } 226 if !reflect.DeepEqual(got, tt.want) { 227 t.Errorf("Frameworks() got = %v, want %v", got, tt.want) 228 } 229 ts.Close() 230 }) 231 } 232 } 233 234 func TestTestComposer_Versions(t *testing.T) { 235 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 236 var err error 237 switch r.RequestURI { 238 case "/v2/testcomposer/frameworks?frameworkName=cypress": 239 w.WriteHeader(http.StatusOK) 240 _, err = w.Write([]byte(`[{"name":"cypress","version":"7.3.0","eolDate":"2023-01-01T00:00:00Z","removalDate":"2023-04-01T00:00:00Z","runner":{"cloudRunnerVersion":"","dockerImage":"saucelabs/stt-cypress-mocha-node:v7.1.1","gitRelease":"saucelabs/sauce-cypress-runner:v7.1.1"},"platforms":[{"name":"windows 10","browsers":["googlechrome","firefox","microsoftedge"]}]},{"name":"cypress","version":"7.1.0","eolDate":"2023-01-01T00:00:00Z","removalDate":"2023-04-01T00:00:00Z","runner":{"cloudRunnerVersion":"","dockerImage":"saucelabs/stt-cypress-mocha-node:v7.0.6","gitRelease":"saucelabs/sauce-cypress-runner:v7.0.6"},"platforms":[{"name":"windows 10","browsers":["googlechrome","firefox","microsoftedge"]}]},{"name":"cypress","version":"6.6.0","eolDate":"2023-01-01T00:00:00Z","removalDate":"2023-04-01T00:00:00Z","runner":{"cloudRunnerVersion":"","dockerImage":"saucelabs/stt-cypress-mocha-node:v6.0.2","gitRelease":"saucelabs/sauce-cypress-runner:v6.0.2"},"platforms":[{"name":"windows 10","browsers":["googlechrome","firefox","microsoftedge"]}]}]`)) 241 case "/v2/testcomposer/frameworks?frameworkName=non-existent": 242 w.WriteHeader(http.StatusOK) 243 _, err = w.Write([]byte(`[]`)) 244 default: 245 w.WriteHeader(http.StatusInternalServerError) 246 } 247 248 if err != nil { 249 t.Errorf("failed to respond: %v", err) 250 } 251 })) 252 defer ts.Close() 253 c := &TestComposer{ 254 HTTPClient: ts.Client(), 255 URL: ts.URL, 256 Credentials: iam.Credentials{Username: "test", AccessKey: "123"}, 257 } 258 type args struct { 259 frameworkName string 260 } 261 tests := []struct { 262 name string 263 want []framework.Metadata 264 args args 265 wantErr bool 266 }{ 267 { 268 name: "HTTP - 200", 269 args: args{ 270 frameworkName: "cypress", 271 }, 272 want: []framework.Metadata{ 273 { 274 FrameworkName: "cypress", 275 FrameworkVersion: "7.3.0", 276 EOLDate: time.Date(2023, 01, 01, 0, 0, 0, 0, time.UTC), 277 RemovalDate: time.Date(2023, 04, 01, 0, 0, 0, 0, time.UTC), 278 GitRelease: "saucelabs/sauce-cypress-runner:v7.1.1", 279 DockerImage: "saucelabs/stt-cypress-mocha-node:v7.1.1", 280 Platforms: []framework.Platform{ 281 { 282 PlatformName: "windows 10", 283 BrowserNames: []string{"googlechrome", "firefox", "microsoftedge"}, 284 }, 285 }, 286 }, { 287 FrameworkName: "cypress", 288 FrameworkVersion: "7.1.0", 289 EOLDate: time.Date(2023, 01, 01, 0, 0, 0, 0, time.UTC), 290 RemovalDate: time.Date(2023, 04, 01, 0, 0, 0, 0, time.UTC), 291 GitRelease: "saucelabs/sauce-cypress-runner:v7.0.6", 292 DockerImage: "saucelabs/stt-cypress-mocha-node:v7.0.6", 293 Platforms: []framework.Platform{ 294 { 295 PlatformName: "windows 10", 296 BrowserNames: []string{"googlechrome", "firefox", "microsoftedge"}, 297 }, 298 }, 299 }, { 300 FrameworkName: "cypress", 301 FrameworkVersion: "6.6.0", 302 EOLDate: time.Date(2023, 01, 01, 0, 0, 0, 0, time.UTC), 303 RemovalDate: time.Date(2023, 04, 01, 0, 0, 0, 0, time.UTC), 304 GitRelease: "saucelabs/sauce-cypress-runner:v6.0.2", 305 DockerImage: "saucelabs/stt-cypress-mocha-node:v6.0.2", 306 Platforms: []framework.Platform{ 307 { 308 PlatformName: "windows 10", 309 BrowserNames: []string{"googlechrome", "firefox", "microsoftedge"}, 310 }, 311 }, 312 }, 313 }, 314 wantErr: false, 315 }, { 316 name: "HTTP - 500", 317 args: args{ 318 frameworkName: "buggy", 319 }, 320 want: []framework.Metadata{}, 321 wantErr: true, 322 }, { 323 name: "HTTP - Non-existent framework", 324 args: args{ 325 frameworkName: "non-existent", 326 }, 327 wantErr: false, 328 }, 329 } 330 for _, tt := range tests { 331 t.Run(tt.name, func(t *testing.T) { 332 got, err := c.Versions(context.Background(), tt.args.frameworkName) 333 if (err != nil) != tt.wantErr { 334 t.Errorf("Versions() error = %v, wantErr %v", err, tt.wantErr) 335 return 336 } 337 if !reflect.DeepEqual(got, tt.want) { 338 t.Errorf("Versions() got = %v, want %v", got, tt.want) 339 } 340 }) 341 } 342 }