mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-11-08 23:57:30 -06:00
[bugfix] ensure timeline limit query is respected (#4141)
# Description Fixes a bug in the new timeline code in which the limit query parameter wasn't always being fulfilled, in which case some clients like Tusky would then assume it didn't need to add a "load more" placeholder view even when there were more statuses to be loaded. This also fiddles around a bit in the logging middleware handler to add some more code comments, and add logging of full request URIs when it is safe to do so. ## Checklist - [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md). - [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat. - [x] I/we have not leveraged AI to create the proposed changes. - [x] I/we have performed a self-review of added code. - [x] I/we have written code that is legible and maintainable by others. - [x] I/we have commented the added code, particularly in hard-to-understand areas. - [ ] I/we have made any necessary changes to documentation. - [x] I/we have added tests that cover new code. - [x] I/we have run tests and they pass locally with the changes. - [x] I/we have run `go fmt ./...` and `golangci-lint run`. Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4141 Co-authored-by: kim <grufwub@gmail.com> Co-committed-by: kim <grufwub@gmail.com>
This commit is contained in:
parent
e464de1322
commit
8264b63337
5 changed files with 172 additions and 65 deletions
83
internal/cache/timeline/status_test.go
vendored
83
internal/cache/timeline/status_test.go
vendored
|
|
@ -18,11 +18,16 @@
|
|||
package timeline
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"slices"
|
||||
"testing"
|
||||
|
||||
apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/id"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/log"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/paging"
|
||||
"codeberg.org/gruf/go-structr"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
|
@ -60,6 +65,46 @@ var testStatusMeta = []*StatusMeta{
|
|||
},
|
||||
}
|
||||
|
||||
func TestStatusTimelineLoadLimit(t *testing.T) {
|
||||
var tt StatusTimeline
|
||||
tt.Init(1000)
|
||||
|
||||
// Prepare new context for the duration of this test.
|
||||
ctx, cncl := context.WithCancel(context.Background())
|
||||
defer cncl()
|
||||
|
||||
// Clone the input test status data.
|
||||
data := slices.Clone(testStatusMeta)
|
||||
|
||||
// Insert test data into timeline.
|
||||
_ = tt.cache.Insert(data...)
|
||||
|
||||
// Manually mark timeline as 'preloaded'.
|
||||
tt.preloader.CheckPreload(tt.preloader.Done)
|
||||
|
||||
// Craft a new page for selection,
|
||||
// setting placeholder min / max values
|
||||
// but in particular setting a limit
|
||||
// HIGHER than currently cached values.
|
||||
page := new(paging.Page)
|
||||
page.Min = paging.MinID(id.Lowest)
|
||||
page.Max = paging.MaxID(id.Highest)
|
||||
page.Limit = len(data) + 10
|
||||
|
||||
// Load crafted page from the cache. This
|
||||
// SHOULD load all cached entries, then
|
||||
// generate an extra 10 statuses up to limit.
|
||||
apiStatuses, _, _, err := tt.Load(ctx,
|
||||
page,
|
||||
loadGeneratedStatusPage,
|
||||
loadStatusIDsFrom(data),
|
||||
nil, // no filtering
|
||||
func(status *gtsmodel.Status) (*apimodel.Status, error) { return new(apimodel.Status), nil },
|
||||
)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, apiStatuses, page.Limit)
|
||||
}
|
||||
|
||||
func TestStatusTimelineUnprepare(t *testing.T) {
|
||||
var tt StatusTimeline
|
||||
tt.Init(1000)
|
||||
|
|
@ -301,6 +346,44 @@ func TestStatusTimelineTrim(t *testing.T) {
|
|||
assert.Equal(t, before, tt.cache.Len())
|
||||
}
|
||||
|
||||
// loadStatusIDsFrom imitates loading of statuses of given IDs from the database, instead selecting
|
||||
// statuses with appropriate IDs from the given slice of status meta, converting them to statuses.
|
||||
func loadStatusIDsFrom(data []*StatusMeta) func(ids []string) ([]*gtsmodel.Status, error) {
|
||||
return func(ids []string) ([]*gtsmodel.Status, error) {
|
||||
var statuses []*gtsmodel.Status
|
||||
for _, id := range ids {
|
||||
i := slices.IndexFunc(data, func(s *StatusMeta) bool {
|
||||
return s.ID == id
|
||||
})
|
||||
if i < 0 || i >= len(data) {
|
||||
panic(fmt.Sprintf("could not find %s in %v", id, log.VarDump(data)))
|
||||
}
|
||||
statuses = append(statuses, >smodel.Status{
|
||||
ID: data[i].ID,
|
||||
AccountID: data[i].AccountID,
|
||||
BoostOfID: data[i].BoostOfID,
|
||||
BoostOfAccountID: data[i].BoostOfAccountID,
|
||||
})
|
||||
}
|
||||
return statuses, nil
|
||||
}
|
||||
}
|
||||
|
||||
// loadGeneratedStatusPage imitates loading of a given page of statuses,
|
||||
// simply generating new statuses until the given page's limit is reached.
|
||||
func loadGeneratedStatusPage(page *paging.Page) ([]*gtsmodel.Status, error) {
|
||||
var statuses []*gtsmodel.Status
|
||||
for range page.Limit {
|
||||
statuses = append(statuses, >smodel.Status{
|
||||
ID: id.NewULID(),
|
||||
AccountID: id.NewULID(),
|
||||
BoostOfID: id.NewULID(),
|
||||
BoostOfAccountID: id.NewULID(),
|
||||
})
|
||||
}
|
||||
return statuses, nil
|
||||
}
|
||||
|
||||
// containsStatusID returns whether timeline contains a status with ID.
|
||||
func containsStatusID(t *StatusTimeline, id string) bool {
|
||||
return getStatusByID(t, id) != nil
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue