more work on test rig
This commit is contained in:
parent
9a57dac5a1
commit
7ab9e78b44
|
@ -13,7 +13,6 @@ import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/mock"
|
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/config"
|
"github.com/superseriousbusiness/gotosocial/internal/config"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||||
|
@ -27,19 +26,25 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type MediaCreateTestSuite struct {
|
type MediaCreateTestSuite struct {
|
||||||
|
// standard suite interfaces
|
||||||
suite.Suite
|
suite.Suite
|
||||||
config *config.Config
|
config *config.Config
|
||||||
mockOauthServer *oauth.MockServer
|
db db.DB
|
||||||
mockStorage *storage.MockStorage
|
log *logrus.Logger
|
||||||
mediaHandler media.MediaHandler
|
storage storage.Storage
|
||||||
mastoConverter mastotypes.Converter
|
mastoConverter mastotypes.Converter
|
||||||
|
mediaHandler media.MediaHandler
|
||||||
|
oauthServer oauth.Server
|
||||||
|
|
||||||
|
// standard suite models
|
||||||
testTokens map[string]*oauth.Token
|
testTokens map[string]*oauth.Token
|
||||||
testClients map[string]*oauth.Client
|
testClients map[string]*oauth.Client
|
||||||
testApplications map[string]*gtsmodel.Application
|
testApplications map[string]*gtsmodel.Application
|
||||||
testUsers map[string]*gtsmodel.User
|
testUsers map[string]*gtsmodel.User
|
||||||
testAccounts map[string]*gtsmodel.Account
|
testAccounts map[string]*gtsmodel.Account
|
||||||
log *logrus.Logger
|
testAttachments map[string]*gtsmodel.MediaAttachment
|
||||||
db db.DB
|
|
||||||
|
// item being tested
|
||||||
mediaModule *mediaModule
|
mediaModule *mediaModule
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,28 +52,17 @@ type MediaCreateTestSuite struct {
|
||||||
TEST INFRASTRUCTURE
|
TEST INFRASTRUCTURE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// SetupSuite sets some variables on the suite that we can use as consts (more or less) throughout
|
|
||||||
func (suite *MediaCreateTestSuite) SetupSuite() {
|
func (suite *MediaCreateTestSuite) SetupSuite() {
|
||||||
// some of our subsequent entities need a log so create this here
|
// setup standard items
|
||||||
log := logrus.New()
|
|
||||||
log.SetLevel(logrus.TraceLevel)
|
|
||||||
suite.log = log
|
|
||||||
|
|
||||||
// Direct config to local postgres instance
|
|
||||||
suite.config = testrig.NewTestConfig()
|
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
|
// setup module being tested
|
||||||
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)
|
|
||||||
suite.mediaModule = New(suite.db, suite.mediaHandler, suite.mastoConverter, suite.config, suite.log).(*mediaModule)
|
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() {
|
func (suite *MediaCreateTestSuite) SetupTest() {
|
||||||
testrig.StandardDBSetup(suite.db)
|
testrig.StandardDBSetup(suite.db)
|
||||||
|
testrig.StandardStorageSetup(suite.storage, "../../../testrig/media")
|
||||||
suite.testTokens = testrig.NewTestTokens()
|
suite.testTokens = testrig.NewTestTokens()
|
||||||
suite.testClients = testrig.NewTestClients()
|
suite.testClients = testrig.NewTestClients()
|
||||||
suite.testApplications = testrig.NewTestApplications()
|
suite.testApplications = testrig.NewTestApplications()
|
||||||
suite.testUsers = testrig.NewTestUsers()
|
suite.testUsers = testrig.NewTestUsers()
|
||||||
suite.testAccounts = testrig.NewTestAccounts()
|
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() {
|
func (suite *MediaCreateTestSuite) TearDownTest() {
|
||||||
testrig.StandardDBTeardown(suite.db)
|
testrig.StandardDBTeardown(suite.db)
|
||||||
|
testrig.StandardStorageTeardown(suite.storage)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -98,28 +94,42 @@ func (suite *MediaCreateTestSuite) TearDownTest() {
|
||||||
|
|
||||||
func (suite *MediaCreateTestSuite) TestStatusCreatePOSTImageHandlerSuccessful() {
|
func (suite *MediaCreateTestSuite) TestStatusCreatePOSTImageHandlerSuccessful() {
|
||||||
|
|
||||||
|
// set up the context for the request
|
||||||
t := suite.testTokens["local_account_1"]
|
t := suite.testTokens["local_account_1"]
|
||||||
oauthToken := oauth.PGTokenToOauthToken(t)
|
oauthToken := oauth.PGTokenToOauthToken(t)
|
||||||
|
|
||||||
// setup
|
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
ctx, _ := gin.CreateTestContext(recorder)
|
ctx, _ := gin.CreateTestContext(recorder)
|
||||||
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
|
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
|
||||||
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
|
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
|
||||||
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
|
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
|
||||||
ctx.Set(oauth.SessionAuthorizedAccount, suite.testAccounts["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",
|
"description": "this is a test image -- a cool background from somewhere",
|
||||||
"focus": "-0.5,0.5",
|
"focus": "-0.5,0.5",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
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 = 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())
|
ctx.Request.Header.Set("Content-Type", w.FormDataContentType())
|
||||||
|
|
||||||
|
// do the actual request
|
||||||
suite.mediaModule.mediaCreatePOSTHandler(ctx)
|
suite.mediaModule.mediaCreatePOSTHandler(ctx)
|
||||||
|
|
||||||
|
// check what's in storage *after* the request
|
||||||
|
storageKeysAfterRequest, err := suite.storage.ListKeys()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
// check response
|
// check response
|
||||||
suite.EqualValues(http.StatusAccepted, recorder.Code)
|
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.ID)
|
||||||
assert.NotEmpty(suite.T(), attachmentReply.URL)
|
assert.NotEmpty(suite.T(), attachmentReply.URL)
|
||||||
assert.NotEmpty(suite.T(), attachmentReply.PreviewURL)
|
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) {
|
func TestMediaCreateTestSuite(t *testing.T) {
|
||||||
|
|
|
@ -31,6 +31,7 @@ import (
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/apimodule/account"
|
"github.com/superseriousbusiness/gotosocial/internal/apimodule/account"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/apimodule/app"
|
"github.com/superseriousbusiness/gotosocial/internal/apimodule/app"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/apimodule/auth"
|
"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/cache"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/config"
|
"github.com/superseriousbusiness/gotosocial/internal/config"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
"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)
|
return fmt.Errorf("error creating router: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
storageBackend, err := storage.NewInMem(c, log)
|
storageBackend, err := storage.NewLocal(c, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error creating storage backend: %s", err)
|
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)
|
authModule := auth.New(oauthServer, dbService, log)
|
||||||
accountModule := account.New(c, dbService, oauthServer, mediaHandler, mastoConverter, log)
|
accountModule := account.New(c, dbService, oauthServer, mediaHandler, mastoConverter, log)
|
||||||
appsModule := app.New(oauthServer, dbService, mastoConverter, log)
|
appsModule := app.New(oauthServer, dbService, mastoConverter, log)
|
||||||
|
mm := mediaModule.New(dbService, mediaHandler, mastoConverter, c, log)
|
||||||
|
|
||||||
apiModules := []apimodule.ClientAPIModule{
|
apiModules := []apimodule.ClientAPIModule{
|
||||||
authModule, // this one has to go first so the other modules use its middleware
|
authModule, // this one has to go first so the other modules use its middleware
|
||||||
accountModule,
|
accountModule,
|
||||||
appsModule,
|
appsModule,
|
||||||
|
mm,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, m := range apiModules {
|
for _, m := range apiModules {
|
||||||
|
|
|
@ -104,3 +104,45 @@ func (_m *MockConverter) AppToMastoSensitive(application *gtsmodel.Application)
|
||||||
|
|
||||||
return r0, r1
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -12,6 +12,29 @@ type MockMediaHandler struct {
|
||||||
mock.Mock
|
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
|
// SetHeaderOrAvatarForAccountID provides a mock function with given fields: img, accountID, headerOrAvi
|
||||||
func (_m *MockMediaHandler) SetHeaderOrAvatarForAccountID(img []byte, accountID string, headerOrAvi string) (*gtsmodel.MediaAttachment, error) {
|
func (_m *MockMediaHandler) SetHeaderOrAvatarForAccountID(img []byte, accountID string, headerOrAvi string) (*gtsmodel.MediaAttachment, error) {
|
||||||
ret := _m.Called(img, accountID, headerOrAvi)
|
ret := _m.Called(img, accountID, headerOrAvi)
|
||||||
|
|
|
@ -15,22 +15,41 @@ import (
|
||||||
func NewInMem(c *config.Config, log *logrus.Logger) (Storage, error) {
|
func NewInMem(c *config.Config, log *logrus.Logger) (Storage, error) {
|
||||||
return &inMemStorage{
|
return &inMemStorage{
|
||||||
stored: make(map[string][]byte),
|
stored: make(map[string][]byte),
|
||||||
|
log: log,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type inMemStorage struct {
|
type inMemStorage struct {
|
||||||
stored map[string][]byte
|
stored map[string][]byte
|
||||||
|
log *logrus.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *inMemStorage) StoreFileAt(path string, data []byte) error {
|
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
|
s.stored[path] = data
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *inMemStorage) RetrieveFileFrom(path string) ([]byte, error) {
|
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]
|
d, ok := s.stored[path]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("no data found at path %s", path)
|
return nil, fmt.Errorf("no data found at path %s", path)
|
||||||
}
|
}
|
||||||
return d, nil
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
package storage
|
package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/config"
|
"github.com/superseriousbusiness/gotosocial/internal/config"
|
||||||
)
|
)
|
||||||
|
@ -8,16 +13,58 @@ import (
|
||||||
// NewLocal returns an implementation of the Storage interface that uses
|
// NewLocal returns an implementation of the Storage interface that uses
|
||||||
// the local filesystem for storing and retrieving files, attachments, etc.
|
// the local filesystem for storing and retrieving files, attachments, etc.
|
||||||
func NewLocal(c *config.Config, log *logrus.Logger) (Storage, error) {
|
func NewLocal(c *config.Config, log *logrus.Logger) (Storage, error) {
|
||||||
return &localStorage{}, nil
|
return &localStorage{
|
||||||
|
config: c,
|
||||||
|
log: log,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type localStorage struct {
|
type localStorage struct {
|
||||||
|
config *config.Config
|
||||||
|
log *logrus.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *localStorage) StoreFileAt(path string, data []byte) error {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *localStorage) RetrieveFileFrom(path string) ([]byte, error) {
|
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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,43 @@ type MockStorage struct {
|
||||||
mock.Mock
|
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
|
// RetrieveFileFrom provides a mock function with given fields: path
|
||||||
func (_m *MockStorage) RetrieveFileFrom(path string) ([]byte, error) {
|
func (_m *MockStorage) RetrieveFileFrom(path string) ([]byte, error) {
|
||||||
ret := _m.Called(path)
|
ret := _m.Called(path)
|
||||||
|
|
|
@ -25,4 +25,6 @@ package storage
|
||||||
type Storage interface {
|
type Storage interface {
|
||||||
StoreFileAt(path string, data []byte) error
|
StoreFileAt(path string, data []byte) error
|
||||||
RetrieveFileFrom(path string) ([]byte, error)
|
RetrieveFileFrom(path string) ([]byte, error)
|
||||||
|
ListKeys() ([]string, error)
|
||||||
|
RemoveFileAt(path string) error
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
package testrig
|
package testrig
|
||||||
|
|
||||||
import "github.com/superseriousbusiness/gotosocial/internal/config"
|
import "github.com/superseriousbusiness/gotosocial/internal/config"
|
||||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
package testrig
|
package testrig
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
28
testrig/log.go
Normal file
28
testrig/log.go
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
29
testrig/mastoconverter.go
Normal file
29
testrig/mastoconverter.go
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
BIN
testrig/media/welcome-original.jpeg
Executable file
BIN
testrig/media/welcome-original.jpeg
Executable file
Binary file not shown.
After Width: | Height: | Size: 61 KiB |
BIN
testrig/media/welcome-small.jpeg
Executable file
BIN
testrig/media/welcome-small.jpeg
Executable file
Binary file not shown.
After Width: | Height: | Size: 6.7 KiB |
31
testrig/mediahandler.go
Normal file
31
testrig/mediahandler.go
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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())
|
||||||
|
}
|
29
testrig/oauthserver.go
Normal file
29
testrig/oauthserver.go
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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())
|
||||||
|
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
package testrig
|
package testrig
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/sirupsen/logrus"
|
"fmt"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/config"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/storage"
|
"github.com/superseriousbusiness/gotosocial/internal/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewTestStorage returns a new in memory storage with the given config
|
// NewTestStorage returns a new in memory storage with the default test config
|
||||||
func NewTestStorage(c *config.Config, log *logrus.Logger) storage.Storage {
|
func NewTestStorage() storage.Storage {
|
||||||
s, err := storage.NewInMem(c, log)
|
s, err := storage.NewInMem(NewTestConfig(), NewTestLog())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return s
|
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) {
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
package testrig
|
package testrig
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -10,6 +28,7 @@ import (
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/oauth"
|
"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 {
|
func NewTestTokens() map[string]*oauth.Token {
|
||||||
tokens := map[string]*oauth.Token{
|
tokens := map[string]*oauth.Token{
|
||||||
"local_account_1": {
|
"local_account_1": {
|
||||||
|
@ -26,6 +45,7 @@ func NewTestTokens() map[string]*oauth.Token {
|
||||||
return tokens
|
return tokens
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewTestClients returns a map of Clients keyed according to which account they are used by.
|
||||||
func NewTestClients() map[string]*oauth.Client {
|
func NewTestClients() map[string]*oauth.Client {
|
||||||
clients := map[string]*oauth.Client{
|
clients := map[string]*oauth.Client{
|
||||||
"local_account_1": {
|
"local_account_1": {
|
||||||
|
@ -38,6 +58,7 @@ func NewTestClients() map[string]*oauth.Client {
|
||||||
return clients
|
return clients
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewTestApplications returns a map of applications keyed to which number application they are.
|
||||||
func NewTestApplications() map[string]*gtsmodel.Application {
|
func NewTestApplications() map[string]*gtsmodel.Application {
|
||||||
apps := map[string]*gtsmodel.Application{
|
apps := map[string]*gtsmodel.Application{
|
||||||
"application_1": {
|
"application_1": {
|
||||||
|
@ -54,6 +75,7 @@ func NewTestApplications() map[string]*gtsmodel.Application {
|
||||||
return apps
|
return apps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewTestUsers returns a map of Users keyed by which account belongs to them.
|
||||||
func NewTestUsers() map[string]*gtsmodel.User {
|
func NewTestUsers() map[string]*gtsmodel.User {
|
||||||
users := map[string]*gtsmodel.User{
|
users := map[string]*gtsmodel.User{
|
||||||
"unconfirmed_account": {
|
"unconfirmed_account": {
|
||||||
|
@ -181,6 +203,7 @@ func NewTestUsers() map[string]*gtsmodel.User {
|
||||||
return users
|
return users
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewTestAccounts returns a map of accounts keyed by what type of account they are.
|
||||||
func NewTestAccounts() map[string]*gtsmodel.Account {
|
func NewTestAccounts() map[string]*gtsmodel.Account {
|
||||||
accounts := map[string]*gtsmodel.Account{
|
accounts := map[string]*gtsmodel.Account{
|
||||||
"unconfirmed_account": {
|
"unconfirmed_account": {
|
||||||
|
@ -440,14 +463,66 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
|
||||||
return accounts
|
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 {
|
func NewTestAttachments() map[string]*gtsmodel.MediaAttachment {
|
||||||
return 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 {
|
func NewTestStatuses() map[string]*gtsmodel.Status {
|
||||||
return map[string]*gtsmodel.Status{
|
return map[string]*gtsmodel.Status{
|
||||||
"admin_account_status_1": {
|
"admin_account_status_1": {
|
Loading…
Reference in New Issue
Block a user