func TestGroupOnDemandRefresh(t *testing.T) { mock := newMock() mock.usersGroupsError = errors.New("") config := &Config{ AccountRefreshFrequency: time.Hour, AccountRefreshCooldown: 0, KeyRefreshFrequency: time.Hour, KeyRefreshCooldown: 0, } store := testStore(mock, config) mock.usersGroupsError = nil ch := registerCallback(config) testbase.RunCases(t, []testbase.TestCase{ &testbase.FailureCase{ `GroupByName("group1")`, func() (interface{}, error) { return store.GroupByName("group1") }, `unable to find group with name "group1"`, }, }) <-ch removeCallback() testbase.RunCases(t, []testbase.TestCase{ &testbase.SuccessCase{ `GroupByName("group1")`, func() (interface{}, error) { return store.GroupByName("group1") }, testbase.ExpGroups[0], }, }) }
func TestGroupOnDemandRefresh(t *testing.T) { mock.Clear() mock.usersGroupsError = errors.New("") // No cooldown. config := &Config{time.Hour, 0, time.Hour, 0} store := testStore(mock, config) mock.usersGroupsError = nil ch := make(chan struct{}) accountRefreshCallback = func() { close(ch) } testbase.RunCases(t, []testbase.TestCase{ &testbase.FailureCase{ `GroupByName("group1")`, func() (interface{}, error) { return store.GroupByName("group1") }, `unable to find group with name "group1"`, }, }) <-ch accountRefreshCallback = func() {} ch = make(chan struct{}) // Ensure keys are refreshed. keyRefreshCallback = func() { close(ch) } testbase.RunCases(t, []testbase.TestCase{ &testbase.SuccessCase{ `GroupByName("group1")`, func() (interface{}, error) { return store.GroupByName("group1") }, testbase.ExpGroups[0], }, }) <-ch keyRefreshCallback = func() {} // First update and once for missing username. mock.AssertCalls(t, 2, 2) }
func TestHugeData(t *testing.T) { // 1000 keys ranging from 1000 bytes to ~11 Kb. keys := make([]string, 1000) for x := range keys { key := make([]byte, 1000+(x*10)) var b byte for y := range key { if rune(b) == '\n' { continue } key[y] = b b++ } keys[x] = string(key) } socketPath = tempFile() mock := &testbase.MockProvider{Usrs: testbase.ExpUsers, Keys: map[string][]string{"user1": keys}} client := &Client{} startServer(mock) defer os.Remove(socketPath) testbase.RunCases(t, []testbase.TestCase{ &testbase.SuccessCase{ `AuthorizedKeys("user1")`, func() (interface{}, error) { return client.AuthorizedKeys("user1") }, keys, }, }) }
func TestKeysBasicCase(t *testing.T) { mock := newMock() config := &Config{ AccountRefreshFrequency: time.Hour, AccountRefreshCooldown: 0, KeyRefreshFrequency: time.Hour, KeyRefreshCooldown: 0, } store := testStore(mock, config) testbase.RunCases(t, []testbase.TestCase{ &testbase.SuccessCase{ `AuthorizedKeys("user1")`, func() (interface{}, error) { return store.AuthorizedKeys("user1") }, testbase.ExpKeys["user1"], }, &testbase.SuccessCase{ `AuthorizedKeys("user2")`, func() (interface{}, error) { return store.AuthorizedKeys("user2") }, []string(nil), }, &testbase.FailureCase{ `AuthorizedKeys("user3")`, func() (interface{}, error) { return store.AuthorizedKeys("user3") }, `unable to find user with name "user3"`, }, }) }
func TestEmptyUsersGroups(t *testing.T) { emptyMock := &mockAPIClient{} config := &Config{time.Hour, time.Hour, time.Hour, 0} store := testStore(emptyMock, config) testbase.RunCases(t, []testbase.TestCase{ &testbase.SuccessCase{ "Names()", func() (interface{}, error) { return store.Names() }, []string{"gce-sudoers"}, }, }) }
func TestKeyCooldownAndRefresh(t *testing.T) { mTime := time.Now().UTC() // Mock time. timeNow = func() time.Time { return mTime } pulse := make(chan time.Time) timeAfter = func(time.Duration) <-chan time.Time { return pulse } mock := newMock() config := &Config{ AccountRefreshFrequency: time.Hour, AccountRefreshCooldown: 0, KeyRefreshFrequency: time.Second, KeyRefreshCooldown: 0, } store := testStore(mock, config) testbase.RunCases(t, []testbase.TestCase{ &testbase.SuccessCase{ `AuthorizedKeys("user1")`, func() (interface{}, error) { return store.AuthorizedKeys("user1") }, testbase.ExpKeys["user1"], }, }) mock.keys["user1"] = []string{"key1"} mTime = mTime.Add(time.Second + time.Nanosecond) ch := registerCallback(config) // Trigger refresh. pulse <- mTime <-ch removeCallback() mock.keys["user1"] = []string{"key2"} testbase.RunCases(t, []testbase.TestCase{ &testbase.SuccessCase{ `AuthorizedKeys("user1")`, func() (interface{}, error) { return store.AuthorizedKeys("user1") }, []string{"key1"}, }, }) timeAfter = time.After timeNow = time.Now }
func TestEmptyKeys(t *testing.T) { emptyMock := &mockAPIClient{users: mock.users} config := &Config{time.Hour, time.Hour, time.Hour, 0} store := testStore(emptyMock, config) testbase.RunCases(t, []testbase.TestCase{ &testbase.SuccessCase{ `AuthorizedKeys("user1")`, func() (interface{}, error) { return store.AuthorizedKeys("user1") }, []string(nil), }, }) emptyMock.AssertCalls(t, 1, 3) }
func TestKeyPrewarmingAndCaching(t *testing.T) { mock.Clear() // Background key refreshes happen every second. config := &Config{time.Hour, time.Hour, time.Hour, 0} store := testStore(mock, config) mock.keysError = errors.New("API error") testbase.RunCases(t, []testbase.TestCase{ &testbase.SuccessCase{ `AuthorizedKeys("user1")`, func() (interface{}, error) { return store.AuthorizedKeys("user1") }, testbase.ExpKeys["user1"], }, &testbase.SuccessCase{ `AuthorizedKeys("user2")`, func() (interface{}, error) { return store.AuthorizedKeys("user2") }, []string(nil), }, }) mock.AssertCalls(t, 1, 4) }
func TestKeyCooldownAndRefresh(t *testing.T) { mTime := time.Now().UTC() // Mock time. timeNow = func() time.Time { return mTime } pulse := make(chan time.Time) timeAfter = func(time.Duration) <-chan time.Time { return pulse } mock.Clear() // Background key refreshes happen every second. config := &Config{time.Hour, 0, time.Second, 0} store := testStore(mock, config) testbase.RunCases(t, []testbase.TestCase{ &testbase.SuccessCase{ `AuthorizedKeys("user1")`, func() (interface{}, error) { return store.AuthorizedKeys("user1") }, testbase.ExpKeys["user1"], }, &testbase.SuccessCase{ `AuthorizedKeys("user2")`, func() (interface{}, error) { return store.AuthorizedKeys("user2") }, []string(nil), }, }) mock.AssertCalls(t, 1, 2) mTime = mTime.Add(time.Second + time.Nanosecond) ch := make(chan struct{}) keyRefreshCallback = func() { close(ch) } // Trigger refresh. pulse <- mTime <-ch keyRefreshCallback = func() {} mock.AssertCalls(t, 2, 4) timeAfter = time.After timeNow = time.Now }
func TestKeysBasicCase(t *testing.T) { mock.Clear() config := &Config{time.Hour, time.Hour, time.Hour, 0} store := testStore(mock, config) testbase.RunCases(t, []testbase.TestCase{ &testbase.SuccessCase{ `AuthorizedKeys("user1")`, func() (interface{}, error) { return store.AuthorizedKeys("user1") }, testbase.ExpKeys["user1"], }, &testbase.SuccessCase{ `AuthorizedKeys("user2")`, func() (interface{}, error) { return store.AuthorizedKeys("user2") }, []string(nil), }, &testbase.FailureCase{ `AuthorizedKeys("user3")`, func() (interface{}, error) { return store.AuthorizedKeys("user3") }, `unable to find user with name "user3"`, }, }) // Prewarm and on-demand key fetches. mock.AssertCalls(t, 1, 4) }
func TestKeyPrewarmingAndCaching(t *testing.T) { mock := newMock() // Background key refreshes happen every second. config := &Config{ AccountRefreshFrequency: time.Hour, AccountRefreshCooldown: 0, KeyRefreshFrequency: time.Hour, KeyRefreshCooldown: 0, } store := testStore(mock, config) mock.keysError = errors.New("API error") testbase.RunCases(t, []testbase.TestCase{ &testbase.SuccessCase{ `AuthorizedKeys("user1")`, func() (interface{}, error) { return store.AuthorizedKeys("user1") }, testbase.ExpKeys["user1"], }, &testbase.SuccessCase{ `AuthorizedKeys("user2")`, func() (interface{}, error) { return store.AuthorizedKeys("user2") }, []string(nil), }, }) }
func TestAll(t *testing.T) { socketPath = tempFile() mock := &testbase.MockProvider{Usrs: testbase.ExpUsers, Grps: testbase.ExpGroups, Nams: testbase.ExpNames, Keys: testbase.ExpKeys} client := &Client{} startServer(mock) defer os.Remove(socketPath) testbase.RunCases(t, []testbase.TestCase{ &testbase.SuccessCase{ `UserByName("user1")`, func() (interface{}, error) { return client.UserByName("user1") }, testbase.ExpUsers[0], }, &testbase.SuccessCase{ "UserByUID(1002)", func() (interface{}, error) { return client.UserByUID(1002) }, testbase.ExpUsers[1], }, &testbase.SuccessCase{ `GroupByName("group1")`, func() (interface{}, error) { return client.GroupByName("group1") }, testbase.ExpGroups[0], }, &testbase.SuccessCase{ "GroupByGID(1001)", func() (interface{}, error) { return client.GroupByGID(1001) }, testbase.ExpGroups[1], }, &testbase.SuccessCase{ "Users()", func() (interface{}, error) { return client.Users() }, testbase.ExpUsers, }, &testbase.SuccessCase{ "Groups()", func() (interface{}, error) { return client.Groups() }, testbase.ExpGroups, }, &testbase.SuccessCase{ "Names()", func() (interface{}, error) { return client.Names() }, testbase.ExpNames, }, &testbase.SuccessCase{ `IsName("user1")`, func() (interface{}, error) { return client.IsName("user1") }, true, }, &testbase.SuccessCase{ `IsName("group1")`, func() (interface{}, error) { return client.IsName("group1") }, true, }, &testbase.SuccessCase{ `IsName("nil")`, func() (interface{}, error) { return client.IsName("nil") }, false, }, &testbase.SuccessCase{ `AuthorizedKeys("user1")`, func() (interface{}, error) { return client.AuthorizedKeys("user1") }, testbase.ExpKeys["user1"], }, &testbase.SuccessCase{ `AuthorizedKeys("user2")`, func() (interface{}, error) { return client.AuthorizedKeys("user2") }, []string{}, }, &testbase.FailureCase{ `UserByName("nil")`, func() (interface{}, error) { return client.UserByName("nil") }, "unable to find user or group", }, &testbase.FailureCase{ "UserByUID(2)", func() (interface{}, error) { return client.UserByUID(2) }, "unable to find user or group", }, &testbase.FailureCase{ `GroupByName("nil")`, func() (interface{}, error) { return client.GroupByName("nil") }, "unable to find user or group", }, &testbase.FailureCase{ "GroupByGID(1)", func() (interface{}, error) { return client.GroupByGID(1) }, "unable to find user or group", }, }) mock.Err = errors.New("") testbase.RunCases(t, []testbase.TestCase{ &testbase.FailureCase{ `UserByName("user1")`, func() (interface{}, error) { return client.UserByName("user1") }, "request failed", }, &testbase.FailureCase{ "UserByUID(1002)", func() (interface{}, error) { return client.UserByUID(1002) }, "request failed", }, &testbase.FailureCase{ `GroupByName("group1")`, func() (interface{}, error) { return client.GroupByName("group1") }, "request failed", }, &testbase.FailureCase{ "GroupByGID(1001)", func() (interface{}, error) { return client.GroupByGID(1001) }, "request failed", }, &testbase.FailureCase{ "Users()", func() (interface{}, error) { return client.Users() }, "request failed", }, &testbase.FailureCase{ "Groups()", func() (interface{}, error) { return client.Groups() }, "request failed", }, &testbase.FailureCase{ "Names()", func() (interface{}, error) { return client.Names() }, "request failed", }, &testbase.FailureCase{ `IsName("user1")`, func() (interface{}, error) { return client.IsName("user1") }, "request failed", }, &testbase.FailureCase{ `IsName("group1")`, func() (interface{}, error) { return client.IsName("group1") }, "request failed", }, &testbase.FailureCase{ `IsName("nil")`, func() (interface{}, error) { return client.IsName("nil") }, "request failed", }, &testbase.FailureCase{ `AuthorizedKeys("user1")`, func() (interface{}, error) { return client.AuthorizedKeys("user1") }, "request failed", }, }) }
func TestUsersGroups(t *testing.T) { mock.Clear() config := &Config{time.Hour, time.Hour, time.Hour, 0} store := testStore(mock, config) testbase.RunCases(t, []testbase.TestCase{ &testbase.SuccessCase{ `UserByName("user1")`, func() (interface{}, error) { return store.UserByName("user1") }, testbase.ExpUsers[0], }, &testbase.SuccessCase{ "UserByUID(4002)", func() (interface{}, error) { return store.UserByUID(4002) }, testbase.ExpUsers[1], }, &testbase.SuccessCase{ `GroupByName("group1")`, func() (interface{}, error) { return store.GroupByName("group1") }, testbase.ExpGroups[0], }, &testbase.SuccessCase{ "GroupByGID(4001)", func() (interface{}, error) { return store.GroupByGID(4001) }, testbase.ExpGroups[1], }, &testbase.SuccessCase{ "Users()", func() (interface{}, error) { r, e := store.Users(); sort.Sort(userSlice(r)); return r, e }, testbase.ExpUsers, }, &testbase.SuccessCase{ "Groups()", func() (interface{}, error) { r, e := store.Groups(); sort.Sort(groupSlice(r)); return r, e }, testbase.ExpGroups, }, &testbase.SuccessCase{ "Names()", func() (interface{}, error) { r, e := store.Names(); sort.Sort(sort.StringSlice(r)); return r, e }, testbase.ExpNames, }, &testbase.SuccessCase{ `IsName("user1")`, func() (interface{}, error) { return store.IsName("user1") }, true, }, &testbase.SuccessCase{ `IsName("group1")`, func() (interface{}, error) { return store.IsName("group1") }, true, }, &testbase.SuccessCase{ `IsName("nil")`, func() (interface{}, error) { return store.IsName("nil") }, false, }, &testbase.FailureCase{ `UserByName("nil")`, func() (interface{}, error) { return store.UserByName("nil") }, `unable to find user with name "nil"`, }, &testbase.FailureCase{ "UserByUID(2)", func() (interface{}, error) { return store.UserByUID(2) }, "unable to find user with UID 2", }, &testbase.FailureCase{ `GroupByName("nil")`, func() (interface{}, error) { return store.GroupByName("nil") }, `unable to find group with name "nil"`, }, &testbase.FailureCase{ "GroupByGID(1)", func() (interface{}, error) { return store.GroupByGID(1) }, "unable to find group with GID 1", }, }) // First refresh and key prewarm. mock.AssertCalls(t, 1, 2) }
func TestUsersGroups(t *testing.T) { mock := newMock() config := &Config{ AccountRefreshFrequency: time.Hour, AccountRefreshCooldown: 0, KeyRefreshFrequency: time.Hour, KeyRefreshCooldown: 0, } store := testStore(mock, config) testbase.RunCases(t, []testbase.TestCase{ &testbase.SuccessCase{ `UserByName("user1")`, func() (interface{}, error) { return store.UserByName("user1") }, testbase.ExpUsers[0], }, &testbase.SuccessCase{ "UserByUID(1002)", func() (interface{}, error) { return store.UserByUID(1002) }, testbase.ExpUsers[1], }, &testbase.SuccessCase{ `GroupByName("group1")`, func() (interface{}, error) { return store.GroupByName("group1") }, testbase.ExpGroups[0], }, &testbase.SuccessCase{ `GroupByName("gce-sudoers")`, func() (interface{}, error) { return store.GroupByName("gce-sudoers") }, expSudoers, }, &testbase.SuccessCase{ "GroupByGID(1001)", func() (interface{}, error) { return store.GroupByGID(1001) }, testbase.ExpGroups[1], }, &testbase.SuccessCase{ "GroupByGID(4001)", func() (interface{}, error) { return store.GroupByGID(4001) }, expSudoers, }, &testbase.SuccessCase{ "Users()", func() (interface{}, error) { r, e := store.Users(); sort.Sort(userSlice(r)); return r, e }, testbase.ExpUsers, }, &testbase.SuccessCase{ "Groups()", func() (interface{}, error) { r, e := store.Groups(); sort.Sort(groupSlice(r)); return r, e }, append([]*accounts.Group{expSudoers}, testbase.ExpGroups...), }, &testbase.SuccessCase{ "Names()", func() (interface{}, error) { r, e := store.Names(); sort.Sort(sort.StringSlice(r)); return r, e }, append([]string{"gce-sudoers"}, testbase.ExpNames...), }, &testbase.SuccessCase{ `IsName("user1")`, func() (interface{}, error) { return store.IsName("user1") }, true, }, &testbase.SuccessCase{ `IsName("group1")`, func() (interface{}, error) { return store.IsName("group1") }, true, }, &testbase.SuccessCase{ `IsName("gce-sudoers")`, func() (interface{}, error) { return store.IsName("gce-sudoers") }, true, }, &testbase.SuccessCase{ `IsName("nil")`, func() (interface{}, error) { return store.IsName("nil") }, false, }, &testbase.FailureCase{ `UserByName("nil")`, func() (interface{}, error) { return store.UserByName("nil") }, `unable to find user with name "nil"`, }, &testbase.FailureCase{ "UserByUID(2)", func() (interface{}, error) { return store.UserByUID(2) }, "unable to find user with UID 2", }, &testbase.FailureCase{ `GroupByName("nil")`, func() (interface{}, error) { return store.GroupByName("nil") }, `unable to find group with name "nil"`, }, &testbase.FailureCase{ "GroupByGID(1)", func() (interface{}, error) { return store.GroupByGID(1) }, "unable to find group with GID 1", }, }) }