Files
ym-dl-watcher/internal/storage/storage_test.go
T
Mrixs fe62910311 Initial commit: ym-dl with yandex-music-api-go library migration
Migrate ym-dl from custom oapi-codegen Yandex Music API client to external
gitea.mrixs.me/Mrixs/yandex-music-api-go library with token-only authentication.

Key changes:
- Replace custom Yandex API client with yandexmusic library wrapper
- Token-based OAuth authentication only (no username/password fallback)
- SQLite storage index with JSON index migration path
- Extended ID3 tag support: genre, comment, lyrics, publisher, ISRC, copyright
- High-resolution album covers (1000x1000)
- Fixed album download check (requires all tracks, not just one)
2026-10-17 17:09:42 +03:00

291 lines
7.0 KiB
Go

package storage
import (
"path/filepath"
"os"
"testing"
"time"
"gitea.mrixs.me/Mrixs/yandex-music-api-go/yandexmusic"
)
func TestStorageNew(t *testing.T) {
tmpDir := t.TempDir()
s, err := NewStorage(tmpDir, true)
if err != nil {
t.Fatalf("NewStorage failed: %v", err)
}
if s == nil {
t.Fatal("expected non-nil storage")
}
}
func TestStorageSaveAndLoadTrack(t *testing.T) {
tmpDir := t.TempDir()
s, err := NewStorage(tmpDir, true)
if err != nil {
t.Fatalf("NewStorage failed: %v", err)
}
meta := TrackMeta{
TrackID: "123",
AlbumID: "456",
ArtistID: "789",
Title: "Test Track",
ArtistName: "Test Artist",
AlbumTitle: "Test Album",
TrackNumber: 1,
DiscNumber: 1,
DurationMs: 180000,
Bitrate: 320,
Codec: "mp3",
DownloadedAt: time.Now().Format(time.RFC3339),
}
data := []byte("fake audio data")
if err := s.SaveTrack(meta, data, nil); err != nil {
t.Fatalf("SaveTrack failed: %v", err)
}
// Check index
if !s.IsTrackDownloaded("123") {
t.Error("track not marked as downloaded")
}
loadedMeta, ok := s.GetTrackMeta("123")
if !ok {
t.Fatal("track not found in index")
}
if loadedMeta.Title != "Test Track" {
t.Errorf("expected title 'Test Track', got '%s'", loadedMeta.Title)
}
if loadedMeta.FileSize != int64(len(data)) {
t.Errorf("expected file size %d, got %d", len(data), loadedMeta.FileSize)
}
// Check file exists using the stored path
if _, err := os.Stat(loadedMeta.FilePath); os.IsNotExist(err) {
t.Error("track file not created")
}
}
func TestStorageIdempotent(t *testing.T) {
tmpDir := t.TempDir()
s, err := NewStorage(tmpDir, true)
if err != nil {
t.Fatalf("NewStorage failed: %v", err)
}
meta := TrackMeta{
TrackID: "123",
Title: "Test Track",
ArtistName: "Test Artist",
AlbumTitle: "Test Album",
TrackNumber: 1,
Codec: "mp3",
}
data := []byte("fake audio data")
// Save first time
if err := s.SaveTrack(meta, data, nil); err != nil {
t.Fatalf("first SaveTrack failed: %v", err)
}
firstPath := meta.FilePath
// Save second time (should not create duplicate)
if err := s.SaveTrack(meta, data, nil); err != nil {
t.Fatalf("second SaveTrack failed: %v", err)
}
if meta.FilePath != firstPath {
t.Errorf("file path changed on second save: %s vs %s", meta.FilePath, firstPath)
}
// Verify only one file exists
files, _ := os.ReadDir(filepath.Join(tmpDir, "Test Artist", "Test Album"))
count := 0
for _, f := range files {
if !f.IsDir() {
count++
}
}
if count != 1 {
t.Errorf("expected 1 file, found %d", count)
}
}
func TestStorageOrganizeFalse(t *testing.T) {
tmpDir := t.TempDir()
s, err := NewStorage(tmpDir, false)
if err != nil {
t.Fatalf("NewStorage failed: %v", err)
}
meta := TrackMeta{
TrackID: "123",
Title: "Test Track",
ArtistName: "Test Artist",
AlbumTitle: "Test Album",
TrackNumber: 1,
Codec: "mp3",
DownloadedAt: time.Now().Format(time.RFC3339),
}
data := []byte("fake audio data")
if err := s.SaveTrack(meta, data, nil); err != nil {
t.Fatalf("SaveTrack failed: %v", err)
}
// Should be flat structure - get the saved meta from index
loadedMeta, ok := s.GetTrackMeta("123")
if !ok {
t.Fatal("track not found in index")
}
expectedDir := tmpDir
if filepath.Dir(loadedMeta.FilePath) != expectedDir {
t.Errorf("expected flat structure in %s, got %s", expectedDir, filepath.Dir(loadedMeta.FilePath))
}
}
func TestStorageSanitizeFilename(t *testing.T) {
tests := []struct {
input string
expected string
}{
{"normal", "normal"},
{"with/slash", "with_slash"},
{"with\\backslash", "with_backslash"},
{"with:colon", "with_colon"},
{"with*star", "with_star"},
{"with?question", "with_question"},
{"with\"quote", "with_quote"},
{"with<lt", "with_lt"},
{"with>gt", "with_gt"},
{"with|pipe", "with_pipe"},
}
for _, tc := range tests {
result := sanitizeFilename(tc.input)
if result != tc.expected {
t.Errorf("sanitizeFilename(%q) = %q, want %q", tc.input, result, tc.expected)
}
}
}
func TestStorageBuildTrackMetaFromYandex(t *testing.T) {
track := &yandexmusic.Track{
ID: "123",
Title: "Test Track",
Genre: "Pop",
DurationMs: 180000,
Artists: []yandexmusic.Artist{
{ID: "789", Name: "Test Artist"},
},
Albums: []yandexmusic.Album{
{ID: "456", Title: "Test Album"},
},
}
album := &yandexmusic.Album{
ID: "456",
Title: "Test Album",
Genre: "Album Pop",
Year: 2023,
ReleaseDate: "2023-05-15",
Label: "Test Label",
Description: "Test album description",
CatalogNumber: "TC-001",
Artists: []yandexmusic.Artist{
{ID: "789", Name: "Test Artist"},
},
}
downloadInfo := yandexmusic.DownloadInfo{
Bitrate: 320,
Codec: "mp3",
}
meta := BuildTrackMetaFromYandex(track, album, 1, 1, downloadInfo)
if meta.TrackID != "123" {
t.Errorf("expected track ID 123, got %s", meta.TrackID)
}
if meta.Title != "Test Track" {
t.Errorf("expected title 'Test Track', got '%s'", meta.Title)
}
if meta.ArtistName != "Test Artist" {
t.Errorf("expected artist 'Test Artist', got '%s'", meta.ArtistName)
}
if meta.AlbumTitle != "Test Album" {
t.Errorf("expected album 'Test Album', got '%s'", meta.AlbumTitle)
}
if meta.Bitrate != 320 {
t.Errorf("expected bitrate 320, got %d", meta.Bitrate)
}
if meta.Codec != "mp3" {
t.Errorf("expected codec mp3, got %s", meta.Codec)
}
// Extended metadata checks
if meta.Genre != "Pop" {
t.Errorf("expected genre 'Pop', got '%s'", meta.Genre)
}
if meta.Comment != "Test album description" {
t.Errorf("expected comment 'Test album description', got '%s'", meta.Comment)
}
if meta.Lyrics != "" {
t.Errorf("expected empty lyrics (no lyrics in track), got '%s'", meta.Lyrics)
}
if meta.Publisher != "Test Label" {
t.Errorf("expected publisher 'Test Label', got '%s'", meta.Publisher)
}
if meta.EncodedBy != "ym-dl" {
t.Errorf("expected encoded_by 'ym-dl', got '%s'", meta.EncodedBy)
}
if meta.OriginalYear != "2023" {
t.Errorf("expected original_year '2023', got '%s'", meta.OriginalYear)
}
if meta.Copyright != "TC-001" {
t.Errorf("expected copyright 'TC-001', got '%s'", meta.Copyright)
}
}
func TestStorageBuildAlbumMetaFromYandex(t *testing.T) {
album := &yandexmusic.Album{
ID: "456",
Title: "Test Album",
Artists: []yandexmusic.Artist{
{ID: "789", Name: "Test Artist"},
},
Year: 2023,
}
tracks := []TrackMeta{
{TrackID: "1", Title: "Track 1"},
{TrackID: "2", Title: "Track 2"},
}
meta := BuildAlbumMetaFromYandex(album, tracks)
if meta.AlbumID != "456" {
t.Errorf("expected album ID 456, got %s", meta.AlbumID)
}
if meta.Title != "Test Album" {
t.Errorf("expected title 'Test Album', got '%s'", meta.Title)
}
if meta.ArtistName != "Test Artist" {
t.Errorf("expected artist 'Test Artist', got '%s'", meta.ArtistName)
}
if meta.Year != 2023 {
t.Errorf("expected year 2023, got %d", meta.Year)
}
if meta.TrackCount != 2 {
t.Errorf("expected track count 2, got %d", meta.TrackCount)
}
}