Skip to content

Commit 41a898f

Browse files
authored
Merge pull request #4031 from gofiber/update-app.reloadviews-for-sub-app-reloading
2 parents 52eaa82 + 539bed9 commit 41a898f

File tree

4 files changed

+116
-10
lines changed

4 files changed

+116
-10
lines changed

app.go

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -715,16 +715,30 @@ func (app *App) ReloadViews() error {
715715
app.mutex.Lock()
716716
defer app.mutex.Unlock()
717717

718-
if app.config.Views == nil {
719-
return ErrNoViewEngineConfigured
718+
apps := map[string]*App{"": app}
719+
if app.mountFields != nil {
720+
apps = app.mountFields.appList
720721
}
721722

722-
if viewValue := reflect.ValueOf(app.config.Views); viewValue.Kind() == reflect.Pointer && viewValue.IsNil() {
723-
return ErrNoViewEngineConfigured
723+
var reloaded bool
724+
for _, targetApp := range apps {
725+
if targetApp == nil || targetApp.config.Views == nil {
726+
continue
727+
}
728+
729+
if viewValue := reflect.ValueOf(targetApp.config.Views); viewValue.Kind() == reflect.Pointer && viewValue.IsNil() {
730+
continue
731+
}
732+
733+
if err := targetApp.config.Views.Load(); err != nil {
734+
return fmt.Errorf("fiber: failed to reload views: %w", err)
735+
}
736+
737+
reloaded = true
724738
}
725739

726-
if err := app.config.Views.Load(); err != nil {
727-
return fmt.Errorf("fiber: failed to reload views: %w", err)
740+
if !reloaded {
741+
return ErrNoViewEngineConfigured
728742
}
729743

730744
return nil
@@ -845,8 +859,7 @@ func (app *App) Use(args ...any) Router {
845859

846860
for _, prefix := range prefixes {
847861
if subApp != nil {
848-
app.mount(prefix, subApp)
849-
return app
862+
return app.mount(prefix, subApp)
850863
}
851864

852865
app.register([]string{methodUse}, prefix, nil, handlers...)

app_test.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,25 @@ import (
3636
"github.com/valyala/fasthttp/fasthttputil"
3737
)
3838

39+
type fileView struct {
40+
path string
41+
content string
42+
loads int
43+
}
44+
45+
func (v *fileView) Load() error {
46+
contents, err := os.ReadFile(v.path)
47+
if err != nil {
48+
return fmt.Errorf("read template: %w", err)
49+
}
50+
51+
v.content = string(contents)
52+
v.loads++
53+
return nil
54+
}
55+
56+
func (*fileView) Render(io.Writer, string, any, ...string) error { return nil }
57+
3958
func testEmptyHandler(_ Ctx) error {
4059
return nil
4160
}
@@ -2047,6 +2066,77 @@ func Test_App_ReloadViews_InterfaceNilPointer(t *testing.T) {
20472066
require.ErrorIs(t, err, ErrNoViewEngineConfigured)
20482067
}
20492068

2069+
func Test_App_ReloadViews_MountedViews(t *testing.T) {
2070+
t.Parallel()
2071+
tempDir := t.TempDir()
2072+
templatePath := filepath.Join(tempDir, "template.html")
2073+
2074+
require.NoError(t, os.WriteFile(templatePath, []byte("before"), 0o600))
2075+
2076+
view := &fileView{path: templatePath}
2077+
subApp := New(Config{Views: view})
2078+
app := New()
2079+
app.Use("/sub", subApp)
2080+
2081+
require.NoError(t, view.Load())
2082+
initialLoads := view.loads
2083+
require.Equal(t, "before", view.content)
2084+
2085+
require.NoError(t, os.WriteFile(templatePath, []byte("after"), 0o600))
2086+
require.NoError(t, app.ReloadViews())
2087+
2088+
require.Equal(t, "after", view.content)
2089+
require.Greater(t, view.loads, initialLoads)
2090+
}
2091+
2092+
func Test_App_ReloadViews_MountedViews_Error(t *testing.T) {
2093+
t.Parallel()
2094+
expectedErr := errors.New("sub view error")
2095+
subView := &countingView{loadErr: expectedErr}
2096+
subApp := New(Config{Views: subView})
2097+
app := New()
2098+
app.Use("/sub", subApp)
2099+
2100+
err := app.ReloadViews()
2101+
require.ErrorIs(t, err, expectedErr)
2102+
}
2103+
2104+
func Test_App_ReloadViews_MountedViews_MultipleApps(t *testing.T) {
2105+
t.Parallel()
2106+
viewA := &countingView{}
2107+
viewB := &countingView{}
2108+
subAppA := New(Config{Views: viewA})
2109+
subAppB := New(Config{Views: viewB})
2110+
app := New()
2111+
app.Use("/a", subAppA)
2112+
app.Use("/b", subAppB)
2113+
2114+
initialLoadsA := viewA.loads
2115+
initialLoadsB := viewB.loads
2116+
2117+
require.NoError(t, app.ReloadViews())
2118+
2119+
require.Equal(t, initialLoadsA+1, viewA.loads)
2120+
require.Equal(t, initialLoadsB+1, viewB.loads)
2121+
}
2122+
2123+
func Test_App_ReloadViews_MountedViews_WithParentViews(t *testing.T) {
2124+
t.Parallel()
2125+
parentView := &countingView{}
2126+
subView := &countingView{}
2127+
subApp := New(Config{Views: subView})
2128+
app := New(Config{Views: parentView})
2129+
app.Use("/sub", subApp)
2130+
2131+
initialParentLoads := parentView.loads
2132+
initialSubLoads := subView.loads
2133+
2134+
require.NoError(t, app.ReloadViews())
2135+
2136+
require.Equal(t, initialParentLoads+1, parentView.loads)
2137+
require.Equal(t, initialSubLoads+1, subView.loads)
2138+
}
2139+
20502140
// go test -run Test_App_Init_Error_View
20512141
func Test_App_Init_Error_View(t *testing.T) {
20522142
t.Parallel()

group.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,7 @@ func (grp *Group) Use(args ...any) Router {
9696

9797
for _, prefix := range prefixes {
9898
if subApp != nil {
99-
grp.mount(prefix, subApp)
100-
return grp
99+
return grp.mount(prefix, subApp)
101100
}
102101

103102
grp.app.register([]string{methodUse}, getGroupPath(grp.Prefix, prefix), grp, handlers...)

mount.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,15 @@ func (app *App) mount(prefix string, subApp *App) Router {
4545
prefix = "/"
4646
}
4747

48+
app.mutex.Lock()
4849
// Support for configs of mounted-apps and sub-mounted-apps
4950
for mountedPrefixes, subApp := range subApp.mountFields.appList {
5051
path := getGroupPath(prefix, mountedPrefixes)
5152

5253
subApp.mountFields.mountPath = path
5354
app.mountFields.appList[path] = subApp
5455
}
56+
app.mutex.Unlock()
5557

5658
// register mounted group
5759
mountGroup := &Group{Prefix: prefix, app: subApp}
@@ -75,13 +77,15 @@ func (grp *Group) mount(prefix string, subApp *App) Router {
7577
groupPath = "/"
7678
}
7779

80+
grp.app.mutex.Lock()
7881
// Support for configs of mounted-apps and sub-mounted-apps
7982
for mountedPrefixes, subApp := range subApp.mountFields.appList {
8083
path := getGroupPath(groupPath, mountedPrefixes)
8184

8285
subApp.mountFields.mountPath = path
8386
grp.app.mountFields.appList[path] = subApp
8487
}
88+
grp.app.mutex.Unlock()
8589

8690
// register mounted group
8791
mountGroup := &Group{Prefix: groupPath, app: subApp}

0 commit comments

Comments
 (0)