github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/creds/cached_secrets_test.go (about) 1 package creds_test 2 3 import ( 4 "fmt" 5 "time" 6 7 "github.com/pf-qiu/concourse/v6/atc/creds" 8 "github.com/pf-qiu/concourse/v6/atc/creds/credsfakes" 9 10 . "github.com/onsi/ginkgo" 11 . "github.com/onsi/gomega" 12 ) 13 14 func makeGetStub(name string, value interface{}, expiration *time.Time, found bool, err error, cntReads *int, cntMisses *int) func(string) (interface{}, *time.Time, bool, error) { 15 return func(secretPath string) (interface{}, *time.Time, bool, error) { 16 if secretPath == name { 17 *cntReads++ 18 return value, expiration, found, err 19 } 20 *cntMisses++ 21 return nil, nil, false, nil 22 } 23 } 24 25 var _ = Describe("Caching of secrets", func() { 26 27 var secretManager *credsfakes.FakeSecrets 28 var cacheConfig creds.SecretCacheConfig 29 var cachedSecretManager *creds.CachedSecrets 30 var underlyingReads int 31 var underlyingMisses int 32 33 BeforeEach(func() { 34 secretManager = new(credsfakes.FakeSecrets) 35 cacheConfig = creds.SecretCacheConfig{ 36 Duration: 2 * time.Second, 37 DurationNotFound: 1 * time.Second, 38 PurgeInterval: 100 * time.Millisecond, 39 } 40 cachedSecretManager = creds.NewCachedSecrets(secretManager, cacheConfig) 41 underlyingReads = 0 42 underlyingMisses = 0 43 }) 44 45 It("should handle missing secrets correctly and cache misses", func() { 46 secretManager.GetStub = makeGetStub("foo", "value", nil, true, nil, &underlyingReads, &underlyingMisses) 47 48 // miss 49 value, expiration, found, err := cachedSecretManager.Get("bar") 50 Expect(value).To(BeNil()) 51 Expect(expiration).To(BeNil()) 52 Expect(found).To(BeFalse()) 53 Expect(err).To(BeNil()) 54 Expect(underlyingReads).To(BeIdenticalTo(0)) 55 Expect(underlyingMisses).To(BeIdenticalTo(1)) 56 57 // cached miss 58 value, expiration, found, err = cachedSecretManager.Get("bar") 59 Expect(value).To(BeNil()) 60 Expect(expiration).To(BeNil()) 61 Expect(found).To(BeFalse()) 62 Expect(err).To(BeNil()) 63 Expect(underlyingReads).To(BeIdenticalTo(0)) 64 Expect(underlyingMisses).To(BeIdenticalTo(1)) 65 }) 66 67 It("should handle existing secrets correctly and cache them, returning previous value if the underlying value has changed", func() { 68 secretManager.GetStub = makeGetStub("foo", "value", nil, true, nil, &underlyingReads, &underlyingMisses) 69 70 // hit 71 value, expiration, found, err := cachedSecretManager.Get("foo") 72 Expect(value).To(BeIdenticalTo("value")) 73 Expect(expiration).To(BeNil()) 74 Expect(found).To(BeTrue()) 75 Expect(err).To(BeNil()) 76 Expect(underlyingReads).To(BeIdenticalTo(1)) 77 Expect(underlyingMisses).To(BeIdenticalTo(0)) 78 79 // cached hit 80 secretManager.GetStub = makeGetStub("foo", "different-value", nil, true, nil, &underlyingReads, &underlyingMisses) 81 value, expiration, found, err = cachedSecretManager.Get("foo") 82 Expect(value).To(BeIdenticalTo("value")) 83 Expect(expiration).To(BeNil()) 84 Expect(found).To(BeTrue()) 85 Expect(err).To(BeNil()) 86 Expect(underlyingReads).To(BeIdenticalTo(1)) 87 Expect(underlyingMisses).To(BeIdenticalTo(0)) 88 }) 89 90 It("should handle errors correctly and avoid caching errors", func() { 91 secretManager.GetStub = makeGetStub("baz", nil, nil, false, fmt.Errorf("unexpected error"), &underlyingReads, &underlyingMisses) 92 93 // error 94 value, expiration, found, err := cachedSecretManager.Get("baz") 95 Expect(value).To(BeNil()) 96 Expect(expiration).To(BeNil()) 97 Expect(found).To(BeFalse()) 98 Expect(err).NotTo(BeNil()) 99 Expect(underlyingReads).To(BeIdenticalTo(1)) 100 Expect(underlyingMisses).To(BeIdenticalTo(0)) 101 102 // no caching of error 103 value, expiration, found, err = cachedSecretManager.Get("baz") 104 Expect(value).To(BeNil()) 105 Expect(expiration).To(BeNil()) 106 Expect(found).To(BeFalse()) 107 Expect(err).NotTo(BeNil()) 108 Expect(underlyingReads).To(BeIdenticalTo(2)) 109 Expect(underlyingMisses).To(BeIdenticalTo(0)) 110 }) 111 112 It("should re-retrieve expired entries", func() { 113 secretManager.GetStub = makeGetStub("foo", "value", nil, true, nil, &underlyingReads, &underlyingMisses) 114 115 // get few entries first 116 _, _, _, _ = cachedSecretManager.Get("foo") 117 _, _, _, _ = cachedSecretManager.Get("bar") 118 _, _, _, _ = cachedSecretManager.Get("baz") 119 Expect(underlyingReads).To(BeIdenticalTo(1)) 120 Expect(underlyingMisses).To(BeIdenticalTo(2)) 121 122 // get these entries again and make sure they are cached 123 _, _, _, _ = cachedSecretManager.Get("foo") 124 _, _, _, _ = cachedSecretManager.Get("bar") 125 _, _, _, _ = cachedSecretManager.Get("baz") 126 Expect(underlyingReads).To(BeIdenticalTo(1)) 127 Expect(underlyingMisses).To(BeIdenticalTo(2)) 128 129 // sleep 130 time.Sleep(cacheConfig.Duration + time.Millisecond) 131 132 // check counters again and make sure the entries are re-retrieved 133 _, _, _, _ = cachedSecretManager.Get("foo") 134 _, _, _, _ = cachedSecretManager.Get("bar") 135 _, _, _, _ = cachedSecretManager.Get("baz") 136 Expect(underlyingReads).To(BeIdenticalTo(2)) 137 Expect(underlyingMisses).To(BeIdenticalTo(4)) 138 }) 139 140 It("should cache negative responses for a separately specified duration", func() { 141 secretManager.GetStub = makeGetStub("foo", "value", nil, true, nil, &underlyingReads, &underlyingMisses) 142 143 // get few entries first 144 _, _, _, _ = cachedSecretManager.Get("foo") 145 _, _, _, _ = cachedSecretManager.Get("bar") 146 _, _, _, _ = cachedSecretManager.Get("baz") 147 Expect(underlyingReads).To(BeIdenticalTo(1)) 148 Expect(underlyingMisses).To(BeIdenticalTo(2)) 149 150 // sleep 151 time.Sleep(cacheConfig.DurationNotFound + time.Millisecond) 152 153 // existing secret should still be cached 154 _, _, _, _ = cachedSecretManager.Get("foo") 155 Expect(underlyingReads).To(BeIdenticalTo(1)) 156 Expect(underlyingMisses).To(BeIdenticalTo(2)) 157 158 // non-existing secrets should be attempted to be retrieved again 159 _, _, _, _ = cachedSecretManager.Get("bar") 160 _, _, _, _ = cachedSecretManager.Get("baz") 161 Expect(underlyingReads).To(BeIdenticalTo(1)) 162 Expect(underlyingMisses).To(BeIdenticalTo(4)) 163 }) 164 165 })