go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/logdog/server/config/context_test.go (about) 1 // Copyright 2020 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package config 16 17 import ( 18 "context" 19 "testing" 20 "time" 21 22 "go.chromium.org/luci/common/clock/testclock" 23 "go.chromium.org/luci/config" 24 "go.chromium.org/luci/config/cfgclient" 25 cfgmem "go.chromium.org/luci/config/impl/memory" 26 "go.chromium.org/luci/gae/impl/memory" 27 "go.chromium.org/luci/gae/service/datastore" 28 29 . "github.com/smartystreets/goconvey/convey" 30 ) 31 32 func TestCache(t *testing.T) { 33 t.Parallel() 34 35 Convey("With mocks", t, func() { 36 configs := map[config.Set]cfgmem.Files{ 37 "services/${appid}": { 38 "services.cfg": `coordinator { admin_auth_group: "a" }`, 39 }, 40 "projects/a": { 41 "${appid}.cfg": `archive_gs_bucket: "a"`, 42 }, 43 } 44 45 ctx := context.Background() 46 ctx = memory.Use(ctx) 47 ctx, tc := testclock.UseTime(ctx, testclock.TestTimeUTC) 48 ctx = cfgclient.Use(ctx, cfgmem.New(configs)) 49 ctx = WithStore(ctx, &Store{}) 50 51 sync := func() { 52 So(Sync(ctx), ShouldBeNil) 53 datastore.GetTestable(ctx).CatchupIndexes() 54 } 55 56 sync() 57 58 Convey("Service config cache", func() { 59 cfg, err := Config(ctx) 60 So(err, ShouldBeNil) 61 So(cfg.Coordinator.AdminAuthGroup, ShouldEqual, "a") 62 63 configs["services/${appid}"]["services.cfg"] = `coordinator { admin_auth_group: "b" }` 64 sync() 65 66 // Still seeing the cached config. 67 cfg, err = Config(ctx) 68 So(err, ShouldBeNil) 69 So(cfg.Coordinator.AdminAuthGroup, ShouldEqual, "a") 70 71 tc.Add(2 * time.Minute) 72 73 // The cache expired and we loaded a newer config. 74 cfg, err = Config(ctx) 75 So(err, ShouldBeNil) 76 So(cfg.Coordinator.AdminAuthGroup, ShouldEqual, "b") 77 }) 78 79 Convey("Project config cache", func() { 80 cfg, err := ProjectConfig(ctx, "a") 81 So(err, ShouldBeNil) 82 So(cfg.ArchiveGsBucket, ShouldEqual, "a") 83 84 configs["projects/a"]["${appid}.cfg"] = `archive_gs_bucket: "b"` 85 sync() 86 87 // Still seeing the cached config. 88 cfg, err = ProjectConfig(ctx, "a") 89 So(err, ShouldBeNil) 90 So(cfg.ArchiveGsBucket, ShouldEqual, "a") 91 92 tc.Add(2 * time.Minute) 93 94 // The cache expired and we loaded a newer config. 95 cfg, err = ProjectConfig(ctx, "a") 96 So(err, ShouldBeNil) 97 So(cfg.ArchiveGsBucket, ShouldEqual, "b") 98 }) 99 100 Convey("New project", func() { 101 // Missing initially. 102 _, err := ProjectConfig(ctx, "new") 103 So(err, ShouldEqual, config.ErrNoConfig) 104 105 // Appears. 106 configs["projects/new"] = cfgmem.Files{ 107 "${appid}.cfg": `archive_gs_bucket: "a"`, 108 } 109 sync() 110 111 // Its absence is still cached. 112 _, err = ProjectConfig(ctx, "new") 113 So(err, ShouldEqual, config.ErrNoConfig) 114 115 tc.Add(2 * time.Minute) 116 117 // Appears now. 118 cfg, err := ProjectConfig(ctx, "new") 119 So(err, ShouldBeNil) 120 So(cfg.ArchiveGsBucket, ShouldEqual, "a") 121 }) 122 123 Convey("Deleted project", func() { 124 cfg, err := ProjectConfig(ctx, "a") 125 So(err, ShouldBeNil) 126 So(cfg.ArchiveGsBucket, ShouldEqual, "a") 127 128 // Gone. 129 delete(configs, "projects/a") 130 sync() 131 132 // Old config is still cached. 133 cfg, err = ProjectConfig(ctx, "a") 134 So(err, ShouldBeNil) 135 So(cfg.ArchiveGsBucket, ShouldEqual, "a") 136 137 tc.Add(2 * time.Minute) 138 139 // Gone now. 140 _, err = ProjectConfig(ctx, "a") 141 So(err, ShouldEqual, config.ErrNoConfig) 142 }) 143 }) 144 }