scanner_test.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. package read_test
  2. import (
  3. "os"
  4. "path"
  5. . "github.com/onsi/ginkgo"
  6. . "github.com/onsi/gomega"
  7. "github.com/felamaslen/gmus-backend/pkg/database"
  8. "github.com/felamaslen/gmus-backend/pkg/read"
  9. setup "github.com/felamaslen/gmus-backend/pkg/testing"
  10. "github.com/felamaslen/gmus-backend/pkg/types"
  11. )
  12. var _ = Describe("Scanning directories", func() {
  13. db := database.GetConnection()
  14. BeforeEach(func() {
  15. setup.PrepareDatabaseForTesting()
  16. })
  17. Describe("ScanDirectory", func() {
  18. var results []*types.File
  19. var testScanDirectory = func() {
  20. results = nil
  21. files := read.ScanDirectory(read.TestDirectory)
  22. done := false
  23. for !done {
  24. select {
  25. case result, more := <-files:
  26. if more {
  27. results = append(results, result)
  28. }
  29. done = !more
  30. }
  31. }
  32. }
  33. Context("when the database is empty", func() {
  34. BeforeEach(testScanDirectory)
  35. It("should return a channel with all the files in the directory", func() {
  36. Expect(results).To(HaveLen(2))
  37. if results[0].RelativePath == read.TestSong.RelativePath {
  38. Expect(results[0].RelativePath).To(Equal(read.TestSong.RelativePath))
  39. Expect(results[1].RelativePath).To(Equal(read.TestSongNested.RelativePath))
  40. } else {
  41. Expect(results[1].RelativePath).To(Equal(read.TestSong.RelativePath))
  42. Expect(results[0].RelativePath).To(Equal(read.TestSongNested.RelativePath))
  43. }
  44. })
  45. })
  46. Context("when the database already contains one of the files", func() {
  47. BeforeEach(func() {
  48. info, _ := os.Stat(path.Join(read.TestSong.BasePath, read.TestSong.RelativePath))
  49. db.MustExec(
  50. `
  51. insert into songs (title, artist, album, base_path, relative_path, modified_date)
  52. values ($1, $2, $3, $4, $5, $6)
  53. `,
  54. "old title",
  55. "old artist",
  56. "old album",
  57. read.TestSong.BasePath,
  58. read.TestSong.RelativePath,
  59. info.ModTime().Unix(),
  60. )
  61. testScanDirectory()
  62. })
  63. It("should only return those files which do not exist in the database", func() {
  64. Expect(results).To(HaveLen(1))
  65. Expect(results[0].RelativePath).To(Equal(read.TestSongNested.RelativePath))
  66. })
  67. })
  68. Context("when an error previously occurred scanning one of the files", func() {
  69. BeforeEach(func() {
  70. db.MustExec(`
  71. insert into scan_errors (base_path, relative_path, error)
  72. values ($1, $2, $3)
  73. `, read.TestSong.BasePath, read.TestSong.RelativePath, "A bad thing happened")
  74. testScanDirectory()
  75. })
  76. It("should only return those files which did not have errors marked against them", func() {
  77. Expect(results).To(HaveLen(1))
  78. Expect(results[0].RelativePath).To(Equal(read.TestSongNested.RelativePath))
  79. })
  80. })
  81. })
  82. Describe("UpsertSongsFromChannel", func() {
  83. var songs chan *types.Song
  84. var testScanSongs = func() {
  85. songs = make(chan *types.Song)
  86. go func() {
  87. defer close(songs)
  88. songs <- &types.Song{
  89. TrackNumber: 7,
  90. Title: "Hey Jude",
  91. Artist: "The Beatles",
  92. Album: "",
  93. Duration: 431,
  94. BasePath: "/path/to",
  95. RelativePath: "file.ogg",
  96. ModifiedDate: 8876,
  97. }
  98. songs <- &types.Song{
  99. TrackNumber: 11,
  100. Title: "Starman",
  101. Artist: "David Bowie",
  102. Album: "The Rise and Fall of Ziggy Stardust and the Spiders from Mars",
  103. Duration: 256,
  104. BasePath: "/different/path",
  105. RelativePath: "otherFile.ogg",
  106. ModifiedDate: 11883,
  107. }
  108. }()
  109. read.UpsertSongsFromChannel(songs)
  110. }
  111. Context("when the songs do not already exist in the database", func() {
  112. BeforeEach(testScanSongs)
  113. It("should insert the correct number of songs", func() {
  114. var count int
  115. db.Get(&count, "select count(*) from songs")
  116. Expect(count).To(Equal(2))
  117. })
  118. It("should insert both songs", func() {
  119. var songs []types.Song
  120. db.Select(&songs, `
  121. select track_number, title, artist, album, duration, base_path, relative_path, modified_date
  122. from songs
  123. order by title
  124. `)
  125. Expect(songs[0]).To(Equal(types.Song{
  126. TrackNumber: 7,
  127. Title: "Hey Jude",
  128. Artist: "The Beatles",
  129. Album: "",
  130. Duration: 431,
  131. BasePath: "/path/to",
  132. RelativePath: "file.ogg",
  133. ModifiedDate: 8876,
  134. }))
  135. Expect(songs[1]).To(Equal(types.Song{
  136. TrackNumber: 11,
  137. Title: "Starman",
  138. Artist: "David Bowie",
  139. Album: "The Rise and Fall of Ziggy Stardust and the Spiders from Mars",
  140. Duration: 256,
  141. BasePath: "/different/path",
  142. RelativePath: "otherFile.ogg",
  143. ModifiedDate: 11883,
  144. }))
  145. })
  146. })
  147. Context("when there is already a file in the database with the same name", func() {
  148. BeforeEach(func() {
  149. db.MustExec(
  150. `
  151. insert into songs (title, artist, album, base_path, relative_path, modified_date)
  152. values ($1, $2, $3, $4, $5, $6)
  153. `,
  154. "my title",
  155. "my artist",
  156. "my album",
  157. "/path/to",
  158. "file.ogg",
  159. 7782,
  160. )
  161. testScanSongs()
  162. })
  163. It("should not add an additional row for the same file", func() {
  164. var count int
  165. db.Get(&count, `
  166. select count(*) from songs
  167. where base_path = '/path/to' and relative_path = 'file.ogg'
  168. `)
  169. Expect(count).To(Equal(1))
  170. })
  171. It("should upsert the existing item", func() {
  172. var songs []types.Song
  173. db.Select(&songs, `
  174. select
  175. track_number
  176. ,title
  177. ,artist
  178. ,album
  179. ,duration
  180. ,base_path
  181. ,relative_path
  182. ,modified_date
  183. from songs
  184. where base_path = '/path/to' and relative_path = 'file.ogg'
  185. `)
  186. Expect(songs).To(HaveLen(1))
  187. var song = songs[0]
  188. Expect(song.TrackNumber).To(Equal(7))
  189. Expect(song.Title).To(Equal("Hey Jude"))
  190. Expect(song.Artist).To(Equal("The Beatles"))
  191. Expect(song.Album).To(Equal(""))
  192. Expect(song.Duration).To(Equal(431))
  193. Expect(song.ModifiedDate).To(Equal(int64(8876)))
  194. })
  195. })
  196. })
  197. Describe("ScanAndInsert", func() {
  198. It("should recursively scan files from a directory and add them to the database", func() {
  199. read.ScanAndInsert(read.TestDirectory)
  200. var songs []types.Song
  201. err := db.Select(&songs, `
  202. select title, artist, album, duration, base_path, relative_path
  203. from songs
  204. `)
  205. Expect(err).To(BeNil())
  206. Expect(songs).To(HaveLen(2))
  207. Expect(types.Song{
  208. Title: read.TestSong.Title,
  209. Artist: read.TestSong.Artist,
  210. Album: read.TestSong.Album,
  211. Duration: read.TestSong.Duration,
  212. BasePath: read.TestSong.BasePath,
  213. RelativePath: read.TestSong.RelativePath,
  214. }).To(BeElementOf(songs))
  215. Expect(types.Song{
  216. Title: read.TestSongNested.Title,
  217. Artist: read.TestSongNested.Artist,
  218. Album: read.TestSongNested.Album,
  219. Duration: read.TestSongNested.Duration,
  220. BasePath: read.TestSongNested.BasePath,
  221. RelativePath: read.TestSongNested.RelativePath,
  222. }).To(BeElementOf(songs))
  223. })
  224. })
  225. })