Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(107)

Side by Side Diff: milo/appengine/buildbot/pubsub_test.go

Issue 2944983003: [milo] {buildbucket,buildbot,swarming,logdog} -> backends/*. (Closed)
Patch Set: Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file.
4
5 package buildbot
6
7 import (
8 "bytes"
9 "compress/zlib"
10 "encoding/base64"
11 "encoding/json"
12 "io"
13 "io/ioutil"
14 "math/rand"
15 "net/http"
16 "net/http/httptest"
17 "testing"
18 "time"
19
20 "github.com/luci/gae/impl/memory"
21 ds "github.com/luci/gae/service/datastore"
22 "github.com/luci/luci-go/common/clock/testclock"
23 memcfg "github.com/luci/luci-go/common/config/impl/memory"
24 "github.com/luci/luci-go/common/logging/gologger"
25 "github.com/luci/luci-go/luci_config/server/cfgclient/backend/testconfig "
26 "github.com/luci/luci-go/milo/appengine/common"
27 "github.com/luci/luci-go/server/auth"
28 "github.com/luci/luci-go/server/auth/authtest"
29 "github.com/luci/luci-go/server/auth/identity"
30 "github.com/luci/luci-go/server/router"
31
32 "github.com/julienschmidt/httprouter"
33 "golang.org/x/net/context"
34
35 . "github.com/luci/luci-go/common/testing/assertions"
36 . "github.com/smartystreets/goconvey/convey"
37 )
38
39 var (
40 fakeTime = time.Date(2001, time.February, 3, 4, 5, 6, 7, time.UTC)
41 letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX YZ")
42 )
43
44 func RandStringRunes(n int) string {
45 b := make([]rune, n)
46 for i := range b {
47 b[i] = letterRunes[rand.Intn(len(letterRunes))]
48 }
49 return string(b)
50 }
51
52 func buildbotTimesFinished(start, end float64) []*float64 {
53 return []*float64{&start, &end}
54 }
55
56 func buildbotTimesPending(start float64) []*float64 {
57 return []*float64{&start, nil}
58 }
59
60 func newCombinedPsBody(bs []*buildbotBuild, m *buildbotMaster, internal bool) io .ReadCloser {
61 bmsg := buildMasterMsg{
62 Master: m,
63 Builds: bs,
64 }
65 bm, _ := json.Marshal(bmsg)
66 var b bytes.Buffer
67 zw := zlib.NewWriter(&b)
68 zw.Write(bm)
69 zw.Close()
70 sub := "projects/luci-milo/subscriptions/buildbot-public"
71 if internal {
72 sub = "projects/luci-milo/subscriptions/buildbot-private"
73 }
74 msg := pubSubSubscription{
75 Subscription: sub,
76 Message: pubSubMessage{
77 Data: base64.StdEncoding.EncodeToString(b.Bytes()),
78 },
79 }
80 jmsg, _ := json.Marshal(msg)
81 return ioutil.NopCloser(bytes.NewReader(jmsg))
82 }
83
84 func TestPubSub(t *testing.T) {
85 Convey(`A test Environment`, t, func() {
86 c := memory.UseWithAppID(context.Background(), "dev~luci-milo")
87 c = gologger.StdConfig.Use(c)
88 c, _ = testclock.UseTime(c, fakeTime)
89 c = testconfig.WithCommonClient(c, memcfg.New(bbAclConfigs))
90 c = auth.WithState(c, &authtest.FakeState{
91 Identity: identity.AnonymousIdentity,
92 IdentityGroups: []string{"all"},
93 })
94 // Update the service config so that the settings are loaded.
95 err := common.UpdateServiceConfig(c)
96 So(err, ShouldBeNil)
97
98 rand.Seed(5)
99
100 Convey("Remove source changes", func() {
101 m := &buildbotMaster{
102 Name: "fake",
103 Builders: map[string]*buildbotBuilder{
104 "fake builder": {
105 PendingBuildStates: []*buildbotP ending{
106 {
107 Source: buildbot SourceStamp{
108 Changes: []buildbotChange{{Comments: "foo"}},
109 },
110 },
111 },
112 },
113 },
114 }
115 So(putDSMasterJSON(c, m, false), ShouldBeNil)
116 lm, _, _, err := getMasterJSON(c, "fake")
117 So(err, ShouldBeNil)
118 So(lm.Builders["fake builder"].PendingBuildStates[0].Sou rce.Changes[0].Comments, ShouldResemble, "")
119 })
120
121 Convey("Save build entry", func() {
122 build := &buildbotBuild{
123 Master: "Fake Master",
124 Buildername: "Fake buildername",
125 Number: 1234,
126 Currentstep: "this is a string",
127 Finished: true,
128 }
129 err := ds.Put(c, build)
130 ds.GetTestable(c).CatchupIndexes()
131
132 So(err, ShouldBeNil)
133 Convey("Load build entry", func() {
134 loadB := &buildbotBuild{
135 Master: "Fake Master",
136 Buildername: "Fake buildername",
137 Number: 1234,
138 }
139 err = ds.Get(c, loadB)
140 So(err, ShouldBeNil)
141 So(loadB.Master, ShouldEqual, "Fake Master")
142 So(loadB.Internal, ShouldEqual, false)
143 So(loadB.Currentstep.(string), ShouldEqual, "thi s is a string")
144 So(loadB.Finished, ShouldEqual, true)
145 })
146
147 Convey("Query build entry", func() {
148 q := ds.NewQuery("buildbotBuild")
149 buildbots := []*buildbotBuild{}
150 err = ds.GetAll(c, q, &buildbots)
151 So(err, ShouldBeNil)
152
153 So(len(buildbots), ShouldEqual, 1)
154 So(buildbots[0].Currentstep.(string), ShouldEqua l, "this is a string")
155 Convey("Query for finished entries should be 1", func() {
156 q = q.Eq("finished", true)
157 buildbots = []*buildbotBuild{}
158 err = ds.GetAll(c, q, &buildbots)
159 So(err, ShouldBeNil)
160 So(len(buildbots), ShouldEqual, 1)
161 })
162 Convey("Query for unfinished entries should be 0 ", func() {
163 q = q.Eq("finished", false)
164 buildbots = []*buildbotBuild{}
165 err = ds.GetAll(c, q, &buildbots)
166 So(err, ShouldBeNil)
167 So(len(buildbots), ShouldEqual, 0)
168 })
169 })
170
171 Convey("Save a few more entries", func() {
172 ds.GetTestable(c).Consistent(true)
173 ds.GetTestable(c).AutoIndex(true)
174 for i := 1235; i < 1240; i++ {
175 build := &buildbotBuild{
176 Master: "Fake Master",
177 Buildername: "Fake buildername",
178 Number: i,
179 Currentstep: "this is a string",
180 Finished: i%2 == 0,
181 }
182 err := ds.Put(c, build)
183 So(err, ShouldBeNil)
184 }
185 q := ds.NewQuery("buildbotBuild")
186 q = q.Eq("finished", true)
187 q = q.Eq("master", "Fake Master")
188 q = q.Eq("builder", "Fake buildername")
189 q = q.Order("-number")
190 buildbots := []*buildbotBuild{}
191 err = ds.GetAll(c, q, &buildbots)
192 So(err, ShouldBeNil)
193 So(len(buildbots), ShouldEqual, 3) // 1235, 1237 , 1239
194 })
195 })
196
197 Convey("Build panics on invalid query", func() {
198 build := &buildbotBuild{
199 Master: "Fake Master",
200 }
201 So(func() { ds.Put(c, build) }, ShouldPanicLike, "No Mas ter or Builder found")
202 })
203
204 ts := 555
205 b := &buildbotBuild{
206 Master: "Fake Master",
207 Buildername: "Fake buildername",
208 Number: 1234,
209 Currentstep: "this is a string",
210 Times: buildbotTimesPending(123.0),
211 TimeStamp: &ts,
212 }
213
214 Convey("Basic master + build pusbsub subscription", func() {
215 h := httptest.NewRecorder()
216 slaves := map[string]*buildbotSlave{}
217 ft := 1234.0
218 slaves["testslave"] = &buildbotSlave{
219 Name: "testslave",
220 Connected: true,
221 Runningbuilds: []*buildbotBuild{
222 {
223 Master: "Fake Master",
224 Buildername: "Fake buildername",
225 Number: 2222,
226 Times: []*float64{&ft, nil },
227 },
228 },
229 }
230 ms := buildbotMaster{
231 Name: "Fake Master",
232 Project: buildbotProject{Title: "some title"},
233 Slaves: slaves,
234 Builders: map[string]*buildbotBuilder{},
235 }
236
237 ms.Builders["Fake buildername"] = &buildbotBuilder{
238 CurrentBuilds: []int{1234},
239 }
240 r := &http.Request{
241 Body: newCombinedPsBody([]*buildbotBuild{b}, &ms , false),
242 }
243 p := httprouter.Params{}
244 PubSubHandler(&router.Context{
245 Context: c,
246 Writer: h,
247 Request: r,
248 Params: p,
249 })
250 So(h.Code, ShouldEqual, 200)
251 Convey("And stores correctly", func() {
252 loadB := &buildbotBuild{
253 Master: "Fake Master",
254 Buildername: "Fake buildername",
255 Number: 1234,
256 }
257 err := ds.Get(c, loadB)
258 So(err, ShouldBeNil)
259 So(loadB.Master, ShouldEqual, "Fake Master")
260 So(loadB.Currentstep.(string), ShouldEqual, "thi s is a string")
261 m, _, t, err := getMasterJSON(c, "Fake Master")
262 So(err, ShouldBeNil)
263 So(t.Unix(), ShouldEqual, 981173106)
264 So(m.Name, ShouldEqual, "Fake Master")
265 So(m.Project.Title, ShouldEqual, "some title")
266 So(m.Slaves["testslave"].Name, ShouldEqual, "tes tslave")
267 So(len(m.Slaves["testslave"].Runningbuilds), Sho uldEqual, 0)
268 So(len(m.Slaves["testslave"].RunningbuildsMap), ShouldEqual, 1)
269 So(m.Slaves["testslave"].RunningbuildsMap["Fake buildername"][0],
270 ShouldEqual, 2222)
271 })
272
273 Convey("And a new master overwrites", func() {
274 c, _ = testclock.UseTime(c, fakeTime.Add(time.Du ration(1*time.Second)))
275 ms.Project.Title = "some other title"
276 h = httptest.NewRecorder()
277 r := &http.Request{
278 Body: newCombinedPsBody([]*buildbotBuild {b}, &ms, false)}
279 p = httprouter.Params{}
280 PubSubHandler(&router.Context{
281 Context: c,
282 Writer: h,
283 Request: r,
284 Params: p,
285 })
286 So(h.Code, ShouldEqual, 200)
287 m, _, t, err := getMasterJSON(c, "Fake Master")
288 So(err, ShouldBeNil)
289 So(m.Project.Title, ShouldEqual, "some other tit le")
290 So(t.Unix(), ShouldEqual, 981173107)
291 So(m.Name, ShouldEqual, "Fake Master")
292 })
293 Convey("And a new build overwrites", func() {
294 b.Times = buildbotTimesFinished(123.0, 124.0)
295 h = httptest.NewRecorder()
296 r = &http.Request{
297 Body: newCombinedPsBody([]*buildbotBuild {b}, &ms, false),
298 }
299 p = httprouter.Params{}
300 PubSubHandler(&router.Context{
301 Context: c,
302 Writer: h,
303 Request: r,
304 Params: p,
305 })
306 So(h.Code, ShouldEqual, 200)
307 loadB := &buildbotBuild{
308 Master: "Fake Master",
309 Buildername: "Fake buildername",
310 Number: 1234,
311 }
312 err := ds.Get(c, loadB)
313 So(err, ShouldBeNil)
314 So(*loadB.Times[0], ShouldEqual, 123.0)
315 So(*loadB.Times[1], ShouldEqual, 124.0)
316 Convey("And another pending build is rejected", func() {
317 b.Times = buildbotTimesPending(123.0)
318 h = httptest.NewRecorder()
319 r = &http.Request{
320 Body: newCombinedPsBody([]*build botBuild{b}, &ms, false),
321 }
322 p = httprouter.Params{}
323 PubSubHandler(&router.Context{
324 Context: c,
325 Writer: h,
326 Request: r,
327 Params: p,
328 })
329 So(h.Code, ShouldEqual, 200)
330 loadB := &buildbotBuild{
331 Master: "Fake Master",
332 Buildername: "Fake buildername",
333 Number: 1234,
334 }
335 err := ds.Get(c, loadB)
336 So(err, ShouldBeNil)
337 So(*loadB.Times[0], ShouldEqual, 123.0)
338 So(*loadB.Times[1], ShouldEqual, 124.0)
339 })
340 })
341 Convey("Don't Expire non-existant current build under 20 min", func() {
342 b.Number = 1235
343 ts := int(fakeTime.Unix()) - 1000
344 b.TimeStamp = &ts
345 h = httptest.NewRecorder()
346 r = &http.Request{
347 Body: newCombinedPsBody([]*buildbotBuild {b}, &ms, false),
348 }
349 p = httprouter.Params{}
350 ds.GetTestable(c).Consistent(true)
351 PubSubHandler(&router.Context{
352 Context: c,
353 Writer: h,
354 Request: r,
355 Params: p,
356 })
357 So(h.Code, ShouldEqual, 200)
358 loadB := &buildbotBuild{
359 Master: "Fake Master",
360 Buildername: "Fake buildername",
361 Number: 1235,
362 }
363 err := ds.Get(c, loadB)
364 So(err, ShouldBeNil)
365 So(loadB.Finished, ShouldEqual, false)
366 So(*loadB.Times[0], ShouldEqual, 123.0)
367 So(loadB.Times[1], ShouldBeNil)
368 })
369 Convey("Expire non-existant current build", func() {
370 b.Number = 1235
371 ts := int(fakeTime.Unix()) - 1201
372 b.TimeStamp = &ts
373 h = httptest.NewRecorder()
374 r = &http.Request{
375 Body: newCombinedPsBody([]*buildbotBuild {b}, &ms, false),
376 }
377 p = httprouter.Params{}
378 ds.GetTestable(c).Consistent(true)
379 PubSubHandler(&router.Context{
380 Context: c,
381 Writer: h,
382 Request: r,
383 Params: p,
384 })
385 So(h.Code, ShouldEqual, 200)
386 loadB := &buildbotBuild{
387 Master: "Fake Master",
388 Buildername: "Fake buildername",
389 Number: 1235,
390 }
391 err := ds.Get(c, loadB)
392 So(err, ShouldBeNil)
393 So(loadB.Finished, ShouldEqual, true)
394 So(*loadB.Times[0], ShouldEqual, 123.0)
395 So(loadB.Times[1], ShouldNotEqual, nil)
396 So(*loadB.Times[1], ShouldEqual, ts)
397 So(*loadB.Results, ShouldEqual, 4)
398 })
399 Convey("Large pubsub message", func() {
400 // This has to be a random string, so that after gzip compresses it
401 // it remains larger than 950KB
402 b.Text = append(b.Text, RandStringRunes(1500000) )
403 h := httptest.NewRecorder()
404 r := &http.Request{
405 Body: newCombinedPsBody([]*buildbotBuild {b}, &ms, false),
406 }
407 p := httprouter.Params{}
408 PubSubHandler(&router.Context{
409 Context: c,
410 Writer: h,
411 Request: r,
412 Params: p,
413 })
414 So(h.Code, ShouldEqual, 200)
415 })
416
417 })
418
419 Convey("Empty pubsub message", func() {
420 h := httptest.NewRecorder()
421 r := &http.Request{Body: ioutil.NopCloser(bytes.NewReade r([]byte{}))}
422 p := httprouter.Params{}
423 PubSubHandler(&router.Context{
424 Context: c,
425 Writer: h,
426 Request: r,
427 Params: p,
428 })
429 So(h.Code, ShouldEqual, 200)
430 })
431
432 Convey("Internal master + build pusbsub subscription", func() {
433 h := httptest.NewRecorder()
434 slaves := map[string]*buildbotSlave{}
435 ft := 1234.0
436 slaves["testslave"] = &buildbotSlave{
437 Name: "testslave",
438 Connected: true,
439 Runningbuilds: []*buildbotBuild{
440 {
441 Master: "Fake Master",
442 Buildername: "Fake buildername",
443 Number: 2222,
444 Times: []*float64{&ft, nil },
445 },
446 },
447 }
448 ms := buildbotMaster{
449 Name: "Fake Master",
450 Project: buildbotProject{Title: "some title"},
451 Slaves: slaves,
452 }
453 r := &http.Request{
454 Body: newCombinedPsBody([]*buildbotBuild{b}, &ms , true),
455 }
456 p := httprouter.Params{}
457 PubSubHandler(&router.Context{
458 Context: c,
459 Writer: h,
460 Request: r,
461 Params: p,
462 })
463 So(h.Code, ShouldEqual, 200)
464 Convey("And stores correctly", func() {
465 err := common.UpdateProjectConfigs(c)
466 So(err, ShouldBeNil)
467 c = auth.WithState(c, &authtest.FakeState{
468 Identity: "user:alicebob@google.co m",
469 IdentityGroups: []string{"googlers", "al l"},
470 })
471 loadB := &buildbotBuild{
472 Master: "Fake Master",
473 Buildername: "Fake buildername",
474 Number: 1234,
475 }
476 err = ds.Get(c, loadB)
477 So(err, ShouldBeNil)
478 So(loadB.Master, ShouldEqual, "Fake Master")
479 So(loadB.Internal, ShouldEqual, true)
480 So(loadB.Currentstep.(string), ShouldEqual, "thi s is a string")
481 m, _, t, err := getMasterJSON(c, "Fake Master")
482 So(err, ShouldBeNil)
483 So(t.Unix(), ShouldEqual, 981173106)
484 So(m.Name, ShouldEqual, "Fake Master")
485 So(m.Project.Title, ShouldEqual, "some title")
486 So(m.Slaves["testslave"].Name, ShouldEqual, "tes tslave")
487 So(len(m.Slaves["testslave"].Runningbuilds), Sho uldEqual, 0)
488 So(len(m.Slaves["testslave"].RunningbuildsMap), ShouldEqual, 1)
489 So(m.Slaves["testslave"].RunningbuildsMap["Fake buildername"][0],
490 ShouldEqual, 2222)
491 })
492 })
493 })
494 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698