gtsocial-umbx

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

servefile_test.go (8882B)


      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 fileserver_test
     19 
     20 import (
     21 	"context"
     22 	"io/ioutil"
     23 	"net/http"
     24 	"net/http/httptest"
     25 	"testing"
     26 
     27 	"github.com/stretchr/testify/suite"
     28 	"github.com/superseriousbusiness/gotosocial/internal/api/fileserver"
     29 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
     30 	"github.com/superseriousbusiness/gotosocial/internal/media"
     31 	"github.com/superseriousbusiness/gotosocial/testrig"
     32 )
     33 
     34 type ServeFileTestSuite struct {
     35 	FileserverTestSuite
     36 }
     37 
     38 // GetFile is just a convenience function to save repetition in this test suite.
     39 // It takes the required params to serve a file, calls the handler, and returns
     40 // the http status code, the response headers, and the parsed body bytes.
     41 func (suite *ServeFileTestSuite) GetFile(
     42 	accountID string,
     43 	mediaType media.Type,
     44 	mediaSize media.Size,
     45 	filename string,
     46 ) (code int, headers http.Header, body []byte) {
     47 	recorder := httptest.NewRecorder()
     48 
     49 	ctx, _ := testrig.CreateGinTestContext(recorder, nil)
     50 	ctx.Request = httptest.NewRequest(http.MethodGet, "http://localhost:8080/whatever", nil)
     51 	ctx.Request.Header.Set("accept", "*/*")
     52 	ctx.AddParam(fileserver.AccountIDKey, accountID)
     53 	ctx.AddParam(fileserver.MediaTypeKey, string(mediaType))
     54 	ctx.AddParam(fileserver.MediaSizeKey, string(mediaSize))
     55 	ctx.AddParam(fileserver.FileNameKey, filename)
     56 
     57 	suite.fileServer.ServeFile(ctx)
     58 	code = recorder.Code
     59 	headers = recorder.Result().Header
     60 
     61 	var err error
     62 	body, err = ioutil.ReadAll(recorder.Body)
     63 	if err != nil {
     64 		suite.FailNow(err.Error())
     65 	}
     66 
     67 	return
     68 }
     69 
     70 // UncacheAttachment is a convenience function that uncaches the targetAttachment by
     71 // removing its associated files from storage, and updating the database.
     72 func (suite *ServeFileTestSuite) UncacheAttachment(targetAttachment *gtsmodel.MediaAttachment) {
     73 	ctx := context.Background()
     74 
     75 	cached := false
     76 	targetAttachment.Cached = &cached
     77 
     78 	if err := suite.db.UpdateByID(ctx, targetAttachment, targetAttachment.ID, "cached"); err != nil {
     79 		suite.FailNow(err.Error())
     80 	}
     81 	if err := suite.storage.Delete(ctx, targetAttachment.File.Path); err != nil {
     82 		suite.FailNow(err.Error())
     83 	}
     84 	if err := suite.storage.Delete(ctx, targetAttachment.Thumbnail.Path); err != nil {
     85 		suite.FailNow(err.Error())
     86 	}
     87 }
     88 
     89 func (suite *ServeFileTestSuite) TestServeOriginalLocalFileOK() {
     90 	targetAttachment := &gtsmodel.MediaAttachment{}
     91 	*targetAttachment = *suite.testAttachments["admin_account_status_1_attachment_1"]
     92 	fileInStorage, err := suite.storage.Get(context.Background(), targetAttachment.File.Path)
     93 	if err != nil {
     94 		suite.FailNow(err.Error())
     95 	}
     96 
     97 	code, headers, body := suite.GetFile(
     98 		targetAttachment.AccountID,
     99 		media.TypeAttachment,
    100 		media.SizeOriginal,
    101 		targetAttachment.ID+".jpg",
    102 	)
    103 
    104 	suite.Equal(http.StatusOK, code)
    105 	suite.Equal("image/jpeg", headers.Get("content-type"))
    106 	suite.Equal(fileInStorage, body)
    107 }
    108 
    109 func (suite *ServeFileTestSuite) TestServeSmallLocalFileOK() {
    110 	targetAttachment := &gtsmodel.MediaAttachment{}
    111 	*targetAttachment = *suite.testAttachments["admin_account_status_1_attachment_1"]
    112 	fileInStorage, err := suite.storage.Get(context.Background(), targetAttachment.Thumbnail.Path)
    113 	if err != nil {
    114 		suite.FailNow(err.Error())
    115 	}
    116 
    117 	code, headers, body := suite.GetFile(
    118 		targetAttachment.AccountID,
    119 		media.TypeAttachment,
    120 		media.SizeSmall,
    121 		targetAttachment.ID+".jpg",
    122 	)
    123 
    124 	suite.Equal(http.StatusOK, code)
    125 	suite.Equal("image/jpeg", headers.Get("content-type"))
    126 	suite.Equal(fileInStorage, body)
    127 }
    128 
    129 func (suite *ServeFileTestSuite) TestServeOriginalRemoteFileOK() {
    130 	targetAttachment := &gtsmodel.MediaAttachment{}
    131 	*targetAttachment = *suite.testAttachments["remote_account_1_status_1_attachment_1"]
    132 	fileInStorage, err := suite.storage.Get(context.Background(), targetAttachment.File.Path)
    133 	if err != nil {
    134 		suite.FailNow(err.Error())
    135 	}
    136 
    137 	code, headers, body := suite.GetFile(
    138 		targetAttachment.AccountID,
    139 		media.TypeAttachment,
    140 		media.SizeOriginal,
    141 		targetAttachment.ID+".jpg",
    142 	)
    143 
    144 	suite.Equal(http.StatusOK, code)
    145 	suite.Equal("image/jpeg", headers.Get("content-type"))
    146 	suite.Equal(fileInStorage, body)
    147 }
    148 
    149 func (suite *ServeFileTestSuite) TestServeSmallRemoteFileOK() {
    150 	targetAttachment := &gtsmodel.MediaAttachment{}
    151 	*targetAttachment = *suite.testAttachments["remote_account_1_status_1_attachment_1"]
    152 	fileInStorage, err := suite.storage.Get(context.Background(), targetAttachment.Thumbnail.Path)
    153 	if err != nil {
    154 		suite.FailNow(err.Error())
    155 	}
    156 
    157 	code, headers, body := suite.GetFile(
    158 		targetAttachment.AccountID,
    159 		media.TypeAttachment,
    160 		media.SizeSmall,
    161 		targetAttachment.ID+".jpg",
    162 	)
    163 
    164 	suite.Equal(http.StatusOK, code)
    165 	suite.Equal("image/jpeg", headers.Get("content-type"))
    166 	suite.Equal(fileInStorage, body)
    167 }
    168 
    169 func (suite *ServeFileTestSuite) TestServeOriginalRemoteFileRecache() {
    170 	targetAttachment := &gtsmodel.MediaAttachment{}
    171 	*targetAttachment = *suite.testAttachments["remote_account_1_status_1_attachment_1"]
    172 	fileInStorage, err := suite.storage.Get(context.Background(), targetAttachment.File.Path)
    173 	if err != nil {
    174 		suite.FailNow(err.Error())
    175 	}
    176 
    177 	// uncache the attachment so we'll have to refetch it from the 'remote' instance
    178 	suite.UncacheAttachment(targetAttachment)
    179 
    180 	code, headers, body := suite.GetFile(
    181 		targetAttachment.AccountID,
    182 		media.TypeAttachment,
    183 		media.SizeOriginal,
    184 		targetAttachment.ID+".jpg",
    185 	)
    186 
    187 	suite.Equal(http.StatusOK, code)
    188 	suite.Equal("image/jpeg", headers.Get("content-type"))
    189 	suite.Equal(fileInStorage, body)
    190 }
    191 
    192 func (suite *ServeFileTestSuite) TestServeSmallRemoteFileRecache() {
    193 	targetAttachment := &gtsmodel.MediaAttachment{}
    194 	*targetAttachment = *suite.testAttachments["remote_account_1_status_1_attachment_1"]
    195 	fileInStorage, err := suite.storage.Get(context.Background(), targetAttachment.Thumbnail.Path)
    196 	if err != nil {
    197 		suite.FailNow(err.Error())
    198 	}
    199 
    200 	// uncache the attachment so we'll have to refetch it from the 'remote' instance
    201 	suite.UncacheAttachment(targetAttachment)
    202 
    203 	code, headers, body := suite.GetFile(
    204 		targetAttachment.AccountID,
    205 		media.TypeAttachment,
    206 		media.SizeSmall,
    207 		targetAttachment.ID+".jpg",
    208 	)
    209 
    210 	suite.Equal(http.StatusOK, code)
    211 	suite.Equal("image/jpeg", headers.Get("content-type"))
    212 	suite.Equal(fileInStorage, body)
    213 }
    214 
    215 func (suite *ServeFileTestSuite) TestServeOriginalRemoteFileRecacheNotFound() {
    216 	targetAttachment := &gtsmodel.MediaAttachment{}
    217 	*targetAttachment = *suite.testAttachments["remote_account_1_status_1_attachment_1"]
    218 
    219 	// uncache the attachment *and* set the remote URL to something that will return a 404
    220 	suite.UncacheAttachment(targetAttachment)
    221 	targetAttachment.RemoteURL = "http://nothing.at.this.url/weeeeeeeee"
    222 	if err := suite.db.UpdateByID(context.Background(), targetAttachment, targetAttachment.ID, "remote_url"); err != nil {
    223 		suite.FailNow(err.Error())
    224 	}
    225 
    226 	code, _, _ := suite.GetFile(
    227 		targetAttachment.AccountID,
    228 		media.TypeAttachment,
    229 		media.SizeOriginal,
    230 		targetAttachment.ID+".jpg",
    231 	)
    232 
    233 	suite.Equal(http.StatusNotFound, code)
    234 }
    235 
    236 func (suite *ServeFileTestSuite) TestServeSmallRemoteFileRecacheNotFound() {
    237 	targetAttachment := &gtsmodel.MediaAttachment{}
    238 	*targetAttachment = *suite.testAttachments["remote_account_1_status_1_attachment_1"]
    239 
    240 	// uncache the attachment *and* set the remote URL to something that will return a 404
    241 	suite.UncacheAttachment(targetAttachment)
    242 	targetAttachment.RemoteURL = "http://nothing.at.this.url/weeeeeeeee"
    243 	if err := suite.db.UpdateByID(context.Background(), targetAttachment, targetAttachment.ID, "remote_url"); err != nil {
    244 		suite.FailNow(err.Error())
    245 	}
    246 
    247 	code, _, _ := suite.GetFile(
    248 		targetAttachment.AccountID,
    249 		media.TypeAttachment,
    250 		media.SizeSmall,
    251 		targetAttachment.ID+".jpg",
    252 	)
    253 
    254 	suite.Equal(http.StatusNotFound, code)
    255 }
    256 
    257 // Callers trying to get some random-ass file that doesn't exist should just get a 404
    258 func (suite *ServeFileTestSuite) TestServeFileNotFound() {
    259 	code, _, _ := suite.GetFile(
    260 		"01GMMY4G9B0QEG0PQK5Q5JGJWZ",
    261 		media.TypeAttachment,
    262 		media.SizeOriginal,
    263 		"01GMMY68Y7E5DJ3CA3Y9SS8524.jpg",
    264 	)
    265 
    266 	suite.Equal(http.StatusNotFound, code)
    267 }
    268 
    269 func TestServeFileTestSuite(t *testing.T) {
    270 	suite.Run(t, new(ServeFileTestSuite))
    271 }