@@ -129,8 +129,10 @@ func TestIndexServesServiceLinks(t *testing.T) {
129129func TestDashboardServicesAPIListsServiceRegistry (t * testing.T ) {
130130 s3Store := s3svc .NewFileBucketStore (t .TempDir ())
131131 server := NewServer (Config {
132- MailEndpoint : "smtp://127.0.0.1:2525" ,
133- S3Endpoint : "http://127.0.0.1:4567" ,
132+ MailEndpoint : "smtp://127.0.0.1:2525" ,
133+ MailStoragePath : ".devcloud/test/mail" ,
134+ S3Endpoint : "http://127.0.0.1:4567" ,
135+ S3StoragePath : ".devcloud/test/s3" ,
134136 }, newDashboardStore (nil , nil ), s3Store )
135137
136138 rec := performRequest (server .routes (), http .MethodGet , "/api/dashboard/services" )
@@ -149,18 +151,20 @@ func TestDashboardServicesAPIListsServiceRegistry(t *testing.T) {
149151 t .Fatalf ("services len = %d, want 2: %#v" , len (response .Services ), response .Services )
150152 }
151153 assertService (t , response .Services [0 ], DashboardService {
152- ID : "mail" ,
153- Name : "Mail" ,
154- Path : "/mail" ,
155- Status : "running" ,
156- Endpoint : "smtp://127.0.0.1:2525" ,
154+ ID : "mail" ,
155+ Name : "Mail" ,
156+ Path : "/mail" ,
157+ Status : "running" ,
158+ Endpoint : "smtp://127.0.0.1:2525" ,
159+ StoragePath : ".devcloud/test/mail" ,
157160 })
158161 assertService (t , response .Services [1 ], DashboardService {
159- ID : "s3" ,
160- Name : "S3" ,
161- Path : "/s3" ,
162- Status : "running" ,
163- Endpoint : "http://127.0.0.1:4567" ,
162+ ID : "s3" ,
163+ Name : "S3" ,
164+ Path : "/s3" ,
165+ Status : "running" ,
166+ Endpoint : "http://127.0.0.1:4567" ,
167+ StoragePath : ".devcloud/test/s3" ,
164168 })
165169}
166170
@@ -200,6 +204,77 @@ func TestDashboardServicesAPIRejectsUnsupportedMethods(t *testing.T) {
200204 }
201205}
202206
207+ func TestReactDashboardAssetsServeWithoutInterceptingCompatibilityRoutes (t * testing.T ) {
208+ routes := NewServer (Config {}, newDashboardStore (nil , nil )).routes ()
209+
210+ index := performRequest (routes , http .MethodGet , "/dashboard/" )
211+ if index .Code != http .StatusOK {
212+ t .Fatalf ("react dashboard status = %d, want %d" , index .Code , http .StatusOK )
213+ }
214+ if got := index .Header ().Get ("Content-Type" ); ! strings .HasPrefix (got , "text/html" ) {
215+ t .Fatalf ("react dashboard Content-Type = %q, want text/html" , got )
216+ }
217+ if body := index .Body .String (); ! strings .Contains (body , "devcloud Dashboard" ) {
218+ t .Fatalf ("react dashboard index missing title: %s" , body )
219+ }
220+
221+ nestedRoute := performRequest (routes , http .MethodGet , "/dashboard/mail" )
222+ if nestedRoute .Code != http .StatusOK {
223+ t .Fatalf ("react nested route status = %d, want %d" , nestedRoute .Code , http .StatusOK )
224+ }
225+ if body := nestedRoute .Body .String (); ! strings .Contains (body , "devcloud Dashboard" ) {
226+ t .Fatalf ("react nested route did not fall back to index: %s" , body )
227+ }
228+ if got := nestedRoute .Header ().Get ("Cache-Control" ); got != "no-cache" {
229+ t .Fatalf ("react nested route Cache-Control = %q, want no-cache" , got )
230+ }
231+
232+ assetPath := reactAssetPath (t , index .Body .String ())
233+ asset := performRequest (routes , http .MethodGet , assetPath )
234+ if asset .Code != http .StatusOK {
235+ t .Fatalf ("react asset status = %d, want %d for %s" , asset .Code , http .StatusOK , assetPath )
236+ }
237+ if got := asset .Header ().Get ("Cache-Control" ); got != "public, max-age=31536000, immutable" {
238+ t .Fatalf ("react asset Cache-Control = %q, want immutable cache" , got )
239+ }
240+ missingAsset := performRequest (routes , http .MethodGet , "/dashboard/assets/missing.js" )
241+ if missingAsset .Code != http .StatusNotFound {
242+ t .Fatalf ("missing react asset status = %d, want %d" , missingAsset .Code , http .StatusNotFound )
243+ }
244+
245+ compatMail := performRequest (routes , http .MethodGet , "/mail" )
246+ if compatMail .Code != http .StatusOK || ! strings .Contains (compatMail .Body .String (), "devcloud Mail" ) {
247+ t .Fatalf ("compat mail route changed: status=%d body=%s" , compatMail .Code , compatMail .Body .String ())
248+ }
249+
250+ registry := performRequest (routes , http .MethodGet , "/api/dashboard/services" )
251+ if registry .Code != http .StatusOK {
252+ t .Fatalf ("registry status = %d, want %d" , registry .Code , http .StatusOK )
253+ }
254+ if got := registry .Header ().Get ("Content-Type" ); ! strings .HasPrefix (got , "application/json" ) {
255+ t .Fatalf ("registry Content-Type = %q, want application/json" , got )
256+ }
257+ }
258+
259+ func reactAssetPath (t * testing.T , indexHTML string ) string {
260+ t .Helper ()
261+ marker := `src="/dashboard/`
262+ start := strings .Index (indexHTML , marker )
263+ if start == - 1 {
264+ marker = `href="/dashboard/`
265+ start = strings .Index (indexHTML , marker )
266+ }
267+ if start == - 1 {
268+ t .Fatalf ("react index missing dashboard asset reference: %s" , indexHTML )
269+ }
270+ start += len (marker ) - len ("/dashboard/" )
271+ end := strings .Index (indexHTML [start :], `"` )
272+ if end == - 1 {
273+ t .Fatalf ("react index has unterminated asset reference: %s" , indexHTML )
274+ }
275+ return indexHTML [start : start + end ]
276+ }
277+
203278func TestMailPathServesStaticMailDashboard (t * testing.T ) {
204279 server := NewServer (Config {}, newDashboardStore (nil , nil ))
205280 req := httptest .NewRequest (http .MethodGet , "/mail" , nil )
@@ -497,7 +572,7 @@ func performRequest(handler http.Handler, method string, target string) *httptes
497572
498573func assertService (t * testing.T , got DashboardService , want DashboardService ) {
499574 t .Helper ()
500- if got .ID != want .ID || got .Name != want .Name || got .Path != want .Path || got .Status != want .Status || got .Endpoint != want .Endpoint {
575+ if got .ID != want .ID || got .Name != want .Name || got .Path != want .Path || got .Status != want .Status || got .Endpoint != want .Endpoint || got . StoragePath != want . StoragePath {
501576 t .Fatalf ("service = %#v, want fields %#v" , got , want )
502577 }
503578 if got .Description == "" {
0 commit comments