follows.test.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. import { ApolloServer } from 'apollo-server-express'
  2. import { Mongoose } from 'mongoose'
  3. import { Aggregates } from '../src/types'
  4. import { buildAggregates, connectMongoose, createServer } from '../src/server'
  5. import {
  6. FOLLOW_CHANNEL,
  7. FollowChannel,
  8. FollowChannelArgs,
  9. GET_CHANNEL_FOLLOWS,
  10. GetChannelFollows,
  11. GetChannelFollowsArgs,
  12. UNFOLLOW_CHANNEL,
  13. UnfollowChannel,
  14. UnfollowChannelArgs,
  15. GET_MOST_FOLLOWED_CHANNELS,
  16. GetMostFollowedChannels,
  17. GetMostFollowedChannelsArgs,
  18. GET_MOST_FOLLOWED_CHANNELS_ALL_TIME,
  19. GetMostFollowedChannelsAllTime,
  20. GetMostFollowedChannelsAllTimeArgs,
  21. } from './queries/follows'
  22. import { ChannelFollowsInfo } from '../src/entities/ChannelFollowsInfo'
  23. import { ChannelEventsBucketModel } from '../src/models/ChannelEvent'
  24. import { TEST_BUCKET_SIZE } from './setup'
  25. import { createMutationFn, createQueryFn, MutationFn, QueryFn } from './helpers'
  26. const FIRST_CHANNEL_ID = '22'
  27. const SECOND_CHANNEL_ID = '23'
  28. describe('Channel follows resolver', () => {
  29. let server: ApolloServer
  30. let mongoose: Mongoose
  31. let aggregates: Aggregates
  32. let query: QueryFn
  33. let mutate: MutationFn
  34. beforeEach(async () => {
  35. mongoose = await connectMongoose(process.env.MONGO_URL!)
  36. aggregates = await buildAggregates()
  37. server = await createServer(mongoose, aggregates)
  38. await server.start()
  39. query = createQueryFn(server)
  40. mutate = createMutationFn(server)
  41. })
  42. afterEach(async () => {
  43. await server.stop()
  44. await ChannelEventsBucketModel.deleteMany({})
  45. await mongoose.disconnect()
  46. })
  47. const followChannel = async (channelId: string) => {
  48. const followChannelResponse = await mutate<FollowChannel, FollowChannelArgs>({
  49. mutation: FOLLOW_CHANNEL,
  50. variables: { channelId },
  51. })
  52. expect(followChannelResponse.errors).toBeUndefined()
  53. return followChannelResponse.data?.followChannel
  54. }
  55. const unfollowChannel = async (channelId: string) => {
  56. const unfollowChannelResponse = await mutate<UnfollowChannel, UnfollowChannelArgs>({
  57. mutation: UNFOLLOW_CHANNEL,
  58. variables: { channelId },
  59. })
  60. expect(unfollowChannelResponse.errors).toBeUndefined()
  61. return unfollowChannelResponse.data?.unfollowChannel
  62. }
  63. const getChannelFollows = async (channelId: string) => {
  64. const channelFollowsResponse = await query<GetChannelFollows, GetChannelFollowsArgs>({
  65. query: GET_CHANNEL_FOLLOWS,
  66. variables: { channelId },
  67. })
  68. expect(channelFollowsResponse.errors).toBeUndefined()
  69. return channelFollowsResponse.data?.channelFollows
  70. }
  71. const getMostFollowedChannels = async (timePeriodDays: number) => {
  72. const mostFollowedChannelsResponse = await query<GetMostFollowedChannels, GetMostFollowedChannelsArgs>({
  73. query: GET_MOST_FOLLOWED_CHANNELS,
  74. variables: { timePeriodDays },
  75. })
  76. expect(mostFollowedChannelsResponse.errors).toBeUndefined()
  77. return mostFollowedChannelsResponse.data?.mostFollowedChannels
  78. }
  79. const getMostFollowedChannelsAllTime = async (limit: number) => {
  80. const mostFollowedChannelsAllTimeResponse = await query<
  81. GetMostFollowedChannelsAllTime,
  82. GetMostFollowedChannelsAllTimeArgs
  83. >({
  84. query: GET_MOST_FOLLOWED_CHANNELS_ALL_TIME,
  85. variables: { limit },
  86. })
  87. expect(mostFollowedChannelsAllTimeResponse.errors).toBeUndefined()
  88. return mostFollowedChannelsAllTimeResponse.data?.mostFollowedChannelsAllTime
  89. }
  90. it('should return null for unknown channel follows', async () => {
  91. const channelFollows = await getChannelFollows(FIRST_CHANNEL_ID)
  92. const mostFollowedChannels = await getMostFollowedChannels(30)
  93. const mostFollowedChannelsAllTime = await getMostFollowedChannelsAllTime(10)
  94. expect(channelFollows).toBeNull()
  95. expect(mostFollowedChannels).toHaveLength(0)
  96. expect(mostFollowedChannelsAllTime).toHaveLength(0)
  97. })
  98. it('should properly handle channel follow', async () => {
  99. const expectedChannelFollows: ChannelFollowsInfo = {
  100. id: FIRST_CHANNEL_ID,
  101. follows: 1,
  102. }
  103. let addChannelFollowData = await followChannel(FIRST_CHANNEL_ID)
  104. expect(addChannelFollowData).toEqual(expectedChannelFollows)
  105. let channelFollows = await getChannelFollows(FIRST_CHANNEL_ID)
  106. let mostFollowedChannels = await getMostFollowedChannels(30)
  107. let mostFollowedChannelsAllTime = await getMostFollowedChannelsAllTime(10)
  108. expect(channelFollows).toEqual(expectedChannelFollows)
  109. expect(mostFollowedChannels).toEqual([expectedChannelFollows])
  110. expect(mostFollowedChannelsAllTime).toEqual([expectedChannelFollows])
  111. expectedChannelFollows.follows++
  112. addChannelFollowData = await followChannel(FIRST_CHANNEL_ID)
  113. expect(addChannelFollowData).toEqual(expectedChannelFollows)
  114. channelFollows = await getChannelFollows(FIRST_CHANNEL_ID)
  115. mostFollowedChannels = await getMostFollowedChannels(30)
  116. mostFollowedChannelsAllTime = await getMostFollowedChannelsAllTime(10)
  117. expect(channelFollows).toEqual(expectedChannelFollows)
  118. expect(mostFollowedChannels).toEqual([expectedChannelFollows])
  119. expect(mostFollowedChannelsAllTime).toEqual([expectedChannelFollows])
  120. })
  121. it('should properly handle channel unfollow', async () => {
  122. const expectedChannelFollows: ChannelFollowsInfo = {
  123. id: FIRST_CHANNEL_ID,
  124. follows: 5,
  125. }
  126. await followChannel(FIRST_CHANNEL_ID)
  127. await followChannel(FIRST_CHANNEL_ID)
  128. await followChannel(FIRST_CHANNEL_ID)
  129. await followChannel(FIRST_CHANNEL_ID)
  130. await followChannel(FIRST_CHANNEL_ID)
  131. let channelFollows = await getChannelFollows(FIRST_CHANNEL_ID)
  132. let mostFollowedChannels = await getMostFollowedChannels(30)
  133. let mostFollowedChannelsAllTime = await getMostFollowedChannelsAllTime(10)
  134. expect(channelFollows).toEqual(expectedChannelFollows)
  135. expect(mostFollowedChannels).toEqual([expectedChannelFollows])
  136. expect(mostFollowedChannelsAllTime).toEqual([expectedChannelFollows])
  137. expectedChannelFollows.follows--
  138. const unfollowChannelData = await unfollowChannel(FIRST_CHANNEL_ID)
  139. expect(unfollowChannelData).toEqual(expectedChannelFollows)
  140. channelFollows = await getChannelFollows(FIRST_CHANNEL_ID)
  141. mostFollowedChannels = await getMostFollowedChannels(30)
  142. mostFollowedChannelsAllTime = await getMostFollowedChannelsAllTime(10)
  143. expect(channelFollows).toEqual(expectedChannelFollows)
  144. expect(mostFollowedChannels).toEqual([expectedChannelFollows])
  145. expect(mostFollowedChannelsAllTime).toEqual([expectedChannelFollows])
  146. })
  147. it('should keep the channel follows non-negative', async () => {
  148. const expectedChannelFollows: ChannelFollowsInfo = {
  149. id: FIRST_CHANNEL_ID,
  150. follows: 0,
  151. }
  152. await followChannel(FIRST_CHANNEL_ID)
  153. await followChannel(FIRST_CHANNEL_ID)
  154. await unfollowChannel(FIRST_CHANNEL_ID)
  155. await unfollowChannel(FIRST_CHANNEL_ID)
  156. await unfollowChannel(FIRST_CHANNEL_ID)
  157. const channelFollows = await getChannelFollows(FIRST_CHANNEL_ID)
  158. const mostFollowedChannels = await getMostFollowedChannels(30)
  159. const mostFollowedChannelsAllTime = await getMostFollowedChannelsAllTime(10)
  160. expect(channelFollows).toEqual(expectedChannelFollows)
  161. expect(mostFollowedChannels).toEqual([expectedChannelFollows])
  162. expect(mostFollowedChannelsAllTime).toEqual([expectedChannelFollows])
  163. })
  164. it('should distinct follows of separate channels', async () => {
  165. const expectedFirstChannelFollows: ChannelFollowsInfo = {
  166. id: FIRST_CHANNEL_ID,
  167. follows: 1,
  168. }
  169. const expectedSecondChannelFollows: ChannelFollowsInfo = {
  170. id: SECOND_CHANNEL_ID,
  171. follows: 1,
  172. }
  173. const firstChannelFollowData = await followChannel(FIRST_CHANNEL_ID)
  174. const secondChannelFollowData = await followChannel(SECOND_CHANNEL_ID)
  175. expect(firstChannelFollowData).toEqual(expectedFirstChannelFollows)
  176. expect(secondChannelFollowData).toEqual(expectedSecondChannelFollows)
  177. expectedFirstChannelFollows.follows++
  178. await followChannel(FIRST_CHANNEL_ID)
  179. const firstChannelFollows = await getChannelFollows(FIRST_CHANNEL_ID)
  180. const secondChannelFollows = await getChannelFollows(SECOND_CHANNEL_ID)
  181. const mostFollowedChannels = await getMostFollowedChannels(30)
  182. const mostFollowedChannelsAllTime = await getMostFollowedChannelsAllTime(10)
  183. expect(firstChannelFollows).toEqual(expectedFirstChannelFollows)
  184. expect(secondChannelFollows).toEqual(expectedSecondChannelFollows)
  185. expect(mostFollowedChannels).toEqual([expectedFirstChannelFollows, expectedSecondChannelFollows])
  186. expect(mostFollowedChannelsAllTime).toEqual([expectedFirstChannelFollows, expectedSecondChannelFollows])
  187. })
  188. it('should properly rebuild the aggregate', async () => {
  189. const expectedFirstChannelFollows: ChannelFollowsInfo = {
  190. id: FIRST_CHANNEL_ID,
  191. follows: 3,
  192. }
  193. const expectedSecondChannelFollows: ChannelFollowsInfo = {
  194. id: SECOND_CHANNEL_ID,
  195. follows: 4,
  196. }
  197. const checkFollows = async () => {
  198. const firstChannelFollows = await getChannelFollows(FIRST_CHANNEL_ID)
  199. const secondChannelFollows = await getChannelFollows(SECOND_CHANNEL_ID)
  200. const mostFollowedChannels = await getMostFollowedChannels(30)
  201. const mostFollowedChannelsAllTime = await getMostFollowedChannelsAllTime(10)
  202. expect(firstChannelFollows).toEqual(expectedFirstChannelFollows)
  203. expect(secondChannelFollows).toEqual(expectedSecondChannelFollows)
  204. expect(mostFollowedChannels).toEqual([expectedSecondChannelFollows, expectedFirstChannelFollows])
  205. expect(mostFollowedChannelsAllTime).toEqual([expectedSecondChannelFollows, expectedFirstChannelFollows])
  206. }
  207. await followChannel(FIRST_CHANNEL_ID)
  208. await followChannel(FIRST_CHANNEL_ID)
  209. await followChannel(FIRST_CHANNEL_ID)
  210. await followChannel(SECOND_CHANNEL_ID)
  211. await followChannel(SECOND_CHANNEL_ID)
  212. await followChannel(SECOND_CHANNEL_ID)
  213. await followChannel(SECOND_CHANNEL_ID)
  214. await followChannel(SECOND_CHANNEL_ID)
  215. await unfollowChannel(SECOND_CHANNEL_ID)
  216. await checkFollows()
  217. await server.stop()
  218. aggregates = await buildAggregates()
  219. server = await createServer(mongoose, aggregates)
  220. query = createQueryFn(server)
  221. mutate = createMutationFn(server)
  222. await checkFollows()
  223. })
  224. it('should properly handle saving events across buckets', async () => {
  225. const eventsCount = TEST_BUCKET_SIZE * 2 + 1
  226. const expectedChannelFollows: ChannelFollowsInfo = {
  227. id: FIRST_CHANNEL_ID,
  228. follows: eventsCount,
  229. }
  230. for (let i = 0; i < eventsCount; i++) {
  231. await followChannel(FIRST_CHANNEL_ID)
  232. }
  233. const channelFollows = await getChannelFollows(FIRST_CHANNEL_ID)
  234. const mostFollowedChannels = await getMostFollowedChannels(30)
  235. const mostFollowedChannelsAllTime = await getMostFollowedChannelsAllTime(10)
  236. expect(channelFollows).toEqual(expectedChannelFollows)
  237. expect(mostFollowedChannels).toEqual([expectedChannelFollows])
  238. expect(mostFollowedChannelsAllTime).toEqual([expectedChannelFollows])
  239. })
  240. })