go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/server/auth/authdb/internal/conds/conds_test.go (about)

     1  // Copyright 2022 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 conds
    16  
    17  import (
    18  	"context"
    19  	"testing"
    20  
    21  	"go.chromium.org/luci/server/auth/realms"
    22  	"go.chromium.org/luci/server/auth/service/protocol"
    23  
    24  	. "github.com/smartystreets/goconvey/convey"
    25  	. "go.chromium.org/luci/common/testing/assertions"
    26  )
    27  
    28  func TestConds(t *testing.T) {
    29  	t.Parallel()
    30  
    31  	ctx := context.Background()
    32  
    33  	restrict := func(attr string, vals []string) *protocol.Condition {
    34  		return &protocol.Condition{
    35  			Op: &protocol.Condition_Restrict{
    36  				Restrict: &protocol.Condition_AttributeRestriction{
    37  					Attribute: attr,
    38  					Values:    vals,
    39  				},
    40  			},
    41  		}
    42  	}
    43  
    44  	Convey("AttributeRestriction empty", t, func() {
    45  		builder := NewBuilder([]*protocol.Condition{
    46  			restrict("a", nil),
    47  		})
    48  
    49  		cond, err := builder.Condition([]uint32{0})
    50  		So(err, ShouldBeNil)
    51  		So(cond, ShouldNotBeNil)
    52  
    53  		So(cond.Eval(ctx, realms.Attrs{"a": "b"}), ShouldBeFalse)
    54  		So(cond.Eval(ctx, realms.Attrs{"a": ""}), ShouldBeFalse)
    55  	})
    56  
    57  	Convey("AttributeRestriction non-empty", t, func() {
    58  		builder := NewBuilder([]*protocol.Condition{
    59  			restrict("a", []string{"val1", "val2"}),
    60  		})
    61  
    62  		cond, err := builder.Condition([]uint32{0})
    63  		So(err, ShouldBeNil)
    64  		So(cond, ShouldNotBeNil)
    65  
    66  		So(cond.Eval(ctx, nil), ShouldBeFalse)
    67  		So(cond.Eval(ctx, realms.Attrs{"a": "val1"}), ShouldBeTrue)
    68  		So(cond.Eval(ctx, realms.Attrs{"a": "val2"}), ShouldBeTrue)
    69  		So(cond.Eval(ctx, realms.Attrs{"a": "val3"}), ShouldBeFalse)
    70  		So(cond.Eval(ctx, realms.Attrs{"b": "val1"}), ShouldBeFalse)
    71  	})
    72  
    73  	Convey("Unrecognized elementary condition", t, func() {
    74  		builder := NewBuilder([]*protocol.Condition{
    75  			{},
    76  		})
    77  
    78  		cond, err := builder.Condition([]uint32{0})
    79  		So(err, ShouldBeNil)
    80  		So(cond, ShouldNotBeNil)
    81  
    82  		So(cond.Eval(ctx, nil), ShouldBeFalse)
    83  	})
    84  
    85  	Convey("Empty Condition", t, func() {
    86  		builder := NewBuilder(nil)
    87  
    88  		cond, err := builder.Condition(nil)
    89  		So(err, ShouldBeNil)
    90  		So(cond, ShouldBeNil)
    91  	})
    92  
    93  	Convey("Condition ANDs elementary conditions", t, func() {
    94  		builder := NewBuilder([]*protocol.Condition{
    95  			restrict("a", []string{"val1", "val2"}),
    96  			restrict("b", []string{"val1", "val2"}),
    97  		})
    98  
    99  		cond, err := builder.Condition([]uint32{0, 1})
   100  		So(err, ShouldBeNil)
   101  		So(cond, ShouldNotBeNil)
   102  
   103  		So(cond.Eval(ctx, nil), ShouldBeFalse)
   104  		So(cond.Eval(ctx, realms.Attrs{"a": "val1"}), ShouldBeFalse)
   105  		So(cond.Eval(ctx, realms.Attrs{"b": "val1"}), ShouldBeFalse)
   106  		So(cond.Eval(ctx, realms.Attrs{"a": "val1", "b": "val1"}), ShouldBeTrue)
   107  		So(cond.Eval(ctx, realms.Attrs{"a": "val2", "b": "val2"}), ShouldBeTrue)
   108  		So(cond.Eval(ctx, realms.Attrs{"a": "xxxx", "b": "val1"}), ShouldBeFalse)
   109  	})
   110  
   111  	Convey("Conditions are cached", t, func() {
   112  		builder := NewBuilder([]*protocol.Condition{
   113  			restrict("a", []string{"val1", "val2"}),
   114  			restrict("b", []string{"val1", "val2"}),
   115  			restrict("c", []string{"val1", "val2"}),
   116  		})
   117  
   118  		cond1, err := builder.Condition([]uint32{0, 1})
   119  		So(err, ShouldBeNil)
   120  		So(cond1, ShouldNotBeNil)
   121  		So(cond1.Index(), ShouldEqual, 0)
   122  
   123  		cond2, err := builder.Condition([]uint32{0, 1})
   124  		So(err, ShouldBeNil)
   125  		So(cond2, ShouldEqual, cond1) // the exact same pointer
   126  
   127  		cond3, err := builder.Condition([]uint32{1, 0})
   128  		So(err, ShouldBeNil)
   129  		So(cond3, ShouldNotEqual, cond1) // different, the order matters
   130  		So(cond3.Index(), ShouldEqual, 1)
   131  
   132  		cond4, err := builder.Condition([]uint32{0})
   133  		So(err, ShouldBeNil)
   134  		So(cond4, ShouldNotEqual, cond1)
   135  		So(cond4.Index(), ShouldEqual, 2)
   136  
   137  		cond5, err := builder.Condition([]uint32{0, 2})
   138  		So(err, ShouldBeNil)
   139  		So(cond5, ShouldNotEqual, cond1)
   140  		So(cond5.Index(), ShouldEqual, 3)
   141  	})
   142  
   143  	Convey("Out of bounds", t, func() {
   144  		builder := NewBuilder(nil)
   145  
   146  		cond, err := builder.Condition([]uint32{0})
   147  		So(err, ShouldErrLike, "condition index is out of bounds: 0 >= 0")
   148  		So(cond, ShouldBeNil)
   149  	})
   150  }