actions_test.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  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. "master": "some-master-client"
  40. }
  41. }
  42. `), &action)
  43. myClient := "my-client"
  44. action.FromClient = &myClient
  45. songId := 123
  46. expectedAction := server.Action{
  47. Type: server.StateSet,
  48. FromClient: &myClient,
  49. Payload: server.MusicPlayer{
  50. SongId: &songId,
  51. Playing: true,
  52. CurrentTime: 94,
  53. SeekTime: -1,
  54. Master: "some-master-client",
  55. },
  56. }
  57. expectedActionString, jsonErr := json.Marshal(expectedAction)
  58. if jsonErr != nil {
  59. panic(jsonErr)
  60. }
  61. BeforeEach(func() {
  62. rdb.On("Publish", server.TOPIC_BROADCAST, expectedActionString).Return(redis.NewIntResult(0, nil))
  63. })
  64. It("should publish the action to the redis pubsub", func() {
  65. err := server.PublishActionFromClient(rdb, &action)
  66. Expect(rdb.Calls).NotTo(BeEmpty())
  67. Expect(err).To(BeNil())
  68. })
  69. })
  70. Context("when the song ID is non-positive", func() {
  71. var action server.Action
  72. json.Unmarshal([]byte(`
  73. {
  74. "type": "STATE_SET",
  75. "payload": {
  76. "songId": 0,
  77. "playing": true,
  78. "currentTime": 94,
  79. "seekTime": -1,
  80. "master": "some-master-client"
  81. }
  82. }
  83. `), &action)
  84. It("should not publish a message", func() {
  85. err := server.PublishActionFromClient(rdb, &action)
  86. Expect(rdb.Calls).To(BeEmpty())
  87. Expect(err).NotTo(BeNil())
  88. })
  89. })
  90. Context("when the song ID is null", func() {
  91. var action server.Action
  92. json.Unmarshal([]byte(`
  93. {
  94. "type": "STATE_SET",
  95. "payload": {
  96. "songId": null,
  97. "playing": false,
  98. "currentTime": 0,
  99. "seekTime": -1,
  100. "master": "some-master-client"
  101. }
  102. }
  103. `), &action)
  104. expectedAction := server.Action{
  105. Type: server.StateSet,
  106. Payload: server.MusicPlayer{
  107. SongId: nil,
  108. Playing: false,
  109. CurrentTime: 0,
  110. SeekTime: -1,
  111. Master: "some-master-client",
  112. },
  113. }
  114. expectedActionString, jsonErr := json.Marshal(expectedAction)
  115. if jsonErr != nil {
  116. panic(jsonErr)
  117. }
  118. BeforeEach(func() {
  119. rdb.On("Publish", server.TOPIC_BROADCAST, expectedActionString).Return(redis.NewIntResult(0, nil))
  120. })
  121. It("should publish a message", func() {
  122. err := server.PublishActionFromClient(rdb, &action)
  123. Expect(rdb.Calls).NotTo(BeEmpty())
  124. Expect(err).To(BeNil())
  125. })
  126. })
  127. Context("when the current time is negative", func() {
  128. var action server.Action
  129. json.Unmarshal([]byte(`
  130. {
  131. "type": "STATE_SET",
  132. "payload": {
  133. "songId": 123,
  134. "playing": false,
  135. "currentTime": -32,
  136. "seekTime": -1,
  137. "master": "some-master-client"
  138. }
  139. }
  140. `), &action)
  141. It("should not publish a message", func() {
  142. err := server.PublishActionFromClient(rdb, &action)
  143. Expect(rdb.Calls).To(BeEmpty())
  144. Expect(err).NotTo(BeNil())
  145. })
  146. })
  147. Context("when the seek time is less than -1", func() {
  148. var action server.Action
  149. json.Unmarshal([]byte(`
  150. {
  151. "type": "STATE_SET",
  152. "payload": {
  153. "songId": 123,
  154. "playing": false,
  155. "currentTime": 13,
  156. "seekTime": -3,
  157. "master": "some-master-client"
  158. }
  159. }
  160. `), &action)
  161. It("should not publish a message", func() {
  162. err := server.PublishActionFromClient(rdb, &action)
  163. Expect(rdb.Calls).To(BeEmpty())
  164. Expect(err).NotTo(BeNil())
  165. })
  166. })
  167. Context("when the master is empty", func() {
  168. var action server.Action
  169. json.Unmarshal([]byte(`
  170. {
  171. "type": "STATE_SET",
  172. "payload": {
  173. "songId": 123,
  174. "playing": false,
  175. "currentTime": 13,
  176. "seekTime": -3,
  177. "master": ""
  178. }
  179. }
  180. `), &action)
  181. It("should not publish a message", func() {
  182. err := server.PublishActionFromClient(rdb, &action)
  183. Expect(rdb.Calls).To(BeEmpty())
  184. Expect(err).NotTo(BeNil())
  185. })
  186. })
  187. })
  188. Describe("when the action is unrecognised", func() {
  189. var action server.Action
  190. // CLIENT_LIST_UPDATED should only ever come from the server
  191. err := json.Unmarshal([]byte(`
  192. {
  193. "type": "CLIENT_LIST_UPDATED",
  194. "payload": [
  195. { "name": "client-a", "lastPing": 123 },
  196. { "name": "client-b", "lastPing": 456 }
  197. ]
  198. }
  199. `), &action)
  200. if err != nil {
  201. panic(err)
  202. }
  203. BeforeEach(func() {
  204. rdb.On("Publish", server.TOPIC_BROADCAST, "").Return(redis.NewIntResult(0, nil))
  205. })
  206. It("should not publish a message", func() {
  207. err := server.PublishActionFromClient(rdb, &action)
  208. Expect(rdb.Calls).To(BeEmpty())
  209. Expect(err).NotTo(BeNil())
  210. })
  211. })
  212. })
  213. })