| OLD | NEW |
| 1 // Copyright 2015 The LUCI Authors. All rights reserved. | 1 // Copyright 2015 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
| 4 | 4 |
| 5 package coordinatorTest | 5 package coordinatorTest |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "fmt" | 8 "fmt" |
| 9 "strings" | 9 "strings" |
| 10 "time" | 10 "time" |
| 11 | 11 |
| 12 "github.com/luci/luci-go/common/clock" | 12 "github.com/luci/luci-go/common/clock" |
| 13 "github.com/luci/luci-go/common/clock/testclock" | 13 "github.com/luci/luci-go/common/clock/testclock" |
| 14 luciConfig "github.com/luci/luci-go/common/config" | 14 luciConfig "github.com/luci/luci-go/common/config" |
| 15 "github.com/luci/luci-go/common/config/impl/memory" | 15 "github.com/luci/luci-go/common/config/impl/memory" |
| 16 "github.com/luci/luci-go/common/data/caching/cacheContext" | 16 "github.com/luci/luci-go/common/data/caching/cacheContext" |
| 17 "github.com/luci/luci-go/common/gcloud/gs" | 17 "github.com/luci/luci-go/common/gcloud/gs" |
| 18 "github.com/luci/luci-go/common/logging" | 18 "github.com/luci/luci-go/common/logging" |
| 19 "github.com/luci/luci-go/common/logging/gologger" | 19 "github.com/luci/luci-go/common/logging/gologger" |
| 20 "github.com/luci/luci-go/common/proto/google" | 20 "github.com/luci/luci-go/common/proto/google" |
| 21 "github.com/luci/luci-go/logdog/api/config/svcconfig" | 21 "github.com/luci/luci-go/logdog/api/config/svcconfig" |
| 22 "github.com/luci/luci-go/logdog/appengine/coordinator" | 22 "github.com/luci/luci-go/logdog/appengine/coordinator" |
| 23 "github.com/luci/luci-go/logdog/appengine/coordinator/config" | 23 "github.com/luci/luci-go/logdog/appengine/coordinator/config" |
| 24 "github.com/luci/luci-go/logdog/common/storage/archive" | 24 "github.com/luci/luci-go/logdog/common/storage/archive" |
| 25 "github.com/luci/luci-go/logdog/common/storage/bigtable" | 25 "github.com/luci/luci-go/logdog/common/storage/bigtable" |
| 26 "github.com/luci/luci-go/luci_config/common/cfgtypes" |
| 26 "github.com/luci/luci-go/server/auth" | 27 "github.com/luci/luci-go/server/auth" |
| 27 "github.com/luci/luci-go/server/auth/authtest" | 28 "github.com/luci/luci-go/server/auth/authtest" |
| 28 "github.com/luci/luci-go/server/auth/identity" | 29 "github.com/luci/luci-go/server/auth/identity" |
| 29 "github.com/luci/luci-go/server/settings" | 30 "github.com/luci/luci-go/server/settings" |
| 30 "github.com/luci/luci-go/tumble" | 31 "github.com/luci/luci-go/tumble" |
| 31 | 32 |
| 32 ds "github.com/luci/gae/service/datastore" | 33 ds "github.com/luci/gae/service/datastore" |
| 33 "github.com/luci/gae/service/info" | 34 "github.com/luci/gae/service/info" |
| 34 | 35 |
| 35 "github.com/golang/protobuf/proto" | 36 "github.com/golang/protobuf/proto" |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 89 // LeaveAllGroups clears all auth groups that the user is currently a member of. | 90 // LeaveAllGroups clears all auth groups that the user is currently a member of. |
| 90 func (e *Environment) LeaveAllGroups() { | 91 func (e *Environment) LeaveAllGroups() { |
| 91 e.AuthState.IdentityGroups = nil | 92 e.AuthState.IdentityGroups = nil |
| 92 e.JoinGroup("all") | 93 e.JoinGroup("all") |
| 93 } | 94 } |
| 94 | 95 |
| 95 // ClearCoordinatorConfig removes the Coordinator configuration entry, | 96 // ClearCoordinatorConfig removes the Coordinator configuration entry, |
| 96 // simulating a missing config. | 97 // simulating a missing config. |
| 97 func (e *Environment) ClearCoordinatorConfig(c context.Context) { | 98 func (e *Environment) ClearCoordinatorConfig(c context.Context) { |
| 98 configSet, _ := config.ServiceConfigPath(c) | 99 configSet, _ := config.ServiceConfigPath(c) |
| 99 » delete(e.Config, configSet) | 100 » delete(e.Config, string(configSet)) |
| 100 } | 101 } |
| 101 | 102 |
| 102 // ModServiceConfig loads the current service configuration, invokes the | 103 // ModServiceConfig loads the current service configuration, invokes the |
| 103 // callback with its contents, and writes the result back to config. | 104 // callback with its contents, and writes the result back to config. |
| 104 func (e *Environment) ModServiceConfig(c context.Context, fn func(*svcconfig.Con
fig)) { | 105 func (e *Environment) ModServiceConfig(c context.Context, fn func(*svcconfig.Con
fig)) { |
| 105 configSet, configPath := config.ServiceConfigPath(c) | 106 configSet, configPath := config.ServiceConfigPath(c) |
| 106 | 107 |
| 107 var cfg svcconfig.Config | 108 var cfg svcconfig.Config |
| 108 e.modTextProtobuf(c, configSet, configPath, &cfg, func() { | 109 e.modTextProtobuf(c, configSet, configPath, &cfg, func() { |
| 109 fn(&cfg) | 110 fn(&cfg) |
| 110 }) | 111 }) |
| 111 } | 112 } |
| 112 | 113 |
| 113 // ModProjectConfig loads the current configuration for the named project, | 114 // ModProjectConfig loads the current configuration for the named project, |
| 114 // invokes the callback with its contents, and writes the result back to config. | 115 // invokes the callback with its contents, and writes the result back to config. |
| 115 func (e *Environment) ModProjectConfig(c context.Context, proj luciConfig.Projec
tName, fn func(*svcconfig.ProjectConfig)) { | 116 func (e *Environment) ModProjectConfig(c context.Context, proj cfgtypes.ProjectN
ame, fn func(*svcconfig.ProjectConfig)) { |
| 116 » configSet, configPath := luciConfig.ProjectConfigSet(proj), config.Proje
ctConfigPath(c) | 117 » configSet, configPath := cfgtypes.ProjectConfigSet(proj), config.Project
ConfigPath(c) |
| 117 | 118 |
| 118 var pcfg svcconfig.ProjectConfig | 119 var pcfg svcconfig.ProjectConfig |
| 119 e.modTextProtobuf(c, configSet, configPath, &pcfg, func() { | 120 e.modTextProtobuf(c, configSet, configPath, &pcfg, func() { |
| 120 fn(&pcfg) | 121 fn(&pcfg) |
| 121 }) | 122 }) |
| 122 } | 123 } |
| 123 | 124 |
| 124 // IterateTumbleAll iterates all Tumble instances across all namespaces. | 125 // IterateTumbleAll iterates all Tumble instances across all namespaces. |
| 125 func (e *Environment) IterateTumbleAll(c context.Context) { | 126 func (e *Environment) IterateTumbleAll(c context.Context) { |
| 126 projects, err := luciConfig.GetProjects(c) | 127 projects, err := luciConfig.GetProjects(c) |
| 127 if err != nil { | 128 if err != nil { |
| 128 panic(err) | 129 panic(err) |
| 129 } | 130 } |
| 130 | 131 |
| 131 for _, proj := range projects { | 132 for _, proj := range projects { |
| 132 » » WithProjectNamespace(c, luciConfig.ProjectName(proj.ID), func(c
context.Context) { | 133 » » WithProjectNamespace(c, cfgtypes.ProjectName(proj.ID), func(c co
ntext.Context) { |
| 133 e.Tumble.Iterate(c) | 134 e.Tumble.Iterate(c) |
| 134 }) | 135 }) |
| 135 } | 136 } |
| 136 } | 137 } |
| 137 | 138 |
| 138 func (e *Environment) modTextProtobuf(c context.Context, configSet, path string,
msg proto.Message, fn func()) { | 139 func (e *Environment) modTextProtobuf(c context.Context, configSet cfgtypes.Conf
igSet, path string, msg proto.Message, fn func()) { |
| 139 » cfg, err := e.ConfigIface.GetConfig(c, configSet, path, false) | 140 » cfg, err := e.ConfigIface.GetConfig(c, string(configSet), path, false) |
| 140 | 141 |
| 141 switch err { | 142 switch err { |
| 142 case nil: | 143 case nil: |
| 143 if err := proto.UnmarshalText(cfg.Content, msg); err != nil { | 144 if err := proto.UnmarshalText(cfg.Content, msg); err != nil { |
| 144 panic(err) | 145 panic(err) |
| 145 } | 146 } |
| 146 | 147 |
| 147 case luciConfig.ErrNoConfig: | 148 case luciConfig.ErrNoConfig: |
| 148 break | 149 break |
| 149 | 150 |
| 150 default: | 151 default: |
| 151 panic(err) | 152 panic(err) |
| 152 } | 153 } |
| 153 | 154 |
| 154 fn() | 155 fn() |
| 155 e.addConfigEntry(configSet, path, proto.MarshalTextString(msg)) | 156 e.addConfigEntry(configSet, path, proto.MarshalTextString(msg)) |
| 156 } | 157 } |
| 157 | 158 |
| 158 func (e *Environment) addConfigEntry(configSet, path, content string) { | 159 func (e *Environment) addConfigEntry(configSet cfgtypes.ConfigSet, path, content
string) { |
| 159 » cset := e.Config[configSet] | 160 » cset := e.Config[string(configSet)] |
| 160 if cset == nil { | 161 if cset == nil { |
| 161 cset = make(map[string]string) | 162 cset = make(map[string]string) |
| 162 » » e.Config[configSet] = cset | 163 » » e.Config[string(configSet)] = cset |
| 163 } | 164 } |
| 164 cset[path] = content | 165 cset[path] = content |
| 165 } | 166 } |
| 166 | 167 |
| 167 // Install creates a testing Context and installs common test facilities into | 168 // Install creates a testing Context and installs common test facilities into |
| 168 // it, returning the Environment to which they're bound. | 169 // it, returning the Environment to which they're bound. |
| 169 func Install() (context.Context, *Environment) { | 170 func Install() (context.Context, *Environment) { |
| 170 e := Environment{ | 171 e := Environment{ |
| 171 Config: make(map[string]memory.ConfigSet), | 172 Config: make(map[string]memory.ConfigSet), |
| 172 GSClient: GSClient{}, | 173 GSClient: GSClient{}, |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 222 | 223 |
| 223 // Install GAE config service settings. | 224 // Install GAE config service settings. |
| 224 c = settings.Use(c, settings.New(&settings.MemoryStorage{})) | 225 c = settings.Use(c, settings.New(&settings.MemoryStorage{})) |
| 225 | 226 |
| 226 // Setup luci-config configuration. | 227 // Setup luci-config configuration. |
| 227 e.ConfigIface = memory.New(e.Config) | 228 e.ConfigIface = memory.New(e.Config) |
| 228 c = luciConfig.SetImplementation(c, e.ConfigIface) | 229 c = luciConfig.SetImplementation(c, e.ConfigIface) |
| 229 | 230 |
| 230 // luci-config: Projects. | 231 // luci-config: Projects. |
| 231 projectName := info.AppID(c) | 232 projectName := info.AppID(c) |
| 232 » addProjectConfig := func(proj luciConfig.ProjectName, access ...string)
{ | 233 » addProjectConfig := func(proj cfgtypes.ProjectName, access ...string) { |
| 233 e.ModProjectConfig(c, proj, func(pcfg *svcconfig.ProjectConfig)
{ | 234 e.ModProjectConfig(c, proj, func(pcfg *svcconfig.ProjectConfig)
{ |
| 234 for _, a := range access { | 235 for _, a := range access { |
| 235 parts := strings.SplitN(a, ":", 2) | 236 parts := strings.SplitN(a, ":", 2) |
| 236 group, field := parts[0], &pcfg.ReaderAuthGroups | 237 group, field := parts[0], &pcfg.ReaderAuthGroups |
| 237 if len(parts) == 2 { | 238 if len(parts) == 2 { |
| 238 switch parts[1] { | 239 switch parts[1] { |
| 239 case "R": | 240 case "R": |
| 240 break | 241 break |
| 241 case "W": | 242 case "W": |
| 242 field = &pcfg.WriterAuthGroups | 243 field = &pcfg.WriterAuthGroups |
| 243 default: | 244 default: |
| 244 panic(a) | 245 panic(a) |
| 245 } | 246 } |
| 246 } | 247 } |
| 247 *field = append(*field, group) | 248 *field = append(*field, group) |
| 248 } | 249 } |
| 249 }) | 250 }) |
| 250 } | 251 } |
| 251 addProjectConfig("proj-foo", "all:R", "all:W") | 252 addProjectConfig("proj-foo", "all:R", "all:W") |
| 252 addProjectConfig("proj-bar", "all:R", "auth:W") | 253 addProjectConfig("proj-bar", "all:R", "auth:W") |
| 253 addProjectConfig("proj-exclusive", "auth:R", "auth:W") | 254 addProjectConfig("proj-exclusive", "auth:R", "auth:W") |
| 254 | 255 |
| 255 // Add a project without a LogDog project config. | 256 // Add a project without a LogDog project config. |
| 256 e.addConfigEntry("projects/proj-unconfigured", "not-logdog.cfg", "junk") | 257 e.addConfigEntry("projects/proj-unconfigured", "not-logdog.cfg", "junk") |
| 257 | 258 |
| 258 » configSet, configPath := luciConfig.ProjectConfigSet("proj-malformed"),
config.ProjectConfigPath(c) | 259 » configSet, configPath := cfgtypes.ProjectConfigSet("proj-malformed"), co
nfig.ProjectConfigPath(c) |
| 259 e.addConfigEntry(configSet, configPath, "!!! not a text protobuf !!!") | 260 e.addConfigEntry(configSet, configPath, "!!! not a text protobuf !!!") |
| 260 | 261 |
| 261 // luci-config: Coordinator Defaults | 262 // luci-config: Coordinator Defaults |
| 262 e.ModServiceConfig(c, func(cfg *svcconfig.Config) { | 263 e.ModServiceConfig(c, func(cfg *svcconfig.Config) { |
| 263 cfg.Transport = &svcconfig.Transport{ | 264 cfg.Transport = &svcconfig.Transport{ |
| 264 Type: &svcconfig.Transport_Pubsub{ | 265 Type: &svcconfig.Transport_Pubsub{ |
| 265 Pubsub: &svcconfig.Transport_PubSub{ | 266 Pubsub: &svcconfig.Transport_PubSub{ |
| 266 Project: projectName, | 267 Project: projectName, |
| 267 Topic: "test-topic", | 268 Topic: "test-topic", |
| 268 }, | 269 }, |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 320 return &e.ArchivalPublisher, nil | 321 return &e.ArchivalPublisher, nil |
| 321 }, | 322 }, |
| 322 } | 323 } |
| 323 c = coordinator.WithServices(c, &e.Services) | 324 c = coordinator.WithServices(c, &e.Services) |
| 324 | 325 |
| 325 return cacheContext.Wrap(c), &e | 326 return cacheContext.Wrap(c), &e |
| 326 } | 327 } |
| 327 | 328 |
| 328 // WithProjectNamespace runs f in proj's namespace, bypassing authentication | 329 // WithProjectNamespace runs f in proj's namespace, bypassing authentication |
| 329 // checks. | 330 // checks. |
| 330 func WithProjectNamespace(c context.Context, proj luciConfig.ProjectName, f func
(context.Context)) { | 331 func WithProjectNamespace(c context.Context, proj cfgtypes.ProjectName, f func(c
ontext.Context)) { |
| 331 if err := coordinator.WithProjectNamespace(&c, proj, coordinator.Namespa
ceAccessAllTesting); err != nil { | 332 if err := coordinator.WithProjectNamespace(&c, proj, coordinator.Namespa
ceAccessAllTesting); err != nil { |
| 332 panic(err) | 333 panic(err) |
| 333 } | 334 } |
| 334 f(c) | 335 f(c) |
| 335 } | 336 } |
| OLD | NEW |