Add a simple tests for CreateSecret

This commit is contained in:
erthalion 2018-09-21 11:36:01 +02:00
parent ba1f886043
commit b0756a1f75
5 changed files with 174 additions and 25 deletions

View File

@ -127,6 +127,14 @@ func New(cfg Config, kubeClient k8sutil.KubernetesClient, pgSpec acidv1.Postgres
return cluster 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 { func (c *Cluster) clusterName() spec.NamespacedName {
return util.NameFromMeta(c.ObjectMeta) return util.NameFromMeta(c.ObjectMeta)
} }
@ -222,7 +230,7 @@ func (c *Cluster) PlanForSecrets() (plan Plan) {
if k8sutil.ResourceNotFound(err) { if k8sutil.ResourceNotFound(err) {
msg = "Generate plan to create new secret %q" 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)) plan = append(plan, NewCreateSecret(secretUsername, secretSpec, c))
continue continue
} }

View File

@ -13,6 +13,7 @@ import (
"k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/tools/cache" "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/apiserver"
"github.com/zalando-incubator/postgres-operator/pkg/cluster" "github.com/zalando-incubator/postgres-operator/pkg/cluster"
"github.com/zalando-incubator/postgres-operator/pkg/spec" "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" 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 // Controller represents operator controller
type Controller struct { type Controller struct {
config spec.ControllerConfig config spec.ControllerConfig
@ -59,6 +74,8 @@ type Controller struct {
PodServiceAccount *v1.ServiceAccount PodServiceAccount *v1.ServiceAccount
PodServiceAccountRoleBinding *rbacv1beta1.RoleBinding PodServiceAccountRoleBinding *rbacv1beta1.RoleBinding
namespacesWithDefinedRBAC sync.Map namespacesWithDefinedRBAC sync.Map
clusterFactory ClusterFactory
} }
// NewController creates a new controller // NewController creates a new controller
@ -77,6 +94,7 @@ func NewController(controllerConfig *spec.ControllerConfig) *Controller {
teamClusters: make(map[string][]spec.NamespacedName), teamClusters: make(map[string][]spec.NamespacedName),
stopCh: make(chan struct{}), stopCh: make(chan struct{}),
podCh: make(chan cluster.PodEvent), podCh: make(chan cluster.PodEvent),
clusterFactory: &ClusterGenerator{},
} }
logger.Hooks.Add(c) logger.Hooks.Add(c)

View File

@ -136,7 +136,7 @@ func (c *Controller) acquireInitialListOfClusters() error {
continue continue
} }
clusterName = util.NameFromMeta(pg.ObjectMeta) 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) c.logger.Debugf("added new cluster: %q", clusterName)
} }
// initiate initial sync of all clusters. // initiate initial sync of all clusters.
@ -144,18 +144,20 @@ func (c *Controller) acquireInitialListOfClusters() error {
return nil return nil
} }
func (c *Controller) addCluster(lg *logrus.Entry, clusterName spec.NamespacedName, pgSpec *acidv1.Postgresql) *cluster.Cluster { func (c *ClusterGenerator) addCluster(ctrl *Controller,
cl := cluster.New(c.makeClusterConfig(), c.KubeClient, *pgSpec, lg) lg *logrus.Entry, clusterName spec.NamespacedName, pgSpec *acidv1.Postgresql) *cluster.Cluster {
cl.Run(c.stopCh)
cl := cluster.New(ctrl.makeClusterConfig(), ctrl.KubeClient, *pgSpec, lg)
cl.Run(ctrl.stopCh)
teamName := strings.ToLower(cl.Spec.TeamID) teamName := strings.ToLower(cl.Spec.TeamID)
defer c.clustersMu.Unlock() defer ctrl.clustersMu.Unlock()
c.clustersMu.Lock() ctrl.clustersMu.Lock()
c.teamClusters[teamName] = append(c.teamClusters[teamName], clusterName) ctrl.teamClusters[teamName] = append(ctrl.teamClusters[teamName], clusterName)
c.clusters[clusterName] = cl ctrl.clusters[clusterName] = cl
c.clusterLogs[clusterName] = ringlog.New(c.opConfig.RingLogLines) ctrl.clusterLogs[clusterName] = ringlog.New(ctrl.opConfig.RingLogLines)
c.clusterHistory[clusterName] = ringlog.New(c.opConfig.ClusterHistoryEntries) ctrl.clusterHistory[clusterName] = ringlog.New(ctrl.opConfig.ClusterHistoryEntries)
return cl return cl
} }
@ -182,7 +184,7 @@ func (c *Controller) generatePlan(event ClusterEvent) cluster.Plan {
case EventAdd: case EventAdd:
log.Infof("Creation of the cluster started") 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) c.curWorkerCluster.Store(event.WorkerID, newCluster)
return newCluster.PlanForCreate() return newCluster.PlanForCreate()
@ -272,7 +274,7 @@ func (c *Controller) processEvent(event ClusterEvent) {
lg.Infof("creation of the cluster started") 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) 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 // no race condition because a cluster is always processed by single worker
if !clusterFound { if !clusterFound {
cl = c.addCluster(lg, clusterName, event.NewSpec) cl = c.clusterFactory.addCluster(c, lg, clusterName, event.NewSpec)
} }
c.curWorkerCluster.Store(event.WorkerID, cl) c.curWorkerCluster.Store(event.WorkerID, cl)

View File

@ -1,20 +1,101 @@
package controller package controller
import ( import (
acidv1 "github.com/zalando-incubator/postgres-operator/pkg/apis/acid.zalan.do/v1"
"github.com/zalando-incubator/postgres-operator/pkg/spec"
"reflect" "reflect"
"testing" "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 ( var (
True = true True = true
False = false 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) { func TestMergeDeprecatedPostgreSQLSpecParameters(t *testing.T) {
c := NewController(&spec.ControllerConfig{}) c := NewController(&spec.ControllerConfig{})
tests := []struct { tests := []struct {
name string name string
in *acidv1.PostgresSpec 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)
}
}
}
}

View File

@ -196,10 +196,10 @@ func (c *Controller) podClusterName(pod *v1.Pod) spec.NamespacedName {
} }
func eventInSlice(a EventType, list []EventType) bool { func eventInSlice(a EventType, list []EventType) bool {
for _, b := range list { for _, b := range list {
if b == a { if b == a {
return true return true
} }
} }
return false return false
} }