blob: 8cd43c6c99e351e48135ba50b506f73584084d63 [file] [log] [blame]
// Copyright 2018 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package validation
import (
"context"
"fmt"
"testing"
"go.chromium.org/luci/common/errors"
. "github.com/smartystreets/goconvey/convey"
. "go.chromium.org/luci/common/testing/assertions"
)
func TestRuleSet(t *testing.T) {
t.Parallel()
Convey("With validator callback", t, func() {
ctx := context.Background()
type call struct {
validatorID string
configSet string
path string
}
calls := []call{}
validator := func(id string) Func {
return func(ctx *Context, configSet, path string, content []byte) error {
calls = append(calls, call{id, configSet, path})
return nil
}
}
Convey("Works", func() {
r := NewRuleSet()
r.Vars.Register("a", func(context.Context) (string, error) { return "a_val", nil })
r.Vars.Register("b", func(context.Context) (string, error) { return "b_val", nil })
r.Add("services/${a}", "paths/a", validator("rule_1"))
r.Add("services/${a}", "paths/${b}", validator("rule_2"))
r.Add("services/c", "paths/c", validator("rule_3"))
r.Add("regex:services/.*", "paths/c", validator("rule_4"))
patterns, err := r.ConfigPatterns(ctx)
So(err, ShouldBeNil)
type pair struct {
configSet string
path string
}
asPairs := make([]pair, len(patterns))
for i, p := range patterns {
asPairs[i] = pair{p.ConfigSet.String(), p.Path.String()}
}
So(asPairs, ShouldResemble, []pair{
{"exact:services/a_val", "exact:paths/a"},
{"exact:services/a_val", "exact:paths/b_val"},
{"exact:services/c", "exact:paths/c"},
{"regex:^services/.*$", "exact:paths/c"},
})
callValidator := func(configSet, path string) {
c := Context{Context: ctx}
So(r.ValidateConfig(&c, configSet, path, []byte("body")), ShouldBeNil)
}
callValidator("services/unknown", "paths/a")
callValidator("services/a_val", "paths/a")
callValidator("services/a_val", "paths/b_val")
callValidator("services/a_val", "paths/c")
callValidator("services/c", "paths/c")
So(calls, ShouldResemble, []call{
{"rule_1", "services/a_val", "paths/a"},
{"rule_2", "services/a_val", "paths/b_val"},
{"rule_4", "services/a_val", "paths/c"},
{"rule_3", "services/c", "paths/c"},
{"rule_4", "services/c", "paths/c"},
})
})
Convey("Error in the var callback", func() {
r := NewRuleSet()
r.Vars.Register("a", func(context.Context) (string, error) { return "", fmt.Errorf("boom") })
r.Add("services/${a}", "paths/a", validator("rule_1"))
err := r.ValidateConfig(&Context{Context: ctx}, "services/zzz", "some path", []byte("body"))
So(err, ShouldErrLike, "boom")
})
Convey("Missing variables", func() {
r := NewRuleSet()
r.Vars.Register("a", func(context.Context) (string, error) { return "a_val", nil })
r.Add("${zzz}", "a", validator("1"))
r.Add("a", "${zzz}", validator("1"))
_, err := r.ConfigPatterns(ctx)
merr := err.(errors.MultiError)
So(merr, ShouldHaveLength, 2)
So(merr[0], ShouldErrLike,
`config set pattern "exact:${zzz}": no placeholder named "zzz" is registered`)
So(merr[1], ShouldErrLike,
`path pattern "exact:${zzz}": no placeholder named "zzz" is registered`)
err = r.ValidateConfig(&Context{Context: ctx}, "set", "path", nil)
merr = err.(errors.MultiError)
So(merr, ShouldHaveLength, 2)
So(merr[0], ShouldErrLike,
`config set pattern "exact:${zzz}": no placeholder named "zzz" is registered`)
So(merr[1], ShouldErrLike,
`path pattern "exact:${zzz}": no placeholder named "zzz" is registered`)
})
Convey("Pattern is validated", func() {
r := NewRuleSet()
r.Vars.Register("a", func(context.Context) (string, error) { return "a_val", nil })
r.Add("unknown:${a}", "a", validator("1"))
r.Add("a", "unknown:${a}", validator("1"))
_, err := r.ConfigPatterns(ctx)
merr := err.(errors.MultiError)
So(merr, ShouldHaveLength, 2)
So(merr[0], ShouldErrLike,
`config set pattern "unknown:${a}": unknown pattern kind: "unknown"`)
So(merr[1], ShouldErrLike,
`path pattern "unknown:${a}": unknown pattern kind: "unknown"`)
err = r.ValidateConfig(&Context{Context: ctx}, "set", "path", nil)
merr = err.(errors.MultiError)
So(merr, ShouldHaveLength, 2)
So(merr[0], ShouldErrLike,
`config set pattern "unknown:${a}": unknown pattern kind: "unknown"`)
So(merr[1], ShouldErrLike,
`path pattern "unknown:${a}": unknown pattern kind: "unknown"`)
})
})
}