Skip to content

Commit c3afcac

Browse files
committed
tests + fix of no cache.
1 parent 9532b82 commit c3afcac

9 files changed

Lines changed: 1034 additions & 11 deletions

File tree

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
name: Test and release library
2+
3+
on:
4+
push:
5+
branches: ["main"]
6+
pull_request:
7+
branches: ["main"]
8+
9+
permissions:
10+
contents: write
11+
12+
env:
13+
REGISTRY: ghcr.io
14+
IMAGE_NAME: ${{ github.repository }}
15+
16+
jobs:
17+
test:
18+
runs-on: ubuntu-latest
19+
steps:
20+
- name: Checkout repository
21+
uses: actions/checkout@v4
22+
23+
- name: Run Tests
24+
run: go test ./... -v
25+
26+
27+
release:
28+
name: Tag and Release
29+
needs: test
30+
runs-on: ubuntu-latest
31+
if: success()
32+
33+
steps:
34+
- name: Checkout full history
35+
uses: actions/checkout@v4
36+
with:
37+
fetch-depth: 0
38+
token: ${{ secrets.GITHUB_TOKEN }}
39+
40+
- name: Get latest tag
41+
id: get_tag
42+
run: |
43+
git fetch --tags
44+
latest_tag=$(git tag --sort=-v:refname | head -n 1)
45+
echo "latest_tag=${latest_tag:-v0.0.0}" >> $GITHUB_OUTPUT
46+
47+
- name: Bump patch version
48+
id: bump
49+
run: |
50+
latest=${{ steps.get_tag.outputs.latest_tag }}
51+
IFS='.' read -r major minor patch <<<"${latest//v/}"
52+
patch=$((patch+1))
53+
new_tag="v${major}.${minor}.${patch}"
54+
echo "new_tag=$new_tag" >> $GITHUB_OUTPUT
55+
56+
- name: Create and push tag
57+
id: tag
58+
run: |
59+
git config user.name "github-actions"
60+
git config user.email "actions@github.com"
61+
git tag ${{ steps.bump.outputs.new_tag }}
62+
git push origin ${{ steps.bump.outputs.new_tag }}
63+
64+
- name: Create GitHub release
65+
uses: softprops/action-gh-release@v2
66+
with:
67+
tag_name: ${{ steps.bump.outputs.new_tag }}
68+
name: Release ${{ steps.bump.outputs.new_tag }}
69+
generate_release_notes: true

cacheable_list_test.go

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
package gocache
2+
3+
import (
4+
"context"
5+
"errors"
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
"github.com/stretchr/testify/require"
10+
)
11+
12+
type mockRepository struct {
13+
data map[string]testEntity
14+
callCount int
15+
err error
16+
}
17+
18+
type testEntity struct {
19+
ID string `json:"id"`
20+
Name string `json:"name"`
21+
Value int `json:"value"`
22+
}
23+
24+
func (m *mockRepository) GetByIdList(ctx context.Context, ids []string) (map[string]testEntity, error) {
25+
m.callCount++
26+
if m.err != nil {
27+
return nil, m.err
28+
}
29+
30+
result := make(map[string]testEntity)
31+
for _, id := range ids {
32+
if entity, ok := m.data[id]; ok {
33+
result[id] = entity
34+
}
35+
}
36+
return result, nil
37+
}
38+
39+
func TestGetCacheableList_AllInCache(t *testing.T) {
40+
client, cleanup := setupRedisContainer(t)
41+
defer cleanup()
42+
43+
ctx := context.Background()
44+
cache := NewTypedRedisCache[testEntity](client)
45+
46+
entity1 := testEntity{ID: "1", Name: "Entity 1", Value: 100}
47+
entity2 := testEntity{ID: "2", Name: "Entity 2", Value: 200}
48+
49+
err := cache.Set(ctx, "1", entity1)
50+
require.NoError(t, err)
51+
err = cache.Set(ctx, "2", entity2)
52+
require.NoError(t, err)
53+
54+
repo := &mockRepository{
55+
data: map[string]testEntity{},
56+
}
57+
58+
results, err := GetCacheableList(ctx, []string{"1", "2"}, repo, cache)
59+
require.NoError(t, err)
60+
assert.Len(t, results, 2)
61+
assert.Equal(t, 0, repo.callCount, "repository should not be called when all items are in cache")
62+
63+
assert.Equal(t, entity1.Name, results["1"].Name)
64+
assert.Equal(t, entity2.Name, results["2"].Name)
65+
}
66+
67+
func TestGetCacheableList_NoneInCache(t *testing.T) {
68+
client, cleanup := setupRedisContainer(t)
69+
defer cleanup()
70+
71+
ctx := context.Background()
72+
cache := NewTypedRedisCache[testEntity](client)
73+
74+
entity1 := testEntity{ID: "1", Name: "Entity 1", Value: 100}
75+
entity2 := testEntity{ID: "2", Name: "Entity 2", Value: 200}
76+
77+
repo := &mockRepository{
78+
data: map[string]testEntity{
79+
"1": entity1,
80+
"2": entity2,
81+
},
82+
}
83+
84+
results, err := GetCacheableList(ctx, []string{"1", "2"}, repo, cache)
85+
require.NoError(t, err)
86+
assert.Len(t, results, 2)
87+
assert.Equal(t, 1, repo.callCount, "repository should be called once")
88+
89+
assert.Equal(t, entity1.Name, results["1"].Name)
90+
assert.Equal(t, entity2.Name, results["2"].Name)
91+
92+
cached1, err := cache.Get(ctx, "1")
93+
require.NoError(t, err)
94+
require.NotNil(t, cached1)
95+
assert.Equal(t, entity1.Name, cached1.Name)
96+
97+
cached2, err := cache.Get(ctx, "2")
98+
require.NoError(t, err)
99+
require.NotNil(t, cached2)
100+
assert.Equal(t, entity2.Name, cached2.Name)
101+
}
102+
103+
func TestGetCacheableList_PartialCache(t *testing.T) {
104+
client, cleanup := setupRedisContainer(t)
105+
defer cleanup()
106+
107+
ctx := context.Background()
108+
cache := NewTypedRedisCache[testEntity](client)
109+
110+
entity1 := testEntity{ID: "1", Name: "Cached Entity", Value: 100}
111+
entity2 := testEntity{ID: "2", Name: "Repo Entity", Value: 200}
112+
113+
err := cache.Set(ctx, "1", entity1)
114+
require.NoError(t, err)
115+
116+
repo := &mockRepository{
117+
data: map[string]testEntity{
118+
"2": entity2,
119+
},
120+
}
121+
122+
results, err := GetCacheableList(ctx, []string{"1", "2"}, repo, cache)
123+
require.NoError(t, err)
124+
assert.Len(t, results, 2)
125+
assert.Equal(t, 1, repo.callCount, "repository should be called once for missing items")
126+
127+
assert.Equal(t, entity1.Name, results["1"].Name)
128+
assert.Equal(t, entity2.Name, results["2"].Name)
129+
130+
cached2, err := cache.Get(ctx, "2")
131+
require.NoError(t, err)
132+
require.NotNil(t, cached2)
133+
assert.Equal(t, entity2.Name, cached2.Name)
134+
}
135+
136+
func TestGetCacheableList_RepositoryError(t *testing.T) {
137+
client, cleanup := setupRedisContainer(t)
138+
defer cleanup()
139+
140+
ctx := context.Background()
141+
cache := NewTypedRedisCache[testEntity](client)
142+
143+
repo := &mockRepository{
144+
data: map[string]testEntity{},
145+
err: errors.New("repository error"),
146+
}
147+
148+
results, err := GetCacheableList(ctx, []string{"1", "2"}, repo, cache)
149+
assert.Error(t, err)
150+
assert.Nil(t, results)
151+
}
152+
153+
func TestGetCacheableList_PartialRepositoryError(t *testing.T) {
154+
client, cleanup := setupRedisContainer(t)
155+
defer cleanup()
156+
157+
ctx := context.Background()
158+
cache := NewTypedRedisCache[testEntity](client)
159+
160+
entity1 := testEntity{ID: "1", Name: "Cached Entity", Value: 100}
161+
err := cache.Set(ctx, "1", entity1)
162+
require.NoError(t, err)
163+
164+
repo := &mockRepository{
165+
data: map[string]testEntity{},
166+
err: errors.New("repository error"),
167+
}
168+
169+
results, err := GetCacheableList(ctx, []string{"1", "2"}, repo, cache)
170+
require.NoError(t, err)
171+
assert.Len(t, results, 1)
172+
assert.Equal(t, entity1.Name, results["1"].Name)
173+
}
174+
175+
func TestGetCacheableList_EmptyIDs(t *testing.T) {
176+
client, cleanup := setupRedisContainer(t)
177+
defer cleanup()
178+
179+
ctx := context.Background()
180+
cache := NewTypedRedisCache[testEntity](client)
181+
182+
repo := &mockRepository{
183+
data: map[string]testEntity{},
184+
}
185+
186+
results, err := GetCacheableList(ctx, []string{}, repo, cache)
187+
require.NoError(t, err)
188+
assert.Empty(t, results)
189+
assert.Equal(t, 0, repo.callCount)
190+
}
191+
192+
func TestGetCacheableList_SomeNotFoundInRepository(t *testing.T) {
193+
client, cleanup := setupRedisContainer(t)
194+
defer cleanup()
195+
196+
ctx := context.Background()
197+
cache := NewTypedRedisCache[testEntity](client)
198+
199+
entity1 := testEntity{ID: "1", Name: "Entity 1", Value: 100}
200+
201+
repo := &mockRepository{
202+
data: map[string]testEntity{
203+
"1": entity1,
204+
},
205+
}
206+
207+
results, err := GetCacheableList(ctx, []string{"1", "2", "3"}, repo, cache)
208+
require.NoError(t, err)
209+
assert.Len(t, results, 1)
210+
assert.Equal(t, entity1.Name, results["1"].Name)
211+
212+
_, exists2 := results["2"]
213+
assert.False(t, exists2)
214+
_, exists3 := results["3"]
215+
assert.False(t, exists3)
216+
}

functions_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package gocache
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
type User struct {
10+
ID string
11+
Name string
12+
}
13+
14+
type Product struct {
15+
SKU string
16+
Price float64
17+
}
18+
19+
type OrderItem struct {
20+
Quantity int
21+
}
22+
23+
func TestGetTypeName(t *testing.T) {
24+
t.Run("user type name", func(t *testing.T) {
25+
typeName := GetTypeName[User]()
26+
assert.Equal(t, "user", typeName)
27+
})
28+
29+
t.Run("product type name", func(t *testing.T) {
30+
typeName := GetTypeName[Product]()
31+
assert.Equal(t, "product", typeName)
32+
})
33+
34+
t.Run("orderitem type name", func(t *testing.T) {
35+
typeName := GetTypeName[OrderItem]()
36+
assert.Equal(t, "orderitem", typeName)
37+
})
38+
39+
t.Run("string type name", func(t *testing.T) {
40+
typeName := GetTypeName[string]()
41+
assert.Equal(t, "string", typeName)
42+
})
43+
44+
t.Run("int type name", func(t *testing.T) {
45+
typeName := GetTypeName[int]()
46+
assert.Equal(t, "int", typeName)
47+
})
48+
}

0 commit comments

Comments
 (0)