@@ -1135,6 +1135,49 @@ func TestController_TelemetrySuccess(t *testing.T) {
1135
1135
require .Equal (t , []byte ("test event" ), testEvents [0 ].Id )
1136
1136
}
1137
1137
1138
+ func TestController_WorkspaceUpdates (t * testing.T ) {
1139
+ t .Parallel ()
1140
+ theError := xerrors .New ("a bad thing happened" )
1141
+ testCtx := testutil .Context (t , testutil .WaitShort )
1142
+ ctx , cancel := context .WithCancel (testCtx )
1143
+ logger := slogtest .Make (t , & slogtest.Options {
1144
+ IgnoredErrorIs : append (slogtest .DefaultIgnoredErrorIs , theError ),
1145
+ }).Leveled (slog .LevelDebug )
1146
+
1147
+ fClient := newFakeWorkspaceUpdateClient (testCtx , t )
1148
+ dialer := & fakeWorkspaceUpdatesDialer {
1149
+ client : fClient ,
1150
+ }
1151
+
1152
+ uut := tailnet .NewController (logger .Named ("ctrl" ), dialer )
1153
+ fCtrl := newFakeUpdatesController (ctx , t )
1154
+ uut .WorkspaceUpdatesCtrl = fCtrl
1155
+ uut .Run (ctx )
1156
+
1157
+ // it should dial and pass the client to the controller
1158
+ call := testutil .RequireRecvCtx (testCtx , t , fCtrl .calls )
1159
+ require .Equal (t , fClient , call .client )
1160
+ fCW := newFakeCloserWaiter ()
1161
+ testutil .RequireSendCtx [tailnet.CloserWaiter ](testCtx , t , call .resp , fCW )
1162
+
1163
+ // if the CloserWaiter exits...
1164
+ testutil .RequireSendCtx (testCtx , t , fCW .errCh , theError )
1165
+
1166
+ // it should close, redial and reconnect
1167
+ cCall := testutil .RequireRecvCtx (testCtx , t , fClient .close )
1168
+ testutil .RequireSendCtx (testCtx , t , cCall , nil )
1169
+
1170
+ call = testutil .RequireRecvCtx (testCtx , t , fCtrl .calls )
1171
+ require .Equal (t , fClient , call .client )
1172
+ fCW = newFakeCloserWaiter ()
1173
+ testutil .RequireSendCtx [tailnet.CloserWaiter ](testCtx , t , call .resp , fCW )
1174
+
1175
+ // canceling the context should close the client
1176
+ cancel ()
1177
+ cCall = testutil .RequireRecvCtx (testCtx , t , fClient .close )
1178
+ testutil .RequireSendCtx (testCtx , t , cCall , nil )
1179
+ }
1180
+
1138
1181
type fakeTailnetConn struct {
1139
1182
peersLostCh chan struct {}
1140
1183
}
@@ -1717,3 +1760,97 @@ func TestTunnelAllWorkspaceUpdatesController_HandleErrors(t *testing.T) {
1717
1760
})
1718
1761
}
1719
1762
}
1763
+
1764
+ type fakeWorkspaceUpdatesController struct {
1765
+ ctx context.Context
1766
+ t testing.TB
1767
+ calls chan * newWorkspaceUpdatesCall
1768
+ }
1769
+
1770
+ type newWorkspaceUpdatesCall struct {
1771
+ client tailnet.WorkspaceUpdatesClient
1772
+ resp chan <- tailnet.CloserWaiter
1773
+ }
1774
+
1775
+ func (f fakeWorkspaceUpdatesController ) New (client tailnet.WorkspaceUpdatesClient ) tailnet.CloserWaiter {
1776
+ resps := make (chan tailnet.CloserWaiter )
1777
+ call := & newWorkspaceUpdatesCall {
1778
+ client : client ,
1779
+ resp : resps ,
1780
+ }
1781
+ select {
1782
+ case <- f .ctx .Done ():
1783
+ f .t .Error ("timed out waiting to send New call" )
1784
+ cw := newFakeCloserWaiter ()
1785
+ cw .errCh <- f .ctx .Err ()
1786
+ return cw
1787
+ case f .calls <- call :
1788
+ // OK
1789
+ }
1790
+ select {
1791
+ case <- f .ctx .Done ():
1792
+ f .t .Error ("timed out waiting to get New call response" )
1793
+ cw := newFakeCloserWaiter ()
1794
+ cw .errCh <- f .ctx .Err ()
1795
+ return cw
1796
+ case resp := <- resps :
1797
+ return resp
1798
+ }
1799
+ }
1800
+
1801
+ func newFakeUpdatesController (ctx context.Context , t * testing.T ) * fakeWorkspaceUpdatesController {
1802
+ return & fakeWorkspaceUpdatesController {
1803
+ ctx : ctx ,
1804
+ t : t ,
1805
+ calls : make (chan * newWorkspaceUpdatesCall ),
1806
+ }
1807
+ }
1808
+
1809
+ type fakeCloserWaiter struct {
1810
+ closeCalls chan chan error
1811
+ errCh chan error
1812
+ }
1813
+
1814
+ func (f * fakeCloserWaiter ) Close (ctx context.Context ) error {
1815
+ errRes := make (chan error )
1816
+ select {
1817
+ case <- ctx .Done ():
1818
+ return ctx .Err ()
1819
+ case f .closeCalls <- errRes :
1820
+ // OK
1821
+ }
1822
+ select {
1823
+ case <- ctx .Done ():
1824
+ return ctx .Err ()
1825
+ case err := <- errRes :
1826
+ return err
1827
+ }
1828
+ }
1829
+
1830
+ func (f * fakeCloserWaiter ) Wait () <- chan error {
1831
+ return f .errCh
1832
+ }
1833
+
1834
+ func newFakeCloserWaiter () * fakeCloserWaiter {
1835
+ return & fakeCloserWaiter {
1836
+ closeCalls : make (chan chan error ),
1837
+ errCh : make (chan error , 1 ),
1838
+ }
1839
+ }
1840
+
1841
+ type fakeWorkspaceUpdatesDialer struct {
1842
+ client tailnet.WorkspaceUpdatesClient
1843
+ }
1844
+
1845
+ func (f * fakeWorkspaceUpdatesDialer ) Dial (_ context.Context , _ tailnet.ResumeTokenController ) (tailnet.ControlProtocolClients , error ) {
1846
+ return tailnet.ControlProtocolClients {
1847
+ WorkspaceUpdates : f .client ,
1848
+ Closer : fakeCloser {},
1849
+ }, nil
1850
+ }
1851
+
1852
+ type fakeCloser struct {}
1853
+
1854
+ func (f fakeCloser ) Close () error {
1855
+ return nil
1856
+ }
0 commit comments