mattermost/server/channels/web/params_test.go
Agniva De Sarker 4803892492
MM-56906: Remove redundant calls on team switch (#30771)
On page load, we load ALL channels and channel members from all teams.
But then, on team_switch, we would again load channels and channel
members from that team. This was redundant and mainly kept
because previously the websocket events were considered unreliable.

Now with reliable websockets, and client-side pings, we can detect
broken connections faster and recover without loss.

Additionally, the getAllChannelMembers call would page through
all responses on the client side. This was inefficient and incur
extra latency. To optimize for this, we introduce server-side
streaming of the full response if page is set to -1.

This optimizes the intial response as well.

https://mattermost.atlassian.net/browse/MM-56906

```release-note
Optimize team switch operation by removing calls to get channels
and channel members.
```


Co-authored-by: Mattermost Build <build@mattermost.com>
2025-05-12 20:05:46 +05:30

502 lines
10 KiB
Go

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package web
import (
"net/http"
"net/url"
"testing"
"github.com/gorilla/mux"
"github.com/stretchr/testify/require"
"github.com/mattermost/mattermost/server/public/model"
)
func TestParamsFromRequest(t *testing.T) {
testCases := []struct {
Description string
URL *url.URL
Vars map[string]string
Params *Params
}{
{
"empty params",
mustURL("/"),
nil,
&Params{
PerPage: PerPageDefault,
LogsPerPage: LogsPerPageDefault,
LimitAfter: LimitDefault,
LimitBefore: LimitDefault,
},
},
{
"query params",
mustURL("/page?" +
"channel_id=abc123&" +
"filename=file.ext&" +
"page=42&" +
"time_range=then-till-now&" +
"permanent=1&" +
"logs_per_page=5&" +
"limit_after=6&" +
"limit_before=7&" +
"q=picard&" +
"is_linked=t&" +
"is_configured=TRUE&" +
"not_associated_to_team=this_team&" +
"not_associated_to_channel=this_channel&" +
"filter_allow_reference=true&" +
"filter_parent_team_permitted=True&" +
"paginate=T&" +
"include_member_count=1&" +
"not_associated_to_group=test&" +
"exclude_default_channels=1&" +
"group_ids=hello,world&" +
"include_total_count=T&" +
"include_deleted=True&" +
"exclude_policy_constrained=TRUE&" +
"filter_has_member=xyz"),
nil,
&Params{
ChannelId: "abc123",
Filename: "file.ext",
Page: 42,
TimeRange: "then-till-now",
PerPage: PerPageDefault,
Permanent: true,
LogsPerPage: 5,
LimitAfter: 6,
LimitBefore: 7,
Q: "picard",
IsLinked: boolPtr(true),
IsConfigured: boolPtr(true),
NotAssociatedToTeam: "this_team",
NotAssociatedToChannel: "this_channel",
FilterAllowReference: true,
FilterParentTeamPermitted: true,
Paginate: boolPtr(true),
IncludeMemberCount: true,
NotAssociatedToGroup: "test",
ExcludeDefaultChannels: true,
GroupIDs: "hello,world",
IncludeTotalCount: true,
IncludeDeleted: true,
ExcludePolicyConstrained: true,
FilterHasMember: "xyz",
},
},
{
"page invalid",
mustURL("?page=hello"),
nil,
&Params{
Page: PageDefault,
PerPage: PerPageDefault,
LogsPerPage: LogsPerPageDefault,
LimitAfter: LimitDefault,
LimitBefore: LimitDefault,
},
},
{
"page negative",
mustURL("?page=-1"),
nil,
&Params{
Page: PageDefault,
PerPage: PerPageDefault,
LogsPerPage: LogsPerPageDefault,
LimitAfter: LimitDefault,
LimitBefore: LimitDefault,
},
},
{
"per page valid",
mustURL("?per_page=123"),
nil,
&Params{
PerPage: 123,
LogsPerPage: LogsPerPageDefault,
LimitAfter: LimitDefault,
LimitBefore: LimitDefault,
},
},
{
"per page too small",
mustURL("?per_page=-100"),
nil,
&Params{
PerPage: PerPageDefault,
LogsPerPage: LogsPerPageDefault,
LimitAfter: LimitDefault,
LimitBefore: LimitDefault,
},
},
{
"per page too big",
mustURL("?per_page=100000"),
nil,
&Params{
PerPage: PerPageMaximum,
LogsPerPage: LogsPerPageDefault,
LimitAfter: LimitDefault,
LimitBefore: LimitDefault,
},
},
{
"logs per page valid",
mustURL("?logs_per_page=512"),
nil,
&Params{
LogsPerPage: 512,
PerPage: PerPageDefault,
LimitAfter: LimitDefault,
LimitBefore: LimitDefault,
},
},
{
"logs per page invalid",
mustURL("?logs_per_page=logs"),
nil,
&Params{
LogsPerPage: LogsPerPageDefault,
PerPage: PerPageDefault,
LimitAfter: LimitDefault,
LimitBefore: LimitDefault,
},
},
{
"logs per page too small",
mustURL("?logs_per_page=-512"),
nil,
&Params{
LogsPerPage: LogsPerPageDefault,
PerPage: PerPageDefault,
LimitAfter: LimitDefault,
LimitBefore: LimitDefault,
},
},
{
"logs per page too big",
mustURL("?logs_per_page=99999999"),
nil,
&Params{
LogsPerPage: LogsPerPageMaximum,
PerPage: PerPageDefault,
LimitAfter: LimitDefault,
LimitBefore: LimitDefault,
},
},
{
"limit before valid",
mustURL("?limit_before=100"),
nil,
&Params{
LimitBefore: 100,
PerPage: PerPageDefault,
LogsPerPage: LogsPerPageDefault,
LimitAfter: LimitDefault,
},
},
{
"limit before invalid",
mustURL("?limit_before=limit"),
nil,
&Params{
LimitBefore: LimitDefault,
PerPage: PerPageDefault,
LogsPerPage: LogsPerPageDefault,
LimitAfter: LimitDefault,
},
},
{
"limit before too small",
mustURL("?limit_before=-100"),
nil,
&Params{
LimitBefore: LimitDefault,
PerPage: PerPageDefault,
LogsPerPage: LogsPerPageDefault,
LimitAfter: LimitDefault,
},
},
{
"limit before too big",
mustURL("?limit_before=99999"),
nil,
&Params{
LimitBefore: LimitMaximum,
PerPage: PerPageDefault,
LogsPerPage: LogsPerPageDefault,
LimitAfter: LimitDefault,
},
},
{
"limit after valid",
mustURL("?limit_after=100"),
nil,
&Params{
LimitAfter: 100,
PerPage: PerPageDefault,
LogsPerPage: LogsPerPageDefault,
LimitBefore: LimitDefault,
},
},
{
"limit after invalid",
mustURL("?limit_after=limit"),
nil,
&Params{
LimitAfter: LimitDefault,
PerPage: PerPageDefault,
LogsPerPage: LogsPerPageDefault,
LimitBefore: LimitDefault,
},
},
{
"limit after too small",
mustURL("?limit_aftere=-100"),
nil,
&Params{
LimitAfter: LimitDefault,
PerPage: PerPageDefault,
LogsPerPage: LogsPerPageDefault,
LimitBefore: LimitDefault,
},
},
{
"limit after too big",
mustURL("?limit_after=99999"),
nil,
&Params{
LimitAfter: LimitMaximum,
PerPage: PerPageDefault,
LogsPerPage: LogsPerPageDefault,
LimitBefore: LimitDefault,
},
},
{
"group source custom",
mustURL("?group_source=custom"),
nil,
&Params{
GroupSource: model.GroupSourceCustom,
PerPage: PerPageDefault,
LogsPerPage: LogsPerPageDefault,
LimitBefore: LimitDefault,
LimitAfter: LimitDefault,
},
},
{
"group source LDAP",
mustURL("?group_source=ldap"),
nil,
&Params{
GroupSource: model.GroupSourceLdap,
PerPage: PerPageDefault,
LogsPerPage: LogsPerPageDefault,
LimitBefore: LimitDefault,
LimitAfter: LimitDefault,
},
},
{
"group source other",
mustURL("?group_source=aabbcc"),
nil,
&Params{
GroupSource: model.GroupSourceLdap,
PerPage: PerPageDefault,
LogsPerPage: LogsPerPageDefault,
LimitBefore: LimitDefault,
LimitAfter: LimitDefault,
},
},
{
"group source empty",
mustURL("?group_souce="),
nil,
&Params{
GroupSource: "",
PerPage: PerPageDefault,
LogsPerPage: LogsPerPageDefault,
LimitBefore: LimitDefault,
LimitAfter: LimitDefault,
},
},
{
"timestamp valid",
mustURL("/"),
map[string]string{
"timestamp": "1234567",
},
&Params{
Timestamp: 1234567,
PerPage: PerPageDefault,
LogsPerPage: LogsPerPageDefault,
LimitBefore: LimitDefault,
LimitAfter: LimitDefault,
},
},
{
"timestamp valid",
mustURL("/"),
map[string]string{
"timestamp": "yes",
},
&Params{
Timestamp: 0,
PerPage: PerPageDefault,
LogsPerPage: LogsPerPageDefault,
LimitBefore: LimitDefault,
LimitAfter: LimitDefault,
},
},
{
"timestamp too small",
mustURL("/"),
map[string]string{
"timestamp": "-1234567",
},
&Params{
Timestamp: 0,
PerPage: PerPageDefault,
LogsPerPage: LogsPerPageDefault,
LimitBefore: LimitDefault,
LimitAfter: LimitDefault,
},
},
{
"syncable type teams",
mustURL("/"),
map[string]string{
"syncable_type": "teams",
},
&Params{
SyncableType: model.GroupSyncableTypeTeam,
PerPage: PerPageDefault,
LogsPerPage: LogsPerPageDefault,
LimitBefore: LimitDefault,
LimitAfter: LimitDefault,
},
},
{
"syncable type channels",
mustURL("/"),
map[string]string{
"syncable_type": "channels",
},
&Params{
SyncableType: model.GroupSyncableTypeChannel,
PerPage: PerPageDefault,
LogsPerPage: LogsPerPageDefault,
LimitBefore: LimitDefault,
LimitAfter: LimitDefault,
},
},
{
"syncable type other",
mustURL("/"),
map[string]string{
"syncable_type": "unknownvalue",
},
&Params{
SyncableType: "",
PerPage: PerPageDefault,
LogsPerPage: LogsPerPageDefault,
LimitBefore: LimitDefault,
LimitAfter: LimitDefault,
},
},
{
"include channel bookmarks",
mustURL("/?include_bookmarks=true"),
nil,
&Params{
BookmarksSince: 0,
LimitAfter: LimitDefault,
PerPage: PerPageDefault,
LogsPerPage: LogsPerPageDefault,
LimitBefore: LimitDefault,
},
},
{
"include channel bookmarks with negative bookmark since",
mustURL("/?include_bookmarks=true&bookmarks_since=-1"),
nil,
&Params{
BookmarksSince: 0,
LimitAfter: LimitDefault,
PerPage: PerPageDefault,
LogsPerPage: LogsPerPageDefault,
LimitBefore: LimitDefault,
},
},
{
"include channel bookmarks with bookmark since",
mustURL("/?include_bookmarks=true&bookmarks_since=123456789"),
nil,
&Params{
BookmarksSince: 123456789,
LimitAfter: LimitDefault,
PerPage: PerPageDefault,
LogsPerPage: LogsPerPageDefault,
LimitBefore: LimitDefault,
},
},
}
for _, testCase := range testCases {
t.Run(testCase.Description, func(t *testing.T) {
t.Parallel()
r := &http.Request{URL: testCase.URL}
r = mux.SetURLVars(r, testCase.Vars)
params := ParamsFromRequest(r)
require.Equal(t, testCase.Params, params)
})
}
}
func mustURL(u string) *url.URL {
parsed, err := url.Parse(u)
if err != nil {
panic(err)
}
return parsed
}
func boolPtr(b bool) *bool {
return &b
}