@@ -37,9 +37,12 @@ func Test_ResolveRequest(t *testing.T) {
37
37
appNameAuthed = "app-authed"
38
38
appNamePublic = "app-public"
39
39
appNameInvalidURL = "app-invalid-url"
40
- appNameUnhealthy = "app-unhealthy"
40
+ // Users can access unhealthy and initializing apps (as of 2024-02).
41
+ appNameUnhealthy = "app-unhealthy"
42
+ appNameInitializing = "app-initializing"
41
43
42
44
// This agent will never connect, so it will never become "connected".
45
+ // Users cannot access unhealthy agents.
43
46
agentNameUnhealthy = "agent-unhealthy"
44
47
appNameAgentUnhealthy = "app-agent-unhealthy"
45
48
@@ -55,6 +58,15 @@ func Test_ResolveRequest(t *testing.T) {
55
58
w .WriteHeader (http .StatusInternalServerError )
56
59
_ ,_ = w .Write ([]byte ("unhealthy" ))
57
60
}))
61
+ t .Cleanup (unhealthySrv .Close )
62
+
63
+ // Start a listener for a server that never responds.
64
+ initializingServer ,err := net .Listen ("tcp" ,"localhost:0" )
65
+ require .NoError (t ,err )
66
+ t .Cleanup (func () {
67
+ _ = initializingServer .Close ()
68
+ })
69
+ initializingURL := fmt .Sprintf ("http://%s" ,initializingServer .Addr ().String ())
58
70
59
71
deploymentValues := coderdtest .DeploymentValues (t )
60
72
deploymentValues .DisablePathApps = false
@@ -82,7 +94,7 @@ func Test_ResolveRequest(t *testing.T) {
82
94
})
83
95
84
96
ctx ,cancel := context .WithTimeout (context .Background (),testutil .WaitMedium )
85
- defer cancel ( )
97
+ t . Cleanup ( cancel )
86
98
87
99
firstUser := coderdtest .CreateFirstUser (t ,client )
88
100
me ,err := client .User (ctx ,codersdk .Me )
@@ -143,6 +155,17 @@ func Test_ResolveRequest(t *testing.T) {
143
155
Threshold :1 ,
144
156
},
145
157
},
158
+ {
159
+ Slug :appNameInitializing ,
160
+ DisplayName :appNameInitializing ,
161
+ SharingLevel :proto .AppSharingLevel_PUBLIC ,
162
+ Url :appURL ,
163
+ Healthcheck :& proto.Healthcheck {
164
+ Url :initializingURL ,
165
+ Interval :30 ,
166
+ Threshold :1000 ,
167
+ },
168
+ },
146
169
},
147
170
},
148
171
{
@@ -805,7 +828,55 @@ func Test_ResolveRequest(t *testing.T) {
805
828
require .Contains (t ,bodyStr ,`Agent state is "` )
806
829
})
807
830
808
- t .Run ("UnhealthyApp" ,func (t * testing.T ) {
831
+ // Initializing apps are now permitted to connect anyways. This wasn't
832
+ // always the case, but we're testing the behavior to ensure it doesn't
833
+ // change back accidentally.
834
+ t .Run ("InitializingAppPermitted" ,func (t * testing.T ) {
835
+ t .Parallel ()
836
+
837
+ ctx ,cancel := context .WithTimeout (context .Background (),testutil .WaitShort )
838
+ defer cancel ()
839
+
840
+ agent ,err := client .WorkspaceAgent (ctx ,agentID )
841
+ require .NoError (t ,err )
842
+
843
+ for _ ,app := range agent .Apps {
844
+ if app .Slug == appNameInitializing {
845
+ t .Log ("app is" ,app .Health )
846
+ require .Equal (t ,codersdk .WorkspaceAppHealthInitializing ,app .Health )
847
+ break
848
+ }
849
+ }
850
+
851
+ req := (workspaceapps.Request {
852
+ AccessMethod :workspaceapps .AccessMethodPath ,
853
+ BasePath :"/app" ,
854
+ UsernameOrID :me .Username ,
855
+ WorkspaceNameOrID :workspace .Name ,
856
+ AgentNameOrID :agentName ,
857
+ AppSlugOrPort :appNameInitializing ,
858
+ }).Normalize ()
859
+
860
+ rw := httptest .NewRecorder ()
861
+ r := httptest .NewRequest ("GET" ,"/app" ,nil )
862
+ r .Header .Set (codersdk .SessionTokenHeader ,client .SessionToken ())
863
+
864
+ token ,ok := workspaceapps .ResolveRequest (rw ,r , workspaceapps.ResolveRequestOptions {
865
+ Logger :api .Logger ,
866
+ SignedTokenProvider :api .WorkspaceAppsProvider ,
867
+ DashboardURL :api .AccessURL ,
868
+ PathAppBaseURL :api .AccessURL ,
869
+ AppHostname :api .AppHostname ,
870
+ AppRequest :req ,
871
+ })
872
+ require .True (t ,ok ,"ResolveRequest failed, should pass even though app is initializing" )
873
+ require .NotNil (t ,token )
874
+ })
875
+
876
+ // Unhealthy apps are now permitted to connect anyways. This wasn't always
877
+ // the case, but we're testing the behavior to ensure it doesn't change back
878
+ // accidentally.
879
+ t .Run ("UnhealthyAppPermitted" ,func (t * testing.T ) {
809
880
t .Parallel ()
810
881
811
882
require .Eventually (t ,func ()bool {
@@ -850,17 +921,7 @@ func Test_ResolveRequest(t *testing.T) {
850
921
AppHostname :api .AppHostname ,
851
922
AppRequest :req ,
852
923
})
853
- require .False (t ,ok ,"request succeeded even though app is unhealthy" )
854
- require .Nil (t ,token )
855
-
856
- w := rw .Result ()
857
- defer w .Body .Close ()
858
- require .Equal (t ,http .StatusBadGateway ,w .StatusCode )
859
-
860
- body ,err := io .ReadAll (w .Body )
861
- require .NoError (t ,err )
862
- bodyStr := string (body )
863
- bodyStr = strings .ReplaceAll (bodyStr ,""" ,`"` )
864
- require .Contains (t ,bodyStr ,`App health is "unhealthy"` )
924
+ require .True (t ,ok ,"ResolveRequest failed, should pass even though app is unhealthy" )
925
+ require .NotNil (t ,token )
865
926
})
866
927
}