github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/libkb/identify3_test.go (about)

     1  package libkb
     2  
     3  import (
     4  	"encoding/hex"
     5  	"testing"
     6  	"time"
     7  
     8  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
     9  	"github.com/keybase/clockwork"
    10  	"github.com/stretchr/testify/require"
    11  	context "golang.org/x/net/context"
    12  )
    13  
    14  type id3FakeUIRouter struct {
    15  	ui id3FakeUI
    16  }
    17  
    18  func (i *id3FakeUIRouter) SetUI(ConnectionID, UIKind)         {}
    19  func (i *id3FakeUIRouter) GetIdentifyUI() (IdentifyUI, error) { return nil, nil }
    20  func (i *id3FakeUIRouter) GetIdentifyUICtx(ctx context.Context) (int, IdentifyUI, error) {
    21  	return 0, nil, nil
    22  }
    23  func (i *id3FakeUIRouter) GetSecretUI(sessionID int) (SecretUI, error)               { return nil, nil }
    24  func (i *id3FakeUIRouter) GetRekeyUI() (keybase1.RekeyUIInterface, int, error)       { return nil, 0, nil }
    25  func (i *id3FakeUIRouter) GetRekeyUINoSessionID() (keybase1.RekeyUIInterface, error) { return nil, nil }
    26  func (i *id3FakeUIRouter) GetHomeUI() (keybase1.HomeUIInterface, error)              { return nil, nil }
    27  func (i *id3FakeUIRouter) GetChatUI() (ChatUI, error)                                { return nil, nil }
    28  func (i *id3FakeUIRouter) GetLogUI() (LogUI, error)                                  { return nil, nil }
    29  func (i *id3FakeUIRouter) GetIdentify3UIAdapter(MetaContext) (IdentifyUI, error) {
    30  	return nil, nil
    31  }
    32  func (i *id3FakeUIRouter) DumpUIs() map[UIKind]ConnectionID {
    33  	return nil
    34  }
    35  func (i *id3FakeUIRouter) Shutdown() {}
    36  
    37  func (i *id3FakeUIRouter) GetIdentify3UI(MetaContext) (keybase1.Identify3UiInterface, error) {
    38  	return &i.ui, nil
    39  }
    40  
    41  func (i *id3FakeUIRouter) WaitForUIType(uiKind UIKind, timeout time.Duration) bool {
    42  	return false
    43  }
    44  
    45  type id3FakeUI struct {
    46  	timeOuts []keybase1.Identify3GUIID
    47  }
    48  
    49  func (i *id3FakeUI) assertAndCleanState(t *testing.T, expected []keybase1.Identify3GUIID) {
    50  	require.Equal(t, len(expected), len(i.timeOuts))
    51  	for j, v := range expected {
    52  		require.Equal(t, v, i.timeOuts[j])
    53  	}
    54  	i.timeOuts = nil
    55  }
    56  
    57  func (i *id3FakeUI) Identify3ShowTracker(context.Context, keybase1.Identify3ShowTrackerArg) error {
    58  	return nil
    59  }
    60  func (i *id3FakeUI) Identify3UpdateRow(context.Context, keybase1.Identify3Row) error {
    61  	return nil
    62  }
    63  func (i *id3FakeUI) Identify3UpdateUserCard(context.Context, keybase1.Identify3UpdateUserCardArg) error {
    64  	return nil
    65  }
    66  func (i *id3FakeUI) Identify3UserReset(_ context.Context, id keybase1.Identify3GUIID) error {
    67  	return nil
    68  }
    69  func (i *id3FakeUI) Identify3TrackerTimedOut(_ context.Context, id keybase1.Identify3GUIID) error {
    70  	i.timeOuts = append(i.timeOuts, id)
    71  	return nil
    72  }
    73  func (i *id3FakeUI) Identify3Result(context.Context, keybase1.Identify3ResultArg) error { return nil }
    74  func (i *id3FakeUI) Identify3Summary(_ context.Context, summary keybase1.Identify3Summary) error {
    75  	return nil
    76  }
    77  
    78  func TestIdentify3State(t *testing.T) {
    79  	tc := SetupTest(t, "TestIdentify3State()", 1)
    80  	defer tc.Cleanup()
    81  
    82  	fakeClock := clockwork.NewFakeClock()
    83  	tc.G.SetClock(fakeClock)
    84  	uiRouter := id3FakeUIRouter{}
    85  	tc.G.UIRouter = &uiRouter
    86  	tc.G.Identify3State.Shutdown()
    87  
    88  	id3state, testCompletionCh := NewIdentify3StateForTest(tc.G)
    89  	tc.G.Identify3State = id3state
    90  
    91  	mkID := func(i int) keybase1.Identify3GUIID {
    92  		var buf [1]byte
    93  		buf[0] = byte(i)
    94  		return keybase1.Identify3GUIID(hex.EncodeToString(buf[:]))
    95  	}
    96  	mkSession := func(i int) *Identify3Session {
    97  		return &Identify3Session{
    98  			created: fakeClock.Now(),
    99  			id:      mkID(i),
   100  		}
   101  	}
   102  
   103  	assertState := func(cache, queue []int) {
   104  		id3state.Lock()
   105  		require.Equal(t, len(cache), len(id3state.cache))
   106  		for _, v := range cache {
   107  			_, found := id3state.cache[mkID(v)]
   108  			require.True(t, found)
   109  		}
   110  		require.Equal(t, len(queue), len(id3state.expirationQueue))
   111  		for i, v := range queue {
   112  			require.Equal(t, mkID(v), id3state.expirationQueue[i].id)
   113  		}
   114  		id3state.Unlock()
   115  	}
   116  
   117  	advance := func(d time.Duration) {
   118  		id3state.bgThreadTimeMu.Lock()
   119  		fakeClock.Advance(d)
   120  		now := fakeClock.Now()
   121  		id3state.bgThreadTimeMu.Unlock()
   122  		for {
   123  			completedThough := <-testCompletionCh
   124  			if !completedThough.Before(now) {
   125  				break
   126  			}
   127  		}
   128  	}
   129  
   130  	inc := id3state.expireTime / 10000
   131  	epsilon := inc / 2
   132  
   133  	// put in 3 items all inc time apart.
   134  	err := id3state.Put(mkSession(1))
   135  	require.NoError(t, err)
   136  	fakeClock.Advance(inc)
   137  	err = id3state.Put(mkSession(2))
   138  	require.NoError(t, err)
   139  	fakeClock.Advance(inc)
   140  	err = id3state.Put(mkSession(3))
   141  	require.NoError(t, err)
   142  
   143  	// make sure that all 3 items hit the cache, and in the right order.
   144  	set := []int{1, 2, 3}
   145  	assertState(set, set)
   146  
   147  	// After advancing a little bit more than necessary expiration time, we should
   148  	// see a situation where item 1 is going from both the cache and the queue,
   149  	// and that it shows up as expired in the UI.
   150  	advance(id3state.expireTime - inc - epsilon)
   151  	set = []int{2, 3}
   152  	assertState(set, set)
   153  	uiRouter.ui.assertAndCleanState(t, []keybase1.Identify3GUIID{mkID(1)})
   154  
   155  	// When we remove an item explicitly, it's removed from the cache, but not
   156  	// the queue, so check this expectation.
   157  	id3state.Remove(mkID(3))
   158  	assertState([]int{2}, []int{2, 3})
   159  
   160  	// Now item 2 is about to expire, which will leave just 3 sitting around in
   161  	// the queue.
   162  	advance(inc)
   163  	assertState([]int{}, []int{3})
   164  	uiRouter.ui.assertAndCleanState(t, []keybase1.Identify3GUIID{mkID(2)})
   165  
   166  	// Because 3 was removed prior to its expiration, it shouldn't trigger a UI
   167  	// event.
   168  	advance(inc)
   169  	assertState([]int{}, []int{})
   170  	uiRouter.ui.assertAndCleanState(t, []keybase1.Identify3GUIID{})
   171  }