...

Source file src/github.com/letsencrypt/boulder/wfe2/cache_test.go

Documentation: github.com/letsencrypt/boulder/wfe2

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

View as plain text