go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/config/validation/validation_test.go (about) 1 // Copyright 2017 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 validation 16 17 import ( 18 "context" 19 "testing" 20 21 "go.chromium.org/luci/common/errors" 22 configpb "go.chromium.org/luci/common/proto/config" 23 24 . "github.com/smartystreets/goconvey/convey" 25 . "go.chromium.org/luci/common/testing/assertions" 26 ) 27 28 func TestValidation(t *testing.T) { 29 t.Parallel() 30 31 Convey("No errors", t, func() { 32 c := Context{Context: context.Background()} 33 34 c.SetFile("zz") 35 c.Enter("zzz") 36 c.Exit() 37 38 So(c.Finalize(), ShouldBeNil) 39 }) 40 41 Convey("One simple error", t, func() { 42 c := Context{Context: context.Background()} 43 44 c.SetFile("file.cfg") 45 c.Enter("ctx %d", 123) 46 c.Errorf("blah %s", "zzz") 47 err := c.Finalize() 48 So(err, ShouldHaveSameTypeAs, &Error{}) 49 So(err.Error(), ShouldEqual, `in "file.cfg" (ctx 123): blah zzz`) 50 51 singleErr := err.(*Error).Errors[0] 52 So(singleErr.Error(), ShouldEqual, `in "file.cfg" (ctx 123): blah zzz`) 53 d, ok := fileTag.In(singleErr) 54 So(ok, ShouldBeTrue) 55 So(d, ShouldEqual, "file.cfg") 56 57 elts, ok := elementTag.In(singleErr) 58 So(ok, ShouldBeTrue) 59 So(elts, ShouldResemble, []string{"ctx 123"}) 60 61 severity, ok := SeverityTag.In(singleErr) 62 So(ok, ShouldBeTrue) 63 So(severity, ShouldEqual, Blocking) 64 65 blocking := err.(*Error).WithSeverity(Blocking) 66 So(blocking.(errors.MultiError), ShouldHaveLength, 1) 67 warns := err.(*Error).WithSeverity(Warning) 68 So(warns, ShouldBeNil) 69 70 So(err.(*Error).ToValidationResultMsgs(c.Context), ShouldResembleProto, []*configpb.ValidationResult_Message{ 71 { 72 Path: "file.cfg", 73 Severity: configpb.ValidationResult_ERROR, 74 Text: `in "file.cfg" (ctx 123): blah zzz`, 75 }, 76 }) 77 }) 78 79 Convey("One simple warning", t, func() { 80 c := Context{Context: context.Background()} 81 c.Warningf("option %q is a noop, please remove", "xyz: true") 82 err := c.Finalize() 83 So(err, ShouldNotBeNil) 84 singleErr := err.(*Error).Errors[0] 85 So(singleErr.Error(), ShouldContainSubstring, `option "xyz: true" is a noop, please remove`) 86 87 severity, ok := SeverityTag.In(singleErr) 88 So(ok, ShouldBeTrue) 89 So(severity, ShouldEqual, Warning) 90 91 blocking := err.(*Error).WithSeverity(Blocking) 92 So(blocking, ShouldBeNil) 93 warns := err.(*Error).WithSeverity(Warning) 94 So(warns.(errors.MultiError), ShouldHaveLength, 1) 95 96 So(err.(*Error).ToValidationResultMsgs(c.Context), ShouldResembleProto, []*configpb.ValidationResult_Message{ 97 { 98 Path: "unspecified file", 99 Severity: configpb.ValidationResult_WARNING, 100 Text: `in <unspecified file>: option "xyz: true" is a noop, please remove`, 101 }, 102 }) 103 }) 104 105 Convey("Regular usage", t, func() { 106 c := Context{Context: context.Background()} 107 108 c.Errorf("top %d", 1) 109 c.Errorf("top %d", 2) 110 111 c.SetFile("file_1.cfg") 112 c.Errorf("f1") 113 c.Errorf("f2") 114 115 c.Enter("p %d", 1) 116 c.Errorf("zzz 1") 117 118 c.Enter("p %d", 2) 119 c.Errorf("zzz 2") 120 c.Exit() 121 122 c.Warningf("zzz 3") 123 124 c.SetFile("file_2.cfg") 125 c.Errorf("zzz 4") 126 127 err := c.Finalize() 128 So(err, ShouldHaveSameTypeAs, &Error{}) 129 So(err.Error(), ShouldEqual, `in <unspecified file>: top 1 (and 7 other errors)`) 130 131 var errs []string 132 for _, e := range err.(*Error).Errors { 133 errs = append(errs, e.Error()) 134 } 135 So(errs, ShouldResemble, []string{ 136 `in <unspecified file>: top 1`, 137 `in <unspecified file>: top 2`, 138 `in "file_1.cfg": f1`, 139 `in "file_1.cfg": f2`, 140 `in "file_1.cfg" (p 1): zzz 1`, 141 `in "file_1.cfg" (p 1 / p 2): zzz 2`, 142 `in "file_1.cfg" (p 1): zzz 3`, 143 `in "file_2.cfg": zzz 4`, 144 }) 145 146 blocking := err.(*Error).WithSeverity(Blocking) 147 So(blocking.(errors.MultiError), ShouldHaveLength, 7) 148 warns := err.(*Error).WithSeverity(Warning) 149 So(warns.(errors.MultiError), ShouldHaveLength, 1) 150 }) 151 }