| OLD | NEW |
| (Empty) |
| 1 // Copyright 2017 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 "testing" | |
| 9 | |
| 10 miloProto "github.com/luci/luci-go/common/proto/milo" | |
| 11 "github.com/luci/luci-go/logdog/api/endpoints/coordinator/logs/v1" | |
| 12 "github.com/luci/luci-go/logdog/api/logpb" | |
| 13 "github.com/luci/luci-go/logdog/client/coordinator" | |
| 14 milo "github.com/luci/luci-go/milo/api/proto" | |
| 15 | |
| 16 "github.com/luci/gae/impl/memory" | |
| 17 ds "github.com/luci/gae/service/datastore" | |
| 18 | |
| 19 "github.com/golang/protobuf/proto" | |
| 20 "golang.org/x/net/context" | |
| 21 "google.golang.org/grpc" | |
| 22 | |
| 23 . "github.com/luci/luci-go/common/testing/assertions" | |
| 24 . "github.com/smartystreets/goconvey/convey" | |
| 25 ) | |
| 26 | |
| 27 // testLogDogClient is a minimal functional LogsClient implementation. | |
| 28 // | |
| 29 // It retains its latest input parameter and returns its configured err (if not | |
| 30 // nil) or resp. | |
| 31 type testLogDogClient struct { | |
| 32 logdog.LogsClient | |
| 33 | |
| 34 req []interface{} | |
| 35 resp []interface{} | |
| 36 err error | |
| 37 } | |
| 38 | |
| 39 func (tc *testLogDogClient) popResp() (resp interface{}) { | |
| 40 resp, tc.resp = tc.resp[0], tc.resp[1:] | |
| 41 return | |
| 42 } | |
| 43 | |
| 44 func (tc *testLogDogClient) Tail(ctx context.Context, in *logdog.TailRequest, op
ts ...grpc.CallOption) ( | |
| 45 *logdog.GetResponse, error) { | |
| 46 | |
| 47 tc.req = append(tc.req, in) | |
| 48 if tc.err != nil { | |
| 49 return nil, tc.err | |
| 50 } | |
| 51 return tc.popResp().(*logdog.GetResponse), nil | |
| 52 } | |
| 53 | |
| 54 // Query returns log stream paths that match the requested query. | |
| 55 func (tc *testLogDogClient) Query(ctx context.Context, in *logdog.QueryRequest,
opts ...grpc.CallOption) ( | |
| 56 *logdog.QueryResponse, error) { | |
| 57 | |
| 58 tc.req = append(tc.req, in) | |
| 59 if tc.err != nil { | |
| 60 return nil, tc.err | |
| 61 } | |
| 62 return tc.popResp().(*logdog.QueryResponse), nil | |
| 63 } | |
| 64 | |
| 65 func datagramGetResponse(project, prefix string, msg proto.Message) *logdog.GetR
esponse { | |
| 66 data, err := proto.Marshal(msg) | |
| 67 if err != nil { | |
| 68 panic(err) | |
| 69 } | |
| 70 return &logdog.GetResponse{ | |
| 71 Project: project, | |
| 72 Desc: &logpb.LogStreamDescriptor{ | |
| 73 Prefix: prefix, | |
| 74 ContentType: miloProto.ContentTypeAnnotations, | |
| 75 StreamType: logpb.StreamType_DATAGRAM, | |
| 76 }, | |
| 77 State: &logdog.LogStreamState{}, | |
| 78 Logs: []*logpb.LogEntry{ | |
| 79 { | |
| 80 Content: &logpb.LogEntry_Datagram{ | |
| 81 Datagram: &logpb.Datagram{ | |
| 82 Data: data, | |
| 83 }, | |
| 84 }, | |
| 85 }, | |
| 86 }, | |
| 87 } | |
| 88 } | |
| 89 | |
| 90 func TestBuildInfo(t *testing.T) { | |
| 91 t.Parallel() | |
| 92 | |
| 93 Convey("A testing BuildInfoProvider", t, func() { | |
| 94 c := context.Background() | |
| 95 c = memory.Use(c) | |
| 96 | |
| 97 testClient := testLogDogClient{} | |
| 98 bip := BuildInfoProvider{ | |
| 99 LogdogClientFunc: func(context.Context) (*coordinator.Cl
ient, error) { | |
| 100 return &coordinator.Client{ | |
| 101 C: &testClient, | |
| 102 Host: "example.com", | |
| 103 }, nil | |
| 104 }, | |
| 105 } | |
| 106 | |
| 107 build := buildbotBuild{ | |
| 108 Master: "foo master", | |
| 109 Buildername: "bar builder", | |
| 110 Number: 1337, | |
| 111 Properties: []*buildbotProperty{ | |
| 112 {Name: "foo", Value: "build-foo"}, | |
| 113 {Name: "bar", Value: "build-bar"}, | |
| 114 }, | |
| 115 } | |
| 116 | |
| 117 logdogStep := miloProto.Step{ | |
| 118 Command: &miloProto.Step_Command{ | |
| 119 CommandLine: []string{"foo", "bar", "baz"}, | |
| 120 }, | |
| 121 Text: []string{"test step"}, | |
| 122 Property: []*miloProto.Step_Property{ | |
| 123 {Name: "bar", Value: "log-bar"}, | |
| 124 }, | |
| 125 } | |
| 126 | |
| 127 biReq := milo.BuildInfoRequest{ | |
| 128 Build: &milo.BuildInfoRequest_Buildbot{ | |
| 129 Buildbot: &milo.BuildInfoRequest_BuildBot{ | |
| 130 MasterName: "foo master", | |
| 131 BuilderName: "bar builder", | |
| 132 BuildNumber: 1337, | |
| 133 }, | |
| 134 }, | |
| 135 } | |
| 136 | |
| 137 Convey("Load an invalid build", func() { | |
| 138 _, err := bip.GetBuildInfo(c, | |
| 139 &milo.BuildInfoRequest_BuildBot{ | |
| 140 MasterName: "foo master", | |
| 141 BuilderName: "bar builder", | |
| 142 BuildNumber: 1334, | |
| 143 }, "") | |
| 144 So(err.Error(), ShouldResemble, "rpc error: code = Unaut
henticated desc = ") | |
| 145 }) | |
| 146 | |
| 147 Convey("Can load a BuildBot build by log location.", func() { | |
| 148 build.Properties = append(build.Properties, []*buildbotP
roperty{ | |
| 149 {Name: "log_location", Value: "logdog://example.
com/testproject/foo/bar/+/baz/annotations"}, | |
| 150 }...) | |
| 151 So(ds.Put(c, &build), ShouldBeNil) | |
| 152 testClient.resp = []interface{}{ | |
| 153 datagramGetResponse("testproject", "foo/bar", &l
ogdogStep), | |
| 154 } | |
| 155 | |
| 156 resp, err := bip.GetBuildInfo(c, biReq.GetBuildbot(), ""
) | |
| 157 So(err, ShouldBeNil) | |
| 158 So(testClient.req, ShouldResemble, []interface{}{ | |
| 159 &logdog.TailRequest{ | |
| 160 Project: "testproject", | |
| 161 Path: "foo/bar/+/baz/annotations", | |
| 162 State: true, | |
| 163 }, | |
| 164 }) | |
| 165 So(resp, ShouldResemble, &milo.BuildInfoResponse{ | |
| 166 Project: "testproject", | |
| 167 Step: &miloProto.Step{ | |
| 168 Command: &miloProto.Step_Command{ | |
| 169 CommandLine: []string{"foo", "ba
r", "baz"}, | |
| 170 }, | |
| 171 Text: []string{"test step"}, | |
| 172 Property: []*miloProto.Step_Property{ | |
| 173 {Name: "bar", Value: "log-bar"}, | |
| 174 {Name: "foo", Value: "build-foo"
}, | |
| 175 {Name: "log_location", Value: "l
ogdog://example.com/testproject/foo/bar/+/baz/annotations"}, | |
| 176 }, | |
| 177 }, | |
| 178 AnnotationStream: &miloProto.LogdogStream{ | |
| 179 Server: "example.com", | |
| 180 Prefix: "foo/bar", | |
| 181 Name: "baz/annotations", | |
| 182 }, | |
| 183 }) | |
| 184 }) | |
| 185 | |
| 186 Convey("Can load a BuildBot build by annotation URL.", func() { | |
| 187 build.Properties = append(build.Properties, []*buildbotP
roperty{ | |
| 188 {Name: "log_location", Value: "protocol://not/a/
logdog/url"}, | |
| 189 {Name: "logdog_annotation_url", Value: "logdog:/
/example.com/testproject/foo/bar/+/baz/annotations"}, | |
| 190 }...) | |
| 191 So(ds.Put(c, &build), ShouldBeNil) | |
| 192 testClient.resp = []interface{}{ | |
| 193 datagramGetResponse("testproject", "foo/bar", &l
ogdogStep), | |
| 194 } | |
| 195 | |
| 196 resp, err := bip.GetBuildInfo(c, biReq.GetBuildbot(), ""
) | |
| 197 So(err, ShouldBeNil) | |
| 198 So(testClient.req, ShouldResemble, []interface{}{ | |
| 199 &logdog.TailRequest{ | |
| 200 Project: "testproject", | |
| 201 Path: "foo/bar/+/baz/annotations", | |
| 202 State: true, | |
| 203 }, | |
| 204 }) | |
| 205 So(resp, ShouldResemble, &milo.BuildInfoResponse{ | |
| 206 Project: "testproject", | |
| 207 Step: &miloProto.Step{ | |
| 208 Command: &miloProto.Step_Command{ | |
| 209 CommandLine: []string{"foo", "ba
r", "baz"}, | |
| 210 }, | |
| 211 Text: []string{"test step"}, | |
| 212 Property: []*miloProto.Step_Property{ | |
| 213 {Name: "bar", Value: "log-bar"}, | |
| 214 {Name: "foo", Value: "build-foo"
}, | |
| 215 {Name: "log_location", Value: "p
rotocol://not/a/logdog/url"}, | |
| 216 {Name: "logdog_annotation_url",
Value: "logdog://example.com/testproject/foo/bar/+/baz/annotations"}, | |
| 217 }, | |
| 218 }, | |
| 219 AnnotationStream: &miloProto.LogdogStream{ | |
| 220 Server: "example.com", | |
| 221 Prefix: "foo/bar", | |
| 222 Name: "baz/annotations", | |
| 223 }, | |
| 224 }) | |
| 225 }) | |
| 226 | |
| 227 Convey("Can load a BuildBot build by tag.", func() { | |
| 228 build.Properties = append(build.Properties, []*buildbotP
roperty{ | |
| 229 {Name: "logdog_prefix", Value: "foo/bar"}, | |
| 230 {Name: "logdog_project", Value: "testproject"}, | |
| 231 }...) | |
| 232 So(ds.Put(c, &build), ShouldBeNil) | |
| 233 testClient.resp = []interface{}{ | |
| 234 datagramGetResponse("testproject", "foo/bar", &l
ogdogStep), | |
| 235 } | |
| 236 | |
| 237 resp, err := bip.GetBuildInfo(c, biReq.GetBuildbot(), ""
) | |
| 238 So(err, ShouldBeNil) | |
| 239 So(testClient.req, ShouldResemble, []interface{}{ | |
| 240 &logdog.TailRequest{ | |
| 241 Project: "testproject", | |
| 242 Path: "foo/bar/+/annotations", | |
| 243 State: true, | |
| 244 }, | |
| 245 }) | |
| 246 So(resp, ShouldResemble, &milo.BuildInfoResponse{ | |
| 247 Project: "testproject", | |
| 248 Step: &miloProto.Step{ | |
| 249 Command: &miloProto.Step_Command{ | |
| 250 CommandLine: []string{"foo", "ba
r", "baz"}, | |
| 251 }, | |
| 252 Text: []string{"test step"}, | |
| 253 Property: []*miloProto.Step_Property{ | |
| 254 {Name: "bar", Value: "log-bar"}, | |
| 255 {Name: "foo", Value: "build-foo"
}, | |
| 256 {Name: "logdog_prefix", Value: "
foo/bar"}, | |
| 257 {Name: "logdog_project", Value:
"testproject"}, | |
| 258 }, | |
| 259 }, | |
| 260 AnnotationStream: &miloProto.LogdogStream{ | |
| 261 Server: "example.com", | |
| 262 Prefix: "foo/bar", | |
| 263 Name: "annotations", | |
| 264 }, | |
| 265 }) | |
| 266 }) | |
| 267 | |
| 268 Convey("Fails to load a BuildBot build by query if no project hi
nt is provided.", func() { | |
| 269 So(ds.Put(c, &build), ShouldBeNil) | |
| 270 | |
| 271 _, err := bip.GetBuildInfo(c, biReq.GetBuildbot(), "") | |
| 272 So(err, ShouldErrLike, "annotation stream not found") | |
| 273 }) | |
| 274 | |
| 275 Convey("Can load a BuildBot build by query with a project hint."
, func() { | |
| 276 So(ds.Put(c, &build), ShouldBeNil) | |
| 277 testClient.resp = []interface{}{ | |
| 278 &logdog.QueryResponse{ | |
| 279 Streams: []*logdog.QueryResponse_Stream{ | |
| 280 { | |
| 281 Path: "foo/bar/+/annotat
ions", | |
| 282 }, | |
| 283 { | |
| 284 Path: "other/ignore/+/me
", | |
| 285 }, | |
| 286 }, | |
| 287 }, | |
| 288 datagramGetResponse("testproject", "foo/bar/+/an
notations", &logdogStep), | |
| 289 } | |
| 290 | |
| 291 resp, err := bip.GetBuildInfo(c, biReq.GetBuildbot(), "t
estproject") | |
| 292 So(err, ShouldBeNil) | |
| 293 So(testClient.req, ShouldResemble, []interface{}{ | |
| 294 &logdog.QueryRequest{ | |
| 295 Project: "testproject", | |
| 296 ContentType: miloProto.ContentTypeAnnota
tions, | |
| 297 Tags: map[string]string{ | |
| 298 "buildbot.master": "foo mas
ter", | |
| 299 "buildbot.builder": "bar bui
lder", | |
| 300 "buildbot.buildnumber": "1337", | |
| 301 }, | |
| 302 }, | |
| 303 &logdog.TailRequest{ | |
| 304 Project: "testproject", | |
| 305 Path: "foo/bar/+/annotations", | |
| 306 State: true, | |
| 307 }, | |
| 308 }) | |
| 309 | |
| 310 So(resp, ShouldResemble, &milo.BuildInfoResponse{ | |
| 311 Project: "testproject", | |
| 312 Step: &miloProto.Step{ | |
| 313 Command: &miloProto.Step_Command{ | |
| 314 CommandLine: []string{"foo", "ba
r", "baz"}, | |
| 315 }, | |
| 316 Text: []string{"test step"}, | |
| 317 Property: []*miloProto.Step_Property{ | |
| 318 {Name: "bar", Value: "log-bar"}, | |
| 319 {Name: "foo", Value: "build-foo"
}, | |
| 320 }, | |
| 321 }, | |
| 322 AnnotationStream: &miloProto.LogdogStream{ | |
| 323 Server: "example.com", | |
| 324 Prefix: "foo/bar", | |
| 325 Name: "annotations", | |
| 326 }, | |
| 327 }) | |
| 328 }) | |
| 329 | |
| 330 Convey("Can load a BuildBot build by inferred name.", func() { | |
| 331 So(ds.Put(c, &build), ShouldBeNil) | |
| 332 testClient.resp = []interface{}{ | |
| 333 &logdog.QueryResponse{}, | |
| 334 datagramGetResponse("testproject", "foo/bar/+/an
notations", &logdogStep), | |
| 335 } | |
| 336 | |
| 337 resp, err := bip.GetBuildInfo(c, biReq.GetBuildbot(), "t
estproject") | |
| 338 So(err, ShouldBeNil) | |
| 339 So(testClient.req, ShouldResemble, []interface{}{ | |
| 340 &logdog.QueryRequest{ | |
| 341 Project: "testproject", | |
| 342 ContentType: miloProto.ContentTypeAnnota
tions, | |
| 343 Tags: map[string]string{ | |
| 344 "buildbot.master": "foo mas
ter", | |
| 345 "buildbot.builder": "bar bui
lder", | |
| 346 "buildbot.buildnumber": "1337", | |
| 347 }, | |
| 348 }, | |
| 349 &logdog.TailRequest{ | |
| 350 Project: "testproject", | |
| 351 Path: "bb/foo_master/bar_builder/1337
/+/annotations", | |
| 352 State: true, | |
| 353 }, | |
| 354 }) | |
| 355 | |
| 356 So(resp, ShouldResemble, &milo.BuildInfoResponse{ | |
| 357 Project: "testproject", | |
| 358 Step: &miloProto.Step{ | |
| 359 Command: &miloProto.Step_Command{ | |
| 360 CommandLine: []string{"foo", "ba
r", "baz"}, | |
| 361 }, | |
| 362 Text: []string{"test step"}, | |
| 363 Property: []*miloProto.Step_Property{ | |
| 364 {Name: "bar", Value: "log-bar"}, | |
| 365 {Name: "foo", Value: "build-foo"
}, | |
| 366 }, | |
| 367 }, | |
| 368 AnnotationStream: &miloProto.LogdogStream{ | |
| 369 Server: "example.com", | |
| 370 Prefix: "bb/foo_master/bar_builder/1337"
, | |
| 371 Name: "annotations", | |
| 372 }, | |
| 373 }) | |
| 374 }) | |
| 375 }) | |
| 376 } | |
| OLD | NEW |