sigs.k8s.io/prow@v0.0.0-20240503223140-c5e374dc7eb1/pkg/pluginhelp/hook/hook_test.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package hook 18 19 import ( 20 "fmt" 21 "net/http" 22 "net/http/httptest" 23 "reflect" 24 "sort" 25 "testing" 26 27 "github.com/sirupsen/logrus" 28 29 "k8s.io/apimachinery/pkg/util/sets" 30 prowconfig "sigs.k8s.io/prow/pkg/config" 31 "sigs.k8s.io/prow/pkg/github" 32 "sigs.k8s.io/prow/pkg/pluginhelp" 33 "sigs.k8s.io/prow/pkg/pluginhelp/externalplugins" 34 "sigs.k8s.io/prow/pkg/plugins" 35 ) 36 37 type fakeGitHubClient map[string][]string 38 39 func (fghc fakeGitHubClient) GetRepos(org string, _ bool) ([]github.Repo, error) { 40 var repos []github.Repo 41 for _, repo := range fghc[org] { 42 repos = append(repos, github.Repo{FullName: fmt.Sprintf("%s/%s", org, repo)}) 43 } 44 return repos, nil 45 } 46 47 type fakePluginAgent plugins.Configuration 48 49 func (fpa fakePluginAgent) Config() *plugins.Configuration { 50 config := plugins.Configuration(fpa) 51 return &config 52 } 53 54 func TestGeneratePluginHelp(t *testing.T) { 55 orgToRepos := map[string][]string{"org1": {"repo1", "repo2", "repo3"}, "org2": {"repo1"}} 56 fghc := fakeGitHubClient(orgToRepos) 57 58 normalHelp := map[string]pluginhelp.PluginHelp{ 59 "org-plugin": {Description: "org-plugin", Config: map[string]string{"": "overall config"}}, 60 "repo-plugin1": { 61 Description: "repo-plugin1", 62 Config: map[string]string{ 63 "org1/repo1": "repo1 config", 64 "org1/repo2": "repo2 config", 65 }, 66 }, 67 "repo-plugin2": {Description: "repo-plugin2", Config: map[string]string{}}, 68 "repo-plugin3": {Description: "repo-plugin3", Config: map[string]string{}}, 69 } 70 helpfulExternalHelp := pluginhelp.PluginHelp{Description: "helpful-external"} 71 noHelpSever := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 72 http.Error(w, "404 Not Found", http.StatusNotFound) 73 })) 74 defer noHelpSever.Close() 75 mux := http.NewServeMux() 76 externalplugins.ServeExternalPluginHelp( 77 mux, 78 logrus.WithField("plugin", "helpful-external"), 79 func(enabledRepos []prowconfig.OrgRepo) (*pluginhelp.PluginHelp, error) { 80 if got, expected := enabledRepos, []prowconfig.OrgRepo{{Org: "org1", Repo: "repo1"}}; !reflect.DeepEqual(got, expected) { 81 t.Errorf("Plugin 'helpful-external' expected to be enabled on repos %q, but got %q.", expected, got) 82 } 83 return &helpfulExternalHelp, nil 84 }, 85 ) 86 helpfulServer := httptest.NewServer(mux) 87 defer helpfulServer.Close() 88 89 config := &plugins.Configuration{ 90 Plugins: plugins.Plugins{ 91 "org1": {Plugins: []string{"org-plugin"}}, 92 "org1/repo1": {Plugins: []string{"repo-plugin1", "no-help-plugin"}}, 93 "org1/repo2": {Plugins: []string{"repo-plugin1", "repo-plugin2"}}, 94 "org2/repo1": {Plugins: []string{"repo-plugin3"}}, 95 }, 96 ExternalPlugins: map[string][]plugins.ExternalPlugin{ 97 "org1/repo1": { 98 {Name: "no-endpoint-external", Endpoint: "http://no-endpoint-external", Events: []string{"issue_comment"}}, 99 {Name: "no-help-external", Endpoint: noHelpSever.URL, Events: []string{"issue_comment"}}, 100 {Name: "helpful-external", Endpoint: helpfulServer.URL, Events: []string{"pull_request", "issue"}}, 101 }, 102 }, 103 } 104 fpa := fakePluginAgent(*config) 105 106 expectedAllRepos := []string{"org1/repo1", "org1/repo2", "org1/repo3", "org2/repo1"} 107 108 normalExpectedReposForPlugin := map[string][]string{ 109 "org-plugin": {"org1/repo1", "org1/repo2", "org1/repo3"}, 110 "repo-plugin1": {"org1/repo1", "org1/repo2"}, 111 "repo-plugin2": {"org1/repo2"}, 112 "repo-plugin3": {"org2/repo1"}, 113 "no-help-plugin": {"org1/repo1"}, 114 } 115 normalExpectedPluginsForRepo := map[string][]string{ 116 "": {"org-plugin", "repo-plugin1", "repo-plugin2", "repo-plugin3", "no-help-plugin"}, 117 "org1": {"org-plugin"}, 118 "org1/repo1": {"repo-plugin1", "no-help-plugin"}, 119 "org1/repo2": {"repo-plugin1", "repo-plugin2"}, 120 "org2/repo1": {"repo-plugin3"}, 121 } 122 normalExpectedEvents := map[string][]string{ 123 "org-plugin": {"issue_comment"}, 124 "repo-plugin1": {"issue"}, 125 "repo-plugin2": {"pull_request"}, 126 "repo-plugin3": {"pull_request_review", "pull_request_review_comment"}, 127 "no-help-plugin": {"issue_comment"}, 128 } 129 130 externalExpectedPluginsForRepo := map[string][]string{ 131 "": {"no-endpoint-external", "no-help-external", "helpful-external"}, 132 "org1/repo1": {"no-endpoint-external", "no-help-external", "helpful-external"}, 133 } 134 externalExpectedEvents := map[string][]string{ 135 "no-endpoint-external": {"issue_comment"}, 136 "no-help-external": {"issue_comment"}, 137 "helpful-external": {"pull_request", "issue"}, 138 } 139 140 registerNormalPlugins(t, normalExpectedEvents, normalHelp, normalExpectedReposForPlugin) 141 142 help := NewHelpAgent(fpa, fghc).GeneratePluginHelp() 143 if help == nil { 144 t.Fatal("NewHelpAgent returned nil HelpAgent struct pointer.") 145 } 146 if got, expected := sets.New[string](help.AllRepos...), sets.New[string](expectedAllRepos...); !got.Equal(expected) { 147 t.Errorf("Expected 'AllRepos' to be %q, but got %q.", sets.List(expected), sets.List(got)) 148 } 149 checkPluginsForRepo := func(expected, got map[string][]string) { 150 for _, plugins := range expected { 151 sort.Strings(plugins) 152 } 153 for _, plugins := range got { 154 sort.Strings(plugins) 155 } 156 if !reflect.DeepEqual(expected, got) { 157 t.Errorf("Expected repo->plugin map %v, but got %v.", expected, got) 158 } 159 } 160 checkPluginsForRepo(normalExpectedPluginsForRepo, help.RepoPlugins) 161 checkPluginsForRepo(externalExpectedPluginsForRepo, help.RepoExternalPlugins) 162 163 checkPluginHelp := func(plugin string, expected, got pluginhelp.PluginHelp, eventsForPlugin []string) { 164 sort.Strings(eventsForPlugin) 165 sort.Strings(got.Events) 166 if expected, got := eventsForPlugin, got.Events; !reflect.DeepEqual(expected, got) { 167 t.Errorf("Expected plugin '%s' to subscribe to events %q, but got %q.", plugin, expected, got) 168 } 169 // Events field is correct, everything else should match the input exactly. 170 got.Events = nil 171 if !reflect.DeepEqual(got, expected) { 172 t.Errorf("Expected plugin '%s' to have help: %v, but got %v.", plugin, expected, got) 173 } 174 } 175 176 for plugin, expected := range normalHelp { 177 checkPluginHelp(plugin, expected, help.PluginHelp[plugin], normalExpectedEvents[plugin]) 178 } 179 checkPluginHelp("helpful-external", helpfulExternalHelp, help.ExternalPluginHelp["helpful-external"], externalExpectedEvents["helpful-external"]) 180 } 181 182 func registerNormalPlugins(t *testing.T, pluginsToEvents map[string][]string, pluginHelp map[string]pluginhelp.PluginHelp, expectedRepos map[string][]string) { 183 for plugin, events := range pluginsToEvents { 184 plugin := plugin 185 helpProvider := func(_ *plugins.Configuration, enabledRepos []prowconfig.OrgRepo) (*pluginhelp.PluginHelp, error) { 186 if got, expected := sets.New[string](prowconfig.OrgReposToStrings(enabledRepos)...), sets.New[string](expectedRepos[plugin]...); !got.Equal(expected) { 187 t.Errorf("Plugin '%s' expected to be enabled on repos %q, but got %q.", plugin, sets.List(expected), sets.List(got)) 188 } 189 help := pluginHelp[plugin] 190 return &help, nil 191 } 192 for _, event := range events { 193 switch event { 194 case "issue_comment": 195 plugins.RegisterIssueCommentHandler(plugin, nil, helpProvider) 196 case "issue": 197 plugins.RegisterIssueHandler(plugin, nil, helpProvider) 198 case "pull_request": 199 plugins.RegisterPullRequestHandler(plugin, nil, helpProvider) 200 case "pull_request_review": 201 plugins.RegisterReviewEventHandler(plugin, nil, helpProvider) 202 case "pull_request_review_comment": 203 plugins.RegisterReviewCommentEventHandler(plugin, nil, helpProvider) 204 default: 205 t.Fatalf("Invalid test! Unknown event type '%s' for plugin '%s'.", event, plugin) 206 } 207 } 208 } 209 }