gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

getfile_test.go (7522B)


      1 // GoToSocial
      2 // Copyright (C) GoToSocial Authors admin@gotosocial.org
      3 // SPDX-License-Identifier: AGPL-3.0-or-later
      4 //
      5 // This program is free software: you can redistribute it and/or modify
      6 // it under the terms of the GNU Affero General Public License as published by
      7 // the Free Software Foundation, either version 3 of the License, or
      8 // (at your option) any later version.
      9 //
     10 // This program is distributed in the hope that it will be useful,
     11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 // GNU Affero General Public License for more details.
     14 //
     15 // You should have received a copy of the GNU Affero General Public License
     16 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17 
     18 package media_test
     19 
     20 import (
     21 	"bytes"
     22 	"context"
     23 	"io"
     24 	"path"
     25 	"testing"
     26 
     27 	"github.com/stretchr/testify/suite"
     28 	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
     29 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
     30 	"github.com/superseriousbusiness/gotosocial/internal/media"
     31 	"github.com/superseriousbusiness/gotosocial/testrig"
     32 )
     33 
     34 type GetFileTestSuite struct {
     35 	MediaStandardTestSuite
     36 }
     37 
     38 func (suite *GetFileTestSuite) TestGetRemoteFileCached() {
     39 	ctx := context.Background()
     40 
     41 	testAttachment := suite.testAttachments["remote_account_1_status_1_attachment_1"]
     42 	fileName := path.Base(testAttachment.File.Path)
     43 	requestingAccount := suite.testAccounts["local_account_1"]
     44 
     45 	content, errWithCode := suite.mediaProcessor.GetFile(ctx, requestingAccount, &apimodel.GetContentRequestForm{
     46 		AccountID: testAttachment.AccountID,
     47 		MediaType: string(media.TypeAttachment),
     48 		MediaSize: string(media.SizeOriginal),
     49 		FileName:  fileName,
     50 	})
     51 
     52 	suite.NoError(errWithCode)
     53 	suite.NotNil(content)
     54 	b, err := io.ReadAll(content.Content)
     55 	suite.NoError(err)
     56 
     57 	if closer, ok := content.Content.(io.Closer); ok {
     58 		suite.NoError(closer.Close())
     59 	}
     60 
     61 	suite.Equal(suite.testRemoteAttachments[testAttachment.RemoteURL].Data, b)
     62 	suite.Equal(suite.testRemoteAttachments[testAttachment.RemoteURL].ContentType, content.ContentType)
     63 	suite.EqualValues(len(suite.testRemoteAttachments[testAttachment.RemoteURL].Data), content.ContentLength)
     64 }
     65 
     66 func (suite *GetFileTestSuite) TestGetRemoteFileUncached() {
     67 	ctx := context.Background()
     68 
     69 	// uncache the file from local
     70 	testAttachment := suite.testAttachments["remote_account_1_status_1_attachment_1"]
     71 	testAttachment.Cached = testrig.FalseBool()
     72 	err := suite.db.UpdateByID(ctx, testAttachment, testAttachment.ID, "cached")
     73 	suite.NoError(err)
     74 	err = suite.storage.Delete(ctx, testAttachment.File.Path)
     75 	suite.NoError(err)
     76 	err = suite.storage.Delete(ctx, testAttachment.Thumbnail.Path)
     77 	suite.NoError(err)
     78 
     79 	// now fetch it
     80 	fileName := path.Base(testAttachment.File.Path)
     81 	requestingAccount := suite.testAccounts["local_account_1"]
     82 
     83 	content, errWithCode := suite.mediaProcessor.GetFile(ctx, requestingAccount, &apimodel.GetContentRequestForm{
     84 		AccountID: testAttachment.AccountID,
     85 		MediaType: string(media.TypeAttachment),
     86 		MediaSize: string(media.SizeOriginal),
     87 		FileName:  fileName,
     88 	})
     89 
     90 	suite.NoError(errWithCode)
     91 	suite.NotNil(content)
     92 	b, err := io.ReadAll(content.Content)
     93 	suite.NoError(err)
     94 	suite.NoError(content.Content.Close())
     95 
     96 	suite.Equal(suite.testRemoteAttachments[testAttachment.RemoteURL].Data, b)
     97 	suite.Equal(suite.testRemoteAttachments[testAttachment.RemoteURL].ContentType, content.ContentType)
     98 	suite.EqualValues(len(suite.testRemoteAttachments[testAttachment.RemoteURL].Data), content.ContentLength)
     99 
    100 	// the attachment should be updated in the database
    101 	var dbAttachment *gtsmodel.MediaAttachment
    102 	if !testrig.WaitFor(func() bool {
    103 		dbAttachment, err = suite.db.GetAttachmentByID(ctx, testAttachment.ID)
    104 		return dbAttachment != nil
    105 	}) {
    106 		suite.FailNow("timed out waiting for updated attachment")
    107 	}
    108 
    109 	suite.NoError(err)
    110 	suite.True(*dbAttachment.Cached)
    111 
    112 	// the file should be back in storage at the same path as before
    113 	refreshedBytes, err := suite.storage.Get(ctx, testAttachment.File.Path)
    114 	suite.NoError(err)
    115 	suite.Equal(suite.testRemoteAttachments[testAttachment.RemoteURL].Data, refreshedBytes)
    116 }
    117 
    118 func (suite *GetFileTestSuite) TestGetRemoteFileUncachedInterrupted() {
    119 	ctx := context.Background()
    120 
    121 	// uncache the file from local
    122 	testAttachment := suite.testAttachments["remote_account_1_status_1_attachment_1"]
    123 	testAttachment.Cached = testrig.FalseBool()
    124 	err := suite.db.UpdateByID(ctx, testAttachment, testAttachment.ID, "cached")
    125 	suite.NoError(err)
    126 	err = suite.storage.Delete(ctx, testAttachment.File.Path)
    127 	suite.NoError(err)
    128 	err = suite.storage.Delete(ctx, testAttachment.Thumbnail.Path)
    129 	suite.NoError(err)
    130 
    131 	// now fetch it
    132 	fileName := path.Base(testAttachment.File.Path)
    133 	requestingAccount := suite.testAccounts["local_account_1"]
    134 
    135 	content, errWithCode := suite.mediaProcessor.GetFile(ctx, requestingAccount, &apimodel.GetContentRequestForm{
    136 		AccountID: testAttachment.AccountID,
    137 		MediaType: string(media.TypeAttachment),
    138 		MediaSize: string(media.SizeOriginal),
    139 		FileName:  fileName,
    140 	})
    141 
    142 	suite.NoError(errWithCode)
    143 	suite.NotNil(content)
    144 
    145 	// only read the first kilobyte and then stop
    146 	b := make([]byte, 0, 1024)
    147 	if !testrig.WaitFor(func() bool {
    148 		read, err := io.CopyN(bytes.NewBuffer(b), content.Content, 1024)
    149 		return err == nil && read == 1024
    150 	}) {
    151 		suite.FailNow("timed out trying to read first 1024 bytes")
    152 	}
    153 
    154 	// close the reader
    155 	suite.NoError(content.Content.Close())
    156 
    157 	// the attachment should still be updated in the database even though the caller hung up
    158 	if !testrig.WaitFor(func() bool {
    159 		dbAttachment, _ := suite.db.GetAttachmentByID(ctx, testAttachment.ID)
    160 		return *dbAttachment.Cached
    161 	}) {
    162 		suite.FailNow("timed out waiting for attachment to be updated")
    163 	}
    164 
    165 	// the file should be back in storage at the same path as before
    166 	refreshedBytes, err := suite.storage.Get(ctx, testAttachment.File.Path)
    167 	suite.NoError(err)
    168 	suite.Equal(suite.testRemoteAttachments[testAttachment.RemoteURL].Data, refreshedBytes)
    169 }
    170 
    171 func (suite *GetFileTestSuite) TestGetRemoteFileThumbnailUncached() {
    172 	ctx := context.Background()
    173 	testAttachment := suite.testAttachments["remote_account_1_status_1_attachment_1"]
    174 
    175 	// fetch the existing thumbnail bytes from storage first
    176 	thumbnailBytes, err := suite.storage.Get(ctx, testAttachment.Thumbnail.Path)
    177 	suite.NoError(err)
    178 
    179 	// uncache the file from local
    180 	testAttachment.Cached = testrig.FalseBool()
    181 	err = suite.db.UpdateByID(ctx, testAttachment, testAttachment.ID, "cached")
    182 	suite.NoError(err)
    183 	err = suite.storage.Delete(ctx, testAttachment.File.Path)
    184 	suite.NoError(err)
    185 	err = suite.storage.Delete(ctx, testAttachment.Thumbnail.Path)
    186 	suite.NoError(err)
    187 
    188 	// now fetch the thumbnail
    189 	fileName := path.Base(testAttachment.File.Path)
    190 	requestingAccount := suite.testAccounts["local_account_1"]
    191 
    192 	content, errWithCode := suite.mediaProcessor.GetFile(ctx, requestingAccount, &apimodel.GetContentRequestForm{
    193 		AccountID: testAttachment.AccountID,
    194 		MediaType: string(media.TypeAttachment),
    195 		MediaSize: string(media.SizeSmall),
    196 		FileName:  fileName,
    197 	})
    198 
    199 	suite.NoError(errWithCode)
    200 	suite.NotNil(content)
    201 	b, err := io.ReadAll(content.Content)
    202 	suite.NoError(err)
    203 	suite.NoError(content.Content.Close())
    204 
    205 	suite.Equal(thumbnailBytes, b)
    206 	suite.Equal("image/jpeg", content.ContentType)
    207 	suite.EqualValues(testAttachment.Thumbnail.FileSize, content.ContentLength)
    208 }
    209 
    210 func TestGetFileTestSuite(t *testing.T) {
    211 	suite.Run(t, &GetFileTestSuite{})
    212 }