go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/swarming/server/cfg/pools_test.go (about)

     1  // Copyright 2023 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 cfg
    16  
    17  import (
    18  	"context"
    19  	"testing"
    20  
    21  	"go.chromium.org/luci/common/errors"
    22  	"go.chromium.org/luci/config/validation"
    23  
    24  	configpb "go.chromium.org/luci/swarming/proto/config"
    25  
    26  	. "github.com/smartystreets/goconvey/convey"
    27  )
    28  
    29  var goodPoolsCfg = &configpb.PoolsCfg{
    30  	Pool: []*configpb.Pool{
    31  		{
    32  			Name:             []string{"a"},
    33  			Realm:            "test:1",
    34  			DefaultTaskRealm: "test:default",
    35  		},
    36  		{
    37  			Name:  []string{"b", "c"},
    38  			Realm: "test:2",
    39  		},
    40  	},
    41  }
    42  
    43  func TestNewPoolsConfig(t *testing.T) {
    44  	t.Parallel()
    45  
    46  	Convey("Works", t, func() {
    47  		pools, err := newPoolsConfig(goodPoolsCfg)
    48  		So(err, ShouldBeNil)
    49  		So(pools, ShouldHaveLength, 3)
    50  
    51  		So(pools["a"].Realm, ShouldEqual, "test:1")
    52  		So(pools["b"].Realm, ShouldEqual, "test:2")
    53  		So(pools["c"].Realm, ShouldEqual, "test:2")
    54  
    55  		So(pools["a"].DefaultTaskRealm, ShouldEqual, "test:default")
    56  		So(pools["b"].DefaultTaskRealm, ShouldEqual, "")
    57  		So(pools["c"].DefaultTaskRealm, ShouldEqual, "")
    58  	})
    59  }
    60  
    61  func TestPoolsValidation(t *testing.T) {
    62  	t.Parallel()
    63  
    64  	call := func(cfg *configpb.PoolsCfg) []string {
    65  		ctx := validation.Context{Context: context.Background()}
    66  		ctx.SetFile("pools.cfg")
    67  		validatePoolsCfg(&ctx, cfg)
    68  		if err := ctx.Finalize(); err != nil {
    69  			var verr *validation.Error
    70  			errors.As(err, &verr)
    71  			out := make([]string, len(verr.Errors))
    72  			for i, err := range verr.Errors {
    73  				out[i] = err.Error()
    74  			}
    75  			return out
    76  		}
    77  		return nil
    78  	}
    79  
    80  	Convey("Empty", t, func() {
    81  		So(call(&configpb.PoolsCfg{}), ShouldBeNil)
    82  	})
    83  
    84  	Convey("Good", t, func() {
    85  		So(call(goodPoolsCfg), ShouldBeNil)
    86  	})
    87  
    88  	Convey("Errors", t, func() {
    89  		onePool := func(p *configpb.Pool) *configpb.PoolsCfg {
    90  			return &configpb.PoolsCfg{
    91  				Pool: []*configpb.Pool{p},
    92  			}
    93  		}
    94  
    95  		testCases := []struct {
    96  			cfg *configpb.PoolsCfg
    97  			err string
    98  		}{
    99  			{
   100  				cfg: onePool(&configpb.Pool{
   101  					Name:       []string{"a"},
   102  					Realm:      "test:1",
   103  					Schedulers: &configpb.Schedulers{},
   104  				}),
   105  				err: "(pool #1 (a)): setting deprecated field `schedulers`",
   106  			},
   107  			{
   108  				cfg: onePool(&configpb.Pool{
   109  					Name:          []string{"a"},
   110  					Realm:         "test:1",
   111  					BotMonitoring: "bzzz",
   112  				}),
   113  				err: "(pool #1 (a)): setting deprecated field `bot_monitoring`",
   114  			},
   115  			{
   116  				cfg: onePool(&configpb.Pool{
   117  					Realm: "test:1",
   118  				}),
   119  				err: "(pool #1 (unnamed)): at least one pool name must be given",
   120  			},
   121  			{
   122  				cfg: onePool(&configpb.Pool{
   123  					Name:  []string{"a", ""},
   124  					Realm: "test:1",
   125  				}),
   126  				err: `(pool #1 (a,)): bad pool name "": the value cannot be empty`,
   127  			},
   128  			{
   129  				cfg: onePool(&configpb.Pool{
   130  					Name:  []string{"a", "a"},
   131  					Realm: "test:1",
   132  				}),
   133  				err: "(pool #1 (a,a)): pool \"a\" was already declared",
   134  			},
   135  			{
   136  				cfg: onePool(&configpb.Pool{
   137  					Name: []string{"a"},
   138  				}),
   139  				err: "(pool #1 (a)): missing required `realm` field",
   140  			},
   141  			{
   142  				cfg: onePool(&configpb.Pool{
   143  					Name:  []string{"a"},
   144  					Realm: "not-global",
   145  				}),
   146  				err: "(pool #1 (a)): bad `realm` field: bad global realm name \"not-global\" - should be <project>:<realm>",
   147  			},
   148  			{
   149  				cfg: onePool(&configpb.Pool{
   150  					Name:             []string{"a"},
   151  					Realm:            "test:1",
   152  					DefaultTaskRealm: "not-global",
   153  				}),
   154  				err: "(pool #1 (a)): bad `default_task_realm` field: bad global realm name \"not-global\" - should be <project>:<realm>",
   155  			},
   156  		}
   157  		for _, cs := range testCases {
   158  			So(call(cs.cfg), ShouldResemble, []string{`in "pools.cfg" ` + cs.err})
   159  		}
   160  	})
   161  }