go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/server/quotabeta/quotaconfig/configservice/configservice_test.go (about) 1 // Copyright 2022 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 configservice 16 17 import ( 18 "context" 19 "testing" 20 21 "google.golang.org/protobuf/proto" 22 23 "go.chromium.org/luci/config" 24 "go.chromium.org/luci/config/cfgclient" 25 "go.chromium.org/luci/config/impl/memory" 26 27 "go.chromium.org/luci/server/caching" 28 "go.chromium.org/luci/server/caching/cachingtest" 29 pb "go.chromium.org/luci/server/quotabeta/proto" 30 "go.chromium.org/luci/server/quotabeta/quotaconfig" 31 32 . "github.com/smartystreets/goconvey/convey" 33 . "go.chromium.org/luci/common/testing/assertions" 34 ) 35 36 func TestConfigService(t *testing.T) { 37 t.Parallel() 38 39 Convey("ConfigService", t, func() { 40 ctx := cachingtest.WithGlobalCache(context.Background(), map[string]caching.BlobCache{ 41 "quota.configservice": cachingtest.NewBlobCache(), 42 }) 43 44 Convey("New", func() { 45 Convey("no cache", func() { 46 shouldPanic := func() { 47 New(context.Background(), "services/test", "policies.cfg") 48 } 49 So(shouldPanic, ShouldPanicLike, "no global cache available") 50 }) 51 52 Convey("ok", func() { 53 So(New(ctx, "services/test", "policies.cfg"), ShouldNotBeNil) 54 }) 55 }) 56 57 Convey("Get", func() { 58 c := &configService{ 59 cache: caching.GlobalCache(ctx, "quota.configservice"), 60 cfgSet: "services/test", 61 path: "policies.cfg", 62 } 63 So(c.cache, ShouldNotBeNil) 64 bytes, err := proto.Marshal(&pb.Policy{ 65 Name: "name", 66 Resources: 1, 67 Replenishment: 1, 68 }) 69 So(err, ShouldBeNil) 70 So(c.cache.Set(ctx, "name", bytes, 0), ShouldBeNil) 71 72 Convey("policy not found", func() { 73 p, err := c.Get(ctx, "missing") 74 So(err, ShouldEqual, quotaconfig.ErrNotFound) 75 So(p, ShouldBeNil) 76 }) 77 78 Convey("found", func() { 79 p, err := c.Get(ctx, "name") 80 So(err, ShouldBeNil) 81 So(p, ShouldResembleProto, &pb.Policy{ 82 Name: "name", 83 Resources: 1, 84 Replenishment: 1, 85 }) 86 }) 87 88 Convey("immutable", func() { 89 p, err := c.Get(ctx, "name") 90 So(err, ShouldBeNil) 91 So(p, ShouldResembleProto, &pb.Policy{ 92 Name: "name", 93 Resources: 1, 94 Replenishment: 1, 95 }) 96 97 p.Resources++ 98 99 p, err = c.Get(ctx, "name") 100 So(err, ShouldBeNil) 101 So(p, ShouldResembleProto, &pb.Policy{ 102 Name: "name", 103 Resources: 1, 104 Replenishment: 1, 105 }) 106 }) 107 }) 108 109 Convey("Refresh", func() { 110 c := &configService{ 111 cache: caching.GlobalCache(ctx, "quota.configservice"), 112 cfgSet: "services/test", 113 path: "policies.cfg", 114 } 115 So(c.cache, ShouldNotBeNil) 116 117 Convey("not found", func() { 118 ctx := cfgclient.Use(ctx, memory.New(map[config.Set]memory.Files{})) 119 So(c.Refresh(ctx), ShouldErrLike, "no such config") 120 }) 121 122 Convey("empty", func() { 123 ctx := cfgclient.Use(ctx, memory.New(map[config.Set]memory.Files{ 124 "services/test": map[string]string{ 125 "policies.cfg": "", 126 }, 127 })) 128 So(c.Refresh(ctx), ShouldBeNil) 129 }) 130 131 Convey("invalid config", func() { 132 ctx := cfgclient.Use(ctx, memory.New(map[config.Set]memory.Files{ 133 "services/test": map[string]string{ 134 "policies.cfg": "invalid", 135 }, 136 })) 137 So(c.Refresh(ctx), ShouldErrLike, "unknown field name") 138 }) 139 140 Convey("invalid policy", func() { 141 ctx := cfgclient.Use(ctx, memory.New(map[config.Set]memory.Files{ 142 "services/test": map[string]string{ 143 "policies.cfg": ` 144 policy { 145 name: "name", 146 resources: -1, 147 } 148 `, 149 }, 150 })) 151 So(c.Refresh(ctx), ShouldErrLike, "did not pass validation") 152 153 p, err := c.Get(ctx, "name") 154 So(err, ShouldEqual, quotaconfig.ErrNotFound) 155 So(p, ShouldBeNil) 156 }) 157 158 Convey("one", func() { 159 ctx := cfgclient.Use(ctx, memory.New(map[config.Set]memory.Files{ 160 "services/test": map[string]string{ 161 "policies.cfg": ` 162 policy { 163 name: "name", 164 resources: 2, 165 replenishment: 1, 166 } 167 `, 168 }, 169 })) 170 So(c.Refresh(ctx), ShouldBeNil) 171 172 p, err := c.Get(ctx, "name") 173 So(err, ShouldBeNil) 174 So(p, ShouldResembleProto, &pb.Policy{ 175 Name: "name", 176 Resources: 2, 177 Replenishment: 1, 178 }) 179 }) 180 181 Convey("many", func() { 182 ctx := cfgclient.Use(ctx, memory.New(map[config.Set]memory.Files{ 183 "services/test": map[string]string{ 184 "policies.cfg": ` 185 policy { 186 name: "policy1", 187 resources: 1, 188 } 189 policy { 190 name: "policy2", 191 } 192 policy { 193 name: "policy3", 194 replenishment: 1, 195 } 196 `, 197 }, 198 })) 199 So(c.Refresh(ctx), ShouldBeNil) 200 201 p, err := c.Get(ctx, "policy1") 202 So(err, ShouldBeNil) 203 So(p, ShouldResembleProto, &pb.Policy{ 204 Name: "policy1", 205 Resources: 1, 206 }) 207 208 p, err = c.Get(ctx, "policy2") 209 So(err, ShouldBeNil) 210 So(p, ShouldResembleProto, &pb.Policy{ 211 Name: "policy2", 212 }) 213 214 p, err = c.Get(ctx, "policy3") 215 So(err, ShouldBeNil) 216 So(p, ShouldResembleProto, &pb.Policy{ 217 Name: "policy3", 218 Replenishment: 1, 219 }) 220 }) 221 222 Convey("update", func() { 223 bytes, err := proto.Marshal(&pb.Policy{ 224 Name: "name", 225 Resources: 1, 226 Replenishment: 1, 227 }) 228 So(err, ShouldBeNil) 229 So(c.cache.Set(ctx, "name", bytes, 0), ShouldBeNil) 230 231 p, err := c.Get(ctx, "name") 232 So(err, ShouldBeNil) 233 So(p, ShouldResembleProto, &pb.Policy{ 234 Name: "name", 235 Resources: 1, 236 Replenishment: 1, 237 }) 238 239 ctx := cfgclient.Use(ctx, memory.New(map[config.Set]memory.Files{ 240 "services/test": map[string]string{ 241 "policies.cfg": ` 242 policy { 243 name: "name", 244 resources: 2, 245 replenishment: 1, 246 } 247 `, 248 }, 249 })) 250 So(c.Refresh(ctx), ShouldBeNil) 251 252 p, err = c.Get(ctx, "name") 253 So(err, ShouldBeNil) 254 So(p, ShouldResembleProto, &pb.Policy{ 255 Name: "name", 256 Resources: 2, 257 Replenishment: 1, 258 }) 259 260 ctx = cfgclient.Use(ctx, memory.New(map[config.Set]memory.Files{ 261 "services/test": map[string]string{ 262 "policies.cfg": ` 263 policy { 264 name: "name", 265 resources: 2, 266 replenishment: 2, 267 } 268 `, 269 }, 270 })) 271 So(c.Refresh(ctx), ShouldBeNil) 272 273 p, err = c.Get(ctx, "name") 274 So(err, ShouldBeNil) 275 So(p, ShouldResembleProto, &pb.Policy{ 276 Name: "name", 277 Resources: 2, 278 Replenishment: 2, 279 }) 280 }) 281 }) 282 }) 283 }