From b0756a1f750a32b03b26c73cf146013938e71610 Mon Sep 17 00:00:00 2001 From: erthalion <9erthalion6@gmail.com> Date: Fri, 21 Sep 2018 11:36:01 +0200 Subject: [PATCH] Add a simple tests for CreateSecret --- pkg/cluster/cluster.go | 10 ++- pkg/controller/controller.go | 18 ++++ pkg/controller/postgresql.go | 28 ++++--- pkg/controller/postgresql_test.go | 131 ++++++++++++++++++++++++++++-- pkg/controller/util.go | 12 +-- 5 files changed, 174 insertions(+), 25 deletions(-) diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index b352e8e93..6799c5740 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -127,6 +127,14 @@ func New(cfg Config, kubeClient k8sutil.KubernetesClient, pgSpec acidv1.Postgres return cluster } +func (c *Cluster) SetTeamsAPIClient(client teams.Interface) { + c.teamsAPIClient = client +} + +func (c *Cluster) SetOAuthTokenGetter(getter OAuthTokenGetter) { + c.oauthTokenGetter = getter +} + func (c *Cluster) clusterName() spec.NamespacedName { return util.NameFromMeta(c.ObjectMeta) } @@ -222,7 +230,7 @@ func (c *Cluster) PlanForSecrets() (plan Plan) { if k8sutil.ResourceNotFound(err) { msg = "Generate plan to create new secret %q" - c.logger.Debugf(msg, util.NameFromMeta(secret.ObjectMeta)) + c.logger.Debugf(msg, util.NameFromMeta(secretSpec.ObjectMeta)) plan = append(plan, NewCreateSecret(secretUsername, secretSpec, c)) continue } diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go index f99d836b8..3812cf626 100644 --- a/pkg/controller/controller.go +++ b/pkg/controller/controller.go @@ -13,6 +13,7 @@ import ( "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/tools/cache" + acidv1 "github.com/zalando-incubator/postgres-operator/pkg/apis/acid.zalan.do/v1" "github.com/zalando-incubator/postgres-operator/pkg/apiserver" "github.com/zalando-incubator/postgres-operator/pkg/cluster" "github.com/zalando-incubator/postgres-operator/pkg/spec" @@ -25,6 +26,20 @@ import ( acidv1informer "github.com/zalando-incubator/postgres-operator/pkg/generated/informers/externalversions/acid.zalan.do/v1" ) +type ClusterFactory interface { + addCluster(ctrl *Controller, + lg *logrus.Entry, + clusterName spec.NamespacedName, + pgSpec *acidv1.Postgresql, + ) *cluster.Cluster +} + +type ClusterGenerator struct { + ClusterFactory + + KubeClient k8sutil.KubernetesClient +} + // Controller represents operator controller type Controller struct { config spec.ControllerConfig @@ -59,6 +74,8 @@ type Controller struct { PodServiceAccount *v1.ServiceAccount PodServiceAccountRoleBinding *rbacv1beta1.RoleBinding namespacesWithDefinedRBAC sync.Map + + clusterFactory ClusterFactory } // NewController creates a new controller @@ -77,6 +94,7 @@ func NewController(controllerConfig *spec.ControllerConfig) *Controller { teamClusters: make(map[string][]spec.NamespacedName), stopCh: make(chan struct{}), podCh: make(chan cluster.PodEvent), + clusterFactory: &ClusterGenerator{}, } logger.Hooks.Add(c) diff --git a/pkg/controller/postgresql.go b/pkg/controller/postgresql.go index 71fbff0b1..14e9c5c7c 100644 --- a/pkg/controller/postgresql.go +++ b/pkg/controller/postgresql.go @@ -136,7 +136,7 @@ func (c *Controller) acquireInitialListOfClusters() error { continue } clusterName = util.NameFromMeta(pg.ObjectMeta) - c.addCluster(c.logger, clusterName, &pg) + c.clusterFactory.addCluster(c, c.logger, clusterName, &pg) c.logger.Debugf("added new cluster: %q", clusterName) } // initiate initial sync of all clusters. @@ -144,18 +144,20 @@ func (c *Controller) acquireInitialListOfClusters() error { return nil } -func (c *Controller) addCluster(lg *logrus.Entry, clusterName spec.NamespacedName, pgSpec *acidv1.Postgresql) *cluster.Cluster { - cl := cluster.New(c.makeClusterConfig(), c.KubeClient, *pgSpec, lg) - cl.Run(c.stopCh) +func (c *ClusterGenerator) addCluster(ctrl *Controller, + lg *logrus.Entry, clusterName spec.NamespacedName, pgSpec *acidv1.Postgresql) *cluster.Cluster { + + cl := cluster.New(ctrl.makeClusterConfig(), ctrl.KubeClient, *pgSpec, lg) + cl.Run(ctrl.stopCh) teamName := strings.ToLower(cl.Spec.TeamID) - defer c.clustersMu.Unlock() - c.clustersMu.Lock() + defer ctrl.clustersMu.Unlock() + ctrl.clustersMu.Lock() - c.teamClusters[teamName] = append(c.teamClusters[teamName], clusterName) - c.clusters[clusterName] = cl - c.clusterLogs[clusterName] = ringlog.New(c.opConfig.RingLogLines) - c.clusterHistory[clusterName] = ringlog.New(c.opConfig.ClusterHistoryEntries) + ctrl.teamClusters[teamName] = append(ctrl.teamClusters[teamName], clusterName) + ctrl.clusters[clusterName] = cl + ctrl.clusterLogs[clusterName] = ringlog.New(ctrl.opConfig.RingLogLines) + ctrl.clusterHistory[clusterName] = ringlog.New(ctrl.opConfig.ClusterHistoryEntries) return cl } @@ -182,7 +184,7 @@ func (c *Controller) generatePlan(event ClusterEvent) cluster.Plan { case EventAdd: log.Infof("Creation of the cluster started") - newCluster := c.addCluster(log, clusterName, event.NewSpec) + newCluster := c.clusterFactory.addCluster(c, log, clusterName, event.NewSpec) c.curWorkerCluster.Store(event.WorkerID, newCluster) return newCluster.PlanForCreate() @@ -272,7 +274,7 @@ func (c *Controller) processEvent(event ClusterEvent) { lg.Infof("creation of the cluster started") - cl = c.addCluster(lg, clusterName, event.NewSpec) + cl = c.clusterFactory.addCluster(c, lg, clusterName, event.NewSpec) c.curWorkerCluster.Store(event.WorkerID, cl) @@ -341,7 +343,7 @@ func (c *Controller) processEvent(event ClusterEvent) { // no race condition because a cluster is always processed by single worker if !clusterFound { - cl = c.addCluster(lg, clusterName, event.NewSpec) + cl = c.clusterFactory.addCluster(c, lg, clusterName, event.NewSpec) } c.curWorkerCluster.Store(event.WorkerID, cl) diff --git a/pkg/controller/postgresql_test.go b/pkg/controller/postgresql_test.go index c3a74be74..f23d6a8de 100644 --- a/pkg/controller/postgresql_test.go +++ b/pkg/controller/postgresql_test.go @@ -1,20 +1,101 @@ package controller import ( - acidv1 "github.com/zalando-incubator/postgres-operator/pkg/apis/acid.zalan.do/v1" - "github.com/zalando-incubator/postgres-operator/pkg/spec" "reflect" "testing" + + "github.com/Sirupsen/logrus" + "k8s.io/api/core/v1" + + acidv1 "github.com/zalando-incubator/postgres-operator/pkg/apis/acid.zalan.do/v1" + "github.com/zalando-incubator/postgres-operator/pkg/cluster" + "github.com/zalando-incubator/postgres-operator/pkg/spec" + "github.com/zalando-incubator/postgres-operator/pkg/util/k8sutil" + "github.com/zalando-incubator/postgres-operator/pkg/util/teams" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1core "k8s.io/client-go/kubernetes/typed/core/v1" ) var ( - True = true - False = false + True = true + False = false + logger = logrus.New().WithField("test", "cluster") ) +const ( + superUserName = "postgres" + replicationUserName = "standby" +) + +var mockTeamsAPI mockTeamsAPIClient + +type mockOAuthTokenGetter struct { + cluster.OAuthTokenGetter +} + +type mockClusterGenerator struct { + ClusterGenerator +} + +type NotFoundError struct{} + +func (e *NotFoundError) Error() string { + return "error" +} + +func (e *NotFoundError) Status() metav1.Status { + return metav1.Status{ + Reason: metav1.StatusReasonNotFound, + } +} + +func (m *mockClusterGenerator) addCluster(ctrl *Controller, + lg *logrus.Entry, clusterName spec.NamespacedName, pgSpec *acidv1.Postgresql) *cluster.Cluster { + + mockTeamsAPI.setMembers([]string{"test-user"}) + cl := cluster.New(ctrl.makeClusterConfig(), ctrl.KubeClient, *pgSpec, lg) + cl.SetTeamsAPIClient(&mockTeamsAPI) + cl.SetOAuthTokenGetter(&mockOAuthTokenGetter{}) + cl.Spec.TeamID = "test-team" + return cl +} + +type mockTeamsAPIClient struct { + members []string +} + +func (m *mockTeamsAPIClient) TeamInfo(teamID, token string) (tm *teams.Team, err error) { + return &teams.Team{Members: m.members}, nil +} + +func (m *mockTeamsAPIClient) setMembers(members []string) { + m.members = members +} + +type mockNoSecretGetter struct { +} + +type testNoSecret struct { + v1core.SecretInterface +} + +func (c *testNoSecret) Get(name string, options metav1.GetOptions) (*v1.Secret, error) { + return nil, &NotFoundError{} + +} + +func (c *mockNoSecretGetter) Secrets(namespace string) v1core.SecretInterface { + return &testNoSecret{} +} + +func mockKubernetesClient() k8sutil.KubernetesClient { + return k8sutil.KubernetesClient{ + SecretsGetter: &mockNoSecretGetter{}, + } +} + func TestMergeDeprecatedPostgreSQLSpecParameters(t *testing.T) { c := NewController(&spec.ControllerConfig{}) - tests := []struct { name string in *acidv1.PostgresSpec @@ -42,3 +123,43 @@ func TestMergeDeprecatedPostgreSQLSpecParameters(t *testing.T) { } } } + +func TestGeneratePlan(t *testing.T) { + c := NewController(&spec.ControllerConfig{}) + c.opConfig.SuperUsername = "test-superuser" + c.opConfig.SecretNameTemplate = "secret" + c.clusterFactory = &mockClusterGenerator{} + c.KubeClient = mockKubernetesClient() + + tests := []struct { + name string + in ClusterEvent + contains cluster.Plan + error string + }{ + { + "Cluster add produces plan with a CreateSecret", + ClusterEvent{ + EventType: EventAdd, + NewSpec: &acidv1.Postgresql{ + ObjectMeta: metav1.ObjectMeta{ + Name: "TestCluster", + Namespace: "TestNamespace", + }, + }, + }, + []cluster.Action{cluster.CreateSecret{}, cluster.CreateSecret{}}, + "A plan for a new cluster should create secrets", + }, + } + for _, tt := range tests { + result := c.generatePlan(tt.in) + for idx, output := range result { + output := reflect.TypeOf(output) + expected := reflect.TypeOf(tt.contains[idx]) + if output != expected { + t.Errorf("%s: %v", tt.name, tt.error) + } + } + } +} diff --git a/pkg/controller/util.go b/pkg/controller/util.go index 34def1283..6b5af56b1 100644 --- a/pkg/controller/util.go +++ b/pkg/controller/util.go @@ -196,10 +196,10 @@ func (c *Controller) podClusterName(pod *v1.Pod) spec.NamespacedName { } func eventInSlice(a EventType, list []EventType) bool { - for _, b := range list { - if b == a { - return true - } - } - return false + for _, b := range list { + if b == a { + return true + } + } + return false }