actions_test.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. package server_test
  2. import (
  3. "encoding/json"
  4. "github.com/felamaslen/gmus-backend/pkg/server"
  5. . "github.com/onsi/ginkgo"
  6. . "github.com/onsi/gomega"
  7. "github.com/alicebob/miniredis/v2"
  8. "github.com/elliotchance/redismock"
  9. "github.com/go-redis/redis"
  10. )
  11. func newTestRedis() *redismock.ClientMock {
  12. mr, err := miniredis.Run()
  13. if err != nil {
  14. panic(err)
  15. }
  16. client := redis.NewClient(&redis.Options{
  17. Addr: mr.Addr(),
  18. })
  19. return redismock.NewNiceMock(client)
  20. }
  21. var _ = Describe("Server actions", func() {
  22. var rdb *redismock.ClientMock
  23. BeforeEach(func() {
  24. rdb = newTestRedis()
  25. rdb.On("Publish").Return(redis.NewIntResult(0, nil))
  26. })
  27. Describe("PublishActionFromClient", func() {
  28. Describe("state set actions", func() {
  29. Context("when the action is valid", func() {
  30. var action server.Action
  31. json.Unmarshal([]byte(`
  32. {
  33. "type": "STATE_SET",
  34. "payload": {
  35. "songId": 123,
  36. "playing": true,
  37. "currentTime": 94,
  38. "seekTime": -1,
  39. "queue": [],
  40. "master": "some-master-client"
  41. }
  42. }
  43. `), &action)
  44. myClient := "my-client"
  45. action.FromClient = &myClient
  46. songId := 123
  47. expectedAction := server.Action{
  48. Type: server.StateSet,
  49. FromClient: &myClient,
  50. Payload: server.MusicPlayer{
  51. SongId: &songId,
  52. Playing: true,
  53. CurrentTime: 94,
  54. SeekTime: -1,
  55. Master: "some-master-client",
  56. Queue: &[]int{},
  57. },
  58. }
  59. expectedActionString, jsonErr := json.Marshal(expectedAction)
  60. if jsonErr != nil {
  61. panic(jsonErr)
  62. }
  63. BeforeEach(func() {
  64. rdb.On("Publish", server.TOPIC_BROADCAST, expectedActionString).Return(redis.NewIntResult(0, nil))
  65. })
  66. It("should publish the action to the redis pubsub", func() {
  67. err := server.PublishActionFromClient(rdb, &action)
  68. Expect(rdb.Calls).NotTo(BeEmpty())
  69. Expect(err).To(BeNil())
  70. })
  71. })
  72. Context("when the song ID is non-positive", func() {
  73. var action server.Action
  74. json.Unmarshal([]byte(`
  75. {
  76. "type": "STATE_SET",
  77. "payload": {
  78. "songId": 0,
  79. "playing": true,
  80. "currentTime": 94,
  81. "seekTime": -1,
  82. "queue": [],
  83. "master": "some-master-client"
  84. }
  85. }
  86. `), &action)
  87. It("should not publish a message", func() {
  88. err := server.PublishActionFromClient(rdb, &action)
  89. Expect(rdb.Calls).To(BeEmpty())
  90. Expect(err).NotTo(BeNil())
  91. })
  92. })
  93. Context("when the song ID is null", func() {
  94. var action server.Action
  95. json.Unmarshal([]byte(`
  96. {
  97. "type": "STATE_SET",
  98. "payload": {
  99. "songId": null,
  100. "playing": false,
  101. "currentTime": 0,
  102. "seekTime": -1,
  103. "queue": [],
  104. "master": "some-master-client"
  105. }
  106. }
  107. `), &action)
  108. expectedAction := server.Action{
  109. Type: server.StateSet,
  110. Payload: server.MusicPlayer{
  111. SongId: nil,
  112. Playing: false,
  113. CurrentTime: 0,
  114. SeekTime: -1,
  115. Master: "some-master-client",
  116. Queue: &[]int{},
  117. },
  118. }
  119. expectedActionString, jsonErr := json.Marshal(expectedAction)
  120. if jsonErr != nil {
  121. panic(jsonErr)
  122. }
  123. BeforeEach(func() {
  124. rdb.On("Publish", server.TOPIC_BROADCAST, expectedActionString).Return(redis.NewIntResult(0, nil))
  125. })
  126. It("should publish a message", func() {
  127. err := server.PublishActionFromClient(rdb, &action)
  128. Expect(rdb.Calls).NotTo(BeEmpty())
  129. Expect(err).To(BeNil())
  130. })
  131. })
  132. Context("when the current time is negative", func() {
  133. var action server.Action
  134. json.Unmarshal([]byte(`
  135. {
  136. "type": "STATE_SET",
  137. "payload": {
  138. "songId": 123,
  139. "playing": false,
  140. "currentTime": -32,
  141. "seekTime": -1,
  142. "queue": [],
  143. "master": "some-master-client"
  144. }
  145. }
  146. `), &action)
  147. It("should not publish a message", func() {
  148. err := server.PublishActionFromClient(rdb, &action)
  149. Expect(rdb.Calls).To(BeEmpty())
  150. Expect(err).NotTo(BeNil())
  151. })
  152. })
  153. Context("when the seek time is less than -1", func() {
  154. var action server.Action
  155. json.Unmarshal([]byte(`
  156. {
  157. "type": "STATE_SET",
  158. "payload": {
  159. "songId": 123,
  160. "playing": false,
  161. "currentTime": 13,
  162. "seekTime": -3,
  163. "queue": [],
  164. "master": "some-master-client"
  165. }
  166. }
  167. `), &action)
  168. It("should not publish a message", func() {
  169. err := server.PublishActionFromClient(rdb, &action)
  170. Expect(rdb.Calls).To(BeEmpty())
  171. Expect(err).NotTo(BeNil())
  172. })
  173. })
  174. Context("when the master is empty", func() {
  175. var action server.Action
  176. json.Unmarshal([]byte(`
  177. {
  178. "type": "STATE_SET",
  179. "payload": {
  180. "songId": 123,
  181. "playing": false,
  182. "currentTime": 13,
  183. "seekTime": -3,
  184. "queue": [],
  185. "master": ""
  186. }
  187. }
  188. `), &action)
  189. It("should not publish a message", func() {
  190. err := server.PublishActionFromClient(rdb, &action)
  191. Expect(rdb.Calls).To(BeEmpty())
  192. Expect(err).NotTo(BeNil())
  193. })
  194. })
  195. })
  196. Describe("when the action is unrecognised", func() {
  197. var action server.Action
  198. // CLIENT_LIST_UPDATED should only ever come from the server
  199. err := json.Unmarshal([]byte(`
  200. {
  201. "type": "CLIENT_LIST_UPDATED",
  202. "payload": [
  203. { "name": "client-a", "lastPing": 123 },
  204. { "name": "client-b", "lastPing": 456 }
  205. ]
  206. }
  207. `), &action)
  208. if err != nil {
  209. panic(err)
  210. }
  211. BeforeEach(func() {
  212. rdb.On("Publish", server.TOPIC_BROADCAST, "").Return(redis.NewIntResult(0, nil))
  213. })
  214. It("should not publish a message", func() {
  215. err := server.PublishActionFromClient(rdb, &action)
  216. Expect(rdb.Calls).To(BeEmpty())
  217. Expect(err).NotTo(BeNil())
  218. })
  219. })
  220. })
  221. })