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  }