views.test.ts 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. import { ApolloServer } from 'apollo-server-express'
  2. import { Mongoose } from 'mongoose'
  3. import { Aggregates } from '../src/types'
  4. import { ApolloServerTestClient } from 'apollo-server-testing/dist/createTestClient'
  5. import { buildAggregates, connectMongoose, createServer } from '../src/server'
  6. import { createTestClient } from 'apollo-server-testing'
  7. import {
  8. ADD_VIDEO_VIEW,
  9. AddVideoView,
  10. AddVideoViewArgs,
  11. GET_CHANNEL_VIEWS,
  12. GET_VIDEO_VIEWS,
  13. GetChannelViews,
  14. GetChannelViewsArgs,
  15. GetVideoViews,
  16. GetVideoViewsArgs,
  17. } from './queries/views'
  18. import { EntityViewsInfo } from '../src/entities/EntityViewsInfo'
  19. import { VideoEventsBucketModel } from '../src/models/VideoEvent'
  20. import { TEST_BUCKET_SIZE } from './setup'
  21. const FIRST_VIDEO_ID = '12'
  22. const SECOND_VIDEO_ID = '13'
  23. const FIRST_CHANNEL_ID = '22'
  24. const SECOND_CHANNEL_ID = '23'
  25. describe('Video and channel views resolver', () => {
  26. let server: ApolloServer
  27. let mongoose: Mongoose
  28. let aggregates: Aggregates
  29. let query: ApolloServerTestClient['query']
  30. let mutate: ApolloServerTestClient['mutate']
  31. beforeEach(async () => {
  32. mongoose = await connectMongoose(process.env.MONGO_URL!)
  33. aggregates = await buildAggregates()
  34. server = await createServer(mongoose, aggregates)
  35. const testClient = createTestClient(server)
  36. query = testClient.query
  37. mutate = testClient.mutate
  38. })
  39. afterEach(async () => {
  40. await server.stop()
  41. await VideoEventsBucketModel.deleteMany({})
  42. await mongoose.disconnect()
  43. })
  44. const addVideoView = async (videoId: string, channelId: string) => {
  45. const addVideoViewResponse = await mutate<AddVideoView, AddVideoViewArgs>({
  46. mutation: ADD_VIDEO_VIEW,
  47. variables: { videoId, channelId },
  48. })
  49. expect(addVideoViewResponse.errors).toBeUndefined()
  50. return addVideoViewResponse.data?.addVideoView
  51. }
  52. const getVideoViews = async (videoId: string) => {
  53. const videoViewsResponse = await query<GetVideoViews, GetVideoViewsArgs>({
  54. query: GET_VIDEO_VIEWS,
  55. variables: { videoId },
  56. })
  57. expect(videoViewsResponse.errors).toBeUndefined()
  58. return videoViewsResponse.data?.videoViews
  59. }
  60. const getChannelViews = async (channelId: string) => {
  61. const channelViewsResponse = await query<GetChannelViews, GetChannelViewsArgs>({
  62. query: GET_CHANNEL_VIEWS,
  63. variables: { channelId },
  64. })
  65. expect(channelViewsResponse.errors).toBeUndefined()
  66. return channelViewsResponse.data?.channelViews
  67. }
  68. it('should return null for unknown video and channel views', async () => {
  69. const videoViews = await getVideoViews(FIRST_VIDEO_ID)
  70. const channelViews = await getChannelViews(FIRST_CHANNEL_ID)
  71. expect(videoViews).toBeNull()
  72. expect(channelViews).toBeNull()
  73. })
  74. it('should properly save video and channel views', async () => {
  75. const expectedVideoViews: EntityViewsInfo = {
  76. id: FIRST_VIDEO_ID,
  77. views: 1,
  78. }
  79. const expectedChannelViews: EntityViewsInfo = {
  80. id: FIRST_CHANNEL_ID,
  81. views: 1,
  82. }
  83. const checkViews = async () => {
  84. const videoViews = await getVideoViews(FIRST_VIDEO_ID)
  85. const channelViews = await getChannelViews(FIRST_CHANNEL_ID)
  86. expect(videoViews).toEqual(expectedVideoViews)
  87. expect(channelViews).toEqual(expectedChannelViews)
  88. }
  89. let addVideoViewData = await addVideoView(FIRST_VIDEO_ID, FIRST_CHANNEL_ID)
  90. expect(addVideoViewData).toEqual(expectedVideoViews)
  91. await checkViews()
  92. expectedVideoViews.views++
  93. expectedChannelViews.views++
  94. addVideoViewData = await addVideoView(FIRST_VIDEO_ID, FIRST_CHANNEL_ID)
  95. expect(addVideoViewData).toEqual(expectedVideoViews)
  96. await checkViews()
  97. })
  98. it('should distinct views of separate videos', async () => {
  99. const expectedFirstVideoViews: EntityViewsInfo = {
  100. id: FIRST_VIDEO_ID,
  101. views: 1,
  102. }
  103. const expectedSecondVideoViews: EntityViewsInfo = {
  104. id: SECOND_VIDEO_ID,
  105. views: 1,
  106. }
  107. const addFirstVideoViewData = await addVideoView(FIRST_VIDEO_ID, FIRST_CHANNEL_ID)
  108. const addSecondVideoViewData = await addVideoView(SECOND_VIDEO_ID, FIRST_CHANNEL_ID)
  109. expect(addFirstVideoViewData).toEqual(expectedFirstVideoViews)
  110. expect(addSecondVideoViewData).toEqual(expectedSecondVideoViews)
  111. expectedFirstVideoViews.views++
  112. await addVideoView(FIRST_VIDEO_ID, FIRST_CHANNEL_ID)
  113. const firstVideoViews = await getVideoViews(FIRST_VIDEO_ID)
  114. const secondVideoViews = await getVideoViews(SECOND_VIDEO_ID)
  115. expect(firstVideoViews).toEqual(expectedFirstVideoViews)
  116. expect(secondVideoViews).toEqual(expectedSecondVideoViews)
  117. })
  118. it('should distinct views of separate channels', async () => {
  119. const expectedFirstChanelViews: EntityViewsInfo = {
  120. id: FIRST_CHANNEL_ID,
  121. views: 1,
  122. }
  123. const expectedSecondChannelViews: EntityViewsInfo = {
  124. id: SECOND_CHANNEL_ID,
  125. views: 1,
  126. }
  127. await addVideoView(FIRST_VIDEO_ID, FIRST_CHANNEL_ID)
  128. await addVideoView(SECOND_VIDEO_ID, SECOND_CHANNEL_ID)
  129. const firstChannelViews = await getChannelViews(FIRST_CHANNEL_ID)
  130. const secondChannelViews = await getChannelViews(SECOND_CHANNEL_ID)
  131. expect(firstChannelViews).toEqual(expectedFirstChanelViews)
  132. expect(secondChannelViews).toEqual(expectedSecondChannelViews)
  133. })
  134. it('should properly aggregate views of a channel', async () => {
  135. const expectedChannelViews: EntityViewsInfo = {
  136. id: FIRST_CHANNEL_ID,
  137. views: 2,
  138. }
  139. await addVideoView(FIRST_VIDEO_ID, FIRST_CHANNEL_ID)
  140. await addVideoView(SECOND_VIDEO_ID, FIRST_CHANNEL_ID)
  141. const channelViews = await getChannelViews(FIRST_CHANNEL_ID)
  142. expect(channelViews).toEqual(expectedChannelViews)
  143. })
  144. it('should properly rebuild the aggregate', async () => {
  145. const expectedFirstVideoViews: EntityViewsInfo = {
  146. id: FIRST_VIDEO_ID,
  147. views: 3,
  148. }
  149. const expectedSecondVideoViews: EntityViewsInfo = {
  150. id: SECOND_VIDEO_ID,
  151. views: 4,
  152. }
  153. const expectedChannelViews: EntityViewsInfo = {
  154. id: FIRST_CHANNEL_ID,
  155. views: 7,
  156. }
  157. const checkViews = async () => {
  158. const firstVideoViews = await getVideoViews(FIRST_VIDEO_ID)
  159. const secondVideoViews = await getVideoViews(SECOND_VIDEO_ID)
  160. const channelViews = await getChannelViews(FIRST_CHANNEL_ID)
  161. expect(firstVideoViews).toEqual(expectedFirstVideoViews)
  162. expect(secondVideoViews).toEqual(expectedSecondVideoViews)
  163. expect(channelViews).toEqual(expectedChannelViews)
  164. }
  165. await addVideoView(FIRST_VIDEO_ID, FIRST_CHANNEL_ID)
  166. await addVideoView(FIRST_VIDEO_ID, FIRST_CHANNEL_ID)
  167. await addVideoView(FIRST_VIDEO_ID, FIRST_CHANNEL_ID)
  168. await addVideoView(SECOND_VIDEO_ID, FIRST_CHANNEL_ID)
  169. await addVideoView(SECOND_VIDEO_ID, FIRST_CHANNEL_ID)
  170. await addVideoView(SECOND_VIDEO_ID, FIRST_CHANNEL_ID)
  171. await addVideoView(SECOND_VIDEO_ID, FIRST_CHANNEL_ID)
  172. await checkViews()
  173. await server.stop()
  174. aggregates = await buildAggregates()
  175. server = await createServer(mongoose, aggregates)
  176. const testClient = createTestClient(server)
  177. query = testClient.query
  178. mutate = testClient.mutate
  179. await checkViews()
  180. })
  181. it('should properly handle saving events across buckets', async () => {
  182. const eventsCount = TEST_BUCKET_SIZE * 2 + 1
  183. const expectedVideoViews: EntityViewsInfo = {
  184. id: FIRST_VIDEO_ID,
  185. views: eventsCount,
  186. }
  187. for (let i = 0; i < eventsCount; i++) {
  188. await addVideoView(FIRST_VIDEO_ID, FIRST_CHANNEL_ID)
  189. }
  190. const videoViews = await getVideoViews(FIRST_VIDEO_ID)
  191. expect(videoViews).toEqual(expectedVideoViews)
  192. })
  193. })