fix bug in jwtcachefiller caused when status update returns error

Co-authored-by: Ashish Amarnath <ashish.amarnath@broadcom.com>
This commit is contained in:
Ryan Richard
2024-08-05 11:32:20 -07:00
co-authored by Ashish Amarnath
parent a888083c50
commit f5da417450
10 changed files with 259 additions and 159 deletions
@@ -36,6 +36,7 @@ type Key struct {
type Value interface {
authenticator.Token
Close()
}
// New returns an empty cache.
@@ -45,21 +46,31 @@ func New() *Cache {
// Get an authenticator by key.
func (c *Cache) Get(key Key) Value {
res, _ := c.cache.Load(key)
if res == nil {
v, _ := c.cache.Load(key)
if v == nil {
return nil
}
return res.(Value)
return v.(Value)
}
// Store an authenticator into the cache.
// Store an authenticator into the cache. If overwriting a value in the cache, closes the overwritten value.
func (c *Cache) Store(key Key, value Value) {
c.cache.Store(key, value)
previousValue, _ := c.cache.Swap(key, value)
// Wait until after it has been overwritten in the cache to close it, to ensure that it is only closed
// after it is not available for cache reads anymore.
if previousValue != nil {
previousValue.(Value).Close()
}
}
// Delete an authenticator from the cache.
// Delete an authenticator from the cache. Closes the authenticator after removing it from the cache.
func (c *Cache) Delete(key Key) {
c.cache.Delete(key)
deletedValue, _ := c.cache.LoadAndDelete(key)
// Wait until after it has been removed from the cache to close it, to ensure that it is only closed
// after it is not available for cache reads anymore.
if deletedValue != nil {
deletedValue.(Value).Close()
}
}
// Keys currently stored in the cache.
@@ -19,35 +19,52 @@ import (
authenticationv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/authentication/v1alpha1"
loginapi "go.pinniped.dev/generated/latest/apis/concierge/login"
"go.pinniped.dev/internal/mocks/mocktokenauthenticator"
"go.pinniped.dev/internal/mocks/mockcachevalue"
)
func TestCache(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
t.Cleanup(func() {
ctrl.Finish()
})
cache := New()
require.NotNil(t, cache)
key1 := Key{Name: "authenticator-one"}
mockToken1 := mocktokenauthenticator.NewMockToken(ctrl)
cache.Store(key1, mockToken1)
require.Equal(t, mockToken1, cache.Get(key1))
mockValue1 := mockcachevalue.NewMockValue(ctrl)
require.Nil(t, cache.Get(key1))
cache.Store(key1, mockValue1)
require.Equal(t, mockValue1, cache.Get(key1))
require.Equal(t, 1, len(cache.Keys()))
key2 := Key{Name: "authenticator-two"}
mockToken2 := mocktokenauthenticator.NewMockToken(ctrl)
cache.Store(key2, mockToken2)
require.Equal(t, mockToken2, cache.Get(key2))
mockValue2 := mockcachevalue.NewMockValue(ctrl)
cache.Store(key2, mockValue2)
require.Equal(t, mockValue2, cache.Get(key2))
require.Equal(t, 2, len(cache.Keys()))
// Assert that Close() has not been called yet, and it should be called by the end of the test.
mockValue1.EXPECT().Close().Times(1)
mockValue2.EXPECT().Close().Times(1)
for _, key := range cache.Keys() {
cache.Delete(key)
}
require.Zero(t, len(cache.Keys()))
key3 := Key{Name: "authenticator-three"}
mockValue3 := mockcachevalue.NewMockValue(ctrl)
cache.Store(key3, mockValue3)
require.Equal(t, mockValue3, cache.Get(key3))
require.Equal(t, 1, len(cache.Keys()))
mockValue4 := mockcachevalue.NewMockValue(ctrl)
// Assert that Close() has not been called yet, and it should be called by the end of the test.
mockValue3.EXPECT().Close().Times(1)
cache.Store(key3, mockValue4) // overwrite
// Fill the cache back up with a fixed set of keys, but inserted in shuffled order.
keysInExpectedOrder := []Key{
{APIGroup: "a", Kind: "a", Name: "a"},
@@ -92,7 +109,7 @@ func TestAuthenticateTokenCredentialRequest(t *testing.T) {
mockCache := func(t *testing.T, res *authenticator.Response, authenticated bool, err error) *Cache {
ctrl := gomock.NewController(t)
t.Cleanup(ctrl.Finish)
m := mocktokenauthenticator.NewMockToken(ctrl)
m := mockcachevalue.NewMockValue(ctrl)
m.EXPECT().AuthenticateToken(audienceFreeContext{}, validRequest.Spec.Token).Return(res, authenticated, err)
c := New()
c.Store(validRequestKey, m)
@@ -137,7 +154,7 @@ func TestAuthenticateTokenCredentialRequest(t *testing.T) {
t.Run("context is cancelled", func(t *testing.T) {
ctrl := gomock.NewController(t)
t.Cleanup(ctrl.Finish)
m := mocktokenauthenticator.NewMockToken(ctrl)
m := mockcachevalue.NewMockValue(ctrl)
m.EXPECT().AuthenticateToken(gomock.Any(), validRequest.Spec.Token).DoAndReturn(
func(ctx context.Context, token string) (*authenticator.Response, bool, error) {
select {