func TestSimpleStop(t *testing.T) { tests := []struct { fake *reaperFake kind string actions []testclient.Action expectError bool test string }{ { fake: &reaperFake{ Fake: &testclient.Fake{}, }, kind: "Pod", actions: []testclient.Action{ testclient.NewGetAction("pods", api.NamespaceDefault, "foo"), testclient.NewDeleteAction("pods", api.NamespaceDefault, "foo"), }, expectError: false, test: "stop pod succeeds", }, { fake: &reaperFake{ Fake: &testclient.Fake{}, }, kind: "Service", actions: []testclient.Action{ testclient.NewGetAction("services", api.NamespaceDefault, "foo"), testclient.NewDeleteAction("services", api.NamespaceDefault, "foo"), }, expectError: false, test: "stop service succeeds", }, { fake: &reaperFake{ Fake: &testclient.Fake{}, noSuchPod: true, }, kind: "Pod", actions: []testclient.Action{}, expectError: true, test: "stop pod fails, no pod", }, { fake: &reaperFake{ Fake: &testclient.Fake{}, noDeleteService: true, }, kind: "Service", actions: []testclient.Action{ testclient.NewGetAction("services", api.NamespaceDefault, "foo"), }, expectError: true, test: "stop service fails, can't delete", }, } for _, test := range tests { fake := test.fake reaper, err := ReaperFor(test.kind, fake) if err != nil { t.Errorf("unexpected error: %v (%s)", err, test.test) } s, err := reaper.Stop("default", "foo", 0, nil) if err != nil && !test.expectError { t.Errorf("unexpected error: %v (%s)", err, test.test) } if err == nil { if test.expectError { t.Errorf("unexpected non-error: %v (%s)", err, test.test) } if s != "foo stopped" { t.Errorf("unexpected return: %s (%s)", s, test.test) } } actions := fake.Actions() if len(test.actions) != len(actions) { t.Errorf("unexpected actions: %v; expected %v (%s)", fake.Actions, test.actions, test.test) } for i, action := range actions { testAction := test.actions[i] if action != testAction { t.Errorf("unexpected action: %#v; expected %v (%s)", action, testAction, test.test) } } } }
func TestTokenCreation(t *testing.T) { testcases := map[string]struct { ClientObjects []runtime.Object SecretsSyncPending bool ServiceAccountsSyncPending bool ExistingServiceAccount *api.ServiceAccount ExistingSecrets []*api.Secret AddedServiceAccount *api.ServiceAccount UpdatedServiceAccount *api.ServiceAccount DeletedServiceAccount *api.ServiceAccount AddedSecret *api.Secret UpdatedSecret *api.Secret DeletedSecret *api.Secret ExpectedActions []testclient.Action }{ "new serviceaccount with no secrets": { ClientObjects: []runtime.Object{serviceAccount(emptySecretReferences()), createdTokenSecret()}, AddedServiceAccount: serviceAccount(emptySecretReferences()), ExpectedActions: []testclient.Action{ testclient.NewGetAction("serviceaccounts", api.NamespaceDefault, "default"), testclient.NewCreateAction("secrets", api.NamespaceDefault, createdTokenSecret()), testclient.NewUpdateAction("serviceaccounts", api.NamespaceDefault, serviceAccount(addTokenSecretReference(emptySecretReferences()))), }, }, "new serviceaccount with no secrets with unsynced secret store": { ClientObjects: []runtime.Object{serviceAccount(emptySecretReferences()), createdTokenSecret()}, SecretsSyncPending: true, AddedServiceAccount: serviceAccount(emptySecretReferences()), ExpectedActions: []testclient.Action{ testclient.NewGetAction("serviceaccounts", api.NamespaceDefault, "default"), testclient.NewCreateAction("secrets", api.NamespaceDefault, createdTokenSecret()), testclient.NewUpdateAction("serviceaccounts", api.NamespaceDefault, serviceAccount(addTokenSecretReference(emptySecretReferences()))), }, }, "new serviceaccount with missing secrets": { ClientObjects: []runtime.Object{serviceAccount(missingSecretReferences()), createdTokenSecret()}, AddedServiceAccount: serviceAccount(missingSecretReferences()), ExpectedActions: []testclient.Action{ testclient.NewGetAction("serviceaccounts", api.NamespaceDefault, "default"), testclient.NewCreateAction("secrets", api.NamespaceDefault, createdTokenSecret()), testclient.NewUpdateAction("serviceaccounts", api.NamespaceDefault, serviceAccount(addTokenSecretReference(missingSecretReferences()))), }, }, "new serviceaccount with missing secrets with unsynced secret store": { ClientObjects: []runtime.Object{serviceAccount(missingSecretReferences()), createdTokenSecret()}, SecretsSyncPending: true, AddedServiceAccount: serviceAccount(missingSecretReferences()), ExpectedActions: []testclient.Action{}, }, "new serviceaccount with non-token secrets": { ClientObjects: []runtime.Object{serviceAccount(regularSecretReferences()), createdTokenSecret(), opaqueSecret()}, AddedServiceAccount: serviceAccount(regularSecretReferences()), ExpectedActions: []testclient.Action{ testclient.NewGetAction("serviceaccounts", api.NamespaceDefault, "default"), testclient.NewCreateAction("secrets", api.NamespaceDefault, createdTokenSecret()), testclient.NewUpdateAction("serviceaccounts", api.NamespaceDefault, serviceAccount(addTokenSecretReference(regularSecretReferences()))), }, }, "new serviceaccount with token secrets": { ClientObjects: []runtime.Object{serviceAccount(tokenSecretReferences()), serviceAccountTokenSecret()}, ExistingSecrets: []*api.Secret{serviceAccountTokenSecret()}, AddedServiceAccount: serviceAccount(tokenSecretReferences()), ExpectedActions: []testclient.Action{}, }, "new serviceaccount with no secrets with resource conflict": { ClientObjects: []runtime.Object{updatedServiceAccount(emptySecretReferences()), createdTokenSecret()}, AddedServiceAccount: serviceAccount(emptySecretReferences()), ExpectedActions: []testclient.Action{ testclient.NewGetAction("serviceaccounts", api.NamespaceDefault, "default"), }, }, "updated serviceaccount with no secrets": { ClientObjects: []runtime.Object{serviceAccount(emptySecretReferences()), createdTokenSecret()}, UpdatedServiceAccount: serviceAccount(emptySecretReferences()), ExpectedActions: []testclient.Action{ testclient.NewGetAction("serviceaccounts", api.NamespaceDefault, "default"), testclient.NewCreateAction("secrets", api.NamespaceDefault, createdTokenSecret()), testclient.NewUpdateAction("serviceaccounts", api.NamespaceDefault, serviceAccount(addTokenSecretReference(emptySecretReferences()))), }, }, "updated serviceaccount with no secrets with unsynced secret store": { ClientObjects: []runtime.Object{serviceAccount(emptySecretReferences()), createdTokenSecret()}, SecretsSyncPending: true, UpdatedServiceAccount: serviceAccount(emptySecretReferences()), ExpectedActions: []testclient.Action{ testclient.NewGetAction("serviceaccounts", api.NamespaceDefault, "default"), testclient.NewCreateAction("secrets", api.NamespaceDefault, createdTokenSecret()), testclient.NewUpdateAction("serviceaccounts", api.NamespaceDefault, serviceAccount(addTokenSecretReference(emptySecretReferences()))), }, }, "updated serviceaccount with missing secrets": { ClientObjects: []runtime.Object{serviceAccount(missingSecretReferences()), createdTokenSecret()}, UpdatedServiceAccount: serviceAccount(missingSecretReferences()), ExpectedActions: []testclient.Action{ testclient.NewGetAction("serviceaccounts", api.NamespaceDefault, "default"), testclient.NewCreateAction("secrets", api.NamespaceDefault, createdTokenSecret()), testclient.NewUpdateAction("serviceaccounts", api.NamespaceDefault, serviceAccount(addTokenSecretReference(missingSecretReferences()))), }, }, "updated serviceaccount with missing secrets with unsynced secret store": { ClientObjects: []runtime.Object{serviceAccount(missingSecretReferences()), createdTokenSecret()}, SecretsSyncPending: true, UpdatedServiceAccount: serviceAccount(missingSecretReferences()), ExpectedActions: []testclient.Action{}, }, "updated serviceaccount with non-token secrets": { ClientObjects: []runtime.Object{serviceAccount(regularSecretReferences()), createdTokenSecret(), opaqueSecret()}, UpdatedServiceAccount: serviceAccount(regularSecretReferences()), ExpectedActions: []testclient.Action{ testclient.NewGetAction("serviceaccounts", api.NamespaceDefault, "default"), testclient.NewCreateAction("secrets", api.NamespaceDefault, createdTokenSecret()), testclient.NewUpdateAction("serviceaccounts", api.NamespaceDefault, serviceAccount(addTokenSecretReference(regularSecretReferences()))), }, }, "updated serviceaccount with token secrets": { ExistingSecrets: []*api.Secret{serviceAccountTokenSecret()}, UpdatedServiceAccount: serviceAccount(tokenSecretReferences()), ExpectedActions: []testclient.Action{}, }, "updated serviceaccount with no secrets with resource conflict": { ClientObjects: []runtime.Object{updatedServiceAccount(emptySecretReferences()), createdTokenSecret()}, UpdatedServiceAccount: serviceAccount(emptySecretReferences()), ExpectedActions: []testclient.Action{ testclient.NewGetAction("serviceaccounts", api.NamespaceDefault, "default"), }, }, "deleted serviceaccount with no secrets": { DeletedServiceAccount: serviceAccount(emptySecretReferences()), ExpectedActions: []testclient.Action{}, }, "deleted serviceaccount with missing secrets": { DeletedServiceAccount: serviceAccount(missingSecretReferences()), ExpectedActions: []testclient.Action{}, }, "deleted serviceaccount with non-token secrets": { ClientObjects: []runtime.Object{opaqueSecret()}, DeletedServiceAccount: serviceAccount(regularSecretReferences()), ExpectedActions: []testclient.Action{}, }, "deleted serviceaccount with token secrets": { ClientObjects: []runtime.Object{serviceAccountTokenSecret()}, ExistingSecrets: []*api.Secret{serviceAccountTokenSecret()}, DeletedServiceAccount: serviceAccount(tokenSecretReferences()), ExpectedActions: []testclient.Action{ testclient.NewDeleteAction("secrets", api.NamespaceDefault, "token-secret-1"), }, }, "added secret without serviceaccount": { ClientObjects: []runtime.Object{serviceAccountTokenSecret()}, AddedSecret: serviceAccountTokenSecret(), ExpectedActions: []testclient.Action{ testclient.NewGetAction("serviceaccounts", api.NamespaceDefault, "default"), testclient.NewDeleteAction("secrets", api.NamespaceDefault, "token-secret-1"), }, }, "added secret with serviceaccount": { ExistingServiceAccount: serviceAccount(tokenSecretReferences()), AddedSecret: serviceAccountTokenSecret(), ExpectedActions: []testclient.Action{}, }, "added token secret without token data": { ClientObjects: []runtime.Object{serviceAccountTokenSecretWithoutTokenData()}, ExistingServiceAccount: serviceAccount(tokenSecretReferences()), AddedSecret: serviceAccountTokenSecretWithoutTokenData(), ExpectedActions: []testclient.Action{ testclient.NewUpdateAction("secrets", api.NamespaceDefault, serviceAccountTokenSecret()), }, }, "added token secret without ca data": { ClientObjects: []runtime.Object{serviceAccountTokenSecretWithoutCAData()}, ExistingServiceAccount: serviceAccount(tokenSecretReferences()), AddedSecret: serviceAccountTokenSecretWithoutCAData(), ExpectedActions: []testclient.Action{ testclient.NewUpdateAction("secrets", api.NamespaceDefault, serviceAccountTokenSecret()), }, }, "added token secret with mismatched ca data": { ClientObjects: []runtime.Object{serviceAccountTokenSecretWithCAData([]byte("mismatched"))}, ExistingServiceAccount: serviceAccount(tokenSecretReferences()), AddedSecret: serviceAccountTokenSecretWithCAData([]byte("mismatched")), ExpectedActions: []testclient.Action{ testclient.NewUpdateAction("secrets", api.NamespaceDefault, serviceAccountTokenSecret()), }, }, "updated secret without serviceaccount": { ClientObjects: []runtime.Object{serviceAccountTokenSecret()}, UpdatedSecret: serviceAccountTokenSecret(), ExpectedActions: []testclient.Action{ testclient.NewGetAction("serviceaccounts", api.NamespaceDefault, "default"), testclient.NewDeleteAction("secrets", api.NamespaceDefault, "token-secret-1"), }, }, "updated secret with serviceaccount": { ExistingServiceAccount: serviceAccount(tokenSecretReferences()), UpdatedSecret: serviceAccountTokenSecret(), ExpectedActions: []testclient.Action{}, }, "updated token secret without token data": { ClientObjects: []runtime.Object{serviceAccountTokenSecretWithoutTokenData()}, ExistingServiceAccount: serviceAccount(tokenSecretReferences()), UpdatedSecret: serviceAccountTokenSecretWithoutTokenData(), ExpectedActions: []testclient.Action{ testclient.NewUpdateAction("secrets", api.NamespaceDefault, serviceAccountTokenSecret()), }, }, "updated token secret without ca data": { ClientObjects: []runtime.Object{serviceAccountTokenSecretWithoutCAData()}, ExistingServiceAccount: serviceAccount(tokenSecretReferences()), UpdatedSecret: serviceAccountTokenSecretWithoutCAData(), ExpectedActions: []testclient.Action{ testclient.NewUpdateAction("secrets", api.NamespaceDefault, serviceAccountTokenSecret()), }, }, "updated token secret with mismatched ca data": { ClientObjects: []runtime.Object{serviceAccountTokenSecretWithCAData([]byte("mismatched"))}, ExistingServiceAccount: serviceAccount(tokenSecretReferences()), UpdatedSecret: serviceAccountTokenSecretWithCAData([]byte("mismatched")), ExpectedActions: []testclient.Action{ testclient.NewUpdateAction("secrets", api.NamespaceDefault, serviceAccountTokenSecret()), }, }, "deleted secret without serviceaccount": { DeletedSecret: serviceAccountTokenSecret(), ExpectedActions: []testclient.Action{}, }, "deleted secret with serviceaccount with reference": { ClientObjects: []runtime.Object{serviceAccount(tokenSecretReferences())}, ExistingServiceAccount: serviceAccount(tokenSecretReferences()), DeletedSecret: serviceAccountTokenSecret(), ExpectedActions: []testclient.Action{ testclient.NewGetAction("serviceaccounts", api.NamespaceDefault, "default"), testclient.NewUpdateAction("serviceaccounts", api.NamespaceDefault, serviceAccount(emptySecretReferences())), }, }, "deleted secret with serviceaccount without reference": { ExistingServiceAccount: serviceAccount(emptySecretReferences()), DeletedSecret: serviceAccountTokenSecret(), ExpectedActions: []testclient.Action{}, }, } for k, tc := range testcases { // Re-seed to reset name generation utilrand.Seed(1) generator := &testGenerator{Token: "ABC"} client := testclient.NewSimpleFake(tc.ClientObjects...) controller := NewTokensController(client, TokensControllerOptions{TokenGenerator: generator, RootCA: []byte("CA Data")}) // Tell the token controller whether its stores have been synced controller.serviceAccountsSynced = func() bool { return !tc.ServiceAccountsSyncPending } controller.secretsSynced = func() bool { return !tc.SecretsSyncPending } if tc.ExistingServiceAccount != nil { controller.serviceAccounts.Add(tc.ExistingServiceAccount) } for _, s := range tc.ExistingSecrets { controller.secrets.Add(s) } if tc.AddedServiceAccount != nil { controller.serviceAccountAdded(tc.AddedServiceAccount) } if tc.UpdatedServiceAccount != nil { controller.serviceAccountUpdated(nil, tc.UpdatedServiceAccount) } if tc.DeletedServiceAccount != nil { controller.serviceAccountDeleted(tc.DeletedServiceAccount) } if tc.AddedSecret != nil { controller.secretAdded(tc.AddedSecret) } if tc.UpdatedSecret != nil { controller.secretUpdated(nil, tc.UpdatedSecret) } if tc.DeletedSecret != nil { controller.secretDeleted(tc.DeletedSecret) } actions := client.Actions() for i, action := range actions { if len(tc.ExpectedActions) < i+1 { t.Errorf("%s: %d unexpected actions: %+v", k, len(actions)-len(tc.ExpectedActions), actions[i:]) break } expectedAction := tc.ExpectedActions[i] if !reflect.DeepEqual(expectedAction, action) { t.Errorf("%s: Expected\n\t%#v\ngot\n\t%#v", k, expectedAction, action) continue } } if len(tc.ExpectedActions) > len(actions) { t.Errorf("%s: %d additional expected actions:%+v", k, len(tc.ExpectedActions)-len(actions), tc.ExpectedActions[len(actions):]) } } }