github.com/letsencrypt/boulder@v0.20251208.0/wfe2/cache_test.go (about) 1 package wfe2 2 3 import ( 4 "context" 5 "errors" 6 "testing" 7 "time" 8 9 "github.com/jmhodges/clock" 10 "google.golang.org/grpc" 11 "google.golang.org/protobuf/types/known/timestamppb" 12 13 corepb "github.com/letsencrypt/boulder/core/proto" 14 "github.com/letsencrypt/boulder/metrics" 15 sapb "github.com/letsencrypt/boulder/sa/proto" 16 "github.com/letsencrypt/boulder/test" 17 ) 18 19 type recordingBackend struct { 20 requests []int64 21 } 22 23 func (rb *recordingBackend) GetRegistration( 24 ctx context.Context, 25 regID *sapb.RegistrationID, 26 opts ...grpc.CallOption, 27 ) (*corepb.Registration, error) { 28 rb.requests = append(rb.requests, regID.Id) 29 return &corepb.Registration{ 30 Id: regID.Id, 31 }, nil 32 } 33 34 func TestCacheAddRetrieve(t *testing.T) { 35 ctx := context.Background() 36 backend := &recordingBackend{} 37 38 cache := NewAccountCache(backend, 10, time.Second, clock.NewFake(), metrics.NoopRegisterer) 39 40 result, err := cache.GetRegistration(ctx, &sapb.RegistrationID{Id: 1234}) 41 test.AssertNotError(t, err, "getting registration") 42 test.AssertEquals(t, result.Id, int64(1234)) 43 test.AssertEquals(t, len(backend.requests), 1) 44 45 // Request it again. This should hit the cache so our backend should not see additional requests. 46 result, err = cache.GetRegistration(ctx, &sapb.RegistrationID{Id: 1234}) 47 test.AssertNotError(t, err, "getting registration") 48 test.AssertEquals(t, result.Id, int64(1234)) 49 test.AssertEquals(t, len(backend.requests), 1) 50 } 51 52 // Test that the cache copies values before giving them out, so code that receives a cached 53 // value can't modify the cache's contents. 54 func TestCacheCopy(t *testing.T) { 55 ctx := context.Background() 56 backend := &recordingBackend{} 57 58 cache := NewAccountCache(backend, 10, time.Second, clock.NewFake(), metrics.NoopRegisterer) 59 60 acct, err := cache.GetRegistration(ctx, &sapb.RegistrationID{Id: 1234}) 61 test.AssertNotError(t, err, "getting registration") 62 test.AssertEquals(t, len(backend.requests), 1) 63 origTimestamp := acct.CreatedAt 64 65 test.AssertEquals(t, cache.cache.Len(), 1) 66 67 // Request it again. This should hit the cache. 68 result, err := cache.GetRegistration(ctx, &sapb.RegistrationID{Id: 1234}) 69 test.AssertNotError(t, err, "getting registration") 70 test.AssertEquals(t, len(backend.requests), 1) 71 72 // Modify a pointer value inside the result 73 result.CreatedAt = timestamppb.New(time.Now().Add(24 * time.Hour)) 74 75 result, err = cache.GetRegistration(ctx, &sapb.RegistrationID{Id: 1234}) 76 test.AssertNotError(t, err, "getting registration") 77 test.AssertEquals(t, len(backend.requests), 1) 78 79 test.AssertDeepEquals(t, result.CreatedAt, origTimestamp) 80 } 81 82 // Test that the cache expires values. 83 func TestCacheExpires(t *testing.T) { 84 ctx := context.Background() 85 backend := &recordingBackend{} 86 87 clk := clock.NewFake() 88 cache := NewAccountCache(backend, 10, time.Second, clk, metrics.NoopRegisterer) 89 90 _, err := cache.GetRegistration(ctx, &sapb.RegistrationID{Id: 1234}) 91 test.AssertNotError(t, err, "getting registration") 92 test.AssertEquals(t, len(backend.requests), 1) 93 94 // Request it again. This should hit the cache. 95 _, err = cache.GetRegistration(ctx, &sapb.RegistrationID{Id: 1234}) 96 test.AssertNotError(t, err, "getting registration") 97 test.AssertEquals(t, len(backend.requests), 1) 98 99 test.AssertEquals(t, cache.cache.Len(), 1) 100 101 // "Sleep" 10 seconds to expire the entry 102 clk.Sleep(10 * time.Second) 103 104 // This should not hit the cache 105 _, err = cache.GetRegistration(ctx, &sapb.RegistrationID{Id: 1234}) 106 test.AssertNotError(t, err, "getting registration") 107 test.AssertEquals(t, len(backend.requests), 2) 108 } 109 110 type wrongIDBackend struct{} 111 112 func (wib wrongIDBackend) GetRegistration( 113 ctx context.Context, 114 regID *sapb.RegistrationID, 115 opts ...grpc.CallOption, 116 ) (*corepb.Registration, error) { 117 return &corepb.Registration{ 118 Id: regID.Id + 1, 119 }, nil 120 } 121 122 func TestWrongId(t *testing.T) { 123 ctx := context.Background() 124 cache := NewAccountCache(wrongIDBackend{}, 10, time.Second, clock.NewFake(), metrics.NoopRegisterer) 125 126 _, err := cache.GetRegistration(ctx, &sapb.RegistrationID{Id: 1234}) 127 test.AssertError(t, err, "expected error when backend returns wrong ID") 128 } 129 130 type errorBackend struct{} 131 132 func (eb errorBackend) GetRegistration(ctx context.Context, 133 regID *sapb.RegistrationID, 134 opts ...grpc.CallOption, 135 ) (*corepb.Registration, error) { 136 return nil, errors.New("some error") 137 } 138 139 func TestErrorPassthrough(t *testing.T) { 140 ctx := context.Background() 141 cache := NewAccountCache(errorBackend{}, 10, time.Second, clock.NewFake(), metrics.NoopRegisterer) 142 143 _, err := cache.GetRegistration(ctx, &sapb.RegistrationID{Id: 1234}) 144 test.AssertError(t, err, "expected error when backend errors") 145 test.AssertEquals(t, err.Error(), "some error") 146 }