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

     1  // Copyright 2018 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  	"encoding/hex"
     8  	"testing"
     9  
    10  	"github.com/keybase/client/go/libkb"
    11  	"github.com/stretchr/testify/require"
    12  )
    13  
    14  func persistDeviceCloneState(m libkb.MetaContext, d libkb.DeviceCloneState) error {
    15  	return libkb.SetDeviceCloneState(m, d)
    16  }
    17  
    18  func runAndGetDeviceCloneState(m libkb.MetaContext) (d libkb.DeviceCloneState, err error) {
    19  	_, _, err = libkb.UpdateDeviceCloneState(m)
    20  	if err != nil {
    21  		return d, err
    22  	}
    23  	d, _ = libkb.GetDeviceCloneState(m)
    24  	return d, err
    25  }
    26  
    27  func assertIsValidToken(tc libkb.TestContext, token string) {
    28  	_, err := hex.DecodeString(token)
    29  	require.NoError(tc.T, err)
    30  	require.Equal(tc.T, len(token), 32)
    31  }
    32  
    33  func assertSuccessfulRun(tc libkb.TestContext, d libkb.DeviceCloneState, err error) {
    34  	require.NoError(tc.T, err)
    35  	require.Equal(tc.T, d.Stage, "")
    36  	assertIsValidToken(tc, d.Prior)
    37  }
    38  
    39  func TestDeviceCloneStateFirstRun(t *testing.T) {
    40  	tc := SetupEngineTest(t, "DeviceCloneState")
    41  	defer tc.Cleanup()
    42  	_ = CreateAndSignupFakeUser(tc, "fu")
    43  	m := NewMetaContextForTest(tc)
    44  
    45  	d, err := runAndGetDeviceCloneState(m)
    46  	assertSuccessfulRun(tc, d, err)
    47  	require.Equal(tc.T, d.Clones, 1)
    48  }
    49  
    50  func TestDeviceCloneStateSuccessfulUpdate(t *testing.T) {
    51  	tc := SetupEngineTest(t, "DeviceCloneState")
    52  	defer tc.Cleanup()
    53  	_ = CreateAndSignupFakeUser(tc, "fu")
    54  	m := NewMetaContextForTest(tc)
    55  	//setup: perform an initial run
    56  	d0, err := runAndGetDeviceCloneState(m)
    57  	require.NoError(tc.T, err)
    58  
    59  	d, err := runAndGetDeviceCloneState(m)
    60  	assertSuccessfulRun(tc, d, err)
    61  	require.NotEqual(tc.T, d.Prior, d0.Prior)
    62  	require.Equal(tc.T, d.Clones, 1)
    63  }
    64  
    65  func TestDeviceCloneStateRecoveryFromFailureBeforeServer(t *testing.T) {
    66  	tc := SetupEngineTest(t, "DeviceCloneState")
    67  	defer tc.Cleanup()
    68  	_ = CreateAndSignupFakeUser(tc, "fu")
    69  	m := NewMetaContextForTest(tc)
    70  	// setup: persist tokens as if the process failed
    71  	// before the server received the update
    72  	d0 := libkb.DeviceCloneState{
    73  		Prior:  libkb.DefaultCloneTokenValue,
    74  		Stage:  "22222222222222222222222222222222",
    75  		Clones: 1,
    76  	}
    77  	err := persistDeviceCloneState(m, d0)
    78  	require.NoError(t, err)
    79  
    80  	d, err := runAndGetDeviceCloneState(m)
    81  	assertSuccessfulRun(tc, d, err)
    82  	require.Equal(tc.T, d.Prior, d0.Stage)
    83  	require.Equal(tc.T, d.Clones, 1)
    84  }
    85  
    86  func TestDeviceCloneStateRecoveryFromFailureAfterServer(t *testing.T) {
    87  	tc := SetupEngineTest(t, "DeviceCloneState")
    88  	defer tc.Cleanup()
    89  	_ = CreateAndSignupFakeUser(tc, "fu")
    90  	m := NewMetaContextForTest(tc)
    91  	// setup: run twice. then reset the persistence to where it would have been
    92  	// if the server got the second update but did not ack it successfully to the client.
    93  	d0, err := runAndGetDeviceCloneState(m)
    94  	require.NoError(t, err)
    95  	d1, err := runAndGetDeviceCloneState(m)
    96  	require.NoError(t, err)
    97  	tmp := libkb.DeviceCloneState{Prior: d0.Prior, Stage: d1.Prior, Clones: 1}
    98  	err = persistDeviceCloneState(m, tmp)
    99  	require.NoError(t, err)
   100  
   101  	d, err := runAndGetDeviceCloneState(m)
   102  	assertSuccessfulRun(tc, d, err)
   103  	require.Equal(tc.T, d.Prior, d1.Prior)
   104  	require.Equal(tc.T, d.Clones, 1)
   105  }
   106  
   107  func TestDeviceCloneStateCloneDetected(t *testing.T) {
   108  	tc := SetupEngineTest(t, "DeviceCloneState")
   109  	defer tc.Cleanup()
   110  	_ = CreateAndSignupFakeUser(tc, "fu")
   111  	m := NewMetaContextForTest(tc)
   112  	// setup: perform two runs, and then manually persist the earlier
   113  	// prior token to simulate a subsequent run by a cloned device
   114  	d0, err := runAndGetDeviceCloneState(m)
   115  	require.NoError(tc.T, err)
   116  	_, err = runAndGetDeviceCloneState(m)
   117  	require.NoError(tc.T, err)
   118  	err = persistDeviceCloneState(m, d0)
   119  	require.NoError(t, err)
   120  
   121  	before, after, err := libkb.UpdateDeviceCloneState(m)
   122  	require.NoError(t, err)
   123  
   124  	d, err := libkb.GetDeviceCloneState(m)
   125  	assertSuccessfulRun(tc, d, err)
   126  	require.NotEqual(tc.T, d.Prior, d0.Stage, "despite there being a clone, the prior still needs to change")
   127  	require.Equal(tc.T, d.Clones, 2)
   128  	require.Equal(tc.T, before, 1, "there was one clone before the test run")
   129  	require.Equal(tc.T, after, 2, "there were two clones after the test run")
   130  }
   131  
   132  func TestDeviceCloneStateBeforeAndAfterOnFirstRun(t *testing.T) {
   133  	tc := SetupEngineTest(t, "DeviceCloneState")
   134  	defer tc.Cleanup()
   135  	_ = CreateAndSignupFakeUser(tc, "fu")
   136  	m := NewMetaContextForTest(tc)
   137  
   138  	before, after, err := libkb.UpdateDeviceCloneState(m)
   139  	require.NoError(tc.T, err)
   140  	require.Equal(tc.T, before, 1, "there was one clone before the test run")
   141  	require.Equal(tc.T, after, 1, "there was one clone after the test run")
   142  }