gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

relationship_test.go (28195B)


      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 	"errors"
     23 	"reflect"
     24 	"testing"
     25 	"time"
     26 
     27 	"github.com/stretchr/testify/suite"
     28 	"github.com/superseriousbusiness/gotosocial/internal/db"
     29 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
     30 	"github.com/superseriousbusiness/gotosocial/internal/id"
     31 	"github.com/superseriousbusiness/gotosocial/testrig"
     32 )
     33 
     34 type RelationshipTestSuite struct {
     35 	BunDBStandardTestSuite
     36 }
     37 
     38 func (suite *RelationshipTestSuite) TestGetBlockBy() {
     39 	t := suite.T()
     40 
     41 	// Create a new context for this test.
     42 	ctx, cncl := context.WithCancel(context.Background())
     43 	defer cncl()
     44 
     45 	// Sentinel error to mark avoiding a test case.
     46 	sentinelErr := errors.New("sentinel")
     47 
     48 	// isEqual checks if 2 block models are equal.
     49 	isEqual := func(b1, b2 gtsmodel.Block) bool {
     50 		// Clear populated sub-models.
     51 		b1.Account = nil
     52 		b2.Account = nil
     53 		b1.TargetAccount = nil
     54 		b2.TargetAccount = nil
     55 
     56 		// Clear database-set fields.
     57 		b1.CreatedAt = time.Time{}
     58 		b2.CreatedAt = time.Time{}
     59 		b1.UpdatedAt = time.Time{}
     60 		b2.UpdatedAt = time.Time{}
     61 
     62 		return reflect.DeepEqual(b1, b2)
     63 	}
     64 
     65 	var testBlocks []*gtsmodel.Block
     66 
     67 	for _, account1 := range suite.testAccounts {
     68 		for _, account2 := range suite.testAccounts {
     69 			if account1.ID == account2.ID {
     70 				// don't block *yourself* ...
     71 				continue
     72 			}
     73 
     74 			// Create new account block.
     75 			block := &gtsmodel.Block{
     76 				ID:              id.NewULID(),
     77 				URI:             "http://127.0.0.1:8080/" + id.NewULID(),
     78 				AccountID:       account1.ID,
     79 				TargetAccountID: account2.ID,
     80 			}
     81 
     82 			// Attempt to place the block in database (if not already).
     83 			if err := suite.db.PutBlock(ctx, block); err != nil {
     84 				if err != db.ErrAlreadyExists {
     85 					// Unrecoverable database error.
     86 					t.Fatalf("error creating block: %v", err)
     87 				}
     88 
     89 				// Fetch existing block from database between accounts.
     90 				block, _ = suite.db.GetBlock(ctx, account1.ID, account2.ID)
     91 				continue
     92 			}
     93 
     94 			// Append generated block to test cases.
     95 			testBlocks = append(testBlocks, block)
     96 		}
     97 	}
     98 
     99 	for _, block := range testBlocks {
    100 		for lookup, dbfunc := range map[string]func() (*gtsmodel.Block, error){
    101 			"id": func() (*gtsmodel.Block, error) {
    102 				return suite.db.GetBlockByID(ctx, block.ID)
    103 			},
    104 
    105 			"uri": func() (*gtsmodel.Block, error) {
    106 				return suite.db.GetBlockByURI(ctx, block.URI)
    107 			},
    108 
    109 			"origin_target": func() (*gtsmodel.Block, error) {
    110 				return suite.db.GetBlock(ctx, block.AccountID, block.TargetAccountID)
    111 			},
    112 		} {
    113 
    114 			// Clear database caches.
    115 			suite.state.Caches.Init()
    116 
    117 			t.Logf("checking database lookup %q", lookup)
    118 
    119 			// Perform database function.
    120 			checkBlock, err := dbfunc()
    121 			if err != nil {
    122 				if err == sentinelErr {
    123 					continue
    124 				}
    125 
    126 				t.Errorf("error encountered for database lookup %q: %v", lookup, err)
    127 				continue
    128 			}
    129 
    130 			// Check received block data.
    131 			if !isEqual(*checkBlock, *block) {
    132 				t.Errorf("block does not contain expected data: %+v", checkBlock)
    133 				continue
    134 			}
    135 
    136 			// Check that block origin account populated.
    137 			if checkBlock.Account == nil || checkBlock.Account.ID != block.AccountID {
    138 				t.Errorf("block origin account not correctly populated for: %+v", checkBlock)
    139 				continue
    140 			}
    141 
    142 			// Check that block target account populated.
    143 			if checkBlock.TargetAccount == nil || checkBlock.TargetAccount.ID != block.TargetAccountID {
    144 				t.Errorf("block target account not correctly populated for: %+v", checkBlock)
    145 				continue
    146 			}
    147 		}
    148 	}
    149 }
    150 
    151 func (suite *RelationshipTestSuite) TestGetFollowBy() {
    152 	t := suite.T()
    153 
    154 	// Create a new context for this test.
    155 	ctx, cncl := context.WithCancel(context.Background())
    156 	defer cncl()
    157 
    158 	// Sentinel error to mark avoiding a test case.
    159 	sentinelErr := errors.New("sentinel")
    160 
    161 	// isEqual checks if 2 follow models are equal.
    162 	isEqual := func(f1, f2 gtsmodel.Follow) bool {
    163 		// Clear populated sub-models.
    164 		f1.Account = nil
    165 		f2.Account = nil
    166 		f1.TargetAccount = nil
    167 		f2.TargetAccount = nil
    168 
    169 		// Clear database-set fields.
    170 		f1.CreatedAt = time.Time{}
    171 		f2.CreatedAt = time.Time{}
    172 		f1.UpdatedAt = time.Time{}
    173 		f2.UpdatedAt = time.Time{}
    174 
    175 		return reflect.DeepEqual(f1, f2)
    176 	}
    177 
    178 	var testFollows []*gtsmodel.Follow
    179 
    180 	for _, account1 := range suite.testAccounts {
    181 		for _, account2 := range suite.testAccounts {
    182 			if account1.ID == account2.ID {
    183 				// don't follow *yourself* ...
    184 				continue
    185 			}
    186 
    187 			// Create new account follow.
    188 			follow := &gtsmodel.Follow{
    189 				ID:              id.NewULID(),
    190 				URI:             "http://127.0.0.1:8080/" + id.NewULID(),
    191 				AccountID:       account1.ID,
    192 				TargetAccountID: account2.ID,
    193 			}
    194 
    195 			// Attempt to place the follow in database (if not already).
    196 			if err := suite.db.PutFollow(ctx, follow); err != nil {
    197 				if err != db.ErrAlreadyExists {
    198 					// Unrecoverable database error.
    199 					t.Fatalf("error creating follow: %v", err)
    200 				}
    201 
    202 				// Fetch existing follow from database between accounts.
    203 				follow, _ = suite.db.GetFollow(ctx, account1.ID, account2.ID)
    204 				continue
    205 			}
    206 
    207 			// Append generated follow to test cases.
    208 			testFollows = append(testFollows, follow)
    209 		}
    210 	}
    211 
    212 	for _, follow := range testFollows {
    213 		for lookup, dbfunc := range map[string]func() (*gtsmodel.Follow, error){
    214 			"id": func() (*gtsmodel.Follow, error) {
    215 				return suite.db.GetFollowByID(ctx, follow.ID)
    216 			},
    217 
    218 			"uri": func() (*gtsmodel.Follow, error) {
    219 				return suite.db.GetFollowByURI(ctx, follow.URI)
    220 			},
    221 
    222 			"origin_target": func() (*gtsmodel.Follow, error) {
    223 				return suite.db.GetFollow(ctx, follow.AccountID, follow.TargetAccountID)
    224 			},
    225 		} {
    226 			// Clear database caches.
    227 			suite.state.Caches.Init()
    228 
    229 			t.Logf("checking database lookup %q", lookup)
    230 
    231 			// Perform database function.
    232 			checkFollow, err := dbfunc()
    233 			if err != nil {
    234 				if err == sentinelErr {
    235 					continue
    236 				}
    237 
    238 				t.Errorf("error encountered for database lookup %q: %v", lookup, err)
    239 				continue
    240 			}
    241 
    242 			// Check received follow data.
    243 			if !isEqual(*checkFollow, *follow) {
    244 				t.Errorf("follow does not contain expected data: %+v", checkFollow)
    245 				continue
    246 			}
    247 
    248 			// Check that follow origin account populated.
    249 			if checkFollow.Account == nil || checkFollow.Account.ID != follow.AccountID {
    250 				t.Errorf("follow origin account not correctly populated for: %+v", checkFollow)
    251 				continue
    252 			}
    253 
    254 			// Check that follow target account populated.
    255 			if checkFollow.TargetAccount == nil || checkFollow.TargetAccount.ID != follow.TargetAccountID {
    256 				t.Errorf("follow target account not correctly populated for: %+v", checkFollow)
    257 				continue
    258 			}
    259 		}
    260 	}
    261 }
    262 
    263 func (suite *RelationshipTestSuite) TestGetFollowRequestBy() {
    264 	t := suite.T()
    265 
    266 	// Create a new context for this test.
    267 	ctx, cncl := context.WithCancel(context.Background())
    268 	defer cncl()
    269 
    270 	// Sentinel error to mark avoiding a test case.
    271 	sentinelErr := errors.New("sentinel")
    272 
    273 	// isEqual checks if 2 follow request models are equal.
    274 	isEqual := func(f1, f2 gtsmodel.FollowRequest) bool {
    275 		// Clear populated sub-models.
    276 		f1.Account = nil
    277 		f2.Account = nil
    278 		f1.TargetAccount = nil
    279 		f2.TargetAccount = nil
    280 
    281 		// Clear database-set fields.
    282 		f1.CreatedAt = time.Time{}
    283 		f2.CreatedAt = time.Time{}
    284 		f1.UpdatedAt = time.Time{}
    285 		f2.UpdatedAt = time.Time{}
    286 
    287 		return reflect.DeepEqual(f1, f2)
    288 	}
    289 
    290 	var testFollowReqs []*gtsmodel.FollowRequest
    291 
    292 	for _, account1 := range suite.testAccounts {
    293 		for _, account2 := range suite.testAccounts {
    294 			if account1.ID == account2.ID {
    295 				// don't follow *yourself* ...
    296 				continue
    297 			}
    298 
    299 			// Create new account follow request.
    300 			followReq := &gtsmodel.FollowRequest{
    301 				ID:              id.NewULID(),
    302 				URI:             "http://127.0.0.1:8080/" + id.NewULID(),
    303 				AccountID:       account1.ID,
    304 				TargetAccountID: account2.ID,
    305 			}
    306 
    307 			// Attempt to place the follow in database (if not already).
    308 			if err := suite.db.PutFollowRequest(ctx, followReq); err != nil {
    309 				if err != db.ErrAlreadyExists {
    310 					// Unrecoverable database error.
    311 					t.Fatalf("error creating follow request: %v", err)
    312 				}
    313 
    314 				// Fetch existing follow request from database between accounts.
    315 				followReq, _ = suite.db.GetFollowRequest(ctx, account1.ID, account2.ID)
    316 				continue
    317 			}
    318 
    319 			// Append generated follow request to test cases.
    320 			testFollowReqs = append(testFollowReqs, followReq)
    321 		}
    322 	}
    323 
    324 	for _, followReq := range testFollowReqs {
    325 		for lookup, dbfunc := range map[string]func() (*gtsmodel.FollowRequest, error){
    326 			"id": func() (*gtsmodel.FollowRequest, error) {
    327 				return suite.db.GetFollowRequestByID(ctx, followReq.ID)
    328 			},
    329 
    330 			"uri": func() (*gtsmodel.FollowRequest, error) {
    331 				return suite.db.GetFollowRequestByURI(ctx, followReq.URI)
    332 			},
    333 
    334 			"origin_target": func() (*gtsmodel.FollowRequest, error) {
    335 				return suite.db.GetFollowRequest(ctx, followReq.AccountID, followReq.TargetAccountID)
    336 			},
    337 		} {
    338 
    339 			// Clear database caches.
    340 			suite.state.Caches.Init()
    341 
    342 			t.Logf("checking database lookup %q", lookup)
    343 
    344 			// Perform database function.
    345 			checkFollowReq, err := dbfunc()
    346 			if err != nil {
    347 				if err == sentinelErr {
    348 					continue
    349 				}
    350 
    351 				t.Errorf("error encountered for database lookup %q: %v", lookup, err)
    352 				continue
    353 			}
    354 
    355 			// Check received follow request data.
    356 			if !isEqual(*checkFollowReq, *followReq) {
    357 				t.Errorf("follow request does not contain expected data: %+v", checkFollowReq)
    358 				continue
    359 			}
    360 
    361 			// Check that follow request origin account populated.
    362 			if checkFollowReq.Account == nil || checkFollowReq.Account.ID != followReq.AccountID {
    363 				t.Errorf("follow request origin account not correctly populated for: %+v", checkFollowReq)
    364 				continue
    365 			}
    366 
    367 			// Check that follow request target account populated.
    368 			if checkFollowReq.TargetAccount == nil || checkFollowReq.TargetAccount.ID != followReq.TargetAccountID {
    369 				t.Errorf("follow request target account not correctly populated for: %+v", checkFollowReq)
    370 				continue
    371 			}
    372 		}
    373 	}
    374 }
    375 
    376 func (suite *RelationshipTestSuite) TestIsBlocked() {
    377 	ctx := context.Background()
    378 
    379 	account1 := suite.testAccounts["local_account_1"].ID
    380 	account2 := suite.testAccounts["local_account_2"].ID
    381 
    382 	// no blocks exist between account 1 and account 2
    383 	blocked, err := suite.db.IsBlocked(ctx, account1, account2)
    384 	suite.NoError(err)
    385 	suite.False(blocked)
    386 
    387 	blocked, err = suite.db.IsBlocked(ctx, account2, account1)
    388 	suite.NoError(err)
    389 	suite.False(blocked)
    390 
    391 	// have account1 block account2
    392 	if err := suite.db.PutBlock(ctx, &gtsmodel.Block{
    393 		ID:              "01G202BCSXXJZ70BHB5KCAHH8C",
    394 		URI:             "http://localhost:8080/some_block_uri_1",
    395 		AccountID:       account1,
    396 		TargetAccountID: account2,
    397 	}); err != nil {
    398 		suite.FailNow(err.Error())
    399 	}
    400 
    401 	// account 1 now blocks account 2
    402 	blocked, err = suite.db.IsBlocked(ctx, account1, account2)
    403 	suite.NoError(err)
    404 	suite.True(blocked)
    405 
    406 	// account 2 doesn't block account 1
    407 	blocked, err = suite.db.IsBlocked(ctx, account2, account1)
    408 	suite.NoError(err)
    409 	suite.False(blocked)
    410 
    411 	// a block exists in either direction between the two
    412 	blocked, err = suite.db.IsEitherBlocked(ctx, account1, account2)
    413 	suite.NoError(err)
    414 	suite.True(blocked)
    415 	blocked, err = suite.db.IsEitherBlocked(ctx, account2, account1)
    416 	suite.NoError(err)
    417 	suite.True(blocked)
    418 }
    419 
    420 func (suite *RelationshipTestSuite) TestDeleteBlockByID() {
    421 	ctx := context.Background()
    422 
    423 	// put a block in first
    424 	account1 := suite.testAccounts["local_account_1"].ID
    425 	account2 := suite.testAccounts["local_account_2"].ID
    426 	if err := suite.db.PutBlock(ctx, &gtsmodel.Block{
    427 		ID:              "01G202BCSXXJZ70BHB5KCAHH8C",
    428 		URI:             "http://localhost:8080/some_block_uri_1",
    429 		AccountID:       account1,
    430 		TargetAccountID: account2,
    431 	}); err != nil {
    432 		suite.FailNow(err.Error())
    433 	}
    434 
    435 	// make sure the block is in the db
    436 	block, err := suite.db.GetBlock(ctx, account1, account2)
    437 	suite.NoError(err)
    438 	suite.NotNil(block)
    439 	suite.Equal("01G202BCSXXJZ70BHB5KCAHH8C", block.ID)
    440 
    441 	// delete the block by ID
    442 	err = suite.db.DeleteBlockByID(ctx, "01G202BCSXXJZ70BHB5KCAHH8C")
    443 	suite.NoError(err)
    444 
    445 	// block should be gone
    446 	block, err = suite.db.GetBlock(ctx, account1, account2)
    447 	suite.ErrorIs(err, db.ErrNoEntries)
    448 	suite.Nil(block)
    449 }
    450 
    451 func (suite *RelationshipTestSuite) TestDeleteBlockByURI() {
    452 	ctx := context.Background()
    453 
    454 	// put a block in first
    455 	account1 := suite.testAccounts["local_account_1"].ID
    456 	account2 := suite.testAccounts["local_account_2"].ID
    457 	if err := suite.db.PutBlock(ctx, &gtsmodel.Block{
    458 		ID:              "01G202BCSXXJZ70BHB5KCAHH8C",
    459 		URI:             "http://localhost:8080/some_block_uri_1",
    460 		AccountID:       account1,
    461 		TargetAccountID: account2,
    462 	}); err != nil {
    463 		suite.FailNow(err.Error())
    464 	}
    465 
    466 	// make sure the block is in the db
    467 	block, err := suite.db.GetBlock(ctx, account1, account2)
    468 	suite.NoError(err)
    469 	suite.NotNil(block)
    470 	suite.Equal("01G202BCSXXJZ70BHB5KCAHH8C", block.ID)
    471 
    472 	// delete the block by uri
    473 	err = suite.db.DeleteBlockByURI(ctx, "http://localhost:8080/some_block_uri_1")
    474 	suite.NoError(err)
    475 
    476 	// block should be gone
    477 	block, err = suite.db.GetBlock(ctx, account1, account2)
    478 	suite.ErrorIs(err, db.ErrNoEntries)
    479 	suite.Nil(block)
    480 }
    481 
    482 func (suite *RelationshipTestSuite) TestDeleteAccountBlocks() {
    483 	ctx := context.Background()
    484 
    485 	// put a block in first
    486 	account1 := suite.testAccounts["local_account_1"].ID
    487 	account2 := suite.testAccounts["local_account_2"].ID
    488 	if err := suite.db.PutBlock(ctx, &gtsmodel.Block{
    489 		ID:              "01G202BCSXXJZ70BHB5KCAHH8C",
    490 		URI:             "http://localhost:8080/some_block_uri_1",
    491 		AccountID:       account1,
    492 		TargetAccountID: account2,
    493 	}); err != nil {
    494 		suite.FailNow(err.Error())
    495 	}
    496 
    497 	// make sure the block is in the db
    498 	block, err := suite.db.GetBlock(ctx, account1, account2)
    499 	suite.NoError(err)
    500 	suite.NotNil(block)
    501 	suite.Equal("01G202BCSXXJZ70BHB5KCAHH8C", block.ID)
    502 
    503 	// delete the block by originAccountID
    504 	err = suite.db.DeleteAccountBlocks(ctx, account1)
    505 	suite.NoError(err)
    506 
    507 	// block should be gone
    508 	block, err = suite.db.GetBlock(ctx, account1, account2)
    509 	suite.ErrorIs(err, db.ErrNoEntries)
    510 	suite.Nil(block)
    511 }
    512 
    513 func (suite *RelationshipTestSuite) TestGetRelationship() {
    514 	requestingAccount := suite.testAccounts["local_account_1"]
    515 	targetAccount := suite.testAccounts["admin_account"]
    516 
    517 	relationship, err := suite.db.GetRelationship(context.Background(), requestingAccount.ID, targetAccount.ID)
    518 	suite.NoError(err)
    519 	suite.NotNil(relationship)
    520 
    521 	suite.True(relationship.Following)
    522 	suite.True(relationship.ShowingReblogs)
    523 	suite.False(relationship.Notifying)
    524 	suite.True(relationship.FollowedBy)
    525 	suite.False(relationship.Blocking)
    526 	suite.False(relationship.BlockedBy)
    527 	suite.False(relationship.Muting)
    528 	suite.False(relationship.MutingNotifications)
    529 	suite.False(relationship.Requested)
    530 	suite.False(relationship.DomainBlocking)
    531 	suite.False(relationship.Endorsed)
    532 	suite.Empty(relationship.Note)
    533 }
    534 
    535 func (suite *RelationshipTestSuite) TestIsFollowingYes() {
    536 	requestingAccount := suite.testAccounts["local_account_1"]
    537 	targetAccount := suite.testAccounts["admin_account"]
    538 	isFollowing, err := suite.db.IsFollowing(context.Background(), requestingAccount.ID, targetAccount.ID)
    539 	suite.NoError(err)
    540 	suite.True(isFollowing)
    541 }
    542 
    543 func (suite *RelationshipTestSuite) TestIsFollowingNo() {
    544 	requestingAccount := suite.testAccounts["admin_account"]
    545 	targetAccount := suite.testAccounts["local_account_2"]
    546 	isFollowing, err := suite.db.IsFollowing(context.Background(), requestingAccount.ID, targetAccount.ID)
    547 	suite.NoError(err)
    548 	suite.False(isFollowing)
    549 }
    550 
    551 func (suite *RelationshipTestSuite) TestIsMutualFollowing() {
    552 	requestingAccount := suite.testAccounts["local_account_1"]
    553 	targetAccount := suite.testAccounts["admin_account"]
    554 	isMutualFollowing, err := suite.db.IsMutualFollowing(context.Background(), requestingAccount.ID, targetAccount.ID)
    555 	suite.NoError(err)
    556 	suite.True(isMutualFollowing)
    557 }
    558 
    559 func (suite *RelationshipTestSuite) TestIsMutualFollowingNo() {
    560 	requestingAccount := suite.testAccounts["local_account_1"]
    561 	targetAccount := suite.testAccounts["local_account_2"]
    562 	isMutualFollowing, err := suite.db.IsMutualFollowing(context.Background(), requestingAccount.ID, targetAccount.ID)
    563 	suite.NoError(err)
    564 	suite.True(isMutualFollowing)
    565 }
    566 
    567 func (suite *RelationshipTestSuite) TestAcceptFollowRequestOK() {
    568 	ctx := context.Background()
    569 	account := suite.testAccounts["admin_account"]
    570 	targetAccount := suite.testAccounts["local_account_2"]
    571 
    572 	// Fetch relationship before follow request.
    573 	relationship, err := suite.db.GetRelationship(ctx, account.ID, targetAccount.ID)
    574 	if err != nil {
    575 		suite.FailNow(err.Error())
    576 	}
    577 	suite.False(relationship.Following)
    578 	suite.False(relationship.Requested)
    579 
    580 	followRequest := &gtsmodel.FollowRequest{
    581 		ID:              "01GEF753FWHCHRDWR0QEHBXM8W",
    582 		URI:             "http://localhost:8080/weeeeeeeeeeeeeeeee",
    583 		AccountID:       account.ID,
    584 		TargetAccountID: targetAccount.ID,
    585 	}
    586 
    587 	if err := suite.db.PutFollowRequest(ctx, followRequest); err != nil {
    588 		suite.FailNow(err.Error())
    589 	}
    590 
    591 	// Fetch relationship while follow requested.
    592 	relationship, err = suite.db.GetRelationship(ctx, account.ID, targetAccount.ID)
    593 	if err != nil {
    594 		suite.FailNow(err.Error())
    595 	}
    596 	suite.False(relationship.Following)
    597 	suite.True(relationship.Requested)
    598 
    599 	followRequestNotification := &gtsmodel.Notification{
    600 		ID:               "01GV8MY1Q9KX2ZSWN4FAQ3V1PB",
    601 		OriginAccountID:  account.ID,
    602 		TargetAccountID:  targetAccount.ID,
    603 		NotificationType: gtsmodel.NotificationFollowRequest,
    604 	}
    605 
    606 	if err := suite.db.PutNotification(ctx, followRequestNotification); err != nil {
    607 		suite.FailNow(err.Error())
    608 	}
    609 
    610 	follow, err := suite.db.AcceptFollowRequest(ctx, account.ID, targetAccount.ID)
    611 	suite.NoError(err)
    612 	suite.NotNil(follow)
    613 	suite.Equal(followRequest.URI, follow.URI)
    614 
    615 	// Ensure notification is deleted.
    616 	notification, err := suite.db.GetNotificationByID(ctx, followRequestNotification.ID)
    617 	suite.ErrorIs(err, db.ErrNoEntries)
    618 	suite.Nil(notification)
    619 
    620 	// Fetch relationship while followed.
    621 	relationship, err = suite.db.GetRelationship(ctx, account.ID, targetAccount.ID)
    622 	if err != nil {
    623 		suite.FailNow(err.Error())
    624 	}
    625 	suite.True(relationship.Following)
    626 	suite.False(relationship.Requested)
    627 }
    628 
    629 func (suite *RelationshipTestSuite) TestAcceptFollowRequestNoNotification() {
    630 	ctx := context.Background()
    631 	account := suite.testAccounts["admin_account"]
    632 	targetAccount := suite.testAccounts["local_account_2"]
    633 
    634 	followRequest := &gtsmodel.FollowRequest{
    635 		ID:              "01GEF753FWHCHRDWR0QEHBXM8W",
    636 		URI:             "http://localhost:8080/weeeeeeeeeeeeeeeee",
    637 		AccountID:       account.ID,
    638 		TargetAccountID: targetAccount.ID,
    639 	}
    640 
    641 	if err := suite.db.Put(ctx, followRequest); err != nil {
    642 		suite.FailNow(err.Error())
    643 	}
    644 
    645 	// Unlike the above test, don't create a notification.
    646 	// Follow request accept should still produce no error.
    647 
    648 	follow, err := suite.db.AcceptFollowRequest(ctx, account.ID, targetAccount.ID)
    649 	suite.NoError(err)
    650 	suite.NotNil(follow)
    651 	suite.Equal(followRequest.URI, follow.URI)
    652 }
    653 
    654 func (suite *RelationshipTestSuite) TestAcceptFollowRequestNotExisting() {
    655 	ctx := context.Background()
    656 	account := suite.testAccounts["admin_account"]
    657 	targetAccount := suite.testAccounts["local_account_2"]
    658 
    659 	follow, err := suite.db.AcceptFollowRequest(ctx, account.ID, targetAccount.ID)
    660 	suite.ErrorIs(err, db.ErrNoEntries)
    661 	suite.Nil(follow)
    662 }
    663 
    664 func (suite *RelationshipTestSuite) TestAcceptFollowRequestFollowAlreadyExists() {
    665 	ctx := context.Background()
    666 	account := suite.testAccounts["local_account_1"]
    667 	targetAccount := suite.testAccounts["admin_account"]
    668 
    669 	// follow already exists in the db from local_account_1 -> admin_account
    670 	existingFollow := &gtsmodel.Follow{}
    671 	if err := suite.db.GetByID(ctx, suite.testFollows["local_account_1_admin_account"].ID, existingFollow); err != nil {
    672 		suite.FailNow(err.Error())
    673 	}
    674 
    675 	followRequest := &gtsmodel.FollowRequest{
    676 		ID:              "01GEF753FWHCHRDWR0QEHBXM8W",
    677 		URI:             "http://localhost:8080/weeeeeeeeeeeeeeeee",
    678 		AccountID:       account.ID,
    679 		TargetAccountID: targetAccount.ID,
    680 	}
    681 
    682 	if err := suite.db.Put(ctx, followRequest); err != nil {
    683 		suite.FailNow(err.Error())
    684 	}
    685 
    686 	follow, err := suite.db.AcceptFollowRequest(ctx, account.ID, targetAccount.ID)
    687 	suite.NoError(err)
    688 	suite.NotNil(follow)
    689 
    690 	// uri should be equal to value of new/overlapping follow request
    691 	suite.NotEqual(followRequest.URI, existingFollow.URI)
    692 	suite.Equal(followRequest.URI, follow.URI)
    693 }
    694 
    695 func (suite *RelationshipTestSuite) TestRejectFollowRequestOK() {
    696 	ctx := context.Background()
    697 	account := suite.testAccounts["admin_account"]
    698 	targetAccount := suite.testAccounts["local_account_2"]
    699 
    700 	followRequest := &gtsmodel.FollowRequest{
    701 		ID:              "01GEF753FWHCHRDWR0QEHBXM8W",
    702 		URI:             "http://localhost:8080/weeeeeeeeeeeeeeeee",
    703 		AccountID:       account.ID,
    704 		TargetAccountID: targetAccount.ID,
    705 	}
    706 
    707 	if err := suite.db.PutFollowRequest(ctx, followRequest); err != nil {
    708 		suite.FailNow(err.Error())
    709 	}
    710 
    711 	followRequestNotification := &gtsmodel.Notification{
    712 		ID:               "01GV8MY1Q9KX2ZSWN4FAQ3V1PB",
    713 		OriginAccountID:  account.ID,
    714 		TargetAccountID:  targetAccount.ID,
    715 		NotificationType: gtsmodel.NotificationFollowRequest,
    716 	}
    717 
    718 	if err := suite.db.Put(ctx, followRequestNotification); err != nil {
    719 		suite.FailNow(err.Error())
    720 	}
    721 
    722 	err := suite.db.RejectFollowRequest(ctx, account.ID, targetAccount.ID)
    723 	suite.NoError(err)
    724 
    725 	// Ensure notification is deleted.
    726 	notification, err := suite.db.GetNotificationByID(ctx, followRequestNotification.ID)
    727 	suite.ErrorIs(err, db.ErrNoEntries)
    728 	suite.Nil(notification)
    729 }
    730 
    731 func (suite *RelationshipTestSuite) TestRejectFollowRequestNotExisting() {
    732 	ctx := context.Background()
    733 	account := suite.testAccounts["admin_account"]
    734 	targetAccount := suite.testAccounts["local_account_2"]
    735 
    736 	err := suite.db.RejectFollowRequest(ctx, account.ID, targetAccount.ID)
    737 	suite.ErrorIs(err, db.ErrNoEntries)
    738 }
    739 
    740 func (suite *RelationshipTestSuite) TestGetAccountFollowRequests() {
    741 	ctx := context.Background()
    742 	account := suite.testAccounts["admin_account"]
    743 	targetAccount := suite.testAccounts["local_account_2"]
    744 
    745 	followRequest := &gtsmodel.FollowRequest{
    746 		ID:              "01GEF753FWHCHRDWR0QEHBXM8W",
    747 		URI:             "http://localhost:8080/weeeeeeeeeeeeeeeee",
    748 		AccountID:       account.ID,
    749 		TargetAccountID: targetAccount.ID,
    750 	}
    751 
    752 	if err := suite.db.Put(ctx, followRequest); err != nil {
    753 		suite.FailNow(err.Error())
    754 	}
    755 
    756 	followRequests, err := suite.db.GetAccountFollowRequests(ctx, targetAccount.ID)
    757 	suite.NoError(err)
    758 	suite.Len(followRequests, 1)
    759 }
    760 
    761 func (suite *RelationshipTestSuite) TestGetAccountFollows() {
    762 	account := suite.testAccounts["local_account_1"]
    763 	follows, err := suite.db.GetAccountFollows(context.Background(), account.ID)
    764 	suite.NoError(err)
    765 	suite.Len(follows, 2)
    766 }
    767 
    768 func (suite *RelationshipTestSuite) TestCountAccountFollowsLocalOnly() {
    769 	account := suite.testAccounts["local_account_1"]
    770 	followsCount, err := suite.db.CountAccountLocalFollows(context.Background(), account.ID)
    771 	suite.NoError(err)
    772 	suite.Equal(2, followsCount)
    773 }
    774 
    775 func (suite *RelationshipTestSuite) TestCountAccountFollows() {
    776 	account := suite.testAccounts["local_account_1"]
    777 	followsCount, err := suite.db.CountAccountFollows(context.Background(), account.ID)
    778 	suite.NoError(err)
    779 	suite.Equal(2, followsCount)
    780 }
    781 
    782 func (suite *RelationshipTestSuite) TestGetAccountFollowers() {
    783 	account := suite.testAccounts["local_account_1"]
    784 	follows, err := suite.db.GetAccountFollowers(context.Background(), account.ID)
    785 	suite.NoError(err)
    786 	suite.Len(follows, 2)
    787 }
    788 
    789 func (suite *RelationshipTestSuite) TestCountAccountFollowers() {
    790 	account := suite.testAccounts["local_account_1"]
    791 	followsCount, err := suite.db.CountAccountFollowers(context.Background(), account.ID)
    792 	suite.NoError(err)
    793 	suite.Equal(2, followsCount)
    794 }
    795 
    796 func (suite *RelationshipTestSuite) TestCountAccountFollowersLocalOnly() {
    797 	account := suite.testAccounts["local_account_1"]
    798 	followsCount, err := suite.db.CountAccountLocalFollowers(context.Background(), account.ID)
    799 	suite.NoError(err)
    800 	suite.Equal(2, followsCount)
    801 }
    802 
    803 func (suite *RelationshipTestSuite) TestUnfollowExisting() {
    804 	originAccount := suite.testAccounts["local_account_1"]
    805 	targetAccount := suite.testAccounts["admin_account"]
    806 
    807 	follow, err := suite.db.GetFollow(context.Background(), originAccount.ID, targetAccount.ID)
    808 	suite.NoError(err)
    809 	suite.NotNil(follow)
    810 	followID := follow.ID
    811 
    812 	// We should have list entries for this follow.
    813 	listEntries, err := suite.db.GetListEntriesForFollowID(context.Background(), followID)
    814 	suite.NoError(err)
    815 	suite.NotEmpty(listEntries)
    816 
    817 	err = suite.db.DeleteFollowByID(context.Background(), followID)
    818 	suite.NoError(err)
    819 
    820 	follow, err = suite.db.GetFollow(context.Background(), originAccount.ID, targetAccount.ID)
    821 	suite.EqualError(err, db.ErrNoEntries.Error())
    822 	suite.Nil(follow)
    823 
    824 	// ListEntries pertaining to this follow should be deleted too.
    825 	listEntries, err = suite.db.GetListEntriesForFollowID(context.Background(), followID)
    826 	suite.NoError(err)
    827 	suite.Empty(listEntries)
    828 }
    829 
    830 func (suite *RelationshipTestSuite) TestGetFollowNotExisting() {
    831 	originAccount := suite.testAccounts["local_account_1"]
    832 	targetAccountID := "01GTVD9N484CZ6AM90PGGNY7GQ"
    833 
    834 	follow, err := suite.db.GetFollow(context.Background(), originAccount.ID, targetAccountID)
    835 	suite.EqualError(err, db.ErrNoEntries.Error())
    836 	suite.Nil(follow)
    837 }
    838 
    839 func (suite *RelationshipTestSuite) TestUnfollowRequestExisting() {
    840 	ctx := context.Background()
    841 	originAccount := suite.testAccounts["admin_account"]
    842 	targetAccount := suite.testAccounts["local_account_2"]
    843 
    844 	followRequest := &gtsmodel.FollowRequest{
    845 		ID:              "01GEF753FWHCHRDWR0QEHBXM8W",
    846 		URI:             "http://localhost:8080/weeeeeeeeeeeeeeeee",
    847 		AccountID:       originAccount.ID,
    848 		TargetAccountID: targetAccount.ID,
    849 	}
    850 
    851 	if err := suite.db.PutFollowRequest(ctx, followRequest); err != nil {
    852 		suite.FailNow(err.Error())
    853 	}
    854 
    855 	followRequest, err := suite.db.GetFollowRequest(context.Background(), originAccount.ID, targetAccount.ID)
    856 	suite.NoError(err)
    857 	suite.NotNil(followRequest)
    858 
    859 	err = suite.db.DeleteFollowRequestByID(context.Background(), followRequest.ID)
    860 	suite.NoError(err)
    861 
    862 	followRequest, err = suite.db.GetFollowRequest(context.Background(), originAccount.ID, targetAccount.ID)
    863 	suite.EqualError(err, db.ErrNoEntries.Error())
    864 	suite.Nil(followRequest)
    865 }
    866 
    867 func (suite *RelationshipTestSuite) TestUnfollowRequestNotExisting() {
    868 	originAccount := suite.testAccounts["local_account_1"]
    869 	targetAccountID := "01GTVD9N484CZ6AM90PGGNY7GQ"
    870 
    871 	followRequest, err := suite.db.GetFollowRequest(context.Background(), originAccount.ID, targetAccountID)
    872 	suite.EqualError(err, db.ErrNoEntries.Error())
    873 	suite.Nil(followRequest)
    874 }
    875 
    876 func (suite *RelationshipTestSuite) TestUpdateFollow() {
    877 	ctx := context.Background()
    878 
    879 	follow := &gtsmodel.Follow{}
    880 	*follow = *suite.testFollows["local_account_1_admin_account"]
    881 
    882 	follow.Notify = testrig.TrueBool()
    883 	if err := suite.db.UpdateFollow(ctx, follow, "notify"); err != nil {
    884 		suite.FailNow(err.Error())
    885 	}
    886 
    887 	dbFollow, err := suite.db.GetFollowByID(ctx, follow.ID)
    888 	if err != nil {
    889 		suite.FailNow(err.Error())
    890 	}
    891 
    892 	suite.True(*dbFollow.Notify)
    893 
    894 	relationship, err := suite.db.GetRelationship(ctx, follow.AccountID, follow.TargetAccountID)
    895 	if err != nil {
    896 		suite.FailNow(err.Error())
    897 	}
    898 
    899 	suite.True(relationship.Notifying)
    900 }
    901 
    902 func TestRelationshipTestSuite(t *testing.T) {
    903 	suite.Run(t, new(RelationshipTestSuite))
    904 }