gotosocial/internal/federation/federatingdb/move_test.go
kim c9c0773f2c
[performance] update remaining worker pools to use queues (#2865)
* start replacing client + federator + media workers with new worker + queue types

* refactor federatingDB.Delete(), drop queued messages when deleting account / status

* move all queue purging to the processor workers

* undo toolchain updates

* code comments, ensure dereferencer worker pool gets started

* update gruf libraries in readme

* start the job scheduler separately to the worker pools

* reshuffle ordering or server.go + remove duplicate worker start / stop

* update go-list version

* fix vendoring

* move queue invalidation to before wipeing / deletion, to ensure queued work not dropped

* add logging to worker processing functions in testrig, don't start workers in unexpected places

* update go-structr to add (+then rely on) QueueCtx{} type

* ensure more worker pools get started properly in tests

* fix remaining broken tests relying on worker queue logic

* fix account test suite queue popping logic, ensure noop workers do not pull from queue

* move back accidentally shuffled account deletion order

* ensure error (non nil!!) gets passed in refactored federatingDB{}.Delete()

* silently drop deletes from accounts not permitted to

* don't warn log on forwarded deletes

* make if else clauses easier to parse

* use getFederatorMsg()

* improved code comment

* improved code comment re: requesting account delete checks

* remove boolean result from worker start / stop since false = already running or already stopped

* remove optional passed-in http.client

* remove worker starting from the admin CLI commands (we don't need to handle side-effects)

* update prune cli to start scheduler but not all of the workers

* fix rebase issues

* remove redundant return statements

* i'm sorry sir linter
2024-04-26 13:50:46 +01:00

185 lines
6.2 KiB
Go

// 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 federatingdb_test
import (
"encoding/json"
"testing"
"time"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/activity/streams"
"github.com/superseriousbusiness/activity/streams/vocab"
"github.com/superseriousbusiness/gotosocial/internal/ap"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
)
type MoveTestSuite struct {
FederatingDBTestSuite
}
func (suite *MoveTestSuite) move(
receivingAcct *gtsmodel.Account,
requestingAcct *gtsmodel.Account,
moveStr string,
) error {
ctx := createTestContext(receivingAcct, requestingAcct)
rawMove := make(map[string]interface{})
if err := json.Unmarshal([]byte(moveStr), &rawMove); err != nil {
suite.FailNow(err.Error())
}
t, err := streams.ToType(ctx, rawMove)
if err != nil {
suite.FailNow(err.Error())
}
move, ok := t.(vocab.ActivityStreamsMove)
if !ok {
suite.FailNow("", "couldn't cast %T to Move", t)
}
return suite.federatingDB.Move(ctx, move)
}
func (suite *MoveTestSuite) TestMove() {
var (
receivingAcct = suite.testAccounts["local_account_1"]
requestingAcct = suite.testAccounts["remote_account_1"]
moveStr1 = `{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "http://fossbros-anonymous.io/users/foss_satan/moves/01HR9FDFCAGM7JYPMWNTFRDQE9",
"actor": "http://fossbros-anonymous.io/users/foss_satan",
"type": "Move",
"object": "http://fossbros-anonymous.io/users/foss_satan",
"target": "https://turnip.farm/users/turniplover6969",
"to": "http://fossbros-anonymous.io/users/foss_satan/followers"
}`
)
// Trigger the move.
suite.move(receivingAcct, requestingAcct, moveStr1)
// Should be a message heading to the processor.
msg, _ := suite.getFederatorMsg(5 * time.Second)
suite.Equal(ap.ObjectProfile, msg.APObjectType)
suite.Equal(ap.ActivityMove, msg.APActivityType)
// Stub Move should be on the message.
move, ok := msg.GTSModel.(*gtsmodel.Move)
if !ok {
suite.FailNow("", "could not cast %T to *gtsmodel.Move", msg.GTSModel)
}
suite.Equal("http://fossbros-anonymous.io/users/foss_satan", move.OriginURI)
suite.Equal("https://turnip.farm/users/turniplover6969", move.TargetURI)
// Trigger the same move again.
suite.move(receivingAcct, requestingAcct, moveStr1)
// Should be a message heading to the processor
// since this is just a straight up retry.
msg, _ = suite.getFederatorMsg(5 * time.Second)
suite.Equal(ap.ObjectProfile, msg.APObjectType)
suite.Equal(ap.ActivityMove, msg.APActivityType)
// Same as the first Move, but with a different ID.
moveStr2 := `{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "http://fossbros-anonymous.io/users/foss_satan/moves/01HR9XWDD25CKXHW82MYD1GDAR",
"actor": "http://fossbros-anonymous.io/users/foss_satan",
"type": "Move",
"object": "http://fossbros-anonymous.io/users/foss_satan",
"target": "https://turnip.farm/users/turniplover6969",
"to": "http://fossbros-anonymous.io/users/foss_satan/followers"
}`
// Trigger the move.
suite.move(receivingAcct, requestingAcct, moveStr2)
// Should be a message heading to the processor
// since this is just a retry with a different ID.
msg, _ = suite.getFederatorMsg(5 * time.Second)
suite.Equal(ap.ObjectProfile, msg.APObjectType)
suite.Equal(ap.ActivityMove, msg.APActivityType)
}
func (suite *MoveTestSuite) TestBadMoves() {
var (
receivingAcct = suite.testAccounts["local_account_1"]
requestingAcct = suite.testAccounts["remote_account_1"]
)
type testStruct struct {
moveStr string
err string
}
for _, t := range []testStruct{
{
// Move signed by someone else.
moveStr: `{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "http://fossbros-anonymous.io/users/foss_satan/moves/01HR9FDFCAGM7JYPMWNTFRDQE9",
"actor": "http://fossbros-anonymous.io/users/someone_else",
"type": "Move",
"object": "http://fossbros-anonymous.io/users/foss_satan",
"target": "https://turnip.farm/users/turniplover6969",
"to": "http://fossbros-anonymous.io/users/foss_satan/followers"
}`,
err: "Move was signed by http://fossbros-anonymous.io/users/foss_satan but actor was http://fossbros-anonymous.io/users/someone_else",
},
{
// Actor and object not the same.
moveStr: `{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "http://fossbros-anonymous.io/users/foss_satan/moves/01HR9FDFCAGM7JYPMWNTFRDQE9",
"actor": "http://fossbros-anonymous.io/users/foss_satan",
"type": "Move",
"object": "http://fossbros-anonymous.io/users/someone_else",
"target": "https://turnip.farm/users/turniplover6969",
"to": "http://fossbros-anonymous.io/users/foss_satan/followers"
}`,
err: "Move was signed by http://fossbros-anonymous.io/users/foss_satan but object was http://fossbros-anonymous.io/users/someone_else",
},
{
// Object and target the same.
moveStr: `{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "http://fossbros-anonymous.io/users/foss_satan/moves/01HR9FDFCAGM7JYPMWNTFRDQE9",
"actor": "http://fossbros-anonymous.io/users/foss_satan",
"type": "Move",
"object": "http://fossbros-anonymous.io/users/foss_satan",
"target": "http://fossbros-anonymous.io/users/foss_satan",
"to": "http://fossbros-anonymous.io/users/foss_satan/followers"
}`,
err: "Move target and origin were the same (http://fossbros-anonymous.io/users/foss_satan)",
},
} {
// Trigger the move.
err := suite.move(receivingAcct, requestingAcct, t.moveStr)
if t.err != "" {
suite.EqualError(err, t.err)
}
}
}
func TestMoveTestSuite(t *testing.T) {
suite.Run(t, &MoveTestSuite{})
}