go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/cv/internal/gerrit/cfgmatcher/matcher_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 cfgmatcher 16 17 import ( 18 "testing" 19 20 "google.golang.org/protobuf/encoding/prototext" 21 22 cfgpb "go.chromium.org/luci/cv/api/config/v2" 23 "go.chromium.org/luci/cv/internal/configs/prjcfg" 24 "go.chromium.org/luci/cv/internal/configs/prjcfg/prjcfgtest" 25 "go.chromium.org/luci/cv/internal/cvtesting" 26 27 . "github.com/smartystreets/goconvey/convey" 28 ) 29 30 func TestPartitionConfig(t *testing.T) { 31 t.Parallel() 32 33 Convey("Matcher works", t, func() { 34 ct := cvtesting.Test{} 35 ctx, cancel := ct.SetUp(t) 36 defer cancel() 37 38 const cfgText = ` 39 config_groups { 40 name: "g1" 41 gerrit { 42 url: "https://1.example.com" 43 projects { 44 name: "luci/go" 45 ref_regexp: "refs/heads/.+" 46 ref_regexp_exclude: "refs/heads/e.+ed" 47 } 48 projects { 49 name: "default" 50 # Default regexp is "refs/heads/master". 51 } 52 } 53 } 54 config_groups { 55 name: "fallback" 56 fallback: YES 57 gerrit { 58 url: "https://1.example.com" 59 projects { 60 name: "luci/go" 61 ref_regexp: "refs/heads/.+" 62 # NOTE: \\d is for proto parser s.t. actual regexp is just \d 63 ref_regexp: "refs/branch-heads/[\\d]{3,4}" 64 } 65 } 66 } 67 config_groups { 68 name: "g2" 69 gerrit { 70 url: "https://1.example.com" 71 projects { 72 name: "luci/go" 73 ref_regexp: "refs/heads/g2" 74 } 75 } 76 gerrit { 77 url: "https://2.example.com" 78 projects { 79 name: "fo/rk" 80 ref_regexp: "refs/heads/main" 81 } 82 } 83 }` 84 cfg := &cfgpb.Config{} 85 So(prototext.Unmarshal([]byte(cfgText), cfg), ShouldBeNil) 86 87 const luciProject = "luci" 88 const gHost1 = "1.example.com" 89 const gHost2 = "2.example.com" 90 91 prjcfgtest.Create(ctx, luciProject, cfg) 92 meta := prjcfgtest.MustExist(ctx, luciProject) 93 hash := meta.Hash() 94 95 ids := func(ids ...string) []prjcfg.ConfigGroupID { 96 ret := make([]prjcfg.ConfigGroupID, len(ids)) 97 for i, id := range ids { 98 ret[i] = prjcfg.MakeConfigGroupID(hash, id) 99 } 100 return ret 101 } 102 103 testMatches := func(m *Matcher) { 104 Convey("matching works", func() { 105 So(m.Match("random.host", "luci/go", "refs/heads/main"), ShouldBeEmpty) 106 So(m.Match(gHost1, "random/repo", "refs/heads/main"), ShouldBeEmpty) 107 So(m.Match(gHost1, "luci/go", "refs/nei/ther"), ShouldBeEmpty) 108 109 So(m.Match(gHost1, "luci/go", "refs/heads/main"), ShouldResemble, ids("g1")) 110 So(m.Match(gHost1, "luci/go", "refs/heads/exclud-not-really"), ShouldResemble, ids("g1")) 111 So(m.Match(gHost1, "luci/go", "refs/heads/excluded"), ShouldResemble, ids("fallback")) 112 113 So(m.Match(gHost1, "luci/go", "refs/branch-heads/12"), ShouldBeEmpty) 114 So(m.Match(gHost1, "luci/go", "refs/branch-heads/123"), ShouldResemble, ids("fallback")) 115 So(m.Match(gHost1, "luci/go", "refs/branch-heads/1234"), ShouldResemble, ids("fallback")) 116 So(m.Match(gHost1, "luci/go", "refs/branch-heads/12345"), ShouldBeEmpty) 117 118 So(m.Match(gHost1, "luci/go", "refs/heads/g2"), ShouldResemble, ids("g1", "g2")) 119 So(m.Match(gHost1, "luci/go", "refs/heads/g2-not-any-more"), ShouldResemble, ids("g1")) 120 // Test default. 121 So(m.Match(gHost1, "default", "refs/heads/stuff"), ShouldBeEmpty) 122 So(m.Match(gHost1, "default", "refs/heads/main"), ShouldBeEmpty) 123 So(m.Match(gHost1, "default", "refs/heads/master"), ShouldResemble, ids("g1")) 124 125 // 2nd host with 2 hosts in the same config group. 126 So(m.Match(gHost2, "fo/rk", "refs/heads/main"), ShouldResemble, ids("g2")) 127 }) 128 } 129 130 Convey("load from Datstore", func() { 131 m, err := LoadMatcher(ctx, luciProject, hash) 132 So(err, ShouldBeNil) 133 testMatches(m) 134 135 Convey("Serialize/Deserialize", func() { 136 bytes, err := m.Serialize() 137 So(err, ShouldBeNil) 138 m, err := Deserialize(bytes) 139 So(err, ShouldBeNil) 140 testMatches(m) 141 }) 142 }) 143 }) 144 }