go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/resultdb/pbutil/predicate.go (about)

     1  // Copyright 2019 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 pbutil
    16  
    17  import (
    18  	"regexp/syntax"
    19  	"strings"
    20  
    21  	"go.chromium.org/luci/common/errors"
    22  
    23  	pb "go.chromium.org/luci/resultdb/proto/v1"
    24  )
    25  
    26  // testObjectPredicate is implemented by both *pb.TestResultPredicate
    27  // and *pb.TestExonerationPredicate.
    28  type testObjectPredicate interface {
    29  	GetTestIdRegexp() string
    30  	GetVariant() *pb.VariantPredicate
    31  }
    32  
    33  // validateTestObjectPredicate returns a non-nil error if p is determined to be
    34  // invalid.
    35  func validateTestObjectPredicate(p testObjectPredicate) error {
    36  	if err := validateRegexp(p.GetTestIdRegexp()); err != nil {
    37  		return errors.Annotate(err, "test_id_regexp").Err()
    38  	}
    39  
    40  	if p.GetVariant() != nil {
    41  		if err := ValidateVariantPredicate(p.GetVariant()); err != nil {
    42  			return errors.Annotate(err, "variant").Err()
    43  		}
    44  	}
    45  	return nil
    46  }
    47  
    48  // ValidateTestResultPredicate returns a non-nil error if p is determined to be
    49  // invalid.
    50  func ValidateTestResultPredicate(p *pb.TestResultPredicate) error {
    51  	if err := ValidateEnum(int32(p.GetExpectancy()), pb.TestResultPredicate_Expectancy_name); err != nil {
    52  		return errors.Annotate(err, "expectancy").Err()
    53  	}
    54  
    55  	if p.GetExcludeExonerated() && p.GetExpectancy() == pb.TestResultPredicate_ALL {
    56  		return errors.Reason("exclude_exonerated and expectancy=ALL are mutually exclusive").Err()
    57  	}
    58  
    59  	return validateTestObjectPredicate(p)
    60  }
    61  
    62  // ValidateTestExonerationPredicate returns a non-nil error if p is determined to be
    63  // invalid.
    64  func ValidateTestExonerationPredicate(p *pb.TestExonerationPredicate) error {
    65  	return validateTestObjectPredicate(p)
    66  }
    67  
    68  // validateRegexp returns a non-nil error if re is an invalid regular
    69  // expression.
    70  func validateRegexp(re string) error {
    71  	// Note: regexp.Compile uses syntax.Perl.
    72  	if _, err := syntax.Parse(re, syntax.Perl); err != nil {
    73  		return err
    74  	}
    75  
    76  	// Do not allow ^ and $ in the regexp, because we need to be able to prepend
    77  	// a pattern to the user-supplied pattern.
    78  	if strings.HasPrefix(re, "^") {
    79  		return errors.Reason("must not start with ^; it is prepended automatically").Err()
    80  	}
    81  	if strings.HasSuffix(re, "$") {
    82  		return errors.Reason("must not end with $; it is appended automatically").Err()
    83  	}
    84  
    85  	return nil
    86  }
    87  
    88  // ValidateVariantPredicate returns a non-nil error if p is determined to be
    89  // invalid.
    90  func ValidateVariantPredicate(p *pb.VariantPredicate) error {
    91  	switch pr := p.Predicate.(type) {
    92  	case *pb.VariantPredicate_Equals:
    93  		return errors.Annotate(ValidateVariant(pr.Equals), "equals").Err()
    94  	case *pb.VariantPredicate_Contains:
    95  		return errors.Annotate(ValidateVariant(pr.Contains), "contains").Err()
    96  	case nil:
    97  		return unspecified()
    98  	default:
    99  		panic("impossible")
   100  	}
   101  }
   102  
   103  // ValidateArtifactPredicate returns a non-nil error if p is determined to be
   104  // invalid.
   105  func ValidateArtifactPredicate(p *pb.ArtifactPredicate) error {
   106  	if err := ValidateTestResultPredicate(p.GetTestResultPredicate()); err != nil {
   107  		return errors.Annotate(err, "text_result_predicate").Err()
   108  	}
   109  	if err := validateRegexp(p.GetContentTypeRegexp()); err != nil {
   110  		return errors.Annotate(err, "content_type_regexp").Err()
   111  	}
   112  	return nil
   113  }
   114  
   115  // ValidateTestMetadataPredicate returns a non-nil error if p is determined to be
   116  // invalid.
   117  func ValidateTestMetadataPredicate(p *pb.TestMetadataPredicate) error {
   118  	for i, testID := range p.GetTestIds() {
   119  		if err := ValidateTestID(testID); err != nil {
   120  			return errors.Annotate(err, "test_ids[%v]", i).Err()
   121  		}
   122  	}
   123  	return nil
   124  }