-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat(resty): Implement cache for requests Add an optional in-memory configurable generic cache to resty. Configure gobal-player to pass in cache to resty. Pre-fetch all parts of the TUI so they are present in the cache. * refactor(gobal-player): pass cache in as dependency Fixes: #2
- Loading branch information
Showing
11 changed files
with
896 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,4 +8,5 @@ packages: | |
github.com/jj-style/gobal-player/pkg/resty: | ||
interfaces: | ||
Client: | ||
HttpClient: | ||
HttpClient: | ||
Cache: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package resty | ||
|
||
import ( | ||
"context" | ||
"time" | ||
|
||
"github.com/eko/gocache/lib/v4/cache" | ||
gocache_store "github.com/eko/gocache/store/go_cache/v4" | ||
gocache "github.com/patrickmn/go-cache" | ||
) | ||
|
||
// A simple cache interface | ||
type Cache[T any] interface { | ||
// Get the item with the given key | ||
Get(context.Context, string) (T, error) | ||
// Set the value against the given key | ||
Set(context.Context, string, T) error | ||
} | ||
|
||
// generic wrapper around cache.Cache | ||
type cacheImpl[T any] struct { | ||
cache *cache.Cache[T] | ||
} | ||
|
||
// Create a new Cache with the given ttl expiration for items | ||
func NewCache[T any](ttl time.Duration) Cache[T] { | ||
gocacheClient := gocache.New(ttl, 10*time.Minute) | ||
gocacheStore := gocache_store.NewGoCache(gocacheClient) | ||
return &cacheImpl[T]{cache: cache.New[T](gocacheStore)} | ||
} | ||
|
||
func (c *cacheImpl[T]) Get(ctx context.Context, key string) (T, error) { | ||
return c.cache.Get(ctx, key) | ||
} | ||
|
||
func (c *cacheImpl[T]) Set(ctx context.Context, key string, value T) error { | ||
return c.cache.Set(ctx, key, value) | ||
} | ||
|
||
// nilCache is a Cache which does nothing | ||
type nilCache[T any] struct{} | ||
|
||
func (n *nilCache[T]) Get(context.Context, string) (T, error) { | ||
return *new(T), nil | ||
} | ||
|
||
func (n *nilCache[T]) Set(context.Context, string, T) error { | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
package resty | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"testing" | ||
|
||
"github.com/eko/gocache/lib/v4/cache" | ||
"github.com/eko/gocache/lib/v4/store" | ||
"github.com/golang/mock/gomock" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestNilCache(t *testing.T) { | ||
ctx := context.Background() | ||
assert := assert.New(t) | ||
nc := &nilCache[int]{} | ||
|
||
var got int | ||
var err error | ||
|
||
// get | ||
got, err = nc.Get(ctx, "a") | ||
assert.NoError(err) | ||
assert.Equal(0, got) | ||
|
||
// set | ||
err = nc.Set(ctx, "a", 1) | ||
assert.NoError(err) | ||
|
||
// get still nil | ||
got, err = nc.Get(ctx, "a") | ||
assert.NoError(err) | ||
assert.Equal(0, got) | ||
} | ||
|
||
func TestCache_Get(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
key string | ||
setup func(s *store.MockStoreInterface) | ||
want int | ||
assertErr assert.ErrorAssertionFunc | ||
}{ | ||
{ | ||
name: "cache hit", | ||
key: "key", | ||
setup: func(s *store.MockStoreInterface) { | ||
s.EXPECT().Get(gomock.Any(), "key").Return(1, nil) | ||
}, | ||
want: 1, | ||
assertErr: assert.NoError, | ||
}, | ||
{ | ||
name: "cache miss", | ||
key: "key", | ||
setup: func(s *store.MockStoreInterface) { | ||
s.EXPECT().Get(gomock.Any(), "key").Return(0, errors.New("item missing")) | ||
}, | ||
want: 0, | ||
assertErr: assert.Error, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
ctx := context.Background() | ||
|
||
gomockController := gomock.NewController(t) | ||
mstore := store.NewMockStoreInterface(gomockController) | ||
|
||
if tt.setup != nil { | ||
tt.setup(mstore) | ||
} | ||
|
||
c := &cacheImpl[int]{cache: cache.New[int](mstore)} | ||
|
||
var got int | ||
var err error | ||
|
||
got, err = c.Get(ctx, tt.key) | ||
tt.assertErr(t, err) | ||
assert.Equal(t, tt.want, got) | ||
}) | ||
} | ||
} | ||
|
||
func TestCache_Set(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
key string | ||
value int | ||
setup func(s *store.MockStoreInterface) | ||
assertErr assert.ErrorAssertionFunc | ||
}{ | ||
{ | ||
name: "happy", | ||
key: "key", | ||
value: 1, | ||
setup: func(s *store.MockStoreInterface) { | ||
s.EXPECT().Set(gomock.Any(), "key", 1).Return(nil) | ||
}, | ||
assertErr: assert.NoError, | ||
}, | ||
{ | ||
name: "unhappy", | ||
key: "key", | ||
value: 1, | ||
setup: func(s *store.MockStoreInterface) { | ||
s.EXPECT().Set(gomock.Any(), "key", 1).Return(errors.New("boom")) | ||
}, | ||
assertErr: assert.Error, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
ctx := context.Background() | ||
|
||
gomockController := gomock.NewController(t) | ||
mstore := store.NewMockStoreInterface(gomockController) | ||
|
||
if tt.setup != nil { | ||
tt.setup(mstore) | ||
} | ||
|
||
c := &cacheImpl[int]{cache: cache.New[int](mstore)} | ||
|
||
err := c.Set(ctx, tt.key, tt.value) | ||
tt.assertErr(t, err) | ||
}) | ||
} | ||
} |
Oops, something went wrong.