|
| 1 | +package playlists_test |
| 2 | + |
| 3 | +import ( |
| 4 | + "context" |
| 5 | + "errors" |
| 6 | + "io/fs" |
| 7 | + "os" |
| 8 | + "testing" |
| 9 | + "time" |
| 10 | + |
| 11 | + "github.com/ironsmile/euterpe/src/assert" |
| 12 | + "github.com/ironsmile/euterpe/src/library" |
| 13 | + "github.com/ironsmile/euterpe/src/playlists" |
| 14 | +) |
| 15 | + |
| 16 | +// TestPlaylistsManager checks that the playlists manager performs all of the |
| 17 | +// basic operations it is designed to do. |
| 18 | +func TestPlaylistsManager(t *testing.T) { |
| 19 | + ctx := t.Context() |
| 20 | + |
| 21 | + lib := getLibrary(ctx, t) |
| 22 | + defer func() { |
| 23 | + _ = lib.Truncate() |
| 24 | + }() |
| 25 | + manager := playlists.NewManager(lib.ExecuteDBJobAndWait) |
| 26 | + |
| 27 | + count, err := manager.Count(ctx) |
| 28 | + assert.NilErr(t, err, "getting playlists count") |
| 29 | + assert.Equal(t, 0, count, "unexpected number of playlists") |
| 30 | + |
| 31 | + allPlaylists, err := manager.List(ctx, playlists.ListArgs{ |
| 32 | + Offset: 0, |
| 33 | + Count: 100, |
| 34 | + }) |
| 35 | + assert.NilErr(t, err, "getting all playlists") |
| 36 | + assert.Equal(t, 0, len(allPlaylists), "did not expect to return any playlists") |
| 37 | + |
| 38 | + const playlistName = "empty playlist" |
| 39 | + |
| 40 | + now := time.Now() |
| 41 | + id, err := manager.Create(ctx, playlistName, []int64{}) |
| 42 | + assert.NilErr(t, err, "creating empty playlist") |
| 43 | + |
| 44 | + expected := playlists.Playlist{ |
| 45 | + Name: playlistName, |
| 46 | + ID: id, |
| 47 | + Public: true, |
| 48 | + CreatedAt: time.Unix(now.Unix(), 0), // seconds precision in the db |
| 49 | + UpdatedAt: time.Unix(now.Unix(), 0), // seconds precision in the db |
| 50 | + } |
| 51 | + |
| 52 | + playlist, err := manager.Get(ctx, id) |
| 53 | + assertPlaylist(t, expected, playlist) |
| 54 | + |
| 55 | + expected.Name = "new name for empty" |
| 56 | + expected.Desc = "some description" |
| 57 | + expected.Public = false |
| 58 | + |
| 59 | + flse := false |
| 60 | + now = time.Now() |
| 61 | + |
| 62 | + err = manager.Update(ctx, playlist.ID, playlists.UpdateArgs{ |
| 63 | + Name: expected.Name, |
| 64 | + Desc: expected.Desc, |
| 65 | + Public: &flse, |
| 66 | + }) |
| 67 | + assert.NilErr(t, err, "while updating a playlist") |
| 68 | + |
| 69 | + expected.UpdatedAt = time.Unix(now.Unix(), 0) |
| 70 | + |
| 71 | + // Get it again from the database and assert it has the new values. |
| 72 | + playlist, err = manager.Get(ctx, playlist.ID) |
| 73 | + assertPlaylist(t, expected, playlist) |
| 74 | + |
| 75 | + err = manager.Delete(ctx, playlist.ID) |
| 76 | + assert.NilErr(t, err, "while deleting a playlist") |
| 77 | + |
| 78 | + _, err = manager.Get(ctx, playlist.ID) |
| 79 | + assert.NotNilErr(t, err, "expected 'not found' error for deleted playlist") |
| 80 | +} |
| 81 | + |
| 82 | +// TestPlaylistsManagerNotFoundErrors makes sure that the playlists manager returns |
| 83 | +// not found errors. |
| 84 | +func TestPlaylistsManagerNotFoundErrors(t *testing.T) { |
| 85 | + ctx := t.Context() |
| 86 | + |
| 87 | + lib := getLibrary(ctx, t) |
| 88 | + defer func() { |
| 89 | + _ = lib.Truncate() |
| 90 | + }() |
| 91 | + manager := playlists.NewManager(lib.ExecuteDBJobAndWait) |
| 92 | + |
| 93 | + _, err := manager.Get(ctx, 123123) |
| 94 | + if !errors.Is(err, playlists.ErrNotFound) { |
| 95 | + t.Fatalf("get: expected 'not found' error but got: %s", err) |
| 96 | + } |
| 97 | + |
| 98 | + err = manager.Update(ctx, 123123, playlists.UpdateArgs{Name: "baba"}) |
| 99 | + if !errors.Is(err, playlists.ErrNotFound) { |
| 100 | + t.Fatalf("update: expected 'not found' error but got: %s", err) |
| 101 | + } |
| 102 | + |
| 103 | + err = manager.Delete(ctx, 123123123) |
| 104 | + if !errors.Is(err, playlists.ErrNotFound) { |
| 105 | + t.Fatalf("delete: expected 'not found' error but got: %s", err) |
| 106 | + } |
| 107 | +} |
| 108 | + |
| 109 | +func assertPlaylist(t *testing.T, expected, actual playlists.Playlist) { |
| 110 | + t.Helper() |
| 111 | + |
| 112 | + assert.Equal(t, expected.Name, actual.Name, "wrong newly created playlist name") |
| 113 | + assert.Equal(t, expected.ID, actual.ID, "wrong playlist ID returned") |
| 114 | + assert.Equal(t, expected.Desc, actual.Desc, "playlist description was not empty") |
| 115 | + assert.Equal(t, len(expected.Tracks), len(actual.Tracks), "playlist was expected to be empty") |
| 116 | + assert.Equal(t, expected.TracksCount, actual.TracksCount, "wrong playlist tracks count") |
| 117 | + assert.Equal(t, expected.CreatedAt, actual.CreatedAt, "wrong created at") |
| 118 | + assert.Equal(t, expected.UpdatedAt, actual.UpdatedAt, "wrong updated at") |
| 119 | + assert.Equal(t, expected.Public, actual.Public, "wrong public flag") |
| 120 | +} |
| 121 | + |
| 122 | +// getTestMigrationFiles returns the SQLs directory used by the application itself |
| 123 | +// normally. This way tests will be done with the exact same files which will be |
| 124 | +// bundled into the binary on build. |
| 125 | +func getTestMigrationFiles() fs.FS { |
| 126 | + return os.DirFS("../../sqls") |
| 127 | +} |
| 128 | + |
| 129 | +// It is the caller's responsibility to remove the library SQLite database file |
| 130 | +func getLibrary(ctx context.Context, t *testing.T) *library.LocalLibrary { |
| 131 | + lib, err := library.NewLocalLibrary(ctx, library.SQLiteMemoryFile, getTestMigrationFiles()) |
| 132 | + if err != nil { |
| 133 | + t.Fatal(err.Error()) |
| 134 | + } |
| 135 | + |
| 136 | + err = lib.Initialize() |
| 137 | + if err != nil { |
| 138 | + t.Fatalf("Initializing library: %s", err) |
| 139 | + } |
| 140 | + |
| 141 | + return lib |
| 142 | +} |
0 commit comments