github.com/abayer/test-infra@v0.0.5/prow/plugins/dog/dog_test.go (about) 1 /* 2 Copyright 2018 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 dog 18 19 import ( 20 "encoding/json" 21 "flag" 22 "fmt" 23 "io" 24 "net/http" 25 "net/http/httptest" 26 "regexp" 27 "strings" 28 "testing" 29 30 "github.com/sirupsen/logrus" 31 32 "k8s.io/test-infra/prow/github" 33 "k8s.io/test-infra/prow/github/fakegithub" 34 ) 35 36 type fakePack string 37 38 var human = flag.Bool("human", false, "Enable to run additional manual tests") 39 40 func (c fakePack) readDog() (string, error) { 41 return string(c), nil 42 } 43 44 func TestRealDog(t *testing.T) { 45 if !*human { 46 t.Skip("Real dogs disabled for automation. Manual users can add --human [--category=foo]") 47 } 48 if dog, err := dogURL.readDog(); err != nil { 49 t.Errorf("Could not read dog from %s: %v", dogURL, err) 50 } else { 51 fmt.Println(dog) 52 } 53 } 54 55 func TestFormat(t *testing.T) { 56 re := regexp.MustCompile(`\[!\[.+\]\(.+\)\]\(.+\)`) 57 basicURL := "http://example.com" 58 testcases := []struct { 59 name string 60 url string 61 err bool 62 }{ 63 { 64 name: "basically works", 65 url: basicURL, 66 err: false, 67 }, 68 { 69 name: "empty url", 70 url: "", 71 err: true, 72 }, 73 { 74 name: "bad url", 75 url: "http://this is not a url", 76 err: true, 77 }, 78 } 79 for _, tc := range testcases { 80 ret, err := dogResult{ 81 URL: tc.url, 82 }.Format() 83 switch { 84 case tc.err: 85 if err == nil { 86 t.Errorf("%s: failed to raise an error", tc.name) 87 } 88 case err != nil: 89 t.Errorf("%s: unexpected error: %v", tc.name, err) 90 case !re.MatchString(ret): 91 t.Errorf("%s: bad return value: %s", tc.name, ret) 92 } 93 } 94 } 95 96 // Medium integration test (depends on ability to open a TCP port) 97 func TestHttpResponse(t *testing.T) { 98 // create test cases for handling content length of images 99 contentLength := make(map[string]string) 100 contentLength["/dog.jpg"] = "717987" 101 contentLength["/doggo.mp4"] = "37943259" 102 contentLength["/bigdog.jpg"] = "12647753" 103 104 // fake server for images 105 ts2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 106 if s, ok := contentLength[r.URL.Path]; ok { 107 body := "binary image" 108 w.Header().Set("Content-Length", s) 109 io.WriteString(w, body) 110 } else { 111 t.Errorf("Cannot find content length for %s", r.URL.Path) 112 } 113 })) 114 defer ts2.Close() 115 116 // setup a stock valid request 117 url := ts2.URL + "/dog.jpg" 118 b, err := json.Marshal(&dogResult{ 119 URL: url, 120 }) 121 if err != nil { 122 t.Errorf("Failed to encode test data: %v", err) 123 } 124 125 // create test cases for handling http responses 126 validResponse := string(b) 127 var testcases = []struct { 128 name string 129 path string 130 response string 131 isValid bool 132 }{ 133 { 134 name: "valid", 135 path: "/valid", 136 response: validResponse, 137 isValid: true, 138 }, 139 { 140 name: "invalid JSON", 141 path: "/bad-json", 142 response: `{"bad-blob": "not-a-url"`, 143 isValid: false, 144 }, 145 { 146 name: "invalid URL", 147 path: "/bad-url", 148 response: `{"url": "not a url.."}`, 149 isValid: false, 150 }, 151 { 152 name: "mp4 doggo unsupported :(", 153 path: "/mp4-doggo", 154 response: fmt.Sprintf(`{"url": "%s/doggo.mp4"}`, ts2.URL), 155 isValid: false, 156 }, 157 { 158 name: "image too big", 159 path: "/too-big", 160 response: fmt.Sprintf(`{"url": "%s/bigdog.jpg"}`, ts2.URL), 161 isValid: false, 162 }, 163 } 164 165 // fake server for image urls 166 pathToResponse := make(map[string]string) 167 for _, testcase := range testcases { 168 pathToResponse[testcase.path] = testcase.response 169 } 170 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 171 if r, ok := pathToResponse[r.URL.Path]; ok { 172 io.WriteString(w, r) 173 } else { 174 io.WriteString(w, validResponse) 175 } 176 })) 177 defer ts.Close() 178 179 // github fake client 180 fc := &fakegithub.FakeClient{ 181 IssueComments: make(map[int][]github.IssueComment), 182 } 183 184 // run test for each case 185 for _, testcase := range testcases { 186 dog, err := realPack(ts.URL + testcase.path).readDog() 187 if testcase.isValid && err != nil { 188 t.Errorf("For case %s, didn't expect error: %v", testcase.name, err) 189 } else if !testcase.isValid && err == nil { 190 t.Errorf("For case %s, expected error, received dog: %s", testcase.name, dog) 191 } 192 } 193 194 // fully test handling a comment 195 comment := "/woof" 196 e := &github.GenericCommentEvent{ 197 Action: github.GenericCommentActionCreated, 198 Body: comment, 199 Number: 5, 200 IssueState: "open", 201 } 202 err = handle(fc, logrus.WithField("plugin", pluginName), e, realPack(ts.URL)) 203 if err != nil { 204 t.Errorf("For comment /woof, didn't expect error: %v", err) 205 } 206 207 if len(fc.IssueComments[5]) != 1 { 208 t.Error("should have commented.") 209 } 210 if c := fc.IssueComments[5][0]; !strings.Contains(c.Body, url) { 211 t.Errorf("missing image url: %s from comment: %v", url, c) 212 } 213 } 214 215 // Small, unit tests 216 func TestDogs(t *testing.T) { 217 var testcases = []struct { 218 name string 219 action github.GenericCommentEventAction 220 body string 221 state string 222 pr bool 223 shouldComment bool 224 }{ 225 { 226 name: "ignore edited comment", 227 state: "open", 228 action: github.GenericCommentActionEdited, 229 body: "/woof", 230 shouldComment: false, 231 }, 232 { 233 name: "leave dog on pr", 234 state: "open", 235 action: github.GenericCommentActionCreated, 236 body: "/woof", 237 pr: true, 238 shouldComment: true, 239 }, 240 { 241 name: "leave dog on issue", 242 state: "open", 243 action: github.GenericCommentActionCreated, 244 body: "/woof", 245 shouldComment: true, 246 }, 247 { 248 name: "leave dog on issue, trailing space", 249 state: "open", 250 action: github.GenericCommentActionCreated, 251 body: "/woof \r", 252 shouldComment: true, 253 }, 254 { 255 name: "leave dog on issue, trailing /bark", 256 state: "open", 257 action: github.GenericCommentActionCreated, 258 body: "/bark", 259 shouldComment: true, 260 }, 261 { 262 name: "leave dog on issue, trailing /bark, trailing space", 263 state: "open", 264 action: github.GenericCommentActionCreated, 265 body: "/bark \r", 266 shouldComment: true, 267 }, 268 } 269 for _, tc := range testcases { 270 fc := &fakegithub.FakeClient{ 271 IssueComments: make(map[int][]github.IssueComment), 272 } 273 e := &github.GenericCommentEvent{ 274 Action: tc.action, 275 Body: tc.body, 276 Number: 5, 277 IssueState: tc.state, 278 IsPR: tc.pr, 279 } 280 err := handle(fc, logrus.WithField("plugin", pluginName), e, fakePack("doge")) 281 if err != nil { 282 t.Errorf("For case %s, didn't expect error: %v", tc.name, err) 283 } 284 if tc.shouldComment && len(fc.IssueComments[5]) != 1 { 285 t.Errorf("For case %s, should have commented.", tc.name) 286 } else if !tc.shouldComment && len(fc.IssueComments[5]) != 0 { 287 t.Errorf("For case %s, should not have commented.", tc.name) 288 } 289 } 290 }