@@ -23,17 +23,23 @@ public void SetupMocksAndUriHandler()
2323        _mUserNotifier  =  new  Mock < IUserNotifier > ( MockBehavior . Strict ) ; 
2424        _mRdpConnector  =  new  Mock < IRdpConnector > ( MockBehavior . Strict ) ; 
2525        _mRpcController  =  new  Mock < IRpcController > ( MockBehavior . Strict ) ; 
26+         _mCredentialManager  =  new  Mock < ICredentialManager > ( MockBehavior . Strict ) ; 
2627
27-         uriHandler  =  new  UriHandler ( logger ,  _mRpcController . Object ,  _mUserNotifier . Object ,  _mRdpConnector . Object ) ; 
28+         uriHandler  =  new  UriHandler ( logger , 
29+             _mRpcController . Object , 
30+             _mUserNotifier . Object , 
31+             _mRdpConnector . Object , 
32+             _mCredentialManager . Object ) ; 
2833    } 
2934
3035    private  Mock < IUserNotifier >  _mUserNotifier ; 
3136    private  Mock < IRdpConnector >  _mRdpConnector ; 
3237    private  Mock < IRpcController >  _mRpcController ; 
38+     private  Mock < ICredentialManager >  _mCredentialManager ; 
3339    private  UriHandler  uriHandler ;  // Unit under test. 
3440
3541    [ SetUp ] 
36-     public  void  AgentAndWorkspaceFixtures ( ) 
42+     public  void  AgentWorkspaceAndCredentialFixtures ( ) 
3743    { 
3844        agent11  =  new  Agent ( ) ; 
3945        agent11 . Fqdn . Add ( "workspace1.coder" ) ; 
@@ -54,94 +60,116 @@ public void AgentAndWorkspaceFixtures()
5460            Workspaces  =  [ workspace1 ] , 
5561            Agents  =  [ agent11 ] , 
5662        } ; 
63+ 
64+         credentialModel1  =  new  CredentialModel 
65+         { 
66+             State  =  CredentialState . Valid , 
67+             CoderUrl  =  "https://coder.test" , 
68+         } ; 
5769    } 
5870
5971    private  Agent  agent11 ; 
6072    private  Workspace  workspace1 ; 
6173    private  RpcModel  modelWithWorkspace1 ; 
74+     private  CredentialModel  credentialModel1 ; 
6275
6376    [ Test ( Description  =  "Open RDP with username & password" ) ] 
6477    [ CancelAfter ( 30_000 ) ] 
6578    public  async  Task  Mainline ( CancellationToken  ct ) 
6679    { 
67-         var  input  =  new  Uri ( "coder:/v0/open/ws/workspace1/agent/agent11/rdp?username=testy&password=sesame" ) ; 
80+         var  input  =  new  Uri ( 
81+             "coder://coder.test/v0/open/ws/workspace1/agent/agent11/rdp?username=testy&password=sesame" ) ; 
6882
83+         _mCredentialManager . Setup ( m =>  m . GetCachedCredentials ( ) ) . Returns ( credentialModel1 ) ; 
6984        _mRpcController . Setup ( m =>  m . GetState ( ) ) . Returns ( modelWithWorkspace1 ) ; 
7085        var  expectedCred  =  new  RdpCredentials ( "testy" ,  "sesame" ) ; 
7186        _  =  _mRdpConnector . Setup ( m =>  m . WriteCredentials ( agent11 . Fqdn [ 0 ] ,  expectedCred ) ) ; 
7287        _  =  _mRdpConnector . Setup ( m =>  m . Connect ( agent11 . Fqdn [ 0 ] ,  IRdpConnector . DefaultPort ,  ct ) ) 
7388            . Returns ( Task . CompletedTask ) ; 
7489        await  uriHandler . HandleUri ( input ,  ct ) ; 
90+         _mRdpConnector . Verify ( m =>  m . WriteCredentials ( It . IsAny < string > ( ) ,  It . IsAny < RdpCredentials > ( ) ) ) ; 
91+         _mRdpConnector . Verify ( m =>  m . Connect ( It . IsAny < string > ( ) ,  It . IsAny < int > ( ) ,  ct ) ,  Times . Once ) ; 
7592    } 
7693
7794    [ Test ( Description  =  "Open RDP with no credentials" ) ] 
7895    [ CancelAfter ( 30_000 ) ] 
7996    public  async  Task  NoCredentials ( CancellationToken  ct ) 
8097    { 
81-         var  input  =  new  Uri ( "coder:/v0/open/ws/workspace1/agent/agent11/rdp" ) ; 
98+         var  input  =  new  Uri ( "coder://coder.test/ v0/open/ws/workspace1/agent/agent11/rdp" ) ; 
8299
100+         _mCredentialManager . Setup ( m =>  m . GetCachedCredentials ( ) ) . Returns ( credentialModel1 ) ; 
83101        _mRpcController . Setup ( m =>  m . GetState ( ) ) . Returns ( modelWithWorkspace1 ) ; 
84102        _  =  _mRdpConnector . Setup ( m =>  m . Connect ( agent11 . Fqdn [ 0 ] ,  IRdpConnector . DefaultPort ,  ct ) ) 
85103            . Returns ( Task . CompletedTask ) ; 
86104        await  uriHandler . HandleUri ( input ,  ct ) ; 
105+         _mRdpConnector . Verify ( m =>  m . Connect ( It . IsAny < string > ( ) ,  It . IsAny < int > ( ) ,  ct ) ,  Times . Once ) ; 
87106    } 
88107
89108    [ Test ( Description  =  "Unknown app slug" ) ] 
90109    [ CancelAfter ( 30_000 ) ] 
91110    public  async  Task  UnknownApp ( CancellationToken  ct ) 
92111    { 
93-         var  input  =  new  Uri ( "coder:/v0/open/ws/workspace1/agent/agent11/someapp" ) ; 
112+         var  input  =  new  Uri ( "coder://coder.test/ v0/open/ws/workspace1/agent/agent11/someapp" ) ; 
94113
114+         _mCredentialManager . Setup ( m =>  m . GetCachedCredentials ( ) ) . Returns ( credentialModel1 ) ; 
95115        _mRpcController . Setup ( m =>  m . GetState ( ) ) . Returns ( modelWithWorkspace1 ) ; 
96116        _mUserNotifier . Setup ( m =>  m . ShowErrorNotification ( It . IsAny < string > ( ) ,  It . IsRegex ( "someapp" ) ,  ct ) ) 
97117            . Returns ( Task . CompletedTask ) ; 
98118        await  uriHandler . HandleUri ( input ,  ct ) ; 
119+         _mUserNotifier . Verify ( m =>  m . ShowErrorNotification ( It . IsAny < string > ( ) ,  It . IsAny < string > ( ) ,  ct ) ,  Times . Once ( ) ) ; 
99120    } 
100121
101122    [ Test ( Description  =  "Unknown agent name" ) ] 
102123    [ CancelAfter ( 30_000 ) ] 
103124    public  async  Task  UnknownAgent ( CancellationToken  ct ) 
104125    { 
105-         var  input  =  new  Uri ( "coder:/v0/open/ws/workspace1/agent/wrongagent/rdp" ) ; 
126+         var  input  =  new  Uri ( "coder://coder.test/ v0/open/ws/workspace1/agent/wrongagent/rdp" ) ; 
106127
128+         _mCredentialManager . Setup ( m =>  m . GetCachedCredentials ( ) ) . Returns ( credentialModel1 ) ; 
107129        _mRpcController . Setup ( m =>  m . GetState ( ) ) . Returns ( modelWithWorkspace1 ) ; 
108130        _mUserNotifier . Setup ( m =>  m . ShowErrorNotification ( It . IsAny < string > ( ) ,  It . IsRegex ( "wrongagent" ) ,  ct ) ) 
109131            . Returns ( Task . CompletedTask ) ; 
110132        await  uriHandler . HandleUri ( input ,  ct ) ; 
133+         _mUserNotifier . Verify ( m =>  m . ShowErrorNotification ( It . IsAny < string > ( ) ,  It . IsAny < string > ( ) ,  ct ) ,  Times . Once ( ) ) ; 
111134    } 
112135
113136    [ Test ( Description  =  "Unknown workspace name" ) ] 
114137    [ CancelAfter ( 30_000 ) ] 
115138    public  async  Task  UnknownWorkspace ( CancellationToken  ct ) 
116139    { 
117-         var  input  =  new  Uri ( "coder:/v0/open/ws/wrongworkspace/agent/agent11/rdp" ) ; 
140+         var  input  =  new  Uri ( "coder://coder.test/ v0/open/ws/wrongworkspace/agent/agent11/rdp" ) ; 
118141
142+         _mCredentialManager . Setup ( m =>  m . GetCachedCredentials ( ) ) . Returns ( credentialModel1 ) ; 
119143        _mRpcController . Setup ( m =>  m . GetState ( ) ) . Returns ( modelWithWorkspace1 ) ; 
120144        _mUserNotifier . Setup ( m =>  m . ShowErrorNotification ( It . IsAny < string > ( ) ,  It . IsRegex ( "wrongworkspace" ) ,  ct ) ) 
121145            . Returns ( Task . CompletedTask ) ; 
122146        await  uriHandler . HandleUri ( input ,  ct ) ; 
147+         _mUserNotifier . Verify ( m =>  m . ShowErrorNotification ( It . IsAny < string > ( ) ,  It . IsAny < string > ( ) ,  ct ) ,  Times . Once ( ) ) ; 
123148    } 
124149
125150    [ Test ( Description  =  "Malformed Query String" ) ] 
126151    [ CancelAfter ( 30_000 ) ] 
127152    public  async  Task  MalformedQuery ( CancellationToken  ct ) 
128153    { 
129154        // there might be some query string that gets the parser to throw an exception, but I could not find one. 
130-         var  input  =  new  Uri ( "coder:/v0/open/ws/workspace1/agent/agent11/rdp?%&##" ) ; 
155+         var  input  =  new  Uri ( "coder://coder.test/ v0/open/ws/workspace1/agent/agent11/rdp?%&##" ) ; 
131156
157+         _mCredentialManager . Setup ( m =>  m . GetCachedCredentials ( ) ) . Returns ( credentialModel1 ) ; 
132158        _mRpcController . Setup ( m =>  m . GetState ( ) ) . Returns ( modelWithWorkspace1 ) ; 
133159        // treated the same as if we just didn't include credentials 
134160        _  =  _mRdpConnector . Setup ( m =>  m . Connect ( agent11 . Fqdn [ 0 ] ,  IRdpConnector . DefaultPort ,  ct ) ) 
135161            . Returns ( Task . CompletedTask ) ; 
136162        await  uriHandler . HandleUri ( input ,  ct ) ; 
163+         _mRdpConnector . Verify ( m =>  m . Connect ( It . IsAny < string > ( ) ,  It . IsAny < int > ( ) ,  ct ) ,  Times . Once ) ; 
137164    } 
138165
139166    [ Test ( Description  =  "VPN not started" ) ] 
140167    [ CancelAfter ( 30_000 ) ] 
141168    public  async  Task  VPNNotStarted ( CancellationToken  ct ) 
142169    { 
143-         var  input  =  new  Uri ( "coder:/v0/open/ws/wrongworkspace/agent/agent11/rdp" ) ; 
170+         var  input  =  new  Uri ( "coder://coder.test/ v0/open/ws/wrongworkspace/agent/agent11/rdp" ) ; 
144171
172+         _mCredentialManager . Setup ( m =>  m . GetCachedCredentials ( ) ) . Returns ( credentialModel1 ) ; 
145173        _mRpcController . Setup ( m =>  m . GetState ( ) ) . Returns ( new  RpcModel 
146174        { 
147175            VpnLifecycle  =  VpnLifecycle . Starting , 
@@ -150,29 +178,79 @@ public async Task VPNNotStarted(CancellationToken ct)
150178        _mUserNotifier . Setup ( m =>  m . ShowErrorNotification ( It . IsAny < string > ( ) ,  It . IsRegex ( "Coder Connect" ) ,  ct ) ) 
151179            . Returns ( Task . CompletedTask ) ; 
152180        await  uriHandler . HandleUri ( input ,  ct ) ; 
181+         _mUserNotifier . Verify ( m =>  m . ShowErrorNotification ( It . IsAny < string > ( ) ,  It . IsAny < string > ( ) ,  ct ) ,  Times . Once ( ) ) ; 
153182    } 
154183
155184    [ Test ( Description  =  "Wrong number of components" ) ] 
156185    [ CancelAfter ( 30_000 ) ] 
157186    public  async  Task  UnknownNumComponents ( CancellationToken  ct ) 
158187    { 
159-         var  input  =  new  Uri ( "coder:/v0/open/ws/wrongworkspace/agent11/rdp" ) ; 
188+         var  input  =  new  Uri ( "coder://coder.test/ v0/open/ws/wrongworkspace/agent11/rdp" ) ; 
160189
190+         _mCredentialManager . Setup ( m =>  m . GetCachedCredentials ( ) ) . Returns ( credentialModel1 ) ; 
161191        _mRpcController . Setup ( m =>  m . GetState ( ) ) . Returns ( modelWithWorkspace1 ) ; 
162192        _mUserNotifier . Setup ( m =>  m . ShowErrorNotification ( It . IsAny < string > ( ) ,  It . IsAny < string > ( ) ,  ct ) ) 
163193            . Returns ( Task . CompletedTask ) ; 
164194        await  uriHandler . HandleUri ( input ,  ct ) ; 
195+         _mUserNotifier . Verify ( m =>  m . ShowErrorNotification ( It . IsAny < string > ( ) ,  It . IsAny < string > ( ) ,  ct ) ,  Times . Once ( ) ) ; 
165196    } 
166197
167198    [ Test ( Description  =  "Unknown prefix" ) ] 
168199    [ CancelAfter ( 30_000 ) ] 
169200    public  async  Task  UnknownPrefix ( CancellationToken  ct ) 
170201    { 
171-         var  input  =  new  Uri ( "coder:/v300/open/ws/workspace1/agent/agent11/rdp" ) ; 
202+         var  input  =  new  Uri ( "coder://coder.test/ v300/open/ws/workspace1/agent/agent11/rdp" ) ; 
172203
204+         _mCredentialManager . Setup ( m =>  m . GetCachedCredentials ( ) ) . Returns ( credentialModel1 ) ; 
173205        _mRpcController . Setup ( m =>  m . GetState ( ) ) . Returns ( modelWithWorkspace1 ) ; 
174206        _mUserNotifier . Setup ( m =>  m . ShowErrorNotification ( It . IsAny < string > ( ) ,  It . IsAny < string > ( ) ,  ct ) ) 
175207            . Returns ( Task . CompletedTask ) ; 
176208        await  uriHandler . HandleUri ( input ,  ct ) ; 
209+         _mUserNotifier . Verify ( m =>  m . ShowErrorNotification ( It . IsAny < string > ( ) ,  It . IsAny < string > ( ) ,  ct ) ,  Times . Once ( ) ) ; 
210+     } 
211+ 
212+     [ Test ( Description  =  "Unknown authority" ) ] 
213+     [ CancelAfter ( 30_000 ) ] 
214+     public  async  Task  UnknownAuthority ( CancellationToken  ct ) 
215+     { 
216+         var  input  =  new  Uri ( "coder://unknown.test/v0/open/ws/workspace1/agent/agent11/rdp" ) ; 
217+ 
218+         _mCredentialManager . Setup ( m =>  m . GetCachedCredentials ( ) ) . Returns ( credentialModel1 ) ; 
219+         _mRpcController . Setup ( m =>  m . GetState ( ) ) . Returns ( modelWithWorkspace1 ) ; 
220+         _mUserNotifier . Setup ( m =>  m . ShowErrorNotification ( It . IsAny < string > ( ) ,  It . IsRegex ( @"unknown\.test" ) ,  ct ) ) 
221+             . Returns ( Task . CompletedTask ) ; 
222+         await  uriHandler . HandleUri ( input ,  ct ) ; 
223+         _mUserNotifier . Verify ( m =>  m . ShowErrorNotification ( It . IsAny < string > ( ) ,  It . IsAny < string > ( ) ,  ct ) ,  Times . Once ( ) ) ; 
224+     } 
225+ 
226+     [ Test ( Description  =  "Missing authority" ) ] 
227+     [ CancelAfter ( 30_000 ) ] 
228+     public  async  Task  MissingAuthority ( CancellationToken  ct ) 
229+     { 
230+         var  input  =  new  Uri ( "coder:/v0/open/ws/workspace1/agent/agent11/rdp" ) ; 
231+ 
232+         _mCredentialManager . Setup ( m =>  m . GetCachedCredentials ( ) ) . Returns ( credentialModel1 ) ; 
233+         _mRpcController . Setup ( m =>  m . GetState ( ) ) . Returns ( modelWithWorkspace1 ) ; 
234+         _mUserNotifier . Setup ( m =>  m . ShowErrorNotification ( It . IsAny < string > ( ) ,  It . IsRegex ( "Coder server" ) ,  ct ) ) 
235+             . Returns ( Task . CompletedTask ) ; 
236+         await  uriHandler . HandleUri ( input ,  ct ) ; 
237+         _mUserNotifier . Verify ( m =>  m . ShowErrorNotification ( It . IsAny < string > ( ) ,  It . IsAny < string > ( ) ,  ct ) ,  Times . Once ( ) ) ; 
238+     } 
239+ 
240+     [ Test ( Description  =  "Not signed in" ) ] 
241+     [ CancelAfter ( 30_000 ) ] 
242+     public  async  Task  NotSignedIn ( CancellationToken  ct ) 
243+     { 
244+         var  input  =  new  Uri ( "coder://coder.test/v0/open/ws/workspace1/agent/agent11/rdp" ) ; 
245+ 
246+         _mCredentialManager . Setup ( m =>  m . GetCachedCredentials ( ) ) . Returns ( new  CredentialModel ( ) 
247+         { 
248+             State  =  CredentialState . Invalid , 
249+         } ) ; 
250+         _mRpcController . Setup ( m =>  m . GetState ( ) ) . Returns ( modelWithWorkspace1 ) ; 
251+         _mUserNotifier . Setup ( m =>  m . ShowErrorNotification ( It . IsAny < string > ( ) ,  It . IsRegex ( "signed in" ) ,  ct ) ) 
252+             . Returns ( Task . CompletedTask ) ; 
253+         await  uriHandler . HandleUri ( input ,  ct ) ; 
254+         _mUserNotifier . Verify ( m =>  m . ShowErrorNotification ( It . IsAny < string > ( ) ,  It . IsAny < string > ( ) ,  ct ) ,  Times . Once ( ) ) ; 
177255    } 
178256} 
0 commit comments