github.com/abayer/test-infra@v0.0.5/mungegithub/mungers/e2e/e2e_test.go (about) 1 /* 2 Copyright 2015 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 e2e 18 19 import ( 20 "bytes" 21 "encoding/json" 22 "fmt" 23 "net/http" 24 "net/http/httptest" 25 "reflect" 26 "strconv" 27 "testing" 28 29 "strings" 30 31 "k8s.io/contrib/test-utils/utils" 32 "k8s.io/test-infra/mungegithub/options" 33 ) 34 35 type testHandler struct { 36 handler func(http.ResponseWriter, *http.Request) 37 } 38 39 func (t *testHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) { 40 t.handler(res, req) 41 } 42 43 func marshalOrDie(obj interface{}, t *testing.T) []byte { 44 data, err := json.Marshal(obj) 45 if err != nil { 46 t.Errorf("unexpected error: %v", err) 47 } 48 return data 49 } 50 51 func genMockGCSListResponse(files ...string) []byte { 52 respTemplate := "{\"items\":[%s]}" 53 itemTemplate := "{\"name\":\"%s\"}" 54 items := []string{} 55 for _, file := range files { 56 items = append(items, fmt.Sprintf(itemTemplate, file)) 57 } 58 return []byte(fmt.Sprintf(respTemplate, strings.Join(items, ","))) 59 } 60 61 func TestCheckGCSBuilds(t *testing.T) { 62 latestBuildNumberFoo := 42 63 latestBuildNumberBar := 44 64 latestBuildNumberBaz := 99 65 tests := []struct { 66 paths map[string][]byte 67 expectedLastBuild int 68 expectedStatus map[string]BuildInfo 69 }{ 70 { 71 paths: map[string][]byte{ 72 "/bucket/logs/foo/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberFoo)), 73 fmt.Sprintf("/bucket/logs/foo/%v/finished.json", latestBuildNumberFoo): marshalOrDie(utils.FinishedFile{ 74 Result: "SUCCESS", 75 Timestamp: 1234, 76 }, t), 77 "/bucket/logs/bar/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberBar)), 78 fmt.Sprintf("/bucket/logs/bar/%v/finished.json", latestBuildNumberBar): marshalOrDie(utils.FinishedFile{ 79 Result: "SUCCESS", 80 Timestamp: 1234, 81 }, t), 82 "/bucket/logs/baz/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberBaz)), 83 fmt.Sprintf("/bucket/logs/baz/%v/finished.json", latestBuildNumberBaz): marshalOrDie(utils.FinishedFile{ 84 Result: "UNSTABLE", 85 Timestamp: 1234, 86 }, t), 87 "/storage/v1/b/bucket/o": genMockGCSListResponse(), 88 }, 89 expectedStatus: map[string]BuildInfo{ 90 "foo": {Status: "[nonblocking] Stable", ID: "42"}, 91 "bar": {Status: "[nonblocking] Stable", ID: "44"}, 92 "baz": {Status: "[nonblocking] Not Stable", ID: "99"}, 93 }, 94 }, 95 { 96 paths: map[string][]byte{ 97 "/bucket/logs/foo/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberFoo)), 98 fmt.Sprintf("/bucket/logs/foo/%v/finished.json", latestBuildNumberFoo): marshalOrDie(utils.FinishedFile{ 99 Result: "SUCCESS", 100 Timestamp: 1234, 101 }, t), 102 "/bucket/logs/bar/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberBar)), 103 fmt.Sprintf("/bucket/logs/bar/%v/finished.json", latestBuildNumberBar): marshalOrDie(utils.FinishedFile{ 104 Result: "UNSTABLE", 105 Timestamp: 1234, 106 }, t), 107 "/bucket/logs/baz/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberBaz)), 108 fmt.Sprintf("/bucket/logs/baz/%v/finished.json", latestBuildNumberBaz): marshalOrDie(utils.FinishedFile{ 109 Result: "SUCCESS", 110 Timestamp: 1234, 111 }, t), 112 "/storage/v1/b/bucket/o": genMockGCSListResponse(), 113 }, 114 expectedStatus: map[string]BuildInfo{ 115 "foo": {Status: "[nonblocking] Stable", ID: "42"}, 116 "bar": {Status: "[nonblocking] Not Stable", ID: "44"}, 117 "baz": {Status: "[nonblocking] Stable", ID: "99"}, 118 }, 119 }, 120 { 121 paths: map[string][]byte{ 122 "/bucket/logs/foo/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberFoo)), 123 fmt.Sprintf("/bucket/logs/foo/%v/finished.json", latestBuildNumberFoo): marshalOrDie(utils.FinishedFile{ 124 Result: "SUCCESS", 125 Timestamp: 1234, 126 }, t), 127 "/bucket/logs/bar/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberBar)), 128 fmt.Sprintf("/bucket/logs/bar/%v/finished.json", latestBuildNumberBar): marshalOrDie(utils.FinishedFile{ 129 Result: "UNSTABLE", 130 Timestamp: 1234, 131 }, t), 132 fmt.Sprintf("/bucket/logs/bar/%v/artifacts/junit_01.xml", latestBuildNumberBar-1): getJUnit(5, 0), 133 fmt.Sprintf("/bucket/logs/bar/%v/artifacts/junit_02.xml", latestBuildNumberBar-1): getRealJUnitFailure(), 134 fmt.Sprintf("/bucket/logs/bar/%v/artifacts/junit_03.xml", latestBuildNumberBar-1): getJUnit(5, 0), 135 fmt.Sprintf("/bucket/logs/bar/%v/artifacts/junit_01.xml", latestBuildNumberBar): getJUnit(5, 0), 136 fmt.Sprintf("/bucket/logs/bar/%v/artifacts/junit_02.xml", latestBuildNumberBar): getRealJUnitFailure(), 137 fmt.Sprintf("/bucket/logs/bar/%v/artifacts/junit_03.xml", latestBuildNumberBar): getJUnit(5, 0), 138 fmt.Sprintf("/bucket/logs/bar/%v/finished.json", latestBuildNumberBar-1): marshalOrDie(utils.FinishedFile{ 139 Result: "UNSTABLE", 140 Timestamp: 999, 141 }, t), 142 "/storage/v1/b/bucket/o": genMockGCSListResponse( 143 fmt.Sprintf("/bucket/logs/bar/%v/artifacts/junit_01.xml", latestBuildNumberBar-1), 144 fmt.Sprintf("/bucket/logs/bar/%v/artifacts/junit_02.xml", latestBuildNumberBar-1), 145 fmt.Sprintf("/bucket/logs/bar/%v/artifacts/junit_03.xml", latestBuildNumberBar-1), 146 fmt.Sprintf("/bucket/logs/bar/%v/artifacts/junit_01.xml", latestBuildNumberBar), 147 fmt.Sprintf("/bucket/logs/bar/%v/artifacts/junit_02.xml", latestBuildNumberBar), 148 fmt.Sprintf("/bucket/logs/bar/%v/artifacts/junit_03.xml", latestBuildNumberBar), 149 ), 150 }, 151 expectedStatus: map[string]BuildInfo{ 152 "foo": {Status: "[nonblocking] Stable", ID: "42"}, 153 "bar": {Status: "[nonblocking] Not Stable", ID: "44"}, 154 "baz": {Status: "[nonblocking] Not Stable", ID: "-1"}, 155 }, 156 }, 157 158 { 159 paths: map[string][]byte{ 160 "/bucket/logs/foo/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberFoo)), 161 fmt.Sprintf("/bucket/logs/foo/%v/finished.json", latestBuildNumberFoo): marshalOrDie(utils.FinishedFile{ 162 Result: "SUCCESS", 163 Timestamp: 1234, 164 }, t), 165 "/bucket/logs/bar/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberBar)), 166 fmt.Sprintf("/bucket/logs/bar/%v/finished.json", latestBuildNumberBar): marshalOrDie(utils.FinishedFile{ 167 Result: "FAILURE", 168 Timestamp: 1234, 169 }, t), 170 "/storage/v1/b/bucket/o": genMockGCSListResponse(), 171 }, 172 expectedStatus: map[string]BuildInfo{ 173 "foo": {Status: "[nonblocking] Stable", ID: "42"}, 174 "bar": {Status: "[nonblocking] Not Stable", ID: "44"}, 175 "baz": {Status: "[nonblocking] Not Stable", ID: "-1"}, 176 }, 177 }, 178 { 179 paths: map[string][]byte{ 180 "/bucket/logs/foo/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberFoo)), 181 fmt.Sprintf("/bucket/logs/foo/%v/finished.json", latestBuildNumberFoo): marshalOrDie(utils.FinishedFile{ 182 Result: "FAILURE", 183 Timestamp: 1234, 184 }, t), 185 "/bucket/logs/bar/latest-build.txt": []byte(strconv.Itoa(latestBuildNumberBar)), 186 fmt.Sprintf("/bucket/logs/bar/%v/finished.json", latestBuildNumberBar): marshalOrDie(utils.FinishedFile{ 187 Result: "UNSTABLE", 188 Timestamp: 1234, 189 }, t), 190 "/storage/v1/b/bucket/o": genMockGCSListResponse(), 191 }, 192 expectedStatus: map[string]BuildInfo{ 193 "foo": {Status: "[nonblocking] Not Stable", ID: "42"}, 194 "bar": {Status: "[nonblocking] Not Stable", ID: "44"}, 195 "baz": {Status: "[nonblocking] Not Stable", ID: "-1"}, 196 }, 197 }, 198 } 199 for index, test := range tests { 200 server := httptest.NewServer(&testHandler{ 201 handler: func(res http.ResponseWriter, req *http.Request) { 202 data, found := test.paths[req.URL.Path] 203 if !found { 204 res.WriteHeader(http.StatusNotFound) 205 fmt.Fprintf(res, "Unknown path: %s", req.URL.Path) 206 return 207 } 208 res.WriteHeader(http.StatusOK) 209 res.Write(data) 210 }, 211 }) 212 jobs := []string{"foo", "bar", "baz"} 213 e2e := &RealE2ETester{ 214 Opts: options.New(), 215 NonBlockingJobNames: &jobs, 216 BuildStatus: map[string]BuildInfo{}, 217 GoogleGCSBucketUtils: utils.NewTestUtils("bucket", "logs", server.URL), 218 } 219 e2e.Init(nil) 220 221 e2e.LoadNonBlockingStatus() 222 if !reflect.DeepEqual(test.expectedStatus, e2e.BuildStatus) { 223 t.Errorf("%v: expected: %v, saw: %v", index, test.expectedStatus, e2e.BuildStatus) 224 } 225 } 226 } 227 228 func getJUnit(testsNo int, failuresNo int) []byte { 229 return []byte(fmt.Sprintf("%v\n<testsuite tests=\"%v\" failures=\"%v\" time=\"1234\">\n</testsuite>", 230 ExpectedXMLHeader, testsNo, failuresNo)) 231 } 232 233 func getOtherRealJUnitFailure() []byte { 234 return []byte(`<testsuite tests="7" failures="1" time="275.882258919"> 235 <testcase name="[k8s.io] ResourceQuota should create a ResourceQuota and capture the life of a loadBalancer service." classname="Kubernetes e2e suite" time="17.759834805"/> 236 <testcase name="[k8s.io] ResourceQuota should create a ResourceQuota and capture the life of a secret." classname="Kubernetes e2e suite" time="21.201547548"/> 237 <testcase name="OTHER [k8s.io] Kubectl client [k8s.io] Kubectl patch should add annotations for pods in rc [Conformance]" classname="Kubernetes e2e suite" time="126.756441938"> 238 <failure type="Failure"> 239 /go/src/k8s.io/kubernetes/_output/dockerized/go/src/k8s.io/kubernetes/test/e2e/kubectl.go:972 May 18 13:02:24.715: No pods matched the filter. 240 </failure> 241 </testcase> 242 <testcase name="[k8s.io] hostPath should give a volume the correct mode [Conformance]" classname="Kubernetes e2e suite" time="9.246191421"/> 243 <testcase name="[k8s.io] Volumes [Feature:Volumes] [k8s.io] Ceph RBD should be mountable" classname="Kubernetes e2e suite" time="0"> 244 <skipped/> 245 </testcase> 246 <testcase name="[k8s.io] Deployment deployment should label adopted RSs and pods" classname="Kubernetes e2e suite" time="16.557498555"/> 247 <testcase name="[k8s.io] ConfigMap should be consumable from pods in volume as non-root with FSGroup [Feature:FSGroup]" classname="Kubernetes e2e suite" time="0"> 248 <skipped/> 249 </testcase> 250 <testcase name="[k8s.io] V1Job should scale a job down" classname="Kubernetes e2e suite" time="77.122626914"/> 251 <testcase name="[k8s.io] EmptyDir volumes volume on default medium should have the correct mode [Conformance]" classname="Kubernetes e2e suite" time="7.169679079"/> 252 <testcase name="[k8s.io] Reboot [Disruptive] [Feature:Reboot] each node by ordering unclean reboot and ensure they function upon restart" classname="Kubernetes e2e suite" time="0"> 253 <skipped/> 254 </testcase> 255 </testsuite>`) 256 } 257 258 func getRealJUnitFailure() []byte { 259 return []byte(`<testsuite tests="7" failures="1" time="275.882258919"> 260 <testcase name="[k8s.io] ResourceQuota should create a ResourceQuota and capture the life of a loadBalancer service." classname="Kubernetes e2e suite" time="17.759834805"/> 261 <testcase name="[k8s.io] ResourceQuota should create a ResourceQuota and capture the life of a secret." classname="Kubernetes e2e suite" time="21.201547548"/> 262 <testcase name="[k8s.io] Kubectl client [k8s.io] Kubectl patch should add annotations for pods in rc [Conformance]" classname="Kubernetes e2e suite" time="126.756441938"> 263 <failure type="Failure"> 264 /go/src/k8s.io/kubernetes/_output/dockerized/go/src/k8s.io/kubernetes/test/e2e/kubectl.go:972 May 18 13:02:24.715: No pods matched the filter. 265 </failure> 266 </testcase> 267 <testcase name="[k8s.io] hostPath should give a volume the correct mode [Conformance]" classname="Kubernetes e2e suite" time="9.246191421"/> 268 <testcase name="[k8s.io] Volumes [Feature:Volumes] [k8s.io] Ceph RBD should be mountable" classname="Kubernetes e2e suite" time="0"> 269 <skipped/> 270 </testcase> 271 <testcase name="[k8s.io] Deployment deployment should label adopted RSs and pods" classname="Kubernetes e2e suite" time="16.557498555"/> 272 <testcase name="[k8s.io] ConfigMap should be consumable from pods in volume as non-root with FSGroup [Feature:FSGroup]" classname="Kubernetes e2e suite" time="0"> 273 <skipped/> 274 </testcase> 275 <testcase name="[k8s.io] V1Job should scale a job down" classname="Kubernetes e2e suite" time="77.122626914"/> 276 <testcase name="[k8s.io] EmptyDir volumes volume on default medium should have the correct mode [Conformance]" classname="Kubernetes e2e suite" time="7.169679079"/> 277 <testcase name="[k8s.io] Reboot [Disruptive] [Feature:Reboot] each node by ordering unclean reboot and ensure they function upon restart" classname="Kubernetes e2e suite" time="0"> 278 <skipped/> 279 </testcase> 280 </testsuite>`) 281 } 282 283 func getRealJUnitFailureWithTestSuitesTag() []byte { 284 return []byte(`<?xml version="1.0" encoding="UTF-8"?> 285 <testsuites> 286 <testsuite tests="52" failures="2" time="374.434" name="k8s.io/kubernetes/test/integration"> 287 <properties> 288 <property name="go.version" value="go1.6.2"></property> 289 </properties> 290 <testcase classname="integration" name="TestMasterProcessMetrics" time="0.070"></testcase> 291 <testcase classname="integration" name="TestApiserverMetrics" time="0.070"></testcase> 292 <testcase classname="integration" name="TestMasterExportsSymbols" time="0.000"></testcase> 293 <testcase classname="integration" name="TestPersistentVolumeRecycler" time="20.460"></testcase> 294 <testcase classname="integration" name="TestPersistentVolumeMultiPVs" time="10.240"> 295 <failure message="Failed" type="">persistent_volumes_test.go:254: volumes created
persistent_volumes_test.go:260: claim created
persistent_volumes_test.go:264: volume bound
persistent_volumes_test.go:266: claim bound
persistent_volumes_test.go:284: Bind mismatch! Expected pvc-2 capacity 50000000000 but got fake-pvc-72 capacity 5000000000</failure> 296 </testcase> 297 <testcase classname="integration" name="TestPersistentVolumeMultiPVsPVCs" time="3.370"> 298 <failure message="Failed" type="">persistent_volumes_test.go:379: PVC "pvc-0" is not bound</failure> 299 </testcase> 300 <testcase classname="integration" name="TestPersistentVolumeMultiPVsDiffAccessModes" time="10.110"></testcase> 301 </testsuite> 302 </testsuites> 303 `) 304 } 305 306 func TestJUnitFailureParse(t *testing.T) { 307 //parse junit xml result with <testsuite> as top tag 308 junitFailReader := bytes.NewReader(getRealJUnitFailure()) 309 got, err := getJUnitFailures(junitFailReader) 310 if err != nil { 311 t.Fatalf("Parse error? %v", err) 312 } 313 if e, a := map[string]string{ 314 "[k8s.io] Kubectl client [k8s.io] Kubectl patch should add annotations for pods in rc [Conformance] {Kubernetes e2e suite}": ` 315 /go/src/k8s.io/kubernetes/_output/dockerized/go/src/k8s.io/kubernetes/test/e2e/kubectl.go:972 May 18 13:02:24.715: No pods matched the filter. 316 `, 317 }, got; !reflect.DeepEqual(e, a) { 318 t.Errorf("Expected %v, got %v", e, a) 319 } 320 321 //parse junit xml result with <testsuites> as top tag 322 junitFailReader = bytes.NewReader(getRealJUnitFailureWithTestSuitesTag()) 323 got, err = getJUnitFailures(junitFailReader) 324 if err != nil { 325 t.Fatalf("Parse error? %v", err) 326 } 327 if e, a := map[string]string{ 328 "TestPersistentVolumeMultiPVs {integration}": "persistent_volumes_test.go:254: volumes created\npersistent_volumes_test.go:260: claim created\npersistent_volumes_test.go:264: volume bound\npersistent_volumes_test.go:266: claim bound\npersistent_volumes_test.go:284: Bind mismatch! Expected pvc-2 capacity 50000000000 but got fake-pvc-72 capacity 5000000000", 329 "TestPersistentVolumeMultiPVsPVCs {integration}": `persistent_volumes_test.go:379: PVC "pvc-0" is not bound`, 330 }, got; !reflect.DeepEqual(e, a) { 331 t.Errorf("Expected %v, got %v", e, a) 332 } 333 }