github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/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 }