github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/uidmap/uidmap_test.go (about) 1 package uidmap 2 3 import ( 4 "sync" 5 "testing" 6 "time" 7 8 "github.com/keybase/client/go/libkb" 9 keybase1 "github.com/keybase/client/go/protocol/keybase1" 10 "github.com/keybase/clockwork" 11 "github.com/stretchr/testify/require" 12 "golang.org/x/net/context" 13 ) 14 15 type testPair struct { 16 uid string 17 username string 18 } 19 20 const mikem = keybase1.UID("95e88f2087e480cae28f08d81554bc00") 21 const max = keybase1.UID("dbb165b7879fe7b1174df73bed0b9500") 22 23 func TestLookupUsernameOnly(t *testing.T) { 24 tc := libkb.SetupTest(t, "TestLookup", 1) 25 defer tc.Cleanup() 26 27 var seed = []testPair{ 28 {"afb5eda3154bc13c1df0189ce93ba119", "t_bob"}, 29 {"00000000000000000000000000000119", ""}, 30 {"295a7eea607af32040647123732bc819", "t_alice"}, 31 {"00000000000000000000000000000219", ""}, 32 {"9cbca30c38afba6ab02d76b206515919", "t_helen"}, 33 {"00000000000000000000000000000319", ""}, 34 {string(max), "max"}, 35 {"00000000000000000000000000000419", ""}, 36 {string(mikem), "mikem"}, 37 {"00000000000000000000000000000519", ""}, 38 {"9f9611a4b7920637b1c2a839b2a0e119", "t_george"}, 39 {"00000000000000000000000000000619", ""}, 40 {"359c7644857203be38bfd3bf79bf1819", "t_frank"}, 41 {"00000000000000000000000000000719", ""}, 42 } 43 44 var tests []testPair 45 batchSize = 7 46 for len(tests) < batchSize*10 { 47 tests = append(tests, seed...) 48 } 49 50 var uids []keybase1.UID 51 for _, test := range tests { 52 uid, err := keybase1.UIDFromString(test.uid) 53 require.NoError(t, err) 54 uids = append(uids, uid) 55 } 56 57 uidMap := NewUIDMap(10) 58 59 for i := 0; i < 4; i++ { 60 results, err := uidMap.MapUIDsToUsernamePackages(context.TODO(), tc.G, uids, 0, 0, false) 61 require.NoError(t, err) 62 for j, test := range tests { 63 require.True(t, results[j].NormalizedUsername.Eq(libkb.NewNormalizedUsername(test.username))) 64 } 65 if i == 2 { 66 uidMap.Clear() 67 } 68 } 69 } 70 71 func TestLookupUsernameConcurrent(t *testing.T) { 72 tc := libkb.SetupTest(t, "TestLookup", 1) 73 defer tc.Cleanup() 74 75 batchSize = 7 76 77 testStuff := func() { 78 var seed = []testPair{ 79 {"afb5eda3154bc13c1df0189ce93ba119", "t_bob"}, 80 {"00000000000000000000000000000119", ""}, 81 {"295a7eea607af32040647123732bc819", "t_alice"}, 82 {"00000000000000000000000000000219", ""}, 83 {"9cbca30c38afba6ab02d76b206515919", "t_helen"}, 84 {"00000000000000000000000000000319", ""}, 85 {string(max), "max"}, 86 {"00000000000000000000000000000419", ""}, 87 {string(mikem), "mikem"}, 88 {"00000000000000000000000000000519", ""}, 89 {"9f9611a4b7920637b1c2a839b2a0e119", "t_george"}, 90 {"00000000000000000000000000000619", ""}, 91 {"359c7644857203be38bfd3bf79bf1819", "t_frank"}, 92 {"00000000000000000000000000000719", ""}, 93 } 94 95 var tests []testPair 96 for len(tests) < batchSize*10 { 97 tests = append(tests, seed...) 98 } 99 100 var uids []keybase1.UID 101 for _, test := range tests { 102 uid, err := keybase1.UIDFromString(test.uid) 103 require.NoError(t, err) 104 uids = append(uids, uid) 105 } 106 107 uidMap := NewUIDMap(10) 108 109 for i := 0; i < 4; i++ { 110 results, err := uidMap.MapUIDsToUsernamePackages(context.TODO(), tc.G, uids, 0, 0, false) 111 require.NoError(t, err) 112 for j, test := range tests { 113 require.True(t, results[j].NormalizedUsername.Eq(libkb.NewNormalizedUsername(test.username))) 114 } 115 if i == 2 { 116 uidMap.Clear() 117 } 118 } 119 } 120 121 var wg sync.WaitGroup 122 for i := 1; i < 10; i++ { 123 wg.Add(1) 124 go func() { 125 testStuff() 126 wg.Done() 127 }() 128 } 129 130 wg.Wait() 131 } 132 133 const tKB = keybase1.UID("7b7248a1c09d17451f9002d9edc8df19") 134 135 func TestRanOutOfTime(t *testing.T) { 136 tc := libkb.SetupTest(t, "TestLookup", 1) 137 defer tc.Cleanup() 138 139 fakeClock := clockwork.NewFakeClockAt(time.Now()) 140 tc.G.SetClock(fakeClock) 141 142 uidMap := NewUIDMap(10) 143 uids := []keybase1.UID{tKB} 144 errmsg := "ran out of time" 145 146 // This hook runs at the beginning of every iteration though the batch-fetch loop. 147 // It allows us to bump our fake clock forward. 148 hit := false 149 var cachedAt time.Time 150 setCachedAt := false 151 uidMap.testBatchIterHook = func() { 152 hit = true 153 fakeClock.Advance(time.Minute) 154 if setCachedAt { 155 cachedAt = fakeClock.Now() 156 } 157 } 158 159 // user t_kb has a fullname, but we're not giving ourselves enough time to grab it 160 results, err := uidMap.MapUIDsToUsernamePackages(context.TODO(), tc.G, uids, 0, time.Nanosecond, true) 161 require.Error(t, err) 162 require.True(t, hit) 163 require.Equal(t, err.Error(), errmsg) 164 require.True(t, results[0].NormalizedUsername.IsNil()) 165 require.Nil(t, results[0].FullName) 166 167 // user mikem has a fullname, but we're again not giving ourselves enough time to grab it; 168 // however, he has a hard-coded UID mapping so we should be able to still grab his username 169 uids = []keybase1.UID{mikem} 170 hit = false 171 results, err = uidMap.MapUIDsToUsernamePackages(context.TODO(), tc.G, uids, 0, time.Nanosecond, true) 172 require.Error(t, err) 173 require.True(t, hit) 174 require.Equal(t, err.Error(), errmsg) 175 require.True(t, results[0].NormalizedUsername.Eq(libkb.NewNormalizedUsername("mikem"))) 176 require.Nil(t, results[0].FullName) 177 178 // now success for user t_kb, who has a non-hardcoded username and a fullname on the 179 // server 180 t.Logf("tKB: %s", tKB) 181 uids = []keybase1.UID{tKB} 182 hit = false 183 results, err = uidMap.MapUIDsToUsernamePackages(context.TODO(), tc.G, uids, 0, 0, true) 184 require.NoError(t, err) 185 require.True(t, hit) 186 require.Equal(t, results[0].NormalizedUsername, libkb.NewNormalizedUsername("t_kb")) 187 require.Equal(t, results[0].FullName.FullName, keybase1.FullName("Joe Keybaser")) 188 require.Equal(t, results[0].FullName.EldestSeqno, keybase1.Seqno(1)) 189 require.Equal(t, results[0].FullName.Status, keybase1.StatusCode_SCOk) 190 cachedAt = fakeClock.Now() 191 192 // Now we're going to simulate that the fullname resolution became expired, and there 193 // was an attempt to fetch it from the server, but that we ran out of network fetch time 194 // budget. So we should see the stale result and also the error. 195 fakeClock.Advance(time.Hour) 196 hit = false 197 results, err = uidMap.MapUIDsToUsernamePackages(context.TODO(), tc.G, uids, time.Second, time.Nanosecond, false) 198 require.Error(t, err) 199 require.Equal(t, err.Error(), errmsg) 200 require.True(t, hit) 201 require.Equal(t, results[0].NormalizedUsername, libkb.NewNormalizedUsername("t_kb")) 202 require.Equal(t, results[0].FullName.FullName, keybase1.FullName("Joe Keybaser")) 203 require.Equal(t, results[0].FullName.EldestSeqno, keybase1.Seqno(1)) 204 require.Equal(t, results[0].FullName.CachedAt, keybase1.ToTime(cachedAt)) 205 require.Equal(t, results[0].FullName.Status, keybase1.StatusCode_SCOk) 206 207 // Same as above, but give enough time to refresh the name from the server 208 hit = false 209 setCachedAt = true 210 results, err = uidMap.MapUIDsToUsernamePackages(context.TODO(), tc.G, uids, time.Second, 0, false) 211 require.NoError(t, err) 212 require.True(t, hit) 213 require.Equal(t, results[0].NormalizedUsername, libkb.NewNormalizedUsername("t_kb")) 214 require.Equal(t, results[0].FullName.FullName, keybase1.FullName("Joe Keybaser")) 215 require.Equal(t, results[0].FullName.EldestSeqno, keybase1.Seqno(1)) 216 require.Equal(t, results[0].FullName.CachedAt, keybase1.ToTime(cachedAt)) 217 require.Equal(t, results[0].FullName.Status, keybase1.StatusCode_SCOk) 218 219 // In this case, there's not enough time to make any fetches, but it doesn't matter, since our 220 // previous fetch is fresh enough. We should never even hit testBatchIterHook 221 fakeClock.Advance(time.Minute) 222 hit = false 223 setCachedAt = false 224 results, err = uidMap.MapUIDsToUsernamePackages(context.TODO(), tc.G, uids, time.Hour, time.Nanosecond, false) 225 require.NoError(t, err) 226 require.False(t, hit) 227 require.Equal(t, results[0].NormalizedUsername, libkb.NewNormalizedUsername("t_kb")) 228 require.Equal(t, results[0].FullName.FullName, keybase1.FullName("Joe Keybaser")) 229 require.Equal(t, results[0].FullName.EldestSeqno, keybase1.Seqno(1)) 230 require.Equal(t, results[0].FullName.CachedAt, keybase1.ToTime(cachedAt)) 231 require.Equal(t, results[0].FullName.Status, keybase1.StatusCode_SCOk) 232 233 // Do a happy path for several users: 234 uids = []keybase1.UID{mikem, tKB, max} 235 results, err = uidMap.MapUIDsToUsernamePackages(context.TODO(), tc.G, uids, 0, 0, false) 236 require.NoError(t, err) 237 238 // Everyone gets back a normalized username 239 require.Equal(t, results[0].NormalizedUsername, libkb.NewNormalizedUsername("mikem")) 240 require.Equal(t, results[1].NormalizedUsername, libkb.NewNormalizedUsername("t_kb")) 241 require.Equal(t, results[2].NormalizedUsername, libkb.NewNormalizedUsername("max")) 242 243 // But only t_kb has a fullname that's found 244 require.Nil(t, results[0].FullName) 245 require.Equal(t, results[1].FullName.FullName, keybase1.FullName("Joe Keybaser")) 246 require.Equal(t, results[1].FullName.CachedAt, keybase1.ToTime(cachedAt)) 247 require.Equal(t, results[1].FullName.EldestSeqno, keybase1.Seqno(1)) 248 require.Equal(t, results[1].FullName.Status, keybase1.StatusCode_SCOk) 249 require.Nil(t, results[2].FullName) 250 251 // We should get same results from offline call 252 uidMap.testBatchIterHook = func() { 253 require.Fail(t, "unexpected network activity during offline uidmap call") 254 } 255 256 resultsCached, err := uidMap.MapUIDsToUsernamePackagesOffline(context.TODO(), tc.G, uids, 0) 257 require.NoError(t, err) 258 require.Equal(t, results, resultsCached) 259 } 260 261 func TestOfflineUIDMapNoCache(t *testing.T) { 262 tc := libkb.SetupTest(t, "TestOfflineUIDMapNoCache", 1) 263 defer tc.Cleanup() 264 265 uidMap := NewUIDMap(10) 266 uids := []keybase1.UID{mikem, max, tKB} 267 268 uidMap.testBatchIterHook = func() { 269 require.Fail(t, "unexpected network activity during offline uidmap call") 270 } 271 272 resultsCached, err := uidMap.MapUIDsToUsernamePackagesOffline(context.TODO(), tc.G, uids, 0) 273 require.NoError(t, err) 274 require.Len(t, resultsCached, 3) 275 require.EqualValues(t, "mikem", resultsCached[0].NormalizedUsername) 276 require.EqualValues(t, "max", resultsCached[1].NormalizedUsername) 277 require.True(t, resultsCached[2].NormalizedUsername.IsNil()) 278 for _, v := range resultsCached { 279 require.Nil(t, v.FullName) 280 } 281 } 282 283 func TestDuplicateUids(t *testing.T) { 284 tc := libkb.SetupTest(t, "TestLookup", 1) 285 defer tc.Cleanup() 286 287 uidMap := NewUIDMap(10) 288 uids := []keybase1.UID{tAlice, tTracy, tAlice} 289 results, err := uidMap.MapUIDsToUsernamePackages(context.TODO(), tc.G, uids, 290 24*time.Hour, 10*time.Second, true) 291 require.NoError(t, err) 292 293 require.EqualValues(t, results[0].NormalizedUsername, "t_alice") 294 require.EqualValues(t, results[1].NormalizedUsername, "t_tracy") 295 require.Equal(t, results[0], results[2]) 296 }