github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/engine/list_tracking_test.go (about)

     1  // Copyright 2015 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  	"errors"
     8  	"fmt"
     9  	"net/http"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/keybase/client/go/libkb"
    14  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    15  	"github.com/keybase/clockwork"
    16  	jsonw "github.com/keybase/go-jsonw"
    17  	"github.com/stretchr/testify/require"
    18  )
    19  
    20  func TestListTracking(t *testing.T) {
    21  	doWithSigChainVersions(func(sigVersion libkb.SigVersion) {
    22  		_testListTracking(t, sigVersion)
    23  	})
    24  }
    25  
    26  func _verifyListTrackingEntries(entries []keybase1.UserSummary) error {
    27  	if len(entries) != 2 {
    28  		return fmt.Errorf("Num tracks: %d, exected 2.", len(entries))
    29  	}
    30  
    31  	alice := entries[0]
    32  	if alice.Username != "t_alice" {
    33  		return fmt.Errorf("Username: %q, Expected t_alice.", alice.Username)
    34  	}
    35  	bob := entries[1]
    36  	if bob.Username != "t_bob" {
    37  		return fmt.Errorf("Username: %q, Expected t_bob.", bob.Username)
    38  	}
    39  
    40  	return nil
    41  }
    42  
    43  func _testListTracking(t *testing.T, sigVersion libkb.SigVersion) {
    44  	tc := SetupEngineTest(t, "track")
    45  	defer tc.Cleanup()
    46  	fu := CreateAndSignupFakeUser(tc, "track")
    47  	fu.LoginOrBust(tc)
    48  
    49  	trackAlice(tc, fu, sigVersion)
    50  	trackBob(tc, fu, sigVersion)
    51  	defer untrackAlice(tc, fu, sigVersion)
    52  	defer untrackBob(tc, fu, sigVersion)
    53  
    54  	// Perform a proof to make sure that the last item of the chain isn't a track
    55  	proveUI, _, err := proveRooter(tc.G, fu, sigVersion)
    56  	require.NoError(t, err)
    57  	require.False(t, proveUI.overwrite)
    58  	require.False(t, proveUI.warning)
    59  	require.False(t, proveUI.recheck)
    60  	require.True(t, proveUI.checked)
    61  
    62  	eng := NewListTrackingEngine(tc.G, &ListTrackingEngineArg{})
    63  	if err := RunEngine2(NewMetaContextForTest(tc), eng); err != nil {
    64  		t.Fatal("Error in ListTrackingEngine:", err)
    65  	}
    66  	if err := _verifyListTrackingEntries(eng.TableResult().Users); err != nil {
    67  		t.Fatal("Error in tracking engine result entries verification:", err)
    68  	}
    69  
    70  	// We're running this again using a different, non-signed-in cache to test
    71  	// the manual stubbing override.
    72  	tc2 := SetupEngineTest(t, "track-anonymous")
    73  	defer tc2.Cleanup()
    74  
    75  	eng = NewListTrackingEngine(tc2.G, &ListTrackingEngineArg{
    76  		Assertion: fu.Username,
    77  	})
    78  	if err := RunEngine2(NewMetaContextForTest(tc2), eng); err != nil {
    79  		t.Fatal("Error in ListTrackingEngine:", err)
    80  	}
    81  	if err := _verifyListTrackingEntries(eng.TableResult().Users); err != nil {
    82  		t.Fatal("Error in tracking engine result entries verification:", err)
    83  	}
    84  }
    85  
    86  func TestListTrackingJSON(t *testing.T) {
    87  	tc := SetupEngineTest(t, "track")
    88  	defer tc.Cleanup()
    89  	sigVersion := libkb.GetDefaultSigVersion(tc.G)
    90  	fu := CreateAndSignupFakeUser(tc, "track")
    91  	fu.LoginOrBust(tc)
    92  
    93  	trackAlice(tc, fu, sigVersion)
    94  	defer untrackAlice(tc, fu, sigVersion)
    95  
    96  	arg := ListTrackingEngineArg{JSON: true, Verbose: true}
    97  	eng := NewListTrackingEngine(tc.G, &arg)
    98  	m := NewMetaContextForTest(tc)
    99  	err := RunEngine2(m, eng)
   100  	if err != nil {
   101  		t.Fatal("Error in ListTrackingEngine:", err)
   102  	}
   103  
   104  	_, err = jsonw.Unmarshal([]byte(eng.JSONResult()))
   105  	if err != nil {
   106  		t.Fatal(err)
   107  	}
   108  }
   109  
   110  func TestListTrackingLocal(t *testing.T) {
   111  	t.Skip("Skipping test for local tracks in list tracking (milestone 2)")
   112  	tc := SetupEngineTest(t, "track")
   113  	defer tc.Cleanup()
   114  	sigVersion := libkb.GetDefaultSigVersion(tc.G)
   115  	fu := CreateAndSignupFakeUser(tc, "track")
   116  
   117  	trackAlice(tc, fu, sigVersion)
   118  	defer untrackAlice(tc, fu, sigVersion)
   119  
   120  	sv := keybase1.SigVersion(sigVersion)
   121  	trackBobWithOptions(tc, fu, keybase1.TrackOptions{LocalOnly: true, SigVersion: &sv}, fu.NewSecretUI())
   122  	defer untrackBob(tc, fu, sigVersion)
   123  
   124  	arg := ListTrackingEngineArg{}
   125  	eng := NewListTrackingEngine(tc.G, &arg)
   126  	m := NewMetaContextForTest(tc)
   127  	err := RunEngine2(m, eng)
   128  	if err != nil {
   129  		t.Fatal("Error in ListTrackingEngine:", err)
   130  	}
   131  
   132  	entries := eng.TableResult().Users
   133  	if len(entries) != 2 {
   134  		t.Errorf("Num tracks: %d, exected 2", len(entries))
   135  	}
   136  }
   137  
   138  func TestListTrackingServerInterference(t *testing.T) {
   139  	atc := SetupEngineTest(t, "track")
   140  	defer atc.Cleanup()
   141  	btc := SetupEngineTest(t, "track")
   142  	defer btc.Cleanup()
   143  	ctc := SetupEngineTest(t, "track")
   144  	defer ctc.Cleanup()
   145  	sigVersion := libkb.GetDefaultSigVersion(atc.G)
   146  
   147  	alice := CreateAndSignupFakeUser(atc, "track")
   148  	bob := CreateAndSignupFakeUser(btc, "track")
   149  	charlie := CreateAndSignupFakeUser(ctc, "track")
   150  	alice.LoginOrBust(atc)
   151  
   152  	_, _, err := runTrack(atc, alice, bob.Username, sigVersion)
   153  	require.NoError(t, err)
   154  
   155  	eng := NewListTrackingEngine(atc.G, &ListTrackingEngineArg{})
   156  	if err := RunEngine2(NewMetaContextForTest(atc), eng); err != nil {
   157  		t.Fatal("Error in ListTrackingEngine:", err)
   158  	}
   159  	found := false
   160  	for _, user := range eng.TableResult().Users {
   161  		if user.Username == bob.Username {
   162  			found = true
   163  		}
   164  	}
   165  	if !found {
   166  		t.Fatalf("expected to be following bob, but wasn't")
   167  	}
   168  
   169  	ResetAccount(btc, bob)
   170  
   171  	// (MD/TRIAGE-1837) Due to a server bug, it seems the follow version doesn't
   172  	// update immediately on resets, only on the next follow, so we're not
   173  	// going to get the proper filtration until we bump it e.g. by following
   174  	// another random user.
   175  	_, _, err = runTrack(atc, alice, charlie.Username, sigVersion)
   176  	require.NoError(t, err)
   177  
   178  	eng = NewListTrackingEngine(atc.G, &ListTrackingEngineArg{})
   179  	if err := RunEngine2(NewMetaContextForTest(atc), eng); err != nil {
   180  		t.Fatal("Error in ListTrackingEngine:", err)
   181  	}
   182  	found = false
   183  	for _, user := range eng.TableResult().Users {
   184  		if user.Username == bob.Username {
   185  			found = true
   186  		}
   187  	}
   188  	if found {
   189  		t.Fatalf("expected server to filter out reset bob, but didn't; still following after reset")
   190  	}
   191  
   192  	eng = NewListTrackingEngine(atc.G, &ListTrackingEngineArg{})
   193  	eng.disableTrackerSyncerForTest = true
   194  	if err := RunEngine2(NewMetaContextForTest(atc), eng); err != nil {
   195  		t.Fatal("Error in ListTrackingEngine:", err)
   196  	}
   197  	found = false
   198  	for _, user := range eng.TableResult().Users {
   199  		if user.Username == bob.Username {
   200  			found = true
   201  		}
   202  	}
   203  	if !found {
   204  		t.Fatalf("tracker syncer returned error; so we should still succeed but not filter")
   205  	}
   206  }
   207  
   208  type errorAPIMock struct {
   209  	*libkb.APIArgRecorder
   210  	callCount int
   211  }
   212  
   213  func (r *errorAPIMock) GetDecode(mctx libkb.MetaContext, arg libkb.APIArg, w libkb.APIResponseWrapper) error {
   214  	r.callCount++
   215  	return errors.New("timeout or something")
   216  }
   217  
   218  func (r *errorAPIMock) GetResp(mctx libkb.MetaContext, arg libkb.APIArg) (*http.Response, func(), error) {
   219  	r.callCount++
   220  	return nil, func() {}, errors.New("timeout or something")
   221  }
   222  
   223  func (r *errorAPIMock) Get(mctx libkb.MetaContext, arg libkb.APIArg) (*libkb.APIRes, error) {
   224  	r.callCount++
   225  	return nil, errors.New("timeout or something")
   226  }
   227  
   228  func TestListTrackingOfflineBehavior(t *testing.T) {
   229  	atc := SetupEngineTest(t, "track")
   230  	defer atc.Cleanup()
   231  	btc := SetupEngineTest(t, "track")
   232  	defer btc.Cleanup()
   233  	ctc := SetupEngineTest(t, "track")
   234  	defer ctc.Cleanup()
   235  	sigVersion := libkb.GetDefaultSigVersion(atc.G)
   236  
   237  	alice := CreateAndSignupFakeUser(atc, "track")
   238  	bob := CreateAndSignupFakeUser(btc, "track")
   239  	charlie := CreateAndSignupFakeUser(ctc, "track")
   240  	alice.LoginOrBust(atc)
   241  
   242  	_, _, err := runTrack(atc, alice, bob.Username, sigVersion)
   243  	require.NoError(t, err)
   244  
   245  	// Prime UPAK and TrackerSyncer caches when online
   246  	eng := NewListTrackingEngine(atc.G, &ListTrackingEngineArg{})
   247  	if err := RunEngine2(NewMetaContextForTest(atc), eng); err != nil {
   248  		t.Fatal("Error in ListTrackingEngine:", err)
   249  	}
   250  	res1 := eng.TableResult()
   251  
   252  	// realAPI := atc.G.API
   253  	fakeAPI := &errorAPIMock{}
   254  	atc.G.API = fakeAPI
   255  
   256  	// We're offline now
   257  	_, _, err = runTrack(atc, alice, charlie.Username, sigVersion)
   258  	require.Error(t, err)
   259  	require.Contains(t, err.Error(), "timeout or something")
   260  
   261  	c := clockwork.NewFakeClockAt(atc.G.Clock().Now())
   262  	atc.G.SetClock(c)
   263  
   264  	t.Logf("Test CachedOnly")
   265  	// But ListTracking with CachedOnly=true should still work.
   266  	eng = NewListTrackingEngine(atc.G, &ListTrackingEngineArg{CachedOnly: true})
   267  	err = RunEngine2(NewMetaContextForTest(atc), eng)
   268  	require.NoError(t, err)
   269  	res2 := eng.TableResult()
   270  	require.Equal(t, res1, res2, "got same results even when offline")
   271  
   272  	staleness := time.Hour * 24 * 7
   273  	t.Logf("Test offline 1 day later")
   274  	// Should work even if we're still offline 1 day later (longer than the 10
   275  	// minute UPAK staleness window), if CachedOnlyStalenessWindow passed.
   276  	stalenesseng := NewListTrackingEngine(atc.G, &ListTrackingEngineArg{CachedOnly: true, CachedOnlyStalenessWindow: &staleness})
   277  	c.Advance(time.Hour * 24)
   278  	err = RunEngine2(NewMetaContextForTest(atc), stalenesseng)
   279  	require.NoError(t, err)
   280  
   281  	t.Logf("Should return an error past the staleness window")
   282  	c.Advance(time.Hour * 24 * 8)
   283  	err = RunEngine2(NewMetaContextForTest(atc), stalenesseng)
   284  	require.Error(t, err)
   285  	require.IsType(t, err, libkb.UserNotFoundError{})
   286  }