github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/api/accessor/claims_cacher_test.go (about) 1 package accessor_test 2 3 import ( 4 "errors" 5 6 "github.com/pf-qiu/concourse/v6/atc/api/accessor" 7 "github.com/pf-qiu/concourse/v6/atc/api/accessor/accessorfakes" 8 "github.com/pf-qiu/concourse/v6/atc/db" 9 10 . "github.com/onsi/ginkgo" 11 . "github.com/onsi/gomega" 12 ) 13 14 var _ = Describe("ClaimsCacher", func() { 15 var ( 16 fakeAccessTokenFetcher *accessorfakes.FakeAccessTokenFetcher 17 maxCacheSizeBytes int 18 19 claimsCacher accessor.AccessTokenFetcher 20 ) 21 22 BeforeEach(func() { 23 fakeAccessTokenFetcher = new(accessorfakes.FakeAccessTokenFetcher) 24 maxCacheSizeBytes = 1000 25 }) 26 27 JustBeforeEach(func() { 28 claimsCacher = accessor.NewClaimsCacher(fakeAccessTokenFetcher, maxCacheSizeBytes) 29 }) 30 31 It("fetches claims from the DB", func() { 32 claimsCacher.GetAccessToken("token") 33 Expect(fakeAccessTokenFetcher.GetAccessTokenCallCount()).To(Equal(1), "did not fetch from DB") 34 }) 35 36 It("doesn't fetch from the DB when the result is cached", func() { 37 claimsCacher.GetAccessToken("token") 38 claimsCacher.GetAccessToken("token") 39 Expect(fakeAccessTokenFetcher.GetAccessTokenCallCount()).To(Equal(1), "did not cache claims") 40 }) 41 42 It("doesn't cache claims when cache size is exceeded", func() { 43 fakeAccessTokenFetcher.GetAccessTokenReturns(db.AccessToken{ 44 Claims: db.Claims{RawClaims: map[string]interface{}{"a": stringWithLen(2000)}}, 45 }, true, nil) 46 claimsCacher.GetAccessToken("token") 47 claimsCacher.GetAccessToken("token") 48 Expect(fakeAccessTokenFetcher.GetAccessTokenCallCount()).To(Equal(2), "cached claims that exceed length") 49 }) 50 51 It("evicts the least recently used access token when size limit exceeded", func() { 52 fakeAccessTokenFetcher.GetAccessTokenReturns(db.AccessToken{ 53 Claims: db.Claims{RawClaims: map[string]interface{}{"a": stringWithLen(400)}}, 54 }, true, nil) 55 56 By("filling the cache") 57 claimsCacher.GetAccessToken("token1") 58 claimsCacher.GetAccessToken("token2") 59 Expect(fakeAccessTokenFetcher.GetAccessTokenCallCount()).To(Equal(2)) 60 61 By("overflowing the cache") 62 claimsCacher.GetAccessToken("token3") 63 Expect(fakeAccessTokenFetcher.GetAccessTokenCallCount()).To(Equal(3)) 64 65 By("fetching the least recently used token") 66 claimsCacher.GetAccessToken("token1") 67 Expect(fakeAccessTokenFetcher.GetAccessTokenCallCount()).To(Equal(4), "did not evict least recently used") 68 69 By("ensuring the latest token was not evicted") 70 claimsCacher.GetAccessToken("token3") 71 Expect(fakeAccessTokenFetcher.GetAccessTokenCallCount()).To(Equal(4), "evicted the latest token") 72 }) 73 74 It("errors when the DB fails", func() { 75 fakeAccessTokenFetcher.GetAccessTokenReturns(db.AccessToken{}, false, errors.New("error")) 76 _, _, err := claimsCacher.GetAccessToken("token") 77 Expect(err).To(HaveOccurred()) 78 }) 79 80 It("fetches claims from the DB concurrently", func() { 81 // this is designed purely to trigger the race detector 82 go claimsCacher.GetAccessToken("token1") 83 go claimsCacher.GetAccessToken("token2") 84 go claimsCacher.GetAccessToken("token3") 85 Eventually(fakeAccessTokenFetcher.GetAccessTokenCallCount).Should(Equal(3)) 86 }) 87 }) 88 89 func stringWithLen(l int) string { 90 b := make([]byte, l) 91 for i := 0; i < l; i++ { 92 b[i] = 'a' 93 } 94 return string(b) 95 }