@@ -3,9 +3,54 @@ package credentials
33import (
44 "context"
55 "errors"
6+ "sync"
67 "testing"
78)
89
10+ type countingStore struct {
11+ mu sync.Mutex
12+ data map [string ]string
13+ gets int
14+ deletes int
15+ }
16+
17+ func (s * countingStore ) Set (ctx context.Context , account , secret string ) error {
18+ _ = ctx
19+ s .mu .Lock ()
20+ defer s .mu .Unlock ()
21+ if s .data == nil {
22+ s .data = map [string ]string {}
23+ }
24+ s .data [account ] = secret
25+ return nil
26+ }
27+
28+ func (s * countingStore ) Get (ctx context.Context , account string ) (string , error ) {
29+ _ = ctx
30+ s .mu .Lock ()
31+ defer s .mu .Unlock ()
32+ s .gets ++
33+ if s .data == nil {
34+ return "" , ErrNotFound
35+ }
36+ v , ok := s .data [account ]
37+ if ! ok || v == "" {
38+ return "" , ErrNotFound
39+ }
40+ return v , nil
41+ }
42+
43+ func (s * countingStore ) Delete (ctx context.Context , account string ) error {
44+ _ = ctx
45+ s .mu .Lock ()
46+ defer s .mu .Unlock ()
47+ s .deletes ++
48+ if s .data != nil {
49+ delete (s .data , account )
50+ }
51+ return nil
52+ }
53+
954// --- CombinedStore edge-case tests (nil keychain, empty secrets) ---
1055
1156func TestCombinedStore_NilKeychain (t * testing.T ) {
@@ -103,6 +148,69 @@ func TestCombinedStore_FullCycle(t *testing.T) {
103148 }
104149}
105150
151+ func TestCombinedStore_GetUsesShortLivedCache (t * testing.T ) {
152+ t .Parallel ()
153+ backend := & countingStore {data : map [string ]string {"account" : "secret" }}
154+ cs := & CombinedStore {Keychain : backend }
155+ ctx := context .Background ()
156+
157+ got1 , err := cs .Get (ctx , "account" )
158+ if err != nil || got1 != "secret" {
159+ t .Fatalf ("first Get = (%q, %v), want (secret, nil)" , got1 , err )
160+ }
161+ got2 , err := cs .Get (ctx , "account" )
162+ if err != nil || got2 != "secret" {
163+ t .Fatalf ("second Get = (%q, %v), want (secret, nil)" , got2 , err )
164+ }
165+ if backend .gets != 1 {
166+ t .Fatalf ("backend Get count = %d, want 1" , backend .gets )
167+ }
168+ }
169+
170+ func TestCombinedStore_SetInvalidatesCache (t * testing.T ) {
171+ t .Parallel ()
172+ backend := & countingStore {data : map [string ]string {"account" : "old" }}
173+ cs := & CombinedStore {Keychain : backend }
174+ ctx := context .Background ()
175+
176+ got , err := cs .Get (ctx , "account" )
177+ if err != nil || got != "old" {
178+ t .Fatalf ("initial Get = (%q, %v), want (old, nil)" , got , err )
179+ }
180+ if err := cs .Set (ctx , "account" , "new" ); err != nil {
181+ t .Fatalf ("Set error: %v" , err )
182+ }
183+ got , err = cs .Get (ctx , "account" )
184+ if err != nil || got != "new" {
185+ t .Fatalf ("post-Set Get = (%q, %v), want (new, nil)" , got , err )
186+ }
187+ if backend .gets != 2 {
188+ t .Fatalf ("backend Get count after invalidation = %d, want 2" , backend .gets )
189+ }
190+ }
191+
192+ func TestCombinedStore_DeleteInvalidatesCache (t * testing.T ) {
193+ t .Parallel ()
194+ backend := & countingStore {data : map [string ]string {"account" : "secret" }}
195+ cs := & CombinedStore {Keychain : backend }
196+ ctx := context .Background ()
197+
198+ got , err := cs .Get (ctx , "account" )
199+ if err != nil || got != "secret" {
200+ t .Fatalf ("initial Get = (%q, %v), want (secret, nil)" , got , err )
201+ }
202+ if err := cs .Delete (ctx , "account" ); err != nil {
203+ t .Fatalf ("Delete error: %v" , err )
204+ }
205+ got , err = cs .Get (ctx , "account" )
206+ if err != ErrNotFound || got != "" {
207+ t .Fatalf ("post-Delete Get = (%q, %v), want (\" \" , ErrNotFound)" , got , err )
208+ }
209+ if backend .gets != 2 {
210+ t .Fatalf ("backend Get count after delete invalidation = %d, want 2" , backend .gets )
211+ }
212+ }
213+
106214// --- DefaultStore / SetDefaultStore tests ---
107215
108216func TestSetDefaultStore_Override (t * testing.T ) {
0 commit comments