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 }