github.com/saucelabs/saucectl@v0.175.1/internal/http/apitester_test.go (about) 1 package http 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "net/http" 8 "net/http/httptest" 9 "reflect" 10 "testing" 11 "time" 12 13 "github.com/google/go-cmp/cmp" 14 "github.com/hashicorp/go-retryablehttp" 15 "github.com/saucelabs/saucectl/internal/apitest" 16 "github.com/saucelabs/saucectl/internal/config" 17 "github.com/stretchr/testify/assert" 18 "golang.org/x/time/rate" 19 ) 20 21 func createTestRetryableHTTPClient(t *testing.T) *retryablehttp.Client { 22 return &retryablehttp.Client{ 23 HTTPClient: &http.Client{ 24 Timeout: 10 * time.Second, 25 Transport: &http.Transport{Proxy: http.ProxyFromEnvironment}, 26 }, 27 RetryWaitMin: 0 * time.Second, 28 RetryWaitMax: 0 * time.Second, 29 RetryMax: 1, 30 CheckRetry: retryablehttp.DefaultRetryPolicy, 31 Backoff: retryablehttp.DefaultBackoff, 32 ErrorHandler: retryablehttp.PassthroughErrorHandler, 33 } 34 } 35 36 func TestAPITester_GetEventResult(t *testing.T) { 37 type args struct { 38 ctx context.Context 39 hookID string 40 eventID string 41 } 42 tests := []struct { 43 name string 44 args args 45 want apitest.TestResult 46 wantErr bool 47 }{ 48 { 49 name: "passing test", 50 args: args{ 51 hookID: "dummyHookId", 52 eventID: "completedEvent", 53 ctx: context.Background(), 54 }, 55 want: apitest.TestResult{ 56 EventID: "638e1e14a1da1e511c776eea", 57 ExecutionTimeSeconds: 31, 58 Async: false, 59 FailuresCount: 0, 60 Project: apitest.ProjectMeta{ 61 ID: "6244d915ca28694aab958bbe", 62 Name: "Test Project", 63 }, 64 Test: apitest.Test{ 65 ID: "638788b12d29c47170999eee", 66 Name: "test_demo", 67 }, 68 }, 69 wantErr: false, 70 }, 71 { 72 name: "404 Event", 73 args: args{ 74 hookID: "dummyHookId", 75 eventID: "incompleteEvent", 76 ctx: context.Background(), 77 }, 78 wantErr: true, 79 }, 80 { 81 name: "Buggy Event", 82 args: args{ 83 hookID: "dummyHookId", 84 eventID: "buggyEvent", 85 ctx: context.Background(), 86 }, 87 wantErr: true, 88 }, 89 } 90 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 91 var err error 92 switch r.URL.Path { 93 case "/api-testing/rest/v4/dummyHookId/insights/events/completedEvent": 94 completeStatusResp := []byte(`{"_id":"638e1e14a1da1e511c776eea","events":[],"tags":["canfail"],"criticalFailures":[],"httpFailures":[],"facts":{},"date":1670258196613,"test":{"name":"test_demo","id":"638788b12d29c47170999eee"},"failuresCount":0,"warningsCount":0,"compressed":false,"run":{"name":"","id":""},"company":{"name":"","id":"7fb25570b4064716b9b6daae1a997bba"},"project":{"name":"Test Project","id":"6244d915ca28694aab958bbe"},"temp":false,"expireAt":"2023-06-06T04:37:07Z","executionTimeSeconds":31,"taskId":"ad24fdd6-8e47-401c-81ce-866553194bdd","agent":"wstestjs","mode":"ondemand","buildId":"Test","clientname":"","initiator":{"name":"Incitator","id":"de8691a22ff343f08aa6fb63e485fe0d","teamid":"0205cb60678a4372193bac4052c048be"}}`) 95 _, err = w.Write(completeStatusResp) 96 case "/api-testing/rest/v4/dummyHookId/insights/events/incompleteEvent": 97 errorStatusResp := []byte(`{"status": "error","message": "event not found"}`) 98 w.WriteHeader(http.StatusNotFound) 99 _, err = w.Write(errorStatusResp) 100 case "/api-testing/rest/v4/dummyHookId/insights/events/unauthorized": 101 w.WriteHeader(http.StatusUnauthorized) 102 default: 103 w.WriteHeader(http.StatusInternalServerError) 104 } 105 106 if err != nil { 107 t.Errorf("failed to respond: %v", err) 108 } 109 })) 110 defer ts.Close() 111 112 c := &APITester{ 113 HTTPClient: createTestRetryableHTTPClient(t), 114 URL: ts.URL, 115 Username: "dummy", 116 AccessKey: "accesskey", 117 RequestRateLimiter: rate.NewLimiter(rate.Inf, 0), 118 } 119 for _, tt := range tests { 120 t.Run(tt.name, func(t *testing.T) { 121 got, err := c.GetEventResult(tt.args.ctx, tt.args.hookID, tt.args.eventID) 122 if (err != nil) != tt.wantErr { 123 t.Errorf("GetEventResult() error = %v, wantErr %v", err, tt.wantErr) 124 return 125 } 126 if !cmp.Equal(got, tt.want) { 127 t.Errorf("GetEventResult() got = %v, want %v", got, tt.want) 128 } 129 }) 130 } 131 } 132 133 func TestAPITester_GetProject(t *testing.T) { 134 type args struct { 135 ctx context.Context 136 hookID string 137 } 138 tests := []struct { 139 name string 140 args args 141 want apitest.ProjectMeta 142 wantErr bool 143 }{ 144 { 145 name: "Passing Project Fetch", 146 args: args{ctx: context.Background(), hookID: "dummyProject"}, 147 want: apitest.ProjectMeta{ 148 ID: "6244d915ca28694aab000000", 149 Name: "Test Project", 150 }, 151 wantErr: false, 152 }, 153 { 154 name: "Failing Project Fetch", 155 args: args{ctx: context.Background(), hookID: "nonExistingProject"}, 156 wantErr: true, 157 }, 158 } 159 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 160 var err error 161 switch r.URL.Path { 162 case "/api-testing/rest/v4/dummyProject": 163 completeStatusResp := []byte(`{"id":"6244d915ca28694aab000000","name":"Test Project","teamId":"0205cb60678a4372b9ee20408725467ad","description":"","tags":[],"notes":"","type":"project","emailNotifications":[],"connectorNotifications":[]}`) 164 _, err = w.Write(completeStatusResp) 165 case "/api-testing/rest/v4/nonExistingProject": 166 w.WriteHeader(http.StatusNotFound) 167 default: 168 w.WriteHeader(http.StatusInternalServerError) 169 } 170 171 if err != nil { 172 t.Errorf("failed to respond: %v", err) 173 } 174 })) 175 defer ts.Close() 176 c := &APITester{ 177 HTTPClient: createTestRetryableHTTPClient(t), 178 URL: ts.URL, 179 Username: "dummy", 180 AccessKey: "accesskey", 181 } 182 183 for _, tt := range tests { 184 t.Run(tt.name, func(t *testing.T) { 185 got, err := c.GetProject(tt.args.ctx, tt.args.hookID) 186 if (err != nil) != tt.wantErr { 187 t.Errorf("GetProject() error = %v, wantErr %v", err, tt.wantErr) 188 return 189 } 190 if !cmp.Equal(got, tt.want) { 191 t.Errorf("GetProject() got = %v, want %v", got, tt.want) 192 } 193 }) 194 } 195 } 196 197 func TestAPITester_GetTest(t *testing.T) { 198 type args struct { 199 ctx context.Context 200 hookID string 201 testID string 202 } 203 tests := []struct { 204 name string 205 args args 206 want apitest.Test 207 wantErr bool 208 }{ 209 { 210 name: "Passing Test Fetch", 211 args: args{ctx: context.Background(), hookID: "dummyProject", testID: "existingTest"}, 212 want: apitest.Test{ 213 ID: "638788b12d29c47170d20db4", 214 Name: "test_cli", 215 }, 216 wantErr: false, 217 }, 218 { 219 name: "Failing test fetch", 220 args: args{ctx: context.Background(), hookID: "dummyProject", testID: "nonexistentTest"}, 221 wantErr: true, 222 }, 223 } 224 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 225 var err error 226 switch r.URL.Path { 227 case "/api-testing/rest/v4/dummyProject/tests/existingTest": 228 completeStatusResp := []byte(`{"published":{"id":"638788b12d29c47170d20db4","name":"test_cli","description":"","lastModified":"2022-11-30T17:20:08Z","tags":["canfail"],"user":{"id":"de8691a22ff343f08aa6fb63e963121d","name":"Username"},"unit":"assertions:\n - id: get\n children:\n - id: header\n name: x-rapidmock-delay\n value: \"10000\"\n url: https://api.rapidmock.com/mocks/f6GeB\n var: payload\n mode: json\n - id: if\n children:\n - id: comment\n text: endpoint is not working fine, test will be stopped\n - id: flow\n command: stop\n expression: payload_response.statusCode!='200'\nconfigs: []","input":"- id: global\n children:\n - id: variable\n name: protocol\n value: http://\n - id: variable\n name: domain\n value: demoapi.apifortress.com\n - id: variable\n name: endpoint\n value: /api/retail/product/${id}\n - id: variable\n name: auth\n value: ABC123\n- id: sets\n children:\n - id: set\n children:\n - id: variable\n name: id\n value: \"1\"\n name: product 1\n - id: set\n children:\n - id: variable\n name: id\n value: \"4\"\n name: product 2\n - id: set\n children:\n - id: variable\n name: id\n value: \"7\"\n name: product 3","complete":true},"workingCopy":{"id":"638790c8e90a3c46b5c83a98","user":{"id":"de8691a22ff343f08aa6fb63e963121d","name":"Username"},"unit":"assertions:\n - id: get\n children:\n - id: header\n name: x-rapidmock-delay\n value: \"10000\"\n url: https://api.rapidmock.com/mocks/f6GeB\n var: payload\n mode: json\n - id: if\n children:\n - id: comment\n text: endpoint is not working fine, test will be stopped\n - id: flow\n command: stop\n expression: payload_response.statusCode!='200'\nconfigs: []","input":"- id: global\n children:\n - id: variable\n name: protocol\n value: http://\n - id: variable\n name: domain\n value: demoapi.apifortress.com\n - id: variable\n name: endpoint\n value: /api/retail/product/${id}\n - id: variable\n name: auth\n value: ABC123\n- id: sets\n children:\n - id: set\n children:\n - id: variable\n name: id\n value: \"1\"\n name: product 1\n - id: set\n children:\n - id: variable\n name: id\n value: \"4\"\n name: product 2\n - id: set\n children:\n - id: variable\n name: id\n value: \"7\"\n name: product 3","lastModified":"2022-11-30T17:20:08Z"}}`) 229 _, err = w.Write(completeStatusResp) 230 case "/api-testing/rest/v4/dummyProject/tests/nonexistentTest": 231 w.WriteHeader(http.StatusNotFound) 232 default: 233 w.WriteHeader(http.StatusInternalServerError) 234 } 235 236 if err != nil { 237 t.Errorf("failed to respond: %v", err) 238 } 239 })) 240 defer ts.Close() 241 c := &APITester{ 242 HTTPClient: createTestRetryableHTTPClient(t), 243 URL: ts.URL, 244 Username: "dummy", 245 AccessKey: "accesskey", 246 } 247 248 for _, tt := range tests { 249 t.Run(tt.name, func(t *testing.T) { 250 got, err := c.GetTest(tt.args.ctx, tt.args.hookID, tt.args.testID) 251 if (err != nil) != tt.wantErr { 252 t.Errorf("GetProject() error = %v, wantErr %v", err, tt.wantErr) 253 return 254 } 255 if !cmp.Equal(got, tt.want) { 256 t.Errorf("GetProject() got = %v, want %v", got, tt.want) 257 } 258 }) 259 } 260 } 261 262 func TestAPITester_composeURL(t *testing.T) { 263 type args struct { 264 path string 265 buildID string 266 format string 267 tunnel config.Tunnel 268 taskID string 269 } 270 tests := []struct { 271 name string 272 args args 273 want string 274 }{ 275 { 276 name: "Default Path", 277 args: args{ 278 path: "/dummy/path", 279 }, 280 want: "/dummy/path", 281 }, 282 { 283 name: "Path with buildId", 284 args: args{ 285 path: "/dummy/path", 286 buildID: "buildId", 287 }, 288 want: "/dummy/path?buildId=buildId", 289 }, 290 { 291 name: "Path with buildId and Format", 292 args: args{ 293 path: "/dummy/path", 294 buildID: "buildId", 295 format: "json", 296 }, 297 want: "/dummy/path?buildId=buildId&format=json", 298 }, 299 { 300 name: "Path with Format", 301 args: args{ 302 path: "/dummy/path", 303 format: "json", 304 }, 305 want: "/dummy/path?format=json", 306 }, 307 { 308 name: "Path with tunnel with owner", 309 args: args{ 310 path: "/dummy/path", 311 tunnel: config.Tunnel{ 312 Name: "tunnelId", 313 Owner: "tunnelOwner", 314 }, 315 }, 316 want: "/dummy/path?tunnelId=tunnelOwner%3AtunnelId", 317 }, 318 { 319 name: "Path with tunnel without owner", 320 args: args{ 321 path: "/dummy/path", 322 tunnel: config.Tunnel{ 323 Name: "tunnelId", 324 }, 325 }, 326 want: "/dummy/path?tunnelId=dummyUsername%3AtunnelId", 327 }, 328 { 329 name: "Path with taskId", 330 args: args{ 331 path: "/dummy/path", 332 taskID: "taskId", 333 }, 334 want: "/dummy/path?taskId=taskId", 335 }, 336 } 337 c := &APITester{ 338 Username: "dummyUsername", 339 } 340 for _, tt := range tests { 341 t.Run(tt.name, func(t *testing.T) { 342 if got := c.composeURL(tt.args.path, tt.args.buildID, tt.args.format, tt.args.tunnel, tt.args.taskID); got != tt.want { 343 t.Errorf("composeURL() = %v, want %v", got, tt.want) 344 } 345 }) 346 } 347 } 348 349 func TestAPITester_GetProjects(t *testing.T) { 350 tests := []struct { 351 name string 352 want []apitest.ProjectMeta 353 wantErr assert.ErrorAssertionFunc 354 }{ 355 { 356 name: "Fetching Projects Test", 357 wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { 358 return err != nil 359 }, 360 want: []apitest.ProjectMeta{}, 361 }, 362 } 363 364 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 365 var err error 366 switch r.URL.Path { 367 case "/api-testing/api/project": 368 completeStatusResp := []byte(`[{"id":"63dbe9d6f48c8412fe79220d","name":"Demo Project","teamId":null,"description":"","tags":[],"notes":"","type":"project","emailNotifications":[],"connectorNotifications":[]}]`) 369 _, err = w.Write(completeStatusResp) 370 default: 371 w.WriteHeader(http.StatusInternalServerError) 372 } 373 374 if err != nil { 375 t.Errorf("failed to respond: %v", err) 376 } 377 })) 378 defer ts.Close() 379 380 c := &APITester{ 381 HTTPClient: createTestRetryableHTTPClient(t), 382 URL: ts.URL, 383 Username: "dummy", 384 AccessKey: "accesskey", 385 } 386 387 for _, tt := range tests { 388 t.Run(tt.name, func(t *testing.T) { 389 got, err := c.GetProjects(context.Background()) 390 if !tt.wantErr(t, err, fmt.Sprintf("GetProjects(%v)", context.Background())) { 391 return 392 } 393 assert.Equalf(t, tt.want, got, "GetProjects(%v)", context.Background()) 394 }) 395 } 396 } 397 398 func TestAPITester_GetHooks(t *testing.T) { 399 type params struct { 400 projectID string 401 } 402 403 tests := []struct { 404 name string 405 params params 406 want []apitest.Hook 407 wantErr error 408 }{ 409 { 410 name: "Projects with no hooks", 411 params: params{ 412 projectID: "noHooks", 413 }, 414 wantErr: nil, 415 want: []apitest.Hook{}, 416 }, 417 { 418 name: "Projects with multiple hooks", 419 params: params{ 420 projectID: "multipleHooks", 421 }, 422 wantErr: nil, 423 want: []apitest.Hook{ 424 { 425 Identifier: "e291c7c5-d091-4bae-8293-7315fc15cc4c", 426 Name: "name1", 427 }, 428 { 429 Identifier: "4d66f4d0-a29a-43a1-a787-94f7b8cc2e21", 430 Name: "name2", 431 }, 432 }, 433 }, 434 { 435 name: "Invalid Project", 436 params: params{ 437 projectID: "invalidProject", 438 }, 439 wantErr: errors.New(`request failed; unexpected response code:'404', msg:'{"status":"error","message":"Not Found"}'`), 440 want: []apitest.Hook{}, 441 }, 442 } 443 444 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 445 var err error 446 switch r.URL.Path { 447 case "/api-testing/api/project/noHooks/hook": 448 completeStatusResp := []byte(`[]`) 449 _, err = w.Write(completeStatusResp) 450 case "/api-testing/api/project/multipleHooks/hook": 451 completeStatusResp := []byte(`[{"id":"hook1","identifier":"e291c7c5-d091-4bae-8293-7315fc15cc4c","name":"name1","description":"description1"},{"id":"hook2","identifier":"4d66f4d0-a29a-43a1-a787-94f7b8cc2e21","name":"name2","description":"description2"}]`) 452 _, err = w.Write(completeStatusResp) 453 case "/api-testing/api/project/invalidProject/hook": 454 completeStatusResp := []byte(`{"status":"error","message":"Not Found"}`) 455 w.WriteHeader(http.StatusNotFound) 456 _, err = w.Write(completeStatusResp) 457 default: 458 w.WriteHeader(http.StatusInternalServerError) 459 } 460 461 if err != nil { 462 t.Errorf("failed to respond: %v", err) 463 } 464 })) 465 defer ts.Close() 466 467 c := &APITester{ 468 HTTPClient: createTestRetryableHTTPClient(t), 469 URL: ts.URL, 470 Username: "dummy", 471 AccessKey: "accesskey", 472 } 473 474 for _, tt := range tests { 475 t.Run(tt.name, func(t *testing.T) { 476 got, err := c.GetHooks(context.Background(), tt.params.projectID) 477 if !reflect.DeepEqual(err, tt.wantErr) { 478 t.Errorf("GetHooks(%v, %s): got %v want %v", context.Background(), tt.params.projectID, err, tt.wantErr) 479 return 480 } 481 assert.Equalf(t, tt.want, got, "GetHooks(%v, %s)", context.Background(), tt.params.projectID) 482 }) 483 } 484 } 485 486 func TestAPITester_RunAllAsync(t *testing.T) { 487 type args struct { 488 ctx context.Context 489 hookID string 490 buildID string 491 tunnel config.Tunnel 492 } 493 tests := []struct { 494 name string 495 args args 496 want apitest.AsyncResponse 497 wantErr bool 498 }{ 499 { 500 name: "Basic trigger", 501 args: args{ 502 ctx: context.Background(), 503 hookID: "dummyHookId", 504 }, 505 want: apitest.AsyncResponse{ 506 ContextIDs: []string{"221270ac-0229-49d1-9025-251a10e9133d"}, 507 EventIDs: []string{"c4ca4238a0b923820dcc509a"}, 508 TaskID: "6ddf80b7-9753-4802-992b-d42948cdb99f", 509 TestIDs: []string{"c20ad4d76fe97759aa27a0c9"}, 510 }, 511 }, 512 } 513 514 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 515 var err error 516 if r.Method != http.MethodPost { 517 w.WriteHeader(http.StatusNotImplemented) 518 return 519 } 520 switch r.URL.Path { 521 case "/api-testing/rest/v4/dummyHookId/tests/_run-all": 522 completeStatusResp := []byte(`{"contextIds":["221270ac-0229-49d1-9025-251a10e9133d"],"eventIds":["c4ca4238a0b923820dcc509a"],"taskId":"6ddf80b7-9753-4802-992b-d42948cdb99f","testIds":["c20ad4d76fe97759aa27a0c9"]}`) 523 _, err = w.Write(completeStatusResp) 524 default: 525 w.WriteHeader(http.StatusInternalServerError) 526 } 527 528 if err != nil { 529 t.Errorf("failed to respond: %v", err) 530 } 531 })) 532 defer ts.Close() 533 c := &APITester{ 534 HTTPClient: createTestRetryableHTTPClient(t), 535 URL: ts.URL, 536 Username: "dummyUser", 537 AccessKey: "dummyAccesKey", 538 } 539 540 for _, tt := range tests { 541 t.Run(tt.name, func(t *testing.T) { 542 got, err := c.RunAllAsync(tt.args.ctx, tt.args.hookID, tt.args.buildID, tt.args.tunnel, apitest.TestRequest{}) 543 if (err != nil) != tt.wantErr { 544 t.Errorf("RunAllAsync() error = %v, wantErr %v", err, tt.wantErr) 545 return 546 } 547 if !cmp.Equal(got, tt.want) { 548 t.Errorf("RunAllAsync() got = %v, want %v", got, tt.want) 549 } 550 }) 551 } 552 } 553 554 func TestAPITester_RunEphemeralAsync(t *testing.T) { 555 type args struct { 556 ctx context.Context 557 hookID string 558 buildID string 559 tunnel config.Tunnel 560 taskID string 561 test apitest.TestRequest 562 } 563 tests := []struct { 564 name string 565 args args 566 assertRequest func(t *testing.T, r *http.Request) 567 reply []byte 568 want apitest.AsyncResponse 569 wantErr bool 570 }{ 571 { 572 name: "Complete Trigger", 573 args: args{ 574 ctx: context.Background(), 575 hookID: "dummyHookId", 576 taskID: "generatedUuid", 577 buildID: "generatedBuildId", 578 tunnel: config.Tunnel{Name: "tunnelId"}, 579 test: apitest.TestRequest{}, 580 }, 581 assertRequest: func(t *testing.T, r *http.Request) { 582 assert.Equal(t, "/api-testing/rest/v4/dummyHookId/tests/_exec?buildId=generatedBuildId&tunnelId=dummyUser%3AtunnelId", r.RequestURI) 583 }, 584 reply: []byte(`{"contextIds":["221270ac-0229-49d1-9025-251a10e9133d"],"eventIds":["c4ca4238a0b923820dcc509a"],"taskId":"6ddf80b7-9753-4802-992b-d42948cdb99f","testIds":["c20ad4d76fe97759aa27a0c9"]}`), 585 want: apitest.AsyncResponse{ 586 ContextIDs: []string{"221270ac-0229-49d1-9025-251a10e9133d"}, 587 EventIDs: []string{"c4ca4238a0b923820dcc509a"}, 588 TaskID: "6ddf80b7-9753-4802-992b-d42948cdb99f", 589 TestIDs: []string{"c20ad4d76fe97759aa27a0c9"}, 590 }, 591 }, 592 } 593 594 for _, tt := range tests { 595 t.Run(tt.name, func(t *testing.T) { 596 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 597 if r.Method != http.MethodPost { 598 w.WriteHeader(http.StatusNotImplemented) 599 return 600 } 601 switch r.URL.Path { 602 case "/api-testing/rest/v4/dummyHookId/tests/_exec": 603 tt.assertRequest(t, r) 604 completeStatusResp := tt.reply 605 _, _ = w.Write(completeStatusResp) 606 default: 607 w.WriteHeader(http.StatusInternalServerError) 608 } 609 })) 610 defer ts.Close() 611 c := &APITester{ 612 HTTPClient: createTestRetryableHTTPClient(t), 613 URL: ts.URL, 614 Username: "dummyUser", 615 AccessKey: "dummyAccesKey", 616 } 617 618 got, err := c.RunEphemeralAsync(tt.args.ctx, tt.args.hookID, tt.args.buildID, tt.args.tunnel, tt.args.taskID, tt.args.test) 619 if (err != nil) != tt.wantErr { 620 t.Errorf("RunAllAsync() error = %v, wantErr %v", err, tt.wantErr) 621 return 622 } 623 if !cmp.Equal(got, tt.want) { 624 t.Errorf("RunAllAsync() got = %v, want %v", got, tt.want) 625 } 626 }) 627 } 628 } 629 630 func TestAPITester_RunTestAsync(t *testing.T) { 631 type args struct { 632 ctx context.Context 633 testID string 634 hookID string 635 buildID string 636 tunnel config.Tunnel 637 } 638 tests := []struct { 639 name string 640 args args 641 want apitest.AsyncResponse 642 wantErr bool 643 }{ 644 { 645 name: "Basic trigger", 646 args: args{ 647 ctx: context.Background(), 648 hookID: "dummyHookId", 649 testID: "c20ad4d76fe97759aa27a0c9", 650 }, 651 want: apitest.AsyncResponse{ 652 ContextIDs: []string{"221270ac-0229-49d1-9025-251a10e9133d"}, 653 EventIDs: []string{"c4ca4238a0b923820dcc509a"}, 654 TaskID: "6ddf80b7-9753-4802-992b-d42948cdb99f", 655 TestIDs: []string{"c20ad4d76fe97759aa27a0c9"}, 656 }, 657 }, 658 } 659 660 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 661 var err error 662 if r.Method != http.MethodPost { 663 w.WriteHeader(http.StatusNotImplemented) 664 return 665 } 666 switch r.URL.Path { 667 case "/api-testing/rest/v4/dummyHookId/tests/c20ad4d76fe97759aa27a0c9/_run": 668 completeStatusResp := []byte(`{"contextIds":["221270ac-0229-49d1-9025-251a10e9133d"],"eventIds":["c4ca4238a0b923820dcc509a"],"taskId":"6ddf80b7-9753-4802-992b-d42948cdb99f","testIds":["c20ad4d76fe97759aa27a0c9"]}`) 669 _, err = w.Write(completeStatusResp) 670 default: 671 w.WriteHeader(http.StatusInternalServerError) 672 } 673 674 if err != nil { 675 t.Errorf("failed to respond: %v", err) 676 } 677 })) 678 defer ts.Close() 679 c := &APITester{ 680 HTTPClient: createTestRetryableHTTPClient(t), 681 URL: ts.URL, 682 Username: "dummyUser", 683 AccessKey: "dummyAccesKey", 684 } 685 686 for _, tt := range tests { 687 t.Run(tt.name, func(t *testing.T) { 688 got, err := c.RunTestAsync(tt.args.ctx, tt.args.hookID, tt.args.testID, tt.args.buildID, tt.args.tunnel, apitest.TestRequest{}) 689 if (err != nil) != tt.wantErr { 690 t.Errorf("RunAllAsync() error = %v, wantErr %v", err, tt.wantErr) 691 return 692 } 693 if !cmp.Equal(got, tt.want) { 694 t.Errorf("RunAllAsync() got = %v, want %v", got, tt.want) 695 } 696 }) 697 } 698 } 699 700 func TestAPITester_RunTagAsync(t *testing.T) { 701 type args struct { 702 ctx context.Context 703 hookID string 704 buildID string 705 tagID string 706 tunnel config.Tunnel 707 } 708 tests := []struct { 709 name string 710 args args 711 want apitest.AsyncResponse 712 wantErr bool 713 }{ 714 { 715 name: "Basic trigger", 716 args: args{ 717 ctx: context.Background(), 718 hookID: "dummyHookId", 719 tagID: "dummyTag", 720 }, 721 want: apitest.AsyncResponse{ 722 ContextIDs: []string{"221270ac-0229-49d1-9025-251a10e9133d"}, 723 EventIDs: []string{"c4ca4238a0b923820dcc509a"}, 724 TaskID: "6ddf80b7-9753-4802-992b-d42948cdb99f", 725 TestIDs: []string{"c20ad4d76fe97759aa27a0c9"}, 726 }, 727 }, 728 } 729 730 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 731 var err error 732 if r.Method != http.MethodPost { 733 w.WriteHeader(http.StatusNotImplemented) 734 return 735 } 736 switch r.URL.Path { 737 case "/api-testing/rest/v4/dummyHookId/tests/_tag/dummyTag/_run": 738 completeStatusResp := []byte(`{"contextIds":["221270ac-0229-49d1-9025-251a10e9133d"],"eventIds":["c4ca4238a0b923820dcc509a"],"taskId":"6ddf80b7-9753-4802-992b-d42948cdb99f","testIds":["c20ad4d76fe97759aa27a0c9"]}`) 739 _, err = w.Write(completeStatusResp) 740 default: 741 w.WriteHeader(http.StatusInternalServerError) 742 } 743 744 if err != nil { 745 t.Errorf("failed to respond: %v", err) 746 } 747 })) 748 defer ts.Close() 749 c := &APITester{ 750 HTTPClient: createTestRetryableHTTPClient(t), 751 URL: ts.URL, 752 Username: "dummyUser", 753 AccessKey: "dummyAccesKey", 754 } 755 756 for _, tt := range tests { 757 t.Run(tt.name, func(t *testing.T) { 758 got, err := c.RunTagAsync(tt.args.ctx, tt.args.hookID, tt.args.tagID, tt.args.buildID, tt.args.tunnel, apitest.TestRequest{}) 759 if (err != nil) != tt.wantErr { 760 t.Errorf("RunAllAsync() error = %v, wantErr %v", err, tt.wantErr) 761 return 762 } 763 if !cmp.Equal(got, tt.want) { 764 t.Errorf("RunAllAsync() got = %v, want %v", got, tt.want) 765 } 766 }) 767 } 768 }