| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package logs | 5 package logs |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "fmt" | 8 "fmt" |
| 9 "sort" | 9 "sort" |
| 10 "testing" | 10 "testing" |
| 11 "time" | 11 "time" |
| 12 | 12 |
| 13 "github.com/luci/gae/filter/featureBreaker" | 13 "github.com/luci/gae/filter/featureBreaker" |
| 14 "github.com/luci/gae/impl/memory" | 14 "github.com/luci/gae/impl/memory" |
| 15 ds "github.com/luci/gae/service/datastore" | 15 ds "github.com/luci/gae/service/datastore" |
| 16 "github.com/luci/luci-go/appengine/logdog/coordinator" | 16 "github.com/luci/luci-go/appengine/logdog/coordinator" |
| 17 ct "github.com/luci/luci-go/appengine/logdog/coordinator/coordinatorTest
" | 17 ct "github.com/luci/luci-go/appengine/logdog/coordinator/coordinatorTest
" |
| 18 "github.com/luci/luci-go/common/api/logdog_coordinator/logs/v1" | 18 "github.com/luci/luci-go/common/api/logdog_coordinator/logs/v1" |
| 19 "github.com/luci/luci-go/common/clock/testclock" | 19 "github.com/luci/luci-go/common/clock/testclock" |
| 20 "github.com/luci/luci-go/common/config" |
| 20 "github.com/luci/luci-go/common/errors" | 21 "github.com/luci/luci-go/common/errors" |
| 21 "github.com/luci/luci-go/common/logdog/types" | 22 "github.com/luci/luci-go/common/logdog/types" |
| 22 "github.com/luci/luci-go/common/proto/google" | 23 "github.com/luci/luci-go/common/proto/google" |
| 23 "github.com/luci/luci-go/common/proto/logdog/logpb" | 24 "github.com/luci/luci-go/common/proto/logdog/logpb" |
| 24 "github.com/luci/luci-go/server/auth" | 25 "github.com/luci/luci-go/server/auth" |
| 25 "github.com/luci/luci-go/server/auth/authtest" | 26 "github.com/luci/luci-go/server/auth/authtest" |
| 26 "golang.org/x/net/context" | 27 "golang.org/x/net/context" |
| 27 | 28 |
| 28 "github.com/luci/luci-go/common/logging/gologger" | |
| 29 | |
| 30 . "github.com/luci/luci-go/common/testing/assertions" | 29 . "github.com/luci/luci-go/common/testing/assertions" |
| 31 . "github.com/smartystreets/goconvey/convey" | 30 . "github.com/smartystreets/goconvey/convey" |
| 32 ) | 31 ) |
| 33 | 32 |
| 34 func shouldHaveLogPaths(actual interface{}, expected ...interface{}) string { | 33 func shouldHaveLogPaths(actual interface{}, expected ...interface{}) string { |
| 35 resp := actual.(*logdog.QueryResponse) | 34 resp := actual.(*logdog.QueryResponse) |
| 36 var paths []string | 35 var paths []string |
| 37 if len(resp.Streams) > 0 { | 36 if len(resp.Streams) > 0 { |
| 38 paths = make([]string, len(resp.Streams)) | 37 paths = make([]string, len(resp.Streams)) |
| 39 for i, s := range resp.Streams { | 38 for i, s := range resp.Streams { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 60 | 59 |
| 61 return ShouldResemble(paths, exp) | 60 return ShouldResemble(paths, exp) |
| 62 } | 61 } |
| 63 | 62 |
| 64 func TestQuery(t *testing.T) { | 63 func TestQuery(t *testing.T) { |
| 65 t.Parallel() | 64 t.Parallel() |
| 66 | 65 |
| 67 Convey(`With a testing configuration, a Query request`, t, func() { | 66 Convey(`With a testing configuration, a Query request`, t, func() { |
| 68 c, tc := testclock.UseTime(context.Background(), testclock.TestT
imeLocal) | 67 c, tc := testclock.UseTime(context.Background(), testclock.TestT
imeLocal) |
| 69 c = memory.Use(c) | 68 c = memory.Use(c) |
| 70 c = gologger.StdConfig.Use(c) | |
| 71 c, fb := featureBreaker.FilterRDS(c, nil) | 69 c, fb := featureBreaker.FilterRDS(c, nil) |
| 72 | 70 |
| 73 di := ds.Get(c) | |
| 74 | |
| 75 // Add LogStream indexes. | 71 // Add LogStream indexes. |
| 76 // | 72 // |
| 77 // These should be kept in sync with the "query endpoint" indexe
s in the | 73 // These should be kept in sync with the "query endpoint" indexe
s in the |
| 78 // vmuser module's "index.yaml" file. | 74 // vmuser module's "index.yaml" file. |
| 79 indexDefs := [][]string{ | 75 indexDefs := [][]string{ |
| 80 {"Prefix", "-Created"}, | 76 {"Prefix", "-Created"}, |
| 81 {"Name", "-Created"}, | 77 {"Name", "-Created"}, |
| 82 {"State", "-Created"}, | 78 {"State", "-Created"}, |
| 83 {"Purged", "-Created"}, | 79 {"Purged", "-Created"}, |
| 84 {"ProtoVersion", "-Created"}, | 80 {"ProtoVersion", "-Created"}, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 95 cols := make([]ds.IndexColumn, len(id)) | 91 cols := make([]ds.IndexColumn, len(id)) |
| 96 for j, ic := range id { | 92 for j, ic := range id { |
| 97 var err error | 93 var err error |
| 98 cols[j], err = ds.ParseIndexColumn(ic) | 94 cols[j], err = ds.ParseIndexColumn(ic) |
| 99 if err != nil { | 95 if err != nil { |
| 100 panic(fmt.Errorf("failed to parse index
%q: %s", ic, err)) | 96 panic(fmt.Errorf("failed to parse index
%q: %s", ic, err)) |
| 101 } | 97 } |
| 102 } | 98 } |
| 103 indexes[i] = &ds.IndexDefinition{Kind: "LogStream", Sort
By: cols} | 99 indexes[i] = &ds.IndexDefinition{Kind: "LogStream", Sort
By: cols} |
| 104 } | 100 } |
| 105 » » di.Testable().AddIndexes(indexes...) | 101 » » ds.Get(c).Testable().AddIndexes(indexes...) |
| 106 » » di.Testable().Consistent(true) | 102 » » ds.Get(c).Testable().Consistent(true) |
| 107 | 103 |
| 108 fs := authtest.FakeState{} | 104 fs := authtest.FakeState{} |
| 109 c = auth.WithState(c, &fs) | 105 c = auth.WithState(c, &fs) |
| 110 | 106 |
| 111 svcStub := ct.Services{} | 107 svcStub := ct.Services{} |
| 112 svcStub.InitConfig() | 108 svcStub.InitConfig() |
| 113 svcStub.ServiceConfig.Coordinator.AdminAuthGroup = "test-adminis
trators" | 109 svcStub.ServiceConfig.Coordinator.AdminAuthGroup = "test-adminis
trators" |
| 114 c = coordinator.WithServices(c, &svcStub) | 110 c = coordinator.WithServices(c, &svcStub) |
| 115 | 111 |
| 116 var svrBase server | 112 var svrBase server |
| 117 svr := newService(&svrBase) | 113 svr := newService(&svrBase) |
| 118 | 114 |
| 115 // di is a datastore bound to the test project namespace. |
| 116 const project = "test-project" |
| 117 if err := coordinator.WithProjectNamespace(&c, config.ProjectNam
e(project)); err != nil { |
| 118 panic(err) |
| 119 } |
| 120 di := ds.Get(c) |
| 121 |
| 122 // Stock query request, will be modified by each test. |
| 119 req := logdog.QueryRequest{ | 123 req := logdog.QueryRequest{ |
| 120 » » » Tags: map[string]string{}, | 124 » » » Project: project, |
| 125 » » » Tags: map[string]string{}, |
| 121 } | 126 } |
| 122 | 127 |
| 123 // Install a set of stock log streams to query against. | 128 // Install a set of stock log streams to query against. |
| 124 var streamPaths []string | 129 var streamPaths []string |
| 125 var purgedStreamPaths []string | 130 var purgedStreamPaths []string |
| 126 streams := map[string]*coordinator.LogStream{} | 131 streams := map[string]*coordinator.LogStream{} |
| 127 descs := map[string]*logpb.LogStreamDescriptor{} | 132 descs := map[string]*logpb.LogStreamDescriptor{} |
| 128 for i, v := range []types.StreamPath{ | 133 for i, v := range []types.StreamPath{ |
| 129 "testing/+/foo", | 134 "testing/+/foo", |
| 130 "testing/+/foo/bar", | 135 "testing/+/foo/bar", |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 180 | 185 |
| 181 case "datagram": | 186 case "datagram": |
| 182 ls.StreamType = logpb.StreamType
_DATAGRAM | 187 ls.StreamType = logpb.StreamType
_DATAGRAM |
| 183 | 188 |
| 184 case "binary": | 189 case "binary": |
| 185 ls.StreamType = logpb.StreamType
_BINARY | 190 ls.StreamType = logpb.StreamType
_BINARY |
| 186 } | 191 } |
| 187 } | 192 } |
| 188 } | 193 } |
| 189 | 194 |
| 190 » » » if err := ds.Get(c).Put(ls); err != nil { | 195 » » » if err := di.Put(ls); err != nil { |
| 191 panic(fmt.Errorf("failed to put log stream %d: %
v", i, err)) | 196 panic(fmt.Errorf("failed to put log stream %d: %
v", i, err)) |
| 192 } | 197 } |
| 193 | 198 |
| 194 descs[string(v)] = desc | 199 descs[string(v)] = desc |
| 195 streams[string(v)] = ls | 200 streams[string(v)] = ls |
| 196 if !ls.Purged { | 201 if !ls.Purged { |
| 197 streamPaths = append(streamPaths, string(v)) | 202 streamPaths = append(streamPaths, string(v)) |
| 198 } | 203 } |
| 199 purgedStreamPaths = append(purgedStreamPaths, string(v)) | 204 purgedStreamPaths = append(purgedStreamPaths, string(v)) |
| 200 tc.Add(time.Second) | 205 tc.Add(time.Second) |
| (...skipping 10 matching lines...) Expand all Loading... |
| 211 } | 216 } |
| 212 invert(streamPaths) | 217 invert(streamPaths) |
| 213 invert(purgedStreamPaths) | 218 invert(purgedStreamPaths) |
| 214 | 219 |
| 215 Convey(`An empty query will return all log streams.`, func() { | 220 Convey(`An empty query will return all log streams.`, func() { |
| 216 resp, err := svr.Query(c, &req) | 221 resp, err := svr.Query(c, &req) |
| 217 So(err, ShouldBeRPCOK) | 222 So(err, ShouldBeRPCOK) |
| 218 So(resp, shouldHaveLogPaths, streamPaths) | 223 So(resp, shouldHaveLogPaths, streamPaths) |
| 219 }) | 224 }) |
| 220 | 225 |
| 226 Convey(`An empty query to a different project return no log stre
ams.`, func() { |
| 227 req.Project = "does-not-exist" |
| 228 |
| 229 resp, err := svr.Query(c, &req) |
| 230 So(err, ShouldBeRPCOK) |
| 231 So(resp, shouldHaveLogPaths) |
| 232 }) |
| 233 |
| 221 Convey(`An empty query will include purged streams if admin.`, f
unc() { | 234 Convey(`An empty query will include purged streams if admin.`, f
unc() { |
| 222 fs.IdentityGroups = []string{"test-administrators"} | 235 fs.IdentityGroups = []string{"test-administrators"} |
| 223 | 236 |
| 224 resp, err := svr.Query(c, &req) | 237 resp, err := svr.Query(c, &req) |
| 225 So(err, ShouldBeRPCOK) | 238 So(err, ShouldBeRPCOK) |
| 226 So(resp, shouldHaveLogPaths, purgedStreamPaths) | 239 So(resp, shouldHaveLogPaths, purgedStreamPaths) |
| 227 }) | 240 }) |
| 228 | 241 |
| 229 Convey(`A query with an invalid path will return BadRequest erro
r.`, func() { | 242 Convey(`A query with an invalid path will return BadRequest erro
r.`, func() { |
| 230 req.Path = "***" | 243 req.Path = "***" |
| (...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 514 | 527 |
| 515 Convey(`When an invalid tag is specified, returns BadReq
uest error`, func() { | 528 Convey(`When an invalid tag is specified, returns BadReq
uest error`, func() { |
| 516 req.Tags["+++not a valid tag+++"] = "" | 529 req.Tags["+++not a valid tag+++"] = "" |
| 517 | 530 |
| 518 _, err := svr.Query(c, &req) | 531 _, err := svr.Query(c, &req) |
| 519 So(err, ShouldBeRPCInvalidArgument, "invalid tag
constraint") | 532 So(err, ShouldBeRPCInvalidArgument, "invalid tag
constraint") |
| 520 }) | 533 }) |
| 521 }) | 534 }) |
| 522 }) | 535 }) |
| 523 } | 536 } |
| OLD | NEW |