fileplaylist_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. /*
  2. * DudelDu
  3. *
  4. * Copyright 2016 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the MIT
  7. * License, If a copy of the MIT License was not distributed with this
  8. * file, You can obtain one at https://opensource.org/licenses/MIT.
  9. */
  10. package playlist
  11. import (
  12. "flag"
  13. "fmt"
  14. "io/ioutil"
  15. "net/http"
  16. "os"
  17. "sync"
  18. "testing"
  19. "devt.de/krotik/common/fileutil"
  20. "devt.de/krotik/common/httputil"
  21. "devt.de/krotik/dudeldu"
  22. )
  23. const TESTPORT = ":9092"
  24. const pdir = "playlisttest"
  25. const testPlaylist = `
  26. /*
  27. Test comment
  28. */
  29. {
  30. "/testpath" : [
  31. {
  32. "artist" : "artist1", // 1234
  33. "title" : "test1",
  34. "path" : "playlisttest/test1.mp3"
  35. },
  36. {
  37. "artist" : "artist2",
  38. "title" : "test2",
  39. "path" : "playlisttest/test2.nsv"
  40. },
  41. {
  42. "artist" : "artist3",
  43. "title" : "test3",
  44. "path" : "playlisttest/test3.xyz"
  45. }
  46. ]
  47. }`
  48. const testPlaylist2 = `{
  49. "/testpath" : [
  50. {
  51. "artist" : "artist1",
  52. "title" : "test1",
  53. "path" : "playlisttest/test1.mp3"
  54. },
  55. {
  56. "artist" : "artist2",
  57. "title" : "test2",
  58. "path" : "playlisttest/test2.nsv"
  59. },
  60. {
  61. "artist" : "artist2",
  62. "title" : "test2",
  63. "path" : "playlisttest/nonexist"
  64. },
  65. {
  66. "artist" : "artist3",
  67. "title" : "test3",
  68. "path" : "playlisttest/test3.xyz"
  69. },
  70. {
  71. "artist" : "artist4",
  72. "title" : "test4",
  73. "path" : "http://localhost:9092/songs/song1.mp3"
  74. }
  75. ]
  76. }`
  77. const invalidFileName = "**" + string(0x0)
  78. func TestMain(m *testing.M) {
  79. flag.Parse()
  80. // Setup
  81. if res, _ := fileutil.PathExists(pdir); res {
  82. os.RemoveAll(pdir)
  83. }
  84. err := os.Mkdir(pdir, 0770)
  85. if err != nil {
  86. fmt.Print("Could not create test directory:", err.Error())
  87. os.Exit(1)
  88. }
  89. // Run the tests
  90. res := m.Run()
  91. // Teardown
  92. err = os.RemoveAll(pdir)
  93. if err != nil {
  94. fmt.Print("Could not remove test directory:", err.Error())
  95. }
  96. os.Exit(res)
  97. }
  98. func TestFilePlaylist(t *testing.T) {
  99. // Set up
  100. hs, wg := startServer()
  101. if hs == nil {
  102. return
  103. }
  104. defer func() {
  105. stopServer(hs, wg)
  106. }()
  107. http.HandleFunc("/songs/song1.mp3", func(w http.ResponseWriter, r *http.Request) {
  108. w.Write([]byte("songdata123"))
  109. })
  110. err := ioutil.WriteFile(pdir+"/test1.json", []byte(testPlaylist), 0644)
  111. if err != nil {
  112. t.Error(err)
  113. return
  114. }
  115. err = ioutil.WriteFile(pdir+"/test2.json", []byte(testPlaylist2), 0644)
  116. if err != nil {
  117. t.Error(err)
  118. return
  119. }
  120. err = ioutil.WriteFile(pdir+"/test1invalid.json", []byte(testPlaylist[2:]), 0644)
  121. if err != nil {
  122. t.Error(err)
  123. return
  124. }
  125. err = ioutil.WriteFile(pdir+"/test1.mp3", []byte("123"), 0644)
  126. if err != nil {
  127. t.Error(err)
  128. return
  129. }
  130. err = ioutil.WriteFile(pdir+"/test2.nsv", []byte("456789"), 0644)
  131. if err != nil {
  132. t.Error(err)
  133. return
  134. }
  135. err = ioutil.WriteFile(pdir+"/test3.xyz", []byte("AB"), 0644)
  136. if err != nil {
  137. t.Error(err)
  138. return
  139. }
  140. // Load invalid factory
  141. _, err = NewFilePlaylistFactory(invalidFileName)
  142. if err == nil {
  143. t.Error(err)
  144. return
  145. }
  146. _, err = NewFilePlaylistFactory(pdir + "/test1invalid.json")
  147. if err.Error() != "invalid character '*' looking for beginning of value" {
  148. t.Error(err)
  149. return
  150. }
  151. // Create playlist factory
  152. plf, err := NewFilePlaylistFactory(pdir + "/test1.json")
  153. if err != nil {
  154. t.Error(err)
  155. return
  156. }
  157. // Request non-existing path
  158. res := plf.Playlist("/nonexist", false)
  159. if res != nil {
  160. t.Error("Non existing path should return nil")
  161. return
  162. }
  163. // Get existing playlist
  164. pl := plf.Playlist("/testpath", false)
  165. defer pl.Close()
  166. if pl == nil {
  167. t.Error("Playlist should exist")
  168. return
  169. }
  170. if pl.Name() != "/testpath" {
  171. t.Error("Unexpected playlist name:", pl.Name())
  172. return
  173. }
  174. FrameSize = 2
  175. if pl.ContentType() != "audio/mpeg" {
  176. t.Error("Unexpected content type:", pl.ContentType())
  177. return
  178. }
  179. if pl.Artist() != "artist1" {
  180. t.Error("Unexpected artist:", pl.ContentType())
  181. return
  182. }
  183. if pl.Title() != "test1" {
  184. t.Error("Unexpected title:", pl.ContentType())
  185. return
  186. }
  187. // Test close call
  188. frame, err := pl.Frame()
  189. if err != nil {
  190. t.Error(err)
  191. return
  192. } else if string(frame) != "12" {
  193. t.Error("Unexpected frame:", string(frame))
  194. return
  195. }
  196. pl.Close()
  197. // Make the frame pool run dry if more than one byte array is used
  198. pl.(*FilePlaylist).framePool = &sync.Pool{}
  199. pl.(*FilePlaylist).framePool.Put(make([]byte, 2, 2))
  200. // Check that the right frames are returned
  201. frame, err = pl.Frame()
  202. if err != nil {
  203. t.Error(err)
  204. return
  205. } else if string(frame) != "12" {
  206. t.Error("Unexpected frame:", string(frame))
  207. return
  208. }
  209. pl.ReleaseFrame(frame)
  210. if pl.Title() != "test1" || pl.Artist() != "artist1" {
  211. t.Error("Unexpected title/artist:", pl.Title(), pl.Artist())
  212. return
  213. }
  214. frame, err = pl.Frame()
  215. if err != nil {
  216. t.Error(err)
  217. return
  218. } else if string(frame) != "34" {
  219. t.Error("Unexpected frame:", string(frame))
  220. return
  221. }
  222. pl.ReleaseFrame(frame)
  223. if pl.Title() != "test2" || pl.Artist() != "artist2" {
  224. t.Error("Unexpected title/artist:", pl.Title(), pl.Artist())
  225. return
  226. }
  227. frame, err = pl.Frame()
  228. if err != nil {
  229. t.Error(err)
  230. return
  231. } else if string(frame) != "56" {
  232. t.Error("Unexpected frame:", string(frame))
  233. return
  234. }
  235. pl.ReleaseFrame(frame)
  236. if pl.Title() != "test2" || pl.Artist() != "artist2" {
  237. t.Error("Unexpected title/artist:", pl.Title(), pl.Artist())
  238. return
  239. }
  240. frame, err = pl.Frame()
  241. if err != nil {
  242. t.Error(err)
  243. return
  244. } else if string(frame) != "78" {
  245. t.Error("Unexpected frame:", string(frame))
  246. return
  247. }
  248. pl.ReleaseFrame(frame)
  249. frame, err = pl.Frame()
  250. if err != nil {
  251. t.Error(err)
  252. return
  253. } else if string(frame) != "9A" {
  254. t.Error("Unexpected frame:", string(frame))
  255. return
  256. }
  257. pl.ReleaseFrame(frame)
  258. if pl.Title() != "test3" || pl.Artist() != "artist3" {
  259. t.Error("Unexpected title/artist:", pl.Title(), pl.Artist())
  260. return
  261. }
  262. // Check frame pool
  263. if pl.(*FilePlaylist).framePool.Get() == nil {
  264. t.Error("Frame pool should have an entry")
  265. return
  266. }
  267. if pl.(*FilePlaylist).framePool.Get() != nil {
  268. t.Error("Frame pool should have no entry")
  269. return
  270. }
  271. // Put again one byte array back
  272. pl.(*FilePlaylist).framePool.Put(make([]byte, 2, 2))
  273. frame, err = pl.Frame()
  274. if err != dudeldu.ErrPlaylistEnd {
  275. t.Error(err)
  276. return
  277. } else if string(frame) != "B" {
  278. t.Error("Unexpected frame:", string(frame), frame)
  279. return
  280. }
  281. pl.ReleaseFrame(frame)
  282. // Check that the byte array was NOT put back into the pool
  283. if pl.(*FilePlaylist).framePool.Get() != nil {
  284. t.Error("Frame pool should have no entry")
  285. return
  286. }
  287. if !pl.Finished() {
  288. t.Error("Playlist should be finished")
  289. return
  290. }
  291. // Change the last file
  292. err = ioutil.WriteFile(pdir+"/test3.xyz", []byte("A"), 0644)
  293. if err != nil {
  294. t.Error(err)
  295. return
  296. }
  297. // Make the frame pool normal again
  298. pl.(*FilePlaylist).framePool = &sync.Pool{New: func() interface{} { return make([]byte, FrameSize, FrameSize) }}
  299. // Increase the framesize
  300. FrameSize = 5
  301. pl.Close()
  302. frame, err = pl.Frame()
  303. if err != nil {
  304. t.Error(err)
  305. return
  306. } else if string(frame) != "12345" {
  307. t.Error("Unexpected frame:", string(frame), frame)
  308. return
  309. }
  310. // Check that the content type is unknown
  311. if pl.ContentType() != "video/nsv" {
  312. t.Error("Content type should be nsv not:", pl.ContentType())
  313. return
  314. }
  315. frame, err = pl.Frame()
  316. if err != nil {
  317. t.Error(err)
  318. return
  319. } else if string(frame) != "6789A" {
  320. t.Error("Unexpected frame:", string(frame), frame)
  321. return
  322. }
  323. if pl.ContentType() != "audio" {
  324. t.Error("Content type should be generic not:", pl.ContentType())
  325. return
  326. }
  327. frame, err = pl.Frame()
  328. if err != dudeldu.ErrPlaylistEnd {
  329. t.Error(err)
  330. return
  331. } else if string(frame) != "" {
  332. t.Error("Unexpected frame:", string(frame), frame)
  333. return
  334. }
  335. if !pl.Finished() {
  336. t.Error("Playlist should be finished")
  337. return
  338. }
  339. // Increase the framesize
  340. FrameSize = 10
  341. pl.Close()
  342. frame, err = pl.Frame()
  343. if err != nil {
  344. t.Error(err)
  345. return
  346. } else if string(frame) != "123456789A" {
  347. t.Error("Unexpected frame:", string(frame), frame)
  348. return
  349. }
  350. frame, err = pl.Frame()
  351. if err != dudeldu.ErrPlaylistEnd {
  352. t.Error(err)
  353. return
  354. } else if string(frame) != "" {
  355. t.Error("Unexpected frame:", string(frame), frame)
  356. return
  357. }
  358. if !pl.Finished() {
  359. t.Error("Playlist should be finished")
  360. return
  361. }
  362. // Increase the framesize
  363. FrameSize = 11
  364. pl.Close()
  365. frame, err = pl.Frame()
  366. if err != dudeldu.ErrPlaylistEnd {
  367. t.Error(err)
  368. return
  369. } else if string(frame) != "123456789A" {
  370. t.Error("Unexpected frame:", string(frame), frame)
  371. return
  372. }
  373. if !pl.Finished() {
  374. t.Error("Playlist should be finished")
  375. return
  376. }
  377. // Check that the playlist has finished indeed
  378. if _, err := pl.Frame(); err != dudeldu.ErrPlaylistEnd {
  379. t.Error("Playlist end error expected")
  380. return
  381. }
  382. // Create playlist factory
  383. plf, err = NewFilePlaylistFactory(pdir + "/test2.json")
  384. if err != nil {
  385. t.Error(err)
  386. return
  387. }
  388. // Test error
  389. pl2 := plf.Playlist("/testpath", false)
  390. defer pl2.Close()
  391. FrameSize = 6
  392. frame, err = pl2.Frame()
  393. if err != nil {
  394. t.Error(err)
  395. return
  396. } else if string(frame) != "123456" {
  397. t.Error("Unexpected frame:", string(frame), frame)
  398. return
  399. }
  400. frame, err = pl2.Frame()
  401. if err.Error() != "open playlisttest/nonexist: The system cannot find the file specified." &&
  402. err.Error() != "open playlisttest/nonexist: no such file or directory" {
  403. t.Error(err)
  404. return
  405. } else if string(frame) != "789" {
  406. t.Error("Unexpected frame:", string(frame), frame)
  407. return
  408. }
  409. frame, err = pl2.Frame()
  410. if err != nil {
  411. t.Error(err)
  412. return
  413. } else if string(frame) != "Asongd" {
  414. t.Error("Unexpected frame:", string(frame), frame)
  415. return
  416. }
  417. frame, err = pl2.Frame()
  418. if err != dudeldu.ErrPlaylistEnd {
  419. t.Error(err)
  420. return
  421. } else if string(frame) != "ata123" {
  422. t.Error("Unexpected frame:", string(frame), frame)
  423. return
  424. }
  425. // Make sure currentItem does not blow up
  426. if pl2.Title() != "test4" {
  427. t.Error("Unexpected result:", pl2.Title())
  428. return
  429. }
  430. // Test shuffling
  431. pl3 := plf.Playlist("/testpath", true)
  432. if len(pl3.(*FilePlaylist).data) != len(pl2.(*FilePlaylist).data) {
  433. t.Error("Length of playlists differ")
  434. return
  435. }
  436. }
  437. /*
  438. Start a HTTP test server.
  439. */
  440. func startServer() (*httputil.HTTPServer, *sync.WaitGroup) {
  441. hs := &httputil.HTTPServer{}
  442. var wg sync.WaitGroup
  443. wg.Add(1)
  444. go hs.RunHTTPServer(TESTPORT, &wg)
  445. wg.Wait()
  446. // Server is started
  447. if hs.LastError != nil {
  448. panic(hs.LastError)
  449. }
  450. return hs, &wg
  451. }
  452. /*
  453. Stop a started HTTP test server.
  454. */
  455. func stopServer(hs *httputil.HTTPServer, wg *sync.WaitGroup) {
  456. if hs.Running == true {
  457. wg.Add(1)
  458. // Server is shut down
  459. hs.Shutdown()
  460. wg.Wait()
  461. } else {
  462. panic("Server was not running as expected")
  463. }
  464. }