@@ -1861,6 +1861,91 @@ func TestWorkspaceAgentExternalAuthListen(t *testing.T) {
1861
1861
})
1862
1862
}
1863
1863
1864
+ func TestOwnedWorkspacesCoordinate (t * testing.T ) {
1865
+ t .Parallel ()
1866
+
1867
+ ctx := testutil .Context (t ,testutil .WaitLong )
1868
+ logger := slogtest .Make (t ,nil ).Leveled (slog .LevelDebug )
1869
+ firstClient ,closer ,_ := coderdtest .NewWithAPI (t ,& coderdtest.Options {
1870
+ Coordinator :tailnet .NewCoordinator (logger ),
1871
+ IncludeProvisionerDaemon :true ,
1872
+ })
1873
+ defer closer .Close ()
1874
+ firstUser := coderdtest .CreateFirstUser (t ,firstClient )
1875
+ user ,_ := coderdtest .CreateAnotherUser (t ,firstClient ,firstUser .OrganizationID )
1876
+
1877
+ u ,err := user .URL .Parse ("/api/v2/users/me/tailnet" )
1878
+ require .NoError (t ,err )
1879
+ q := u .Query ()
1880
+ q .Set ("version" ,"2.0" )
1881
+ u .RawQuery = q .Encode ()
1882
+
1883
+ //nolint:bodyclose // websocket package closes this for you
1884
+ wsConn ,resp ,err := websocket .Dial (ctx ,u .String (),& websocket.DialOptions {
1885
+ HTTPHeader : http.Header {
1886
+ "Coder-Session-Token" : []string {user .SessionToken ()},
1887
+ },
1888
+ })
1889
+ if err != nil {
1890
+ if resp .StatusCode != http .StatusSwitchingProtocols {
1891
+ err = codersdk .ReadBodyAsError (resp )
1892
+ }
1893
+ require .NoError (t ,err )
1894
+ }
1895
+ defer wsConn .Close (websocket .StatusNormalClosure ,"done" )
1896
+
1897
+ rpcClient ,err := tailnet .NewDRPCClient (
1898
+ websocket .NetConn (ctx ,wsConn ,websocket .MessageBinary ),
1899
+ logger ,
1900
+ )
1901
+ require .NoError (t ,err )
1902
+
1903
+ stream ,err := rpcClient .WorkspaceUpdates (ctx ,& tailnetproto.WorkspaceUpdatesRequest {})
1904
+ require .NoError (t ,err )
1905
+
1906
+ update ,err := stream .Recv ()
1907
+ require .NoError (t ,err )
1908
+ require .Len (t ,update .UpsertedWorkspaces ,0 )
1909
+ require .Len (t ,update .DeletedWorkspaces ,0 )
1910
+ require .Len (t ,update .UpsertedAgents ,0 )
1911
+ require .Len (t ,update .DeletedAgents ,0 )
1912
+
1913
+ // Build a workspace
1914
+ authToken := uuid .NewString ()
1915
+ version := coderdtest .CreateTemplateVersion (t ,firstClient ,firstUser .OrganizationID ,& echo.Responses {
1916
+ Parse :echo .ParseComplete ,
1917
+ ProvisionPlan :echo .PlanComplete ,
1918
+ ProvisionApply :echo .ProvisionApplyWithAgent (authToken ),
1919
+ })
1920
+ coderdtest .AwaitTemplateVersionJobCompleted (t ,firstClient ,version .ID )
1921
+ template := coderdtest .CreateTemplate (t ,firstClient ,firstUser .OrganizationID ,version .ID )
1922
+ workspace := coderdtest .CreateWorkspace (t ,user ,template .ID )
1923
+ coderdtest .AwaitWorkspaceBuildJobCompleted (t ,firstClient ,workspace .LatestBuild .ID )
1924
+
1925
+ // Starting workspace
1926
+ update ,err = stream .Recv ()
1927
+ require .NoError (t ,err )
1928
+ require .Len (t ,update .UpsertedWorkspaces ,1 )
1929
+ require .Equal (t ,update .UpsertedWorkspaces [0 ].Status ,tailnetproto .Workspace_STARTING )
1930
+
1931
+ // Workspace is running
1932
+ update ,err = stream .Recv ()
1933
+ require .NoError (t ,err )
1934
+ require .Len (t ,update .UpsertedWorkspaces ,1 )
1935
+ require .Equal (t ,update .UpsertedWorkspaces [0 ].Status ,tailnetproto .Workspace_RUNNING )
1936
+ wsID := update .UpsertedWorkspaces [0 ].Id
1937
+
1938
+ _ = agenttest .New (t ,user .URL ,authToken )
1939
+ resources := coderdtest .NewWorkspaceAgentWaiter (t ,user ,workspace .ID ).Wait ()
1940
+
1941
+ // Agent is created
1942
+ update ,err = stream .Recv ()
1943
+ require .NoError (t ,err )
1944
+ require .Len (t ,update .UpsertedAgents ,1 )
1945
+ require .Equal (t ,update .UpsertedAgents [0 ].WorkspaceId ,wsID )
1946
+ require .EqualValues (t ,update .UpsertedAgents [0 ].Id ,resources [0 ].Agents [0 ].ID )
1947
+ }
1948
+
1864
1949
func requireGetManifest (ctx context.Context ,t testing.TB ,aAPI agentproto.DRPCAgentClient ) agentsdk.Manifest {
1865
1950
mp ,err := aAPI .GetManifest (ctx ,& agentproto.GetManifestRequest {})
1866
1951
require .NoError (t ,err )