From 1a6e5719c31ee4b7475ce654ecc686b87426672d Mon Sep 17 00:00:00 2001 From: Hyeonmin Park Date: Fri, 7 Jan 2022 08:50:26 +0900 Subject: [PATCH] test: Add tests with self-hosted label for #953 (#1030) --- README.md | 2 +- .../horizontal_runner_autoscaler_webhook.go | 4 +- ...rizontal_runner_autoscaler_webhook_test.go | 139 ++++++++++++++++ ...ow_job_with_self_hosted_label_payload.json | 152 ++++++++++++++++++ 4 files changed, 294 insertions(+), 3 deletions(-) create mode 100644 controllers/testdata/org_webhook_workflow_job_with_self_hosted_label_payload.json diff --git a/README.md b/README.md index c06f9787..896846d7 100644 --- a/README.md +++ b/README.md @@ -616,7 +616,7 @@ spec: duration: "30m" ``` -This webhook requires you to explicitely set the labels in the RunnerDeployment / RunnerSet if you are using them in your workflow to match the agents (field `runs-on`). Only `self-hosted` will be considered as included by default. +This webhook requires you to explicitly set the labels in the RunnerDeployment / RunnerSet if you are using them in your workflow to match the agents (field `runs-on`). Only `self-hosted` will be considered as included by default. You can configure your GitHub webhook settings to only include `Workflows Job` events, so that it sends us three kinds of `workflow_job` events per a job run. diff --git a/controllers/horizontal_runner_autoscaler_webhook.go b/controllers/horizontal_runner_autoscaler_webhook.go index f2fabd24..3db381a7 100644 --- a/controllers/horizontal_runner_autoscaler_webhook.go +++ b/controllers/horizontal_runner_autoscaler_webhook.go @@ -662,7 +662,7 @@ HRA: continue } - // TODO labels related to OS and architecture needs to be explicitely declared or the current implementation will not be able to find them. + // TODO labels related to OS and architecture needs to be explicitly declared or the current implementation will not be able to find them. for _, l2 := range rs.Spec.Labels { if l == l2 { @@ -693,7 +693,7 @@ HRA: continue } - // TODO labels related to OS and architecture needs to be explicitely declared or the current implementation will not be able to find them. + // TODO labels related to OS and architecture needs to be explicitly declared or the current implementation will not be able to find them. for _, l2 := range rd.Spec.Template.Spec.Labels { if l == l2 { diff --git a/controllers/horizontal_runner_autoscaler_webhook_test.go b/controllers/horizontal_runner_autoscaler_webhook_test.go index 9027647e..7d31c854 100644 --- a/controllers/horizontal_runner_autoscaler_webhook_test.go +++ b/controllers/horizontal_runner_autoscaler_webhook_test.go @@ -253,6 +253,145 @@ func TestWebhookWorkflowJob(t *testing.T) { }) } +func TestWebhookWorkflowJobWithSelfHostedLabel(t *testing.T) { + setupTest := func() github.WorkflowJobEvent { + f, err := os.Open("testdata/org_webhook_workflow_job_with_self_hosted_label_payload.json") + if err != nil { + t.Fatalf("could not open the fixture: %s", err) + } + defer f.Close() + var e github.WorkflowJobEvent + if err := json.NewDecoder(f).Decode(&e); err != nil { + t.Fatalf("invalid json: %s", err) + } + + return e + } + t.Run("Successful", func(t *testing.T) { + e := setupTest() + hra := &actionsv1alpha1.HorizontalRunnerAutoscaler{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-name", + }, + Spec: actionsv1alpha1.HorizontalRunnerAutoscalerSpec{ + ScaleTargetRef: actionsv1alpha1.ScaleTargetRef{ + Name: "test-name", + }, + }, + } + + rd := &actionsv1alpha1.RunnerDeployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-name", + }, + Spec: actionsv1alpha1.RunnerDeploymentSpec{ + Template: actionsv1alpha1.RunnerTemplate{ + Spec: actionsv1alpha1.RunnerSpec{ + RunnerConfig: actionsv1alpha1.RunnerConfig{ + Organization: "MYORG", + Labels: []string{"label1"}, + }, + }, + }, + }, + } + + initObjs := []runtime.Object{hra, rd} + + testServerWithInitObjs(t, + "workflow_job", + &e, + 200, + "scaled test-name by 1", + initObjs, + ) + }) + t.Run("WrongLabels", func(t *testing.T) { + e := setupTest() + hra := &actionsv1alpha1.HorizontalRunnerAutoscaler{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-name", + }, + Spec: actionsv1alpha1.HorizontalRunnerAutoscalerSpec{ + ScaleTargetRef: actionsv1alpha1.ScaleTargetRef{ + Name: "test-name", + }, + }, + } + + rd := &actionsv1alpha1.RunnerDeployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-name", + }, + Spec: actionsv1alpha1.RunnerDeploymentSpec{ + Template: actionsv1alpha1.RunnerTemplate{ + Spec: actionsv1alpha1.RunnerSpec{ + RunnerConfig: actionsv1alpha1.RunnerConfig{ + Organization: "MYORG", + Labels: []string{"bad-label"}, + }, + }, + }, + }, + } + + initObjs := []runtime.Object{hra, rd} + + testServerWithInitObjs(t, + "workflow_job", + &e, + 200, + "no horizontalrunnerautoscaler to scale for this github event", + initObjs, + ) + }) + // This test verifies that the old way of matching labels doesn't work anymore + t.Run("OldLabels", func(t *testing.T) { + e := setupTest() + hra := &actionsv1alpha1.HorizontalRunnerAutoscaler{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-name", + }, + Spec: actionsv1alpha1.HorizontalRunnerAutoscalerSpec{ + ScaleTargetRef: actionsv1alpha1.ScaleTargetRef{ + Name: "test-name", + }, + }, + } + + rd := &actionsv1alpha1.RunnerDeployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-name", + }, + Spec: actionsv1alpha1.RunnerDeploymentSpec{ + Template: actionsv1alpha1.RunnerTemplate{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "label1": "label1", + }, + }, + Spec: actionsv1alpha1.RunnerSpec{ + RunnerConfig: actionsv1alpha1.RunnerConfig{ + Organization: "MYORG", + Labels: []string{"bad-label"}, + }, + }, + }, + }, + } + + initObjs := []runtime.Object{hra, rd} + + testServerWithInitObjs(t, + "workflow_job", + &e, + 200, + "no horizontalrunnerautoscaler to scale for this github event", + initObjs, + ) + }) +} + func TestGetRequest(t *testing.T) { hra := HorizontalRunnerAutoscalerGitHubWebhook{} request, _ := http.NewRequest(http.MethodGet, "/", nil) diff --git a/controllers/testdata/org_webhook_workflow_job_with_self_hosted_label_payload.json b/controllers/testdata/org_webhook_workflow_job_with_self_hosted_label_payload.json new file mode 100644 index 00000000..c70c84e8 --- /dev/null +++ b/controllers/testdata/org_webhook_workflow_job_with_self_hosted_label_payload.json @@ -0,0 +1,152 @@ +{ + "action": "queued", + "workflow_job": { + "id": 1234567890, + "run_id": 1234567890, + "run_url": "https://api.github.com/repos/MYORG/MYREPO/actions/runs/1234567890", + "node_id": "CR_kwDOGCados7e1x2g", + "head_sha": "1234567890123456789012345678901234567890", + "url": "https://api.github.com/repos/MYORG/MYREPO/actions/jobs/1234567890", + "html_url": "https://github.com/MYORG/MYREPO/runs/1234567890", + "status": "queued", + "conclusion": null, + "started_at": "2021-09-28T23:45:29Z", + "completed_at": null, + "name": "build", + "steps": [], + "check_run_url": "https://api.github.com/repos/MYORG/MYREPO/check-runs/1234567890", + "labels": [ + "self-hosted", + "label1" + ] + }, + "repository": { + "id": 1234567890, + "node_id": "ABCDEFGHIJKLMNOPQRSTUVWXYZ=", + "name": "MYREPO", + "full_name": "MYORG/MYREPO", + "private": true, + "owner": { + "login": "MYORG", + "id": 1234567890, + "node_id": "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "avatar_url": "https://avatars.githubusercontent.com/u/1234567890?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/MYORG", + "html_url": "https://github.com/MYORG", + "followers_url": "https://api.github.com/users/MYORG/followers", + "following_url": "https://api.github.com/users/MYORG/following{/other_user}", + "gists_url": "https://api.github.com/users/MYORG/gists{/gist_id}", + "starred_url": "https://api.github.com/users/MYORG/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/MYORG/subscriptions", + "organizations_url": "https://api.github.com/users/MYORG/orgs", + "repos_url": "https://api.github.com/users/MYORG/repos", + "events_url": "https://api.github.com/users/MYORG/events{/privacy}", + "received_events_url": "https://api.github.com/users/MYORG/received_events", + "type": "Organization", + "site_admin": false + }, + "html_url": "https://github.com/MYORG/MYREPO", + "description": "MYREPO", + "fork": false, + "url": "https://api.github.com/repos/MYORG/MYREPO", + "forks_url": "https://api.github.com/repos/MYORG/MYREPO/forks", + "keys_url": "https://api.github.com/repos/MYORG/MYREPO/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/MYORG/MYREPO/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/MYORG/MYREPO/teams", + "hooks_url": "https://api.github.com/repos/MYORG/MYREPO/hooks", + "issue_events_url": "https://api.github.com/repos/MYORG/MYREPO/issues/events{/number}", + "events_url": "https://api.github.com/repos/MYORG/MYREPO/events", + "assignees_url": "https://api.github.com/repos/MYORG/MYREPO/assignees{/user}", + "branches_url": "https://api.github.com/repos/MYORG/MYREPO/branches{/branch}", + "tags_url": "https://api.github.com/repos/MYORG/MYREPO/tags", + "blobs_url": "https://api.github.com/repos/MYORG/MYREPO/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/MYORG/MYREPO/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/MYORG/MYREPO/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/MYORG/MYREPO/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/MYORG/MYREPO/statuses/{sha}", + "languages_url": "https://api.github.com/repos/MYORG/MYREPO/languages", + "stargazers_url": "https://api.github.com/repos/MYORG/MYREPO/stargazers", + "contributors_url": "https://api.github.com/repos/MYORG/MYREPO/contributors", + "subscribers_url": "https://api.github.com/repos/MYORG/MYREPO/subscribers", + "subscription_url": "https://api.github.com/repos/MYORG/MYREPO/subscription", + "commits_url": "https://api.github.com/repos/MYORG/MYREPO/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/MYORG/MYREPO/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/MYORG/MYREPO/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/MYORG/MYREPO/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/MYORG/MYREPO/contents/{+path}", + "compare_url": "https://api.github.com/repos/MYORG/MYREPO/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/MYORG/MYREPO/merges", + "archive_url": "https://api.github.com/repos/MYORG/MYREPO/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/MYORG/MYREPO/downloads", + "issues_url": "https://api.github.com/repos/MYORG/MYREPO/issues{/number}", + "pulls_url": "https://api.github.com/repos/MYORG/MYREPO/pulls{/number}", + "milestones_url": "https://api.github.com/repos/MYORG/MYREPO/milestones{/number}", + "notifications_url": "https://api.github.com/repos/MYORG/MYREPO/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/MYORG/MYREPO/labels{/name}", + "releases_url": "https://api.github.com/repos/MYORG/MYREPO/releases{/id}", + "deployments_url": "https://api.github.com/repos/MYORG/MYREPO/deployments", + "created_at": "2021-09-10T18:55:38Z", + "updated_at": "2021-09-10T18:55:41Z", + "pushed_at": "2021-09-28T23:25:26Z", + "git_url": "git://github.com/MYORG/MYREPO.git", + "ssh_url": "git@github.com:MYORG/MYREPO.git", + "clone_url": "https://github.com/MYORG/MYREPO.git", + "svn_url": "https://github.com/MYORG/MYREPO", + "homepage": null, + "size": 121, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 1, + "license": null, + "allow_forking": false, + "forks": 0, + "open_issues": 1, + "watchers": 0, + "default_branch": "master" + }, + "organization": { + "login": "MYORG", + "id": 1234567890, + "node_id": "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "url": "https://api.github.com/orgs/MYORG", + "repos_url": "https://api.github.com/orgs/MYORG/repos", + "events_url": "https://api.github.com/orgs/MYORG/events", + "hooks_url": "https://api.github.com/orgs/MYORG/hooks", + "issues_url": "https://api.github.com/orgs/MYORG/issues", + "members_url": "https://api.github.com/orgs/MYORG/members{/member}", + "public_members_url": "https://api.github.com/orgs/MYORG/public_members{/member}", + "avatar_url": "https://avatars.githubusercontent.com/u/1234567890?v=4", + "description": "" + }, + "sender": { + "login": "MYNAME", + "id": 1234567890, + "node_id": "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "avatar_url": "https://avatars.githubusercontent.com/u/1234567890?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/MYNAME", + "html_url": "https://github.com/MYNAME", + "followers_url": "https://api.github.com/users/MYNAME/followers", + "following_url": "https://api.github.com/users/MYNAME/following{/other_user}", + "gists_url": "https://api.github.com/users/MYNAME/gists{/gist_id}", + "starred_url": "https://api.github.com/users/MYNAME/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/MYNAME/subscriptions", + "organizations_url": "https://api.github.com/users/MYNAME/orgs", + "repos_url": "https://api.github.com/users/MYNAME/repos", + "events_url": "https://api.github.com/users/MYNAME/events{/privacy}", + "received_events_url": "https://api.github.com/users/MYNAME/received_events", + "type": "User", + "site_admin": false + } +}