|
|
|
|
@ -14,6 +14,7 @@ import ( |
|
|
|
|
|
|
|
|
|
"tailscale.com/control/controlclient" |
|
|
|
|
"tailscale.com/ipn" |
|
|
|
|
"tailscale.com/syncs" |
|
|
|
|
"tailscale.com/tailcfg" |
|
|
|
|
"tailscale.com/types/empty" |
|
|
|
|
"tailscale.com/types/logger" |
|
|
|
|
@ -277,7 +278,7 @@ func TestStateMachine(t *testing.T) { |
|
|
|
|
c := qt.New(t) |
|
|
|
|
|
|
|
|
|
logf := t.Logf |
|
|
|
|
store := new(ipn.MemoryStore) |
|
|
|
|
store := new(testStateStorage) |
|
|
|
|
e, err := wgengine.NewFakeUserspaceEngine(logf, 0) |
|
|
|
|
if err != nil { |
|
|
|
|
t.Fatalf("NewFakeUserspaceEngine: %v", err) |
|
|
|
|
@ -523,6 +524,7 @@ func TestStateMachine(t *testing.T) { |
|
|
|
|
|
|
|
|
|
// The user changes their preference to WantRunning after all.
|
|
|
|
|
t.Logf("\n\nWantRunning -> true") |
|
|
|
|
store.awaitWrite() |
|
|
|
|
notifies.expect(2) |
|
|
|
|
b.EditPrefs(&ipn.MaskedPrefs{ |
|
|
|
|
WantRunningSet: true, |
|
|
|
|
@ -537,6 +539,7 @@ func TestStateMachine(t *testing.T) { |
|
|
|
|
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) |
|
|
|
|
c.Assert(store.sawWrite(), qt.IsTrue) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Test the fast-path frontend reconnection.
|
|
|
|
|
@ -561,6 +564,7 @@ func TestStateMachine(t *testing.T) { |
|
|
|
|
b.state = ipn.Starting |
|
|
|
|
|
|
|
|
|
// User wants to logout.
|
|
|
|
|
store.awaitWrite() |
|
|
|
|
t.Logf("\n\nLogout (async)") |
|
|
|
|
notifies.expect(2) |
|
|
|
|
b.Logout() |
|
|
|
|
@ -573,6 +577,7 @@ func TestStateMachine(t *testing.T) { |
|
|
|
|
c.Assert(nn[1].Prefs.LoggedOut, qt.IsTrue) |
|
|
|
|
c.Assert(nn[1].Prefs.WantRunning, qt.IsFalse) |
|
|
|
|
c.Assert(ipn.Stopped, qt.Equals, b.State()) |
|
|
|
|
c.Assert(store.sawWrite(), qt.IsTrue) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Let's make the logout succeed.
|
|
|
|
|
@ -861,3 +866,29 @@ func TestStateMachine(t *testing.T) { |
|
|
|
|
c.Assert(ipn.Starting, qt.Equals, b.State()) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type testStateStorage struct { |
|
|
|
|
mem ipn.MemoryStore |
|
|
|
|
written syncs.AtomicBool |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (s *testStateStorage) ReadState(id ipn.StateKey) ([]byte, error) { |
|
|
|
|
return s.mem.ReadState(id) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (s *testStateStorage) WriteState(id ipn.StateKey, bs []byte) error { |
|
|
|
|
s.written.Set(true) |
|
|
|
|
return s.mem.WriteState(id, bs) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// awaitWrite clears the "I've seen writes" bit, in prep for a future
|
|
|
|
|
// call to sawWrite to see if a write arrived.
|
|
|
|
|
func (s *testStateStorage) awaitWrite() { s.written.Set(false) } |
|
|
|
|
|
|
|
|
|
// sawWrite reports whether there's been a WriteState call since the most
|
|
|
|
|
// recent awaitWrite call.
|
|
|
|
|
func (s *testStateStorage) sawWrite() bool { |
|
|
|
|
v := s.written.Get() |
|
|
|
|
s.awaitWrite() |
|
|
|
|
return v |
|
|
|
|
} |
|
|
|
|
|