github.com/abayer/test-infra@v0.0.5/robots/commenter/main_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 main 18 19 import ( 20 "errors" 21 "fmt" 22 "k8s.io/test-infra/prow/github" 23 "strconv" 24 "strings" 25 "testing" 26 "time" 27 ) 28 29 func TestParseHTMLURL(t *testing.T) { 30 cases := []struct { 31 name string 32 url string 33 org string 34 repo string 35 num int 36 fail bool 37 }{ 38 { 39 name: "normal issue", 40 url: "https://github.com/org/repo/issues/1234", 41 org: "org", 42 repo: "repo", 43 num: 1234, 44 }, 45 { 46 name: "normal pull", 47 url: "https://github.com/pull-org/pull-repo/pull/5555", 48 org: "pull-org", 49 repo: "pull-repo", 50 num: 5555, 51 }, 52 { 53 name: "different host", 54 url: "ftp://gitlab.whatever/org/repo/issues/6666", 55 org: "org", 56 repo: "repo", 57 num: 6666, 58 }, 59 { 60 name: "string issue", 61 url: "https://github.com/org/repo/issues/future", 62 fail: true, 63 }, 64 { 65 name: "weird issue", 66 url: "https://k8s-gubernator.appspot.com/build/kubernetes-jenkins/logs/ci-kubernetes-e2e-gci-gce/11947/", 67 fail: true, 68 }, 69 } 70 71 for _, tc := range cases { 72 org, repo, num, err := parseHTMLURL(tc.url) 73 if err != nil && !tc.fail { 74 t.Errorf("%s: should not have produced error: %v", tc.name, err) 75 } else if err == nil && tc.fail { 76 t.Errorf("%s: failed to produce an error", tc.name) 77 } else { 78 if org != tc.org { 79 t.Errorf("%s: org %s != expected %s", tc.name, org, tc.org) 80 } 81 if repo != tc.repo { 82 t.Errorf("%s: repo %s != expected %s", tc.name, repo, tc.repo) 83 } 84 if num != tc.num { 85 t.Errorf("%s: num %d != expected %d", tc.name, num, tc.num) 86 } 87 } 88 } 89 } 90 91 func TestMakeQuery(t *testing.T) { 92 cases := []struct { 93 name string 94 query string 95 closed bool 96 dur time.Duration 97 expected []string 98 unexpected []string 99 err bool 100 }{ 101 { 102 name: "basic query", 103 query: "hello world", 104 expected: []string{"hello world", "is:open"}, 105 unexpected: []string{"updated:", "openhello", "worldis"}, 106 }, 107 { 108 name: "basic closed", 109 query: "hello world", 110 closed: true, 111 expected: []string{"hello world"}, 112 unexpected: []string{"is:open"}, 113 }, 114 { 115 name: "basic duration", 116 query: "hello", 117 dur: 1 * time.Hour, 118 expected: []string{"hello", "updated:<"}, 119 }, 120 { 121 name: "weird characters not escaped", 122 query: "oh yeah!@#$&*()", 123 expected: []string{"!", "@", "#", " "}, 124 unexpected: []string{"%", "+"}, 125 }, 126 { 127 name: "include closed with is:open query errors", 128 query: "hello is:open", 129 closed: true, 130 err: true, 131 }, 132 { 133 name: "is:closed without includeClosed", 134 query: "hello is:closed", 135 err: true, 136 }, 137 } 138 139 for _, tc := range cases { 140 actual, err := makeQuery(tc.query, tc.closed, tc.dur) 141 if err != nil && !tc.err { 142 t.Errorf("%s: unexpected error: %v", tc.name, err) 143 } else if err == nil && tc.err { 144 t.Errorf("%s: failed to raise an error", tc.name) 145 } 146 for _, e := range tc.expected { 147 if !strings.Contains(actual, e) { 148 t.Errorf("%s: could not find %s in %s", tc.name, e, actual) 149 } 150 } 151 for _, u := range tc.unexpected { 152 if strings.Contains(actual, u) { 153 t.Errorf("%s: should not have found %s in %s", tc.name, u, actual) 154 } 155 } 156 } 157 } 158 159 func makeIssue(owner, repo string, number int, title string) github.Issue { 160 return github.Issue{ 161 HTMLURL: fmt.Sprintf("fake://localhost/%s/%s/pull/%d", owner, repo, number), 162 Title: title, 163 } 164 } 165 166 type fakeClient struct { 167 comments []int 168 issues []github.Issue 169 } 170 171 // Fakes Creating a client, using the same signature as github.Client 172 func (c *fakeClient) CreateComment(owner, repo string, number int, comment string) error { 173 if strings.Contains(comment, "error") || repo == "error" { 174 return errors.New(comment) 175 } 176 c.comments = append(c.comments, number) 177 return nil 178 } 179 180 // Fakes searching for issues, using the same signature as github.Client 181 func (c *fakeClient) FindIssues(query, sort string, asc bool) ([]github.Issue, error) { 182 if strings.Contains(query, "error") { 183 return nil, errors.New(query) 184 } 185 ret := []github.Issue{} 186 for _, i := range c.issues { 187 if strings.Contains(i.Title, query) { 188 ret = append(ret, i) 189 } 190 } 191 return ret, nil 192 } 193 194 func TestRun(t *testing.T) { 195 manyIssues := []github.Issue{} 196 manyComments := []int{} 197 for i := 0; i < 100; i++ { 198 manyIssues = append(manyIssues, makeIssue("o", "r", i, "many "+strconv.Itoa(i))) 199 manyComments = append(manyComments, i) 200 } 201 202 cases := []struct { 203 name string 204 query string 205 comment string 206 template bool 207 ceiling int 208 client fakeClient 209 expected []int 210 err bool 211 }{ 212 { 213 name: "find all", 214 query: "many", 215 comment: "found you", 216 client: fakeClient{issues: manyIssues}, 217 expected: manyComments, 218 }, 219 { 220 name: "find first 10", 221 query: "many", 222 ceiling: 10, 223 comment: "hey", 224 client: fakeClient{issues: manyIssues}, 225 expected: []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 226 }, 227 { 228 name: "find none", 229 query: "none", 230 comment: "this should not happen", 231 client: fakeClient{issues: manyIssues}, 232 }, 233 { 234 name: "search error", 235 query: "this search should error", 236 comment: "comment", 237 client: fakeClient{issues: manyIssues}, 238 err: true, 239 }, 240 { 241 name: "comment error", 242 query: "problematic", 243 comment: "rolo tomassi", 244 client: fakeClient{issues: []github.Issue{ 245 makeIssue("o", "r", 1, "problematic this should work"), 246 makeIssue("o", "error", 2, "problematic expect an error"), 247 makeIssue("o", "r", 3, "problematic works as well"), 248 }}, 249 err: true, 250 expected: []int{1, 3}, 251 }, 252 { 253 name: "template comment", 254 query: "67", 255 client: fakeClient{issues: manyIssues}, 256 comment: "https://gubernator.k8s.io/pr/{{.Org}}/{{.Repo}}/{{.Number}}", 257 template: true, 258 expected: []int{67}, 259 }, 260 { 261 name: "bad template errors", 262 query: "67", 263 client: fakeClient{issues: manyIssues}, 264 comment: "Bad {{.UnknownField}}", 265 template: true, 266 err: true, 267 }, 268 } 269 270 for _, tc := range cases { 271 ignoreSorting := "" 272 ignoreOrder := false 273 err := run(&tc.client, tc.query, ignoreSorting, ignoreOrder, makeCommenter(tc.comment, tc.template), tc.ceiling) 274 if tc.err && err == nil { 275 t.Errorf("%s: failed to received an error", tc.name) 276 continue 277 } 278 if !tc.err && err != nil { 279 t.Errorf("%s: unexpected error: %v", tc.name, err) 280 continue 281 } 282 if len(tc.expected) != len(tc.client.comments) { 283 t.Errorf("%s: expected comments %v != actual %v", tc.name, tc.expected, tc.client.comments) 284 continue 285 } 286 missing := []int{} 287 for _, e := range tc.expected { 288 found := false 289 for _, cmt := range tc.client.comments { 290 if cmt == e { 291 found = true 292 break 293 } 294 } 295 if !found { 296 missing = append(missing, e) 297 } 298 } 299 if len(missing) > 0 { 300 t.Errorf("%s: missing %v from actual comments %v", tc.name, missing, tc.client.comments) 301 } 302 } 303 } 304 305 func TestMakeCommenter(t *testing.T) { 306 m := meta{ 307 Number: 10, 308 Org: "org", 309 Repo: "repo", 310 Issue: github.Issue{ 311 Number: 10, 312 HTMLURL: "url", 313 Title: "title", 314 }, 315 } 316 cases := []struct { 317 name string 318 comment string 319 template bool 320 expected string 321 err bool 322 }{ 323 { 324 name: "string works", 325 comment: "hello world {{.Number}} {{.Invalid}}", 326 expected: "hello world {{.Number}} {{.Invalid}}", 327 }, 328 { 329 name: "template works", 330 comment: "N={{.Number}} R={{.Repo}} O={{.Org}} U={{.Issue.HTMLURL}} T={{.Issue.Title}}", 331 template: true, 332 expected: "N=10 R=repo O=org U=url T=title", 333 }, 334 { 335 name: "bad template errors", 336 comment: "Bad {{.UnknownField}} Template", 337 expected: "Bad ", 338 template: true, 339 err: true, 340 }, 341 } 342 343 for _, tc := range cases { 344 c := makeCommenter(tc.comment, tc.template) 345 actual, err := c(m) 346 if actual != tc.expected { 347 t.Errorf("%s: expected '%s' != actual '%s'", tc.name, tc.expected, actual) 348 } 349 if err != nil && !tc.err { 350 t.Errorf("%s: unexpected err: %v", tc.name, err) 351 } 352 if err == nil && tc.err { 353 t.Errorf("%s: failed to raise an exception", tc.name) 354 } 355 } 356 }