github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/engine/soft_snooze_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  	"strings"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/keybase/client/go/libkb"
    12  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    13  	"github.com/keybase/clockwork"
    14  )
    15  
    16  type flakeyRooterAPI struct {
    17  	orig     libkb.ExternalAPI
    18  	flakeOut bool
    19  	hardFail bool
    20  	G        *libkb.GlobalContext
    21  }
    22  
    23  func (e *flakeyRooterAPI) GetText(m libkb.MetaContext, arg libkb.APIArg) (*libkb.ExternalTextRes, error) {
    24  	e.G.Log.Debug("| flakeyRooterAPI.GetText, hard = %v, flake = %v", e.hardFail, e.flakeOut)
    25  	return e.orig.GetText(m, arg)
    26  }
    27  
    28  func (e *flakeyRooterAPI) Get(m libkb.MetaContext, arg libkb.APIArg) (res *libkb.ExternalAPIRes, err error) {
    29  	e.G.Log.Debug("| flakeyRooterAPI.Get, hard = %v, flake = %v", e.hardFail, e.flakeOut)
    30  	// Show an error if we're in flakey mode
    31  	if strings.Contains(arg.Endpoint, "rooter") {
    32  		if e.hardFail {
    33  			return &libkb.ExternalAPIRes{HTTPStatus: 404}, &libkb.APIError{Msg: "NotFound", Code: 404}
    34  		}
    35  		if e.flakeOut {
    36  			return &libkb.ExternalAPIRes{HTTPStatus: 429}, &libkb.APIError{Msg: "Ratelimited", Code: 429}
    37  		}
    38  	}
    39  
    40  	return e.orig.Get(m, arg)
    41  }
    42  
    43  func (e *flakeyRooterAPI) GetHTML(m libkb.MetaContext, arg libkb.APIArg) (res *libkb.ExternalHTMLRes, err error) {
    44  	e.G.Log.Debug("| flakeyRooterAPI.GetHTML, hard = %v, flake = %v", e.hardFail, e.flakeOut)
    45  	return e.orig.GetHTML(m, arg)
    46  }
    47  
    48  func (e *flakeyRooterAPI) Post(m libkb.MetaContext, arg libkb.APIArg) (res *libkb.ExternalAPIRes, err error) {
    49  	return e.orig.Post(m, arg)
    50  }
    51  
    52  func (e *flakeyRooterAPI) PostHTML(m libkb.MetaContext, arg libkb.APIArg) (res *libkb.ExternalHTMLRes, err error) {
    53  	return e.orig.PostHTML(m, arg)
    54  }
    55  
    56  func TestSoftSnooze(t *testing.T) {
    57  	tc := SetupEngineTest(t, "track")
    58  	defer tc.Cleanup()
    59  	sigVersion := libkb.GetDefaultSigVersion(tc.G)
    60  
    61  	fakeClock := clockwork.NewFakeClockAt(time.Now())
    62  	tc.G.SetClock(fakeClock)
    63  	fu := CreateAndSignupFakeUser(tc, "track")
    64  
    65  	flakeyAPI := flakeyRooterAPI{orig: tc.G.XAPI, flakeOut: false, G: tc.G}
    66  	tc.G.XAPI = &flakeyAPI
    67  
    68  	idUI := &FakeIdentifyUI{}
    69  	username := "t_tracy"
    70  	arg := &keybase1.Identify2Arg{
    71  		UserAssertion:    username,
    72  		NeedProofSet:     true,
    73  		IdentifyBehavior: keybase1.TLFIdentifyBehavior_CLI,
    74  	}
    75  	uis := libkb.UIs{
    76  		LogUI:      tc.G.UI.GetLogUI(),
    77  		IdentifyUI: idUI,
    78  		SecretUI:   fu.NewSecretUI(),
    79  	}
    80  	// Identify tracy; all proofs should work
    81  	eng := NewResolveThenIdentify2(tc.G, arg)
    82  	m := NewMetaContextForTest(tc).WithUIs(uis)
    83  	if err := RunEngine2(m, eng); err != nil {
    84  		t.Fatal(err)
    85  	}
    86  	sv := keybase1.SigVersion(sigVersion)
    87  	targ := TrackTokenArg{
    88  		Token:   idUI.Token,
    89  		Options: keybase1.TrackOptions{BypassConfirm: true, SigVersion: &sv},
    90  	}
    91  
    92  	// Track tracy
    93  	teng := NewTrackToken(tc.G, &targ)
    94  	if err := RunEngine2(m, teng); err != nil {
    95  		t.Fatal(err)
    96  	}
    97  
    98  	defer func() { _ = runUntrack(tc, fu, username, sigVersion) }()
    99  
   100  	// Now make her Rooter proof flakey / fail with a 429
   101  	flakeyAPI.flakeOut = true
   102  	idUI = &FakeIdentifyUI{}
   103  	m = m.WithIdentifyUI(idUI)
   104  
   105  	// Advance so that our previous cached success is out of
   106  	// cache on its own, but still can override a 429-like soft failure.
   107  	fakeClock.Advance(tc.G.Env.GetProofCacheMediumDur() + time.Minute)
   108  
   109  	eng = NewResolveThenIdentify2(tc.G, arg)
   110  	eng.testArgs = &Identify2WithUIDTestArgs{noCache: true}
   111  	// Should not get an error
   112  	if err := RunEngine2(m, eng); err != nil {
   113  		t.Fatal(err)
   114  	}
   115  	result, found := idUI.ProofResults["rooter"]
   116  	if !found {
   117  		t.Fatal("Failed to find a rooter proof")
   118  	}
   119  	if pe := libkb.ImportProofError(result.SnoozedResult); pe == nil {
   120  		t.Fatal("expected a snoozed error result")
   121  	}
   122  
   123  	// Now time out the success that allowed us to circumvent
   124  	// the soft failure.
   125  	fakeClock.Advance(tc.G.Env.GetProofCacheLongDur())
   126  	eng = NewResolveThenIdentify2(tc.G, arg)
   127  	eng.testArgs = &Identify2WithUIDTestArgs{noCache: true}
   128  	idUI = &FakeIdentifyUI{}
   129  	m = m.WithIdentifyUI(idUI)
   130  	if err := RunEngine2(m, eng); err == nil {
   131  		t.Fatal("Expected a failure in our proof")
   132  	}
   133  
   134  	result, found = idUI.ProofResults["rooter"]
   135  	if !found {
   136  		t.Fatal("Failed to find a rooter proof")
   137  	}
   138  	if pe := libkb.ImportProofError(result.ProofResult); pe == nil {
   139  		t.Fatal("expected a Rooter error result")
   140  	}
   141  	if !idUI.BrokenTracking {
   142  		t.Fatal("expected broken tracking!")
   143  	}
   144  
   145  	assertTracking(tc, username)
   146  }