ipn/ipnlocal: switch from testify to quicktest

Per discussion, we want to have only one test assertion library,
and we want to start by exploring quicktest.

This was a mostly mechanical translation.
I think we could make this nicer by defining a few helper
closures at the beginning of the test. Later.

Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
This commit is contained in:
Josh Bleecher Snyder 2021-04-30 14:47:16 -07:00
parent 90002be6c0
commit 96ef8d34ef
3 changed files with 138 additions and 144 deletions

4
go.mod
View File

@ -7,12 +7,13 @@ require (
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 // indirect
github.com/coreos/go-iptables v0.4.5
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect
github.com/frankban/quicktest v1.12.1
github.com/github/certstore v0.1.0
github.com/gliderlabs/ssh v0.2.2
github.com/go-multierror/multierror v1.0.2
github.com/go-ole/go-ole v1.2.4
github.com/godbus/dbus/v5 v5.0.3
github.com/google/go-cmp v0.5.4
github.com/google/go-cmp v0.5.5
github.com/goreleaser/nfpm v1.1.10
github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
@ -24,7 +25,6 @@ require (
github.com/pborman/getopt v0.0.0-20190409184431-ee0cd42419d3
github.com/peterbourgon/ff/v2 v2.0.0
github.com/pkg/errors v0.9.1 // indirect
github.com/stretchr/testify v1.4.0
github.com/tailscale/depaware v0.0.0-20201214215404-77d1e9757027
github.com/tailscale/wireguard-go v0.0.0-20210429195722-6cd106ab1339
github.com/tcnksm/go-httpstat v0.2.0

6
go.sum
View File

@ -25,6 +25,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/dvyukov/go-fuzz v0.0.0-20201127111758-49e582c6c23d/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/frankban/quicktest v1.12.1 h1:P6vQcHwZYgVGIpUzKB5DXzkEeYJppJOStPLuh9aB89c=
github.com/frankban/quicktest v1.12.1/go.mod h1:qLE0fzW0VuyUAJgPU19zByoIr0HtCHN/r/VLSOOIySU=
github.com/github/fakeca v0.1.0 h1:Km/MVOFvclqxPM9dZBC4+QE564nU4gz4iZ0D9pMw28I=
github.com/github/fakeca v0.1.0/go.mod h1:+bormgoGMMuamOscx7N91aOuUST7wdaJ2rNjeohylyo=
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
@ -44,6 +46,8 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/rpmpack v0.0.0-20191226140753-aa36bfddb3a0 h1:BW6OvS3kpT5UEPbCZ+KyX/OB4Ks9/MNMhWjqPPkZxsE=
github.com/google/rpmpack v0.0.0-20191226140753-aa36bfddb3a0/go.mod h1:RaTPr0KUf2K7fnZYLNDrr8rxAamWs3iNywJLtQ2AzBg=
@ -68,6 +72,8 @@ github.com/klauspost/compress v1.10.10 h1:a/y8CglcM7gLGYmlbP/stPE5sR3hbhFRUjCBfd
github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8 h1:AkaSdXYQOWeaO3neb8EM634ahkXXe3jYbVh/F9lq+GI=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=

View File

@ -10,7 +10,7 @@
"testing"
"time"
"github.com/stretchr/testify/assert"
qt "github.com/frankban/quicktest"
"tailscale.com/control/controlclient"
"tailscale.com/ipn"
@ -268,7 +268,7 @@ func (cc *mockControl) UpdateEndpoints(localPort uint16, endpoints []tailcfg.End
// predictable, but maybe a bit less thorough. This is more of an overall
// state machine test than a test of the wgengine+magicsock integration.
func TestStateMachine(t *testing.T) {
assert := assert.New(t)
c := qt.New(t)
logf := t.Logf
store := new(ipn.MemoryStore)
@ -312,32 +312,30 @@ func TestStateMachine(t *testing.T) {
// Check that it hasn't called us right away.
// The state machine should be idle until we call Start().
assert.Equal(cc.getCalls(), []string{})
c.Assert(cc.getCalls(), qt.HasLen, 0)
// Start the state machine.
// Since !WantRunning by default, it'll create a controlclient,
// but not ask it to do anything yet.
t.Logf("\n\nStart")
notifies.expect(2)
assert.Nil(b.Start(ipn.Options{
StateKey: ipn.GlobalDaemonStateKey,
}))
c.Assert(b.Start(ipn.Options{StateKey: ipn.GlobalDaemonStateKey}), qt.IsNil)
{
// BUG: strictly, it should pause, not unpause, here, since !WantRunning.
assert.Equal([]string{"New", "unpause"}, cc.getCalls())
c.Assert([]string{"New", "unpause"}, qt.DeepEquals, cc.getCalls())
nn := notifies.drain(2)
assert.Equal([]string{}, cc.getCalls())
assert.NotNil(nn[0].Prefs)
assert.NotNil(nn[1].State)
c.Assert(cc.getCalls(), qt.HasLen, 0)
c.Assert(nn[0].Prefs, qt.Not(qt.IsNil))
c.Assert(nn[1].State, qt.Not(qt.IsNil))
prefs := *nn[0].Prefs
// Note: a totally fresh system has Prefs.LoggedOut=false by
// default. We are logged out, but not because the user asked
// for it, so it doesn't count as Prefs.LoggedOut==true.
assert.Equal(false, nn[0].Prefs.LoggedOut)
assert.Equal(false, prefs.WantRunning)
assert.Equal(ipn.NeedsLogin, *nn[1].State)
assert.Equal(ipn.NeedsLogin, b.State())
c.Assert(nn[0].Prefs.LoggedOut, qt.IsFalse)
c.Assert(prefs.WantRunning, qt.IsFalse)
c.Assert(ipn.NeedsLogin, qt.Equals, *nn[1].State)
c.Assert(ipn.NeedsLogin, qt.Equals, b.State())
}
// Restart the state machine.
@ -346,21 +344,19 @@ func TestStateMachine(t *testing.T) {
// events as the first time, so UIs always know what to expect.
t.Logf("\n\nStart2")
notifies.expect(2)
assert.Nil(b.Start(ipn.Options{
StateKey: ipn.GlobalDaemonStateKey,
}))
c.Assert(b.Start(ipn.Options{StateKey: ipn.GlobalDaemonStateKey}), qt.IsNil)
{
// BUG: strictly, it should pause, not unpause, here, since !WantRunning.
assert.Equal([]string{"Shutdown", "New", "unpause"}, cc.getCalls())
c.Assert([]string{"Shutdown", "New", "unpause"}, qt.DeepEquals, cc.getCalls())
nn := notifies.drain(2)
assert.Equal([]string{}, cc.getCalls())
assert.NotNil(nn[0].Prefs)
assert.NotNil(nn[1].State)
assert.Equal(false, nn[0].Prefs.LoggedOut)
assert.Equal(false, nn[0].Prefs.WantRunning)
assert.Equal(ipn.NeedsLogin, *nn[1].State)
assert.Equal(ipn.NeedsLogin, b.State())
c.Assert(cc.getCalls(), qt.HasLen, 0)
c.Assert(nn[0].Prefs, qt.Not(qt.IsNil))
c.Assert(nn[1].State, qt.Not(qt.IsNil))
c.Assert(nn[0].Prefs.LoggedOut, qt.IsFalse)
c.Assert(nn[0].Prefs.WantRunning, qt.IsFalse)
c.Assert(ipn.NeedsLogin, qt.Equals, *nn[1].State)
c.Assert(ipn.NeedsLogin, qt.Equals, b.State())
}
// Start non-interactive login with no token.
@ -370,7 +366,7 @@ func TestStateMachine(t *testing.T) {
notifies.expect(0)
b.Login(nil)
{
assert.Equal(cc.getCalls(), []string{"Login"})
c.Assert(cc.getCalls(), qt.DeepEquals, []string{"Login"})
notifies.drain(0)
// BUG: this should immediately set WantRunning to true.
// Users don't log in if they don't want to also connect.
@ -388,7 +384,7 @@ func TestStateMachine(t *testing.T) {
url1 := "http://localhost:1/1"
cc.send(nil, url1, false, nil)
{
assert.Equal([]string{}, cc.getCalls())
c.Assert(cc.getCalls(), qt.HasLen, 0)
// ...but backend eats that notification, because the user
// didn't explicitly request interactive login yet, and
@ -397,9 +393,9 @@ func TestStateMachine(t *testing.T) {
// Trying to log in automatically sets WantRunning.
// BUG: that should have happened right after Login().
assert.NotNil(nn[0].Prefs)
assert.Equal(false, nn[0].Prefs.LoggedOut)
assert.Equal(true, nn[0].Prefs.WantRunning)
c.Assert(nn[0].Prefs, qt.Not(qt.IsNil))
c.Assert(nn[0].Prefs.LoggedOut, qt.IsFalse)
c.Assert(nn[0].Prefs.WantRunning, qt.IsTrue)
}
// Now we'll try an interactive login.
@ -415,9 +411,9 @@ func TestStateMachine(t *testing.T) {
// We're still not logged in so there's nothing we can do
// with it. (And empirically, it's providing an empty list
// of endpoints.)
assert.Equal([]string{"UpdateEndpoints"}, cc.getCalls())
assert.NotNil(nn[0].BrowseToURL)
assert.Equal(url1, *nn[0].BrowseToURL)
c.Assert([]string{"UpdateEndpoints"}, qt.DeepEquals, cc.getCalls())
c.Assert(nn[0].BrowseToURL, qt.Not(qt.IsNil))
c.Assert(url1, qt.Equals, *nn[0].BrowseToURL)
}
// Sometimes users press the Login button again, in the middle of
@ -431,7 +427,7 @@ func TestStateMachine(t *testing.T) {
{
notifies.drain(0)
// backend asks control for another login sequence
assert.Equal([]string{"Login"}, cc.getCalls())
c.Assert([]string{"Login"}, qt.DeepEquals, cc.getCalls())
}
// Provide a new interactive login URL.
@ -441,13 +437,13 @@ func TestStateMachine(t *testing.T) {
cc.send(nil, url2, false, nil)
{
// BUG: UpdateEndpoints again, this is getting silly.
assert.Equal([]string{"UpdateEndpoints"}, cc.getCalls())
c.Assert([]string{"UpdateEndpoints"}, qt.DeepEquals, cc.getCalls())
// This time, backend should emit it to the UI right away,
// because the UI is anxiously awaiting a new URL to visit.
nn := notifies.drain(1)
assert.NotNil(nn[0].BrowseToURL)
assert.Equal(url2, *nn[0].BrowseToURL)
c.Assert(nn[0].BrowseToURL, qt.Not(qt.IsNil))
c.Assert(url2, qt.Equals, *nn[0].BrowseToURL)
}
// Pretend that the interactive login actually happened.
@ -470,10 +466,10 @@ func TestStateMachine(t *testing.T) {
// wait until it gets into Starting.
// TODO: (Currently this test doesn't detect that bug, but
// it's visible in the logs)
assert.Equal([]string{"unpause", "UpdateEndpoints"}, cc.getCalls())
assert.NotNil(nn[0].LoginFinished)
assert.NotNil(nn[1].State)
assert.Equal(ipn.NeedsMachineAuth, *nn[1].State)
c.Assert([]string{"unpause", "UpdateEndpoints"}, qt.DeepEquals, cc.getCalls())
c.Assert(nn[0].LoginFinished, qt.Not(qt.IsNil))
c.Assert(nn[1].State, qt.Not(qt.IsNil))
c.Assert(ipn.NeedsMachineAuth, qt.Equals, *nn[1].State)
}
// TODO: check that the logged-in username propagates from control
@ -495,9 +491,9 @@ func TestStateMachine(t *testing.T) {
})
{
nn := notifies.drain(1)
assert.Equal([]string{"unpause", "UpdateEndpoints"}, cc.getCalls())
assert.NotNil(nn[0].State)
assert.Equal(ipn.Starting, *nn[0].State)
c.Assert([]string{"unpause", "UpdateEndpoints"}, qt.DeepEquals, cc.getCalls())
c.Assert(nn[0].State, qt.Not(qt.IsNil))
c.Assert(ipn.Starting, qt.Equals, *nn[0].State)
}
// TODO: add a fake DERP server to our fake netmap, so we can
@ -518,11 +514,11 @@ func TestStateMachine(t *testing.T) {
})
{
nn := notifies.drain(2)
assert.Equal([]string{"pause"}, cc.getCalls())
c.Assert([]string{"pause"}, qt.DeepEquals, cc.getCalls())
// BUG: I would expect Prefs to change first, and state after.
assert.NotNil(nn[0].State)
assert.NotNil(nn[1].Prefs)
assert.Equal(ipn.Stopped, *nn[0].State)
c.Assert(nn[0].State, qt.Not(qt.IsNil))
c.Assert(nn[1].Prefs, qt.Not(qt.IsNil))
c.Assert(ipn.Stopped, qt.Equals, *nn[0].State)
}
// The user changes their preference to WantRunning after all.
@ -536,11 +532,11 @@ func TestStateMachine(t *testing.T) {
nn := notifies.drain(2)
// BUG: UpdateEndpoints isn't needed here.
// BUG: Login isn't needed here. We never logged out.
assert.Equal([]string{"Login", "unpause", "UpdateEndpoints"}, cc.getCalls())
c.Assert([]string{"Login", "unpause", "UpdateEndpoints"}, qt.DeepEquals, cc.getCalls())
// BUG: I would expect Prefs to change first, and state after.
assert.NotNil(nn[0].State)
assert.NotNil(nn[1].Prefs)
assert.Equal(ipn.Starting, *nn[0].State)
c.Assert(nn[0].State, qt.Not(qt.IsNil))
c.Assert(nn[1].Prefs, qt.Not(qt.IsNil))
c.Assert(ipn.Starting, qt.Equals, *nn[0].State)
}
// Test the fast-path frontend reconnection.
@ -551,15 +547,13 @@ func TestStateMachine(t *testing.T) {
t.Logf("\n\nFastpath Start()")
notifies.expect(1)
b.state = ipn.Running
assert.Nil(b.Start(ipn.Options{
StateKey: ipn.GlobalDaemonStateKey,
}))
c.Assert(b.Start(ipn.Options{StateKey: ipn.GlobalDaemonStateKey}), qt.IsNil)
{
nn := notifies.drain(1)
assert.Equal([]string{}, cc.getCalls())
assert.NotNil(nn[0].State)
assert.NotNil(nn[0].LoginFinished)
assert.NotNil(nn[0].NetMap)
c.Assert(cc.getCalls(), qt.HasLen, 0)
c.Assert(nn[0].State, qt.Not(qt.IsNil))
c.Assert(nn[0].LoginFinished, qt.Not(qt.IsNil))
c.Assert(nn[0].NetMap, qt.Not(qt.IsNil))
// BUG: Prefs should be sent too, or the UI could end up in
// a bad state. (iOS, the only current user of this feature,
// probably wouldn't notice because it happens to not display
@ -576,13 +570,13 @@ func TestStateMachine(t *testing.T) {
{
nn := notifies.drain(2)
// BUG: now is not the time to unpause.
assert.Equal([]string{"unpause", "StartLogout"}, cc.getCalls())
assert.NotNil(nn[0].State)
assert.NotNil(nn[1].Prefs)
assert.Equal(ipn.NeedsLogin, *nn[0].State)
assert.Equal(true, nn[1].Prefs.LoggedOut)
assert.Equal(false, nn[1].Prefs.WantRunning)
assert.Equal(ipn.NeedsLogin, b.State())
c.Assert([]string{"unpause", "StartLogout"}, qt.DeepEquals, cc.getCalls())
c.Assert(nn[0].State, qt.Not(qt.IsNil))
c.Assert(nn[1].Prefs, qt.Not(qt.IsNil))
c.Assert(ipn.NeedsLogin, qt.Equals, *nn[0].State)
c.Assert(nn[1].Prefs.LoggedOut, qt.IsTrue)
c.Assert(nn[1].Prefs.WantRunning, qt.IsFalse)
c.Assert(ipn.NeedsLogin, qt.Equals, b.State())
}
// Let's make the logout succeed.
@ -592,12 +586,12 @@ func TestStateMachine(t *testing.T) {
cc.send(nil, "", false, nil)
{
nn := notifies.drain(1)
assert.Equal([]string{}, cc.getCalls())
assert.NotNil(nn[0].Prefs)
assert.Equal(true, nn[0].Prefs.LoggedOut)
c.Assert(cc.getCalls(), qt.HasLen, 0)
c.Assert(nn[0].Prefs, qt.Not(qt.IsNil))
c.Assert(nn[0].Prefs.LoggedOut, qt.IsTrue)
// BUG: WantRunning should be false after manual logout.
assert.Equal(true, nn[0].Prefs.WantRunning)
assert.Equal(ipn.NeedsLogin, b.State())
c.Assert(nn[0].Prefs.WantRunning, qt.IsTrue)
c.Assert(ipn.NeedsLogin, qt.Equals, b.State())
}
// A second logout should do nothing, since the prefs haven't changed.
@ -608,12 +602,12 @@ func TestStateMachine(t *testing.T) {
nn := notifies.drain(1)
// BUG: the backend has already called StartLogout, and we're
// still logged out. So it shouldn't call it again.
assert.Equal([]string{"StartLogout"}, cc.getCalls())
c.Assert([]string{"StartLogout"}, qt.DeepEquals, cc.getCalls())
// BUG: Prefs should not change here. Already logged out.
assert.NotNil(nn[0].Prefs)
assert.Equal(true, nn[0].Prefs.LoggedOut)
assert.Equal(false, nn[0].Prefs.WantRunning)
assert.Equal(ipn.NeedsLogin, b.State())
c.Assert(nn[0].Prefs, qt.Not(qt.IsNil))
c.Assert(nn[0].Prefs.LoggedOut, qt.IsTrue)
c.Assert(nn[0].Prefs.WantRunning, qt.IsFalse)
c.Assert(ipn.NeedsLogin, qt.Equals, b.State())
}
// Let's acknowledge the second logout too.
@ -623,12 +617,12 @@ func TestStateMachine(t *testing.T) {
cc.send(nil, "", false, nil)
{
nn := notifies.drain(1)
assert.Equal([]string{}, cc.getCalls())
assert.NotNil(nn[0].Prefs)
assert.Equal(true, nn[0].Prefs.LoggedOut)
c.Assert(cc.getCalls(), qt.HasLen, 0)
c.Assert(nn[0].Prefs, qt.Not(qt.IsNil))
c.Assert(nn[0].Prefs.LoggedOut, qt.IsTrue)
// BUG: second logout shouldn't cause WantRunning->true !!
assert.Equal(true, nn[0].Prefs.WantRunning)
assert.Equal(ipn.NeedsLogin, b.State())
c.Assert(nn[0].Prefs.WantRunning, qt.IsTrue)
c.Assert(ipn.NeedsLogin, qt.Equals, b.State())
}
// Try the synchronous logout feature.
@ -639,11 +633,11 @@ func TestStateMachine(t *testing.T) {
// I guess, since that's supposed to be synchronous.
{
nn := notifies.drain(1)
assert.Equal([]string{"Logout"}, cc.getCalls())
assert.NotNil(nn[0].Prefs)
assert.Equal(true, nn[0].Prefs.LoggedOut)
assert.Equal(false, nn[0].Prefs.WantRunning)
assert.Equal(ipn.NeedsLogin, b.State())
c.Assert([]string{"Logout"}, qt.DeepEquals, cc.getCalls())
c.Assert(nn[0].Prefs, qt.Not(qt.IsNil))
c.Assert(nn[0].Prefs.LoggedOut, qt.IsTrue)
c.Assert(nn[0].Prefs.WantRunning, qt.IsFalse)
c.Assert(ipn.NeedsLogin, qt.Equals, b.State())
}
// Generate the third logout event.
@ -653,12 +647,12 @@ func TestStateMachine(t *testing.T) {
cc.send(nil, "", false, nil)
{
nn := notifies.drain(1)
assert.Equal([]string{}, cc.getCalls())
assert.NotNil(nn[0].Prefs)
assert.Equal(true, nn[0].Prefs.LoggedOut)
c.Assert(cc.getCalls(), qt.HasLen, 0)
c.Assert(nn[0].Prefs, qt.Not(qt.IsNil))
c.Assert(nn[0].Prefs.LoggedOut, qt.IsTrue)
// BUG: third logout shouldn't cause WantRunning->true !!
assert.Equal(true, nn[0].Prefs.WantRunning)
assert.Equal(ipn.NeedsLogin, b.State())
c.Assert(nn[0].Prefs.WantRunning, qt.IsTrue)
c.Assert(ipn.NeedsLogin, qt.Equals, b.State())
}
// Shut down the backend.
@ -668,7 +662,7 @@ func TestStateMachine(t *testing.T) {
{
notifies.drain(0)
// BUG: I expect a transition to ipn.NoState here.
assert.Equal(cc.getCalls(), []string{"Shutdown"})
c.Assert(cc.getCalls(), qt.DeepEquals, []string{"Shutdown"})
}
// Oh, you thought we were done? Ha! Now we have to test what
@ -685,23 +679,21 @@ func TestStateMachine(t *testing.T) {
// The frontend restarts!
t.Logf("\n\nStart3")
notifies.expect(2)
assert.Nil(b.Start(ipn.Options{
StateKey: ipn.GlobalDaemonStateKey,
}))
c.Assert(b.Start(ipn.Options{StateKey: ipn.GlobalDaemonStateKey}), qt.IsNil)
{
// BUG: We already called Shutdown(), no need to do it again.
// BUG: Way too soon for UpdateEndpoints.
// BUG: don't unpause because we're not logged in.
assert.Equal([]string{"Shutdown", "New", "UpdateEndpoints", "unpause"}, cc.getCalls())
c.Assert([]string{"Shutdown", "New", "UpdateEndpoints", "unpause"}, qt.DeepEquals, cc.getCalls())
nn := notifies.drain(2)
assert.Equal([]string{}, cc.getCalls())
assert.NotNil(nn[0].Prefs)
assert.NotNil(nn[1].State)
assert.Equal(true, nn[0].Prefs.LoggedOut)
assert.Equal(true, nn[0].Prefs.WantRunning)
assert.Equal(ipn.NeedsLogin, *nn[1].State)
assert.Equal(ipn.NeedsLogin, b.State())
c.Assert(cc.getCalls(), qt.HasLen, 0)
c.Assert(nn[0].Prefs, qt.Not(qt.IsNil))
c.Assert(nn[1].State, qt.Not(qt.IsNil))
c.Assert(nn[0].Prefs.LoggedOut, qt.IsTrue)
c.Assert(nn[0].Prefs.WantRunning, qt.IsTrue)
c.Assert(ipn.NeedsLogin, qt.Equals, *nn[1].State)
c.Assert(ipn.NeedsLogin, qt.Equals, b.State())
}
// Let's break the rules a little. Our control server accepts
@ -716,12 +708,12 @@ func TestStateMachine(t *testing.T) {
})
{
nn := notifies.drain(3)
assert.Equal([]string{"unpause"}, cc.getCalls())
assert.NotNil(nn[0].Prefs)
assert.NotNil(nn[1].LoginFinished)
assert.NotNil(nn[2].State)
assert.Equal(false, nn[0].Prefs.LoggedOut)
assert.Equal(ipn.Starting, *nn[2].State)
c.Assert([]string{"unpause"}, qt.DeepEquals, cc.getCalls())
c.Assert(nn[0].Prefs, qt.Not(qt.IsNil))
c.Assert(nn[1].LoginFinished, qt.Not(qt.IsNil))
c.Assert(nn[2].State, qt.Not(qt.IsNil))
c.Assert(nn[0].Prefs.LoggedOut, qt.IsFalse)
c.Assert(ipn.Starting, qt.Equals, *nn[2].State)
}
// Now we've logged in successfully. Let's disconnect.
@ -733,20 +725,18 @@ func TestStateMachine(t *testing.T) {
})
{
nn := notifies.drain(2)
assert.Equal([]string{"pause"}, cc.getCalls())
c.Assert([]string{"pause"}, qt.DeepEquals, cc.getCalls())
// BUG: I would expect Prefs to change first, and state after.
assert.NotNil(nn[0].State)
assert.NotNil(nn[1].Prefs)
assert.Equal(ipn.Stopped, *nn[0].State)
assert.Equal(false, nn[1].Prefs.LoggedOut)
c.Assert(nn[0].State, qt.Not(qt.IsNil))
c.Assert(nn[1].Prefs, qt.Not(qt.IsNil))
c.Assert(ipn.Stopped, qt.Equals, *nn[0].State)
c.Assert(nn[1].Prefs.LoggedOut, qt.IsFalse)
}
// One more restart, this time with a valid key, but WantRunning=false.
t.Logf("\n\nStart4")
notifies.expect(2)
assert.Nil(b.Start(ipn.Options{
StateKey: ipn.GlobalDaemonStateKey,
}))
c.Assert(b.Start(ipn.Options{StateKey: ipn.GlobalDaemonStateKey}), qt.IsNil)
{
// NOTE: cc.Shutdown() is correct here, since we didn't call
// b.Shutdown() explicitly ourselves.
@ -755,15 +745,15 @@ func TestStateMachine(t *testing.T) {
// on startup, otherwise UIs can't show the node list, login
// name, etc when in state ipn.Stopped.
// Arguably they shouldn't try. But they currently do.
assert.Equal([]string{"Shutdown", "New", "UpdateEndpoints", "Login", "unpause"}, cc.getCalls())
c.Assert([]string{"Shutdown", "New", "UpdateEndpoints", "Login", "unpause"}, qt.DeepEquals, cc.getCalls())
nn := notifies.drain(2)
assert.Equal([]string{}, cc.getCalls())
assert.NotNil(nn[0].Prefs)
assert.NotNil(nn[1].State)
assert.Equal(false, nn[0].Prefs.WantRunning)
assert.Equal(false, nn[0].Prefs.LoggedOut)
assert.Equal(ipn.Stopped, *nn[1].State)
c.Assert(cc.getCalls(), qt.HasLen, 0)
c.Assert(nn[0].Prefs, qt.Not(qt.IsNil))
c.Assert(nn[1].State, qt.Not(qt.IsNil))
c.Assert(nn[0].Prefs.WantRunning, qt.IsFalse)
c.Assert(nn[0].Prefs.LoggedOut, qt.IsFalse)
c.Assert(ipn.Stopped, qt.Equals, *nn[1].State)
}
// Request connection.
@ -776,31 +766,29 @@ func TestStateMachine(t *testing.T) {
})
{
nn := notifies.drain(2)
assert.Equal([]string{"Login", "unpause"}, cc.getCalls())
c.Assert([]string{"Login", "unpause"}, qt.DeepEquals, cc.getCalls())
// BUG: I would expect Prefs to change first, and state after.
assert.NotNil(nn[0].State)
assert.NotNil(nn[1].Prefs)
assert.Equal(ipn.Starting, *nn[0].State)
c.Assert(nn[0].State, qt.Not(qt.IsNil))
c.Assert(nn[1].Prefs, qt.Not(qt.IsNil))
c.Assert(ipn.Starting, qt.Equals, *nn[0].State)
}
// The last test case is the most common one: restarting when both
// logged in and WantRunning.
t.Logf("\n\nStart5")
notifies.expect(1)
assert.Nil(b.Start(ipn.Options{
StateKey: ipn.GlobalDaemonStateKey,
}))
c.Assert(b.Start(ipn.Options{StateKey: ipn.GlobalDaemonStateKey}), qt.IsNil)
{
// NOTE: cc.Shutdown() is correct here, since we didn't call
// b.Shutdown() ourselves.
assert.Equal([]string{"Shutdown", "New", "UpdateEndpoints", "Login"}, cc.getCalls())
c.Assert([]string{"Shutdown", "New", "UpdateEndpoints", "Login"}, qt.DeepEquals, cc.getCalls())
nn := notifies.drain(1)
assert.Equal([]string{}, cc.getCalls())
assert.NotNil(nn[0].Prefs)
assert.Equal(false, nn[0].Prefs.LoggedOut)
assert.Equal(true, nn[0].Prefs.WantRunning)
assert.Equal(ipn.NoState, b.State())
c.Assert(cc.getCalls(), qt.HasLen, 0)
c.Assert(nn[0].Prefs, qt.Not(qt.IsNil))
c.Assert(nn[0].Prefs.LoggedOut, qt.IsFalse)
c.Assert(nn[0].Prefs.WantRunning, qt.IsTrue)
c.Assert(ipn.NoState, qt.Equals, b.State())
}
// Control server accepts our valid key from before.
@ -812,13 +800,13 @@ func TestStateMachine(t *testing.T) {
})
{
nn := notifies.drain(2)
assert.Equal([]string{"unpause"}, cc.getCalls())
assert.NotNil(nn[0].LoginFinished)
assert.NotNil(nn[1].State)
assert.Equal(ipn.Starting, *nn[1].State)
c.Assert([]string{"unpause"}, qt.DeepEquals, cc.getCalls())
c.Assert(nn[0].LoginFinished, qt.Not(qt.IsNil))
c.Assert(nn[1].State, qt.Not(qt.IsNil))
c.Assert(ipn.Starting, qt.Equals, *nn[1].State)
// NOTE: No prefs change this time. WantRunning stays true.
// We were in Starting in the first place, so that doesn't
// change either.
assert.Equal(ipn.Starting, b.State())
c.Assert(ipn.Starting, qt.Equals, b.State())
}
}