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  }