mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 22:42:24 -05:00 
			
		
		
		
	[bugfix] Use gtserror package for WrongType errs (#1930)
* [bugfix] Use gtserror package for WrongType errs * test
This commit is contained in:
		
					parent
					
						
							
								e3e0f673cc
							
						
					
				
			
			
				commit
				
					
						d98b6318ac
					
				
			
		
					 11 changed files with 112 additions and 89 deletions
				
			
		|  | @ -184,7 +184,7 @@ func addressable5() ap.Addressable { | ||||||
| 	return note | 	return note | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type ExtractTestSuite struct { | type APTestSuite struct { | ||||||
| 	suite.Suite | 	suite.Suite | ||||||
| 	document1         vocab.ActivityStreamsDocument | 	document1         vocab.ActivityStreamsDocument | ||||||
| 	attachment1       vocab.ActivityStreamsAttachmentProperty | 	attachment1       vocab.ActivityStreamsAttachmentProperty | ||||||
|  | @ -196,7 +196,36 @@ type ExtractTestSuite struct { | ||||||
| 	addressable5      ap.Addressable | 	addressable5      ap.Addressable | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (suite *ExtractTestSuite) SetupTest() { | func (suite *APTestSuite) jsonToType(rawJson string) (vocab.Type, map[string]interface{}) { | ||||||
|  | 	var raw map[string]interface{} | ||||||
|  | 	err := json.Unmarshal([]byte(rawJson), &raw) | ||||||
|  | 	if err != nil { | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	t, err := streams.ToType(context.Background(), raw) | ||||||
|  | 	if err != nil { | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return t, raw | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (suite *APTestSuite) typeToJson(t vocab.Type) string { | ||||||
|  | 	m, err := ap.Serialize(t) | ||||||
|  | 	if err != nil { | ||||||
|  | 		suite.FailNow(err.Error()) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	b, err := json.MarshalIndent(m, "", "  ") | ||||||
|  | 	if err != nil { | ||||||
|  | 		suite.FailNow(err.Error()) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return string(b) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (suite *APTestSuite) SetupTest() { | ||||||
| 	suite.document1 = document1() | 	suite.document1 = document1() | ||||||
| 	suite.attachment1 = attachment1() | 	suite.attachment1 = attachment1() | ||||||
| 	suite.noteWithMentions1 = noteWithMentions1() | 	suite.noteWithMentions1 = noteWithMentions1() | ||||||
|  | @ -1,35 +0,0 @@ | ||||||
| // 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 ap |  | ||||||
| 
 |  | ||||||
| import "fmt" |  | ||||||
| 
 |  | ||||||
| // ErrWrongType indicates that we tried to resolve a type into |  | ||||||
| // an interface that it's not compatible with, eg a Person into |  | ||||||
| // a Statusable. |  | ||||||
| type ErrWrongType struct { |  | ||||||
| 	wrapped error |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (err *ErrWrongType) Error() string { |  | ||||||
| 	return fmt.Sprintf("wrong received type: %v", err.wrapped) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func newErrWrongType(err error) error { |  | ||||||
| 	return &ErrWrongType{wrapped: err} |  | ||||||
| } |  | ||||||
|  | @ -26,7 +26,7 @@ import ( | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type ExtractAttachmentsTestSuite struct { | type ExtractAttachmentsTestSuite struct { | ||||||
| 	ExtractTestSuite | 	APTestSuite | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (suite *ExtractAttachmentsTestSuite) TestExtractAttachmentMissingURL() { | func (suite *ExtractAttachmentsTestSuite) TestExtractAttachmentMissingURL() { | ||||||
|  |  | ||||||
|  | @ -25,7 +25,7 @@ import ( | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type ExtractContentTestSuite struct { | type ExtractContentTestSuite struct { | ||||||
| 	ExtractTestSuite | 	APTestSuite | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (suite *ExtractContentTestSuite) TestExtractContent1() { | func (suite *ExtractContentTestSuite) TestExtractContent1() { | ||||||
|  |  | ||||||
|  | @ -25,7 +25,7 @@ import ( | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type ExtractMentionsTestSuite struct { | type ExtractMentionsTestSuite struct { | ||||||
| 	ExtractTestSuite | 	APTestSuite | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (suite *ExtractMentionsTestSuite) TestExtractMentions() { | func (suite *ExtractMentionsTestSuite) TestExtractMentions() { | ||||||
|  |  | ||||||
|  | @ -25,7 +25,7 @@ import ( | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type ExtractSensitiveTestSuite struct { | type ExtractSensitiveTestSuite struct { | ||||||
| 	ExtractTestSuite | 	APTestSuite | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (suite *ExtractMentionsTestSuite) TestExtractSensitive() { | func (suite *ExtractMentionsTestSuite) TestExtractSensitive() { | ||||||
|  |  | ||||||
|  | @ -26,7 +26,7 @@ import ( | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type ExtractVisibilityTestSuite struct { | type ExtractVisibilityTestSuite struct { | ||||||
| 	ExtractTestSuite | 	APTestSuite | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (suite *ExtractVisibilityTestSuite) TestExtractVisibilityPublic() { | func (suite *ExtractVisibilityTestSuite) TestExtractVisibilityPublic() { | ||||||
|  |  | ||||||
|  | @ -18,48 +18,16 @@ | ||||||
| package ap_test | package ap_test | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"context" |  | ||||||
| 	"encoding/json" |  | ||||||
| 	"testing" | 	"testing" | ||||||
| 
 | 
 | ||||||
| 	"github.com/stretchr/testify/suite" | 	"github.com/stretchr/testify/suite" | ||||||
| 	"github.com/superseriousbusiness/activity/streams" |  | ||||||
| 	"github.com/superseriousbusiness/activity/streams/vocab" | 	"github.com/superseriousbusiness/activity/streams/vocab" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/ap" | 	"github.com/superseriousbusiness/gotosocial/internal/ap" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/testrig" | 	"github.com/superseriousbusiness/gotosocial/testrig" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type NormalizeTestSuite struct { | type NormalizeTestSuite struct { | ||||||
| 	suite.Suite | 	APTestSuite | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (suite *NormalizeTestSuite) jsonToType(rawJson string) (vocab.Type, map[string]interface{}) { |  | ||||||
| 	var raw map[string]interface{} |  | ||||||
| 	err := json.Unmarshal([]byte(rawJson), &raw) |  | ||||||
| 	if err != nil { |  | ||||||
| 		panic(err) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	t, err := streams.ToType(context.Background(), raw) |  | ||||||
| 	if err != nil { |  | ||||||
| 		panic(err) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return t, raw |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (suite *NormalizeTestSuite) typeToJson(t vocab.Type) string { |  | ||||||
| 	m, err := ap.Serialize(t) |  | ||||||
| 	if err != nil { |  | ||||||
| 		suite.FailNow(err.Error()) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	b, err := json.MarshalIndent(m, "", "  ") |  | ||||||
| 	if err != nil { |  | ||||||
| 		suite.FailNow(err.Error()) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return string(b) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (suite *NormalizeTestSuite) getStatusable() (vocab.ActivityStreamsNote, map[string]interface{}) { | func (suite *NormalizeTestSuite) getStatusable() (vocab.ActivityStreamsNote, map[string]interface{}) { | ||||||
|  |  | ||||||
|  | @ -20,10 +20,10 @@ package ap | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" |  | ||||||
| 
 | 
 | ||||||
| 	"github.com/superseriousbusiness/activity/streams" | 	"github.com/superseriousbusiness/activity/streams" | ||||||
| 	"github.com/superseriousbusiness/activity/streams/vocab" | 	"github.com/superseriousbusiness/activity/streams/vocab" | ||||||
|  | 	"github.com/superseriousbusiness/gotosocial/internal/gtserror" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // ResolveStatusable tries to resolve the given bytes into an ActivityPub Statusable representation. | // ResolveStatusable tries to resolve the given bytes into an ActivityPub Statusable representation. | ||||||
|  | @ -33,12 +33,12 @@ import ( | ||||||
| func ResolveStatusable(ctx context.Context, b []byte) (Statusable, error) { | func ResolveStatusable(ctx context.Context, b []byte) (Statusable, error) { | ||||||
| 	rawStatusable := make(map[string]interface{}) | 	rawStatusable := make(map[string]interface{}) | ||||||
| 	if err := json.Unmarshal(b, &rawStatusable); err != nil { | 	if err := json.Unmarshal(b, &rawStatusable); err != nil { | ||||||
| 		return nil, fmt.Errorf("ResolveStatusable: error unmarshalling bytes into json: %w", err) | 		return nil, gtserror.Newf("error unmarshalling bytes into json: %w", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	t, err := streams.ToType(ctx, rawStatusable) | 	t, err := streams.ToType(ctx, rawStatusable) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("ResolveStatusable: error resolving json into ap vocab type: %w", err) | 		return nil, gtserror.Newf("error resolving json into ap vocab type: %w", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	var ( | 	var ( | ||||||
|  | @ -68,8 +68,8 @@ func ResolveStatusable(ctx context.Context, b []byte) (Statusable, error) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if !ok { | 	if !ok { | ||||||
| 		err = fmt.Errorf("ResolveStatusable: could not resolve %T to Statusable", t) | 		err = gtserror.Newf("could not resolve %T to Statusable", t) | ||||||
| 		return nil, newErrWrongType(err) | 		return nil, gtserror.SetWrongType(err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	NormalizeIncomingContent(statusable, rawStatusable) | 	NormalizeIncomingContent(statusable, rawStatusable) | ||||||
|  | @ -87,12 +87,12 @@ func ResolveStatusable(ctx context.Context, b []byte) (Statusable, error) { | ||||||
| func ResolveAccountable(ctx context.Context, b []byte) (Accountable, error) { | func ResolveAccountable(ctx context.Context, b []byte) (Accountable, error) { | ||||||
| 	rawAccountable := make(map[string]interface{}) | 	rawAccountable := make(map[string]interface{}) | ||||||
| 	if err := json.Unmarshal(b, &rawAccountable); err != nil { | 	if err := json.Unmarshal(b, &rawAccountable); err != nil { | ||||||
| 		return nil, fmt.Errorf("ResolveAccountable: error unmarshalling bytes into json: %w", err) | 		return nil, gtserror.Newf("error unmarshalling bytes into json: %w", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	t, err := streams.ToType(ctx, rawAccountable) | 	t, err := streams.ToType(ctx, rawAccountable) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("ResolveAccountable: error resolving json into ap vocab type: %w", err) | 		return nil, gtserror.Newf("error resolving json into ap vocab type: %w", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	var ( | 	var ( | ||||||
|  | @ -114,8 +114,8 @@ func ResolveAccountable(ctx context.Context, b []byte) (Accountable, error) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if !ok { | 	if !ok { | ||||||
| 		err = fmt.Errorf("ResolveAccountable: could not resolve %T to Accountable", t) | 		err = gtserror.Newf("could not resolve %T to Accountable", t) | ||||||
| 		return nil, newErrWrongType(err) | 		return nil, gtserror.SetWrongType(err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	NormalizeIncomingSummary(accountable, rawAccountable) | 	NormalizeIncomingSummary(accountable, rawAccountable) | ||||||
|  |  | ||||||
							
								
								
									
										52
									
								
								internal/ap/resolve_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								internal/ap/resolve_test.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,52 @@ | ||||||
|  | // 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 ap_test | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/stretchr/testify/suite" | ||||||
|  | 	"github.com/superseriousbusiness/gotosocial/internal/ap" | ||||||
|  | 	"github.com/superseriousbusiness/gotosocial/internal/gtserror" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type ResolveTestSuite struct { | ||||||
|  | 	APTestSuite | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (suite *ResolveTestSuite) TestResolveDocumentAsStatusable() { | ||||||
|  | 	b := []byte(suite.typeToJson(suite.document1)) | ||||||
|  | 
 | ||||||
|  | 	statusable, err := ap.ResolveStatusable(context.Background(), b) | ||||||
|  | 	suite.NoError(err) | ||||||
|  | 	suite.NotNil(statusable) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (suite *ResolveTestSuite) TestResolveDocumentAsAccountable() { | ||||||
|  | 	b := []byte(suite.typeToJson(suite.document1)) | ||||||
|  | 
 | ||||||
|  | 	accountable, err := ap.ResolveAccountable(context.Background(), b) | ||||||
|  | 	suite.True(gtserror.WrongType(err)) | ||||||
|  | 	suite.EqualError(err, "ResolveAccountable: could not resolve *typedocument.ActivityStreamsDocument to Accountable") | ||||||
|  | 	suite.Nil(accountable) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestResolveTestSuite(t *testing.T) { | ||||||
|  | 	suite.Run(t, &ResolveTestSuite{}) | ||||||
|  | } | ||||||
|  | @ -40,26 +40,35 @@ const ( | ||||||
| 	TypeSMTP ErrorType = "smtp" // smtp (mail) | 	TypeSMTP ErrorType = "smtp" // smtp (mail) | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // Unretrievable ... | // Unretrievable checks error for a stored "unretrievable" flag. | ||||||
|  | // | ||||||
|  | // Unretrievable indicates that a call to retrieve a resource | ||||||
|  | // (account, status, etc) could not be fulfilled, either because | ||||||
|  | // it was not found locally, or because some prerequisite remote | ||||||
|  | // resource call failed, making it impossible to return the item. | ||||||
| func Unretrievable(err error) bool { | func Unretrievable(err error) bool { | ||||||
| 	_, ok := errors.Value(err, unrtrvableKey).(struct{}) | 	_, ok := errors.Value(err, unrtrvableKey).(struct{}) | ||||||
| 	return ok | 	return ok | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // SetUnretrievable ... | // SetUnretrievable will wrap the given error to store an "unretrievable" | ||||||
|  | // flag, returning wrapped error. See "Unretrievable" for example use-cases. | ||||||
| func SetUnretrievable(err error) error { | func SetUnretrievable(err error) error { | ||||||
| 	return errors.WithValue(err, unrtrvableKey, struct{}{}) | 	return errors.WithValue(err, unrtrvableKey, struct{}{}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // WrongType ... | // WrongType checks error for a stored "wrong type" flag. Wrong type | ||||||
|  | // indicates that an ActivityPub URI returned a type we weren't expecting: | ||||||
|  | // Statusable instead of Accountable, or vice versa, for example. | ||||||
| func WrongType(err error) bool { | func WrongType(err error) bool { | ||||||
| 	_, ok := errors.Value(err, wrongTypeKey).(struct{}) | 	_, ok := errors.Value(err, wrongTypeKey).(struct{}) | ||||||
| 	return ok | 	return ok | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // SetWrongType ... | // SetWrongType will wrap the given error to store a "wrong type" flag, | ||||||
|  | // returning wrapped error. See "WrongType" for example use-cases. | ||||||
| func SetWrongType(err error) error { | func SetWrongType(err error) error { | ||||||
| 	return errors.WithValue(err, unrtrvableKey, struct{}{}) | 	return errors.WithValue(err, wrongTypeKey, struct{}{}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // StatusCode checks error for a stored status code value. For example | // StatusCode checks error for a stored status code value. For example | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue