1// Copyright 2015 Keybase, Inc. All rights reserved. Use of
2// this source code is governed by the included BSD license.
3
4package systests
5
6import (
7	"fmt"
8	"os"
9	"path/filepath"
10	"testing"
11	"time"
12
13	"net/http"
14	_ "net/http/pprof"
15
16	"github.com/keybase/client/go/externalstest"
17	"github.com/keybase/client/go/libkb"
18	keybase1 "github.com/keybase/client/go/protocol/keybase1"
19	"github.com/keybase/clockwork"
20	"github.com/stretchr/testify/require"
21	context "golang.org/x/net/context"
22)
23
24func TestMain(m *testing.M) {
25	if os.Getenv("KEYBASE_SYSTESTS_DEBUG") != "" {
26		go func() {
27			_ = http.ListenAndServe("localhost:8080", nil)
28		}()
29	}
30	os.Exit(m.Run())
31}
32
33func setupTest(t libkb.TestingTB, nm string) *libkb.TestContext {
34	tc := externalstest.SetupTest(t, nm, 2)
35	installInsecureTriplesec(tc.G)
36	tc.SetRuntimeDir(filepath.Join(tc.Tp.Home, "run"))
37	if err := tc.G.ConfigureSocketInfo(); err != nil {
38		t.Fatal(err)
39	}
40	return &tc
41}
42
43func cloneContext(prev *libkb.TestContext) *libkb.TestContext {
44	ret := prev.Clone()
45	ret.SetRuntimeDir(filepath.Join(ret.Tp.Home, "run"))
46	if err := ret.G.ConfigureSocketInfo(); err != nil {
47		ret.T.Fatal(err)
48	}
49	return &ret
50}
51
52type baseNullUI struct {
53	g *libkb.GlobalContext
54}
55
56type dumbUI struct{}
57
58func (d dumbUI) Printf(format string, args ...interface{}) (int, error) {
59	return 0, nil
60}
61func (d dumbUI) PrintfStderr(format string, args ...interface{}) (int, error) {
62	return 0, nil
63}
64func (d dumbUI) PrintfUnescaped(format string, args ...interface{}) (int, error) {
65	return 0, nil
66}
67
68func (n *baseNullUI) GetDumbOutputUI() libkb.DumbOutputUI            { return dumbUI{} }
69func (n *baseNullUI) GetIdentifyUI() libkb.IdentifyUI                { return nil }
70func (n *baseNullUI) GetIdentifySelfUI() libkb.IdentifyUI            { return nil }
71func (n *baseNullUI) GetIdentifyTrackUI() libkb.IdentifyUI           { return nil }
72func (n *baseNullUI) GetLoginUI() libkb.LoginUI                      { return nil }
73func (n *baseNullUI) GetTerminalUI() libkb.TerminalUI                { return nil }
74func (n *baseNullUI) GetSecretUI() libkb.SecretUI                    { return nil }
75func (n *baseNullUI) GetProveUI() libkb.ProveUI                      { return nil }
76func (n *baseNullUI) GetGPGUI() libkb.GPGUI                          { return nil }
77func (n *baseNullUI) GetLogUI() libkb.LogUI                          { return n.g.Log }
78func (n *baseNullUI) GetPgpUI() libkb.PgpUI                          { return nil }
79func (n *baseNullUI) GetProvisionUI(libkb.KexRole) libkb.ProvisionUI { return nil }
80
81func (n *baseNullUI) Configure() error { return nil }
82func (n *baseNullUI) Shutdown() error  { return nil }
83
84type genericUI struct {
85	g               *libkb.GlobalContext
86	DumbOutputUI    libkb.DumbOutputUI
87	IdentifyUI      libkb.IdentifyUI
88	IdentifySelfUI  libkb.IdentifyUI
89	IdentifyTrackUI libkb.IdentifyUI
90	LoginUI         libkb.LoginUI
91	TerminalUI      libkb.TerminalUI
92	SecretUI        libkb.SecretUI
93	ProveUI         libkb.ProveUI
94	GPGUI           libkb.GPGUI
95	LogUI           libkb.LogUI
96	PgpUI           libkb.PgpUI
97	ProvisionUI     libkb.ProvisionUI
98}
99
100func (n *genericUI) GetDumbOutputUI() libkb.DumbOutputUI {
101	if n.DumbOutputUI == nil {
102		return dumbUI{}
103	}
104	return n.DumbOutputUI
105}
106func (n *genericUI) GetIdentifyUI() libkb.IdentifyUI      { return n.IdentifyUI }
107func (n *genericUI) GetIdentifySelfUI() libkb.IdentifyUI  { return n.IdentifyUI }
108func (n *genericUI) GetIdentifyTrackUI() libkb.IdentifyUI { return n.IdentifyUI }
109func (n *genericUI) GetLoginUI() libkb.LoginUI            { return n.LoginUI }
110func (n *genericUI) GetTerminalUI() libkb.TerminalUI      { return n.TerminalUI }
111func (n *genericUI) GetSecretUI() libkb.SecretUI          { return n.SecretUI }
112func (n *genericUI) GetProveUI() libkb.ProveUI            { return n.ProveUI }
113func (n *genericUI) GetGPGUI() libkb.GPGUI                { return n.GPGUI }
114func (n *genericUI) GetLogUI() libkb.LogUI {
115	if n.LogUI == nil {
116		return n.g.Log
117	}
118	return n.LogUI
119}
120func (n *genericUI) GetPgpUI() libkb.PgpUI                          { return n.PgpUI }
121func (n *genericUI) GetProvisionUI(libkb.KexRole) libkb.ProvisionUI { return n.ProvisionUI }
122
123func (n *genericUI) Configure() error { return nil }
124func (n *genericUI) Shutdown() error  { return nil }
125
126type nullProvisionUI struct {
127	deviceName string
128}
129
130func (n nullProvisionUI) ChooseProvisioningMethod(context.Context, keybase1.ChooseProvisioningMethodArg) (ret keybase1.ProvisionMethod, err error) {
131	return ret, nil
132}
133func (n nullProvisionUI) ChooseGPGMethod(context.Context, keybase1.ChooseGPGMethodArg) (ret keybase1.GPGMethod, err error) {
134	return ret, nil
135}
136func (n nullProvisionUI) SwitchToGPGSignOK(context.Context, keybase1.SwitchToGPGSignOKArg) (bool, error) {
137	return false, nil
138}
139func (n nullProvisionUI) ChooseDevice(context.Context, keybase1.ChooseDeviceArg) (ret keybase1.DeviceID, err error) {
140	return ret, nil
141}
142func (n nullProvisionUI) ChooseDeviceType(context.Context, keybase1.ChooseDeviceTypeArg) (ret keybase1.DeviceType, err error) {
143	return ret, nil
144}
145func (n nullProvisionUI) DisplayAndPromptSecret(context.Context, keybase1.DisplayAndPromptSecretArg) (ret keybase1.SecretResponse, err error) {
146	return ret, nil
147}
148func (n nullProvisionUI) DisplaySecretExchanged(context.Context, int) error { return nil }
149func (n nullProvisionUI) PromptNewDeviceName(context.Context, keybase1.PromptNewDeviceNameArg) (string, error) {
150	return n.deviceName, nil
151}
152func (n nullProvisionUI) ProvisioneeSuccess(context.Context, keybase1.ProvisioneeSuccessArg) error {
153	return nil
154}
155func (n nullProvisionUI) ProvisionerSuccess(context.Context, keybase1.ProvisionerSuccessArg) error {
156	return nil
157}
158
159func getActiveDevicesAndKeys(tc *libkb.TestContext, username string) ([]*libkb.Device, []libkb.GenericKey) {
160	arg := libkb.NewLoadUserByNameArg(tc.G, username).WithPublicKeyOptional()
161	user, err := libkb.LoadUser(arg)
162	if err != nil {
163		tc.T.Fatal(err)
164	}
165	sibkeys := user.GetComputedKeyFamily().GetAllActiveSibkeys()
166	subkeys := user.GetComputedKeyFamily().GetAllActiveSubkeys()
167
168	activeDevices := []*libkb.Device{}
169	for _, device := range user.GetComputedKeyFamily().GetAllDevices() {
170		if device.Status != nil && *device.Status == libkb.DeviceStatusActive {
171			activeDevices = append(activeDevices, device.Device)
172		}
173	}
174	return activeDevices, append(sibkeys, subkeys...)
175}
176
177func pollFor(t *testing.T, label string, totalTime time.Duration, g *libkb.GlobalContext, poller func(i int) bool) {
178	t.Logf("pollFor '%s'", label)
179	totalTime *= libkb.CITimeMultiplier(g)
180	clock := clockwork.NewRealClock()
181	start := clock.Now()
182	endCh := clock.After(totalTime)
183	wait := 10 * time.Millisecond
184	var i int
185	for {
186		satisfied := poller(i)
187		since := clock.Since(start)
188		t.Logf("pollFor '%s' round:%v -> %v running:%v", label, i, satisfied, since)
189		if satisfied {
190			t.Logf("pollFor '%s' succeeded after %v attempts over %v", label, i, since)
191			return
192		}
193		if since > totalTime {
194			// Game over
195			msg := fmt.Sprintf("pollFor '%s' timed out after %v attempts over %v", label, i, since)
196			t.Logf(msg)
197			require.Fail(t, msg)
198			require.FailNow(t, msg)
199			return
200		}
201		t.Logf("pollFor '%s' wait:%v", label, wait)
202		select {
203		case <-endCh:
204		case <-clock.After(wait):
205		}
206		wait *= 2
207		i++
208	}
209}
210