Skip to content

Commit

Permalink
add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
rusq committed Jul 13, 2024
1 parent c7e4b84 commit 3fcdd77
Show file tree
Hide file tree
Showing 4 changed files with 269 additions and 47 deletions.
53 changes: 6 additions & 47 deletions cmd/slackdump/internal/list/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import (
"io"
"os"
"path/filepath"
"runtime/trace"
"time"

"github.com/charmbracelet/huh"
"github.com/rusq/fsadapter"
Expand All @@ -19,7 +17,6 @@ import (
"github.com/rusq/slackdump/v3/cmd/slackdump/internal/golang/base"
"github.com/rusq/slackdump/v3/internal/cache"
"github.com/rusq/slackdump/v3/internal/format"
"github.com/rusq/slackdump/v3/internal/osext"
"github.com/rusq/slackdump/v3/logger"
"github.com/rusq/slackdump/v3/types"
)
Expand Down Expand Up @@ -110,7 +107,11 @@ func list(ctx context.Context, listFn listFunc) error {
teamID := sess.Info().TeamID
users, ok := data.(types.Users) // Hax
if !ok && !noresolve {
users, err = getCachedUsers(ctx, sess, m, teamID, cfg.NoUserCache)
if cfg.NoUserCache {
users, err = sess.GetUsers(ctx)
} else {
users, err = getCachedUsers(ctx, sess, m, teamID)
}
if err != nil {
return err
}
Expand Down Expand Up @@ -150,48 +151,6 @@ func saveData(ctx context.Context, fs fsadapter.FS, data any, filename string, t
return nil
}

type userGetter interface {
GetUsers(ctx context.Context) (types.Users, error)
}

type userCacher interface {
LoadUsers(teamID string, retention time.Duration) ([]slack.User, error)
CacheUsers(teamID string, users []slack.User) error
}

func getCachedUsers(ctx context.Context, ug userGetter, m userCacher, teamID string, forceAPI bool) ([]slack.User, error) {
lg := logger.FromContext(ctx)

var users []slack.User
if !forceAPI {
users, err := m.LoadUsers(teamID, cfg.UserCacheRetention)
if err == nil {
return users, nil
}

// failed to load from cache
if !errors.Is(err, cache.ErrExpired) && !errors.Is(err, cache.ErrEmpty) && !os.IsNotExist(err) && !osext.IsPathError(err) {
// some funky error
return nil, err
}
lg.Println("user cache expired or empty, caching users")
}

// getting users from API
users, err := ug.GetUsers(ctx)
if err != nil {
return nil, err
}

// saving users to cache, will ignore any errors, but notify the user.
if err := m.CacheUsers(teamID, users); err != nil {
trace.Logf(ctx, "error", "saving user cache to %q, error: %s", userCacheBase, err)
lg.Printf("warning: failed saving user cache to %q: %s, but nevermind, let's continue", userCacheBase, err)
}

return users, nil
}

// fmtPrint prints the given data to the given writer, using the given format.
// It should be supplied with prepopulated users, as it may need to look up
// users by ID.
Expand Down Expand Up @@ -225,7 +184,7 @@ func makeFilename(prefix string, teamID string, ext string) string {
return fmt.Sprintf("%s-%s%s", prefix, teamID, ext)
}

func wizard(ctx context.Context, listFn listFunc) error {
func wizard(context.Context, listFunc) error {
// pick format
var types []string
for _, t := range format.All() {
Expand Down
109 changes: 109 additions & 0 deletions cmd/slackdump/internal/list/mocks_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 50 additions & 0 deletions cmd/slackdump/internal/list/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,20 @@ package list

import (
"context"
"errors"
"fmt"
"os"
"runtime/trace"
"time"

"github.com/rusq/slack"
"github.com/rusq/slackdump/v3"
"github.com/rusq/slackdump/v3/cmd/slackdump/internal/cfg"
"github.com/rusq/slackdump/v3/cmd/slackdump/internal/golang/base"
"github.com/rusq/slackdump/v3/internal/cache"
"github.com/rusq/slackdump/v3/internal/osext"
"github.com/rusq/slackdump/v3/logger"
"github.com/rusq/slackdump/v3/types"
)

var CmdListUsers = &base.Command{
Expand Down Expand Up @@ -49,3 +58,44 @@ func wizUsers(ctx context.Context, cmd *base.Command, args []string) error {
return users, filename, err
})
}

//go:generate mockgen -source=users.go -destination=mocks_test.go -package=list userGetter,userCacher

type userGetter interface {
GetUsers(ctx context.Context) (types.Users, error)
}

type userCacher interface {
LoadUsers(teamID string, retention time.Duration) ([]slack.User, error)
CacheUsers(teamID string, users []slack.User) error
}

func getCachedUsers(ctx context.Context, ug userGetter, m userCacher, teamID string) ([]slack.User, error) {
lg := logger.FromContext(ctx)

users, err := m.LoadUsers(teamID, cfg.UserCacheRetention)
if err == nil {
return users, nil
}

// failed to load from cache
if !errors.Is(err, cache.ErrExpired) && !errors.Is(err, cache.ErrEmpty) && !os.IsNotExist(err) && !osext.IsPathError(err) {
// some funky error
return nil, err
}
lg.Println("user cache expired or empty, caching users")

// getting users from API
users, err = ug.GetUsers(ctx)
if err != nil {
return nil, err
}

// saving users to cache, will ignore any errors, but notify the user.
if err := m.CacheUsers(teamID, users); err != nil {
trace.Logf(ctx, "error", "saving user cache to %q, error: %s", userCacheBase, err)
lg.Printf("warning: failed saving user cache to %q: %s, but nevermind, let's continue", userCacheBase, err)
}

return users, nil
}
104 changes: 104 additions & 0 deletions cmd/slackdump/internal/list/users_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package list

import (
"context"
"errors"
"io/fs"
"reflect"
"testing"

"github.com/rusq/slack"
"go.uber.org/mock/gomock"
)

func Test_getCachedUsers(t *testing.T) {
var (
testUsers = []slack.User{
{ID: "U1"},
{ID: "U2"},
{ID: "U3"},
}
)
type args struct {
ctx context.Context
teamID string
}
tests := []struct {
name string
args args
expect func(c *MockuserCacher, g *MockuserGetter)
want []slack.User
wantErr bool
}{
/* oh happy days */
{
"users loaded from cache",
args{context.Background(), "TEAM1"},
func(c *MockuserCacher, g *MockuserGetter) {
c.EXPECT().LoadUsers("TEAM1", gomock.Any()).Return(testUsers, nil)
},
testUsers,
false,
},
{
"getting users from API ok (recoverable cache error)",
args{context.Background(), "TEAM1"},
func(c *MockuserCacher, g *MockuserGetter) {
c.EXPECT().LoadUsers("TEAM1", gomock.Any()).Return(nil, &fs.PathError{})
g.EXPECT().GetUsers(gomock.Any()).Return(testUsers, nil)
c.EXPECT().CacheUsers("TEAM1", testUsers).Return(nil)
},
testUsers,
false,
},
{
"saving cache fails, but we continue",
args{context.Background(), "TEAM1"},
func(c *MockuserCacher, g *MockuserGetter) {
c.EXPECT().LoadUsers("TEAM1", gomock.Any()).Return(nil, &fs.PathError{})
g.EXPECT().GetUsers(gomock.Any()).Return(testUsers, nil)
c.EXPECT().CacheUsers("TEAM1", testUsers).Return(errors.New("disk mulching detected"))
},
testUsers,
false,
},
/* unhappy days */
{
"unrecoverable error",
args{context.Background(), "TEAM1"},
func(c *MockuserCacher, g *MockuserGetter) {
c.EXPECT().LoadUsers("TEAM1", gomock.Any()).Return(nil, errors.New("frobnication error"))
},
nil,
true,
},
{
"getting users from API fails",
args{context.Background(), "TEAM1"},
func(c *MockuserCacher, g *MockuserGetter) {
c.EXPECT().LoadUsers("TEAM1", gomock.Any()).Return(nil, &fs.PathError{})
g.EXPECT().GetUsers(gomock.Any()).Return(nil, errors.New("blip"))
},
nil,
true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctrl := gomock.NewController(t)
muc := NewMockuserCacher(ctrl)
mug := NewMockuserGetter(ctrl)

tt.expect(muc, mug)

got, err := getCachedUsers(tt.args.ctx, mug, muc, tt.args.teamID)
if (err != nil) != tt.wantErr {
t.Errorf("getCachedUsers() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("getCachedUsers() = %v, want %v", got, tt.want)
}
})
}
}

0 comments on commit 3fcdd77

Please sign in to comment.