github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/offline/rpc_cache_test.go (about)

     1  // Copyright 2019 Keybase, Inc. All rights reserved. Use of
     2  // this source code is governed by the included BSD license.
     3  
     4  package offline
     5  
     6  import (
     7  	"testing"
     8  
     9  	"github.com/keybase/client/go/libkb"
    10  	"github.com/keybase/client/go/protocol/keybase1"
    11  	"github.com/keybase/clockwork"
    12  	"github.com/stretchr/testify/require"
    13  )
    14  
    15  func TestRPCCacheBestEffort(t *testing.T) {
    16  	tc := libkb.SetupTest(t, "RPCCache()", 1)
    17  	defer tc.Cleanup()
    18  
    19  	fakeClock := clockwork.NewFakeClock()
    20  	tc.G.SetClock(fakeClock)
    21  
    22  	rpcCache := NewRPCCache(tc.G)
    23  
    24  	inHandlerCh := make(chan struct{}, 1)
    25  	handlerCh := make(chan interface{}, 1)
    26  	handler := func(mctx libkb.MetaContext) (interface{}, error) {
    27  		inHandlerCh <- struct{}{}
    28  		return <-handlerCh, nil
    29  	}
    30  
    31  	mctx := libkb.NewMetaContextBackground(tc.G)
    32  
    33  	t.Log("Populate the cache via the handler")
    34  	rpc := "TestRPC"
    35  	key := 1
    36  	value := 2
    37  	handlerCh <- value
    38  	var res int
    39  	resp := &res
    40  	servedRes, err := rpcCache.Serve(
    41  		mctx, keybase1.OfflineAvailability_BEST_EFFORT, 1, rpc, false,
    42  		key, resp, handler)
    43  	require.NoError(t, err)
    44  	require.Equal(t, 0, res) // `res` isn't filled in when the handler is used.
    45  	require.Equal(t, value, servedRes.(int))
    46  	<-inHandlerCh
    47  
    48  	t.Log("Read via the handler, when the cache is populated")
    49  	var res2 int
    50  	resp2 := &res2
    51  	handlerCh <- value
    52  	servedRes2, err := rpcCache.Serve(
    53  		mctx, keybase1.OfflineAvailability_BEST_EFFORT, 1, rpc, false,
    54  		key, resp2, handler)
    55  	require.NoError(t, err)
    56  	require.Equal(t, 2, res2) // `res` is filled in by the cache, but shouldn't be used because `servedRes2` is also filled in.
    57  	require.Equal(t, value, servedRes2.(int))
    58  	<-inHandlerCh
    59  
    60  	t.Log("Read via the cache, when connected but the handler is slow")
    61  	var res3 int
    62  	resp3 := &res3
    63  	var servedRes3 interface{}
    64  	errCh := make(chan error)
    65  	go func() {
    66  		var err error
    67  		servedRes3, err = rpcCache.Serve(
    68  			mctx, keybase1.OfflineAvailability_BEST_EFFORT, 1, rpc, false,
    69  			key, resp3, handler)
    70  		errCh <- err
    71  	}()
    72  
    73  	// Wait for the handler to be entered, then advance the clock.
    74  	<-inHandlerCh
    75  	fakeClock.Advance(bestEffortHandlerTimeout + 1)
    76  	err = <-errCh
    77  	require.NoError(t, err)
    78  	require.Equal(t, 2, res3)
    79  	require.Nil(t, servedRes3) // The filled-in cached value should be used.
    80  }