manager_test.go (45727B)
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 "fmt" 24 "io" 25 "os" 26 "path" 27 "testing" 28 "time" 29 30 "codeberg.org/gruf/go-store/v2/storage" 31 "github.com/stretchr/testify/suite" 32 gtsmodel "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" 33 "github.com/superseriousbusiness/gotosocial/internal/media" 34 "github.com/superseriousbusiness/gotosocial/internal/state" 35 gtsstorage "github.com/superseriousbusiness/gotosocial/internal/storage" 36 "github.com/superseriousbusiness/gotosocial/testrig" 37 ) 38 39 type ManagerTestSuite struct { 40 MediaStandardTestSuite 41 } 42 43 func (suite *ManagerTestSuite) TestEmojiProcessBlocking() { 44 ctx := context.Background() 45 46 data := func(_ context.Context) (io.ReadCloser, int64, error) { 47 // load bytes from a test image 48 b, err := os.ReadFile("./test/rainbow-original.png") 49 if err != nil { 50 panic(err) 51 } 52 return io.NopCloser(bytes.NewBuffer(b)), int64(len(b)), nil 53 } 54 55 emojiID := "01GDQ9G782X42BAMFASKP64343" 56 emojiURI := "http://localhost:8080/emoji/01GDQ9G782X42BAMFASKP64343" 57 58 processingEmoji, err := suite.manager.ProcessEmoji(ctx, data, "rainbow_test", emojiID, emojiURI, nil, false) 59 suite.NoError(err) 60 61 // do a blocking call to fetch the emoji 62 emoji, err := processingEmoji.LoadEmoji(ctx) 63 suite.NoError(err) 64 suite.NotNil(emoji) 65 66 // make sure it's got the stuff set on it that we expect 67 suite.Equal(emojiID, emoji.ID) 68 69 // file meta should be correctly derived from the image 70 suite.Equal("image/png", emoji.ImageContentType) 71 suite.Equal("image/png", emoji.ImageStaticContentType) 72 suite.Equal(36702, emoji.ImageFileSize) 73 74 // now make sure the emoji is in the database 75 dbEmoji, err := suite.db.GetEmojiByID(ctx, emojiID) 76 suite.NoError(err) 77 suite.NotNil(dbEmoji) 78 79 // make sure the processed emoji file is in storage 80 processedFullBytes, err := suite.storage.Get(ctx, emoji.ImagePath) 81 suite.NoError(err) 82 suite.NotEmpty(processedFullBytes) 83 84 // load the processed bytes from our test folder, to compare 85 processedFullBytesExpected, err := os.ReadFile("./test/rainbow-original.png") 86 suite.NoError(err) 87 suite.NotEmpty(processedFullBytesExpected) 88 89 // the bytes in storage should be what we expected 90 suite.Equal(processedFullBytesExpected, processedFullBytes) 91 92 // now do the same for the thumbnail and make sure it's what we expected 93 processedStaticBytes, err := suite.storage.Get(ctx, emoji.ImageStaticPath) 94 suite.NoError(err) 95 suite.NotEmpty(processedStaticBytes) 96 97 processedStaticBytesExpected, err := os.ReadFile("./test/rainbow-static.png") 98 suite.NoError(err) 99 suite.NotEmpty(processedStaticBytesExpected) 100 101 suite.Equal(processedStaticBytesExpected, processedStaticBytes) 102 } 103 104 func (suite *ManagerTestSuite) TestEmojiProcessBlockingRefresh() { 105 ctx := context.Background() 106 107 // we're going to 'refresh' the remote 'yell' emoji by changing the image url to the pixellated gts logo 108 originalEmoji := suite.testEmojis["yell"] 109 110 emojiToUpdate := >smodel.Emoji{} 111 *emojiToUpdate = *originalEmoji 112 newImageRemoteURL := "http://fossbros-anonymous.io/some/image/path.png" 113 114 oldEmojiImagePath := emojiToUpdate.ImagePath 115 oldEmojiImageStaticPath := emojiToUpdate.ImageStaticPath 116 117 data := func(_ context.Context) (io.ReadCloser, int64, error) { 118 b, err := os.ReadFile("./test/gts_pixellated-original.png") 119 if err != nil { 120 panic(err) 121 } 122 return io.NopCloser(bytes.NewBuffer(b)), int64(len(b)), nil 123 } 124 125 emojiID := emojiToUpdate.ID 126 emojiURI := emojiToUpdate.URI 127 128 processingEmoji, err := suite.manager.ProcessEmoji(ctx, data, "yell", emojiID, emojiURI, &media.AdditionalEmojiInfo{ 129 CreatedAt: &emojiToUpdate.CreatedAt, 130 Domain: &emojiToUpdate.Domain, 131 ImageRemoteURL: &newImageRemoteURL, 132 }, true) 133 suite.NoError(err) 134 135 // do a blocking call to fetch the emoji 136 emoji, err := processingEmoji.LoadEmoji(ctx) 137 suite.NoError(err) 138 suite.NotNil(emoji) 139 140 // make sure it's got the stuff set on it that we expect 141 suite.Equal(emojiID, emoji.ID) 142 143 // file meta should be correctly derived from the image 144 suite.Equal("image/png", emoji.ImageContentType) 145 suite.Equal("image/png", emoji.ImageStaticContentType) 146 suite.Equal(10296, emoji.ImageFileSize) 147 148 // now make sure the emoji is in the database 149 dbEmoji, err := suite.db.GetEmojiByID(ctx, emojiID) 150 suite.NoError(err) 151 suite.NotNil(dbEmoji) 152 153 // make sure the processed emoji file is in storage 154 processedFullBytes, err := suite.storage.Get(ctx, emoji.ImagePath) 155 suite.NoError(err) 156 suite.NotEmpty(processedFullBytes) 157 158 // load the processed bytes from our test folder, to compare 159 processedFullBytesExpected, err := os.ReadFile("./test/gts_pixellated-original.png") 160 suite.NoError(err) 161 suite.NotEmpty(processedFullBytesExpected) 162 163 // the bytes in storage should be what we expected 164 suite.Equal(processedFullBytesExpected, processedFullBytes) 165 166 // now do the same for the thumbnail and make sure it's what we expected 167 processedStaticBytes, err := suite.storage.Get(ctx, emoji.ImageStaticPath) 168 suite.NoError(err) 169 suite.NotEmpty(processedStaticBytes) 170 171 processedStaticBytesExpected, err := os.ReadFile("./test/gts_pixellated-static.png") 172 suite.NoError(err) 173 suite.NotEmpty(processedStaticBytesExpected) 174 175 suite.Equal(processedStaticBytesExpected, processedStaticBytes) 176 177 // most fields should be different on the emoji now from what they were before 178 suite.Equal(originalEmoji.ID, dbEmoji.ID) 179 suite.NotEqual(originalEmoji.ImageRemoteURL, dbEmoji.ImageRemoteURL) 180 suite.NotEqual(originalEmoji.ImageURL, dbEmoji.ImageURL) 181 suite.NotEqual(originalEmoji.ImageStaticURL, dbEmoji.ImageStaticURL) 182 suite.NotEqual(originalEmoji.ImageFileSize, dbEmoji.ImageFileSize) 183 suite.NotEqual(originalEmoji.ImageStaticFileSize, dbEmoji.ImageStaticFileSize) 184 suite.NotEqual(originalEmoji.ImagePath, dbEmoji.ImagePath) 185 suite.NotEqual(originalEmoji.ImageStaticPath, dbEmoji.ImageStaticPath) 186 suite.NotEqual(originalEmoji.ImageStaticPath, dbEmoji.ImageStaticPath) 187 suite.NotEqual(originalEmoji.UpdatedAt, dbEmoji.UpdatedAt) 188 suite.NotEqual(originalEmoji.ImageUpdatedAt, dbEmoji.ImageUpdatedAt) 189 190 // the old image files should no longer be in storage 191 _, err = suite.storage.Get(ctx, oldEmojiImagePath) 192 suite.ErrorIs(err, storage.ErrNotFound) 193 _, err = suite.storage.Get(ctx, oldEmojiImageStaticPath) 194 suite.ErrorIs(err, storage.ErrNotFound) 195 } 196 197 func (suite *ManagerTestSuite) TestEmojiProcessBlockingTooLarge() { 198 ctx := context.Background() 199 200 data := func(_ context.Context) (io.ReadCloser, int64, error) { 201 // load bytes from a test image 202 b, err := os.ReadFile("./test/big-panda.gif") 203 if err != nil { 204 panic(err) 205 } 206 return io.NopCloser(bytes.NewBuffer(b)), int64(len(b)), nil 207 } 208 209 emojiID := "01GDQ9G782X42BAMFASKP64343" 210 emojiURI := "http://localhost:8080/emoji/01GDQ9G782X42BAMFASKP64343" 211 212 processingEmoji, err := suite.manager.ProcessEmoji(ctx, data, "big_panda", emojiID, emojiURI, nil, false) 213 suite.NoError(err) 214 215 // do a blocking call to fetch the emoji 216 emoji, err := processingEmoji.LoadEmoji(ctx) 217 suite.EqualError(err, "given emoji size 630kiB greater than max allowed 50.0kiB") 218 suite.Nil(emoji) 219 } 220 221 func (suite *ManagerTestSuite) TestEmojiProcessBlockingTooLargeNoSizeGiven() { 222 ctx := context.Background() 223 224 data := func(_ context.Context) (io.ReadCloser, int64, error) { 225 // load bytes from a test image 226 b, err := os.ReadFile("./test/big-panda.gif") 227 if err != nil { 228 panic(err) 229 } 230 return io.NopCloser(bytes.NewBuffer(b)), -1, nil 231 } 232 233 emojiID := "01GDQ9G782X42BAMFASKP64343" 234 emojiURI := "http://localhost:8080/emoji/01GDQ9G782X42BAMFASKP64343" 235 236 processingEmoji, err := suite.manager.ProcessEmoji(ctx, data, "big_panda", emojiID, emojiURI, nil, false) 237 suite.NoError(err) 238 239 // do a blocking call to fetch the emoji 240 emoji, err := processingEmoji.LoadEmoji(ctx) 241 suite.EqualError(err, "calculated emoji size 630kiB greater than max allowed 50.0kiB") 242 suite.Nil(emoji) 243 } 244 245 func (suite *ManagerTestSuite) TestEmojiProcessBlockingNoFileSizeGiven() { 246 ctx := context.Background() 247 248 data := func(_ context.Context) (io.ReadCloser, int64, error) { 249 // load bytes from a test image 250 b, err := os.ReadFile("./test/rainbow-original.png") 251 if err != nil { 252 panic(err) 253 } 254 return io.NopCloser(bytes.NewBuffer(b)), -1, nil 255 } 256 257 emojiID := "01GDQ9G782X42BAMFASKP64343" 258 emojiURI := "http://localhost:8080/emoji/01GDQ9G782X42BAMFASKP64343" 259 260 // process the media with no additional info provided 261 processingEmoji, err := suite.manager.ProcessEmoji(ctx, data, "rainbow_test", emojiID, emojiURI, nil, false) 262 suite.NoError(err) 263 264 // do a blocking call to fetch the emoji 265 emoji, err := processingEmoji.LoadEmoji(ctx) 266 suite.NoError(err) 267 suite.NotNil(emoji) 268 269 // make sure it's got the stuff set on it that we expect 270 suite.Equal(emojiID, emoji.ID) 271 272 // file meta should be correctly derived from the image 273 suite.Equal("image/png", emoji.ImageContentType) 274 suite.Equal("image/png", emoji.ImageStaticContentType) 275 suite.Equal(36702, emoji.ImageFileSize) 276 277 // now make sure the emoji is in the database 278 dbEmoji, err := suite.db.GetEmojiByID(ctx, emojiID) 279 suite.NoError(err) 280 suite.NotNil(dbEmoji) 281 282 // make sure the processed emoji file is in storage 283 processedFullBytes, err := suite.storage.Get(ctx, emoji.ImagePath) 284 suite.NoError(err) 285 suite.NotEmpty(processedFullBytes) 286 287 // load the processed bytes from our test folder, to compare 288 processedFullBytesExpected, err := os.ReadFile("./test/rainbow-original.png") 289 suite.NoError(err) 290 suite.NotEmpty(processedFullBytesExpected) 291 292 // the bytes in storage should be what we expected 293 suite.Equal(processedFullBytesExpected, processedFullBytes) 294 295 // now do the same for the thumbnail and make sure it's what we expected 296 processedStaticBytes, err := suite.storage.Get(ctx, emoji.ImageStaticPath) 297 suite.NoError(err) 298 suite.NotEmpty(processedStaticBytes) 299 300 processedStaticBytesExpected, err := os.ReadFile("./test/rainbow-static.png") 301 suite.NoError(err) 302 suite.NotEmpty(processedStaticBytesExpected) 303 304 suite.Equal(processedStaticBytesExpected, processedStaticBytes) 305 } 306 307 func (suite *ManagerTestSuite) TestSimpleJpegProcessBlocking() { 308 ctx := context.Background() 309 310 data := func(_ context.Context) (io.ReadCloser, int64, error) { 311 // load bytes from a test image 312 b, err := os.ReadFile("./test/test-jpeg.jpg") 313 if err != nil { 314 panic(err) 315 } 316 return io.NopCloser(bytes.NewBuffer(b)), int64(len(b)), nil 317 } 318 319 accountID := "01FS1X72SK9ZPW0J1QQ68BD264" 320 321 // process the media with no additional info provided 322 processingMedia, err := suite.manager.ProcessMedia(ctx, data, accountID, nil) 323 suite.NoError(err) 324 // fetch the attachment id from the processing media 325 attachmentID := processingMedia.AttachmentID() 326 327 // do a blocking call to fetch the attachment 328 attachment, err := processingMedia.LoadAttachment(ctx) 329 suite.NoError(err) 330 suite.NotNil(attachment) 331 332 // make sure it's got the stuff set on it that we expect 333 // the attachment ID and accountID we expect 334 suite.Equal(attachmentID, attachment.ID) 335 suite.Equal(accountID, attachment.AccountID) 336 337 // file meta should be correctly derived from the image 338 suite.EqualValues(gtsmodel.Original{ 339 Width: 1920, Height: 1080, Size: 2073600, Aspect: 1.7777777777777777, 340 }, attachment.FileMeta.Original) 341 suite.EqualValues(gtsmodel.Small{ 342 Width: 512, Height: 288, Size: 147456, Aspect: 1.7777777777777777, 343 }, attachment.FileMeta.Small) 344 suite.Equal("image/jpeg", attachment.File.ContentType) 345 suite.Equal("image/jpeg", attachment.Thumbnail.ContentType) 346 suite.Equal(269739, attachment.File.FileSize) 347 suite.Equal("LiBzRk#6V[WF_NvzV@WY_3rqV@a$", attachment.Blurhash) 348 349 // now make sure the attachment is in the database 350 dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachmentID) 351 suite.NoError(err) 352 suite.NotNil(dbAttachment) 353 354 // make sure the processed file is in storage 355 processedFullBytes, err := suite.storage.Get(ctx, attachment.File.Path) 356 suite.NoError(err) 357 suite.NotEmpty(processedFullBytes) 358 359 // load the processed bytes from our test folder, to compare 360 processedFullBytesExpected, err := os.ReadFile("./test/test-jpeg-processed.jpg") 361 suite.NoError(err) 362 suite.NotEmpty(processedFullBytesExpected) 363 364 // the bytes in storage should be what we expected 365 suite.Equal(processedFullBytesExpected, processedFullBytes) 366 367 // now do the same for the thumbnail and make sure it's what we expected 368 processedThumbnailBytes, err := suite.storage.Get(ctx, attachment.Thumbnail.Path) 369 suite.NoError(err) 370 suite.NotEmpty(processedThumbnailBytes) 371 372 processedThumbnailBytesExpected, err := os.ReadFile("./test/test-jpeg-thumbnail.jpg") 373 suite.NoError(err) 374 suite.NotEmpty(processedThumbnailBytesExpected) 375 376 suite.Equal(processedThumbnailBytesExpected, processedThumbnailBytes) 377 } 378 379 func (suite *ManagerTestSuite) TestSlothVineProcessBlocking() { 380 ctx := context.Background() 381 382 data := func(_ context.Context) (io.ReadCloser, int64, error) { 383 // load bytes from a test video 384 b, err := os.ReadFile("./test/test-mp4-original.mp4") 385 if err != nil { 386 panic(err) 387 } 388 return io.NopCloser(bytes.NewBuffer(b)), int64(len(b)), nil 389 } 390 391 accountID := "01FS1X72SK9ZPW0J1QQ68BD264" 392 393 // process the media with no additional info provided 394 processingMedia, err := suite.manager.ProcessMedia(ctx, data, accountID, nil) 395 suite.NoError(err) 396 // fetch the attachment id from the processing media 397 attachmentID := processingMedia.AttachmentID() 398 399 // do a blocking call to fetch the attachment 400 attachment, err := processingMedia.LoadAttachment(ctx) 401 suite.NoError(err) 402 suite.NotNil(attachment) 403 404 // make sure it's got the stuff set on it that we expect 405 // the attachment ID and accountID we expect 406 suite.Equal(attachmentID, attachment.ID) 407 suite.Equal(accountID, attachment.AccountID) 408 409 // file meta should be correctly derived from the video 410 suite.Equal(338, attachment.FileMeta.Original.Width) 411 suite.Equal(240, attachment.FileMeta.Original.Height) 412 suite.Equal(81120, attachment.FileMeta.Original.Size) 413 suite.EqualValues(1.4083333, attachment.FileMeta.Original.Aspect) 414 suite.EqualValues(6.640907, *attachment.FileMeta.Original.Duration) 415 suite.EqualValues(29.000029, *attachment.FileMeta.Original.Framerate) 416 suite.EqualValues(0x59e74, *attachment.FileMeta.Original.Bitrate) 417 suite.EqualValues(gtsmodel.Small{ 418 Width: 338, Height: 240, Size: 81120, Aspect: 1.4083333333333334, 419 }, attachment.FileMeta.Small) 420 suite.Equal("video/mp4", attachment.File.ContentType) 421 suite.Equal("image/jpeg", attachment.Thumbnail.ContentType) 422 suite.Equal(312413, attachment.File.FileSize) 423 suite.Equal("L00000fQfQfQfQfQfQfQfQfQfQfQ", attachment.Blurhash) 424 425 // now make sure the attachment is in the database 426 dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachmentID) 427 suite.NoError(err) 428 suite.NotNil(dbAttachment) 429 430 // make sure the processed file is in storage 431 processedFullBytes, err := suite.storage.Get(ctx, attachment.File.Path) 432 suite.NoError(err) 433 suite.NotEmpty(processedFullBytes) 434 435 // load the processed bytes from our test folder, to compare 436 processedFullBytesExpected, err := os.ReadFile("./test/test-mp4-processed.mp4") 437 suite.NoError(err) 438 suite.NotEmpty(processedFullBytesExpected) 439 440 // the bytes in storage should be what we expected 441 suite.Equal(processedFullBytesExpected, processedFullBytes) 442 443 // now do the same for the thumbnail and make sure it's what we expected 444 processedThumbnailBytes, err := suite.storage.Get(ctx, attachment.Thumbnail.Path) 445 suite.NoError(err) 446 suite.NotEmpty(processedThumbnailBytes) 447 448 processedThumbnailBytesExpected, err := os.ReadFile("./test/test-mp4-thumbnail.jpg") 449 suite.NoError(err) 450 suite.NotEmpty(processedThumbnailBytesExpected) 451 452 suite.Equal(processedThumbnailBytesExpected, processedThumbnailBytes) 453 } 454 455 func (suite *ManagerTestSuite) TestLongerMp4ProcessBlocking() { 456 ctx := context.Background() 457 458 data := func(_ context.Context) (io.ReadCloser, int64, error) { 459 // load bytes from a test video 460 b, err := os.ReadFile("./test/longer-mp4-original.mp4") 461 if err != nil { 462 panic(err) 463 } 464 return io.NopCloser(bytes.NewBuffer(b)), int64(len(b)), nil 465 } 466 467 accountID := "01FS1X72SK9ZPW0J1QQ68BD264" 468 469 // process the media with no additional info provided 470 processingMedia, err := suite.manager.ProcessMedia(ctx, data, accountID, nil) 471 suite.NoError(err) 472 // fetch the attachment id from the processing media 473 attachmentID := processingMedia.AttachmentID() 474 475 // do a blocking call to fetch the attachment 476 attachment, err := processingMedia.LoadAttachment(ctx) 477 suite.NoError(err) 478 suite.NotNil(attachment) 479 480 // make sure it's got the stuff set on it that we expect 481 // the attachment ID and accountID we expect 482 suite.Equal(attachmentID, attachment.ID) 483 suite.Equal(accountID, attachment.AccountID) 484 485 // file meta should be correctly derived from the video 486 suite.Equal(600, attachment.FileMeta.Original.Width) 487 suite.Equal(330, attachment.FileMeta.Original.Height) 488 suite.Equal(198000, attachment.FileMeta.Original.Size) 489 suite.EqualValues(1.8181819, attachment.FileMeta.Original.Aspect) 490 suite.EqualValues(16.6, *attachment.FileMeta.Original.Duration) 491 suite.EqualValues(10, *attachment.FileMeta.Original.Framerate) 492 suite.EqualValues(0xc8fb, *attachment.FileMeta.Original.Bitrate) 493 suite.EqualValues(gtsmodel.Small{ 494 Width: 512, Height: 281, Size: 143872, Aspect: 1.822064, 495 }, attachment.FileMeta.Small) 496 suite.Equal("video/mp4", attachment.File.ContentType) 497 suite.Equal("image/jpeg", attachment.Thumbnail.ContentType) 498 suite.Equal(109549, attachment.File.FileSize) 499 suite.Equal("L00000fQfQfQfQfQfQfQfQfQfQfQ", attachment.Blurhash) 500 501 // now make sure the attachment is in the database 502 dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachmentID) 503 suite.NoError(err) 504 suite.NotNil(dbAttachment) 505 506 // make sure the processed file is in storage 507 processedFullBytes, err := suite.storage.Get(ctx, attachment.File.Path) 508 suite.NoError(err) 509 suite.NotEmpty(processedFullBytes) 510 511 // load the processed bytes from our test folder, to compare 512 processedFullBytesExpected, err := os.ReadFile("./test/longer-mp4-processed.mp4") 513 suite.NoError(err) 514 suite.NotEmpty(processedFullBytesExpected) 515 516 // the bytes in storage should be what we expected 517 suite.Equal(processedFullBytesExpected, processedFullBytes) 518 519 // now do the same for the thumbnail and make sure it's what we expected 520 processedThumbnailBytes, err := suite.storage.Get(ctx, attachment.Thumbnail.Path) 521 suite.NoError(err) 522 suite.NotEmpty(processedThumbnailBytes) 523 524 processedThumbnailBytesExpected, err := os.ReadFile("./test/longer-mp4-thumbnail.jpg") 525 suite.NoError(err) 526 suite.NotEmpty(processedThumbnailBytesExpected) 527 528 suite.Equal(processedThumbnailBytesExpected, processedThumbnailBytes) 529 } 530 531 func (suite *ManagerTestSuite) TestBirdnestMp4ProcessBlocking() { 532 ctx := context.Background() 533 534 data := func(_ context.Context) (io.ReadCloser, int64, error) { 535 // load bytes from a test video 536 b, err := os.ReadFile("./test/birdnest-original.mp4") 537 if err != nil { 538 panic(err) 539 } 540 return io.NopCloser(bytes.NewBuffer(b)), int64(len(b)), nil 541 } 542 543 accountID := "01FS1X72SK9ZPW0J1QQ68BD264" 544 545 // process the media with no additional info provided 546 processingMedia, err := suite.manager.ProcessMedia(ctx, data, accountID, nil) 547 suite.NoError(err) 548 // fetch the attachment id from the processing media 549 attachmentID := processingMedia.AttachmentID() 550 551 // do a blocking call to fetch the attachment 552 attachment, err := processingMedia.LoadAttachment(ctx) 553 suite.NoError(err) 554 suite.NotNil(attachment) 555 556 // make sure it's got the stuff set on it that we expect 557 // the attachment ID and accountID we expect 558 suite.Equal(attachmentID, attachment.ID) 559 suite.Equal(accountID, attachment.AccountID) 560 561 // file meta should be correctly derived from the video 562 suite.Equal(404, attachment.FileMeta.Original.Width) 563 suite.Equal(720, attachment.FileMeta.Original.Height) 564 suite.Equal(290880, attachment.FileMeta.Original.Size) 565 suite.EqualValues(0.5611111, attachment.FileMeta.Original.Aspect) 566 suite.EqualValues(9.822041, *attachment.FileMeta.Original.Duration) 567 suite.EqualValues(30, *attachment.FileMeta.Original.Framerate) 568 suite.EqualValues(0x117c79, *attachment.FileMeta.Original.Bitrate) 569 suite.EqualValues(gtsmodel.Small{ 570 Width: 287, Height: 512, Size: 146944, Aspect: 0.5605469, 571 }, attachment.FileMeta.Small) 572 suite.Equal("video/mp4", attachment.File.ContentType) 573 suite.Equal("image/jpeg", attachment.Thumbnail.ContentType) 574 suite.Equal(1409577, attachment.File.FileSize) 575 suite.Equal("L00000fQfQfQfQfQfQfQfQfQfQfQ", attachment.Blurhash) 576 577 // now make sure the attachment is in the database 578 dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachmentID) 579 suite.NoError(err) 580 suite.NotNil(dbAttachment) 581 582 // make sure the processed file is in storage 583 processedFullBytes, err := suite.storage.Get(ctx, attachment.File.Path) 584 suite.NoError(err) 585 suite.NotEmpty(processedFullBytes) 586 587 // load the processed bytes from our test folder, to compare 588 processedFullBytesExpected, err := os.ReadFile("./test/birdnest-processed.mp4") 589 suite.NoError(err) 590 suite.NotEmpty(processedFullBytesExpected) 591 592 // the bytes in storage should be what we expected 593 suite.Equal(processedFullBytesExpected, processedFullBytes) 594 595 // now do the same for the thumbnail and make sure it's what we expected 596 processedThumbnailBytes, err := suite.storage.Get(ctx, attachment.Thumbnail.Path) 597 suite.NoError(err) 598 suite.NotEmpty(processedThumbnailBytes) 599 600 processedThumbnailBytesExpected, err := os.ReadFile("./test/birdnest-thumbnail.jpg") 601 suite.NoError(err) 602 suite.NotEmpty(processedThumbnailBytesExpected) 603 604 suite.Equal(processedThumbnailBytesExpected, processedThumbnailBytes) 605 } 606 607 func (suite *ManagerTestSuite) TestNotAnMp4ProcessBlocking() { 608 // try to load an 'mp4' that's actually an mkv in disguise 609 610 ctx := context.Background() 611 612 data := func(_ context.Context) (io.ReadCloser, int64, error) { 613 // load bytes from a test video 614 b, err := os.ReadFile("./test/not-an.mp4") 615 if err != nil { 616 panic(err) 617 } 618 return io.NopCloser(bytes.NewBuffer(b)), int64(len(b)), nil 619 } 620 621 accountID := "01FS1X72SK9ZPW0J1QQ68BD264" 622 623 // pre processing should go fine but... 624 processingMedia, err := suite.manager.ProcessMedia(ctx, data, accountID, nil) 625 suite.NoError(err) 626 627 // we should get an error while loading 628 attachment, err := processingMedia.LoadAttachment(ctx) 629 suite.EqualError(err, "error decoding video: error determining video metadata: [width height framerate]") 630 suite.Nil(attachment) 631 } 632 633 func (suite *ManagerTestSuite) TestSimpleJpegProcessBlockingNoContentLengthGiven() { 634 ctx := context.Background() 635 636 data := func(_ context.Context) (io.ReadCloser, int64, error) { 637 // load bytes from a test image 638 b, err := os.ReadFile("./test/test-jpeg.jpg") 639 if err != nil { 640 panic(err) 641 } 642 // give length as -1 to indicate unknown 643 return io.NopCloser(bytes.NewBuffer(b)), -1, nil 644 } 645 646 accountID := "01FS1X72SK9ZPW0J1QQ68BD264" 647 648 // process the media with no additional info provided 649 processingMedia, err := suite.manager.ProcessMedia(ctx, data, accountID, nil) 650 suite.NoError(err) 651 // fetch the attachment id from the processing media 652 attachmentID := processingMedia.AttachmentID() 653 654 // do a blocking call to fetch the attachment 655 attachment, err := processingMedia.LoadAttachment(ctx) 656 suite.NoError(err) 657 suite.NotNil(attachment) 658 659 // make sure it's got the stuff set on it that we expect 660 // the attachment ID and accountID we expect 661 suite.Equal(attachmentID, attachment.ID) 662 suite.Equal(accountID, attachment.AccountID) 663 664 // file meta should be correctly derived from the image 665 suite.EqualValues(gtsmodel.Original{ 666 Width: 1920, Height: 1080, Size: 2073600, Aspect: 1.7777777777777777, 667 }, attachment.FileMeta.Original) 668 suite.EqualValues(gtsmodel.Small{ 669 Width: 512, Height: 288, Size: 147456, Aspect: 1.7777777777777777, 670 }, attachment.FileMeta.Small) 671 suite.Equal("image/jpeg", attachment.File.ContentType) 672 suite.Equal("image/jpeg", attachment.Thumbnail.ContentType) 673 suite.Equal(269739, attachment.File.FileSize) 674 suite.Equal("LiBzRk#6V[WF_NvzV@WY_3rqV@a$", attachment.Blurhash) 675 676 // now make sure the attachment is in the database 677 dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachmentID) 678 suite.NoError(err) 679 suite.NotNil(dbAttachment) 680 681 // make sure the processed file is in storage 682 processedFullBytes, err := suite.storage.Get(ctx, attachment.File.Path) 683 suite.NoError(err) 684 suite.NotEmpty(processedFullBytes) 685 686 // load the processed bytes from our test folder, to compare 687 processedFullBytesExpected, err := os.ReadFile("./test/test-jpeg-processed.jpg") 688 suite.NoError(err) 689 suite.NotEmpty(processedFullBytesExpected) 690 691 // the bytes in storage should be what we expected 692 suite.Equal(processedFullBytesExpected, processedFullBytes) 693 694 // now do the same for the thumbnail and make sure it's what we expected 695 processedThumbnailBytes, err := suite.storage.Get(ctx, attachment.Thumbnail.Path) 696 suite.NoError(err) 697 suite.NotEmpty(processedThumbnailBytes) 698 699 processedThumbnailBytesExpected, err := os.ReadFile("./test/test-jpeg-thumbnail.jpg") 700 suite.NoError(err) 701 suite.NotEmpty(processedThumbnailBytesExpected) 702 703 suite.Equal(processedThumbnailBytesExpected, processedThumbnailBytes) 704 } 705 706 func (suite *ManagerTestSuite) TestSimpleJpegProcessBlockingReadCloser() { 707 ctx := context.Background() 708 709 data := func(_ context.Context) (io.ReadCloser, int64, error) { 710 // open test image as a file 711 f, err := os.Open("./test/test-jpeg.jpg") 712 if err != nil { 713 panic(err) 714 } 715 // give length as -1 to indicate unknown 716 return f, -1, nil 717 } 718 719 accountID := "01FS1X72SK9ZPW0J1QQ68BD264" 720 721 // process the media with no additional info provided 722 processingMedia, err := suite.manager.ProcessMedia(ctx, data, accountID, nil) 723 suite.NoError(err) 724 // fetch the attachment id from the processing media 725 attachmentID := processingMedia.AttachmentID() 726 727 // do a blocking call to fetch the attachment 728 attachment, err := processingMedia.LoadAttachment(ctx) 729 suite.NoError(err) 730 suite.NotNil(attachment) 731 732 // make sure it's got the stuff set on it that we expect 733 // the attachment ID and accountID we expect 734 suite.Equal(attachmentID, attachment.ID) 735 suite.Equal(accountID, attachment.AccountID) 736 737 // file meta should be correctly derived from the image 738 suite.EqualValues(gtsmodel.Original{ 739 Width: 1920, Height: 1080, Size: 2073600, Aspect: 1.7777777777777777, 740 }, attachment.FileMeta.Original) 741 suite.EqualValues(gtsmodel.Small{ 742 Width: 512, Height: 288, Size: 147456, Aspect: 1.7777777777777777, 743 }, attachment.FileMeta.Small) 744 suite.Equal("image/jpeg", attachment.File.ContentType) 745 suite.Equal("image/jpeg", attachment.Thumbnail.ContentType) 746 suite.Equal(269739, attachment.File.FileSize) 747 suite.Equal("LiBzRk#6V[WF_NvzV@WY_3rqV@a$", attachment.Blurhash) 748 749 // now make sure the attachment is in the database 750 dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachmentID) 751 suite.NoError(err) 752 suite.NotNil(dbAttachment) 753 754 // make sure the processed file is in storage 755 processedFullBytes, err := suite.storage.Get(ctx, attachment.File.Path) 756 suite.NoError(err) 757 suite.NotEmpty(processedFullBytes) 758 759 // load the processed bytes from our test folder, to compare 760 processedFullBytesExpected, err := os.ReadFile("./test/test-jpeg-processed.jpg") 761 suite.NoError(err) 762 suite.NotEmpty(processedFullBytesExpected) 763 764 // the bytes in storage should be what we expected 765 suite.Equal(processedFullBytesExpected, processedFullBytes) 766 767 // now do the same for the thumbnail and make sure it's what we expected 768 processedThumbnailBytes, err := suite.storage.Get(ctx, attachment.Thumbnail.Path) 769 suite.NoError(err) 770 suite.NotEmpty(processedThumbnailBytes) 771 772 processedThumbnailBytesExpected, err := os.ReadFile("./test/test-jpeg-thumbnail.jpg") 773 suite.NoError(err) 774 suite.NotEmpty(processedThumbnailBytesExpected) 775 776 suite.Equal(processedThumbnailBytesExpected, processedThumbnailBytes) 777 } 778 779 func (suite *ManagerTestSuite) TestPngNoAlphaChannelProcessBlocking() { 780 ctx := context.Background() 781 782 data := func(_ context.Context) (io.ReadCloser, int64, error) { 783 // load bytes from a test image 784 b, err := os.ReadFile("./test/test-png-noalphachannel.png") 785 if err != nil { 786 panic(err) 787 } 788 return io.NopCloser(bytes.NewBuffer(b)), int64(len(b)), nil 789 } 790 791 accountID := "01FS1X72SK9ZPW0J1QQ68BD264" 792 793 // process the media with no additional info provided 794 processingMedia, err := suite.manager.ProcessMedia(ctx, data, accountID, nil) 795 suite.NoError(err) 796 // fetch the attachment id from the processing media 797 attachmentID := processingMedia.AttachmentID() 798 799 // do a blocking call to fetch the attachment 800 attachment, err := processingMedia.LoadAttachment(ctx) 801 suite.NoError(err) 802 suite.NotNil(attachment) 803 804 // make sure it's got the stuff set on it that we expect 805 // the attachment ID and accountID we expect 806 suite.Equal(attachmentID, attachment.ID) 807 suite.Equal(accountID, attachment.AccountID) 808 809 // file meta should be correctly derived from the image 810 suite.EqualValues(gtsmodel.Original{ 811 Width: 186, Height: 187, Size: 34782, Aspect: 0.9946524064171123, 812 }, attachment.FileMeta.Original) 813 suite.EqualValues(gtsmodel.Small{ 814 Width: 186, Height: 187, Size: 34782, Aspect: 0.9946524064171123, 815 }, attachment.FileMeta.Small) 816 suite.Equal("image/png", attachment.File.ContentType) 817 suite.Equal("image/jpeg", attachment.Thumbnail.ContentType) 818 suite.Equal(17471, attachment.File.FileSize) 819 suite.Equal("LFQT7e.A%O%4?co$M}M{_1W9~TxV", attachment.Blurhash) 820 821 // now make sure the attachment is in the database 822 dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachmentID) 823 suite.NoError(err) 824 suite.NotNil(dbAttachment) 825 826 // make sure the processed file is in storage 827 processedFullBytes, err := suite.storage.Get(ctx, attachment.File.Path) 828 suite.NoError(err) 829 suite.NotEmpty(processedFullBytes) 830 831 // load the processed bytes from our test folder, to compare 832 processedFullBytesExpected, err := os.ReadFile("./test/test-png-noalphachannel-processed.png") 833 suite.NoError(err) 834 suite.NotEmpty(processedFullBytesExpected) 835 836 // the bytes in storage should be what we expected 837 suite.Equal(processedFullBytesExpected, processedFullBytes) 838 839 // now do the same for the thumbnail and make sure it's what we expected 840 processedThumbnailBytes, err := suite.storage.Get(ctx, attachment.Thumbnail.Path) 841 suite.NoError(err) 842 suite.NotEmpty(processedThumbnailBytes) 843 844 processedThumbnailBytesExpected, err := os.ReadFile("./test/test-png-noalphachannel-thumbnail.jpg") 845 suite.NoError(err) 846 suite.NotEmpty(processedThumbnailBytesExpected) 847 848 suite.Equal(processedThumbnailBytesExpected, processedThumbnailBytes) 849 } 850 851 func (suite *ManagerTestSuite) TestPngAlphaChannelProcessBlocking() { 852 ctx := context.Background() 853 854 data := func(_ context.Context) (io.ReadCloser, int64, error) { 855 // load bytes from a test image 856 b, err := os.ReadFile("./test/test-png-alphachannel.png") 857 if err != nil { 858 panic(err) 859 } 860 return io.NopCloser(bytes.NewBuffer(b)), int64(len(b)), nil 861 } 862 863 accountID := "01FS1X72SK9ZPW0J1QQ68BD264" 864 865 // process the media with no additional info provided 866 processingMedia, err := suite.manager.ProcessMedia(ctx, data, accountID, nil) 867 suite.NoError(err) 868 // fetch the attachment id from the processing media 869 attachmentID := processingMedia.AttachmentID() 870 871 // do a blocking call to fetch the attachment 872 attachment, err := processingMedia.LoadAttachment(ctx) 873 suite.NoError(err) 874 suite.NotNil(attachment) 875 876 // make sure it's got the stuff set on it that we expect 877 // the attachment ID and accountID we expect 878 suite.Equal(attachmentID, attachment.ID) 879 suite.Equal(accountID, attachment.AccountID) 880 881 // file meta should be correctly derived from the image 882 suite.EqualValues(gtsmodel.Original{ 883 Width: 186, Height: 187, Size: 34782, Aspect: 0.9946524064171123, 884 }, attachment.FileMeta.Original) 885 suite.EqualValues(gtsmodel.Small{ 886 Width: 186, Height: 187, Size: 34782, Aspect: 0.9946524064171123, 887 }, attachment.FileMeta.Small) 888 suite.Equal("image/png", attachment.File.ContentType) 889 suite.Equal("image/jpeg", attachment.Thumbnail.ContentType) 890 suite.Equal(18904, attachment.File.FileSize) 891 suite.Equal("LFQT7e.A%O%4?co$M}M{_1W9~TxV", attachment.Blurhash) 892 893 // now make sure the attachment is in the database 894 dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachmentID) 895 suite.NoError(err) 896 suite.NotNil(dbAttachment) 897 898 // make sure the processed file is in storage 899 processedFullBytes, err := suite.storage.Get(ctx, attachment.File.Path) 900 suite.NoError(err) 901 suite.NotEmpty(processedFullBytes) 902 903 // load the processed bytes from our test folder, to compare 904 processedFullBytesExpected, err := os.ReadFile("./test/test-png-alphachannel-processed.png") 905 suite.NoError(err) 906 suite.NotEmpty(processedFullBytesExpected) 907 908 // the bytes in storage should be what we expected 909 suite.Equal(processedFullBytesExpected, processedFullBytes) 910 911 // now do the same for the thumbnail and make sure it's what we expected 912 processedThumbnailBytes, err := suite.storage.Get(ctx, attachment.Thumbnail.Path) 913 suite.NoError(err) 914 suite.NotEmpty(processedThumbnailBytes) 915 916 processedThumbnailBytesExpected, err := os.ReadFile("./test/test-png-alphachannel-thumbnail.jpg") 917 suite.NoError(err) 918 suite.NotEmpty(processedThumbnailBytesExpected) 919 920 suite.Equal(processedThumbnailBytesExpected, processedThumbnailBytes) 921 } 922 923 func (suite *ManagerTestSuite) TestSimpleJpegProcessBlockingWithCallback() { 924 ctx := context.Background() 925 926 data := func(_ context.Context) (io.ReadCloser, int64, error) { 927 // load bytes from a test image 928 b, err := os.ReadFile("./test/test-jpeg.jpg") 929 if err != nil { 930 panic(err) 931 } 932 return io.NopCloser(bytes.NewBuffer(b)), int64(len(b)), nil 933 } 934 935 accountID := "01FS1X72SK9ZPW0J1QQ68BD264" 936 937 // process the media with no additional info provided 938 processingMedia, err := suite.manager.ProcessMedia(ctx, data, accountID, nil) 939 suite.NoError(err) 940 // fetch the attachment id from the processing media 941 attachmentID := processingMedia.AttachmentID() 942 943 // do a blocking call to fetch the attachment 944 attachment, err := processingMedia.LoadAttachment(ctx) 945 suite.NoError(err) 946 suite.NotNil(attachment) 947 948 // make sure it's got the stuff set on it that we expect 949 // the attachment ID and accountID we expect 950 suite.Equal(attachmentID, attachment.ID) 951 suite.Equal(accountID, attachment.AccountID) 952 953 // file meta should be correctly derived from the image 954 suite.EqualValues(gtsmodel.Original{ 955 Width: 1920, Height: 1080, Size: 2073600, Aspect: 1.7777777777777777, 956 }, attachment.FileMeta.Original) 957 suite.EqualValues(gtsmodel.Small{ 958 Width: 512, Height: 288, Size: 147456, Aspect: 1.7777777777777777, 959 }, attachment.FileMeta.Small) 960 suite.Equal("image/jpeg", attachment.File.ContentType) 961 suite.Equal("image/jpeg", attachment.Thumbnail.ContentType) 962 suite.Equal(269739, attachment.File.FileSize) 963 suite.Equal("LiBzRk#6V[WF_NvzV@WY_3rqV@a$", attachment.Blurhash) 964 965 // now make sure the attachment is in the database 966 dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachmentID) 967 suite.NoError(err) 968 suite.NotNil(dbAttachment) 969 970 // make sure the processed file is in storage 971 processedFullBytes, err := suite.storage.Get(ctx, attachment.File.Path) 972 suite.NoError(err) 973 suite.NotEmpty(processedFullBytes) 974 975 // load the processed bytes from our test folder, to compare 976 processedFullBytesExpected, err := os.ReadFile("./test/test-jpeg-processed.jpg") 977 suite.NoError(err) 978 suite.NotEmpty(processedFullBytesExpected) 979 980 // the bytes in storage should be what we expected 981 suite.Equal(processedFullBytesExpected, processedFullBytes) 982 983 // now do the same for the thumbnail and make sure it's what we expected 984 processedThumbnailBytes, err := suite.storage.Get(ctx, attachment.Thumbnail.Path) 985 suite.NoError(err) 986 suite.NotEmpty(processedThumbnailBytes) 987 988 processedThumbnailBytesExpected, err := os.ReadFile("./test/test-jpeg-thumbnail.jpg") 989 suite.NoError(err) 990 suite.NotEmpty(processedThumbnailBytesExpected) 991 992 suite.Equal(processedThumbnailBytesExpected, processedThumbnailBytes) 993 } 994 995 func (suite *ManagerTestSuite) TestSimpleJpegProcessAsync() { 996 ctx, cncl := context.WithTimeout(context.Background(), time.Second*30) 997 defer cncl() 998 999 data := func(_ context.Context) (io.ReadCloser, int64, error) { 1000 // load bytes from a test image 1001 b, err := os.ReadFile("./test/test-jpeg.jpg") 1002 if err != nil { 1003 panic(err) 1004 } 1005 return io.NopCloser(bytes.NewBuffer(b)), int64(len(b)), nil 1006 } 1007 1008 accountID := "01FS1X72SK9ZPW0J1QQ68BD264" 1009 1010 // process the media with no additional info provided 1011 processingMedia, err := suite.manager.ProcessMedia(ctx, data, accountID, nil) 1012 suite.NoError(err) 1013 1014 // fetch the attachment id from the processing media 1015 attachmentID := processingMedia.AttachmentID() 1016 1017 // wait for processing to complete 1018 var attachment *gtsmodel.MediaAttachment 1019 if !testrig.WaitFor(func() bool { 1020 attachment, err = suite.db.GetAttachmentByID(ctx, attachmentID) 1021 return err == nil && attachment != nil 1022 }) { 1023 suite.FailNow("timed out waiting for attachment to process") 1024 } 1025 1026 // make sure it's got the stuff set on it that we expect 1027 // the attachment ID and accountID we expect 1028 suite.Equal(attachmentID, attachment.ID) 1029 suite.Equal(accountID, attachment.AccountID) 1030 1031 // file meta should be correctly derived from the image 1032 suite.EqualValues(gtsmodel.Original{ 1033 Width: 1920, Height: 1080, Size: 2073600, Aspect: 1.7777777777777777, 1034 }, attachment.FileMeta.Original) 1035 suite.EqualValues(gtsmodel.Small{ 1036 Width: 512, Height: 288, Size: 147456, Aspect: 1.7777777777777777, 1037 }, attachment.FileMeta.Small) 1038 suite.Equal("image/jpeg", attachment.File.ContentType) 1039 suite.Equal("image/jpeg", attachment.Thumbnail.ContentType) 1040 suite.Equal(269739, attachment.File.FileSize) 1041 suite.Equal("LiBzRk#6V[WF_NvzV@WY_3rqV@a$", attachment.Blurhash) 1042 1043 // now make sure the attachment is in the database 1044 dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachmentID) 1045 suite.NoError(err) 1046 suite.NotNil(dbAttachment) 1047 1048 // make sure the processed file is in storage 1049 processedFullBytes, err := suite.storage.Get(ctx, attachment.File.Path) 1050 suite.NoError(err) 1051 suite.NotEmpty(processedFullBytes) 1052 1053 // load the processed bytes from our test folder, to compare 1054 processedFullBytesExpected, err := os.ReadFile("./test/test-jpeg-processed.jpg") 1055 suite.NoError(err) 1056 suite.NotEmpty(processedFullBytesExpected) 1057 1058 // the bytes in storage should be what we expected 1059 suite.Equal(processedFullBytesExpected, processedFullBytes) 1060 1061 // now do the same for the thumbnail and make sure it's what we expected 1062 processedThumbnailBytes, err := suite.storage.Get(ctx, attachment.Thumbnail.Path) 1063 suite.NoError(err) 1064 suite.NotEmpty(processedThumbnailBytes) 1065 1066 processedThumbnailBytesExpected, err := os.ReadFile("./test/test-jpeg-thumbnail.jpg") 1067 suite.NoError(err) 1068 suite.NotEmpty(processedThumbnailBytesExpected) 1069 1070 suite.Equal(processedThumbnailBytesExpected, processedThumbnailBytes) 1071 } 1072 1073 func (suite *ManagerTestSuite) TestSimpleJpegQueueSpamming() { 1074 // in this test, we spam the manager queue with 50 new media requests, just to see how it holds up 1075 ctx := context.Background() 1076 1077 b, err := os.ReadFile("./test/test-jpeg.jpg") 1078 if err != nil { 1079 panic(err) 1080 } 1081 1082 data := func(_ context.Context) (io.ReadCloser, int64, error) { 1083 // load bytes from a test image 1084 return io.NopCloser(bytes.NewReader(b)), int64(len(b)), nil 1085 } 1086 1087 accountID := "01FS1X72SK9ZPW0J1QQ68BD264" 1088 1089 spam := 50 1090 inProcess := []*media.ProcessingMedia{} 1091 for i := 0; i < spam; i++ { 1092 // process the media with no additional info provided 1093 processingMedia, err := suite.manager.ProcessMedia(ctx, data, accountID, nil) 1094 suite.NoError(err) 1095 inProcess = append(inProcess, processingMedia) 1096 } 1097 1098 for _, processingMedia := range inProcess { 1099 // fetch the attachment id from the processing media 1100 attachmentID := processingMedia.AttachmentID() 1101 1102 // do a blocking call to fetch the attachment 1103 attachment, err := processingMedia.LoadAttachment(ctx) 1104 suite.NoError(err) 1105 suite.NotNil(attachment) 1106 1107 // make sure it's got the stuff set on it that we expect 1108 // the attachment ID and accountID we expect 1109 suite.Equal(attachmentID, attachment.ID) 1110 suite.Equal(accountID, attachment.AccountID) 1111 1112 // file meta should be correctly derived from the image 1113 suite.EqualValues(gtsmodel.Original{ 1114 Width: 1920, Height: 1080, Size: 2073600, Aspect: 1.7777777777777777, 1115 }, attachment.FileMeta.Original) 1116 suite.EqualValues(gtsmodel.Small{ 1117 Width: 512, Height: 288, Size: 147456, Aspect: 1.7777777777777777, 1118 }, attachment.FileMeta.Small) 1119 suite.Equal("image/jpeg", attachment.File.ContentType) 1120 suite.Equal("image/jpeg", attachment.Thumbnail.ContentType) 1121 suite.Equal(269739, attachment.File.FileSize) 1122 suite.Equal("LiBzRk#6V[WF_NvzV@WY_3rqV@a$", attachment.Blurhash) 1123 1124 // now make sure the attachment is in the database 1125 dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachmentID) 1126 suite.NoError(err) 1127 suite.NotNil(dbAttachment) 1128 1129 // make sure the processed file is in storage 1130 processedFullBytes, err := suite.storage.Get(ctx, attachment.File.Path) 1131 suite.NoError(err) 1132 suite.NotEmpty(processedFullBytes) 1133 1134 // load the processed bytes from our test folder, to compare 1135 processedFullBytesExpected, err := os.ReadFile("./test/test-jpeg-processed.jpg") 1136 suite.NoError(err) 1137 suite.NotEmpty(processedFullBytesExpected) 1138 1139 // the bytes in storage should be what we expected 1140 suite.Equal(processedFullBytesExpected, processedFullBytes) 1141 1142 // now do the same for the thumbnail and make sure it's what we expected 1143 processedThumbnailBytes, err := suite.storage.Get(ctx, attachment.Thumbnail.Path) 1144 suite.NoError(err) 1145 suite.NotEmpty(processedThumbnailBytes) 1146 1147 processedThumbnailBytesExpected, err := os.ReadFile("./test/test-jpeg-thumbnail.jpg") 1148 suite.NoError(err) 1149 suite.NotEmpty(processedThumbnailBytesExpected) 1150 1151 suite.Equal(processedThumbnailBytesExpected, processedThumbnailBytes) 1152 } 1153 } 1154 1155 func (suite *ManagerTestSuite) TestSimpleJpegProcessBlockingWithDiskStorage() { 1156 ctx := context.Background() 1157 1158 data := func(_ context.Context) (io.ReadCloser, int64, error) { 1159 // load bytes from a test image 1160 b, err := os.ReadFile("./test/test-jpeg.jpg") 1161 if err != nil { 1162 panic(err) 1163 } 1164 return io.NopCloser(bytes.NewBuffer(b)), int64(len(b)), nil 1165 } 1166 1167 accountID := "01FS1X72SK9ZPW0J1QQ68BD264" 1168 1169 temp := fmt.Sprintf("%s/gotosocial-test", os.TempDir()) 1170 defer os.RemoveAll(temp) 1171 1172 disk, err := storage.OpenDisk(temp, &storage.DiskConfig{ 1173 LockFile: path.Join(temp, "store.lock"), 1174 }) 1175 if err != nil { 1176 panic(err) 1177 } 1178 1179 var state state.State 1180 1181 state.Workers.Start() 1182 defer state.Workers.Stop() 1183 1184 storage := >sstorage.Driver{ 1185 Storage: disk, 1186 } 1187 state.Storage = storage 1188 state.DB = suite.db 1189 1190 diskManager := media.NewManager(&state) 1191 suite.manager = diskManager 1192 1193 // process the media with no additional info provided 1194 processingMedia, err := diskManager.ProcessMedia(ctx, data, accountID, nil) 1195 suite.NoError(err) 1196 // fetch the attachment id from the processing media 1197 attachmentID := processingMedia.AttachmentID() 1198 1199 // do a blocking call to fetch the attachment 1200 attachment, err := processingMedia.LoadAttachment(ctx) 1201 suite.NoError(err) 1202 suite.NotNil(attachment) 1203 1204 // make sure it's got the stuff set on it that we expect 1205 // the attachment ID and accountID we expect 1206 suite.Equal(attachmentID, attachment.ID) 1207 suite.Equal(accountID, attachment.AccountID) 1208 1209 // file meta should be correctly derived from the image 1210 suite.EqualValues(gtsmodel.Original{ 1211 Width: 1920, Height: 1080, Size: 2073600, Aspect: 1.7777777777777777, 1212 }, attachment.FileMeta.Original) 1213 suite.EqualValues(gtsmodel.Small{ 1214 Width: 512, Height: 288, Size: 147456, Aspect: 1.7777777777777777, 1215 }, attachment.FileMeta.Small) 1216 suite.Equal("image/jpeg", attachment.File.ContentType) 1217 suite.Equal("image/jpeg", attachment.Thumbnail.ContentType) 1218 suite.Equal(269739, attachment.File.FileSize) 1219 suite.Equal("LiBzRk#6V[WF_NvzV@WY_3rqV@a$", attachment.Blurhash) 1220 1221 // now make sure the attachment is in the database 1222 dbAttachment, err := suite.db.GetAttachmentByID(ctx, attachmentID) 1223 suite.NoError(err) 1224 suite.NotNil(dbAttachment) 1225 1226 // make sure the processed file is in storage 1227 processedFullBytes, err := storage.Get(ctx, attachment.File.Path) 1228 suite.NoError(err) 1229 suite.NotEmpty(processedFullBytes) 1230 1231 // load the processed bytes from our test folder, to compare 1232 processedFullBytesExpected, err := os.ReadFile("./test/test-jpeg-processed.jpg") 1233 suite.NoError(err) 1234 suite.NotEmpty(processedFullBytesExpected) 1235 1236 // the bytes in storage should be what we expected 1237 suite.Equal(processedFullBytesExpected, processedFullBytes) 1238 1239 // now do the same for the thumbnail and make sure it's what we expected 1240 processedThumbnailBytes, err := storage.Get(ctx, attachment.Thumbnail.Path) 1241 suite.NoError(err) 1242 suite.NotEmpty(processedThumbnailBytes) 1243 1244 processedThumbnailBytesExpected, err := os.ReadFile("./test/test-jpeg-thumbnail.jpg") 1245 suite.NoError(err) 1246 suite.NotEmpty(processedThumbnailBytesExpected) 1247 1248 suite.Equal(processedThumbnailBytesExpected, processedThumbnailBytes) 1249 } 1250 1251 func TestManagerTestSuite(t *testing.T) { 1252 suite.Run(t, &ManagerTestSuite{}) 1253 }