SplitTestSessionHandlerTests.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. const Path = require('path')
  2. const SandboxedModule = require('sandboxed-module')
  3. const sinon = require('sinon')
  4. const { expect } = require('chai')
  5. const MODULE_PATH = Path.join(
  6. __dirname,
  7. '../../../../app/src/Features/SplitTests/SplitTestSessionHandler'
  8. )
  9. describe('SplitTestSessionHandler', function () {
  10. beforeEach(function () {
  11. this.SplitTestCache = {
  12. get: sinon.stub().resolves(),
  13. }
  14. this.SplitTestUserGetter = {}
  15. this.Metrics = {}
  16. this.SplitTestCache.get = sinon.stub().resolves(
  17. new Map(
  18. Object.entries({
  19. 'anon-test-1': {
  20. _id: '661f92a4669764bb03f73e37',
  21. name: 'anon-test-1',
  22. versions: [
  23. {
  24. versionNumber: 1,
  25. variants: [
  26. {
  27. name: 'enabled',
  28. },
  29. ],
  30. },
  31. ],
  32. },
  33. 'anon-test-2': {
  34. _id: '661f92a9d68ea711d6bf2df4',
  35. name: 'anon-test-2',
  36. versions: [
  37. {
  38. versionNumber: 1,
  39. variants: [
  40. {
  41. name: 'v-1',
  42. },
  43. {
  44. name: 'v-2',
  45. },
  46. ],
  47. },
  48. ],
  49. },
  50. })
  51. )
  52. )
  53. this.SplitTestSessionHandler = SandboxedModule.require(MODULE_PATH, {
  54. requires: {
  55. './SplitTestCache': this.SplitTestCache,
  56. './SplitTestUserGetter': this.SplitTestUserGetter,
  57. '@overleaf/metrics': this.Metrics,
  58. },
  59. })
  60. })
  61. it('should read from the splitTests field', async function () {
  62. const session = {
  63. splitTests: {
  64. 'anon-test-1': [
  65. {
  66. variantName: 'default',
  67. versionNumber: 1,
  68. phase: 'release',
  69. assignedAt: new Date(1712872800000), // 2024-04-11 22:00:00
  70. },
  71. ],
  72. 'anon-test-2': [
  73. {
  74. variantName: 'default',
  75. versionNumber: 1,
  76. phase: 'release',
  77. assignedAt: new Date(1712307600000), // 2024-04-05 09:00:00
  78. },
  79. {
  80. variantName: 'v-2',
  81. versionNumber: 2,
  82. phase: 'release',
  83. assignedAt: new Date(1712581200000), // 2024-04-08 13:00:00
  84. },
  85. ],
  86. },
  87. sta: ``,
  88. }
  89. const assignments =
  90. await this.SplitTestSessionHandler.promises.getAssignments(session)
  91. expect(assignments).to.deep.equal({
  92. 'anon-test-1': [
  93. {
  94. variantName: 'default',
  95. versionNumber: 1,
  96. phase: 'release',
  97. assignedAt: new Date(1712872800000),
  98. },
  99. ],
  100. 'anon-test-2': [
  101. {
  102. variantName: 'default',
  103. versionNumber: 1,
  104. phase: 'release',
  105. assignedAt: new Date(1712307600000),
  106. },
  107. {
  108. variantName: 'v-2',
  109. versionNumber: 2,
  110. phase: 'release',
  111. assignedAt: new Date(1712581200000),
  112. },
  113. ],
  114. })
  115. })
  116. it('should read from the sta field', async function () {
  117. this.SplitTestCache.get = sinon.stub().resolves(
  118. new Map(
  119. Object.entries({
  120. 'anon-test-1': {
  121. _id: '661f92a4669764bb03f73e37',
  122. name: 'anon-test-1',
  123. versions: [
  124. {
  125. versionNumber: 1,
  126. variants: [
  127. {
  128. name: 'enabled',
  129. },
  130. ],
  131. },
  132. ],
  133. },
  134. 'anon-test-2': {
  135. _id: '661f92a9d68ea711d6bf2df4',
  136. name: 'anon-test-2',
  137. versions: [
  138. {
  139. versionNumber: 1,
  140. variants: [
  141. {
  142. name: 'v-1',
  143. },
  144. {
  145. name: 'v-2',
  146. },
  147. ],
  148. },
  149. ],
  150. },
  151. })
  152. )
  153. )
  154. const session = {
  155. sta: `Zh+SpGaXZLsD9z43_1=d:sbrvs0;Zh+SqdaOpxHWvy30_1=d:sbtqg0;Zh+SqdaOpxHWvy30_2=1:sbsi00`,
  156. }
  157. const assignments =
  158. await this.SplitTestSessionHandler.promises.getAssignments(session)
  159. expect(assignments).to.deep.equal({
  160. 'anon-test-1': [
  161. {
  162. variantName: 'default',
  163. versionNumber: 1,
  164. phase: 'release',
  165. assignedAt: new Date(1712829600000),
  166. },
  167. ],
  168. 'anon-test-2': [
  169. {
  170. variantName: 'default',
  171. versionNumber: 1,
  172. phase: 'release',
  173. assignedAt: new Date(1712916000000),
  174. },
  175. {
  176. variantName: 'v-2',
  177. versionNumber: 2,
  178. phase: 'release',
  179. assignedAt: new Date(1712858400000),
  180. },
  181. ],
  182. })
  183. })
  184. it('should deduplicate entries from the sta field', async function () {
  185. this.SplitTestCache.get = sinon.stub().resolves(
  186. new Map(
  187. Object.entries({
  188. 'anon-test-1': {
  189. _id: '661f92a4669764bb03f73e37',
  190. name: 'anon-test-1',
  191. versions: [
  192. {
  193. versionNumber: 1,
  194. variants: [
  195. {
  196. name: 'enabled',
  197. },
  198. ],
  199. },
  200. ],
  201. },
  202. 'anon-test-2': {
  203. _id: '661f92a9d68ea711d6bf2df4',
  204. name: 'anon-test-2',
  205. versions: [
  206. {
  207. versionNumber: 1,
  208. variants: [
  209. {
  210. name: 'v-1',
  211. },
  212. {
  213. name: 'v-2',
  214. },
  215. ],
  216. },
  217. ],
  218. },
  219. })
  220. )
  221. )
  222. const session = {
  223. sta: `Zh+SpGaXZLsD9z43_1=d:sbrvs0;Zh+SqdaOpxHWvy30_1=d:sbtqg0;Zh+SqdaOpxHWvy30_1=d:sbtqg0;Zh+SpGaXZLsD9z43_1=d:sbrvs0;Zh+SqdaOpxHWvy30_2=1:sbsi00;Zh+SqdaOpxHWvy30_1=d:sbtqg0`,
  224. }
  225. const assignments =
  226. await this.SplitTestSessionHandler.promises.getAssignments(session)
  227. expect(assignments).to.deep.equal({
  228. 'anon-test-1': [
  229. {
  230. variantName: 'default',
  231. versionNumber: 1,
  232. phase: 'release',
  233. assignedAt: new Date(1712829600000),
  234. },
  235. ],
  236. 'anon-test-2': [
  237. {
  238. variantName: 'default',
  239. versionNumber: 1,
  240. phase: 'release',
  241. assignedAt: new Date(1712916000000),
  242. },
  243. {
  244. variantName: 'v-2',
  245. versionNumber: 2,
  246. phase: 'release',
  247. assignedAt: new Date(1712858400000),
  248. },
  249. ],
  250. })
  251. })
  252. it('should merge assignments from both splitTests and sta fields', async function () {
  253. const session = {
  254. splitTests: {
  255. 'anon-test-1': [
  256. {
  257. variantName: 'default',
  258. versionNumber: 1,
  259. phase: 'release',
  260. assignedAt: new Date(1712872800000),
  261. },
  262. ],
  263. 'anon-test-2': [
  264. {
  265. variantName: 'default',
  266. versionNumber: 1,
  267. phase: 'release',
  268. assignedAt: new Date(1712307600000),
  269. },
  270. ],
  271. },
  272. sta: `Zh+SqdaOpxHWvy30_2=1:sbsi00`,
  273. }
  274. const assignments =
  275. await this.SplitTestSessionHandler.promises.getAssignments(session)
  276. expect(assignments).to.deep.equal({
  277. 'anon-test-1': [
  278. {
  279. variantName: 'default',
  280. versionNumber: 1,
  281. phase: 'release',
  282. assignedAt: new Date(1712872800000),
  283. },
  284. ],
  285. 'anon-test-2': [
  286. {
  287. variantName: 'v-2',
  288. versionNumber: 2,
  289. phase: 'release',
  290. assignedAt: new Date(1712858400000),
  291. },
  292. {
  293. variantName: 'default',
  294. versionNumber: 1,
  295. phase: 'release',
  296. assignedAt: new Date(1712307600000),
  297. },
  298. ],
  299. })
  300. })
  301. })