210 lines
5.1 KiB
Go
210 lines
5.1 KiB
Go
package subtitles
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
type mockSubtitleRepo struct {
|
|
mu sync.Mutex
|
|
byKey map[string]*DownloadedSubtitle
|
|
nextID int
|
|
inserts int
|
|
}
|
|
|
|
func newMockSubtitleRepo() *mockSubtitleRepo {
|
|
return &mockSubtitleRepo{byKey: make(map[string]*DownloadedSubtitle)}
|
|
}
|
|
|
|
func (m *mockSubtitleRepo) InsertDownloadedSubtitle(_ context.Context, sub *DownloadedSubtitle) error {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
m.inserts++
|
|
m.nextID++
|
|
sub.ID = m.nextID
|
|
sub.CreatedAt = time.Now()
|
|
m.byKey[sub.S3Key] = sub
|
|
return nil
|
|
}
|
|
|
|
func (m *mockSubtitleRepo) GetDownloadedSubtitle(context.Context, int) (*DownloadedSubtitle, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *mockSubtitleRepo) ListDownloadedSubtitles(context.Context, int) ([]DownloadedSubtitle, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *mockSubtitleRepo) UpdateDownloadedSubtitle(_ context.Context, id int, update SubtitleMetadataUpdate) (*DownloadedSubtitle, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
for _, sub := range m.byKey {
|
|
if sub.ID == id {
|
|
sub.Language = update.Language
|
|
sub.ReleaseName = update.ReleaseName
|
|
sub.HearingImpaired = update.HearingImpaired
|
|
if sub.S3Key != update.S3Key {
|
|
delete(m.byKey, sub.S3Key)
|
|
sub.S3Key = update.S3Key
|
|
m.byKey[sub.S3Key] = sub
|
|
}
|
|
copy := *sub
|
|
return ©, nil
|
|
}
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *mockSubtitleRepo) DeleteDownloadedSubtitle(context.Context, int) (*DownloadedSubtitle, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *mockSubtitleRepo) GetDownloadedSubtitleByS3Key(_ context.Context, s3Key string) (*DownloadedSubtitle, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
if sub, ok := m.byKey[s3Key]; ok {
|
|
copy := *sub
|
|
return ©, nil
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *mockSubtitleRepo) ListProviderConfigs(context.Context) ([]ProviderConfig, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *mockSubtitleRepo) GetProviderConfig(context.Context, string) (*ProviderConfig, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *mockSubtitleRepo) UpsertProviderConfig(context.Context, *ProviderConfig) error {
|
|
return nil
|
|
}
|
|
|
|
type mockS3Client struct {
|
|
mu sync.Mutex
|
|
keys map[string][]byte
|
|
puts int
|
|
deletes int
|
|
}
|
|
|
|
func newMockS3Client() *mockS3Client {
|
|
return &mockS3Client{keys: make(map[string][]byte)}
|
|
}
|
|
|
|
func (m *mockS3Client) PutObject(_ context.Context, _, key string, data []byte) error {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
m.puts++
|
|
m.keys[key] = append([]byte(nil), data...)
|
|
return nil
|
|
}
|
|
|
|
func (m *mockS3Client) GetObject(_ context.Context, _, key string) ([]byte, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
return append([]byte(nil), m.keys[key]...), nil
|
|
}
|
|
|
|
func (m *mockS3Client) DeleteObject(_ context.Context, _, key string) error {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
m.deletes++
|
|
delete(m.keys, key)
|
|
return nil
|
|
}
|
|
|
|
func TestManagerUploadStoresSubtitle(t *testing.T) {
|
|
repo := newMockSubtitleRepo()
|
|
s3 := newMockS3Client()
|
|
manager := NewManager(repo, s3, "test-bucket")
|
|
|
|
data := []byte("1\n00:00:01,000 --> 00:00:02,000\nHello\n")
|
|
sub, err := manager.Upload(context.Background(), UploadRequest{
|
|
MediaFileID: 42,
|
|
Language: "en",
|
|
Filename: "custom.en.srt",
|
|
Data: data,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Upload() error = %v", err)
|
|
}
|
|
if sub.Provider != ProviderUpload {
|
|
t.Fatalf("provider = %q, want %q", sub.Provider, ProviderUpload)
|
|
}
|
|
if sub.Format != FormatSRT {
|
|
t.Fatalf("format = %q, want srt", sub.Format)
|
|
}
|
|
if repo.inserts != 1 {
|
|
t.Fatalf("inserts = %d, want 1", repo.inserts)
|
|
}
|
|
if s3.puts != 1 {
|
|
t.Fatalf("puts = %d, want 1", s3.puts)
|
|
}
|
|
}
|
|
|
|
func TestManagerUploadDedupesIdenticalContent(t *testing.T) {
|
|
repo := newMockSubtitleRepo()
|
|
s3 := newMockS3Client()
|
|
manager := NewManager(repo, s3, "test-bucket")
|
|
|
|
data := []byte("duplicate content")
|
|
first, err := manager.Upload(context.Background(), UploadRequest{
|
|
MediaFileID: 7,
|
|
Language: "en",
|
|
Filename: "a.srt",
|
|
Data: data,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("first Upload() error = %v", err)
|
|
}
|
|
|
|
second, err := manager.Upload(context.Background(), UploadRequest{
|
|
MediaFileID: 7,
|
|
Language: "en",
|
|
Filename: "b.srt",
|
|
Data: data,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("second Upload() error = %v", err)
|
|
}
|
|
if first.ID != second.ID {
|
|
t.Fatalf("dedup failed: ids %d vs %d", first.ID, second.ID)
|
|
}
|
|
if repo.inserts != 1 {
|
|
t.Fatalf("inserts = %d, want 1", repo.inserts)
|
|
}
|
|
if s3.puts != 1 {
|
|
t.Fatalf("puts = %d, want 1", s3.puts)
|
|
}
|
|
}
|
|
|
|
func TestManagerUploadRejectsUnsupportedFormat(t *testing.T) {
|
|
manager := NewManager(newMockSubtitleRepo(), newMockS3Client(), "test-bucket")
|
|
_, err := manager.Upload(context.Background(), UploadRequest{
|
|
MediaFileID: 1,
|
|
Language: "en",
|
|
Filename: "notes.txt",
|
|
Data: []byte("hello"),
|
|
})
|
|
if err == nil {
|
|
t.Fatal("expected error for unsupported format")
|
|
}
|
|
}
|
|
|
|
func TestManagerUploadRejectsOversizedFile(t *testing.T) {
|
|
manager := NewManager(newMockSubtitleRepo(), newMockS3Client(), "test-bucket")
|
|
data := make([]byte, MaxUploadSize+1)
|
|
_, err := manager.Upload(context.Background(), UploadRequest{
|
|
MediaFileID: 1,
|
|
Language: "en",
|
|
Filename: "big.srt",
|
|
Data: data,
|
|
})
|
|
if err == nil {
|
|
t.Fatal("expected error for oversized file")
|
|
}
|
|
}
|