| 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 coordinatorTest | 5 package coordinatorTest |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "fmt" | 8 "fmt" |
| 9 "strings" |
| 10 "time" |
| 9 | 11 |
| 10 "github.com/golang/protobuf/proto" | 12 "github.com/golang/protobuf/proto" |
| 11 ds "github.com/luci/gae/service/datastore" | 13 ds "github.com/luci/gae/service/datastore" |
| 14 "github.com/luci/gae/service/info" |
| 12 "github.com/luci/luci-go/appengine/logdog/coordinator" | 15 "github.com/luci/luci-go/appengine/logdog/coordinator" |
| 13 "github.com/luci/luci-go/appengine/logdog/coordinator/config" | 16 "github.com/luci/luci-go/appengine/logdog/coordinator/config" |
| 14 "github.com/luci/luci-go/appengine/tumble" | 17 "github.com/luci/luci-go/appengine/tumble" |
| 15 "github.com/luci/luci-go/common/clock" | 18 "github.com/luci/luci-go/common/clock" |
| 16 "github.com/luci/luci-go/common/clock/testclock" | 19 "github.com/luci/luci-go/common/clock/testclock" |
| 17 luciConfig "github.com/luci/luci-go/common/config" | 20 luciConfig "github.com/luci/luci-go/common/config" |
| 18 "github.com/luci/luci-go/common/config/impl/memory" | 21 "github.com/luci/luci-go/common/config/impl/memory" |
| 19 "github.com/luci/luci-go/common/gcloud/gs" | 22 "github.com/luci/luci-go/common/gcloud/gs" |
| 20 "github.com/luci/luci-go/common/logging" | 23 "github.com/luci/luci-go/common/logging" |
| 21 "github.com/luci/luci-go/common/logging/gologger" | 24 "github.com/luci/luci-go/common/logging/gologger" |
| 22 » configProto "github.com/luci/luci-go/common/proto/config" | 25 » "github.com/luci/luci-go/common/proto/google" |
| 23 "github.com/luci/luci-go/common/proto/logdog/svcconfig" | 26 "github.com/luci/luci-go/common/proto/logdog/svcconfig" |
| 24 "github.com/luci/luci-go/server/auth" | 27 "github.com/luci/luci-go/server/auth" |
| 25 "github.com/luci/luci-go/server/auth/authtest" | 28 "github.com/luci/luci-go/server/auth/authtest" |
| 26 "github.com/luci/luci-go/server/logdog/storage" | 29 "github.com/luci/luci-go/server/logdog/storage" |
| 27 memoryStorage "github.com/luci/luci-go/server/logdog/storage/memory" | 30 memoryStorage "github.com/luci/luci-go/server/logdog/storage/memory" |
| 28 "github.com/luci/luci-go/server/settings" | 31 "github.com/luci/luci-go/server/settings" |
| 29 "golang.org/x/net/context" | 32 "golang.org/x/net/context" |
| 30 ) | 33 ) |
| 31 | 34 |
| 32 // Environment contains all of the testing facilities that are installed into | 35 // Environment contains all of the testing facilities that are installed into |
| (...skipping 27 matching lines...) Expand all Loading... |
| 60 // default) into Services. | 63 // default) into Services. |
| 61 ArchivalPublisher ArchivalPublisher | 64 ArchivalPublisher ArchivalPublisher |
| 62 } | 65 } |
| 63 | 66 |
| 64 // JoinGroup adds the named group the to the list of groups for the current | 67 // JoinGroup adds the named group the to the list of groups for the current |
| 65 // identity. | 68 // identity. |
| 66 func (e *Environment) JoinGroup(g string) { | 69 func (e *Environment) JoinGroup(g string) { |
| 67 e.AuthState.IdentityGroups = append(e.AuthState.IdentityGroups, g) | 70 e.AuthState.IdentityGroups = append(e.AuthState.IdentityGroups, g) |
| 68 } | 71 } |
| 69 | 72 |
| 73 // LeaveAllGroups clears all auth groups that the user is currently a member of. |
| 74 func (e *Environment) LeaveAllGroups() { |
| 75 e.AuthState.IdentityGroups = nil |
| 76 e.JoinGroup("all") |
| 77 } |
| 78 |
| 70 // ClearCoordinatorConfig removes the Coordinator configuration entry, | 79 // ClearCoordinatorConfig removes the Coordinator configuration entry, |
| 71 // simulating a missing config. | 80 // simulating a missing config. |
| 72 func (e *Environment) ClearCoordinatorConfig(c context.Context) { | 81 func (e *Environment) ClearCoordinatorConfig(c context.Context) { |
| 73 configSet, _ := config.ServiceConfigPath(c) | 82 configSet, _ := config.ServiceConfigPath(c) |
| 74 delete(e.Config, configSet) | 83 delete(e.Config, configSet) |
| 75 } | 84 } |
| 76 | 85 |
| 77 // ModServiceConfig loads the current service configuration, invokes the | 86 // ModServiceConfig loads the current service configuration, invokes the |
| 78 // callback with its contents, and writes the result back to config. | 87 // callback with its contents, and writes the result back to config. |
| 79 func (e *Environment) ModServiceConfig(c context.Context, fn func(*svcconfig.Coo
rdinator)) { | 88 func (e *Environment) ModServiceConfig(c context.Context, fn func(*svcconfig.Con
fig)) { |
| 80 configSet, configPath := config.ServiceConfigPath(c) | 89 configSet, configPath := config.ServiceConfigPath(c) |
| 81 | 90 |
| 82 var cfg svcconfig.Config | 91 var cfg svcconfig.Config |
| 83 e.modTextProtobuf(configSet, configPath, &cfg, func() { | 92 e.modTextProtobuf(configSet, configPath, &cfg, func() { |
| 84 » » if cfg.Coordinator == nil { | 93 » » fn(&cfg) |
| 85 » » » cfg.Coordinator = &svcconfig.Coordinator{} | |
| 86 » » } | |
| 87 » » fn(cfg.Coordinator) | |
| 88 }) | 94 }) |
| 89 } | 95 } |
| 90 | 96 |
| 97 // ModProjectConfig loads the current configuration for the named project, |
| 98 // invokes the callback with its contents, and writes the result back to config. |
| 99 func (e *Environment) ModProjectConfig(c context.Context, proj luciConfig.Projec
tName, fn func(*svcconfig.ProjectConfig)) { |
| 100 configSet, configPath := config.ProjectConfigPath(c, proj) |
| 101 |
| 102 var pcfg svcconfig.ProjectConfig |
| 103 e.modTextProtobuf(configSet, configPath, &pcfg, func() { |
| 104 fn(&pcfg) |
| 105 }) |
| 106 } |
| 107 |
| 91 // DrainTumbleAll drains all Tumble instances across all namespaces. | 108 // DrainTumbleAll drains all Tumble instances across all namespaces. |
| 92 func (e *Environment) DrainTumbleAll(c context.Context) { | 109 func (e *Environment) DrainTumbleAll(c context.Context) { |
| 93 projects, err := luciConfig.Get(c).GetProjects() | 110 projects, err := luciConfig.Get(c).GetProjects() |
| 94 if err != nil { | 111 if err != nil { |
| 95 panic(err) | 112 panic(err) |
| 96 } | 113 } |
| 97 | 114 |
| 98 for _, proj := range projects { | 115 for _, proj := range projects { |
| 99 WithProjectNamespace(c, luciConfig.ProjectName(proj.ID), func(c
context.Context) { | 116 WithProjectNamespace(c, luciConfig.ProjectName(proj.ID), func(c
context.Context) { |
| 100 e.Tumble.Drain(c) | 117 e.Tumble.Drain(c) |
| (...skipping 11 matching lines...) Expand all Loading... |
| 112 } | 129 } |
| 113 | 130 |
| 114 case luciConfig.ErrNoConfig: | 131 case luciConfig.ErrNoConfig: |
| 115 break | 132 break |
| 116 | 133 |
| 117 default: | 134 default: |
| 118 panic(err) | 135 panic(err) |
| 119 } | 136 } |
| 120 | 137 |
| 121 fn() | 138 fn() |
| 139 e.addConfigEntry(configSet, path, proto.MarshalTextString(msg)) |
| 140 } |
| 122 | 141 |
| 142 func (e *Environment) addConfigEntry(configSet, path, content string) { |
| 123 cset := e.Config[configSet] | 143 cset := e.Config[configSet] |
| 124 if cset == nil { | 144 if cset == nil { |
| 125 cset = make(map[string]string) | 145 cset = make(map[string]string) |
| 126 e.Config[configSet] = cset | 146 e.Config[configSet] = cset |
| 127 } | 147 } |
| 128 » cset[path] = proto.MarshalTextString(msg) | 148 » cset[path] = content |
| 129 } | 149 } |
| 130 | 150 |
| 131 // Install creates a testing Context and installs common test facilities into | 151 // Install creates a testing Context and installs common test facilities into |
| 132 // it, returning the Environment to which they're bound. | 152 // it, returning the Environment to which they're bound. |
| 133 func Install() (context.Context, *Environment) { | 153 func Install() (context.Context, *Environment) { |
| 134 e := Environment{ | 154 e := Environment{ |
| 135 Config: make(map[string]memory.ConfigSet), | 155 Config: make(map[string]memory.ConfigSet), |
| 136 } | 156 } |
| 137 | 157 |
| 138 // Get our starting context. This installs, among other things, in-memor
y | 158 // Get our starting context. This installs, among other things, in-memor
y |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 176 e.Clock = clock.Get(c).(testclock.TestClock) | 196 e.Clock = clock.Get(c).(testclock.TestClock) |
| 177 | 197 |
| 178 // Install GAE config service settings. | 198 // Install GAE config service settings. |
| 179 c = settings.Use(c, settings.New(&settings.MemoryStorage{})) | 199 c = settings.Use(c, settings.New(&settings.MemoryStorage{})) |
| 180 | 200 |
| 181 // Setup luci-config configuration. | 201 // Setup luci-config configuration. |
| 182 c = memory.Use(c, e.Config) | 202 c = memory.Use(c, e.Config) |
| 183 e.ConfigIface = luciConfig.Get(c) | 203 e.ConfigIface = luciConfig.Get(c) |
| 184 | 204 |
| 185 // luci-config: Projects. | 205 // luci-config: Projects. |
| 186 » addProjectConfig := func(proj luciConfig.ProjectName, localName string,
access ...string) { | 206 » projectName := info.Get(c).AppID() |
| 187 » » configSet, configPath := config.ProjectConfigPath(c, proj) | 207 » addProjectConfig := func(proj luciConfig.ProjectName, access ...string)
{ |
| 188 | 208 » » e.ModProjectConfig(c, proj, func(pcfg *svcconfig.ProjectConfig)
{ |
| 189 » » var cfg configProto.ProjectCfg | 209 » » » for _, a := range access { |
| 190 » » e.modTextProtobuf(configSet, configPath, &cfg, func() { | 210 » » » » parts := strings.SplitN(a, ":", 2) |
| 191 » » » cfg.Name = &localName | 211 » » » » group, field := parts[0], &pcfg.ReaderAuthGroups |
| 192 » » » cfg.Access = access | 212 » » » » if len(parts) == 2 { |
| 213 » » » » » switch parts[1] { |
| 214 » » » » » case "R": |
| 215 » » » » » » break |
| 216 » » » » » case "W": |
| 217 » » » » » » field = &pcfg.WriterAuthGroups |
| 218 » » » » » default: |
| 219 » » » » » » panic(a) |
| 220 » » » » » } |
| 221 » » » » } |
| 222 » » » » *field = append(*field, group) |
| 223 » » » } |
| 193 }) | 224 }) |
| 194 } | 225 } |
| 195 » addProjectConfig("proj-foo", "Foo Project", "group:all") | 226 » addProjectConfig("proj-foo", "all:R", "all:W") |
| 196 » addProjectConfig("proj-bar", "Bar Project", "group:all") | 227 » addProjectConfig("proj-bar", "all:R", "auth:W") |
| 197 » addProjectConfig("proj-baz", "Baz Project", "group:all") | 228 » addProjectConfig("proj-exclusive", "auth:R", "auth:W") |
| 198 » addProjectConfig("proj-qux", "Qux Project", "group:all") | 229 |
| 199 » addProjectConfig("proj-exclusive", "Exclusive Project", "group:auth") | 230 » // Add a project without a LogDog project config. |
| 231 » e.addConfigEntry("projects/proj-unconfigured", "not-logdog.cfg", "junk") |
| 232 |
| 233 » configSet, configName := config.ProjectConfigPath(c, "proj-malformed") |
| 234 » e.addConfigEntry(configSet, configName, "!!! not a text protobuf !!!") |
| 200 | 235 |
| 201 // luci-config: Coordinator Defaults | 236 // luci-config: Coordinator Defaults |
| 202 » e.ModServiceConfig(c, func(cfg *svcconfig.Coordinator) { | 237 » e.ModServiceConfig(c, func(cfg *svcconfig.Config) { |
| 203 » » *cfg = svcconfig.Coordinator{ | 238 » » cfg.Transport = &svcconfig.Transport{ |
| 239 » » » Type: &svcconfig.Transport_Pubsub{ |
| 240 » » » » Pubsub: &svcconfig.Transport_PubSub{ |
| 241 » » » » » Project: projectName, |
| 242 » » » » » Topic: "test-topic", |
| 243 » » » » }, |
| 244 » » » }, |
| 245 » » } |
| 246 » » cfg.Coordinator = &svcconfig.Coordinator{ |
| 204 AdminAuthGroup: "admin", | 247 AdminAuthGroup: "admin", |
| 205 ServiceAuthGroup: "services", | 248 ServiceAuthGroup: "services", |
| 249 PrefixExpiration: google.NewDuration(24 * time.Hour), |
| 206 } | 250 } |
| 207 }) | 251 }) |
| 208 | 252 |
| 209 // Setup Tumble. This also adds the two Tumble indexes to datastore. | 253 // Setup Tumble. This also adds the two Tumble indexes to datastore. |
| 210 e.Tumble.EnableDelayedMutations(c) | 254 e.Tumble.EnableDelayedMutations(c) |
| 211 | 255 |
| 212 tcfg := e.Tumble.GetConfig(c) | 256 tcfg := e.Tumble.GetConfig(c) |
| 213 tcfg.Namespaced = true | 257 tcfg.Namespaced = true |
| 214 e.Tumble.UpdateSettings(c, tcfg) | 258 e.Tumble.UpdateSettings(c, tcfg) |
| 215 | 259 |
| 216 // Install authentication state. | 260 // Install authentication state. |
| 217 c = auth.WithState(c, &e.AuthState) | 261 c = auth.WithState(c, &e.AuthState) |
| 218 | 262 |
| 219 // Setup authentication state. | 263 // Setup authentication state. |
| 220 » e.JoinGroup("all") | 264 » e.LeaveAllGroups() |
| 221 | 265 |
| 222 // Setup our default Coordinator services. | 266 // Setup our default Coordinator services. |
| 223 e.Services = Services{ | 267 e.Services = Services{ |
| 224 IS: func() (storage.Storage, error) { | 268 IS: func() (storage.Storage, error) { |
| 225 return &e.IntermediateStorage, nil | 269 return &e.IntermediateStorage, nil |
| 226 }, | 270 }, |
| 227 GS: func() (gs.Client, error) { | 271 GS: func() (gs.Client, error) { |
| 228 return &e.GSClient, nil | 272 return &e.GSClient, nil |
| 229 }, | 273 }, |
| 230 AP: func() (coordinator.ArchivalPublisher, error) { | 274 AP: func() (coordinator.ArchivalPublisher, error) { |
| 231 return &e.ArchivalPublisher, nil | 275 return &e.ArchivalPublisher, nil |
| 232 }, | 276 }, |
| 233 } | 277 } |
| 234 c = coordinator.WithServices(c, &e.Services) | 278 c = coordinator.WithServices(c, &e.Services) |
| 235 | 279 |
| 236 return c, &e | 280 return c, &e |
| 237 } | 281 } |
| 238 | 282 |
| 239 // WithProjectNamespace runs f in proj's namespace, bypassing authentication | 283 // WithProjectNamespace runs f in proj's namespace, bypassing authentication |
| 240 // checks. | 284 // checks. |
| 241 func WithProjectNamespace(c context.Context, proj luciConfig.ProjectName, f func
(context.Context)) { | 285 func WithProjectNamespace(c context.Context, proj luciConfig.ProjectName, f func
(context.Context)) { |
| 242 if err := coordinator.WithProjectNamespaceNoAuth(&c, proj); err != nil { | 286 if err := coordinator.WithProjectNamespaceNoAuth(&c, proj); err != nil { |
| 243 panic(err) | 287 panic(err) |
| 244 } | 288 } |
| 245 f(c) | 289 f(c) |
| 246 } | 290 } |
| OLD | NEW |