bookmarks_test.go (12293B)
1 // GoToSocial 2 // Copyright (C) GoToSocial Authors admin@gotosocial.org 3 // SPDX-License-Identifier: AGPL-3.0-or-later 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package bookmarks_test 19 20 import ( 21 "context" 22 "encoding/json" 23 "fmt" 24 "io/ioutil" 25 "net/http" 26 "net/http/httptest" 27 "strconv" 28 "testing" 29 30 "github.com/stretchr/testify/suite" 31 "github.com/superseriousbusiness/gotosocial/internal/api/client/bookmarks" 32 "github.com/superseriousbusiness/gotosocial/internal/api/client/statuses" 33 apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" 34 "github.com/superseriousbusiness/gotosocial/internal/config" 35 "github.com/superseriousbusiness/gotosocial/internal/db" 36 "github.com/superseriousbusiness/gotosocial/internal/email" 37 "github.com/superseriousbusiness/gotosocial/internal/federation" 38 "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" 39 "github.com/superseriousbusiness/gotosocial/internal/media" 40 "github.com/superseriousbusiness/gotosocial/internal/oauth" 41 "github.com/superseriousbusiness/gotosocial/internal/processing" 42 "github.com/superseriousbusiness/gotosocial/internal/state" 43 "github.com/superseriousbusiness/gotosocial/internal/storage" 44 "github.com/superseriousbusiness/gotosocial/internal/typeutils" 45 "github.com/superseriousbusiness/gotosocial/internal/visibility" 46 "github.com/superseriousbusiness/gotosocial/testrig" 47 ) 48 49 type BookmarkTestSuite struct { 50 // standard suite interfaces 51 suite.Suite 52 db db.DB 53 tc typeutils.TypeConverter 54 mediaManager *media.Manager 55 federator federation.Federator 56 emailSender email.Sender 57 processor *processing.Processor 58 storage *storage.Driver 59 state state.State 60 61 // standard suite models 62 testTokens map[string]*gtsmodel.Token 63 testClients map[string]*gtsmodel.Client 64 testApplications map[string]*gtsmodel.Application 65 testUsers map[string]*gtsmodel.User 66 testAccounts map[string]*gtsmodel.Account 67 testAttachments map[string]*gtsmodel.MediaAttachment 68 testStatuses map[string]*gtsmodel.Status 69 testFollows map[string]*gtsmodel.Follow 70 testBookmarks map[string]*gtsmodel.StatusBookmark 71 72 // module being tested 73 statusModule *statuses.Module 74 bookmarkModule *bookmarks.Module 75 } 76 77 func (suite *BookmarkTestSuite) SetupSuite() { 78 suite.testTokens = testrig.NewTestTokens() 79 suite.testClients = testrig.NewTestClients() 80 suite.testApplications = testrig.NewTestApplications() 81 suite.testUsers = testrig.NewTestUsers() 82 suite.testAccounts = testrig.NewTestAccounts() 83 suite.testAttachments = testrig.NewTestAttachments() 84 suite.testStatuses = testrig.NewTestStatuses() 85 suite.testFollows = testrig.NewTestFollows() 86 suite.testBookmarks = testrig.NewTestBookmarks() 87 } 88 89 func (suite *BookmarkTestSuite) SetupTest() { 90 suite.state.Caches.Init() 91 testrig.StartWorkers(&suite.state) 92 93 testrig.InitTestConfig() 94 testrig.InitTestLog() 95 96 suite.db = testrig.NewTestDB(&suite.state) 97 suite.state.DB = suite.db 98 suite.storage = testrig.NewInMemoryStorage() 99 suite.state.Storage = suite.storage 100 101 suite.tc = testrig.NewTestTypeConverter(suite.db) 102 103 testrig.StartTimelines( 104 &suite.state, 105 visibility.NewFilter(&suite.state), 106 suite.tc, 107 ) 108 109 testrig.StandardDBSetup(suite.db, nil) 110 testrig.StandardStorageSetup(suite.storage, "../../../../testrig/media") 111 112 suite.mediaManager = testrig.NewTestMediaManager(&suite.state) 113 suite.federator = testrig.NewTestFederator(&suite.state, testrig.NewTestTransportController(&suite.state, testrig.NewMockHTTPClient(nil, "../../../../testrig/media")), suite.mediaManager) 114 suite.emailSender = testrig.NewEmailSender("../../../../web/template/", nil) 115 suite.processor = testrig.NewTestProcessor(&suite.state, suite.federator, suite.emailSender, suite.mediaManager) 116 suite.statusModule = statuses.New(suite.processor) 117 suite.bookmarkModule = bookmarks.New(suite.processor) 118 } 119 120 func (suite *BookmarkTestSuite) TearDownTest() { 121 testrig.StandardDBTeardown(suite.db) 122 testrig.StandardStorageTeardown(suite.storage) 123 testrig.StopWorkers(&suite.state) 124 } 125 126 func (suite *BookmarkTestSuite) getBookmarks( 127 account *gtsmodel.Account, 128 token *gtsmodel.Token, 129 user *gtsmodel.User, 130 expectedHTTPStatus int, 131 maxID string, 132 minID string, 133 limit int, 134 ) ([]*apimodel.Status, string, error) { 135 // instantiate recorder + test context 136 recorder := httptest.NewRecorder() 137 ctx, _ := testrig.CreateGinTestContext(recorder, nil) 138 ctx.Set(oauth.SessionAuthorizedAccount, account) 139 ctx.Set(oauth.SessionAuthorizedToken, oauth.DBTokenToToken(token)) 140 ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"]) 141 ctx.Set(oauth.SessionAuthorizedUser, user) 142 143 // create the request URI 144 requestPath := bookmarks.BasePath + "?" + bookmarks.LimitKey + "=" + strconv.Itoa(limit) 145 if maxID != "" { 146 requestPath = requestPath + "&" + bookmarks.MaxIDKey + "=" + maxID 147 } 148 if minID != "" { 149 requestPath = requestPath + "&" + bookmarks.MinIDKey + "=" + minID 150 } 151 baseURI := config.GetProtocol() + "://" + config.GetHost() 152 requestURI := baseURI + "/api/" + requestPath 153 154 // create the request 155 ctx.Request = httptest.NewRequest(http.MethodGet, requestURI, nil) 156 ctx.Request.Header.Set("accept", "application/json") 157 158 // trigger the handler 159 suite.bookmarkModule.BookmarksGETHandler(ctx) 160 161 // read the response 162 result := recorder.Result() 163 defer result.Body.Close() 164 165 if resultCode := recorder.Code; expectedHTTPStatus != resultCode { 166 return nil, "", fmt.Errorf("expected %d got %d", expectedHTTPStatus, resultCode) 167 } 168 169 b, err := ioutil.ReadAll(result.Body) 170 if err != nil { 171 return nil, "", err 172 } 173 174 resp := []*apimodel.Status{} 175 if err := json.Unmarshal(b, &resp); err != nil { 176 return nil, "", err 177 } 178 179 return resp, result.Header.Get("Link"), nil 180 } 181 182 func (suite *BookmarkTestSuite) TestGetBookmarksSingle() { 183 testAccount := suite.testAccounts["local_account_1"] 184 testToken := suite.testTokens["local_account_1"] 185 testUser := suite.testUsers["local_account_1"] 186 187 statuses, linkHeader, err := suite.getBookmarks(testAccount, testToken, testUser, http.StatusOK, "", "", 10) 188 if err != nil { 189 suite.FailNow(err.Error()) 190 } 191 192 suite.Len(statuses, 1) 193 suite.Equal(`<http://localhost:8080/api/v1/bookmarks?limit=10&max_id=01F8MHD2QCZSZ6WQS2ATVPEYJ9>; rel="next", <http://localhost:8080/api/v1/bookmarks?limit=10&min_id=01F8MHD2QCZSZ6WQS2ATVPEYJ9>; rel="prev"`, linkHeader) 194 } 195 196 func (suite *BookmarkTestSuite) TestGetBookmarksMultiple() { 197 testAccount := suite.testAccounts["local_account_1"] 198 testToken := suite.testTokens["local_account_1"] 199 testUser := suite.testUsers["local_account_1"] 200 201 // Add a few extra bookmarks for this account. 202 ctx := context.Background() 203 for _, b := range []*gtsmodel.StatusBookmark{ 204 { 205 ID: "01GSZPDQYE9WZ26T501KMM876V", // oldest 206 AccountID: testAccount.ID, 207 StatusID: suite.testStatuses["admin_account_status_2"].ID, 208 TargetAccountID: suite.testAccounts["admin_account"].ID, 209 }, 210 { 211 ID: "01GSZPGHY3ACEN11D512V6MR0M", 212 AccountID: testAccount.ID, 213 StatusID: suite.testStatuses["admin_account_status_3"].ID, 214 TargetAccountID: suite.testAccounts["admin_account"].ID, 215 }, 216 { 217 ID: "01GSZPGY4ZSHNV0PR3HSBB1DDV", // newest 218 AccountID: testAccount.ID, 219 StatusID: suite.testStatuses["admin_account_status_4"].ID, 220 TargetAccountID: suite.testAccounts["admin_account"].ID, 221 }, 222 } { 223 if err := suite.db.Put(ctx, b); err != nil { 224 suite.FailNow(err.Error()) 225 } 226 } 227 228 statuses, linkHeader, err := suite.getBookmarks(testAccount, testToken, testUser, http.StatusOK, "", "", 10) 229 if err != nil { 230 suite.FailNow(err.Error()) 231 } 232 233 suite.Len(statuses, 4) 234 suite.Equal(`<http://localhost:8080/api/v1/bookmarks?limit=10&max_id=01F8MHD2QCZSZ6WQS2ATVPEYJ9>; rel="next", <http://localhost:8080/api/v1/bookmarks?limit=10&min_id=01GSZPGY4ZSHNV0PR3HSBB1DDV>; rel="prev"`, linkHeader) 235 } 236 237 func (suite *BookmarkTestSuite) TestGetBookmarksMultiplePaging() { 238 testAccount := suite.testAccounts["local_account_1"] 239 testToken := suite.testTokens["local_account_1"] 240 testUser := suite.testUsers["local_account_1"] 241 242 // Add a few extra bookmarks for this account. 243 ctx := context.Background() 244 for _, b := range []*gtsmodel.StatusBookmark{ 245 { 246 ID: "01GSZPDQYE9WZ26T501KMM876V", // oldest 247 AccountID: testAccount.ID, 248 StatusID: suite.testStatuses["admin_account_status_2"].ID, 249 TargetAccountID: suite.testAccounts["admin_account"].ID, 250 }, 251 { 252 ID: "01GSZPGHY3ACEN11D512V6MR0M", 253 AccountID: testAccount.ID, 254 StatusID: suite.testStatuses["admin_account_status_3"].ID, 255 TargetAccountID: suite.testAccounts["admin_account"].ID, 256 }, 257 { 258 ID: "01GSZPGY4ZSHNV0PR3HSBB1DDV", // newest 259 AccountID: testAccount.ID, 260 StatusID: suite.testStatuses["admin_account_status_4"].ID, 261 TargetAccountID: suite.testAccounts["admin_account"].ID, 262 }, 263 } { 264 if err := suite.db.Put(ctx, b); err != nil { 265 suite.FailNow(err.Error()) 266 } 267 } 268 269 statuses, linkHeader, err := suite.getBookmarks(testAccount, testToken, testUser, http.StatusOK, "01GSZPGY4ZSHNV0PR3HSBB1DDV", "", 10) 270 if err != nil { 271 suite.FailNow(err.Error()) 272 } 273 274 suite.Len(statuses, 3) 275 suite.Equal(`<http://localhost:8080/api/v1/bookmarks?limit=10&max_id=01F8MHD2QCZSZ6WQS2ATVPEYJ9>; rel="next", <http://localhost:8080/api/v1/bookmarks?limit=10&min_id=01GSZPGHY3ACEN11D512V6MR0M>; rel="prev"`, linkHeader) 276 } 277 278 func (suite *BookmarkTestSuite) TestGetBookmarksNone() { 279 testAccount := suite.testAccounts["local_account_1"] 280 testToken := suite.testTokens["local_account_1"] 281 testUser := suite.testUsers["local_account_1"] 282 283 // Remove all bookmarks for this account. 284 if err := suite.db.DeleteStatusBookmarks(context.Background(), "", testAccount.ID); err != nil { 285 suite.FailNow(err.Error()) 286 } 287 288 statuses, linkHeader, err := suite.getBookmarks(testAccount, testToken, testUser, http.StatusOK, "", "", 10) 289 if err != nil { 290 suite.FailNow(err.Error()) 291 } 292 293 suite.Empty(statuses) 294 suite.Empty(linkHeader) 295 } 296 297 func (suite *BookmarkTestSuite) TestGetBookmarksNonexistentStatus() { 298 testAccount := suite.testAccounts["local_account_1"] 299 testToken := suite.testTokens["local_account_1"] 300 testUser := suite.testUsers["local_account_1"] 301 302 // Add a few extra bookmarks for this account. 303 ctx := context.Background() 304 for _, b := range []*gtsmodel.StatusBookmark{ 305 { 306 ID: "01GSZPDQYE9WZ26T501KMM876V", // oldest 307 AccountID: testAccount.ID, 308 StatusID: suite.testStatuses["admin_account_status_2"].ID, 309 TargetAccountID: suite.testAccounts["admin_account"].ID, 310 }, 311 { 312 ID: "01GSZPGHY3ACEN11D512V6MR0M", 313 AccountID: testAccount.ID, 314 StatusID: suite.testStatuses["admin_account_status_3"].ID, 315 TargetAccountID: suite.testAccounts["admin_account"].ID, 316 }, 317 { 318 ID: "01GSZPGY4ZSHNV0PR3HSBB1DDV", // newest 319 AccountID: testAccount.ID, 320 StatusID: "01GSZQCRX4CXPECWA5M37QNV9F", // <-- THIS ONE DOESN'T EXIST 321 TargetAccountID: suite.testAccounts["admin_account"].ID, 322 }, 323 } { 324 if err := suite.db.Put(ctx, b); err != nil { 325 suite.FailNow(err.Error()) 326 } 327 } 328 329 statuses, linkHeader, err := suite.getBookmarks(testAccount, testToken, testUser, http.StatusOK, "", "", 10) 330 if err != nil { 331 suite.FailNow(err.Error()) 332 } 333 334 suite.Len(statuses, 3) 335 suite.Equal(`<http://localhost:8080/api/v1/bookmarks?limit=10&max_id=01F8MHD2QCZSZ6WQS2ATVPEYJ9>; rel="next", <http://localhost:8080/api/v1/bookmarks?limit=10&min_id=01GSZPGHY3ACEN11D512V6MR0M>; rel="prev"`, linkHeader) 336 } 337 338 func TestBookmarkTestSuite(t *testing.T) { 339 suite.Run(t, new(BookmarkTestSuite)) 340 }