mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-12-05 07:38:06 -06:00
[bugfix] Fix multiple dereferences of boosted status causing media duplication (#589)
* add some announces to test models * start on announce test logic * test federatingDB.Announce * change signature of GetRemoteStatus * remove 'refresh' logic and replace it with refetch * go fmt * remove timeline manager from processor test * make zork created at determinate * test get account statuses * test get + serialize zork * make account keys determinate * make admin accountCreate time determinate * test account to as * init test config before test log * test status to frontend * remove daft Within check * hack around a bit * use index of slice
This commit is contained in:
parent
1461adfd3a
commit
f0c9f4169b
18 changed files with 324 additions and 99 deletions
|
|
@ -65,8 +65,6 @@ func (suite *AccountVerifyTestSuite) TestAccountVerifyGet() {
|
|||
|
||||
createdAt, err := time.Parse(time.RFC3339, apimodelAccount.CreatedAt)
|
||||
suite.NoError(err)
|
||||
lastStatusAt, err := time.Parse(time.RFC3339, apimodelAccount.LastStatusAt)
|
||||
suite.NoError(err)
|
||||
|
||||
suite.Equal(testAccount.ID, apimodelAccount.ID)
|
||||
suite.Equal(testAccount.Username, apimodelAccount.Username)
|
||||
|
|
@ -83,7 +81,6 @@ func (suite *AccountVerifyTestSuite) TestAccountVerifyGet() {
|
|||
suite.Equal(2, apimodelAccount.FollowersCount)
|
||||
suite.Equal(2, apimodelAccount.FollowingCount)
|
||||
suite.Equal(5, apimodelAccount.StatusesCount)
|
||||
suite.WithinDuration(time.Now(), lastStatusAt, 5*time.Minute)
|
||||
suite.EqualValues(gtsmodel.VisibilityPublic, apimodelAccount.Source.Privacy)
|
||||
suite.Equal(testAccount.Language, apimodelAccount.Source.Language)
|
||||
suite.Equal(testAccount.NoteRaw, apimodelAccount.Source.Note)
|
||||
|
|
|
|||
|
|
@ -34,6 +34,12 @@ type AccountTestSuite struct {
|
|||
BunDBStandardTestSuite
|
||||
}
|
||||
|
||||
func (suite *AccountTestSuite) TestGetAccountStatuses() {
|
||||
statuses, err := suite.db.GetAccountStatuses(context.Background(), suite.testAccounts["local_account_1"].ID, 20, false, false, "", "", false, false, false)
|
||||
suite.NoError(err)
|
||||
suite.Len(statuses, 5)
|
||||
}
|
||||
|
||||
func (suite *AccountTestSuite) TestGetAccountByIDWithExtras() {
|
||||
account, err := suite.db.GetAccountByID(context.Background(), suite.testAccounts["local_account_1"].ID)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ func (f *federator) GetRemoteAccount(ctx context.Context, username string, remot
|
|||
return f.dereferencer.GetRemoteAccount(ctx, username, remoteAccountID, blocking, refresh)
|
||||
}
|
||||
|
||||
func (f *federator) GetRemoteStatus(ctx context.Context, username string, remoteStatusID *url.URL, refresh, includeParent bool) (*gtsmodel.Status, ap.Statusable, bool, error) {
|
||||
return f.dereferencer.GetRemoteStatus(ctx, username, remoteStatusID, refresh, includeParent)
|
||||
func (f *federator) GetRemoteStatus(ctx context.Context, username string, remoteStatusID *url.URL, refetch, includeParent bool) (*gtsmodel.Status, ap.Statusable, error) {
|
||||
return f.dereferencer.GetRemoteStatus(ctx, username, remoteStatusID, refetch, includeParent)
|
||||
}
|
||||
|
||||
func (f *federator) EnrichRemoteStatus(ctx context.Context, username string, status *gtsmodel.Status, includeParent bool) (*gtsmodel.Status, error) {
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ func (d *deref) DereferenceAnnounce(ctx context.Context, announce *gtsmodel.Stat
|
|||
return fmt.Errorf("DereferenceAnnounce: error dereferencing thread of boosted status: %s", err)
|
||||
}
|
||||
|
||||
boostedStatus, _, _, err := d.GetRemoteStatus(ctx, requestingUsername, boostedStatusURI, false, true)
|
||||
boostedStatus, _, err := d.GetRemoteStatus(ctx, requestingUsername, boostedStatusURI, false, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("DereferenceAnnounce: error dereferencing remote status with id %s: %s", announce.BoostOf.URI, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ import (
|
|||
type Dereferencer interface {
|
||||
GetRemoteAccount(ctx context.Context, username string, remoteAccountID *url.URL, blocking bool, refresh bool) (*gtsmodel.Account, error)
|
||||
|
||||
GetRemoteStatus(ctx context.Context, username string, remoteStatusID *url.URL, refresh, includeParent bool) (*gtsmodel.Status, ap.Statusable, bool, error)
|
||||
GetRemoteStatus(ctx context.Context, username string, remoteStatusID *url.URL, refetch, includeParent bool) (*gtsmodel.Status, ap.Statusable, error)
|
||||
EnrichRemoteStatus(ctx context.Context, username string, status *gtsmodel.Status, includeParent bool) (*gtsmodel.Status, error)
|
||||
|
||||
GetRemoteInstance(ctx context.Context, username string, remoteInstanceURI *url.URL) (*gtsmodel.Instance, error)
|
||||
|
|
|
|||
|
|
@ -53,79 +53,63 @@ func (d *deref) EnrichRemoteStatus(ctx context.Context, username string, status
|
|||
}
|
||||
|
||||
// GetRemoteStatus completely dereferences a remote status, converts it to a GtS model status,
|
||||
// puts it in the database, and returns it to a caller. The boolean indicates whether the status is new
|
||||
// to us or not. If we haven't seen the status before, bool will be true. If we have seen the status before,
|
||||
// it will be false.
|
||||
// puts it in the database, and returns it to a caller.
|
||||
//
|
||||
// If refresh is true, then even if we have the status in our database already, it will be dereferenced from its
|
||||
// remote representation, as will its owner.
|
||||
// If refetch is true, then regardless of whether we have the original status in the database or not,
|
||||
// the ap.Statusable representation of the status will be dereferenced and returned.
|
||||
//
|
||||
// If a dereference was performed, then the function also returns the ap.Statusable representation for further processing.
|
||||
// If refetch is false, the ap.Statusable will only be returned if this is a new status, so callers
|
||||
// should check whether or not this is nil.
|
||||
//
|
||||
// SIDE EFFECTS: remote status will be stored in the database, and the remote status owner will also be stored.
|
||||
func (d *deref) GetRemoteStatus(ctx context.Context, username string, remoteStatusID *url.URL, refresh, includeParent bool) (*gtsmodel.Status, ap.Statusable, bool, error) {
|
||||
new := true
|
||||
|
||||
// check if we already have the status in our db
|
||||
func (d *deref) GetRemoteStatus(ctx context.Context, username string, remoteStatusID *url.URL, refetch, includeParent bool) (*gtsmodel.Status, ap.Statusable, error) {
|
||||
maybeStatus, err := d.db.GetStatusByURI(ctx, remoteStatusID.String())
|
||||
if err == nil {
|
||||
// we've seen this status before so it's not new
|
||||
new = false
|
||||
|
||||
// if we're not being asked to refresh, we can just return the maybeStatus as-is and avoid doing any external calls
|
||||
if !refresh {
|
||||
return maybeStatus, nil, new, nil
|
||||
}
|
||||
if err == nil && !refetch {
|
||||
// we already had the status and we aren't being asked to refetch the AP representation
|
||||
return maybeStatus, nil, nil
|
||||
}
|
||||
|
||||
statusable, err := d.dereferenceStatusable(ctx, username, remoteStatusID)
|
||||
if err != nil {
|
||||
return nil, statusable, new, fmt.Errorf("GetRemoteStatus: error dereferencing statusable: %s", err)
|
||||
return nil, nil, fmt.Errorf("GetRemoteStatus: error dereferencing statusable: %s", err)
|
||||
}
|
||||
|
||||
if maybeStatus != nil && refetch {
|
||||
// we already had the status and we've successfully fetched the AP representation as requested
|
||||
return maybeStatus, statusable, nil
|
||||
}
|
||||
|
||||
// from here on out we can consider this to be a 'new' status because we didn't have the status in the db already
|
||||
accountURI, err := ap.ExtractAttributedTo(statusable)
|
||||
if err != nil {
|
||||
return nil, statusable, new, fmt.Errorf("GetRemoteStatus: error extracting attributedTo: %s", err)
|
||||
return nil, nil, fmt.Errorf("GetRemoteStatus: error extracting attributedTo: %s", err)
|
||||
}
|
||||
|
||||
// do this so we know we have the remote account of the status in the db
|
||||
_, err = d.GetRemoteAccount(ctx, username, accountURI, true, false)
|
||||
if err != nil {
|
||||
return nil, statusable, new, fmt.Errorf("GetRemoteStatus: couldn't derive status author: %s", err)
|
||||
return nil, nil, fmt.Errorf("GetRemoteStatus: couldn't get status author: %s", err)
|
||||
}
|
||||
|
||||
gtsStatus, err := d.typeConverter.ASStatusToStatus(ctx, statusable)
|
||||
if err != nil {
|
||||
return nil, statusable, new, fmt.Errorf("GetRemoteStatus: error converting statusable to status: %s", err)
|
||||
return nil, statusable, fmt.Errorf("GetRemoteStatus: error converting statusable to status: %s", err)
|
||||
}
|
||||
|
||||
if new {
|
||||
ulid, err := id.NewULIDFromTime(gtsStatus.CreatedAt)
|
||||
if err != nil {
|
||||
return nil, statusable, new, fmt.Errorf("GetRemoteStatus: error generating new id for status: %s", err)
|
||||
}
|
||||
gtsStatus.ID = ulid
|
||||
ulid, err := id.NewULIDFromTime(gtsStatus.CreatedAt)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("GetRemoteStatus: error generating new id for status: %s", err)
|
||||
}
|
||||
gtsStatus.ID = ulid
|
||||
|
||||
if err := d.populateStatusFields(ctx, gtsStatus, username, includeParent); err != nil {
|
||||
return nil, statusable, new, fmt.Errorf("GetRemoteStatus: error populating status fields: %s", err)
|
||||
}
|
||||
|
||||
if err := d.db.PutStatus(ctx, gtsStatus); err != nil {
|
||||
return nil, statusable, new, fmt.Errorf("GetRemoteStatus: error putting new status: %s", err)
|
||||
}
|
||||
} else {
|
||||
gtsStatus.ID = maybeStatus.ID
|
||||
|
||||
if err := d.populateStatusFields(ctx, gtsStatus, username, includeParent); err != nil {
|
||||
return nil, statusable, new, fmt.Errorf("GetRemoteStatus: error populating status fields: %s", err)
|
||||
}
|
||||
|
||||
if err := d.db.UpdateByPrimaryKey(ctx, gtsStatus); err != nil {
|
||||
return nil, statusable, new, fmt.Errorf("GetRemoteStatus: error updating status: %s", err)
|
||||
}
|
||||
if err := d.populateStatusFields(ctx, gtsStatus, username, includeParent); err != nil {
|
||||
return nil, nil, fmt.Errorf("GetRemoteStatus: error populating status fields: %s", err)
|
||||
}
|
||||
|
||||
return gtsStatus, statusable, new, nil
|
||||
if err := d.db.PutStatus(ctx, gtsStatus); err != nil {
|
||||
return nil, nil, fmt.Errorf("GetRemoteStatus: error putting new status: %s", err)
|
||||
}
|
||||
|
||||
return gtsStatus, statusable, nil
|
||||
}
|
||||
|
||||
func (d *deref) dereferenceStatusable(ctx context.Context, username string, remoteStatusID *url.URL) (ap.Statusable, error) {
|
||||
|
|
@ -429,14 +413,9 @@ func (d *deref) populateStatusRepliedTo(ctx context.Context, status *gtsmodel.St
|
|||
return err
|
||||
}
|
||||
|
||||
// see if we have the status in our db already
|
||||
replyToStatus, err := d.db.GetStatusByURI(ctx, status.InReplyToURI)
|
||||
replyToStatus, _, err := d.GetRemoteStatus(ctx, requestingUsername, statusURI, false, false)
|
||||
if err != nil {
|
||||
// Status was not in the DB, try fetch
|
||||
replyToStatus, _, _, err = d.GetRemoteStatus(ctx, requestingUsername, statusURI, false, false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("populateStatusRepliedTo: couldn't get reply to status with uri %s: %s", status.InReplyToURI, err)
|
||||
}
|
||||
return fmt.Errorf("populateStatusRepliedTo: couldn't get reply to status with uri %s: %s", status.InReplyToURI, err)
|
||||
}
|
||||
|
||||
// we have the status
|
||||
|
|
|
|||
|
|
@ -38,11 +38,9 @@ func (suite *StatusTestSuite) TestDereferenceSimpleStatus() {
|
|||
fetchingAccount := suite.testAccounts["local_account_1"]
|
||||
|
||||
statusURL := testrig.URLMustParse("https://unknown-instance.com/users/brand_new_person/statuses/01FE4NTHKWW7THT67EF10EB839")
|
||||
status, statusable, new, err := suite.dereferencer.GetRemoteStatus(context.Background(), fetchingAccount.Username, statusURL, false, false)
|
||||
status, _, err := suite.dereferencer.GetRemoteStatus(context.Background(), fetchingAccount.Username, statusURL, false, false)
|
||||
suite.NoError(err)
|
||||
suite.NotNil(status)
|
||||
suite.NotNil(statusable)
|
||||
suite.True(new)
|
||||
|
||||
// status values should be set
|
||||
suite.Equal("https://unknown-instance.com/users/brand_new_person/statuses/01FE4NTHKWW7THT67EF10EB839", status.URI)
|
||||
|
|
@ -80,11 +78,9 @@ func (suite *StatusTestSuite) TestDereferenceStatusWithMention() {
|
|||
fetchingAccount := suite.testAccounts["local_account_1"]
|
||||
|
||||
statusURL := testrig.URLMustParse("https://unknown-instance.com/users/brand_new_person/statuses/01FE5Y30E3W4P7TRE0R98KAYQV")
|
||||
status, statusable, new, err := suite.dereferencer.GetRemoteStatus(context.Background(), fetchingAccount.Username, statusURL, false, false)
|
||||
status, _, err := suite.dereferencer.GetRemoteStatus(context.Background(), fetchingAccount.Username, statusURL, false, false)
|
||||
suite.NoError(err)
|
||||
suite.NotNil(status)
|
||||
suite.NotNil(statusable)
|
||||
suite.True(new)
|
||||
|
||||
// status values should be set
|
||||
suite.Equal("https://unknown-instance.com/users/brand_new_person/statuses/01FE5Y30E3W4P7TRE0R98KAYQV", status.URI)
|
||||
|
|
@ -135,11 +131,9 @@ func (suite *StatusTestSuite) TestDereferenceStatusWithImageAndNoContent() {
|
|||
fetchingAccount := suite.testAccounts["local_account_1"]
|
||||
|
||||
statusURL := testrig.URLMustParse("https://turnip.farm/users/turniplover6969/statuses/70c53e54-3146-42d5-a630-83c8b6c7c042")
|
||||
status, statusable, new, err := suite.dereferencer.GetRemoteStatus(context.Background(), fetchingAccount.Username, statusURL, false, false)
|
||||
status, _, err := suite.dereferencer.GetRemoteStatus(context.Background(), fetchingAccount.Username, statusURL, false, false)
|
||||
suite.NoError(err)
|
||||
suite.NotNil(status)
|
||||
suite.NotNil(statusable)
|
||||
suite.True(new)
|
||||
|
||||
// status values should be set
|
||||
suite.Equal("https://turnip.farm/users/turniplover6969/statuses/70c53e54-3146-42d5-a630-83c8b6c7c042", status.URI)
|
||||
|
|
|
|||
|
|
@ -52,9 +52,9 @@ func (d *deref) DereferenceThread(ctx context.Context, username string, statusIR
|
|||
}
|
||||
|
||||
// first make sure we have this status in our db
|
||||
_, statusable, _, err := d.GetRemoteStatus(ctx, username, statusIRI, true, false)
|
||||
_, statusable, err := d.GetRemoteStatus(ctx, username, statusIRI, true, false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("DereferenceThread: error getting status with id %s: %s", statusIRI.String(), err)
|
||||
return fmt.Errorf("DereferenceThread: error getting initial status with id %s: %s", statusIRI.String(), err)
|
||||
}
|
||||
|
||||
// first iterate up through ancestors, dereferencing if necessary as we go
|
||||
|
|
@ -106,9 +106,8 @@ func (d *deref) iterateAncestors(ctx context.Context, username string, statusIRI
|
|||
return d.iterateAncestors(ctx, username, *nextIRI)
|
||||
}
|
||||
|
||||
// If we reach here, we're looking at a remote status -- make sure we have it in our db by calling GetRemoteStatus
|
||||
// We call it with refresh to true because we want the statusable representation to parse inReplyTo from.
|
||||
_, statusable, _, err := d.GetRemoteStatus(ctx, username, &statusIRI, true, false)
|
||||
// If we reach here, we're looking at a remote status
|
||||
_, statusable, err := d.GetRemoteStatus(ctx, username, &statusIRI, true, false)
|
||||
if err != nil {
|
||||
l.Debugf("error getting remote status: %s", err)
|
||||
return nil
|
||||
|
|
@ -220,8 +219,8 @@ pageLoop:
|
|||
foundReplies++
|
||||
|
||||
// get the remote statusable and put it in the db
|
||||
_, statusable, new, err := d.GetRemoteStatus(ctx, username, itemURI, false, false)
|
||||
if new && err == nil && statusable != nil {
|
||||
_, statusable, err := d.GetRemoteStatus(ctx, username, itemURI, false, false)
|
||||
if err == nil {
|
||||
// now iterate descendants of *that* status
|
||||
if err := d.iterateDescendants(ctx, username, *itemURI, statusable); err != nil {
|
||||
continue
|
||||
|
|
|
|||
93
internal/federation/federatingdb/announce_test.go
Normal file
93
internal/federation/federatingdb/announce_test.go
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
GoToSocial
|
||||
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
|
||||
|
||||
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 (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
"github.com/superseriousbusiness/activity/streams/vocab"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/ap"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
)
|
||||
|
||||
type AnnounceTestSuite struct {
|
||||
FederatingDBTestSuite
|
||||
}
|
||||
|
||||
func (suite *AnnounceTestSuite) TestNewAnnounce() {
|
||||
receivingAccount1 := suite.testAccounts["local_account_1"]
|
||||
announcingAccount := suite.testAccounts["remote_account_1"]
|
||||
|
||||
ctx := createTestContext(receivingAccount1, announcingAccount)
|
||||
announce1 := suite.testActivities["announce_forwarded_1_zork"]
|
||||
|
||||
err := suite.federatingDB.Announce(ctx, announce1.Activity.(vocab.ActivityStreamsAnnounce))
|
||||
suite.NoError(err)
|
||||
|
||||
// should be a message heading to the processor now, which we can intercept here
|
||||
msg := <-suite.fromFederator
|
||||
suite.Equal(ap.ActivityAnnounce, msg.APObjectType)
|
||||
suite.Equal(ap.ActivityCreate, msg.APActivityType)
|
||||
|
||||
boost, ok := msg.GTSModel.(*gtsmodel.Status)
|
||||
suite.True(ok)
|
||||
suite.Equal(announcingAccount.ID, boost.AccountID)
|
||||
|
||||
// only the URI will be set on the boosted status because it still needs to be dereferenced
|
||||
suite.NotEmpty(boost.BoostOf.URI)
|
||||
}
|
||||
|
||||
func (suite *AnnounceTestSuite) TestAnnounceTwice() {
|
||||
receivingAccount1 := suite.testAccounts["local_account_1"]
|
||||
receivingAccount2 := suite.testAccounts["local_account_2"]
|
||||
|
||||
announcingAccount := suite.testAccounts["remote_account_1"]
|
||||
|
||||
ctx1 := createTestContext(receivingAccount1, announcingAccount)
|
||||
announce1 := suite.testActivities["announce_forwarded_1_zork"]
|
||||
|
||||
err := suite.federatingDB.Announce(ctx1, announce1.Activity.(vocab.ActivityStreamsAnnounce))
|
||||
suite.NoError(err)
|
||||
|
||||
// should be a message heading to the processor now, which we can intercept here
|
||||
msg := <-suite.fromFederator
|
||||
suite.Equal(ap.ActivityAnnounce, msg.APObjectType)
|
||||
suite.Equal(ap.ActivityCreate, msg.APActivityType)
|
||||
boost, ok := msg.GTSModel.(*gtsmodel.Status)
|
||||
suite.True(ok)
|
||||
suite.Equal(announcingAccount.ID, boost.AccountID)
|
||||
|
||||
// only the URI will be set on the boosted status because it still needs to be dereferenced
|
||||
suite.NotEmpty(boost.BoostOf.URI)
|
||||
|
||||
ctx2 := createTestContext(receivingAccount2, announcingAccount)
|
||||
announce2 := suite.testActivities["announce_forwarded_1_turtle"]
|
||||
|
||||
err = suite.federatingDB.Announce(ctx2, announce2.Activity.(vocab.ActivityStreamsAnnounce))
|
||||
suite.NoError(err)
|
||||
|
||||
// since this is a repeat announce with the same URI, just delivered to a different inbox,
|
||||
// we should have nothing in the messages channel...
|
||||
suite.Empty(suite.fromFederator)
|
||||
}
|
||||
|
||||
func TestAnnounceTestSuite(t *testing.T) {
|
||||
suite.Run(t, &AnnounceTestSuite{})
|
||||
}
|
||||
|
|
@ -63,8 +63,9 @@ func (suite *FederatingDBTestSuite) SetupSuite() {
|
|||
}
|
||||
|
||||
func (suite *FederatingDBTestSuite) SetupTest() {
|
||||
testrig.InitTestLog()
|
||||
testrig.InitTestConfig()
|
||||
testrig.InitTestLog()
|
||||
|
||||
suite.fedWorker = concurrency.NewWorkerPool[messages.FromFederator](-1, -1)
|
||||
suite.fromFederator = make(chan messages.FromFederator, 10)
|
||||
suite.fedWorker.SetProcessor(func(ctx context.Context, msg messages.FromFederator) error {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ type Federator interface {
|
|||
|
||||
GetRemoteAccount(ctx context.Context, username string, remoteAccountID *url.URL, blocking bool, refresh bool) (*gtsmodel.Account, error)
|
||||
|
||||
GetRemoteStatus(ctx context.Context, username string, remoteStatusID *url.URL, refresh, includeParent bool) (*gtsmodel.Status, ap.Statusable, bool, error)
|
||||
GetRemoteStatus(ctx context.Context, username string, remoteStatusID *url.URL, refetch, includeParent bool) (*gtsmodel.Status, ap.Statusable, error)
|
||||
EnrichRemoteStatus(ctx context.Context, username string, status *gtsmodel.Status, includeParent bool) (*gtsmodel.Status, error)
|
||||
|
||||
GetRemoteInstance(ctx context.Context, username string, remoteInstanceURI *url.URL) (*gtsmodel.Instance, error)
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ func (p *processor) processCreateStatusFromFederator(ctx context.Context, federa
|
|||
return errors.New("ProcessFromFederator: status was not pinned to federatorMsg, and neither was an IRI for us to dereference")
|
||||
}
|
||||
var err error
|
||||
status, _, _, err = p.federator.GetRemoteStatus(ctx, federatorMsg.ReceivingAccount.Username, federatorMsg.APIri, false, false)
|
||||
status, _, err = p.federator.GetRemoteStatus(ctx, federatorMsg.ReceivingAccount.Username, federatorMsg.APIri, false, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ import (
|
|||
"github.com/superseriousbusiness/gotosocial/internal/messages"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/oauth"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/processing"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/timeline"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/transport"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/typeutils"
|
||||
"github.com/superseriousbusiness/gotosocial/testrig"
|
||||
|
|
@ -54,7 +53,6 @@ type ProcessingStandardTestSuite struct {
|
|||
transportController transport.Controller
|
||||
federator federation.Federator
|
||||
oauthServer oauth.Server
|
||||
timelineManager timeline.Manager
|
||||
emailSender email.Sender
|
||||
|
||||
// standard suite models
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ func (p *processor) searchStatusByURI(ctx context.Context, authed *oauth.Auth, u
|
|||
|
||||
// we don't have it locally so dereference it if we're allowed to
|
||||
if resolve {
|
||||
status, _, _, err := p.federator.GetRemoteStatus(ctx, authed.Account.Username, uri, true, true)
|
||||
status, _, err := p.federator.GetRemoteStatus(ctx, authed.Account.Username, uri, false, true)
|
||||
if err == nil {
|
||||
if err := p.federator.DereferenceRemoteThread(ctx, authed.Account.Username, uri); err != nil {
|
||||
// try to deref the thread while we're here
|
||||
|
|
|
|||
|
|
@ -427,8 +427,8 @@ type TypeUtilsTestSuite struct {
|
|||
}
|
||||
|
||||
func (suite *TypeUtilsTestSuite) SetupSuite() {
|
||||
testrig.InitTestLog()
|
||||
testrig.InitTestConfig()
|
||||
testrig.InitTestLog()
|
||||
|
||||
suite.db = testrig.NewTestDB()
|
||||
suite.testAccounts = testrig.NewTestAccounts()
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ package typeutils_test
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -45,8 +45,11 @@ func (suite *InternalToASTestSuite) TestAccountToAS() {
|
|||
bytes, err := json.Marshal(ser)
|
||||
suite.NoError(err)
|
||||
|
||||
fmt.Println(string(bytes))
|
||||
// TODO: write assertions here, rn we're just eyeballing the output
|
||||
// trim off everything up to 'discoverable';
|
||||
// this is necessary because the order of multiple 'context' entries is not determinate
|
||||
trimmed := strings.Split(string(bytes), "\"discoverable\"")[1]
|
||||
|
||||
suite.Equal(`:true,"featured":"http://localhost:8080/users/the_mighty_zork/collections/featured","followers":"http://localhost:8080/users/the_mighty_zork/followers","following":"http://localhost:8080/users/the_mighty_zork/following","icon":{"mediaType":"image/jpeg","type":"Image","url":"http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpeg"},"id":"http://localhost:8080/users/the_mighty_zork","image":{"mediaType":"image/jpeg","type":"Image","url":"http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpeg"},"inbox":"http://localhost:8080/users/the_mighty_zork/inbox","manuallyApprovesFollowers":false,"name":"original zork (he/they)","outbox":"http://localhost:8080/users/the_mighty_zork/outbox","preferredUsername":"the_mighty_zork","publicKey":{"id":"http://localhost:8080/users/the_mighty_zork/main-key","owner":"http://localhost:8080/users/the_mighty_zork","publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwXTcOAvM1Jiw5Ffpk0qn\nr0cwbNvFe/5zQ+Tp7tumK/ZnT37o7X0FUEXrxNi+dkhmeJ0gsaiN+JQGNUewvpSk\nPIAXKvi908aSfCGjs7bGlJCJCuDuL5d6m7hZnP9rt9fJc70GElPpG0jc9fXwlz7T\nlsPb2ecatmG05Y4jPwdC+oN4MNCv9yQzEvCVMzl76EJaM602kIHC1CISn0rDFmYd\n9rSN7XPlNJw1F6PbpJ/BWQ+pXHKw3OEwNTETAUNYiVGnZU+B7a7bZC9f6/aPbJuV\nt8Qmg+UnDvW1Y8gmfHnxaWG2f5TDBvCHmcYtucIZPLQD4trAozC4ryqlmCWQNKbt\n0wIDAQAB\n-----END PUBLIC KEY-----\n"},"summary":"\u003cp\u003ehey yo this is my profile!\u003c/p\u003e","type":"Person","url":"http://localhost:8080/@the_mighty_zork"}`, trimmed)
|
||||
}
|
||||
|
||||
func (suite *InternalToASTestSuite) TestOutboxToASCollection() {
|
||||
|
|
|
|||
58
internal/typeutils/internaltofrontend_test.go
Normal file
58
internal/typeutils/internaltofrontend_test.go
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
GoToSocial
|
||||
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
|
||||
|
||||
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 typeutils_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
type InternalToFrontendTestSuite struct {
|
||||
TypeUtilsTestSuite
|
||||
}
|
||||
|
||||
func (suite *InternalToFrontendTestSuite) TestAccountToFrontend() {
|
||||
testAccount := suite.testAccounts["local_account_1"] // take zork for this test
|
||||
apiAccount, err := suite.typeconverter.AccountToAPIAccountPublic(context.Background(), testAccount)
|
||||
suite.NoError(err)
|
||||
suite.NotNil(apiAccount)
|
||||
|
||||
b, err := json.Marshal(apiAccount)
|
||||
suite.NoError(err)
|
||||
suite.Equal(`{"id":"01F8MH1H7YV1Z7D2C8K2730QBF","username":"the_mighty_zork","acct":"the_mighty_zork","display_name":"original zork (he/they)","locked":false,"bot":false,"created_at":"2022-05-20T11:09:18Z","note":"\u003cp\u003ehey yo this is my profile!\u003c/p\u003e","url":"http://localhost:8080/@the_mighty_zork","avatar":"http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpeg","avatar_static":"http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.jpeg","header":"http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpeg","header_static":"http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.jpeg","followers_count":2,"following_count":2,"statuses_count":5,"last_status_at":"2022-05-20T11:37:55Z","emojis":[],"fields":[]}`, string(b))
|
||||
}
|
||||
|
||||
func (suite *InternalToFrontendTestSuite) TestStatusToFrontend() {
|
||||
testStatus := suite.testStatuses["admin_account_status_1"]
|
||||
requestingAccount := suite.testAccounts["local_account_1"]
|
||||
apiStatus, err := suite.typeconverter.StatusToAPIStatus(context.Background(), testStatus, requestingAccount)
|
||||
suite.NoError(err)
|
||||
|
||||
b, err := json.Marshal(apiStatus)
|
||||
suite.NoError(err)
|
||||
|
||||
suite.Equal(`{"id":"01F8MH75CBF9JFX4ZAD54N0W0R","created_at":"2021-10-20T11:36:45Z","sensitive":false,"spoiler_text":"","visibility":"public","language":"en","uri":"http://localhost:8080/users/admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R","url":"http://localhost:8080/@admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R","replies_count":0,"reblogs_count":0,"favourites_count":1,"favourited":true,"reblogged":false,"muted":false,"bookmarked":false,"content":"hello world! #welcome ! first post on the instance :rainbow: !","application":{"name":"superseriousbusiness","website":"https://superserious.business"},"account":{"id":"01F8MH17FWEB39HZJ76B6VXSKF","username":"admin","acct":"admin","display_name":"","locked":false,"bot":false,"created_at":"2022-05-17T13:10:59Z","note":"","url":"http://localhost:8080/@admin","avatar":"","avatar_static":"","header":"","header_static":"","followers_count":1,"following_count":1,"statuses_count":4,"last_status_at":"2021-10-20T10:41:37Z","emojis":[],"fields":[]},"media_attachments":[{"id":"01F8MH6NEM8D7527KZAECTCR76","type":"image","url":"http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/original/01F8MH6NEM8D7527KZAECTCR76.jpeg","preview_url":"http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/small/01F8MH6NEM8D7527KZAECTCR76.jpeg","meta":{"original":{"width":1200,"height":630,"size":"1200x630","aspect":1.9047619},"small":{"width":256,"height":134,"size":"256x134","aspect":1.9104477},"focus":{"x":0,"y":0}},"description":"Black and white image of some 50's style text saying: Welcome On Board","blurhash":"LNJRdVM{00Rj%Mayt7j[4nWBofRj"}],"mentions":[],"tags":[{"name":"welcome","url":"http://localhost:8080/tags/welcome"}],"emojis":[{"shortcode":"rainbow","url":"http://localhost:8080/fileserver/01F8MH261H1KSV3GW3016GZRY3/emoji/original/01F8MH9H8E4VG3KDYJR9EGPXCQ.png","static_url":"http://localhost:8080/fileserver/01F8MH261H1KSV3GW3016GZRY3/emoji/static/01F8MH9H8E4VG3KDYJR9EGPXCQ.png","visible_in_picker":true}],"card":null,"poll":null,"text":""}`, string(b))
|
||||
}
|
||||
|
||||
func TestInternalToFrontendTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(InternalToFrontendTestSuite))
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue