From 81789849a1a97dadee36ed1a38ec8c826c110821 Mon Sep 17 00:00:00 2001 From: Binbin Li Date: Wed, 3 Apr 2024 07:40:50 +0000 Subject: [PATCH 1/3] feat: add Stores interface to wrap operations on namespaced stores --- pkg/controllers/resource_map.go | 4 + pkg/controllers/store_controller.go | 16 +-- pkg/controllers/store_controller_test.go | 31 ++--- pkg/customresources/referrerstores/api.go | 35 ++++++ pkg/customresources/referrerstores/stores.go | 82 +++++++++++++ .../referrerstores/stores_test.go | 115 ++++++++++++++++++ pkg/manager/manager.go | 11 +- 7 files changed, 257 insertions(+), 37 deletions(-) create mode 100644 pkg/customresources/referrerstores/api.go create mode 100644 pkg/customresources/referrerstores/stores.go create mode 100644 pkg/customresources/referrerstores/stores_test.go diff --git a/pkg/controllers/resource_map.go b/pkg/controllers/resource_map.go index 6a496e6a6..f5b6f9110 100644 --- a/pkg/controllers/resource_map.go +++ b/pkg/controllers/resource_map.go @@ -16,6 +16,7 @@ package controllers import ( "github.com/deislabs/ratify/pkg/customresources/policies" "github.com/deislabs/ratify/pkg/customresources/verifiers" + rs "github.com/deislabs/ratify/pkg/customresources/referrerstores" ) var ( @@ -24,4 +25,7 @@ var ( // ActivePolicy is the active policy generated from CRD. There would be exactly // one active policy belonging to a namespace at any given time. ActivePolicies = policies.NewActivePolicies() + + // a map to track active stores + StoreMap = rs.NewActiveStores() ) diff --git a/pkg/controllers/store_controller.go b/pkg/controllers/store_controller.go index b4421a6ef..5e07ef505 100644 --- a/pkg/controllers/store_controller.go +++ b/pkg/controllers/store_controller.go @@ -27,7 +27,7 @@ import ( configv1beta1 "github.com/deislabs/ratify/api/v1beta1" "github.com/deislabs/ratify/config" - "github.com/deislabs/ratify/pkg/referrerstore" + "github.com/deislabs/ratify/internal/constants" rc "github.com/deislabs/ratify/pkg/referrerstore/config" sf "github.com/deislabs/ratify/pkg/referrerstore/factory" "github.com/deislabs/ratify/pkg/referrerstore/types" @@ -40,11 +40,6 @@ type StoreReconciler struct { Scheme *runtime.Scheme } -var ( - // a map to track active stores - StoreMap = map[string]referrerstore.ReferrerStore{} -) - //+kubebuilder:rbac:groups=config.ratify.deislabs.io,resources=stores,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=config.ratify.deislabs.io,resources=stores/status,verbs=get;update;patch //+kubebuilder:rbac:groups=config.ratify.deislabs.io,resources=stores/finalizers,verbs=update @@ -64,7 +59,7 @@ func (r *StoreReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl if err := r.Get(ctx, req.NamespacedName, &store); err != nil { if apierrors.IsNotFound(err) { storeLogger.Infof("deletion detected, removing store %v", req.Name) - storeRemove(resource) + StoreMap.DeleteStore(constants.EmptyNamespace, resource) } else { storeLogger.Error(err, "unable to fetch store") } @@ -115,17 +110,12 @@ func storeAddOrReplace(spec configv1beta1.StoreSpec, fullname string) error { return fmt.Errorf("store factory failed to create store from store config, err: %w", err) } - StoreMap[fullname] = storeReference + StoreMap.AddStore(constants.EmptyNamespace, fullname, storeReference) logrus.Infof("store '%v' added to store map", storeReference.Name()) return nil } -// Remove store from map -func storeRemove(resourceName string) { - delete(StoreMap, resourceName) -} - // Returns a store reference from spec func specToStoreConfig(storeSpec configv1beta1.StoreSpec) (rc.StorePluginConfig, error) { storeConfig := rc.StorePluginConfig{} diff --git a/pkg/controllers/store_controller_test.go b/pkg/controllers/store_controller_test.go index 8838b9c6d..1897d5711 100644 --- a/pkg/controllers/store_controller_test.go +++ b/pkg/controllers/store_controller_test.go @@ -22,7 +22,8 @@ import ( "testing" configv1beta1 "github.com/deislabs/ratify/api/v1beta1" - "github.com/deislabs/ratify/pkg/referrerstore" + "github.com/deislabs/ratify/internal/constants" + rs "github.com/deislabs/ratify/pkg/customresources/referrerstores" "github.com/deislabs/ratify/pkg/utils" "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/runtime" @@ -47,15 +48,15 @@ func TestStoreAdd_EmptyParameter(t *testing.T) { if err := storeAddOrReplace(testStoreSpec, "oras"); err != nil { t.Fatalf("storeAddOrReplace() expected no error, actual %v", err) } - if len(StoreMap) != 1 { - t.Fatalf("Store map expected size 1, actual %v", len(StoreMap)) + if StoreMap.GetStoreCount() != 1 { + t.Fatalf("Store map expected size 1, actual %v", StoreMap.GetStoreCount()) } } func TestStoreAdd_WithParameters(t *testing.T) { resetStoreMap() - if len(StoreMap) != 0 { - t.Fatalf("Store map expected size 0, actual %v", len(StoreMap)) + if StoreMap.GetStoreCount() != 0 { + t.Fatalf("Store map expected size 0, actual %v", StoreMap.GetStoreCount()) } dirPath, err := utils.CreatePlugin(sampleName) if err != nil { @@ -68,8 +69,8 @@ func TestStoreAdd_WithParameters(t *testing.T) { if err := storeAddOrReplace(testStoreSpec, "testObject"); err != nil { t.Fatalf("storeAddOrReplace() expected no error, actual %v", err) } - if len(StoreMap) != 1 { - t.Fatalf("Store map expected size 1, actual %v", len(StoreMap)) + if StoreMap.GetStoreCount() != 1 { + t.Fatalf("Store map expected size 1, actual %v", StoreMap.GetStoreCount()) } } @@ -137,8 +138,8 @@ func TestStore_UpdateAndDelete(t *testing.T) { if err := storeAddOrReplace(testStoreSpec, sampleName); err != nil { t.Fatalf("storeAddOrReplace() expected no error, actual %v", err) } - if len(StoreMap) != 1 { - t.Fatalf("Store map expected size 1, actual %v", len(StoreMap)) + if StoreMap.GetStoreCount() != 1 { + t.Fatalf("Store map expected size 1, actual %v", StoreMap.GetStoreCount()) } // modify the Store @@ -152,19 +153,19 @@ func TestStore_UpdateAndDelete(t *testing.T) { } // validate no Store has been added - if len(StoreMap) != 1 { - t.Fatalf("Store map should be 1 after replacement, actual %v", len(StoreMap)) + if StoreMap.GetStoreCount() != 1 { + t.Fatalf("Store map should be 1 after replacement, actual %v", StoreMap.GetStoreCount()) } - storeRemove(sampleName) + StoreMap.DeleteStore(constants.EmptyNamespace, sampleName) - if len(StoreMap) != 0 { - t.Fatalf("Store map should be 0 after deletion, actual %v", len(StoreMap)) + if StoreMap.GetStoreCount() != 0 { + t.Fatalf("Store map should be 0 after deletion, actual %v", StoreMap.GetStoreCount()) } } func resetStoreMap() { - StoreMap = map[string]referrerstore.ReferrerStore{} + StoreMap = rs.NewActiveStores() } func getOrasStoreSpec(pluginName, pluginPath string) configv1beta1.StoreSpec { diff --git a/pkg/customresources/referrerstores/api.go b/pkg/customresources/referrerstores/api.go new file mode 100644 index 000000000..af32f7119 --- /dev/null +++ b/pkg/customresources/referrerstores/api.go @@ -0,0 +1,35 @@ +/* +Copyright The Ratify Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package referrerstores + +import ( + "github.com/deislabs/ratify/pkg/referrerstore" +) + +type ReferrerStores interface { + // Stores returns the list of referrer stores for the given scope. + // For K8s users, scope can be either the namespace or empty string("") for cluster-wide scope. + // For CLI users, scope is always empty string("") as there is no namespace specified. + GetStores(scope string) []referrerstore.ReferrerStore + + AddStore(scope, storeName string, store referrerstore.ReferrerStore) + + DeleteStore(scope, storeName string) + + IsEmpty() bool + + GetStoreCount() int +} diff --git a/pkg/customresources/referrerstores/stores.go b/pkg/customresources/referrerstores/stores.go new file mode 100644 index 000000000..d5acd0b92 --- /dev/null +++ b/pkg/customresources/referrerstores/stores.go @@ -0,0 +1,82 @@ +/* +Copyright The Ratify Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package referrerstores + +import ( + "fmt" + + "github.com/deislabs/ratify/pkg/referrerstore" +) + +type ActiveStores struct { + NamespacedStores map[string]map[string]referrerstore.ReferrerStore +} + +func NewActiveStores() ActiveStores { + return ActiveStores{ + NamespacedStores: make(map[string]map[string]referrerstore.ReferrerStore), + } +} + +func NewActiveStoresWithoutNames(stores []referrerstore.ReferrerStore) ActiveStores { + activeStores := make(map[string]map[string]referrerstore.ReferrerStore) + activeStores[""] = make(map[string]referrerstore.ReferrerStore) + + for index, store := range stores { + activeStores[""][fmt.Sprintf("%d", index)] = store + } + + return ActiveStores{ + NamespacedStores: activeStores, + } +} + +// GetStores implements the Stores interface. +// It returns all the stores in the ActiveStores for the given scope. If no stores are found for the given scope, it returns cluster-wide stores. +func (s *ActiveStores) GetStores(scope string) []referrerstore.ReferrerStore { + stores := []referrerstore.ReferrerStore{} + for _, namespacedStores := range s.NamespacedStores { + for _, store := range namespacedStores { + stores = append(stores, store) + } + } + return stores +} + +func (s *ActiveStores) AddStore(scope, storeName string, store referrerstore.ReferrerStore) { + if _, ok := s.NamespacedStores[scope]; !ok { + s.NamespacedStores[scope] = make(map[string]referrerstore.ReferrerStore) + } + s.NamespacedStores[scope][storeName] = store +} + +func (s *ActiveStores) DeleteStore(scope, storeName string) { + if stores, ok := s.NamespacedStores[scope]; ok { + delete(stores, storeName) + } +} + +func (s *ActiveStores) IsEmpty() bool { + return s.GetStoreCount() == 0 +} + +func (s *ActiveStores) GetStoreCount() int { + count := 0 + for _, stores := range s.NamespacedStores { + count += len(stores) + } + return count +} diff --git a/pkg/customresources/referrerstores/stores_test.go b/pkg/customresources/referrerstores/stores_test.go new file mode 100644 index 000000000..fccc5b380 --- /dev/null +++ b/pkg/customresources/referrerstores/stores_test.go @@ -0,0 +1,115 @@ +/* +Copyright The Ratify Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package referrerstores + +import ( + "context" + "testing" + + "github.com/deislabs/ratify/internal/constants" + "github.com/deislabs/ratify/pkg/common" + "github.com/deislabs/ratify/pkg/ocispecs" + rs "github.com/deislabs/ratify/pkg/referrerstore" + "github.com/deislabs/ratify/pkg/referrerstore/config" + "github.com/opencontainers/go-digest" +) + +type mockStore struct { + name string +} + +func (s mockStore) Name() string { + return s.name +} + +func (s mockStore) ListReferrers(_ context.Context, _ common.Reference, _ []string, _ string, _ *ocispecs.SubjectDescriptor) (rs.ListReferrersResult, error) { + return rs.ListReferrersResult{}, nil +} + +func (s mockStore) GetBlobContent(_ context.Context, _ common.Reference, _ digest.Digest) ([]byte, error) { + return nil, nil +} + +func (s mockStore) GetReferenceManifest(_ context.Context, _ common.Reference, _ ocispecs.ReferenceDescriptor) (ocispecs.ReferenceManifest, error) { + return ocispecs.ReferenceManifest{}, nil +} + +func (s mockStore) GetConfig() *config.StoreConfig { + return nil +} + +func (s mockStore) GetSubjectDescriptor(_ context.Context, _ common.Reference) (*ocispecs.SubjectDescriptor, error) { + return nil, nil +} + +const ( + namespace1 = constants.EmptyNamespace + namespace2 = "namespace2" + name1 = "name1" + name2 = "name2" +) + +var ( + store1 = mockStore{name: name1} + store2 = mockStore{name: name2} +) + +func TestStoresOperations(t *testing.T) { + stores := NewActiveStores() + stores.AddStore(namespace1, store1.Name(), store1) + stores.AddStore(namespace1, store2.Name(), store2) + stores.AddStore(namespace2, store1.Name(), store1) + stores.AddStore(namespace2, store2.Name(), store2) + + if stores.GetStoreCount() != 4 { + t.Fatalf("Expected 4 namespaces, got %d", len(stores.NamespacedStores)) + } + + stores.DeleteStore(namespace2, store1.Name()) + if len(stores.NamespacedStores[namespace2]) != 1 { + t.Fatalf("Expected 1 store in namespace %s, got %d", namespace2, len(stores.NamespacedStores[namespace2])) + } + + stores.DeleteStore(namespace2, store2.Name()) + if len(stores.NamespacedStores[namespace2]) != 0 { + t.Fatalf("Expected 0 stores in namespace %s, got %d", namespace2, len(stores.NamespacedStores[namespace2])) + } + + if len(stores.GetStores(namespace2)) != 2 { + t.Fatalf("Expected 2 stores in namespace %s, got %d", namespace2, len(stores.NamespacedStores[namespace2])) + } + + stores.DeleteStore(namespace1, store1.Name()) + if len(stores.NamespacedStores[namespace1]) != 1 { + t.Fatalf("Expected 1 store in namespace %s, got %d", namespace1, len(stores.NamespacedStores[namespace1])) + } + + stores.DeleteStore(namespace1, store2.Name()) + if len(stores.NamespacedStores[namespace1]) != 0 { + t.Fatalf("Expected 0 stores in namespace %s, got %d", namespace1, len(stores.NamespacedStores[namespace1])) + } + + if !stores.IsEmpty() { + t.Fatalf("Expected stores to be empty") + } +} + +func TestNewActiveStoresWithoutNames(t *testing.T) { + stores := NewActiveStoresWithoutNames([]rs.ReferrerStore{store1, store2}) + if len(stores.NamespacedStores[""]) != 2 { + t.Fatalf("Expected 2 stores in namespace %s, got %d", namespace1, len(stores.NamespacedStores[""])) + } +} diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index bb9dfebec..2527f43ce 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -51,7 +51,6 @@ import ( ctxUtils "github.com/deislabs/ratify/internal/context" "github.com/deislabs/ratify/pkg/controllers" ef "github.com/deislabs/ratify/pkg/executor/core" - "github.com/deislabs/ratify/pkg/referrerstore" //+kubebuilder:scaffold:imports ) @@ -84,17 +83,11 @@ func StartServer(httpServerAddress, configFilePath, certDirectory, caCertFile st // initialize server server, err := httpserver.NewServer(context.Background(), httpServerAddress, func(ctx context.Context) *ef.Executor { - var activeStores []referrerstore.ReferrerStore namespace := ctxUtils.GetNamespace(ctx) + activeVerifiers := controllers.VerifierMap.GetVerifiers(namespace) activePolicyEnforcer := controllers.ActivePolicies.GetPolicy(namespace) - - // check if there are active stores from crd controller - if len(controllers.StoreMap) > 0 { - for _, value := range controllers.StoreMap { - activeStores = append(activeStores, value) - } - } + activeStores := controllers.StoreMap.GetStores(namespace) // return executor with latest configuration executor := ef.Executor{ From 91d4d21692a35318d7276dc502e4c6e4f444c406 Mon Sep 17 00:00:00 2001 From: Binbin Li Date: Tue, 2 Apr 2024 09:50:48 +0000 Subject: [PATCH 2/3] feat: add Policies interface to wrap operations on namespaced policies --- pkg/controllers/resource_map.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/controllers/resource_map.go b/pkg/controllers/resource_map.go index f5b6f9110..5352a1462 100644 --- a/pkg/controllers/resource_map.go +++ b/pkg/controllers/resource_map.go @@ -15,8 +15,8 @@ package controllers import ( "github.com/deislabs/ratify/pkg/customresources/policies" - "github.com/deislabs/ratify/pkg/customresources/verifiers" rs "github.com/deislabs/ratify/pkg/customresources/referrerstores" + "github.com/deislabs/ratify/pkg/customresources/verifiers" ) var ( From 5e91637030d08e233251017d1e243b8004928e61 Mon Sep 17 00:00:00 2001 From: Binbin Li Date: Wed, 3 Apr 2024 07:40:50 +0000 Subject: [PATCH 3/3] feat: add Stores interface to wrap operations on namespaced stores --- pkg/controllers/store_controller.go | 2 + pkg/customresources/referrerstores/api.go | 9 ++- pkg/customresources/referrerstores/stores.go | 63 ++++++++++--------- .../referrerstores/stores_test.go | 27 +++----- 4 files changed, 51 insertions(+), 50 deletions(-) diff --git a/pkg/controllers/store_controller.go b/pkg/controllers/store_controller.go index 5e07ef505..5371e7c4c 100644 --- a/pkg/controllers/store_controller.go +++ b/pkg/controllers/store_controller.go @@ -59,6 +59,7 @@ func (r *StoreReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl if err := r.Get(ctx, req.NamespacedName, &store); err != nil { if apierrors.IsNotFound(err) { storeLogger.Infof("deletion detected, removing store %v", req.Name) + // TODO: pass the actual namespace once multi-tenancy is supported. StoreMap.DeleteStore(constants.EmptyNamespace, resource) } else { storeLogger.Error(err, "unable to fetch store") @@ -110,6 +111,7 @@ func storeAddOrReplace(spec configv1beta1.StoreSpec, fullname string) error { return fmt.Errorf("store factory failed to create store from store config, err: %w", err) } + // TODO: pass the actual namespace once multi-tenancy is supported. StoreMap.AddStore(constants.EmptyNamespace, fullname, storeReference) logrus.Infof("store '%v' added to store map", storeReference.Name()) diff --git a/pkg/customresources/referrerstores/api.go b/pkg/customresources/referrerstores/api.go index af32f7119..6b435c7e9 100644 --- a/pkg/customresources/referrerstores/api.go +++ b/pkg/customresources/referrerstores/api.go @@ -19,17 +19,20 @@ import ( "github.com/deislabs/ratify/pkg/referrerstore" ) -type ReferrerStores interface { +// ReferrerStoreManager is an interface that defines the methods for managing referrer stores across different scopes. +type ReferrerStoreManager interface { // Stores returns the list of referrer stores for the given scope. - // For K8s users, scope can be either the namespace or empty string("") for cluster-wide scope. - // For CLI users, scope is always empty string("") as there is no namespace specified. GetStores(scope string) []referrerstore.ReferrerStore + // AddStore adds the given store under the given scope. AddStore(scope, storeName string, store referrerstore.ReferrerStore) + // DeleteStore deletes the policy from the given scope. DeleteStore(scope, storeName string) + // IsEmpty returns true if there are no stores. IsEmpty() bool + // GetStoreCount returns the number of stores in all scopes. GetStoreCount() int } diff --git a/pkg/customresources/referrerstores/stores.go b/pkg/customresources/referrerstores/stores.go index d5acd0b92..f60f83b0e 100644 --- a/pkg/customresources/referrerstores/stores.go +++ b/pkg/customresources/referrerstores/stores.go @@ -16,66 +16,73 @@ limitations under the License. package referrerstores import ( - "fmt" - "github.com/deislabs/ratify/pkg/referrerstore" ) +// ActiveStores implements the ReferrerStoreManager interface. type ActiveStores struct { - NamespacedStores map[string]map[string]referrerstore.ReferrerStore -} - -func NewActiveStores() ActiveStores { - return ActiveStores{ - NamespacedStores: make(map[string]map[string]referrerstore.ReferrerStore), - } + // TODO: Implement concurrent safety using sync.Map + // The structure of the map is as follows: + // The first level maps from scope to stores + // The second level maps from store name to store + // Example: + // { + // "namespace1": { + // "store1": store1, + // "store2": store2 + // } + // } + // Note: Scope is utilized for organizing and isolating stores. In a Kubernetes (K8s) environment, the scope can be either a namespace or an empty string ("") for cluster-wide stores. + ScopedStores map[string]map[string]referrerstore.ReferrerStore } -func NewActiveStoresWithoutNames(stores []referrerstore.ReferrerStore) ActiveStores { - activeStores := make(map[string]map[string]referrerstore.ReferrerStore) - activeStores[""] = make(map[string]referrerstore.ReferrerStore) - - for index, store := range stores { - activeStores[""][fmt.Sprintf("%d", index)] = store - } - - return ActiveStores{ - NamespacedStores: activeStores, +func NewActiveStores() ReferrerStoreManager { + return &ActiveStores{ + ScopedStores: make(map[string]map[string]referrerstore.ReferrerStore), } } -// GetStores implements the Stores interface. +// GetStores fulfills the ReferrerStoreManager interface. // It returns all the stores in the ActiveStores for the given scope. If no stores are found for the given scope, it returns cluster-wide stores. -func (s *ActiveStores) GetStores(scope string) []referrerstore.ReferrerStore { +// TODO: Current implementation fetches stores for all namespaces including cluster-wide ones. Will support actual namespace based stores in future. +func (s *ActiveStores) GetStores(_ string) []referrerstore.ReferrerStore { stores := []referrerstore.ReferrerStore{} - for _, namespacedStores := range s.NamespacedStores { - for _, store := range namespacedStores { + for _, scopedStores := range s.ScopedStores { + for _, store := range scopedStores { stores = append(stores, store) } } return stores } +// AddStore fulfills the ReferrerStoreManager interface. +// It adds the given store under the given scope. func (s *ActiveStores) AddStore(scope, storeName string, store referrerstore.ReferrerStore) { - if _, ok := s.NamespacedStores[scope]; !ok { - s.NamespacedStores[scope] = make(map[string]referrerstore.ReferrerStore) + if _, ok := s.ScopedStores[scope]; !ok { + s.ScopedStores[scope] = make(map[string]referrerstore.ReferrerStore) } - s.NamespacedStores[scope][storeName] = store + s.ScopedStores[scope][storeName] = store } +// DeleteStore fulfills the ReferrerStoreManager interface. +// It deletes the store with the given name under the given scope. func (s *ActiveStores) DeleteStore(scope, storeName string) { - if stores, ok := s.NamespacedStores[scope]; ok { + if stores, ok := s.ScopedStores[scope]; ok { delete(stores, storeName) } } +// IsEmpty fulfills the ReferrerStoreManager interface. +// It returns true if there are no stores in the ActiveStores. func (s *ActiveStores) IsEmpty() bool { return s.GetStoreCount() == 0 } +// GetStore fulfills the ReferrerStoreManager interface. +// GetStoreCount returns the total number of stores in the ActiveStores. func (s *ActiveStores) GetStoreCount() int { count := 0 - for _, stores := range s.NamespacedStores { + for _, stores := range s.ScopedStores { count += len(stores) } return count diff --git a/pkg/customresources/referrerstores/stores_test.go b/pkg/customresources/referrerstores/stores_test.go index fccc5b380..46a375801 100644 --- a/pkg/customresources/referrerstores/stores_test.go +++ b/pkg/customresources/referrerstores/stores_test.go @@ -75,41 +75,30 @@ func TestStoresOperations(t *testing.T) { stores.AddStore(namespace2, store2.Name(), store2) if stores.GetStoreCount() != 4 { - t.Fatalf("Expected 4 namespaces, got %d", len(stores.NamespacedStores)) + t.Fatalf("Expected 4 namespaces, got %d", stores.GetStoreCount()) } stores.DeleteStore(namespace2, store1.Name()) - if len(stores.NamespacedStores[namespace2]) != 1 { - t.Fatalf("Expected 1 store in namespace %s, got %d", namespace2, len(stores.NamespacedStores[namespace2])) + if len(stores.GetStores(namespace2)) != 3 { + t.Fatalf("Expected 3 store in namespace %s, got %d", namespace2, len(stores.GetStores(namespace2))) } stores.DeleteStore(namespace2, store2.Name()) - if len(stores.NamespacedStores[namespace2]) != 0 { - t.Fatalf("Expected 0 stores in namespace %s, got %d", namespace2, len(stores.NamespacedStores[namespace2])) - } - if len(stores.GetStores(namespace2)) != 2 { - t.Fatalf("Expected 2 stores in namespace %s, got %d", namespace2, len(stores.NamespacedStores[namespace2])) + t.Fatalf("Expected 2 stores in namespace %s, got %d", namespace2, len(stores.GetStores(namespace2))) } stores.DeleteStore(namespace1, store1.Name()) - if len(stores.NamespacedStores[namespace1]) != 1 { - t.Fatalf("Expected 1 store in namespace %s, got %d", namespace1, len(stores.NamespacedStores[namespace1])) + if len(stores.GetStores(namespace1)) != 1 { + t.Fatalf("Expected 1 store in namespace %s, got %d", namespace1, len(stores.GetStores(namespace1))) } stores.DeleteStore(namespace1, store2.Name()) - if len(stores.NamespacedStores[namespace1]) != 0 { - t.Fatalf("Expected 0 stores in namespace %s, got %d", namespace1, len(stores.NamespacedStores[namespace1])) + if len(stores.GetStores(namespace1)) != 0 { + t.Fatalf("Expected 0 stores in namespace %s, got %d", namespace1, len(stores.GetStores(namespace1))) } if !stores.IsEmpty() { t.Fatalf("Expected stores to be empty") } } - -func TestNewActiveStoresWithoutNames(t *testing.T) { - stores := NewActiveStoresWithoutNames([]rs.ReferrerStore{store1, store2}) - if len(stores.NamespacedStores[""]) != 2 { - t.Fatalf("Expected 2 stores in namespace %s, got %d", namespace1, len(stores.NamespacedStores[""])) - } -}