go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/server/auth/authdb/snapshot_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 authdb 16 17 import ( 18 "context" 19 "encoding/json" 20 "flag" 21 "math/rand" 22 "net" 23 "net/http" 24 "os" 25 "runtime" 26 "sort" 27 "strings" 28 "testing" 29 30 "google.golang.org/protobuf/proto" 31 32 "go.chromium.org/luci/auth/identity" 33 "go.chromium.org/luci/common/data/stringset" 34 35 "go.chromium.org/luci/server/auth/authdb/internal/graph" 36 "go.chromium.org/luci/server/auth/authdb/internal/legacy" 37 "go.chromium.org/luci/server/auth/authdb/internal/oauthid" 38 "go.chromium.org/luci/server/auth/authdb/internal/realmset" 39 "go.chromium.org/luci/server/auth/internal" 40 "go.chromium.org/luci/server/auth/realms" 41 "go.chromium.org/luci/server/auth/service/protocol" 42 "go.chromium.org/luci/server/auth/signing" 43 "go.chromium.org/luci/server/auth/signing/signingtest" 44 "go.chromium.org/luci/server/caching" 45 46 . "github.com/smartystreets/goconvey/convey" 47 . "go.chromium.org/luci/common/testing/assertions" 48 ) 49 50 var ( 51 perm1 = realms.RegisterPermission("luci.dev.testing1") 52 perm2 = realms.RegisterPermission("luci.dev.testing2") 53 unknownPerm = realms.RegisterPermission("luci.dev.unknown") 54 55 // For the benchmark that uses real AuthDB dumps. 56 bbBuildsGet = realms.RegisterPermission("buildbucket.builds.get") 57 ) 58 59 func init() { 60 perm1.AddFlags(realms.UsedInQueryRealms) 61 bbBuildsGet.AddFlags(realms.UsedInQueryRealms) 62 } 63 64 func TestSnapshotDB(t *testing.T) { 65 c := context.Background() 66 67 securityConfig, _ := proto.Marshal(&protocol.SecurityConfig{ 68 InternalServiceRegexp: []string{ 69 `(.*-dot-)?i1\.example\.com`, 70 `(.*-dot-)?i2\.example\.com`, 71 }, 72 }) 73 74 db, err := NewSnapshotDB(&protocol.AuthDB{ 75 OauthClientId: "primary-client-id", 76 OauthAdditionalClientIds: []string{ 77 "additional-client-id-1", 78 "additional-client-id-2", 79 }, 80 TokenServerUrl: "http://token-server", 81 Groups: []*protocol.AuthGroup{ 82 { 83 Name: "direct", 84 Members: []string{"user:abc@example.com"}, 85 }, 86 { 87 Name: "via glob", 88 Globs: []string{"user:*@example.com"}, 89 }, 90 { 91 Name: "via nested", 92 Nested: []string{"direct"}, 93 }, 94 { 95 Name: "cycle", 96 Nested: []string{"cycle"}, 97 }, 98 { 99 Name: "unknown nested", 100 Nested: []string{"unknown"}, 101 }, 102 { 103 Name: "empty", 104 }, 105 }, 106 IpWhitelistAssignments: []*protocol.AuthIPWhitelistAssignment{ 107 { 108 Identity: "user:abc@example.com", 109 IpWhitelist: "allowlist", 110 }, 111 }, 112 IpWhitelists: []*protocol.AuthIPWhitelist{ 113 { 114 Name: "allowlist", 115 Subnets: []string{ 116 "1.2.3.4/32", 117 "10.0.0.0/8", 118 }, 119 }, 120 { 121 Name: "empty", 122 }, 123 }, 124 SecurityConfig: securityConfig, 125 }, "http://auth-service", 1234, false) 126 if err != nil { 127 panic(err) 128 } 129 130 Convey("IsAllowedOAuthClientID works", t, func() { 131 call := func(email, clientID string) bool { 132 res, err := db.IsAllowedOAuthClientID(c, email, clientID) 133 So(err, ShouldBeNil) 134 return res 135 } 136 137 So(call("dude@example.com", ""), ShouldBeFalse) 138 So(call("dude@example.com", oauthid.GoogleAPIExplorerClientID), ShouldBeTrue) 139 So(call("dude@example.com", "primary-client-id"), ShouldBeTrue) 140 So(call("dude@example.com", "additional-client-id-2"), ShouldBeTrue) 141 So(call("dude@example.com", "unknown-client-id"), ShouldBeFalse) 142 }) 143 144 Convey("IsInternalService works", t, func() { 145 call := func(hostname string) bool { 146 res, err := db.IsInternalService(c, hostname) 147 So(err, ShouldBeNil) 148 return res 149 } 150 151 So(call("i1.example.com"), ShouldBeTrue) 152 So(call("i2.example.com"), ShouldBeTrue) 153 So(call("abc-dot-i1.example.com"), ShouldBeTrue) 154 So(call("external.example.com"), ShouldBeFalse) 155 So(call("something-i1.example.com"), ShouldBeFalse) 156 So(call("i1.example.com-something"), ShouldBeFalse) 157 }) 158 159 Convey("IsMember works", t, func() { 160 call := func(ident string, groups ...string) bool { 161 res, err := db.IsMember(c, identity.Identity(ident), groups) 162 So(err, ShouldBeNil) 163 return res 164 } 165 166 So(call("user:abc@example.com", "direct"), ShouldBeTrue) 167 So(call("user:another@example.com", "direct"), ShouldBeFalse) 168 169 So(call("user:abc@example.com", "via glob"), ShouldBeTrue) 170 So(call("user:abc@another.com", "via glob"), ShouldBeFalse) 171 172 So(call("user:abc@example.com", "via nested"), ShouldBeTrue) 173 So(call("user:another@example.com", "via nested"), ShouldBeFalse) 174 175 So(call("user:abc@example.com", "cycle"), ShouldBeFalse) 176 So(call("user:abc@example.com", "unknown"), ShouldBeFalse) 177 So(call("user:abc@example.com", "unknown nested"), ShouldBeFalse) 178 179 So(call("user:abc@example.com"), ShouldBeFalse) 180 So(call("user:abc@example.com", "unknown", "direct"), ShouldBeTrue) 181 So(call("user:abc@example.com", "via glob", "direct"), ShouldBeTrue) 182 }) 183 184 Convey("CheckMembership works", t, func() { 185 call := func(ident string, groups ...string) []string { 186 res, err := db.CheckMembership(c, identity.Identity(ident), groups) 187 So(err, ShouldBeNil) 188 return res 189 } 190 191 So(call("user:abc@example.com", "direct"), ShouldResemble, []string{"direct"}) 192 So(call("user:another@example.com", "direct"), ShouldBeNil) 193 194 So(call("user:abc@example.com", "via glob"), ShouldResemble, []string{"via glob"}) 195 So(call("user:abc@another.com", "via glob"), ShouldBeNil) 196 197 So(call("user:abc@example.com", "via nested"), ShouldResemble, []string{"via nested"}) 198 So(call("user:another@example.com", "via nested"), ShouldBeNil) 199 200 So(call("user:abc@example.com", "cycle"), ShouldBeNil) 201 So(call("user:abc@example.com", "unknown"), ShouldBeNil) 202 So(call("user:abc@example.com", "unknown nested"), ShouldBeNil) 203 204 So(call("user:abc@example.com"), ShouldBeNil) 205 So(call("user:abc@example.com", "unknown", "direct"), ShouldResemble, []string{"direct"}) 206 So(call("user:abc@example.com", "via glob", "direct"), ShouldResemble, []string{"via glob", "direct"}) 207 }) 208 209 Convey("FilterKnownGroups works", t, func() { 210 known, err := db.FilterKnownGroups(c, []string{"direct", "unknown", "empty", "direct", "unknown"}) 211 So(err, ShouldBeNil) 212 So(known, ShouldResemble, []string{"direct", "empty", "direct"}) 213 }) 214 215 Convey("With realms", t, func() { 216 db, err := NewSnapshotDB(&protocol.AuthDB{ 217 Groups: []*protocol.AuthGroup{ 218 { 219 Name: "direct", 220 Members: []string{"user:abc@example.com"}, 221 }, 222 }, 223 Realms: &protocol.Realms{ 224 ApiVersion: realmset.ExpectedAPIVersion, 225 Permissions: []*protocol.Permission{ 226 {Name: perm1.Name()}, 227 {Name: perm2.Name()}, 228 }, 229 Conditions: []*protocol.Condition{ 230 { 231 Op: &protocol.Condition_Restrict{ 232 Restrict: &protocol.Condition_AttributeRestriction{ 233 Attribute: "a", 234 Values: []string{"ok_1", "ok_2"}, 235 }, 236 }, 237 }, 238 }, 239 Realms: []*protocol.Realm{ 240 { 241 Name: "proj:@root", 242 Bindings: []*protocol.Binding{ 243 { 244 Permissions: []uint32{0}, 245 Principals: []string{"user:root@example.com"}, 246 }, 247 }, 248 Data: &protocol.RealmData{ 249 EnforceInService: []string{"root"}, 250 }, 251 }, 252 { 253 Name: "proj:some/realm", 254 Bindings: []*protocol.Binding{ 255 { 256 Permissions: []uint32{0}, 257 Principals: []string{"user:realm@example.com", "group:direct"}, 258 }, 259 { 260 Conditions: []uint32{0}, 261 Permissions: []uint32{0}, 262 Principals: []string{"user:cond@example.com"}, 263 }, 264 }, 265 Data: &protocol.RealmData{ 266 EnforceInService: []string{"some"}, 267 }, 268 }, 269 { 270 Name: "another:realm", 271 Bindings: []*protocol.Binding{ 272 { 273 Permissions: []uint32{0}, 274 Principals: []string{"user:realm@example.com"}, 275 }, 276 }, 277 }, 278 { 279 Name: "proj:empty", 280 }, 281 }, 282 }, 283 }, "http://auth-service", 1234, false) 284 So(err, ShouldBeNil) 285 286 Convey("HasPermission works", func() { 287 // A direct hit. 288 ok, err := db.HasPermission(c, "user:realm@example.com", perm1, "proj:some/realm", nil) 289 So(err, ShouldBeNil) 290 So(ok, ShouldBeTrue) 291 292 // A hit through a group. 293 ok, err = db.HasPermission(c, "user:abc@example.com", perm1, "proj:some/realm", nil) 294 So(err, ShouldBeNil) 295 So(ok, ShouldBeTrue) 296 297 // Fallback to the root. 298 ok, err = db.HasPermission(c, "user:root@example.com", perm1, "proj:unknown", nil) 299 So(err, ShouldBeNil) 300 So(ok, ShouldBeTrue) 301 302 // No permission. 303 ok, err = db.HasPermission(c, "user:realm@example.com", perm2, "proj:some/realm", nil) 304 So(err, ShouldBeNil) 305 So(ok, ShouldBeFalse) 306 307 // Unknown root realm. 308 ok, err = db.HasPermission(c, "user:realm@example.com", perm1, "unknown:@root", nil) 309 So(err, ShouldBeNil) 310 So(ok, ShouldBeFalse) 311 312 // Unknown permission. 313 ok, err = db.HasPermission(c, "user:realm@example.com", unknownPerm, "proj:some/realm", nil) 314 So(err, ShouldBeNil) 315 So(ok, ShouldBeFalse) 316 317 // Empty realm. 318 ok, err = db.HasPermission(c, "user:realm@example.com", perm1, "proj:empty", nil) 319 So(err, ShouldBeNil) 320 So(ok, ShouldBeFalse) 321 322 // Invalid realm name. 323 _, err = db.HasPermission(c, "user:realm@example.com", perm1, "@root", nil) 324 So(err, ShouldErrLike, "bad global realm name") 325 }) 326 327 Convey("Conditional bindings", func() { 328 ok, err := db.HasPermission(c, "user:cond@example.com", perm1, "proj:some/realm", nil) 329 So(err, ShouldBeNil) 330 So(ok, ShouldBeFalse) 331 332 ok, err = db.HasPermission(c, "user:cond@example.com", perm1, "proj:some/realm", realms.Attrs{"a": "ok_1"}) 333 So(err, ShouldBeNil) 334 So(ok, ShouldBeTrue) 335 336 ok, err = db.HasPermission(c, "user:cond@example.com", perm1, "proj:some/realm", realms.Attrs{"a": "ok_2"}) 337 So(err, ShouldBeNil) 338 So(ok, ShouldBeTrue) 339 340 ok, err = db.HasPermission(c, "user:cond@example.com", perm1, "proj:some/realm", realms.Attrs{"a": "???"}) 341 So(err, ShouldBeNil) 342 So(ok, ShouldBeFalse) 343 344 ok, err = db.HasPermission(c, "user:cond@example.com", perm2, "proj:some/realm", realms.Attrs{"a": "ok_1"}) 345 So(err, ShouldBeNil) 346 So(ok, ShouldBeFalse) 347 }) 348 349 Convey("QueryRealms works", func() { 350 // A direct hit. 351 r, err := db.QueryRealms(c, "user:realm@example.com", perm1, "", nil) 352 sort.Strings(r) 353 So(err, ShouldBeNil) 354 So(r, ShouldResemble, []string{"another:realm", "proj:some/realm"}) 355 356 // Filtering by project. 357 r, err = db.QueryRealms(c, "user:realm@example.com", perm1, "proj", nil) 358 So(err, ShouldBeNil) 359 So(r, ShouldResemble, []string{"proj:some/realm"}) 360 361 // A hit through a group. 362 r, err = db.QueryRealms(c, "user:abc@example.com", perm1, "", nil) 363 So(err, ShouldBeNil) 364 So(r, ShouldResemble, []string{"proj:some/realm"}) 365 }) 366 367 Convey("QueryRealms with conditional bindings", func() { 368 r, err := db.QueryRealms(c, "user:cond@example.com", perm1, "", nil) 369 So(err, ShouldBeNil) 370 So(r, ShouldBeEmpty) 371 372 r, err = db.QueryRealms(c, "user:cond@example.com", perm1, "", realms.Attrs{"a": "ok_1"}) 373 So(err, ShouldBeNil) 374 So(r, ShouldResemble, []string{"proj:some/realm"}) 375 376 r, err = db.QueryRealms(c, "user:cond@example.com", perm1, "", realms.Attrs{"a": "???"}) 377 So(err, ShouldBeNil) 378 So(r, ShouldBeEmpty) 379 }) 380 381 Convey("QueryRealms with unindexed permission", func() { 382 _, err := db.QueryRealms(c, "user:realm@example.com", perm2, "", nil) 383 So(err, ShouldErrLike, "permission luci.dev.testing2 cannot be used in QueryRealms") 384 }) 385 386 Convey("GetRealmData works", func() { 387 // Known realm with data. 388 d, err := db.GetRealmData(c, "proj:some/realm") 389 So(err, ShouldBeNil) 390 So(d, ShouldResembleProto, &protocol.RealmData{ 391 EnforceInService: []string{"some"}, 392 }) 393 394 // Known realm, with no data. 395 d, err = db.GetRealmData(c, "proj:empty") 396 So(err, ShouldBeNil) 397 So(d, ShouldResembleProto, &protocol.RealmData{}) 398 399 // Fallback to root. 400 d, err = db.GetRealmData(c, "proj:unknown") 401 So(err, ShouldBeNil) 402 So(d, ShouldResembleProto, &protocol.RealmData{ 403 EnforceInService: []string{"root"}, 404 }) 405 406 // Completely unknown. 407 d, err = db.GetRealmData(c, "unknown:unknown") 408 So(err, ShouldBeNil) 409 So(d, ShouldBeNil) 410 }) 411 }) 412 413 Convey("GetCertificates works", t, func(c C) { 414 tokenService := signingtest.NewSigner(&signing.ServiceInfo{ 415 AppID: "token-server", 416 ServiceAccountName: "token-server-account@example.com", 417 }) 418 419 calls := 0 420 421 ctx := context.Background() 422 ctx = caching.WithEmptyProcessCache(ctx) 423 424 ctx = internal.WithTestTransport(ctx, func(r *http.Request, body string) (int, string) { 425 calls++ 426 if r.URL.String() != "http://token-server/auth/api/v1/server/certificates" { 427 return 404, "Wrong URL" 428 } 429 certs, err := tokenService.Certificates(ctx) 430 if err != nil { 431 panic(err) 432 } 433 blob, err := json.Marshal(certs) 434 if err != nil { 435 panic(err) 436 } 437 return 200, string(blob) 438 }) 439 440 certs, err := db.GetCertificates(ctx, "user:token-server-account@example.com") 441 So(err, ShouldBeNil) 442 So(certs, ShouldNotBeNil) 443 444 // Fetched one bundle. 445 So(calls, ShouldEqual, 1) 446 447 // For unknown signer returns (nil, nil). 448 certs, err = db.GetCertificates(ctx, "user:unknown@example.com") 449 So(err, ShouldBeNil) 450 So(certs, ShouldBeNil) 451 }) 452 453 Convey("IsAllowedIP works", t, func() { 454 l, err := db.GetAllowlistForIdentity(c, "user:abc@example.com") 455 So(err, ShouldBeNil) 456 So(l, ShouldEqual, "allowlist") 457 458 l, err = db.GetAllowlistForIdentity(c, "user:unknown@example.com") 459 So(err, ShouldBeNil) 460 So(l, ShouldEqual, "") 461 462 call := func(ip, allowlist string) bool { 463 ipaddr := net.ParseIP(ip) 464 So(ipaddr, ShouldNotBeNil) 465 res, err := db.IsAllowedIP(c, ipaddr, allowlist) 466 So(err, ShouldBeNil) 467 return res 468 } 469 470 So(call("1.2.3.4", "allowlist"), ShouldBeTrue) 471 So(call("10.255.255.255", "allowlist"), ShouldBeTrue) 472 So(call("9.255.255.255", "allowlist"), ShouldBeFalse) 473 So(call("1.2.3.4", "empty"), ShouldBeFalse) 474 }) 475 476 Convey("Revision works", t, func() { 477 So(Revision(&SnapshotDB{Rev: 123}), ShouldEqual, 123) 478 So(Revision(ErroringDB{}), ShouldEqual, 0) 479 So(Revision(nil), ShouldEqual, 0) 480 }) 481 482 Convey("SnapshotDBFromTextProto works", t, func() { 483 db, err := SnapshotDBFromTextProto(strings.NewReader(` 484 groups { 485 name: "group" 486 members: "user:a@example.com" 487 } 488 `)) 489 So(err, ShouldBeNil) 490 yes, err := db.IsMember(c, "user:a@example.com", []string{"group"}) 491 So(err, ShouldBeNil) 492 So(yes, ShouldBeTrue) 493 }) 494 495 Convey("SnapshotDBFromTextProto bad proto", t, func() { 496 _, err := SnapshotDBFromTextProto(strings.NewReader(` 497 groupz {} 498 `)) 499 So(err, ShouldErrLike, "not a valid AuthDB text proto file") 500 }) 501 502 Convey("SnapshotDBFromTextProto bad structure", t, func() { 503 _, err := SnapshotDBFromTextProto(strings.NewReader(` 504 groups { 505 name: "group 1" 506 nested: "group 2" 507 } 508 groups { 509 name: "group 2" 510 nested: "group 1" 511 } 512 `)) 513 So(err, ShouldErrLike, "dependency cycle found") 514 }) 515 } 516 517 var authDBPath = flag.String("authdb", "", "path to AuthDB proto to use in tests") 518 var testAuthDB *protocol.AuthDB 519 520 func TestMain(m *testing.M) { 521 flag.Parse() 522 if *authDBPath != "" { 523 testAuthDB = readTestDB(*authDBPath) 524 } 525 os.Exit(m.Run()) 526 } 527 528 var letterRunes = []rune("abcdefghijklmnopqrstuvwxyz0123456789") 529 530 func randString(min, max int, seen stringset.Set) string { 531 for { 532 b := make([]rune, min+rand.Intn(max)) 533 for i := range b { 534 b[i] = letterRunes[rand.Intn(len(letterRunes))] 535 } 536 s := string(b) 537 if seen.Add(s) { 538 return s 539 } 540 } 541 } 542 543 func readTestDB(path string) *protocol.AuthDB { 544 blob, err := os.ReadFile(path) 545 if err != nil { 546 panic(err) 547 } 548 authdb := protocol.AuthDB{} 549 if err := proto.Unmarshal(blob, &authdb); err != nil { 550 panic(err) 551 } 552 return &authdb 553 } 554 555 func makeTestDB(users, groups int) *protocol.AuthDB { 556 if testAuthDB != nil { 557 return testAuthDB 558 } 559 560 db := &protocol.AuthDB{} 561 562 domains := make([]string, 50) 563 seenDomains := stringset.New(50) 564 for i := range domains { 565 domains[i] = "@" + randString(5, 15, seenDomains) + ".com" 566 } 567 members := make([]string, users) 568 seenMembers := stringset.New(users) 569 for i := range members { 570 members[i] = "user:" + randString(3, 20, seenMembers) + domains[rand.Intn(len(domains))] 571 } 572 573 seenGroups := stringset.New(groups) 574 for i := 0; i < groups; i++ { 575 s := rand.Intn(len(members)) 576 l := rand.Intn(len(members) - s) 577 db.Groups = append(db.Groups, &protocol.AuthGroup{ 578 Name: randString(10, 30, seenGroups), 579 Members: members[s : s+l], 580 }) 581 } 582 583 return db 584 } 585 586 type queryableGraph interface { 587 IsMember(ident identity.Identity, group string) graph.IsMemberResult 588 } 589 590 func oldQueryableGraph(db *protocol.AuthDB) queryableGraph { 591 q, err := legacy.BuildGroups(db.Groups) 592 if err != nil { 593 panic(err) 594 } 595 return q 596 } 597 598 func newQueryableGraph(db *protocol.AuthDB) queryableGraph { 599 q, err := graph.BuildQueryable(db.Groups) 600 if err != nil { 601 panic(err) 602 } 603 return q 604 } 605 606 func memUsage(t *testing.T, cb func(*runtime.MemStats)) { 607 var m1, m2 runtime.MemStats 608 609 cb(&m1) 610 runtime.GC() 611 runtime.ReadMemStats(&m2) 612 613 t.Logf("HeapAlloc: %1.f Kb", float64(m1.HeapAlloc-m2.HeapAlloc)/1024) 614 } 615 616 func runMemUsageTest(t *testing.T, cb func(db *protocol.AuthDB) queryableGraph) { 617 db := makeTestDB(1000, 500) 618 memUsage(t, func(m *runtime.MemStats) { 619 q := cb(db) 620 runtime.GC() 621 runtime.ReadMemStats(m) 622 runtime.KeepAlive(q) 623 }) 624 } 625 626 // Note: to run some benchmarks with real AuthDB: 627 // go run go.chromium.org/luci/auth/client/cmd/authdb-dump -output-proto-file auth.db 628 // go test . -run=TestMemUsage* -v -authdb auth.db 629 // go test -bench=QueryRealms -run=XXX -authdb auth.db 630 631 func TestMemUsageOld(t *testing.T) { 632 runMemUsageTest(t, oldQueryableGraph) 633 } 634 635 func TestMemUsageNew(t *testing.T) { 636 runMemUsageTest(t, newQueryableGraph) 637 } 638 639 func TestCompareNewAndOld(t *testing.T) { 640 db := makeTestDB(100, 50) 641 old := oldQueryableGraph(db) 642 new := newQueryableGraph(db) 643 644 idSet := stringset.New(0) 645 for _, g := range db.Groups { 646 for _, m := range g.Members { 647 idSet.Add(m) 648 } 649 } 650 idents := idSet.ToSlice() 651 sort.Strings(idents) 652 653 for _, g := range db.Groups { 654 for _, id := range idents { 655 r1 := old.IsMember(identity.Identity(id), g.Name) 656 r2 := new.IsMember(identity.Identity(id), g.Name) 657 if r1 != r2 { 658 t.Fatalf("IsMember(%q, %q): %v != %v", id, g.Name, r1, r2) 659 } 660 } 661 } 662 } 663 664 func runIsMemberBenchmark(b *testing.B, db *protocol.AuthDB, q queryableGraph) { 665 idSet := stringset.New(0) 666 for _, g := range db.Groups { 667 for _, m := range g.Members { 668 idSet.Add(m) 669 } 670 } 671 idents := idSet.ToSlice() 672 673 b.ResetTimer() 674 for i := 0; i < b.N; i++ { 675 for _, g := range db.Groups { 676 for _, id := range idents { 677 q.IsMember(identity.Identity(id), g.Name) 678 } 679 } 680 } 681 } 682 683 func BenchmarkIsMemberOld(b *testing.B) { 684 db := makeTestDB(100, 50) 685 runIsMemberBenchmark(b, db, oldQueryableGraph(db)) 686 } 687 688 func BenchmarkIsMemberNew(b *testing.B) { 689 db := makeTestDB(100, 50) 690 runIsMemberBenchmark(b, db, newQueryableGraph(db)) 691 } 692 693 func BenchmarkQueryRealms(b *testing.B) { 694 ctx := context.Background() 695 db, err := NewSnapshotDB(makeTestDB(100, 50), "http://auth-service", 1234, false) 696 if err != nil { 697 b.Fatalf("bad AuthDB: %s", err) 698 } 699 b.ResetTimer() 700 for i := 0; i < b.N; i++ { 701 realms, err := db.QueryRealms(ctx, "user:someone@example.com", bbBuildsGet, "", nil) 702 if i == 0 { 703 if err != nil { 704 b.Fatalf("QueryRealms failed: %s", err) 705 } 706 b.Logf("Hits: %d", len(realms)) 707 } 708 } 709 }