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  }