Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions db/bolt/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ func (d *BoltDb) GetTemplatesWithPermissions(projectID int, userID int, filter d
return
}

// Initialize as a non-nil slice so an empty result marshals to `[]` rather than `null`.
// The web UI's templates page hangs when the API returns `null` (issue #3245).
templates = make([]db.TemplateWithPerms, 0, len(res))

for _, tpl := range res {
var tplWithPerms db.TemplateWithPerms
tplWithPerms.Template = tpl
Expand Down
28 changes: 28 additions & 0 deletions db/bolt/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,31 @@ func Test_SetTemplateDescription(t *testing.T) {
t.Fatalf("expected description to be 'New description', got '%s'", *tpl.Description)
}
}

// Regression test for #3245: GetTemplatesWithPermissions used to return a nil
// slice when no templates matched, which JSON-marshals to `null` and wedges
// the web UI's templates page. The API contract is an array; an empty result
// must serialize to `[]`.
func Test_GetTemplatesWithPermissions_EmptyReturnsNonNilSlice(t *testing.T) {
store := CreateTestStore()

proj, err := store.CreateProject(db.Project{
Created: tz.Now(),
Name: "TestProject",
})
if err != nil {
t.Fatal(err.Error())
}

templates, err := store.GetTemplatesWithPermissions(proj.ID, 0, db.TemplateFilter{}, db.RetrieveQueryParams{})
if err != nil {
t.Fatal(err.Error())
}

if templates == nil {
t.Fatal("expected empty (non-nil) slice for project with no templates, got nil")
}
if len(templates) != 0 {
t.Fatalf("expected zero templates, got %d", len(templates))
}
}
Loading