package syncgroups import ( "errors" "fmt" "io/ioutil" "testing" ktestclient "k8s.io/kubernetes/pkg/client/unversioned/testclient" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/util/sets" "github.com/openshift/origin/pkg/client/testclient" "github.com/openshift/origin/pkg/cmd/admin/groups/sync/interfaces" ) func TestGoodPrune(t *testing.T) { testGroupPruner, tc := newTestPruner() errs := testGroupPruner.Prune() for _, err := range errs { t.Errorf("unexpected prune error: %v", err) } checkClientForDeletedGroups(tc, []string{"os" + Group2UID}, t) } func TestListFailsForPrune(t *testing.T) { testGroupPruner, tc := newTestPruner() listErr := errors.New("error during listing") testGroupPruner.GroupLister.(*TestGroupLister).err = listErr errs := testGroupPruner.Prune() if len(errs) != 1 { t.Errorf("unexpected prune errors: %v", errs) } else if errs[0] != listErr { t.Errorf("incorrect prune error:\n\twanted:\n\t%v\n\tgot:\n\t%v\n", listErr, errs[0]) } deletedGroups := extractDeletedGroups(tc) if len(deletedGroups) != 0 { t.Errorf("expected no groups to be deleted, got: %v", deletedGroups) } } // TestLocateFails tests that a failure locating a group does not fail the entire prune job, or cause it to prune that group func TestLocateFails(t *testing.T) { testGroupPruner, tc := newTestPruner() locateErr := fmt.Errorf("error during location for group: %s", Group1UID) testGroupPruner.GroupDetector.(*TestGroupDetector).SourceOfErrors[Group1UID] = locateErr errs := testGroupPruner.Prune() if len(errs) != 1 { t.Errorf("unexpected prune errors: %v", errs) } else if errs[0] != locateErr { t.Errorf("incorrect prune error:\n\twanted:\n\t%v\n\tgot:\n\t%v\n", locateErr, errs[0]) } checkClientForDeletedGroups(tc, []string{"os" + Group2UID}, t) } // TestDeleteFails tests that a prune failure doesn't fail the entire job func TestDeleteFails(t *testing.T) { testGroupPruner, tc := newTestPruner() deleteErr := fmt.Errorf("failed to delete group: %s", "os"+Group1UID) tc.PrependReactor("delete", "groups", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { deleteAction := action.(ktestclient.DeleteAction) if deleteAction.GetName() == "os"+Group1UID { return true, nil, deleteErr } return false, nil, nil }) testGroupPruner.GroupDetector.(*TestGroupDetector).SourceOfTruth[Group1UID] = false errs := testGroupPruner.Prune() if len(errs) != 1 { t.Errorf("unexpected prune error: %v", errs) } else if errs[0] != deleteErr { t.Errorf("incorrect prune error:\n\twanted:\n\t%v\n\tgot:\n\t%v\n", deleteErr, errs[0]) } // although the first delete will fail, the event is still registered // we are interested in seeing that both delete actions happen checkClientForDeletedGroups(tc, []string{"os" + Group1UID, "os" + Group2UID}, t) } func checkClientForDeletedGroups(tc *testclient.Fake, expectedGroups []string, t *testing.T) { actualGroups := sets.NewString(extractDeletedGroups(tc)...) wantedGroups := sets.NewString(expectedGroups...) if !actualGroups.Equal(wantedGroups) { t.Errorf("did not delete correct groups:\n\twanted:\n\t%v\n\tgot:\n\t%v\n", wantedGroups, actualGroups) } } func extractDeletedGroups(tc *testclient.Fake) []string { ret := []string{} for _, genericAction := range tc.Actions() { switch action := genericAction.(type) { case ktestclient.DeleteAction: ret = append(ret, action.GetName()) } } return ret } func newTestPruner() (*LDAPGroupPruner, *testclient.Fake) { tc := testclient.NewSimpleFake() tc.PrependReactor("delete", "groups", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { return true, nil, nil }) return &LDAPGroupPruner{ GroupLister: newTestLister(), GroupDetector: newTestGroupDetector(), GroupNameMapper: newTestGroupNameMapper(), GroupClient: tc.Groups(), Host: newTestHost(), Out: ioutil.Discard, Err: ioutil.Discard, }, tc } func newTestGroupDetector() interfaces.LDAPGroupDetector { return &TestGroupDetector{ SourceOfTruth: map[string]bool{ Group1UID: true, Group2UID: false, Group3UID: true, }, SourceOfErrors: map[string]error{ Group1UID: nil, Group2UID: nil, Group3UID: nil, }, } } var _ interfaces.LDAPGroupDetector = &TestGroupDetector{} type TestGroupDetector struct { SourceOfTruth map[string]bool SourceOfErrors map[string]error } func (l *TestGroupDetector) Exists(ldapGroupUID string) (bool, error) { status, exists := l.SourceOfTruth[ldapGroupUID] return status && exists, l.SourceOfErrors[ldapGroupUID] }