diff options
author | 2023-06-21 18:26:40 +0200 | |
---|---|---|
committer | 2023-06-21 17:26:40 +0100 | |
commit | 831ae09f8bab04af854243421047371339c3e190 (patch) | |
tree | f7709d478cc363dc1899bdb658fe20e2dc7986f3 /internal/api/client/accounts/search_test.go | |
parent | [docs] Disambiguate docker version, don't recommend opening localhost (#1913) (diff) | |
download | gotosocial-831ae09f8bab04af854243421047371339c3e190.tar.xz |
[feature] Add partial text search for accounts + statuses (#1836)
Diffstat (limited to 'internal/api/client/accounts/search_test.go')
-rw-r--r-- | internal/api/client/accounts/search_test.go | 430 |
1 files changed, 430 insertions, 0 deletions
diff --git a/internal/api/client/accounts/search_test.go b/internal/api/client/accounts/search_test.go new file mode 100644 index 000000000..7d778f090 --- /dev/null +++ b/internal/api/client/accounts/search_test.go @@ -0,0 +1,430 @@ +// GoToSocial +// Copyright (C) GoToSocial Authors admin@gotosocial.org +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +package accounts_test + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "net/http/httptest" + "net/url" + "strconv" + "strings" + "testing" + + "github.com/stretchr/testify/suite" + "github.com/superseriousbusiness/gotosocial/internal/api/client/accounts" + apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" + apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util" + "github.com/superseriousbusiness/gotosocial/internal/gtserror" + "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" + "github.com/superseriousbusiness/gotosocial/internal/oauth" + "github.com/superseriousbusiness/gotosocial/testrig" +) + +type AccountSearchTestSuite struct { + AccountStandardTestSuite +} + +func (suite *AccountSearchTestSuite) getSearch( + requestingAccount *gtsmodel.Account, + token *gtsmodel.Token, + user *gtsmodel.User, + limit *int, + offset *int, + query string, + resolve *bool, + following *bool, + expectedHTTPStatus int, + expectedBody string, +) ([]*apimodel.Account, error) { + var ( + recorder = httptest.NewRecorder() + ctx, _ = testrig.CreateGinTestContext(recorder, nil) + requestURL = testrig.URLMustParse("/api" + accounts.BasePath + "/search") + queryParts []string + ) + + // Put the request together. + if limit != nil { + queryParts = append(queryParts, apiutil.LimitKey+"="+strconv.Itoa(*limit)) + } + + if offset != nil { + queryParts = append(queryParts, apiutil.SearchOffsetKey+"="+strconv.Itoa(*offset)) + } + + queryParts = append(queryParts, apiutil.SearchQueryKey+"="+url.QueryEscape(query)) + + if resolve != nil { + queryParts = append(queryParts, apiutil.SearchResolveKey+"="+strconv.FormatBool(*resolve)) + } + + if following != nil { + queryParts = append(queryParts, apiutil.SearchFollowingKey+"="+strconv.FormatBool(*following)) + } + + requestURL.RawQuery = strings.Join(queryParts, "&") + ctx.Request = httptest.NewRequest(http.MethodGet, requestURL.String(), nil) + ctx.Set(oauth.SessionAuthorizedAccount, requestingAccount) + ctx.Set(oauth.SessionAuthorizedToken, oauth.DBTokenToToken(token)) + ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"]) + ctx.Set(oauth.SessionAuthorizedUser, user) + + // Trigger the function being tested. + suite.accountsModule.AccountSearchGETHandler(ctx) + + // Read the result. + result := recorder.Result() + defer result.Body.Close() + + b, err := io.ReadAll(result.Body) + if err != nil { + suite.FailNow(err.Error()) + } + + errs := gtserror.MultiError{} + + // Check expected code + body. + if resultCode := recorder.Code; expectedHTTPStatus != resultCode { + errs = append(errs, fmt.Sprintf("expected %d got %d", expectedHTTPStatus, resultCode)) + } + + // If we got an expected body, return early. + if expectedBody != "" && string(b) != expectedBody { + errs = append(errs, fmt.Sprintf("expected %s got %s", expectedBody, string(b))) + } + + if err := errs.Combine(); err != nil { + suite.FailNow("", "%v (body %s)", err, string(b)) + } + + accounts := []*apimodel.Account{} + if err := json.Unmarshal(b, &accounts); err != nil { + suite.FailNow(err.Error()) + } + + return accounts, nil +} + +func (suite *AccountSearchTestSuite) TestSearchZorkOK() { + var ( + requestingAccount = suite.testAccounts["local_account_1"] + token = suite.testTokens["local_account_1"] + user = suite.testUsers["local_account_1"] + limit *int = nil + offset *int = nil + resolve *bool = nil + query = "zork" + following *bool = nil + expectedHTTPStatus = http.StatusOK + expectedBody = "" + ) + + accounts, err := suite.getSearch( + requestingAccount, + token, + user, + limit, + offset, + query, + resolve, + following, + expectedHTTPStatus, + expectedBody, + ) + + if err != nil { + suite.FailNow(err.Error()) + } + + if l := len(accounts); l != 1 { + suite.FailNow("", "expected length %d got %d", 1, l) + } +} + +func (suite *AccountSearchTestSuite) TestSearchZorkExactOK() { + var ( + requestingAccount = suite.testAccounts["local_account_1"] + token = suite.testTokens["local_account_1"] + user = suite.testUsers["local_account_1"] + limit *int = nil + offset *int = nil + resolve *bool = nil + query = "@the_mighty_zork" + following *bool = nil + expectedHTTPStatus = http.StatusOK + expectedBody = "" + ) + + accounts, err := suite.getSearch( + requestingAccount, + token, + user, + limit, + offset, + query, + resolve, + following, + expectedHTTPStatus, + expectedBody, + ) + + if err != nil { + suite.FailNow(err.Error()) + } + + if l := len(accounts); l != 1 { + suite.FailNow("", "expected length %d got %d", 1, l) + } +} + +func (suite *AccountSearchTestSuite) TestSearchZorkWithDomainOK() { + var ( + requestingAccount = suite.testAccounts["local_account_1"] + token = suite.testTokens["local_account_1"] + user = suite.testUsers["local_account_1"] + limit *int = nil + offset *int = nil + resolve *bool = nil + query = "@the_mighty_zork@localhost:8080" + following *bool = nil + expectedHTTPStatus = http.StatusOK + expectedBody = "" + ) + + accounts, err := suite.getSearch( + requestingAccount, + token, + user, + limit, + offset, + query, + resolve, + following, + expectedHTTPStatus, + expectedBody, + ) + + if err != nil { + suite.FailNow(err.Error()) + } + + if l := len(accounts); l != 1 { + suite.FailNow("", "expected length %d got %d", 1, l) + } +} + +func (suite *AccountSearchTestSuite) TestSearchFossSatanNotFollowing() { + var ( + requestingAccount = suite.testAccounts["local_account_1"] + token = suite.testTokens["local_account_1"] + user = suite.testUsers["local_account_1"] + limit *int = nil + offset *int = nil + resolve *bool = nil + query = "foss_satan" + following *bool = func() *bool { i := false; return &i }() + expectedHTTPStatus = http.StatusOK + expectedBody = "" + ) + + accounts, err := suite.getSearch( + requestingAccount, + token, + user, + limit, + offset, + query, + resolve, + following, + expectedHTTPStatus, + expectedBody, + ) + + if err != nil { + suite.FailNow(err.Error()) + } + + if l := len(accounts); l != 1 { + suite.FailNow("", "expected length %d got %d", 1, l) + } +} + +func (suite *AccountSearchTestSuite) TestSearchFossSatanFollowing() { + var ( + requestingAccount = suite.testAccounts["local_account_1"] + token = suite.testTokens["local_account_1"] + user = suite.testUsers["local_account_1"] + limit *int = nil + offset *int = nil + resolve *bool = nil + query = "foss_satan" + following *bool = func() *bool { i := true; return &i }() + expectedHTTPStatus = http.StatusOK + expectedBody = "" + ) + + accounts, err := suite.getSearch( + requestingAccount, + token, + user, + limit, + offset, + query, + resolve, + following, + expectedHTTPStatus, + expectedBody, + ) + + if err != nil { + suite.FailNow(err.Error()) + } + + if l := len(accounts); l != 0 { + suite.FailNow("", "expected length %d got %d", 0, l) + } +} + +func (suite *AccountSearchTestSuite) TestSearchBonkersQuery() { + var ( + requestingAccount = suite.testAccounts["local_account_1"] + token = suite.testTokens["local_account_1"] + user = suite.testUsers["local_account_1"] + limit *int = nil + offset *int = nil + resolve *bool = nil + query = "aaaaa@aaaaaaaaa@aaaaa **** this won't@ return anything!@!!" + following *bool = nil + expectedHTTPStatus = http.StatusOK + expectedBody = "" + ) + + accounts, err := suite.getSearch( + requestingAccount, + token, + user, + limit, + offset, + query, + resolve, + following, + expectedHTTPStatus, + expectedBody, + ) + + if err != nil { + suite.FailNow(err.Error()) + } + + if l := len(accounts); l != 0 { + suite.FailNow("", "expected length %d got %d", 0, l) + } +} + +func (suite *AccountSearchTestSuite) TestSearchAFollowing() { + var ( + requestingAccount = suite.testAccounts["local_account_1"] + token = suite.testTokens["local_account_1"] + user = suite.testUsers["local_account_1"] + limit *int = nil + offset *int = nil + resolve *bool = nil + query = "a" + following *bool = nil + expectedHTTPStatus = http.StatusOK + expectedBody = "" + ) + + accounts, err := suite.getSearch( + requestingAccount, + token, + user, + limit, + offset, + query, + resolve, + following, + expectedHTTPStatus, + expectedBody, + ) + + if err != nil { + suite.FailNow(err.Error()) + } + + if l := len(accounts); l != 5 { + suite.FailNow("", "expected length %d got %d", 5, l) + } + + usernames := make([]string, 0, 5) + for _, account := range accounts { + usernames = append(usernames, account.Username) + } + + suite.EqualValues([]string{"her_fuckin_maj", "foss_satan", "1happyturtle", "the_mighty_zork", "admin"}, usernames) +} + +func (suite *AccountSearchTestSuite) TestSearchANotFollowing() { + var ( + requestingAccount = suite.testAccounts["local_account_1"] + token = suite.testTokens["local_account_1"] + user = suite.testUsers["local_account_1"] + limit *int = nil + offset *int = nil + resolve *bool = nil + query = "a" + following *bool = func() *bool { i := true; return &i }() + expectedHTTPStatus = http.StatusOK + expectedBody = "" + ) + + accounts, err := suite.getSearch( + requestingAccount, + token, + user, + limit, + offset, + query, + resolve, + following, + expectedHTTPStatus, + expectedBody, + ) + + if err != nil { + suite.FailNow(err.Error()) + } + + if l := len(accounts); l != 2 { + suite.FailNow("", "expected length %d got %d", 2, l) + } + + usernames := make([]string, 0, 2) + for _, account := range accounts { + usernames = append(usernames, account.Username) + } + + suite.EqualValues([]string{"1happyturtle", "admin"}, usernames) +} + +func TestAccountSearchTestSuite(t *testing.T) { + suite.Run(t, new(AccountSearchTestSuite)) +} |