go.chromium.org/luci@v0.0.0-20250314024836-d9a61d0730e6/tokenserver/appengine/impl/utils/identityset/identityset_test.go (about)

     1  // Copyright 2016 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 identityset
    16  
    17  import (
    18  	"context"
    19  	"testing"
    20  
    21  	"go.chromium.org/luci/auth/identity"
    22  	"go.chromium.org/luci/common/testing/ftt"
    23  	"go.chromium.org/luci/common/testing/truth/assert"
    24  	"go.chromium.org/luci/common/testing/truth/should"
    25  	"go.chromium.org/luci/server/auth"
    26  	"go.chromium.org/luci/server/auth/authtest"
    27  )
    28  
    29  func TestFromStrings(t *testing.T) {
    30  	ftt.Run("Empty", t, func(t *ftt.Test) {
    31  		s, err := FromStrings(nil, nil)
    32  		assert.Loosely(t, err, should.BeNil)
    33  		assert.Loosely(t, s, should.Match(&Set{}))
    34  		assert.Loosely(t, s.IsEmpty(), should.BeTrue)
    35  		assert.Loosely(t, s.ToStrings(), should.BeEmpty)
    36  	})
    37  
    38  	ftt.Run("Universal", t, func(t *ftt.Test) {
    39  		s, err := FromStrings([]string{"*", "user:abc@example.com"}, nil)
    40  		assert.Loosely(t, err, should.BeNil)
    41  		assert.Loosely(t, s, should.Match(&Set{All: true}))
    42  		assert.Loosely(t, s.IsEmpty(), should.BeFalse)
    43  		assert.Loosely(t, s.ToStrings(), should.Match([]string{"*"}))
    44  	})
    45  
    46  	ftt.Run("Normal", t, func(t *ftt.Test) {
    47  		s, err := FromStrings([]string{
    48  			"user:abc@example.com",
    49  			"user:def@example.com",
    50  			"user:abc@example.com",
    51  			"skipped",
    52  			"group:abc",
    53  			"group:def",
    54  			"group:abc",
    55  		}, func(s string) bool { return s == "skipped" })
    56  		assert.Loosely(t, err, should.BeNil)
    57  		assert.Loosely(t, s, should.Match(&Set{
    58  			IDs: identSet{
    59  				"user:abc@example.com": struct{}{},
    60  				"user:def@example.com": struct{}{},
    61  			},
    62  			Groups: groupSet{
    63  				"abc": struct{}{},
    64  				"def": struct{}{},
    65  			},
    66  		}))
    67  		assert.Loosely(t, s.IsEmpty(), should.BeFalse)
    68  		assert.Loosely(t, s.ToStrings(), should.Match([]string{
    69  			"group:abc",
    70  			"group:def",
    71  			"user:abc@example.com",
    72  			"user:def@example.com",
    73  		}))
    74  	})
    75  
    76  	ftt.Run("Bad group entry", t, func(t *ftt.Test) {
    77  		s, err := FromStrings([]string{"group:"}, nil)
    78  		assert.Loosely(t, err, should.ErrLike("invalid entry"))
    79  		assert.Loosely(t, s, should.BeNil)
    80  	})
    81  
    82  	ftt.Run("Bad ID entry", t, func(t *ftt.Test) {
    83  		s, err := FromStrings([]string{"shrug"}, nil)
    84  		assert.Loosely(t, err, should.ErrLike("bad identity string"))
    85  		assert.Loosely(t, s, should.BeNil)
    86  	})
    87  }
    88  
    89  func TestIsMember(t *testing.T) {
    90  	c := context.Background()
    91  	c = auth.WithState(c, &authtest.FakeState{
    92  		Identity:       "user:abc@example.com",
    93  		IdentityGroups: []string{"abc"},
    94  	})
    95  
    96  	ftt.Run("nil", t, func(t *ftt.Test) {
    97  		var s *Set
    98  		ok, err := s.IsMember(c, identity.AnonymousIdentity)
    99  		assert.Loosely(t, err, should.BeNil)
   100  		assert.Loosely(t, ok, should.BeFalse)
   101  	})
   102  
   103  	ftt.Run("All", t, func(t *ftt.Test) {
   104  		s := Set{All: true}
   105  		ok, err := s.IsMember(c, identity.AnonymousIdentity)
   106  		assert.Loosely(t, err, should.BeNil)
   107  		assert.Loosely(t, ok, should.BeTrue)
   108  	})
   109  
   110  	ftt.Run("Direct hit", t, func(t *ftt.Test) {
   111  		s, _ := FromStrings([]string{"user:abc@example.com"}, nil)
   112  
   113  		ok, err := s.IsMember(c, identity.Identity("user:abc@example.com"))
   114  		assert.Loosely(t, err, should.BeNil)
   115  		assert.Loosely(t, ok, should.BeTrue)
   116  
   117  		ok, err = s.IsMember(c, identity.AnonymousIdentity)
   118  		assert.Loosely(t, err, should.BeNil)
   119  		assert.Loosely(t, ok, should.BeFalse)
   120  	})
   121  
   122  	ftt.Run("Groups hit", t, func(t *ftt.Test) {
   123  		s, _ := FromStrings([]string{"group:abc"}, nil)
   124  
   125  		ok, err := s.IsMember(c, identity.Identity("user:abc@example.com"))
   126  		assert.Loosely(t, err, should.BeNil)
   127  		assert.Loosely(t, ok, should.BeTrue)
   128  
   129  		ok, err = s.IsMember(c, identity.AnonymousIdentity)
   130  		assert.Loosely(t, err, should.BeNil)
   131  		assert.Loosely(t, ok, should.BeFalse)
   132  	})
   133  }
   134  
   135  func TestIsSubset(t *testing.T) {
   136  	empty := &Set{}
   137  	all := &Set{All: true}
   138  	some, _ := FromStrings([]string{
   139  		"user:abc@example.com",
   140  		"user:def@example.com",
   141  		"group:abc",
   142  		"group:def",
   143  	}, nil)
   144  	some1, _ := FromStrings([]string{
   145  		"user:abc@example.com",
   146  		"user:def@example.com",
   147  	}, nil)
   148  	some2, _ := FromStrings([]string{
   149  		"group:abc",
   150  		"group:def",
   151  	}, nil)
   152  	some3, _ := FromStrings([]string{
   153  		"user:abc@example.com",
   154  		"group:abc",
   155  	}, nil)
   156  	some4, _ := FromStrings([]string{
   157  		"user:xxx@example.com",
   158  		"user:yyy@example.com",
   159  		"group:xxx",
   160  		"group:yyy",
   161  	}, nil)
   162  
   163  	ftt.Run("empty", t, func(t *ftt.Test) {
   164  		assert.Loosely(t, empty.IsSubset(empty), should.BeTrue)
   165  		assert.Loosely(t, empty.IsSubset(all), should.BeTrue)
   166  		assert.Loosely(t, empty.IsSubset(some), should.BeTrue)
   167  
   168  		assert.Loosely(t, empty.IsSuperset(empty), should.BeTrue) // for code coverage
   169  	})
   170  
   171  	ftt.Run("all", t, func(t *ftt.Test) {
   172  		assert.Loosely(t, all.IsSubset(empty), should.BeFalse)
   173  		assert.Loosely(t, all.IsSubset(all), should.BeTrue)
   174  		assert.Loosely(t, all.IsSubset(some), should.BeFalse)
   175  	})
   176  
   177  	ftt.Run("some", t, func(t *ftt.Test) {
   178  		assert.Loosely(t, some.IsSubset(empty), should.BeFalse)
   179  		assert.Loosely(t, some.IsSubset(all), should.BeTrue)
   180  		assert.Loosely(t, some.IsSubset(some), should.BeTrue)
   181  
   182  		assert.Loosely(t, some1.IsSubset(some), should.BeTrue)
   183  		assert.Loosely(t, some2.IsSubset(some), should.BeTrue)
   184  		assert.Loosely(t, some3.IsSubset(some), should.BeTrue)
   185  
   186  		assert.Loosely(t, some1.IsSubset(some2), should.BeFalse)
   187  		assert.Loosely(t, some1.IsSubset(some3), should.BeFalse)
   188  		assert.Loosely(t, some2.IsSubset(some1), should.BeFalse)
   189  		assert.Loosely(t, some3.IsSubset(some1), should.BeFalse)
   190  
   191  		assert.Loosely(t, some1.IsSubset(some3), should.BeFalse)
   192  		assert.Loosely(t, some1.IsSubset(some4), should.BeFalse)
   193  
   194  		assert.Loosely(t, some2.IsSubset(some3), should.BeFalse)
   195  		assert.Loosely(t, some2.IsSubset(some4), should.BeFalse)
   196  	})
   197  }
   198  
   199  func TestUnion(t *testing.T) {
   200  	empty := &Set{}
   201  	all := &Set{All: true}
   202  	some, _ := FromStrings([]string{
   203  		"user:abc@example.com",
   204  		"user:def@example.com",
   205  		"group:abc",
   206  		"group:def",
   207  	}, nil)
   208  	some1, _ := FromStrings([]string{
   209  		"user:abc@example.com",
   210  		"user:def@example.com",
   211  	}, nil)
   212  	some2, _ := FromStrings([]string{
   213  		"group:abc",
   214  		"group:def",
   215  	}, nil)
   216  	some3, _ := FromStrings([]string{
   217  		"user:abc@example.com",
   218  		"group:abc",
   219  	}, nil)
   220  
   221  	ftt.Run("empty", t, func(t *ftt.Test) {
   222  		assert.Loosely(t, Union(), should.Match(empty))
   223  		assert.Loosely(t, Union(empty, nil), should.Match(empty))
   224  	})
   225  
   226  	ftt.Run("one", t, func(t *ftt.Test) {
   227  		assert.Loosely(t, Union(some), should.Match(some))
   228  		assert.Loosely(t, Union(some, empty), should.Match(some))
   229  	})
   230  
   231  	ftt.Run("many", t, func(t *ftt.Test) {
   232  		assert.Loosely(t, Union(some1, some2, some3, empty), should.Match(some))
   233  	})
   234  
   235  	ftt.Run("all", t, func(t *ftt.Test) {
   236  		assert.Loosely(t, Union(all), should.Match(all))
   237  		assert.Loosely(t, Union(all, empty), should.Match(all))
   238  		assert.Loosely(t, Union(all, some1), should.Match(all))
   239  	})
   240  }
   241  
   242  func TestExtend(t *testing.T) {
   243  	ftt.Run("Empty", t, func(t *ftt.Test) {
   244  		assert.Loosely(t, Extend(nil, "user:abc@example.com"), should.Match(&Set{
   245  			IDs: identSet{"user:abc@example.com": struct{}{}},
   246  		}))
   247  	})
   248  
   249  	ftt.Run("All", t, func(t *ftt.Test) {
   250  		all := &Set{All: true}
   251  		assert.Loosely(t, Extend(all, "user:abc@example.com"), should.Match(all))
   252  	})
   253  
   254  	ftt.Run("Already there", t, func(t *ftt.Test) {
   255  		set, _ := FromStrings([]string{
   256  			"user:abc@example.com",
   257  			"group:abc",
   258  		}, nil)
   259  		assert.Loosely(t, Extend(set, "user:abc@example.com"), should.Match(set))
   260  	})
   261  
   262  	ftt.Run("Extends", t, func(t *ftt.Test) {
   263  		set, _ := FromStrings([]string{
   264  			"user:def@example.com",
   265  			"group:abc",
   266  		}, nil)
   267  		assert.Loosely(t, Extend(set, "user:abc@example.com"), should.Match(&Set{
   268  			IDs: identSet{
   269  				"user:abc@example.com": struct{}{},
   270  				"user:def@example.com": struct{}{},
   271  			},
   272  			Groups: groupSet{"abc": struct{}{}},
   273  		}))
   274  	})
   275  }