github.com/cilium/cilium@v1.16.2/pkg/policy/resolve_deny_test.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package policy 5 6 import ( 7 "sync" 8 "testing" 9 10 "github.com/stretchr/testify/require" 11 12 "github.com/cilium/cilium/pkg/identity" 13 "github.com/cilium/cilium/pkg/labels" 14 "github.com/cilium/cilium/pkg/lock" 15 "github.com/cilium/cilium/pkg/option" 16 "github.com/cilium/cilium/pkg/policy/api" 17 "github.com/cilium/cilium/pkg/policy/trafficdirection" 18 ) 19 20 func GenerateL3IngressDenyRules(numRules int) api.Rules { 21 parseFooLabel := labels.ParseSelectLabel("k8s:foo") 22 fooSelector := api.NewESFromLabels(parseFooLabel) 23 barSelector := api.NewESFromLabels(labels.ParseSelectLabel("bar")) 24 25 // Change ingRule and rule in the for-loop below to change what type of rules 26 // are added into the policy repository. 27 ingDenyRule := api.IngressDenyRule{ 28 IngressCommonRule: api.IngressCommonRule{ 29 FromEndpoints: []api.EndpointSelector{barSelector}, 30 }, 31 } 32 33 rules := make(api.Rules, 0, numRules) 34 for i := 1; i <= numRules; i++ { 35 rule := api.Rule{ 36 EndpointSelector: fooSelector, 37 IngressDeny: []api.IngressDenyRule{ingDenyRule}, 38 } 39 rule.Sanitize() 40 rules = append(rules, &rule) 41 } 42 return rules 43 } 44 45 func GenerateL3EgressDenyRules(numRules int) api.Rules { 46 parseFooLabel := labels.ParseSelectLabel("k8s:foo") 47 fooSelector := api.NewESFromLabels(parseFooLabel) 48 barSelector := api.NewESFromLabels(labels.ParseSelectLabel("bar")) 49 50 // Change ingRule and rule in the for-loop below to change what type of rules 51 // are added into the policy repository. 52 egDenyRule := api.EgressDenyRule{ 53 EgressCommonRule: api.EgressCommonRule{ 54 ToEndpoints: []api.EndpointSelector{barSelector}, 55 }, 56 } 57 58 rules := make(api.Rules, 0, numRules) 59 for i := 1; i <= numRules; i++ { 60 rule := api.Rule{ 61 EndpointSelector: fooSelector, 62 EgressDeny: []api.EgressDenyRule{egDenyRule}, 63 } 64 rule.Sanitize() 65 rules = append(rules, &rule) 66 } 67 return rules 68 } 69 70 func GenerateCIDRDenyRules(numRules int) api.Rules { 71 parseFooLabel := labels.ParseSelectLabel("k8s:foo") 72 fooSelector := api.NewESFromLabels(parseFooLabel) 73 //barSelector := api.NewESFromLabels(labels.ParseSelectLabel("bar")) 74 75 // Change ingRule and rule in the for-loop below to change what type of rules 76 // are added into the policy repository. 77 egDenyRule := api.EgressDenyRule{ 78 EgressCommonRule: api.EgressCommonRule{ 79 ToCIDR: []api.CIDR{api.CIDR("10.2.3.0/24"), api.CIDR("ff02::/64")}, 80 }, 81 /*ToRequires: []api.EndpointSelector{barSelector}, 82 ToPorts: []api.PortRule{ 83 { 84 Ports: []api.PortProtocol{ 85 { 86 Port: "8080", 87 Protocol: api.ProtoTCP, 88 }, 89 }, 90 }, 91 },*/ 92 } 93 94 var rules api.Rules 95 for i := 1; i <= numRules; i++ { 96 97 rule := api.Rule{ 98 EndpointSelector: fooSelector, 99 EgressDeny: []api.EgressDenyRule{egDenyRule}, 100 } 101 rule.Sanitize() 102 rules = append(rules, &rule) 103 } 104 return rules 105 } 106 107 func TestL3WithIngressDenyWildcard(t *testing.T) { 108 td := newTestData() 109 repo := td.repo 110 td.bootstrapRepo(GenerateL3IngressDenyRules, 1000, t) 111 112 idFooSelectLabelArray := labels.ParseSelectLabelArray("id=foo") 113 idFooSelectLabels := labels.Labels{} 114 for _, lbl := range idFooSelectLabelArray { 115 idFooSelectLabels[lbl.Key] = lbl 116 } 117 fooIdentity := identity.NewIdentity(12345, idFooSelectLabels) 118 td.addIdentity(fooIdentity) 119 120 selFoo := api.NewESFromLabels(labels.ParseSelectLabel("id=foo")) 121 rule1 := api.Rule{ 122 EndpointSelector: selFoo, 123 IngressDeny: []api.IngressDenyRule{ 124 { 125 ToPorts: []api.PortDenyRule{{ 126 Ports: []api.PortProtocol{ 127 {Port: "80", Protocol: api.ProtoTCP}, 128 }, 129 }}, 130 }, 131 }, 132 } 133 134 rule1.Sanitize() 135 _, _, err := repo.mustAdd(rule1) 136 require.NoError(t, err) 137 138 repo.Mutex.RLock() 139 defer repo.Mutex.RUnlock() 140 selPolicy, err := repo.resolvePolicyLocked(fooIdentity) 141 require.NoError(t, err) 142 policy := selPolicy.DistillPolicy(DummyOwner{}, false) 143 144 expectedEndpointPolicy := EndpointPolicy{ 145 selectorPolicy: &selectorPolicy{ 146 Revision: repo.GetRevision(), 147 SelectorCache: repo.GetSelectorCache(), 148 L4Policy: L4Policy{ 149 Revision: repo.GetRevision(), 150 Ingress: L4DirectionPolicy{PortRules: NewL4PolicyMapWithValues(map[string]*L4Filter{ 151 "80/TCP": { 152 Port: 80, 153 Protocol: api.ProtoTCP, 154 U8Proto: 0x6, 155 wildcard: td.wildcardCachedSelector, 156 L7Parser: ParserTypeNone, 157 Ingress: true, 158 PerSelectorPolicies: L7DataMap{ 159 td.wildcardCachedSelector: &PerSelectorPolicy{IsDeny: true}, 160 }, 161 RuleOrigin: map[CachedSelector]labels.LabelArrayList{td.wildcardCachedSelector: {nil}}, 162 }, 163 }), 164 features: denyRules, 165 }, 166 Egress: newL4DirectionPolicy(), 167 }, 168 IngressPolicyEnabled: true, 169 }, 170 PolicyOwner: DummyOwner{}, 171 // inherit this from the result as it is outside of the scope 172 // of this test 173 policyMapState: policy.policyMapState, 174 } 175 176 // Have to remove circular reference before testing to avoid an infinite loop 177 policy.selectorPolicy.Detach() 178 179 // Assign an empty mutex so that checker.Equal does not complain about the 180 // difference of the internal time.Time from the lock_debug.go. 181 policy.selectorPolicy.L4Policy.mutex = lock.RWMutex{} 182 // policyMapState cannot be compared via DeepEqual 183 require.Truef(t, policy.policyMapState.Equals(expectedEndpointPolicy.policyMapState), 184 policy.policyMapState.Diff(expectedEndpointPolicy.policyMapState)) 185 policy.policyMapState = nil 186 expectedEndpointPolicy.policyMapState = nil 187 require.Equal(t, policy, &expectedEndpointPolicy) 188 } 189 190 func TestL3WithLocalHostWildcardd(t *testing.T) { 191 td := newTestData() 192 repo := td.repo 193 td.bootstrapRepo(GenerateL3IngressDenyRules, 1000, t) 194 195 idFooSelectLabelArray := labels.ParseSelectLabelArray("id=foo") 196 idFooSelectLabels := labels.Labels{} 197 for _, lbl := range idFooSelectLabelArray { 198 idFooSelectLabels[lbl.Key] = lbl 199 } 200 201 fooIdentity := identity.NewIdentity(12345, idFooSelectLabels) 202 td.addIdentity(fooIdentity) 203 204 // Emulate Kubernetes mode with allow from localhost 205 oldLocalhostOpt := option.Config.AllowLocalhost 206 option.Config.AllowLocalhost = option.AllowLocalhostAlways 207 defer func() { option.Config.AllowLocalhost = oldLocalhostOpt }() 208 209 selFoo := api.NewESFromLabels(labels.ParseSelectLabel("id=foo")) 210 rule1 := api.Rule{ 211 EndpointSelector: selFoo, 212 IngressDeny: []api.IngressDenyRule{ 213 { 214 ToPorts: []api.PortDenyRule{{ 215 Ports: []api.PortProtocol{ 216 {Port: "80", Protocol: api.ProtoTCP}, 217 }, 218 }}, 219 }, 220 }, 221 } 222 223 rule1.Sanitize() 224 _, _, err := repo.mustAdd(rule1) 225 require.NoError(t, err) 226 227 repo.Mutex.RLock() 228 defer repo.Mutex.RUnlock() 229 230 selPolicy, err := repo.resolvePolicyLocked(fooIdentity) 231 require.NoError(t, err) 232 policy := selPolicy.DistillPolicy(DummyOwner{}, false) 233 234 cachedSelectorHost := td.sc.FindCachedIdentitySelector(api.ReservedEndpointSelectors[labels.IDNameHost]) 235 require.NotNil(t, cachedSelectorHost) 236 237 expectedEndpointPolicy := EndpointPolicy{ 238 selectorPolicy: &selectorPolicy{ 239 Revision: repo.GetRevision(), 240 SelectorCache: repo.GetSelectorCache(), 241 L4Policy: L4Policy{ 242 Revision: repo.GetRevision(), 243 Ingress: L4DirectionPolicy{PortRules: NewL4PolicyMapWithValues(map[string]*L4Filter{ 244 "80/TCP": { 245 Port: 80, 246 Protocol: api.ProtoTCP, 247 U8Proto: 0x6, 248 wildcard: td.wildcardCachedSelector, 249 L7Parser: ParserTypeNone, 250 Ingress: true, 251 PerSelectorPolicies: L7DataMap{ 252 td.wildcardCachedSelector: &PerSelectorPolicy{IsDeny: true}, 253 }, 254 RuleOrigin: map[CachedSelector]labels.LabelArrayList{td.wildcardCachedSelector: {nil}}, 255 }, 256 }), 257 features: denyRules, 258 }, 259 Egress: newL4DirectionPolicy(), 260 }, 261 IngressPolicyEnabled: true, 262 }, 263 PolicyOwner: DummyOwner{}, 264 // inherit this from the result as it is outside of the scope 265 // of this test 266 policyMapState: policy.policyMapState, 267 } 268 269 // Have to remove circular reference before testing to avoid an infinite loop 270 policy.selectorPolicy.Detach() 271 272 // Assign an empty mutex so that checker.Equal does not complain about the 273 // difference of the internal time.Time from the lock_debug.go. 274 policy.selectorPolicy.L4Policy.mutex = lock.RWMutex{} 275 // policyMapState cannot be compared via DeepEqual 276 require.Truef(t, policy.policyMapState.Equals(expectedEndpointPolicy.policyMapState), 277 policy.policyMapState.Diff(expectedEndpointPolicy.policyMapState)) 278 policy.policyMapState = nil 279 expectedEndpointPolicy.policyMapState = nil 280 require.Equal(t, policy, &expectedEndpointPolicy) 281 } 282 283 func TestMapStateWithIngressDenyWildcard(t *testing.T) { 284 td := newTestData() 285 repo := td.repo 286 td.bootstrapRepo(GenerateL3IngressDenyRules, 1000, t) 287 288 ruleLabel := labels.ParseLabelArray("rule-foo-allow-port-80") 289 ruleLabelAllowAnyEgress := labels.LabelArray{ 290 labels.NewLabel(LabelKeyPolicyDerivedFrom, LabelAllowAnyEgress, labels.LabelSourceReserved), 291 } 292 293 idFooSelectLabelArray := labels.ParseSelectLabelArray("id=foo") 294 idFooSelectLabels := labels.Labels{} 295 for _, lbl := range idFooSelectLabelArray { 296 idFooSelectLabels[lbl.Key] = lbl 297 } 298 fooIdentity := identity.NewIdentity(12345, idFooSelectLabels) 299 td.addIdentity(fooIdentity) 300 301 selFoo := api.NewESFromLabels(labels.ParseSelectLabel("id=foo")) 302 rule1 := api.Rule{ 303 EndpointSelector: selFoo, 304 Labels: ruleLabel, 305 IngressDeny: []api.IngressDenyRule{ 306 { 307 ToPorts: []api.PortDenyRule{{ 308 Ports: []api.PortProtocol{ 309 {Port: "80", Protocol: api.ProtoTCP}, 310 }, 311 }}, 312 }, 313 }, 314 } 315 316 rule1.Sanitize() 317 _, _, err := repo.mustAdd(rule1) 318 require.NoError(t, err) 319 320 repo.Mutex.RLock() 321 defer repo.Mutex.RUnlock() 322 selPolicy, err := repo.resolvePolicyLocked(fooIdentity) 323 require.NoError(t, err) 324 policy := selPolicy.DistillPolicy(DummyOwner{}, false) 325 326 rule1MapStateEntry := NewMapStateEntry(td.wildcardCachedSelector, labels.LabelArrayList{ruleLabel}, 0, "", 0, true, DefaultAuthType, AuthTypeDisabled) 327 allowEgressMapStateEntry := NewMapStateEntry(nil, labels.LabelArrayList{ruleLabelAllowAnyEgress}, 0, "", 0, false, ExplicitAuthType, AuthTypeDisabled) 328 329 expectedEndpointPolicy := EndpointPolicy{ 330 selectorPolicy: &selectorPolicy{ 331 Revision: repo.GetRevision(), 332 SelectorCache: repo.GetSelectorCache(), 333 L4Policy: L4Policy{ 334 Revision: repo.GetRevision(), 335 Ingress: L4DirectionPolicy{PortRules: NewL4PolicyMapWithValues(map[string]*L4Filter{ 336 "80/TCP": { 337 Port: 80, 338 Protocol: api.ProtoTCP, 339 U8Proto: 0x6, 340 wildcard: td.wildcardCachedSelector, 341 L7Parser: ParserTypeNone, 342 Ingress: true, 343 PerSelectorPolicies: L7DataMap{ 344 td.wildcardCachedSelector: &PerSelectorPolicy{IsDeny: true}, 345 }, 346 RuleOrigin: map[CachedSelector]labels.LabelArrayList{td.wildcardCachedSelector: {ruleLabel}}, 347 }, 348 }), 349 features: denyRules, 350 }, 351 Egress: newL4DirectionPolicy(), 352 }, 353 IngressPolicyEnabled: true, 354 }, 355 PolicyOwner: DummyOwner{}, 356 policyMapState: newMapState(map[Key]MapStateEntry{ 357 // Although we have calculated deny policies, the overall policy 358 // will still allow egress to world. 359 {TrafficDirection: trafficdirection.Egress.Uint8(), InvertedPortMask: 0xffff /* This is a wildcard */}: allowEgressMapStateEntry, 360 {DestPort: 80, Nexthdr: 6}: rule1MapStateEntry, 361 }), 362 } 363 364 // Add new identity to test accumulation of MapChanges 365 added1 := identity.IdentityMap{ 366 identity.NumericIdentity(192): labels.ParseSelectLabelArray("id=resolve_test_1"), 367 } 368 wg := &sync.WaitGroup{} 369 td.sc.UpdateIdentities(added1, nil, wg) 370 // Cleanup the identities from the testSelectorCache 371 defer td.sc.UpdateIdentities(nil, added1, wg) 372 wg.Wait() 373 require.Equal(t, 0, len(policy.policyMapChanges.changes)) 374 375 // Have to remove circular reference before testing to avoid an infinite loop 376 policy.selectorPolicy.Detach() 377 378 // Assign an empty mutex so that checker.Equal does not complain about the 379 // difference of the internal time.Time from the lock_debug.go. 380 policy.selectorPolicy.L4Policy.mutex = lock.RWMutex{} 381 // policyMapState cannot be compared via DeepEqual 382 require.Truef(t, policy.policyMapState.Equals(expectedEndpointPolicy.policyMapState), 383 policy.policyMapState.Diff(expectedEndpointPolicy.policyMapState)) 384 policy.policyMapState = nil 385 expectedEndpointPolicy.policyMapState = nil 386 require.Equal(t, policy, &expectedEndpointPolicy) 387 } 388 389 func TestMapStateWithIngressDeny(t *testing.T) { 390 td := newTestData() 391 repo := td.repo 392 td.bootstrapRepo(GenerateL3IngressDenyRules, 1000, t) 393 394 ruleLabel := labels.ParseLabelArray("rule-deny-port-80-world-and-test") 395 ruleLabelAllowAnyEgress := labels.LabelArray{ 396 labels.NewLabel(LabelKeyPolicyDerivedFrom, LabelAllowAnyEgress, labels.LabelSourceReserved), 397 } 398 399 idFooSelectLabelArray := labels.ParseSelectLabelArray("id=foo") 400 idFooSelectLabels := labels.Labels{} 401 for _, lbl := range idFooSelectLabelArray { 402 idFooSelectLabels[lbl.Key] = lbl 403 } 404 fooIdentity := identity.NewIdentity(12345, idFooSelectLabels) 405 td.addIdentity(fooIdentity) 406 407 lblTest := labels.ParseLabel("id=resolve_test_1") 408 409 selFoo := api.NewESFromLabels(labels.ParseSelectLabel("id=foo")) 410 rule1 := api.Rule{ 411 EndpointSelector: selFoo, 412 Labels: ruleLabel, 413 IngressDeny: []api.IngressDenyRule{ 414 { 415 IngressCommonRule: api.IngressCommonRule{ 416 FromEntities: []api.Entity{api.EntityWorld}, 417 }, 418 ToPorts: []api.PortDenyRule{{ 419 Ports: []api.PortProtocol{ 420 {Port: "80", Protocol: api.ProtoTCP}, 421 }, 422 }}, 423 }, 424 { 425 IngressCommonRule: api.IngressCommonRule{ 426 FromEndpoints: []api.EndpointSelector{ 427 api.NewESFromLabels(lblTest), 428 }, 429 }, 430 ToPorts: []api.PortDenyRule{{ 431 Ports: []api.PortProtocol{ 432 {Port: "80", Protocol: api.ProtoTCP}, 433 }, 434 }}, 435 }, 436 }, 437 } 438 439 rule1.Sanitize() 440 _, _, err := repo.mustAdd(rule1) 441 require.NoError(t, err) 442 443 repo.Mutex.RLock() 444 defer repo.Mutex.RUnlock() 445 selPolicy, err := repo.resolvePolicyLocked(fooIdentity) 446 require.NoError(t, err) 447 policy := selPolicy.DistillPolicy(DummyOwner{}, false) 448 449 // Add new identity to test accumulation of MapChanges 450 added1 := identity.IdentityMap{ 451 identity.NumericIdentity(192): labels.ParseSelectLabelArray("id=resolve_test_1", "num=1"), 452 identity.NumericIdentity(193): labels.ParseSelectLabelArray("id=resolve_test_1", "num=2"), 453 identity.NumericIdentity(194): labels.ParseSelectLabelArray("id=resolve_test_1", "num=3"), 454 } 455 wg := &sync.WaitGroup{} 456 td.sc.UpdateIdentities(added1, nil, wg) 457 wg.Wait() 458 require.Len(t, policy.policyMapChanges.changes, 3) 459 460 deleted1 := identity.IdentityMap{ 461 identity.NumericIdentity(193): labels.ParseSelectLabelArray("id=resolve_test_1", "num=2"), 462 } 463 wg = &sync.WaitGroup{} 464 td.sc.UpdateIdentities(nil, deleted1, wg) 465 wg.Wait() 466 require.Len(t, policy.policyMapChanges.changes, 4) 467 468 cachedSelectorWorld := td.sc.FindCachedIdentitySelector(api.ReservedEndpointSelectors[labels.IDNameWorld]) 469 require.NotNil(t, cachedSelectorWorld) 470 471 cachedSelectorWorldV4 := td.sc.FindCachedIdentitySelector(api.ReservedEndpointSelectors[labels.IDNameWorldIPv4]) 472 require.NotNil(t, cachedSelectorWorldV4) 473 474 cachedSelectorWorldV6 := td.sc.FindCachedIdentitySelector(api.ReservedEndpointSelectors[labels.IDNameWorldIPv6]) 475 require.NotNil(t, cachedSelectorWorldV6) 476 477 cachedSelectorTest := td.sc.FindCachedIdentitySelector(api.NewESFromLabels(lblTest)) 478 require.NotNil(t, cachedSelectorTest) 479 480 rule1MapStateEntry := NewMapStateEntry(cachedSelectorTest, labels.LabelArrayList{ruleLabel}, 0, "", 0, true, DefaultAuthType, AuthTypeDisabled) 481 allowEgressMapStateEntry := NewMapStateEntry(nil, labels.LabelArrayList{ruleLabelAllowAnyEgress}, 0, "", 0, false, ExplicitAuthType, AuthTypeDisabled) 482 483 expectedEndpointPolicy := EndpointPolicy{ 484 selectorPolicy: &selectorPolicy{ 485 Revision: repo.GetRevision(), 486 SelectorCache: repo.GetSelectorCache(), 487 L4Policy: L4Policy{ 488 Revision: repo.GetRevision(), 489 Ingress: L4DirectionPolicy{PortRules: NewL4PolicyMapWithValues(map[string]*L4Filter{ 490 "80/TCP": { 491 Port: 80, 492 Protocol: api.ProtoTCP, 493 U8Proto: 0x6, 494 L7Parser: ParserTypeNone, 495 Ingress: true, 496 PerSelectorPolicies: L7DataMap{ 497 cachedSelectorWorld: &PerSelectorPolicy{IsDeny: true}, 498 cachedSelectorWorldV4: &PerSelectorPolicy{IsDeny: true}, 499 cachedSelectorWorldV6: &PerSelectorPolicy{IsDeny: true}, 500 cachedSelectorTest: &PerSelectorPolicy{IsDeny: true}, 501 }, 502 RuleOrigin: map[CachedSelector]labels.LabelArrayList{ 503 cachedSelectorWorld: {ruleLabel}, 504 cachedSelectorWorldV4: {ruleLabel}, 505 cachedSelectorWorldV6: {ruleLabel}, 506 cachedSelectorTest: {ruleLabel}, 507 }, 508 }, 509 }), 510 features: denyRules, 511 }, 512 Egress: newL4DirectionPolicy(), 513 }, 514 IngressPolicyEnabled: true, 515 }, 516 PolicyOwner: DummyOwner{}, 517 policyMapState: newMapState(map[Key]MapStateEntry{ 518 // Although we have calculated deny policies, the overall policy 519 // will still allow egress to world. 520 {TrafficDirection: trafficdirection.Egress.Uint8(), InvertedPortMask: 0xffff /* This is a wildcard */}: allowEgressMapStateEntry, 521 {Identity: uint32(identity.ReservedIdentityWorld), DestPort: 80, Nexthdr: 6}: rule1MapStateEntry.WithOwners(cachedSelectorWorld), 522 {Identity: uint32(identity.ReservedIdentityWorldIPv4), DestPort: 80, Nexthdr: 6}: rule1MapStateEntry.WithOwners(cachedSelectorWorldV4, cachedSelectorWorld), 523 {Identity: uint32(identity.ReservedIdentityWorldIPv6), DestPort: 80, Nexthdr: 6}: rule1MapStateEntry.WithOwners(cachedSelectorWorldV6, cachedSelectorWorld), 524 {Identity: 192, DestPort: 80, Nexthdr: 6}: rule1MapStateEntry, 525 {Identity: 194, DestPort: 80, Nexthdr: 6}: rule1MapStateEntry, 526 }), 527 } 528 529 adds, deletes := policy.ConsumeMapChanges() 530 // maps on the policy got cleared 531 532 require.Equal(t, Keys{ 533 {Identity: 192, DestPort: 80, Nexthdr: 6}: {}, 534 {Identity: 194, DestPort: 80, Nexthdr: 6}: {}, 535 }, adds) 536 require.Equal(t, Keys{ 537 {Identity: 193, DestPort: 80, Nexthdr: 6}: {}, 538 }, deletes) 539 540 // Have to remove circular reference before testing for Equality to avoid an infinite loop 541 policy.selectorPolicy.Detach() 542 // Verify that cached selector is not found after Detach(). 543 // Note that this depends on the other tests NOT using the same selector concurrently! 544 cachedSelectorTest = td.sc.FindCachedIdentitySelector(api.NewESFromLabels(lblTest)) 545 require.Nil(t, cachedSelectorTest) 546 547 // Assign an empty mutex so that checker.Equal does not complain about the 548 // difference of the internal time.Time from the lock_debug.go. 549 policy.selectorPolicy.L4Policy.mutex = lock.RWMutex{} 550 policy.policyMapChanges.mutex = lock.Mutex{} 551 // policyMapState cannot be compared via DeepEqual 552 require.Truef(t, policy.policyMapState.Equals(expectedEndpointPolicy.policyMapState), 553 policy.policyMapState.Diff(expectedEndpointPolicy.policyMapState)) 554 policy.policyMapState = nil 555 expectedEndpointPolicy.policyMapState = nil 556 require.Equal(t, policy, &expectedEndpointPolicy) 557 }