github.com/Axway/agent-sdk@v1.1.101/pkg/apic/apiserver/clients/api/v1/fake.go (about) 1 package v1 2 3 import ( 4 "context" 5 "fmt" 6 "strings" 7 "sync" 8 "time" 9 10 apiv1 "github.com/Axway/agent-sdk/pkg/apic/apiserver/models/api/v1" 11 "github.com/google/uuid" 12 ) 13 14 func event(eType apiv1.EventType, ri *apiv1.ResourceInstance) *apiv1.Event { 15 return &apiv1.Event{ 16 ID: uuid.New().String(), 17 Type: eType, 18 Payload: apiv1.EventPayload{ 19 GroupKind: ri.GroupKind, 20 Scope: ri.Metadata.Scope, 21 Tags: ri.Tags, 22 Attributes: ri.Attributes, 23 ID: ri.Metadata.ID, 24 Name: ri.Name, 25 References: ri.Metadata.References, // needed ? 26 }, 27 } 28 } 29 30 type fakeGroup map[string]fakeVersion 31 32 type fakeVersion map[string]*fakeUnscoped 33 34 type fakeAttribute struct { 35 key string 36 value string 37 } 38 39 type fakeUnscoped struct { 40 fakeScoped 41 scopedKinds map[string]fakeByScope 42 } 43 44 func notFound(name, kind string) NotFoundError { 45 return NotFoundError{[]apiv1.Error{{ 46 Status: 404, 47 Title: "Not found error", 48 Detail: fmt.Sprintf("Resource %s of kind %s not found.", name, kind), 49 }}} 50 } 51 52 func notFoundInScope(name, kind, scopeName string) NotFoundError { 53 return NotFoundError{[]apiv1.Error{{ 54 Status: 404, 55 Title: "Not found error", 56 Detail: fmt.Sprintf("Resource %s of kind %s not found in scope %s.", name, kind, scopeName), 57 }}} 58 } 59 60 type unknownScope NotFoundError 61 62 // Create - 63 func (us unknownScope) Create(ri *apiv1.ResourceInstance, opts ...CreateOption) (*apiv1.ResourceInstance, error) { 64 return us.CreateCtx(context.Background(), ri) 65 } 66 67 // CreateCtx - 68 func (us unknownScope) CreateCtx(_ context.Context, _ *apiv1.ResourceInstance) (*apiv1.ResourceInstance, error) { 69 return nil, NotFoundError(us) 70 } 71 72 // Delete - 73 func (us unknownScope) Delete(ri *apiv1.ResourceInstance) error { 74 return us.DeleteCtx(context.Background(), ri) 75 } 76 77 // DeleteCtx - 78 func (us unknownScope) DeleteCtx(ctx context.Context, _ *apiv1.ResourceInstance) error { 79 return NotFoundError(us) 80 } 81 82 // Get - 83 func (us unknownScope) Get(name string) (*apiv1.ResourceInstance, error) { 84 return us.GetCtx(context.Background(), name) 85 } 86 87 // GetCtx - 88 func (us unknownScope) GetCtx(_ context.Context, _ string) (*apiv1.ResourceInstance, error) { 89 return nil, NotFoundError(us) 90 } 91 92 // List - 93 func (us unknownScope) List(options ...ListOptions) ([]*apiv1.ResourceInstance, error) { 94 return us.ListCtx(context.Background(), options...) 95 } 96 97 // ListCtx - 98 func (us unknownScope) ListCtx(_ context.Context, _ ...ListOptions) ([]*apiv1.ResourceInstance, error) { 99 return nil, NotFoundError(us) 100 } 101 102 // Update - 103 func (us unknownScope) Update(ri *apiv1.ResourceInstance, opts ...UpdateOption) (*apiv1.ResourceInstance, error) { 104 return us.UpdateCtx(context.Background(), ri, opts...) 105 } 106 107 // UpdateCtx - 108 func (us unknownScope) UpdateCtx(_ context.Context, _ *apiv1.ResourceInstance, opts ...UpdateOption) (*apiv1.ResourceInstance, error) { 109 return nil, NotFoundError(us) 110 } 111 112 type fakeByScope struct { 113 apiv1.GroupVersionKind 114 scopeKind apiv1.GroupKind 115 fks map[string]*fakeScoped 116 } 117 118 // Create - 119 func (fk fakeByScope) Create(ri *apiv1.ResourceInstance, opts ...CreateOption) (*apiv1.ResourceInstance, error) { 120 return fk.CreateCtx(context.Background(), ri, opts...) 121 } 122 123 // CreateCtx - 124 func (fk fakeByScope) CreateCtx(c context.Context, ri *apiv1.ResourceInstance, opts ...CreateOption) (*apiv1.ResourceInstance, error) { 125 newri := *ri 126 127 newri.GroupVersionKind = fk.GroupVersionKind 128 newri.ResourceMeta.Metadata.Scope.Kind = fk.scopeKind.Kind 129 130 return fk.fks[ri.ResourceMeta.Metadata.Scope.Name].CreateCtx(c, &newri, opts...) 131 } 132 133 // Delete - 134 func (fk fakeByScope) Delete(ri *apiv1.ResourceInstance) error { 135 return fk.DeleteCtx(context.Background(), ri) 136 } 137 138 // DeleteCtx - 139 func (fk fakeByScope) DeleteCtx(c context.Context, ri *apiv1.ResourceInstance) error { 140 newri := *ri 141 142 newri.GroupVersionKind = fk.GroupVersionKind 143 newri.ResourceMeta.Metadata.Scope.Kind = fk.scopeKind.Kind 144 145 return fk.fks[ri.ResourceMeta.Metadata.Scope.Name].DeleteCtx(c, &newri) 146 } 147 148 // Get - 149 func (fk fakeByScope) Get(ri string) (*apiv1.ResourceInstance, error) { 150 return fk.GetCtx(context.Background(), ri) 151 } 152 153 // GetCtx - 154 func (fk fakeByScope) GetCtx(_ context.Context, name string) (*apiv1.ResourceInstance, error) { 155 split := strings.SplitN(name, `/`, 2) 156 157 if len(split) == 2 { 158 return fk.fks[split[0]].Get(split[1]) 159 } 160 161 return nil, notFound("", fk.scopeKind.Kind) 162 } 163 164 // List - 165 func (fk fakeByScope) List(ri ...ListOptions) ([]*apiv1.ResourceInstance, error) { 166 return fk.ListCtx(context.Background(), ri...) 167 } 168 169 // ListCtx - 170 func (fk fakeByScope) ListCtx(_ context.Context, options ...ListOptions) ([]*apiv1.ResourceInstance, error) { 171 return nil, notFound("", "") 172 } 173 174 // Update - 175 func (fk fakeByScope) Update(ri *apiv1.ResourceInstance, opts ...UpdateOption) (*apiv1.ResourceInstance, error) { 176 return fk.UpdateCtx(context.Background(), ri, opts...) 177 } 178 179 // UpdateCtx - 180 func (fk fakeByScope) UpdateCtx(c context.Context, ri *apiv1.ResourceInstance, opts ...UpdateOption) (*apiv1.ResourceInstance, error) { 181 newri := *ri 182 183 newri.GroupVersionKind = fk.GroupVersionKind 184 newri.ResourceMeta.Metadata.Scope.Kind = fk.scopeKind.Kind 185 186 return fk.fks[ri.ResourceMeta.Metadata.Scope.Name].UpdateCtx(c, &newri, opts...) 187 } 188 189 // WithScope - 190 func (fk fakeByScope) WithScope(name string) Scoped { 191 if s, ok := fk.fks[name]; !ok { 192 return unknownScope(notFound(name, fk.scopeKind.Kind)) 193 } else { 194 return s 195 } 196 } 197 198 // Create - 199 func (fk *fakeUnscoped) Create(ri *apiv1.ResourceInstance, opts ...CreateOption) (*apiv1.ResourceInstance, error) { 200 return fk.CreateCtx(context.Background(), ri, opts...) 201 } 202 203 // CreateCtx - 204 func (fk *fakeUnscoped) CreateCtx(_ context.Context, ri *apiv1.ResourceInstance, opts ...CreateOption) (*apiv1.ResourceInstance, error) { 205 fk.lock.Lock() 206 defer fk.lock.Unlock() 207 208 return fk.create(ri, opts...) 209 } 210 211 // Delete - 212 func (fk *fakeUnscoped) Delete(ri *apiv1.ResourceInstance) error { 213 return fk.DeleteCtx(context.Background(), ri) 214 } 215 216 // DeleteCtx - 217 func (fk *fakeUnscoped) DeleteCtx(_ context.Context, ri *apiv1.ResourceInstance) error { 218 if fk == nil { 219 return notFound(ri.Metadata.Scope.Name, ri.Metadata.Scope.Kind) 220 } 221 222 fk.lock.Lock() 223 defer fk.lock.Unlock() 224 225 _, ok := fk.resources[ri.Name] 226 if !ok { 227 return notFound(ri.Name, fk.Kind) 228 } 229 230 for _, sk := range fk.scopedKinds { 231 sk.fks[ri.Name].deleteAll() 232 233 sk.fks[ri.Name] = nil 234 } 235 236 return fk.fakeScoped.delete(ri) 237 } 238 239 // Get - 240 func (fk *fakeUnscoped) Get(ri string) (*apiv1.ResourceInstance, error) { 241 return fk.GetCtx(context.Background(), ri) 242 } 243 244 // GetCtx - 245 func (fk *fakeUnscoped) GetCtx(_ context.Context, name string) (*apiv1.ResourceInstance, error) { 246 fk.lock.Lock() 247 defer fk.lock.Unlock() 248 249 return fk.get(name) 250 } 251 252 // WithScope - 253 func (fk *fakeScoped) WithScope(name string) Scoped { 254 return (*fakeScoped)(nil) 255 } 256 257 func (fk *fakeUnscoped) create(ri *apiv1.ResourceInstance, opts ...CreateOption) (*apiv1.ResourceInstance, error) { 258 created, err := fk.fakeScoped.create(ri, opts...) 259 if err != nil { 260 return created, err 261 } 262 263 for kind, scoped := range fk.scopedKinds { 264 scoped.fks[created.Name] = newFakeKind( 265 apiv1.GroupVersionKind{ 266 GroupKind: apiv1.GroupKind{ 267 Kind: kind, 268 Group: fk.Group, 269 }, 270 APIVersion: fk.APIVersion, 271 }, 272 apiv1.MetadataScope{ 273 ID: created.Metadata.ID, 274 Kind: fk.GroupVersionKind.Kind, 275 Name: created.Name, 276 }, 277 fk.handler, 278 ) 279 } 280 281 return created, nil 282 } 283 284 // WithScope - 285 func (fk *fakeUnscoped) WithScope(name string) Scoped { 286 return (*fakeScoped)(nil) 287 } 288 289 type set map[string]struct{} 290 291 func newSet(entries ...string) set { 292 s := set{} 293 for _, entry := range entries { 294 s[entry] = struct{}{} 295 } 296 return s 297 } 298 299 // Union - 300 func (s set) Union(other set) set { 301 res := set{} 302 for k, v := range s { 303 res[k] = v 304 } 305 306 for k, v := range other { 307 res[k] = v 308 } 309 310 return res 311 } 312 313 // Intersection - 314 func (s set) Intersection(other set) set { 315 res := set{} 316 for k, v := range s { 317 if _, ok := other[k]; ok { 318 res[k] = v 319 } 320 } 321 322 return res 323 } 324 325 type index map[string][]string 326 327 // LookUp - 328 func (idx index) LookUp(key string) set { 329 names, ok := idx[key] 330 if !ok { 331 return set{} 332 } 333 334 return newSet(names...) 335 } 336 337 // Update - 338 func (idx index) Update(old []string, new []string, val string) { 339 toDelete := append([]string{}, old...) 340 toAdd := append([]string{}, new...) 341 342 n := 0 343 outer: 344 for _, old := range toDelete { 345 for j, new := range toAdd { 346 if old == new { 347 toAdd[j] = toAdd[len(toAdd)-1] 348 toAdd = toAdd[:len(toAdd)-1] 349 continue outer 350 } 351 } 352 toDelete[n] = old 353 n++ 354 } 355 356 toDelete = toDelete[:n] 357 358 for _, del := range toDelete { 359 names, ok := idx[del] 360 if !ok { 361 panic(fmt.Sprintf("Trying to delete unknown index %s", del)) 362 } 363 364 for i := range names { 365 if names[i] == val { 366 names[i] = names[len(names)-1] 367 idx[del] = names[:len(names)-1] 368 break 369 } 370 } 371 } 372 373 for _, add := range toAdd { 374 names, ok := idx[add] 375 if !ok { 376 names = []string{} 377 } 378 idx[add] = append(names, val) 379 } 380 } 381 382 type FakeVisitor struct { 383 resources *fakeScoped 384 set 385 } 386 387 // Visit - 388 func (fv *FakeVisitor) Visit(node QueryNode) { 389 switch n := node.(type) { 390 case andNode: 391 for i, child := range n { 392 childFV := &FakeVisitor{fv.resources, set{}} 393 child.Accept(childFV) 394 if i == 0 { 395 fv.set = childFV.set 396 } else { 397 fv.set = fv.set.Intersection(childFV.set) 398 } 399 } 400 case orNode: 401 for _, child := range n { 402 childFV := &FakeVisitor{fv.resources, set{}} 403 child.Accept(childFV) 404 fv.set = fv.set.Union(childFV.set) 405 } 406 case namesNode: 407 fv.set = newSet(n...).Intersection(fv.resources.nameSet()) 408 case tagNode: 409 for _, tag := range n { 410 fv.set = fv.set.Union(fv.resources.tagsIndex.LookUp(tag)) 411 } 412 case *attrNode: 413 for _, val := range n.values { 414 fv.set = fv.set.Union(fv.resources.attributeIndex.LookUp(fmt.Sprintf("%s;%s", n.key, val))) 415 } 416 default: 417 panic(fmt.Sprintf("unknown node type %+v", n)) 418 } 419 } 420 421 func attrsAsIdxs(attrs map[string]string) []string { 422 // update attributes 423 idxs := make([]string, len(attrs)) 424 425 for key, val := range attrs { 426 idxs = append(idxs, fmt.Sprintf("%s;%s", key, val)) 427 } 428 return idxs 429 } 430 431 type fakeScoped struct { 432 apiv1.GroupVersionKind 433 ms apiv1.MetadataScope 434 resources map[string]*apiv1.ResourceInstance 435 tagsIndex index 436 attributeIndex index 437 lock *sync.Mutex 438 handler EventHandler 439 } 440 441 func (fk *fakeScoped) nameSet() set { 442 res := make(set, len(fk.resources)) 443 for k := range fk.resources { 444 res[k] = struct{}{} 445 } 446 447 return res 448 } 449 450 // Create - 451 func (fk *fakeScoped) Create(ri *apiv1.ResourceInstance, opts ...CreateOption) (*apiv1.ResourceInstance, error) { 452 return fk.CreateCtx(context.Background(), ri, opts...) 453 } 454 455 // CreateCtx - 456 func (fk *fakeScoped) CreateCtx(_ context.Context, ri *apiv1.ResourceInstance, opts ...CreateOption) (*apiv1.ResourceInstance, error) { 457 if fk == nil { 458 return nil, notFound(ri.Metadata.Scope.Name, ri.Metadata.Scope.Kind) 459 } 460 461 fk.lock.Lock() 462 defer fk.lock.Unlock() 463 464 return fk.create(ri, opts...) 465 } 466 467 // Delete - 468 func (fk *fakeScoped) Delete(ri *apiv1.ResourceInstance) error { 469 return fk.DeleteCtx(context.Background(), ri) 470 } 471 472 // DeleteCtx - 473 func (fk *fakeScoped) DeleteCtx(_ context.Context, ri *apiv1.ResourceInstance) error { 474 if fk == nil { 475 return notFound(ri.Metadata.Scope.Name, ri.Metadata.Scope.Kind) 476 } 477 478 fk.lock.Lock() 479 defer fk.lock.Unlock() 480 481 return fk.delete(ri) 482 } 483 484 func (fk *fakeScoped) delete(ri *apiv1.ResourceInstance) error { 485 deleted, ok := fk.resources[ri.Name] 486 if !ok { 487 return notFoundInScope(ri.Name, fk.Kind, fk.ms.Name) 488 } 489 490 fk.attributeIndex.Update(attrsAsIdxs(deleted.Attributes), []string{}, deleted.Name) 491 fk.tagsIndex.Update(deleted.Tags, []string{}, deleted.Name) 492 493 fk.handler.Handle(event(apiv1.ResourceEntryDeletedEvent, deleted)) 494 495 return nil 496 } 497 498 // Get - 499 func (fk *fakeScoped) Get(ri string) (*apiv1.ResourceInstance, error) { 500 return fk.GetCtx(context.Background(), ri) 501 } 502 503 // GetCtx - 504 func (fk *fakeScoped) GetCtx(_ context.Context, name string) (*apiv1.ResourceInstance, error) { 505 fk.lock.Lock() 506 defer fk.lock.Unlock() 507 508 return fk.get(name) 509 } 510 511 // List - 512 func (fk *fakeScoped) List(ri ...ListOptions) ([]*apiv1.ResourceInstance, error) { 513 return fk.ListCtx(context.Background(), ri...) 514 } 515 516 // ListCtx - 517 func (fk *fakeScoped) ListCtx(_ context.Context, options ...ListOptions) ([]*apiv1.ResourceInstance, error) { 518 if fk == nil { 519 return nil, fmt.Errorf("unknown scope") 520 } 521 522 opts := listOptions{} 523 524 for _, o := range options { 525 o(&opts) 526 } 527 528 fk.lock.Lock() 529 defer fk.lock.Unlock() 530 531 if opts.query == nil { 532 ris := make([]*apiv1.ResourceInstance, len(fk.resources)) 533 534 i := 0 535 for _, ri := range fk.resources { 536 ris[i] = ri 537 i++ 538 } 539 return ris, nil 540 } 541 542 fv := &FakeVisitor{ 543 resources: fk, 544 set: set{}, 545 } 546 547 opts.query.Accept(fv) 548 549 ris := make([]*apiv1.ResourceInstance, len(fv.set)) 550 551 i := 0 552 for k := range fv.set { 553 if ri, ok := fk.resources[k]; !ok { 554 panic(fmt.Sprintf("Resource %s in index but not in resource list", k)) 555 } else { 556 ris[i] = ri 557 i++ 558 } 559 } 560 561 return ris, nil 562 } 563 564 // Update - 565 func (fk *fakeScoped) Update(ri *apiv1.ResourceInstance, opts ...UpdateOption) (*apiv1.ResourceInstance, error) { 566 return fk.UpdateCtx(context.Background(), ri, opts...) 567 } 568 569 // UpdateCtx - 570 func (fk *fakeScoped) UpdateCtx(_ context.Context, ri *apiv1.ResourceInstance, opts ...UpdateOption) (*apiv1.ResourceInstance, error) { 571 if fk == nil { 572 return nil, notFound(ri.Metadata.Scope.Name, ri.Metadata.Scope.Kind) 573 } 574 575 fk.lock.Lock() 576 defer fk.lock.Unlock() 577 578 return fk.update(ri, opts...) 579 } 580 581 func (fk *fakeScoped) create(ri *apiv1.ResourceInstance, opts ...CreateOption) (*apiv1.ResourceInstance, error) { 582 583 co := createOptions{} 584 585 for _, opt := range opts { 586 opt(&co) 587 } 588 589 if ri.Name == "" { 590 return nil, fmt.Errorf("empty resource name: %v", ri) 591 } 592 593 if ex, ok := fk.resources[ri.Name]; ok { 594 return nil, fmt.Errorf("existing resource: %v", ex) 595 } 596 597 created := &apiv1.ResourceInstance{ 598 ResourceMeta: apiv1.ResourceMeta{ 599 Name: ri.Name, 600 Title: ri.Title, 601 GroupVersionKind: fk.GroupVersionKind, 602 Metadata: apiv1.Metadata{ 603 ID: uuid.New().String(), 604 Audit: apiv1.AuditMetadata{ 605 CreateTimestamp: apiv1.Time(time.Now()), 606 CreateUserID: co.impersonateUserID, 607 ModifyTimestamp: apiv1.Time(time.Now()), 608 ModifyUserID: co.impersonateUserID, 609 }, 610 Scope: fk.ms, 611 ResourceVersion: "0", 612 References: nil, 613 State: "", 614 }, 615 Attributes: ri.Attributes, 616 Tags: ri.Tags, 617 }, 618 Spec: ri.Spec, 619 } 620 621 fk.attributeIndex.Update([]string{}, attrsAsIdxs(created.Attributes), created.Name) 622 fk.tagsIndex.Update([]string{}, created.Tags, created.Name) 623 624 fk.resources[ri.Name] = created 625 626 fk.handler.Handle(event(apiv1.ResourceEntryCreatedEvent, created)) 627 628 return created, nil 629 } 630 631 func (fk *fakeScoped) update(ri *apiv1.ResourceInstance, opts ...UpdateOption) (*apiv1.ResourceInstance, error) { 632 uo := updateOptions{} 633 634 for _, opt := range opts { 635 opt(&uo) 636 } 637 638 if ri.Name == "" { 639 return nil, notFound(ri.Metadata.Scope.Name, ri.Metadata.Scope.Kind) 640 } 641 642 prev, ok := fk.resources[ri.Name] 643 if !ok && uo.mergeFunc == nil { 644 return nil, notFoundInScope(ri.Name, fk.Kind, fk.ms.Name) 645 } 646 647 if uo.mergeFunc != nil { 648 merged, err := uo.mergeFunc(prev, ri) 649 if err != nil { 650 return nil, err 651 } 652 653 ri, err = merged.AsInstance() 654 if err != nil { 655 return nil, err 656 } 657 658 if !ok { 659 return fk.create(ri, CUserID(uo.impersonateUserID)) 660 } 661 } 662 663 updated := &apiv1.ResourceInstance{ 664 ResourceMeta: apiv1.ResourceMeta{ 665 Name: prev.Name, 666 Title: ri.Title, 667 GroupVersionKind: prev.GroupVersionKind, 668 Metadata: apiv1.Metadata{ 669 ID: prev.Metadata.ID, 670 Audit: apiv1.AuditMetadata{ 671 CreateTimestamp: prev.Metadata.Audit.CreateTimestamp, 672 CreateUserID: prev.Metadata.Audit.CreateUserID, 673 ModifyTimestamp: apiv1.Time(time.Now()), 674 ModifyUserID: uo.impersonateUserID, 675 }, 676 Scope: prev.Metadata.Scope, 677 References: nil, 678 State: "", // needed? 679 }, 680 Attributes: ri.Attributes, 681 Tags: ri.Tags, 682 }, 683 Spec: ri.Spec, 684 } 685 686 // update indexes 687 fk.attributeIndex.Update(attrsAsIdxs(prev.Attributes), attrsAsIdxs(updated.Attributes), updated.Name) 688 fk.tagsIndex.Update(prev.Tags, updated.Tags, updated.Name) 689 690 fk.resources[ri.Name] = updated 691 692 fk.handler.Handle(event(apiv1.ResourceEntryUpdatedEvent, updated)) 693 694 return updated, nil 695 } 696 697 func (fk *fakeScoped) get(name string) (*apiv1.ResourceInstance, error) { 698 if fk == nil { 699 return nil, &NotFoundError{[]apiv1.Error{}} 700 } 701 702 ris, ok := fk.resources[name] 703 if !ok { 704 return nil, notFoundInScope(name, fk.Kind, fk.ms.Name) 705 } 706 707 return ris, nil 708 } 709 710 func (fk *fakeScoped) deleteAll() error { 711 fk.lock.Lock() 712 defer fk.lock.Unlock() 713 714 for _, ri := range fk.resources { 715 fk.handler.Handle(event(apiv1.ResourceEntryDeletedEvent, ri)) 716 } 717 718 *fk = fakeScoped{} 719 720 return nil 721 } 722 723 type delegatingEventHandler struct { 724 wrapped EventHandler 725 } 726 727 // Handle - 728 func (dh *delegatingEventHandler) Handle(e *apiv1.Event) { 729 if dh != nil && dh.wrapped != nil { 730 go func() { 731 if dh != nil && dh.wrapped != nil { 732 dh.wrapped.Handle(e) 733 } 734 }() 735 } 736 } 737 738 type fakeClientBase struct { 739 handler *delegatingEventHandler 740 groups map[string]fakeGroup 741 } 742 743 type fakeClient struct { 744 fakeClientBase 745 Unscoped 746 } 747 748 func newFakeKind(gvk apiv1.GroupVersionKind, ms apiv1.MetadataScope, handler EventHandler) *fakeScoped { 749 return &fakeScoped{ 750 gvk, 751 ms, 752 map[string]*apiv1.ResourceInstance{}, 753 index{}, 754 index{}, 755 &sync.Mutex{}, 756 handler, 757 } 758 } 759 760 // NewFakeClient - 761 func NewFakeClient(is ...apiv1.Interface) (*fakeClientBase, error) { 762 handler := &delegatingEventHandler{} 763 groups := map[string]fakeGroup{} 764 765 for _, gvk := range apiv1.GVKSet() { 766 767 group, ok := groups[gvk.Group] 768 if !ok { 769 group = map[string]fakeVersion{} 770 groups[gvk.Group] = group 771 } 772 773 version, ok := group[gvk.APIVersion] 774 if !ok { 775 version = fakeVersion(map[string]*fakeUnscoped{}) 776 group[gvk.APIVersion] = version 777 } 778 779 sk, ok := apiv1.GetScope(gvk.GroupKind) 780 if !ok { 781 panic(fmt.Sprintf("no scope for gvk: %s", gvk)) 782 } 783 784 if sk != "" { 785 scope, ok := version[sk] 786 if !ok { 787 scope = &fakeUnscoped{ 788 *newFakeKind( 789 apiv1.GroupVersionKind{ 790 GroupKind: apiv1.GroupKind{ 791 Group: gvk.Group, 792 Kind: sk, 793 }, 794 APIVersion: gvk.APIVersion, 795 }, 796 apiv1.MetadataScope{}, 797 handler, 798 ), 799 map[string]fakeByScope{}, 800 } 801 version[sk] = scope 802 } 803 804 _, ok = scope.scopedKinds[gvk.Kind] 805 if !ok { 806 scope.scopedKinds[gvk.Kind] = fakeByScope{ 807 GroupVersionKind: gvk, 808 scopeKind: scope.GroupKind, 809 fks: map[string]*fakeScoped{}, 810 } 811 } 812 813 continue 814 } 815 816 if _, ok := version[gvk.Kind]; !ok { 817 version[gvk.Kind] = &fakeUnscoped{ 818 *newFakeKind( 819 gvk, 820 821 apiv1.MetadataScope{}, 822 handler, 823 ), 824 map[string]fakeByScope{}, 825 } 826 } 827 } 828 829 client := &fakeClientBase{handler, groups} 830 831 // pass through and create unscoped resources 832 for _, i := range is { 833 ri, err := i.AsInstance() 834 if err != nil { 835 return nil, err 836 } 837 838 sk, ok := apiv1.GetScope(ri.GroupKind) 839 if !ok { 840 return nil, fmt.Errorf("no scope kind or unknown kind for ri: %v", ri) 841 } 842 if sk != "" { 843 continue 844 } 845 846 c, err := client.ForKind(ri.GroupVersionKind) 847 if err != nil { 848 return nil, err 849 } 850 851 _, err = c.Create(ri) 852 if err != nil { 853 return nil, err 854 } 855 } 856 857 // pass through and create scoped resources 858 for _, i := range is { 859 ri, err := i.AsInstance() 860 if err != nil { 861 return nil, err 862 } 863 864 sk, ok := apiv1.GetScope(ri.GroupKind) 865 if !ok { 866 return nil, fmt.Errorf("no scope kind or unknown kind for ri: %v", ri) 867 } 868 if sk == "" { 869 continue 870 } 871 872 noScope, err := client.ForKind(ri.GroupVersionKind) 873 if err != nil { 874 return nil, err 875 } 876 877 c := noScope.WithScope(ri.Metadata.Scope.Name) 878 879 _, err = c.Create(ri) 880 if err != nil { 881 return nil, err 882 } 883 } 884 885 return client, nil 886 } 887 888 // ForKind - 889 func (fcb fakeClientBase) ForKind(gvk apiv1.GroupVersionKind) (Unscoped, error) { 890 sk, ok := apiv1.GetScope(gvk.GroupKind) 891 if !ok { 892 panic(fmt.Sprintf("no scope for gvk: %s", gvk)) 893 } 894 895 if sk == "" { 896 return fcb.groups[gvk.Group][gvk.APIVersion][gvk.Kind], nil 897 } 898 899 return fcb.groups[gvk.Group][gvk.APIVersion][sk].scopedKinds[gvk.Kind], nil 900 } 901 902 // SetHandler - 903 func (fcb fakeClientBase) SetHandler(ev EventHandler) { 904 fcb.handler.wrapped = ev 905 }