github.com/navikt/knorten@v0.0.0-20240419132333-1333f46ed8b6/pkg/api/admin_test.go (about) 1 package api 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "io" 8 "net/http" 9 "net/url" 10 "testing" 11 12 "github.com/google/go-cmp/cmp" 13 "github.com/navikt/knorten/pkg/database" 14 "github.com/navikt/knorten/pkg/database/gensql" 15 "github.com/navikt/knorten/pkg/k8s" 16 ) 17 18 func TestAdminAPI(t *testing.T) { 19 ctx := context.Background() 20 teams, err := prepareAdminTests(ctx) 21 if err != nil { 22 t.Fatalf("preparing admin tests: %v", err) 23 } 24 t.Cleanup(func() { 25 if err := cleanUpAdminTests(ctx, teams); err != nil { 26 t.Errorf("cleaning up after admin tests: %v", err) 27 } 28 }) 29 30 t.Run("get admin panel html", func(t *testing.T) { 31 resp, err := server.Client().Get(fmt.Sprintf("%v/admin", server.URL)) 32 if err != nil { 33 t.Error(err) 34 } 35 defer resp.Body.Close() 36 37 if resp.StatusCode != http.StatusOK { 38 t.Errorf("Status code is %v, should be %v", resp.StatusCode, http.StatusOK) 39 } 40 41 if resp.Header.Get("Content-Type") != htmlContentType { 42 t.Errorf("Content-Type header is %v, should be %v", resp.Header.Get("Content-Type"), htmlContentType) 43 } 44 45 received, err := io.ReadAll(resp.Body) 46 if err != nil { 47 t.Error(err) 48 } 49 receivedMinimized, err := minimizeHTML(string(received)) 50 if err != nil { 51 t.Error(err) 52 } 53 54 eventsTeamA, err := repo.EventsByOwnerGet(ctx, teams[0].ID, 1) 55 if err != nil { 56 t.Error(err) 57 } 58 59 eventsTeamB, err := repo.EventsByOwnerGet(ctx, teams[1].ID, 1) 60 if err != nil { 61 t.Error(err) 62 } 63 64 expected, err := createExpectedHTML("admin/index", map[string]any{ 65 "teams": []teamInfo{ 66 { 67 Team: teams[0], 68 Namespace: k8s.TeamIDToNamespace(teams[0].ID), 69 Apps: []gensql.ChartType{ 70 gensql.ChartTypeJupyterhub, 71 }, 72 Events: eventsTeamA, 73 }, 74 { 75 Team: teams[1], 76 Namespace: k8s.TeamIDToNamespace(teams[1].ID), 77 Apps: []gensql.ChartType{ 78 gensql.ChartTypeJupyterhub, 79 gensql.ChartTypeAirflow, 80 }, 81 Events: eventsTeamB, 82 }, 83 }, 84 }) 85 if err != nil { 86 t.Error(err) 87 } 88 expectedMinimized, err := minimizeHTML(expected) 89 if err != nil { 90 t.Error(err) 91 } 92 93 if diff := cmp.Diff(expectedMinimized, receivedMinimized); diff != "" { 94 t.Errorf("mismatch (-want +got):\n%s", diff) 95 } 96 }) 97 98 t.Run("get admin panel jupyter values html", func(t *testing.T) { 99 resp, err := server.Client().Get(fmt.Sprintf("%v/admin/jupyterhub", server.URL)) 100 if err != nil { 101 t.Error(err) 102 } 103 defer resp.Body.Close() 104 105 if resp.StatusCode != http.StatusOK { 106 t.Errorf("Status code is %v, should be %v", resp.StatusCode, http.StatusOK) 107 } 108 109 if resp.Header.Get("Content-Type") != htmlContentType { 110 t.Errorf("Content-Type header is %v, should be %v", resp.Header.Get("Content-Type"), htmlContentType) 111 } 112 113 received, err := io.ReadAll(resp.Body) 114 if err != nil { 115 t.Error(err) 116 } 117 receivedMinimized, err := minimizeHTML(string(received)) 118 if err != nil { 119 t.Error(err) 120 } 121 122 expected, err := createExpectedHTML("admin/chart", map[string]any{ 123 "chart": string(gensql.ChartTypeJupyterhub), 124 "values": []gensql.ChartGlobalValue{ 125 { 126 Key: "jupytervalue", 127 Value: "value", 128 }, 129 }, 130 }) 131 if err != nil { 132 t.Error(err) 133 } 134 expectedMinimized, err := minimizeHTML(expected) 135 if err != nil { 136 t.Error(err) 137 } 138 139 if diff := cmp.Diff(expectedMinimized, receivedMinimized); diff != "" { 140 t.Errorf("mismatch (-want +got):\n%s", diff) 141 } 142 }) 143 144 t.Run("update jupyter global values get confirm html", func(t *testing.T) { 145 // Disable automatic redirect. For the test we need to add the session cookie to the subsequent GET request for the confirm html manually 146 server.Client().CheckRedirect = func(req *http.Request, via []*http.Request) error { 147 return http.ErrUseLastResponse 148 } 149 t.Cleanup(func() { 150 server.Client().CheckRedirect = nil 151 }) 152 153 data := url.Values{"jupytervalue": {"updated"}, "key.0": {"new"}, "value.0": {"new"}} 154 resp, err := server.Client().PostForm(fmt.Sprintf("%v/admin/jupyterhub", server.URL), data) 155 if err != nil { 156 t.Error(err) 157 } 158 defer resp.Body.Close() 159 160 if resp.StatusCode != http.StatusSeeOther { 161 t.Errorf("Status code is %v, should be %v", resp.StatusCode, http.StatusSeeOther) 162 } 163 164 sessionCookie, err := getSessionCookieFromResponse(resp) 165 if err != nil { 166 t.Error(err) 167 } 168 169 req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%v/admin/jupyterhub/confirm", server.URL), nil) 170 if err != nil { 171 t.Error(err) 172 } 173 req.AddCookie(sessionCookie) 174 resp, err = server.Client().Do(req) 175 if err != nil { 176 t.Error(err) 177 } 178 defer resp.Body.Close() 179 180 if resp.StatusCode != http.StatusOK { 181 t.Errorf("Status code is %v, should be %v", resp.StatusCode, http.StatusOK) 182 } 183 184 received, err := io.ReadAll(resp.Body) 185 if err != nil { 186 t.Error(err) 187 } 188 receivedMinimized, err := minimizeHTML(string(received)) 189 if err != nil { 190 t.Error(err) 191 } 192 193 expected, err := createExpectedHTML("admin/confirm", map[string]any{ 194 "chart": string(gensql.ChartTypeJupyterhub), 195 "changedValues": []map[string]diffValue{ 196 { 197 "jupytervalue": { 198 Old: "value", 199 New: "updated", 200 }, 201 "new": { 202 New: "new", 203 }, 204 }, 205 }, 206 }) 207 if err != nil { 208 t.Error(err) 209 } 210 expectedMinimized, err := minimizeHTML(expected) 211 if err != nil { 212 t.Error(err) 213 } 214 215 if diff := cmp.Diff(expectedMinimized, receivedMinimized); diff != "" { 216 t.Errorf("mismatch (-want +got):\n%s", diff) 217 } 218 }) 219 220 t.Run("update jupyter global values", func(t *testing.T) { 221 oldEvents, err := repo.EventsGetType(ctx, database.EventTypeUpdateJupyter) 222 if err != nil { 223 t.Error(err) 224 } 225 226 data := url.Values{"jupytervalue": {"updated"}, "new": {"new"}} 227 resp, err := server.Client().PostForm(fmt.Sprintf("%v/admin/jupyterhub/confirm", server.URL), data) 228 if err != nil { 229 t.Error(err) 230 } 231 defer resp.Body.Close() 232 233 if resp.StatusCode != http.StatusOK { 234 t.Errorf("Status code is %v, should be %v", resp.StatusCode, http.StatusOK) 235 } 236 237 events, err := repo.EventsGetType(ctx, database.EventTypeUpdateJupyter) 238 if err != nil { 239 t.Error(err) 240 } 241 242 newEvents := getNewEvents(oldEvents, events) 243 for _, team := range teams { 244 eventPayload, err := getEventForJupyterhub(newEvents, team.ID) 245 if err != nil { 246 t.Error(err) 247 } 248 249 if eventPayload.TeamID == "" { 250 t.Errorf("update admin values: no update jupyterhub event registered for team %v", team.ID) 251 } 252 } 253 }) 254 255 t.Run("sync jupyterhub chart for team", func(t *testing.T) { 256 oldEvents, err := repo.EventsGetType(ctx, database.EventTypeUpdateJupyter) 257 if err != nil { 258 t.Error(err) 259 } 260 261 data := url.Values{"team": {"team-a-1234"}} 262 resp, err := server.Client().PostForm(fmt.Sprintf("%v/admin/jupyterhub/sync", server.URL), data) 263 if err != nil { 264 t.Error(err) 265 } 266 defer resp.Body.Close() 267 268 if resp.StatusCode != http.StatusOK { 269 t.Errorf("Status code is %v, should be %v", resp.StatusCode, http.StatusOK) 270 } 271 272 events, err := repo.EventsGetType(ctx, database.EventTypeUpdateJupyter) 273 if err != nil { 274 t.Error(err) 275 } 276 277 newEvents := getNewEvents(oldEvents, events) 278 eventPayload, err := getEventForJupyterhub(newEvents, teams[0].ID) 279 if err != nil { 280 t.Error(err) 281 } 282 283 if eventPayload.TeamID == "" { 284 t.Errorf("sync chart: no update jupyterhub event registered for team %v", teams[1].ID) 285 } 286 }) 287 288 t.Run("sync all jupyterhub charts", func(t *testing.T) { 289 oldEvents, err := repo.EventsGetType(ctx, database.EventTypeUpdateJupyter) 290 if err != nil { 291 t.Error(err) 292 } 293 294 resp, err := server.Client().PostForm(fmt.Sprintf("%v/admin/jupyterhub/sync/all", server.URL), nil) 295 if err != nil { 296 t.Error(err) 297 } 298 defer resp.Body.Close() 299 300 if resp.StatusCode != http.StatusOK { 301 t.Errorf("Status code is %v, should be %v", resp.StatusCode, http.StatusOK) 302 } 303 304 events, err := repo.EventsGetType(ctx, database.EventTypeUpdateJupyter) 305 if err != nil { 306 t.Error(err) 307 } 308 309 newEvents := getNewEvents(oldEvents, events) 310 for _, team := range teams { 311 eventPayload, err := getEventForJupyterhub(newEvents, team.ID) 312 if err != nil { 313 t.Error(err) 314 } 315 316 if eventPayload.TeamID == "" { 317 t.Errorf("sync all jupyterhub charts: no update jupyterhub event registered for team %v", team.ID) 318 } 319 } 320 }) 321 322 t.Run("get admin panel airflow values html", func(t *testing.T) { 323 resp, err := server.Client().Get(fmt.Sprintf("%v/admin/airflow", server.URL)) 324 if err != nil { 325 t.Error(err) 326 } 327 defer resp.Body.Close() 328 329 if resp.StatusCode != http.StatusOK { 330 t.Errorf("Status code is %v, should be %v", resp.StatusCode, http.StatusOK) 331 } 332 333 if resp.Header.Get("Content-Type") != htmlContentType { 334 t.Errorf("Content-Type header is %v, should be %v", resp.Header.Get("Content-Type"), htmlContentType) 335 } 336 337 received, err := io.ReadAll(resp.Body) 338 if err != nil { 339 t.Error(err) 340 } 341 receivedMinimized, err := minimizeHTML(string(received)) 342 if err != nil { 343 t.Error(err) 344 } 345 346 expected, err := createExpectedHTML("admin/chart", map[string]any{ 347 "chart": string(gensql.ChartTypeAirflow), 348 "values": []gensql.ChartGlobalValue{ 349 { 350 Key: "airflowvalue", 351 Value: "value", 352 }, 353 }, 354 }) 355 if err != nil { 356 t.Error(err) 357 } 358 expectedMinimized, err := minimizeHTML(expected) 359 if err != nil { 360 t.Error(err) 361 } 362 363 if diff := cmp.Diff(expectedMinimized, receivedMinimized); diff != "" { 364 t.Errorf("mismatch (-want +got):\n%s", diff) 365 } 366 }) 367 368 t.Run("update airflow global values", func(t *testing.T) { 369 // Disable automatic redirect. For the test we need to add the session cookie to the subsequent GET request for the confirm html manually 370 server.Client().CheckRedirect = func(req *http.Request, via []*http.Request) error { 371 return http.ErrUseLastResponse 372 } 373 t.Cleanup(func() { 374 server.Client().CheckRedirect = nil 375 }) 376 377 data := url.Values{"airflowvalue": {"updated"}, "key.0": {"new"}, "value.0": {"new"}} 378 resp, err := server.Client().PostForm(fmt.Sprintf("%v/admin/airflow", server.URL), data) 379 if err != nil { 380 t.Error(err) 381 } 382 defer resp.Body.Close() 383 384 if resp.StatusCode != http.StatusSeeOther { 385 t.Errorf("Status code is %v, should be %v", resp.StatusCode, http.StatusSeeOther) 386 } 387 388 sessionCookie, err := getSessionCookieFromResponse(resp) 389 if err != nil { 390 t.Error(err) 391 } 392 393 req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%v/admin/airflow/confirm", server.URL), nil) 394 if err != nil { 395 t.Error(err) 396 } 397 req.AddCookie(sessionCookie) 398 resp, err = server.Client().Do(req) 399 if err != nil { 400 t.Error(err) 401 } 402 defer resp.Body.Close() 403 404 if resp.StatusCode != http.StatusOK { 405 t.Errorf("Status code is %v, should be %v", resp.StatusCode, http.StatusOK) 406 } 407 408 received, err := io.ReadAll(resp.Body) 409 if err != nil { 410 t.Error(err) 411 } 412 receivedMinimized, err := minimizeHTML(string(received)) 413 if err != nil { 414 t.Error(err) 415 } 416 417 expected, err := createExpectedHTML("admin/confirm", map[string]any{ 418 "chart": string(gensql.ChartTypeAirflow), 419 "changedValues": []map[string]diffValue{ 420 { 421 "airflowvalue": { 422 Old: "value", 423 New: "updated", 424 }, 425 "new": { 426 New: "new", 427 }, 428 }, 429 }, 430 }) 431 if err != nil { 432 t.Error(err) 433 } 434 expectedMinimized, err := minimizeHTML(expected) 435 if err != nil { 436 t.Error(err) 437 } 438 439 if diff := cmp.Diff(expectedMinimized, receivedMinimized); diff != "" { 440 t.Errorf("mismatch (-want +got):\n%s", diff) 441 } 442 }) 443 444 t.Run("update airflow global values", func(t *testing.T) { 445 oldEvents, err := repo.EventsGetType(ctx, database.EventTypeUpdateAirflow) 446 if err != nil { 447 t.Error(err) 448 } 449 450 data := url.Values{"airflowvalue": {"updated"}, "new": {"new"}} 451 resp, err := server.Client().PostForm(fmt.Sprintf("%v/admin/airflow/confirm", server.URL), data) 452 if err != nil { 453 t.Error(err) 454 } 455 defer resp.Body.Close() 456 457 if resp.StatusCode != http.StatusOK { 458 t.Errorf("Status code is %v, should be %v", resp.StatusCode, http.StatusOK) 459 } 460 461 events, err := repo.EventsGetType(ctx, database.EventTypeUpdateAirflow) 462 if err != nil { 463 t.Error(err) 464 } 465 466 newEvents := getNewEvents(oldEvents, events) 467 eventPayload, err := getEventForAirflow(newEvents, teams[1].ID) 468 if err != nil { 469 t.Error(err) 470 } 471 472 if eventPayload.TeamID == "" { 473 t.Errorf("update airflow global values: no update airflow event registered for team %v", teams[1].ID) 474 } 475 }) 476 477 t.Run("sync airflow chart for team", func(t *testing.T) { 478 oldEvents, err := repo.EventsGetType(ctx, database.EventTypeUpdateAirflow) 479 if err != nil { 480 t.Error(err) 481 } 482 483 data := url.Values{"team": {"team-b-1234"}} 484 resp, err := server.Client().PostForm(fmt.Sprintf("%v/admin/airflow/sync", server.URL), data) 485 if err != nil { 486 t.Error(err) 487 } 488 defer resp.Body.Close() 489 490 if resp.StatusCode != http.StatusOK { 491 t.Errorf("Status code is %v, should be %v", resp.StatusCode, http.StatusOK) 492 } 493 494 events, err := repo.EventsGetType(ctx, database.EventTypeUpdateAirflow) 495 if err != nil { 496 t.Error(err) 497 } 498 499 newEvents := getNewEvents(oldEvents, events) 500 eventPayload, err := getEventForAirflow(newEvents, teams[1].ID) 501 if err != nil { 502 t.Error(err) 503 } 504 505 if eventPayload.TeamID == "" { 506 t.Errorf("sync airflow chart for team: no update airflow event registered for team %v", teams[1].ID) 507 } 508 }) 509 510 t.Run("sync all airflow charts", func(t *testing.T) { 511 oldEvents, err := repo.EventsGetType(ctx, database.EventTypeUpdateAirflow) 512 if err != nil { 513 t.Error(err) 514 } 515 516 resp, err := server.Client().PostForm(fmt.Sprintf("%v/admin/airflow/sync/all", server.URL), nil) 517 if err != nil { 518 t.Error(err) 519 } 520 defer resp.Body.Close() 521 522 if resp.StatusCode != http.StatusOK { 523 t.Errorf("Status code is %v, should be %v", resp.StatusCode, http.StatusOK) 524 } 525 526 events, err := repo.EventsGetType(ctx, database.EventTypeUpdateAirflow) 527 if err != nil { 528 t.Error(err) 529 } 530 531 newEvents := getNewEvents(oldEvents, events) 532 eventPayload, err := getEventForAirflow(newEvents, teams[0].ID) 533 if err != nil { 534 t.Error(err) 535 } 536 if eventPayload.TeamID != "" { 537 t.Errorf("sync all airflow charts: airflow event registered for team %v eventhough team does not have airflow", teams[0].ID) 538 } 539 540 eventPayload, err = getEventForAirflow(newEvents, teams[1].ID) 541 if err != nil { 542 t.Error(err) 543 } 544 if eventPayload.TeamID == "" { 545 t.Errorf("sync all airflow charts: no update airflow event registered for team %v", teams[1].ID) 546 } 547 }) 548 549 t.Run("sync all teams", func(t *testing.T) { 550 oldEvents, err := repo.EventsGetType(ctx, database.EventTypeUpdateTeam) 551 if err != nil { 552 t.Error(err) 553 } 554 555 resp, err := server.Client().PostForm(fmt.Sprintf("%v/admin/team/sync/all", server.URL), nil) 556 if err != nil { 557 t.Error(err) 558 } 559 defer resp.Body.Close() 560 561 if resp.StatusCode != http.StatusOK { 562 t.Errorf("Status code is %v, should be %v", resp.StatusCode, http.StatusOK) 563 } 564 565 events, err := repo.EventsGetType(ctx, database.EventTypeUpdateTeam) 566 if err != nil { 567 t.Error(err) 568 } 569 570 newEvents := getNewEvents(oldEvents, events) 571 for _, team := range teams { 572 eventPayload, err := getEventForTeam(newEvents, team.Slug) 573 if err != nil { 574 t.Error(err) 575 } 576 if eventPayload.ID == "" { 577 t.Errorf("sync all teams: no update team event registered for team %v", team.Slug) 578 } 579 } 580 }) 581 582 t.Run("delete team", func(t *testing.T) { 583 team := gensql.Team{ 584 ID: "delete-me-1234", 585 Slug: "delete-me", 586 Users: []string{testUser.Email}, 587 } 588 if err := repo.TeamCreate(ctx, team); err != nil { 589 t.Error(err) 590 } 591 t.Cleanup(func() { 592 if err := repo.TeamDelete(ctx, team.ID); err != nil { 593 t.Error(err) 594 } 595 }) 596 597 resp, err := server.Client().PostForm(fmt.Sprintf("%v/admin/team/%v/delete", server.URL, team.Slug), nil) 598 if err != nil { 599 t.Error(err) 600 } 601 resp.Body.Close() 602 603 if resp.StatusCode != http.StatusOK { 604 t.Errorf("delete team: expected status code 200, got %v", resp.StatusCode) 605 } 606 607 events, err := repo.EventsGetType(ctx, database.EventTypeDeleteTeam) 608 if err != nil { 609 t.Error(err) 610 } 611 612 if !deleteEventCreatedForTeam(events, team.ID) { 613 t.Errorf("delete team: no event registered for team %v", team.ID) 614 } 615 }) 616 617 t.Run("get event html", func(t *testing.T) { 618 events, err := repo.EventsByOwnerGet(ctx, teams[0].ID, 1) 619 if err != nil { 620 t.Error(err) 621 } 622 if len(events) == 0 { 623 t.Errorf("get event html: no event found for team %v", teams[0].ID) 624 } 625 626 resp, err := server.Client().Get(fmt.Sprintf("%v/admin/event/%v", server.URL, events[0].ID)) 627 if err != nil { 628 t.Error(err) 629 } 630 defer resp.Body.Close() 631 632 if resp.StatusCode != http.StatusOK { 633 t.Errorf("Status code is %v, should be %v", resp.StatusCode, http.StatusOK) 634 } 635 636 if resp.Header.Get("Content-Type") != htmlContentType { 637 t.Errorf("Content-Type header is %v, should be %v", resp.Header.Get("Content-Type"), htmlContentType) 638 } 639 640 received, err := io.ReadAll(resp.Body) 641 if err != nil { 642 t.Error(err) 643 } 644 receivedMinimized, err := minimizeHTML(string(received)) 645 if err != nil { 646 t.Error(err) 647 } 648 649 expected, err := createExpectedHTML("admin/event", map[string]any{ 650 "event": events[0], 651 }) 652 if err != nil { 653 t.Error(err) 654 } 655 expectedMinimized, err := minimizeHTML(expected) 656 if err != nil { 657 t.Error(err) 658 } 659 660 if diff := cmp.Diff(expectedMinimized, receivedMinimized); diff != "" { 661 t.Errorf("mismatch (-want +got):\n%s", diff) 662 } 663 }) 664 665 t.Run("update event status", func(t *testing.T) { 666 newStatus := "manual_failed" 667 events, err := repo.EventsByOwnerGet(ctx, teams[0].ID, 1) 668 if err != nil { 669 t.Error(err) 670 } 671 if len(events) == 0 { 672 t.Errorf("get event html: no event found for team %v", teams[0].ID) 673 } 674 675 values := url.Values{"status": {newStatus}} 676 resp, err := server.Client().PostForm(fmt.Sprintf("%v/admin/event/%v", server.URL, events[0].ID), values) 677 if err != nil { 678 t.Error(err) 679 } 680 defer resp.Body.Close() 681 682 if resp.StatusCode != http.StatusOK { 683 t.Errorf("Status code is %v, should be %v", resp.StatusCode, http.StatusOK) 684 } 685 686 if resp.Header.Get("Content-Type") != htmlContentType { 687 t.Errorf("Content-Type header is %v, should be %v", resp.Header.Get("Content-Type"), htmlContentType) 688 } 689 690 received, err := io.ReadAll(resp.Body) 691 if err != nil { 692 t.Error(err) 693 } 694 receivedMinimized, err := minimizeHTML(string(received)) 695 if err != nil { 696 t.Error(err) 697 } 698 699 events, err = repo.EventsByOwnerGet(ctx, teams[0].ID, 1) 700 if err != nil { 701 t.Error(err) 702 } 703 704 event := events[0] 705 if newStatus != event.Status { 706 t.Errorf("expected status %v, got %s", newStatus, event.Status) 707 } 708 709 expected, err := createExpectedHTML("admin/event", map[string]any{ 710 "event": event, 711 }) 712 if err != nil { 713 t.Error(err) 714 } 715 expectedMinimized, err := minimizeHTML(expected) 716 if err != nil { 717 t.Error(err) 718 } 719 720 if diff := cmp.Diff(expectedMinimized, receivedMinimized); diff != "" { 721 t.Errorf("mismatch (-want +got):\n%s", diff) 722 } 723 }) 724 } 725 726 func prepareAdminTests(ctx context.Context) ([]gensql.Team, error) { 727 // teams 728 teamA := gensql.Team{ 729 ID: "team-a-1234", 730 Slug: "team-a", 731 Users: []string{testUser.Email, "user.one@nav.no"}, 732 } 733 err := repo.TeamCreate(ctx, teamA) 734 if err != nil { 735 return nil, err 736 } 737 if err := createChart(ctx, teamA.ID, gensql.ChartTypeJupyterhub); err != nil { 738 return nil, err 739 } 740 741 teamB := gensql.Team{ 742 ID: "team-b-1234", 743 Slug: "team-b", 744 Users: []string{testUser.Email, "user.one@nav.no", "user.two@nav.no"}, 745 } 746 err = repo.TeamCreate(ctx, teamB) 747 if err != nil { 748 return nil, err 749 } 750 if err := createChart(ctx, teamB.ID, gensql.ChartTypeJupyterhub); err != nil { 751 return nil, err 752 } 753 if err := createChart(ctx, teamB.ID, gensql.ChartTypeAirflow); err != nil { 754 return nil, err 755 } 756 757 _, err = db.Exec("DELETE FROM chart_global_values") 758 if err != nil { 759 return nil, err 760 } 761 762 if err := repo.GlobalChartValueInsert(ctx, "jupytervalue", "value", false, gensql.ChartTypeJupyterhub); err != nil { 763 return nil, err 764 } 765 if err := repo.GlobalChartValueInsert(ctx, "airflowvalue", "value", false, gensql.ChartTypeAirflow); err != nil { 766 return nil, err 767 } 768 769 // events 770 if err := repo.RegisterCreateTeamEvent(ctx, teamA); err != nil { 771 return nil, err 772 } 773 if err := repo.RegisterCreateTeamEvent(ctx, teamB); err != nil { 774 return nil, err 775 } 776 777 return []gensql.Team{teamA, teamB}, nil 778 } 779 780 func createChart(ctx context.Context, teamID string, chartType gensql.ChartType) error { 781 return repo.TeamValueInsert(ctx, chartType, "dummy", "dummy", teamID) 782 } 783 784 func getSessionCookieFromResponse(resp *http.Response) (*http.Cookie, error) { 785 for _, cookie := range resp.Cookies() { 786 if cookie.Name == "session" { 787 return cookie, nil 788 } 789 } 790 791 return nil, errors.New("no session cookie in http response") 792 } 793 794 func cleanUpAdminTests(ctx context.Context, teams []gensql.Team) error { 795 for _, team := range teams { 796 if err := repo.TeamDelete(ctx, team.ID); err != nil { 797 return err 798 } 799 } 800 801 if err := repo.GlobalValueDelete(ctx, "jupytervalue", gensql.ChartTypeJupyterhub); err != nil { 802 return err 803 } 804 if err := repo.GlobalValueDelete(ctx, "airflowvalue", gensql.ChartTypeAirflow); err != nil { 805 return err 806 } 807 808 return nil 809 } 810 811 func getNewEvents(oldEvents, events []gensql.Event) []gensql.Event { 812 var new []gensql.Event 813 for _, event := range events { 814 if !containsEvent(oldEvents, event) { 815 new = append(new, event) 816 } 817 } 818 819 return new 820 } 821 822 func containsEvent(events []gensql.Event, event gensql.Event) bool { 823 for _, oldEvent := range events { 824 if oldEvent.ID == event.ID { 825 return true 826 } 827 } 828 829 return false 830 }