diff --git a/internal/apimodule/media/mediacreate_test.go b/internal/apimodule/media/mediacreate_test.go
index f598260..0c5c533 100644
--- a/internal/apimodule/media/mediacreate_test.go
+++ b/internal/apimodule/media/mediacreate_test.go
@@ -13,7 +13,6 @@ import (
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/mock"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
@@ -27,48 +26,43 @@ import (
)
type MediaCreateTestSuite struct {
+ // standard suite interfaces
suite.Suite
- config *config.Config
- mockOauthServer *oauth.MockServer
- mockStorage *storage.MockStorage
- mediaHandler media.MediaHandler
- mastoConverter mastotypes.Converter
+ config *config.Config
+ db db.DB
+ log *logrus.Logger
+ storage storage.Storage
+ mastoConverter mastotypes.Converter
+ mediaHandler media.MediaHandler
+ oauthServer oauth.Server
+
+ // standard suite models
testTokens map[string]*oauth.Token
testClients map[string]*oauth.Client
testApplications map[string]*gtsmodel.Application
testUsers map[string]*gtsmodel.User
testAccounts map[string]*gtsmodel.Account
- log *logrus.Logger
- db db.DB
- mediaModule *mediaModule
+ testAttachments map[string]*gtsmodel.MediaAttachment
+
+ // item being tested
+ mediaModule *mediaModule
}
/*
TEST INFRASTRUCTURE
*/
-// SetupSuite sets some variables on the suite that we can use as consts (more or less) throughout
func (suite *MediaCreateTestSuite) SetupSuite() {
- // some of our subsequent entities need a log so create this here
- log := logrus.New()
- log.SetLevel(logrus.TraceLevel)
- suite.log = log
-
- // Direct config to local postgres instance
+ // setup standard items
suite.config = testrig.NewTestConfig()
+ suite.db = testrig.NewTestDB()
+ suite.log = testrig.NewTestLog()
+ suite.storage = testrig.NewTestStorage()
+ suite.mastoConverter = testrig.NewTestMastoConverter(suite.db)
+ suite.mediaHandler = testrig.NewTestMediaHandler(suite.db, suite.storage)
+ suite.oauthServer = testrig.NewTestOauthServer(suite.db)
- // use an actual database for this, because it's just easier than mocking one out
- database, err := db.New(context.Background(), suite.config, log)
- if err != nil {
- suite.FailNow(err.Error())
- }
- suite.db = database
-
- suite.mockOauthServer = &oauth.MockServer{}
- suite.mockStorage = &storage.MockStorage{}
- suite.mockStorage.On("StoreFileAt", mock.AnythingOfType("string"), mock.AnythingOfType("[]uint8")).Return(nil) // just pretend to store
- suite.mediaHandler = media.New(suite.config, suite.db, suite.mockStorage, log)
- suite.mastoConverter = mastotypes.New(suite.config, suite.db)
+ // setup module being tested
suite.mediaModule = New(suite.db, suite.mediaHandler, suite.mastoConverter, suite.config, suite.log).(*mediaModule)
}
@@ -80,16 +74,18 @@ func (suite *MediaCreateTestSuite) TearDownSuite() {
func (suite *MediaCreateTestSuite) SetupTest() {
testrig.StandardDBSetup(suite.db)
+ testrig.StandardStorageSetup(suite.storage, "../../../testrig/media")
suite.testTokens = testrig.NewTestTokens()
suite.testClients = testrig.NewTestClients()
suite.testApplications = testrig.NewTestApplications()
suite.testUsers = testrig.NewTestUsers()
suite.testAccounts = testrig.NewTestAccounts()
+ suite.testAttachments = testrig.NewTestAttachments()
}
-// TearDownTest drops tables to make sure there's no data in the db
func (suite *MediaCreateTestSuite) TearDownTest() {
testrig.StandardDBTeardown(suite.db)
+ testrig.StandardStorageTeardown(suite.storage)
}
/*
@@ -98,28 +94,42 @@ func (suite *MediaCreateTestSuite) TearDownTest() {
func (suite *MediaCreateTestSuite) TestStatusCreatePOSTImageHandlerSuccessful() {
+ // set up the context for the request
t := suite.testTokens["local_account_1"]
oauthToken := oauth.PGTokenToOauthToken(t)
-
- // setup
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
ctx.Set(oauth.SessionAuthorizedAccount, suite.testAccounts["local_account_1"])
- buf, w, err := testrig.CreateMultipartFormData("file", "../../media/test/test-jpeg.jpg", map[string]string{
+
+ // see what's in storage *before* the request
+ storageKeysBeforeRequest, err := suite.storage.ListKeys()
+ if err != nil {
+ panic(err)
+ }
+
+ // create the request
+ buf, w, err := testrig.CreateMultipartFormData("file", "../../../testrig/media/test-jpeg.jpg", map[string]string{
"description": "this is a test image -- a cool background from somewhere",
"focus": "-0.5,0.5",
})
if err != nil {
panic(err)
}
-
ctx.Request = httptest.NewRequest(http.MethodPost, fmt.Sprintf("http://localhost:8080/%s", basePath), bytes.NewReader(buf.Bytes())) // the endpoint we're hitting
ctx.Request.Header.Set("Content-Type", w.FormDataContentType())
+
+ // do the actual request
suite.mediaModule.mediaCreatePOSTHandler(ctx)
+ // check what's in storage *after* the request
+ storageKeysAfterRequest, err := suite.storage.ListKeys()
+ if err != nil {
+ panic(err)
+ }
+
// check response
suite.EqualValues(http.StatusAccepted, recorder.Code)
@@ -157,6 +167,7 @@ func (suite *MediaCreateTestSuite) TestStatusCreatePOSTImageHandlerSuccessful()
assert.NotEmpty(suite.T(), attachmentReply.ID)
assert.NotEmpty(suite.T(), attachmentReply.URL)
assert.NotEmpty(suite.T(), attachmentReply.PreviewURL)
+ assert.Equal(suite.T(), len(storageKeysBeforeRequest) + 2, len(storageKeysAfterRequest)) // 2 images should be added to storage: the original and the thumbnail
}
func TestMediaCreateTestSuite(t *testing.T) {
diff --git a/internal/gotosocial/actions.go b/internal/gotosocial/actions.go
index 1b3dbf6..2e745e7 100644
--- a/internal/gotosocial/actions.go
+++ b/internal/gotosocial/actions.go
@@ -31,6 +31,7 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/apimodule/account"
"github.com/superseriousbusiness/gotosocial/internal/apimodule/app"
"github.com/superseriousbusiness/gotosocial/internal/apimodule/auth"
+ mediaModule "github.com/superseriousbusiness/gotosocial/internal/apimodule/media"
"github.com/superseriousbusiness/gotosocial/internal/cache"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
@@ -54,7 +55,7 @@ var Run action.GTSAction = func(ctx context.Context, c *config.Config, log *logr
return fmt.Errorf("error creating router: %s", err)
}
- storageBackend, err := storage.NewInMem(c, log)
+ storageBackend, err := storage.NewLocal(c, log)
if err != nil {
return fmt.Errorf("error creating storage backend: %s", err)
}
@@ -70,11 +71,13 @@ var Run action.GTSAction = func(ctx context.Context, c *config.Config, log *logr
authModule := auth.New(oauthServer, dbService, log)
accountModule := account.New(c, dbService, oauthServer, mediaHandler, mastoConverter, log)
appsModule := app.New(oauthServer, dbService, mastoConverter, log)
+ mm := mediaModule.New(dbService, mediaHandler, mastoConverter, c, log)
apiModules := []apimodule.ClientAPIModule{
authModule, // this one has to go first so the other modules use its middleware
accountModule,
appsModule,
+ mm,
}
for _, m := range apiModules {
diff --git a/internal/mastotypes/mock_Converter.go b/internal/mastotypes/mock_Converter.go
index 881bc48..732d933 100644
--- a/internal/mastotypes/mock_Converter.go
+++ b/internal/mastotypes/mock_Converter.go
@@ -104,3 +104,45 @@ func (_m *MockConverter) AppToMastoSensitive(application *gtsmodel.Application)
return r0, r1
}
+
+// AttachmentToMasto provides a mock function with given fields: attachment
+func (_m *MockConverter) AttachmentToMasto(attachment *gtsmodel.MediaAttachment) (mastotypes.Attachment, error) {
+ ret := _m.Called(attachment)
+
+ var r0 mastotypes.Attachment
+ if rf, ok := ret.Get(0).(func(*gtsmodel.MediaAttachment) mastotypes.Attachment); ok {
+ r0 = rf(attachment)
+ } else {
+ r0 = ret.Get(0).(mastotypes.Attachment)
+ }
+
+ var r1 error
+ if rf, ok := ret.Get(1).(func(*gtsmodel.MediaAttachment) error); ok {
+ r1 = rf(attachment)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// MentionToMasto provides a mock function with given fields: m
+func (_m *MockConverter) MentionToMasto(m *gtsmodel.Mention) (mastotypes.Mention, error) {
+ ret := _m.Called(m)
+
+ var r0 mastotypes.Mention
+ if rf, ok := ret.Get(0).(func(*gtsmodel.Mention) mastotypes.Mention); ok {
+ r0 = rf(m)
+ } else {
+ r0 = ret.Get(0).(mastotypes.Mention)
+ }
+
+ var r1 error
+ if rf, ok := ret.Get(1).(func(*gtsmodel.Mention) error); ok {
+ r1 = rf(m)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
diff --git a/internal/media/mock_MediaHandler.go b/internal/media/mock_MediaHandler.go
index 6f04f1f..1f87555 100644
--- a/internal/media/mock_MediaHandler.go
+++ b/internal/media/mock_MediaHandler.go
@@ -12,6 +12,29 @@ type MockMediaHandler struct {
mock.Mock
}
+// ProcessAttachment provides a mock function with given fields: img, accountID
+func (_m *MockMediaHandler) ProcessAttachment(img []byte, accountID string) (*gtsmodel.MediaAttachment, error) {
+ ret := _m.Called(img, accountID)
+
+ var r0 *gtsmodel.MediaAttachment
+ if rf, ok := ret.Get(0).(func([]byte, string) *gtsmodel.MediaAttachment); ok {
+ r0 = rf(img, accountID)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*gtsmodel.MediaAttachment)
+ }
+ }
+
+ var r1 error
+ if rf, ok := ret.Get(1).(func([]byte, string) error); ok {
+ r1 = rf(img, accountID)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
// SetHeaderOrAvatarForAccountID provides a mock function with given fields: img, accountID, headerOrAvi
func (_m *MockMediaHandler) SetHeaderOrAvatarForAccountID(img []byte, accountID string, headerOrAvi string) (*gtsmodel.MediaAttachment, error) {
ret := _m.Called(img, accountID, headerOrAvi)
diff --git a/internal/storage/inmem.go b/internal/storage/inmem.go
index 31c2bd9..976ddd7 100644
--- a/internal/storage/inmem.go
+++ b/internal/storage/inmem.go
@@ -15,22 +15,41 @@ import (
func NewInMem(c *config.Config, log *logrus.Logger) (Storage, error) {
return &inMemStorage{
stored: make(map[string][]byte),
+ log: log,
}, nil
}
type inMemStorage struct {
stored map[string][]byte
+ log *logrus.Logger
}
func (s *inMemStorage) StoreFileAt(path string, data []byte) error {
+ l := s.log.WithField("func", "StoreFileAt")
+ l.Debugf("storing at path %s", path)
s.stored[path] = data
return nil
}
func (s *inMemStorage) RetrieveFileFrom(path string) ([]byte, error) {
+ l := s.log.WithField("func", "RetrieveFileFrom")
+ l.Debugf("retrieving from path %s", path)
d, ok := s.stored[path]
if !ok {
return nil, fmt.Errorf("no data found at path %s", path)
}
return d, nil
}
+
+func (s *inMemStorage)ListKeys() ([]string, error) {
+ keys := []string{}
+ for k := range s.stored {
+ keys = append(keys, k)
+ }
+ return keys, nil
+}
+
+func (s *inMemStorage) RemoveFileAt(path string) error {
+ delete(s.stored, path)
+ return nil
+}
diff --git a/internal/storage/local.go b/internal/storage/local.go
index 620467d..09a62be 100644
--- a/internal/storage/local.go
+++ b/internal/storage/local.go
@@ -1,6 +1,11 @@
package storage
import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "strings"
+
"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/config"
)
@@ -8,16 +13,58 @@ import (
// NewLocal returns an implementation of the Storage interface that uses
// the local filesystem for storing and retrieving files, attachments, etc.
func NewLocal(c *config.Config, log *logrus.Logger) (Storage, error) {
- return &localStorage{}, nil
+ return &localStorage{
+ config: c,
+ log: log,
+ }, nil
}
type localStorage struct {
+ config *config.Config
+ log *logrus.Logger
}
func (s *localStorage) StoreFileAt(path string, data []byte) error {
+ l := s.log.WithField("func", "StoreFileAt")
+ l.Debugf("storing at path %s", path)
+ components := strings.Split(path, "/")
+ dir := strings.Join(components[0:len(components) - 1], "/")
+ if err := os.MkdirAll(dir, 0777); err != nil {
+ return fmt.Errorf("error writing file at %s: %s", path, err)
+ }
+ if err := os.WriteFile(path, data, 0777); err != nil {
+ return fmt.Errorf("error writing file at %s: %s", path, err)
+ }
return nil
}
func (s *localStorage) RetrieveFileFrom(path string) ([]byte, error) {
- return nil, nil
+ l := s.log.WithField("func", "RetrieveFileFrom")
+ l.Debugf("retrieving from path %s", path)
+ b, err := os.ReadFile(path)
+ if err != nil {
+ return nil, fmt.Errorf("error reading file at %s: %s", path, err)
+ }
+ return b, nil
+}
+
+func (s *localStorage) ListKeys() ([]string, error) {
+ keys := []string{}
+ err := filepath.Walk(s.config.StorageConfig.BasePath, func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+ if !info.IsDir() {
+ keys = append(keys, path)
+ }
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+ return keys, nil
+}
+
+func (s *localStorage) RemoveFileAt(path string) error {
+ return os.Remove(path)
}
diff --git a/internal/storage/mock_Storage.go b/internal/storage/mock_Storage.go
index 865d522..2444f03 100644
--- a/internal/storage/mock_Storage.go
+++ b/internal/storage/mock_Storage.go
@@ -9,6 +9,43 @@ type MockStorage struct {
mock.Mock
}
+// ListKeys provides a mock function with given fields:
+func (_m *MockStorage) ListKeys() ([]string, error) {
+ ret := _m.Called()
+
+ var r0 []string
+ if rf, ok := ret.Get(0).(func() []string); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]string)
+ }
+ }
+
+ var r1 error
+ if rf, ok := ret.Get(1).(func() error); ok {
+ r1 = rf()
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// RemoveFileAt provides a mock function with given fields: path
+func (_m *MockStorage) RemoveFileAt(path string) error {
+ ret := _m.Called(path)
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(string) error); ok {
+ r0 = rf(path)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
// RetrieveFileFrom provides a mock function with given fields: path
func (_m *MockStorage) RetrieveFileFrom(path string) ([]byte, error) {
ret := _m.Called(path)
diff --git a/internal/storage/storage.go b/internal/storage/storage.go
index 7c85d0a..493c364 100644
--- a/internal/storage/storage.go
+++ b/internal/storage/storage.go
@@ -25,4 +25,6 @@ package storage
type Storage interface {
StoreFileAt(path string, data []byte) error
RetrieveFileFrom(path string) ([]byte, error)
+ ListKeys() ([]string, error)
+ RemoveFileAt(path string) error
}
diff --git a/testrig/config.go b/testrig/config.go
index 1bc0b8b..f7028b1 100644
--- a/testrig/config.go
+++ b/testrig/config.go
@@ -1,3 +1,21 @@
+/*
+ GoToSocial
+ Copyright (C) 2021 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 .
+*/
+
package testrig
import "github.com/superseriousbusiness/gotosocial/internal/config"
diff --git a/testrig/db.go b/testrig/db.go
index e930ba2..10025c9 100644
--- a/testrig/db.go
+++ b/testrig/db.go
@@ -1,3 +1,21 @@
+/*
+ GoToSocial
+ Copyright (C) 2021 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 .
+*/
+
package testrig
import (
diff --git a/testrig/log.go b/testrig/log.go
new file mode 100644
index 0000000..0bafc96
--- /dev/null
+++ b/testrig/log.go
@@ -0,0 +1,28 @@
+/*
+ GoToSocial
+ Copyright (C) 2021 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 .
+*/
+
+package testrig
+
+import "github.com/sirupsen/logrus"
+
+// NewTestLog returns a trace level logger for testing
+func NewTestLog() *logrus.Logger {
+ log := logrus.New()
+ log.SetLevel(logrus.TraceLevel)
+ return log
+}
diff --git a/testrig/mastoconverter.go b/testrig/mastoconverter.go
new file mode 100644
index 0000000..10bdbdc
--- /dev/null
+++ b/testrig/mastoconverter.go
@@ -0,0 +1,29 @@
+/*
+ GoToSocial
+ Copyright (C) 2021 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 .
+*/
+
+package testrig
+
+import (
+ "github.com/superseriousbusiness/gotosocial/internal/db"
+ "github.com/superseriousbusiness/gotosocial/internal/mastotypes"
+)
+
+// NewTestMastoConverter returned a mastotypes converter with the given db and the default test config
+func NewTestMastoConverter(db db.DB) mastotypes.Converter {
+ return mastotypes.New(NewTestConfig(), db)
+}
diff --git a/testrig/media/welcome-original.jpeg b/testrig/media/welcome-original.jpeg
new file mode 100755
index 0000000..1a54437
Binary files /dev/null and b/testrig/media/welcome-original.jpeg differ
diff --git a/testrig/media/welcome-small.jpeg b/testrig/media/welcome-small.jpeg
new file mode 100755
index 0000000..b1a5851
Binary files /dev/null and b/testrig/media/welcome-small.jpeg differ
diff --git a/testrig/mediahandler.go b/testrig/mediahandler.go
new file mode 100644
index 0000000..fd79866
--- /dev/null
+++ b/testrig/mediahandler.go
@@ -0,0 +1,31 @@
+/*
+ GoToSocial
+ Copyright (C) 2021 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 .
+*/
+
+package testrig
+
+import (
+ "github.com/superseriousbusiness/gotosocial/internal/db"
+ "github.com/superseriousbusiness/gotosocial/internal/media"
+ "github.com/superseriousbusiness/gotosocial/internal/storage"
+)
+
+// NewTestMediaHandler returns a media handler with the default test config, the default test logger,
+// and the given db and storage.
+func NewTestMediaHandler(db db.DB, storage storage.Storage) media.MediaHandler {
+ return media.New(NewTestConfig(), db, storage, NewTestLog())
+}
diff --git a/testrig/oauthserver.go b/testrig/oauthserver.go
new file mode 100644
index 0000000..49615ca
--- /dev/null
+++ b/testrig/oauthserver.go
@@ -0,0 +1,29 @@
+/*
+ GoToSocial
+ Copyright (C) 2021 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 .
+*/
+
+package testrig
+
+import (
+ "github.com/superseriousbusiness/gotosocial/internal/db"
+ "github.com/superseriousbusiness/gotosocial/internal/oauth"
+)
+
+// NewTestOauthServer returns an oauth server with the given db, and the default test logger.
+func NewTestOauthServer(db db.DB) oauth.Server {
+ return oauth.New(db, NewTestLog())
+}
diff --git a/testrig/storage.go b/testrig/storage.go
index 3786b06..a17f620 100644
--- a/testrig/storage.go
+++ b/testrig/storage.go
@@ -1,24 +1,79 @@
+/*
+ GoToSocial
+ Copyright (C) 2021 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 .
+*/
+
package testrig
import (
- "github.com/sirupsen/logrus"
- "github.com/superseriousbusiness/gotosocial/internal/config"
+ "fmt"
+ "os"
+ "strings"
+
"github.com/superseriousbusiness/gotosocial/internal/storage"
)
-// NewTestStorage returns a new in memory storage with the given config
-func NewTestStorage(c *config.Config, log *logrus.Logger) storage.Storage {
- s, err := storage.NewInMem(c, log)
+// NewTestStorage returns a new in memory storage with the default test config
+func NewTestStorage() storage.Storage {
+ s, err := storage.NewInMem(NewTestConfig(), NewTestLog())
if err != nil {
panic(err)
}
return s
}
-func StandardStorageSetup(s storage.Storage) {
-
+// StandardStorageSetup populates the storage with standard test entries from the given directory.
+func StandardStorageSetup(s storage.Storage, relativePath string) {
+ stored := NewTestStored()
+ a := NewTestAttachments()
+ for k, fileNameTemplate := range stored {
+ attachmentInfo, ok := a[k]
+ if !ok {
+ panic(fmt.Errorf("key %s not found in test attachments", k))
+ }
+ filenameOriginal := strings.Replace(fileNameTemplate, "*", "original", 1)
+ filenameSmall := strings.Replace(fileNameTemplate, "*", "small", 1)
+ pathOriginal := attachmentInfo.File.Path
+ pathSmall := attachmentInfo.Thumbnail.Path
+ bOriginal, err := os.ReadFile(fmt.Sprintf("%s/%s", relativePath, filenameOriginal))
+ if err != nil {
+ panic(err)
+ }
+ if err := s.StoreFileAt(pathOriginal, bOriginal); err != nil {
+ panic(err)
+ }
+ bSmall, err := os.ReadFile(fmt.Sprintf("%s/%s", relativePath, filenameSmall))
+ if err != nil {
+ panic(err)
+ }
+ if err := s.StoreFileAt(pathSmall, bSmall); err != nil {
+ panic(err)
+ }
+ }
}
+// StandardStorageTeardown deletes everything in storage so that it's clean for the next test
func StandardStorageTeardown(s storage.Storage) {
-
+ keys, err := s.ListKeys()
+ if err != nil {
+ panic(err)
+ }
+ for _, k := range keys {
+ if err := s.RemoveFileAt(k); err != nil {
+ panic(err)
+ }
+ }
}
diff --git a/testrig/models.go b/testrig/testmodels.go
similarity index 87%
rename from testrig/models.go
rename to testrig/testmodels.go
index 9606199..65358eb 100644
--- a/testrig/models.go
+++ b/testrig/testmodels.go
@@ -1,3 +1,21 @@
+/*
+ GoToSocial
+ Copyright (C) 2021 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 .
+*/
+
package testrig
import (
@@ -10,6 +28,7 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
+// NewTestTokens returns a map of tokens keyed according to which account the token belongs to.
func NewTestTokens() map[string]*oauth.Token {
tokens := map[string]*oauth.Token{
"local_account_1": {
@@ -26,6 +45,7 @@ func NewTestTokens() map[string]*oauth.Token {
return tokens
}
+// NewTestClients returns a map of Clients keyed according to which account they are used by.
func NewTestClients() map[string]*oauth.Client {
clients := map[string]*oauth.Client{
"local_account_1": {
@@ -38,6 +58,7 @@ func NewTestClients() map[string]*oauth.Client {
return clients
}
+// NewTestApplications returns a map of applications keyed to which number application they are.
func NewTestApplications() map[string]*gtsmodel.Application {
apps := map[string]*gtsmodel.Application{
"application_1": {
@@ -54,6 +75,7 @@ func NewTestApplications() map[string]*gtsmodel.Application {
return apps
}
+// NewTestUsers returns a map of Users keyed by which account belongs to them.
func NewTestUsers() map[string]*gtsmodel.User {
users := map[string]*gtsmodel.User{
"unconfirmed_account": {
@@ -181,6 +203,7 @@ func NewTestUsers() map[string]*gtsmodel.User {
return users
}
+// NewTestAccounts returns a map of accounts keyed by what type of account they are.
func NewTestAccounts() map[string]*gtsmodel.Account {
accounts := map[string]*gtsmodel.Account{
"unconfirmed_account": {
@@ -440,14 +463,66 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
return accounts
}
+// NewTestAttachments returns a map of attachments keyed according to which account
+// and status they belong to, and which attachment number of that status they are.
func NewTestAttachments() map[string]*gtsmodel.MediaAttachment {
return map[string]*gtsmodel.MediaAttachment{
- // "admin_account_status_1": {
-
- // },
+ "admin_account_status_1_attachment_1": {
+ ID: "b052241b-f30f-4dc6-92fc-2bad0be1f8d8",
+ StatusID: "502ccd6f-0edf-48d7-9016-2dfa4d3714cd",
+ URL: "http://localhost:8080/fileserver/8020dbb4-1e7b-4d99-a872-4cf94e64210f/attachment/original/b052241b-f30f-4dc6-92fc-2bad0be1f8d8.jpeg",
+ RemoteURL: "",
+ CreatedAt: time.Now().Add(-71 * time.Hour),
+ UpdatedAt: time.Now().Add(-71 * time.Hour),
+ Type: gtsmodel.FileTypeImage,
+ FileMeta: gtsmodel.FileMeta{
+ Original: gtsmodel.Original{
+ Width: 1200,
+ Height: 630,
+ Size: 756000,
+ Aspect: 1.9047619047619047,
+ },
+ Small: gtsmodel.Small{
+ Width: 256,
+ Height: 134,
+ Size: 34304,
+ Aspect: 1.9104477611940298,
+ },
+ },
+ AccountID: "8020dbb4-1e7b-4d99-a872-4cf94e64210f",
+ Description: "Black and white image of some 50's style text saying: Welcome On Board",
+ ScheduledStatusID: "",
+ Blurhash: "LNJRdVM{00Rj%Mayt7j[4nWBofRj",
+ Processing: 2,
+ File: gtsmodel.File{
+ Path: "/gotosocial/storage/8020dbb4-1e7b-4d99-a872-4cf94e64210f/attachment/original/b052241b-f30f-4dc6-92fc-2bad0be1f8d8.jpeg",
+ ContentType: "image/jpeg",
+ FileSize: 62529,
+ UpdatedAt: time.Now().Add(-71 * time.Hour),
+ },
+ Thumbnail: gtsmodel.Thumbnail{
+ Path: "/gotosocial/storage/8020dbb4-1e7b-4d99-a872-4cf94e64210f/attachment/small/b052241b-f30f-4dc6-92fc-2bad0be1f8d8.jpeg",
+ ContentType: "image/jpeg",
+ FileSize: 6872,
+ UpdatedAt: time.Now().Add(-71 * time.Hour),
+ URL: "http://localhost:8080/fileserver/8020dbb4-1e7b-4d99-a872-4cf94e64210f/attachment/small/b052241b-f30f-4dc6-92fc-2bad0be1f8d8.jpeg",
+ RemoteURL: "",
+ },
+ Avatar: false,
+ Header: false,
+ },
}
}
+// NewTestStored returns a map of filenames, keyed according to which attachment they pertain to.
+func NewTestStored() map[string]string {
+ return map[string]string {
+ "admin_account_status_1_attachment_1": "welcome-*.jpeg",
+ }
+}
+
+// NewTestStatuses returns a map of statuses keyed according to which account
+// and status they are.
func NewTestStatuses() map[string]*gtsmodel.Status {
return map[string]*gtsmodel.Status{
"admin_account_status_1": {