timeline_test.go (8172B)
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 bundb_test 19 20 import ( 21 "context" 22 "testing" 23 "time" 24 25 "github.com/stretchr/testify/suite" 26 "github.com/superseriousbusiness/gotosocial/internal/ap" 27 "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" 28 "github.com/superseriousbusiness/gotosocial/internal/id" 29 "github.com/superseriousbusiness/gotosocial/testrig" 30 ) 31 32 type TimelineTestSuite struct { 33 BunDBStandardTestSuite 34 } 35 36 func getFutureStatus() *gtsmodel.Status { 37 theDistantFuture := time.Now().Add(876600 * time.Hour) 38 id, err := id.NewULIDFromTime(theDistantFuture) 39 if err != nil { 40 panic(err) 41 } 42 43 return >smodel.Status{ 44 ID: id, 45 URI: "http://localhost:8080/users/admin/statuses/" + id, 46 URL: "http://localhost:8080/@admin/statuses/" + id, 47 Content: "it's the future, wooooooooooooooooooooooooooooooooo", 48 Text: "it's the future, wooooooooooooooooooooooooooooooooo", 49 AttachmentIDs: []string{}, 50 TagIDs: []string{}, 51 MentionIDs: []string{}, 52 EmojiIDs: []string{}, 53 CreatedAt: theDistantFuture, 54 UpdatedAt: theDistantFuture, 55 Local: testrig.TrueBool(), 56 AccountURI: "http://localhost:8080/users/admin", 57 AccountID: "01F8MH17FWEB39HZJ76B6VXSKF", 58 InReplyToID: "", 59 BoostOfID: "", 60 ContentWarning: "", 61 Visibility: gtsmodel.VisibilityPublic, 62 Sensitive: testrig.FalseBool(), 63 Language: "en", 64 CreatedWithApplicationID: "01F8MGXQRHYF5QPMTMXP78QC2F", 65 Federated: testrig.TrueBool(), 66 Boostable: testrig.TrueBool(), 67 Replyable: testrig.TrueBool(), 68 Likeable: testrig.TrueBool(), 69 ActivityStreamsType: ap.ObjectNote, 70 } 71 } 72 73 func (suite *TimelineTestSuite) publicCount() int { 74 var publicCount int 75 76 for _, status := range suite.testStatuses { 77 if status.Visibility == gtsmodel.VisibilityPublic && 78 status.BoostOfID == "" { 79 publicCount++ 80 } 81 } 82 83 return publicCount 84 } 85 86 func (suite *TimelineTestSuite) checkStatuses(statuses []*gtsmodel.Status, maxID string, minID string, expectedLength int) { 87 if l := len(statuses); l != expectedLength { 88 suite.FailNow("", "expected %d statuses in slice, got %d", expectedLength, l) 89 } else if l == 0 { 90 // Can't test empty slice. 91 return 92 } 93 94 // Check ordering + bounds of statuses. 95 highest := statuses[0].ID 96 for _, status := range statuses { 97 id := status.ID 98 99 if id >= maxID { 100 suite.FailNow("", "%s greater than maxID %s", id, maxID) 101 } 102 103 if id <= minID { 104 suite.FailNow("", "%s smaller than minID %s", id, minID) 105 } 106 107 if id > highest { 108 suite.FailNow("", "statuses in slice were not ordered highest -> lowest ID") 109 } 110 111 highest = id 112 } 113 } 114 115 func (suite *TimelineTestSuite) TestGetPublicTimeline() { 116 ctx := context.Background() 117 118 s, err := suite.db.GetPublicTimeline(ctx, "", "", "", 20, false) 119 if err != nil { 120 suite.FailNow(err.Error()) 121 } 122 123 suite.checkStatuses(s, id.Highest, id.Lowest, suite.publicCount()) 124 } 125 126 func (suite *TimelineTestSuite) TestGetPublicTimelineWithFutureStatus() { 127 ctx := context.Background() 128 129 // Insert a status set far in the 130 // future, it shouldn't be retrieved. 131 futureStatus := getFutureStatus() 132 if err := suite.db.PutStatus(ctx, futureStatus); err != nil { 133 suite.FailNow(err.Error()) 134 } 135 136 s, err := suite.db.GetPublicTimeline(ctx, "", "", "", 20, false) 137 if err != nil { 138 suite.FailNow(err.Error()) 139 } 140 141 suite.NotContains(s, futureStatus) 142 suite.checkStatuses(s, id.Highest, id.Lowest, suite.publicCount()) 143 } 144 145 func (suite *TimelineTestSuite) TestGetHomeTimeline() { 146 var ( 147 ctx = context.Background() 148 viewingAccount = suite.testAccounts["local_account_1"] 149 ) 150 151 s, err := suite.db.GetHomeTimeline(ctx, viewingAccount.ID, "", "", "", 20, false) 152 if err != nil { 153 suite.FailNow(err.Error()) 154 } 155 156 suite.checkStatuses(s, id.Highest, id.Lowest, 16) 157 } 158 159 func (suite *TimelineTestSuite) TestGetHomeTimelineWithFutureStatus() { 160 var ( 161 ctx = context.Background() 162 viewingAccount = suite.testAccounts["local_account_1"] 163 ) 164 165 // Insert a status set far in the 166 // future, it shouldn't be retrieved. 167 futureStatus := getFutureStatus() 168 if err := suite.db.PutStatus(ctx, futureStatus); err != nil { 169 suite.FailNow(err.Error()) 170 } 171 172 s, err := suite.db.GetHomeTimeline(ctx, viewingAccount.ID, "", "", "", 20, false) 173 if err != nil { 174 suite.FailNow(err.Error()) 175 } 176 177 suite.NotContains(s, futureStatus) 178 suite.checkStatuses(s, id.Highest, id.Lowest, 16) 179 } 180 181 func (suite *TimelineTestSuite) TestGetHomeTimelineBackToFront() { 182 var ( 183 ctx = context.Background() 184 viewingAccount = suite.testAccounts["local_account_1"] 185 ) 186 187 s, err := suite.db.GetHomeTimeline(ctx, viewingAccount.ID, "", "", id.Lowest, 5, false) 188 if err != nil { 189 suite.FailNow(err.Error()) 190 } 191 192 suite.checkStatuses(s, id.Highest, id.Lowest, 5) 193 suite.Equal("01F8MHAYFKS4KMXF8K5Y1C0KRN", s[0].ID) 194 suite.Equal("01F8MH75CBF9JFX4ZAD54N0W0R", s[len(s)-1].ID) 195 } 196 197 func (suite *TimelineTestSuite) TestGetHomeTimelineFromHighest() { 198 var ( 199 ctx = context.Background() 200 viewingAccount = suite.testAccounts["local_account_1"] 201 ) 202 203 s, err := suite.db.GetHomeTimeline(ctx, viewingAccount.ID, id.Highest, "", "", 5, false) 204 if err != nil { 205 suite.FailNow(err.Error()) 206 } 207 208 suite.checkStatuses(s, id.Highest, id.Lowest, 5) 209 suite.Equal("01G36SF3V6Y6V5BF9P4R7PQG7G", s[0].ID) 210 suite.Equal("01FCTA44PW9H1TB328S9AQXKDS", s[len(s)-1].ID) 211 } 212 213 func (suite *TimelineTestSuite) TestGetListTimelineNoParams() { 214 var ( 215 ctx = context.Background() 216 list = suite.testLists["local_account_1_list_1"] 217 ) 218 219 s, err := suite.db.GetListTimeline(ctx, list.ID, "", "", "", 20) 220 if err != nil { 221 suite.FailNow(err.Error()) 222 } 223 224 suite.checkStatuses(s, id.Highest, id.Lowest, 11) 225 } 226 227 func (suite *TimelineTestSuite) TestGetListTimelineMaxID() { 228 var ( 229 ctx = context.Background() 230 list = suite.testLists["local_account_1_list_1"] 231 ) 232 233 s, err := suite.db.GetListTimeline(ctx, list.ID, id.Highest, "", "", 5) 234 if err != nil { 235 suite.FailNow(err.Error()) 236 } 237 238 suite.checkStatuses(s, id.Highest, id.Lowest, 5) 239 suite.Equal("01G36SF3V6Y6V5BF9P4R7PQG7G", s[0].ID) 240 suite.Equal("01FCQSQ667XHJ9AV9T27SJJSX5", s[len(s)-1].ID) 241 } 242 243 func (suite *TimelineTestSuite) TestGetListTimelineMinID() { 244 var ( 245 ctx = context.Background() 246 list = suite.testLists["local_account_1_list_1"] 247 ) 248 249 s, err := suite.db.GetListTimeline(ctx, list.ID, "", "", id.Lowest, 5) 250 if err != nil { 251 suite.FailNow(err.Error()) 252 } 253 254 suite.checkStatuses(s, id.Highest, id.Lowest, 5) 255 suite.Equal("01F8MHC8VWDRBQR0N1BATDDEM5", s[0].ID) 256 suite.Equal("01F8MH75CBF9JFX4ZAD54N0W0R", s[len(s)-1].ID) 257 } 258 259 func (suite *TimelineTestSuite) TestGetListTimelineMinIDPagingUp() { 260 var ( 261 ctx = context.Background() 262 list = suite.testLists["local_account_1_list_1"] 263 ) 264 265 s, err := suite.db.GetListTimeline(ctx, list.ID, "", "", "01F8MHC8VWDRBQR0N1BATDDEM5", 5) 266 if err != nil { 267 suite.FailNow(err.Error()) 268 } 269 270 suite.checkStatuses(s, id.Highest, "01F8MHC8VWDRBQR0N1BATDDEM5", 5) 271 suite.Equal("01G20ZM733MGN8J344T4ZDDFY1", s[0].ID) 272 suite.Equal("01F8MHCP5P2NWYQ416SBA0XSEV", s[len(s)-1].ID) 273 } 274 275 func TestTimelineTestSuite(t *testing.T) { 276 suite.Run(t, new(TimelineTestSuite)) 277 }