github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/engine/puk_upgrade_background_test.go (about) 1 // Copyright 2017 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 package engine 5 6 import ( 7 "testing" 8 "time" 9 10 "github.com/keybase/client/go/libkb" 11 "github.com/keybase/clockwork" 12 "github.com/stretchr/testify/require" 13 ) 14 15 // When stopped before RunEngine, the inner loop never runs. 16 func TestPerUserKeyUpgradeBackgroundShutdownFirst(t *testing.T) { 17 tc := SetupEngineTest(t, "pukup") 18 defer tc.Cleanup() 19 fakeClock := clockwork.NewFakeClockAt(time.Now()) 20 tc.G.SetClock(fakeClock) 21 22 advance := func(d time.Duration) { 23 tc.G.Log.Debug("+ fakeClock#advance(%s) start: %s", d, fakeClock.Now()) 24 fakeClock.Advance(d) 25 tc.G.Log.Debug("- fakeClock#adance(%s) end: %s", d, fakeClock.Now()) 26 } 27 28 metaCh := make(chan string, 100) 29 arg := &PerUserKeyUpgradeBackgroundArgs{ 30 testingMetaCh: metaCh, 31 } 32 eng := NewPerUserKeyUpgradeBackground(tc.G, arg) 33 eng.task.args.Settings.StartStagger = 0 // Disable stagger for deterministic testing 34 uis := libkb.UIs{ 35 LogUI: tc.G.UI.GetLogUI(), 36 } 37 38 // shut down before starting 39 eng.Shutdown() 40 m := NewMetaContextForTest(tc).WithUIs(uis) 41 42 err := RunEngine2(m, eng) 43 require.NoError(t, err) 44 45 expectMeta(t, metaCh, "early-shutdown") 46 47 advance(PerUserKeyUpgradeBackgroundSettings.Start) 48 advance(PerUserKeyUpgradeBackgroundSettings.Interval) 49 advance(PerUserKeyUpgradeBackgroundSettings.Interval) 50 advance(PerUserKeyUpgradeBackgroundSettings.Interval) 51 advance(PerUserKeyUpgradeBackgroundSettings.Interval) 52 53 expectMeta(t, metaCh, "") 54 } 55 56 // When stopped before the Start wait time, the loop starts but a round never runs. 57 func TestPerUserKeyUpgradeBackgroundShutdownSoon(t *testing.T) { 58 tc := SetupEngineTest(t, "pukup") 59 defer tc.Cleanup() 60 fakeClock := clockwork.NewFakeClockAt(time.Now()) 61 tc.G.SetClock(fakeClock) 62 63 advance := func(d time.Duration) { 64 tc.G.Log.Debug("+ fakeClock#advance(%s) start: %s", d, fakeClock.Now()) 65 fakeClock.Advance(d) 66 tc.G.Log.Debug("- fakeClock#adance(%s) end: %s", d, fakeClock.Now()) 67 } 68 69 metaCh := make(chan string, 100) 70 roundResCh := make(chan error, 100) 71 arg := &PerUserKeyUpgradeBackgroundArgs{ 72 testingMetaCh: metaCh, 73 testingRoundResCh: roundResCh, 74 } 75 eng := NewPerUserKeyUpgradeBackground(tc.G, arg) 76 m := NewMetaContextForTestWithLogUI(tc) 77 err := RunEngine2(m, eng) 78 require.NoError(t, err) 79 80 expectMeta(t, metaCh, "loop-start") 81 82 advance(PerUserKeyUpgradeBackgroundSettings.Start - time.Second) 83 84 eng.Shutdown() 85 86 expectMeta(t, metaCh, "loop-exit") 87 88 advance(PerUserKeyUpgradeBackgroundSettings.Interval) 89 advance(PerUserKeyUpgradeBackgroundSettings.Interval) 90 91 expectMeta(t, metaCh, "") 92 } 93 94 // Shutting down after a few loop rounds should work. 95 // Also test that LoginRequired comes out when there is no user. 96 func TestPerUserKeyUpgradeBackgroundShutdownMiddle(t *testing.T) { 97 tc := SetupEngineTest(t, "pukup") 98 defer tc.Cleanup() 99 fakeClock := clockwork.NewFakeClockAt(time.Now()) 100 tc.G.SetClock(fakeClock) 101 102 advance := func(d time.Duration) { 103 tc.G.Log.Debug("+ fakeClock#advance(%s) start: %s", d, fakeClock.Now()) 104 fakeClock.Advance(d) 105 tc.G.Log.Debug("- fakeClock#adance(%s) end: %s", d, fakeClock.Now()) 106 } 107 108 metaCh := make(chan string, 100) 109 roundResCh := make(chan error, 100) 110 arg := &PerUserKeyUpgradeBackgroundArgs{ 111 testingMetaCh: metaCh, 112 testingRoundResCh: roundResCh, 113 } 114 eng := NewPerUserKeyUpgradeBackground(tc.G, arg) 115 eng.task.args.Settings.StartStagger = 0 // Disable stagger for deterministic testing 116 m := NewMetaContextForTestWithLogUI(tc) 117 err := RunEngine2(m, eng) 118 require.NoError(t, err) 119 120 expectMeta(t, metaCh, "loop-start") 121 advance(PerUserKeyUpgradeBackgroundSettings.Start + time.Second) 122 expectMeta(t, metaCh, "woke-start") 123 124 n := 3 125 for i := 0; i < n; i++ { 126 t.Logf("check %v", i) 127 select { 128 case x := <-roundResCh: 129 require.Equal(t, libkb.DeviceRequiredError{}, x, "round result") 130 case <-time.After(5 * time.Second): 131 require.FailNow(t, "channel timed out") 132 } 133 expectMeta(t, metaCh, "loop-round-complete") 134 if i < n-1 { 135 advance(PerUserKeyUpgradeBackgroundSettings.Interval + time.Second) 136 expectMeta(t, metaCh, "woke-interval") 137 advance(PerUserKeyUpgradeBackgroundSettings.WakeUp + time.Second) 138 expectMeta(t, metaCh, "woke-wakeup") 139 } 140 } 141 142 eng.Shutdown() 143 expectMeta(t, metaCh, "loop-exit") 144 145 for i := 0; i < 2; i++ { 146 advance(PerUserKeyUpgradeBackgroundSettings.Interval) 147 select { 148 case x := <-roundResCh: 149 require.FailNow(t, "unexpected", x) 150 default: 151 // expected 152 } 153 } 154 155 expectMeta(t, metaCh, "") 156 } 157 158 func TestPerUserKeyUpgradeBackgroundUnnecessary(t *testing.T) { 159 tc := SetupEngineTest(t, "pukup") 160 defer tc.Cleanup() 161 fakeClock := clockwork.NewFakeClockAt(time.Now()) 162 tc.G.SetClock(fakeClock) 163 164 _ = CreateAndSignupFakeUser(tc, "pukup") 165 166 t.Logf("user has a per-user-key") 167 checkPerUserKeyCount(&tc, 1) 168 169 advance := func(d time.Duration) { 170 tc.G.Log.Debug("+ fakeClock#advance(%s) start: %s", d, fakeClock.Now()) 171 fakeClock.Advance(d) 172 tc.G.Log.Debug("- fakeClock#adance(%s) end: %s", d, fakeClock.Now()) 173 } 174 175 metaCh := make(chan string, 100) 176 roundResCh := make(chan error, 100) 177 arg := &PerUserKeyUpgradeBackgroundArgs{ 178 testingMetaCh: metaCh, 179 testingRoundResCh: roundResCh, 180 } 181 eng := NewPerUserKeyUpgradeBackground(tc.G, arg) 182 eng.task.args.Settings.StartStagger = 0 // Disable stagger for deterministic testing 183 m := NewMetaContextForTestWithLogUI(tc) 184 err := RunEngine2(m, eng) 185 require.NoError(t, err) 186 187 expectMeta(t, metaCh, "loop-start") 188 advance(PerUserKeyUpgradeBackgroundSettings.Start + time.Second) 189 expectMeta(t, metaCh, "woke-start") 190 191 // first run doesn't do anything 192 select { 193 case x := <-roundResCh: 194 require.Equal(t, nil, x, "round result") 195 case <-time.After(5 * time.Second): 196 require.FailNow(t, "channel timed out") 197 } 198 expectMeta(t, metaCh, "loop-round-complete") 199 200 checkPerUserKeyCount(&tc, 1) 201 202 eng.Shutdown() 203 expectMeta(t, metaCh, "loop-exit") 204 expectMeta(t, metaCh, "") 205 } 206 207 // The normal case of upgrading a user 208 func TestPerUserKeyUpgradeBackgroundWork(t *testing.T) { 209 tc := SetupEngineTest(t, "pukup") 210 defer tc.Cleanup() 211 fakeClock := clockwork.NewFakeClockAt(time.Now()) 212 tc.G.SetClock(fakeClock) 213 214 tc.Tp.DisableUpgradePerUserKey = true 215 _ = CreateAndSignupFakeUser(tc, "pukup") 216 tc.Tp.DisableUpgradePerUserKey = false 217 218 t.Logf("user has no per-user-key") 219 checkPerUserKeyCount(&tc, 0) 220 221 advance := func(d time.Duration) { 222 tc.G.Log.Debug("+ fakeClock#advance(%s) start: %s", d, fakeClock.Now()) 223 fakeClock.Advance(d) 224 tc.G.Log.Debug("- fakeClock#adance(%s) end: %s", d, fakeClock.Now()) 225 } 226 227 metaCh := make(chan string, 100) 228 roundResCh := make(chan error, 100) 229 arg := &PerUserKeyUpgradeBackgroundArgs{ 230 testingMetaCh: metaCh, 231 testingRoundResCh: roundResCh, 232 } 233 eng := NewPerUserKeyUpgradeBackground(tc.G, arg) 234 eng.task.args.Settings.StartStagger = 0 // Disable stagger for deterministic testing 235 m := NewMetaContextForTestWithLogUI(tc) 236 err := RunEngine2(m, eng) 237 require.NoError(t, err) 238 239 expectMeta(t, metaCh, "loop-start") 240 advance(PerUserKeyUpgradeBackgroundSettings.Start + time.Second) 241 expectMeta(t, metaCh, "woke-start") 242 243 select { 244 case x := <-roundResCh: 245 require.Equal(t, nil, x, "round result") 246 case <-time.After(5 * time.Second): 247 require.FailNow(t, "channel timed out") 248 } 249 expectMeta(t, metaCh, "loop-round-complete") 250 251 // second run that doesn't do anything 252 advance(PerUserKeyUpgradeBackgroundSettings.Interval + time.Second) 253 expectMeta(t, metaCh, "woke-interval") 254 advance(PerUserKeyUpgradeBackgroundSettings.WakeUp + time.Second) 255 expectMeta(t, metaCh, "woke-wakeup") // this line has flaked before (CORE-5410) 256 select { 257 case x := <-roundResCh: 258 require.Equal(t, nil, x, "round result") 259 case <-time.After(5 * time.Second): 260 require.FailNow(t, "channel timed out") 261 } 262 expectMeta(t, metaCh, "loop-round-complete") 263 264 checkPerUserKeyCount(&tc, 1) 265 checkPerUserKeyCountLocal(&tc, 1) 266 267 eng.Shutdown() 268 expectMeta(t, metaCh, "loop-exit") 269 expectMeta(t, metaCh, "") 270 } 271 272 // The task should abort if the sigchain guard is taken. 273 func TestPerUserKeyUpgradeBackgroundYield(t *testing.T) { 274 tc := SetupEngineTest(t, "pukup") 275 defer tc.Cleanup() 276 fakeClock := clockwork.NewFakeClockAt(time.Now()) 277 tc.G.SetClock(fakeClock) 278 279 tc.Tp.DisableUpgradePerUserKey = true 280 _ = CreateAndSignupFakeUser(tc, "pukup") 281 tc.Tp.DisableUpgradePerUserKey = false 282 283 t.Logf("user has no per-user-key") 284 checkPerUserKeyCount(&tc, 0) 285 286 advance := func(d time.Duration) { 287 tc.G.Log.Debug("+ fakeClock#advance(%s) start: %s", d, fakeClock.Now()) 288 fakeClock.Advance(d) 289 tc.G.Log.Debug("- fakeClock#adance(%s) end: %s", d, fakeClock.Now()) 290 } 291 292 metaCh := make(chan string, 100) 293 roundResCh := make(chan error, 100) 294 arg := &PerUserKeyUpgradeBackgroundArgs{ 295 testingMetaCh: metaCh, 296 testingRoundResCh: roundResCh, 297 } 298 eng := NewPerUserKeyUpgradeBackground(tc.G, arg) 299 eng.task.args.Settings.StartStagger = 0 // Disable stagger for deterministic testing 300 m := NewMetaContextForTestWithLogUI(tc) 301 err := RunEngine2(m, eng) 302 require.NoError(t, err) 303 304 expectMeta(t, metaCh, "loop-start") 305 306 tc.G.LocalSigchainGuard().Set(m.Ctx(), "Test") 307 308 advance(PerUserKeyUpgradeBackgroundSettings.Start + time.Second) 309 expectMeta(t, metaCh, "woke-start") 310 311 // first round runs, but yields to the guard 312 select { 313 case x := <-roundResCh: 314 require.Equal(t, nil, x, "round result") 315 case <-time.After(5 * time.Second): 316 require.FailNow(t, "channel timed out") 317 } 318 expectMeta(t, metaCh, "loop-round-complete") 319 320 checkPerUserKeyCount(&tc, 0) 321 checkPerUserKeyCountLocal(&tc, 0) 322 323 // second round runs and works 324 tc.G.LocalSigchainGuard().Clear(m.Ctx(), "Test") 325 advance(PerUserKeyUpgradeBackgroundSettings.Interval + time.Second) 326 expectMeta(t, metaCh, "woke-interval") 327 advance(PerUserKeyUpgradeBackgroundSettings.WakeUp + time.Second) 328 expectMeta(t, metaCh, "woke-wakeup") // this line has flaked before (CORE-5410) 329 select { 330 case x := <-roundResCh: 331 require.Equal(t, nil, x, "round result") 332 case <-time.After(5 * time.Second): 333 require.FailNow(t, "channel timed out") 334 } 335 expectMeta(t, metaCh, "loop-round-complete") 336 337 checkPerUserKeyCount(&tc, 1) 338 checkPerUserKeyCountLocal(&tc, 1) 339 340 eng.Shutdown() 341 expectMeta(t, metaCh, "loop-exit") 342 expectMeta(t, metaCh, "") 343 } 344 345 // Test upgrading after running for a while and then logging in. 346 func TestPerUserKeyUpgradeBackgroundLoginLate(t *testing.T) { 347 tc := SetupEngineTest(t, "pukup") 348 defer tc.Cleanup() 349 fakeClock := clockwork.NewFakeClockAt(time.Now()) 350 tc.G.SetClock(fakeClock) 351 352 t.Logf("user has no per-user-key") 353 354 advance := func(d time.Duration) { 355 tc.G.Log.Debug("+ fakeClock#advance(%s) start: %s", d, fakeClock.Now()) 356 fakeClock.Advance(d) 357 tc.G.Log.Debug("- fakeClock#adance(%s) end: %s", d, fakeClock.Now()) 358 } 359 360 metaCh := make(chan string, 100) 361 roundResCh := make(chan error, 100) 362 arg := &PerUserKeyUpgradeBackgroundArgs{ 363 testingMetaCh: metaCh, 364 testingRoundResCh: roundResCh, 365 } 366 eng := NewPerUserKeyUpgradeBackground(tc.G, arg) 367 eng.task.args.Settings.StartStagger = 0 // Disable stagger for deterministic testing 368 m := NewMetaContextForTestWithLogUI(tc) 369 err := RunEngine2(m, eng) 370 require.NoError(t, err) 371 372 expectMeta(t, metaCh, "loop-start") 373 advance(PerUserKeyUpgradeBackgroundSettings.Start + time.Second) 374 expectMeta(t, metaCh, "woke-start") 375 376 t.Logf("run once while not logged in") 377 select { 378 case x := <-roundResCh: 379 require.Equal(t, libkb.DeviceRequiredError{}, x, "round result") 380 case <-time.After(5 * time.Second): 381 require.FailNow(t, "channel timed out") 382 } 383 expectMeta(t, metaCh, "loop-round-complete") 384 385 t.Logf("sign up and in") 386 tc.Tp.DisableUpgradePerUserKey = true 387 _ = CreateAndSignupFakeUser(tc, "pukup") 388 checkPerUserKeyCount(&tc, 0) 389 390 tc.Tp.DisableUpgradePerUserKey = false 391 392 t.Logf("second run upgrades the user") 393 advance(PerUserKeyUpgradeBackgroundSettings.Interval + time.Second) 394 expectMeta(t, metaCh, "woke-interval") 395 advance(PerUserKeyUpgradeBackgroundSettings.WakeUp + time.Second) 396 expectMeta(t, metaCh, "woke-wakeup") 397 select { 398 case x := <-roundResCh: 399 require.Equal(t, nil, x, "round result") 400 case <-time.After(5 * time.Second): 401 require.FailNow(t, "channel timed out") 402 } 403 expectMeta(t, metaCh, "loop-round-complete") 404 405 checkPerUserKeyCount(&tc, 1) 406 checkPerUserKeyCountLocal(&tc, 1) 407 408 eng.Shutdown() 409 expectMeta(t, metaCh, "loop-exit") 410 expectMeta(t, metaCh, "") 411 } 412 413 func expectMeta(t *testing.T, metaCh <-chan string, s string) { 414 t.Logf("expect meta: %q", s) 415 if s == "" { 416 // assert that there is nothing on the channel 417 // this can false-happy because it doesn't wait for the channel 418 select { 419 case x := <-metaCh: 420 require.FailNow(t, "unexpected", x) 421 default: 422 // expected 423 } 424 } else { 425 select { 426 case x := <-metaCh: 427 require.Equal(t, s, x) 428 case <-time.After(5 * time.Second): 429 require.FailNow(t, "channel timed out") 430 } 431 } 432 }