TpdsProjectFlusherTests.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. const { expect } = require('chai')
  2. const sinon = require('sinon')
  3. const SandboxedModule = require('sandboxed-module')
  4. const { ObjectId } = require('mongodb')
  5. const { Project } = require('../helpers/models/Project')
  6. const MODULE_PATH =
  7. '../../../../app/src/Features/ThirdPartyDataStore/TpdsProjectFlusher'
  8. describe('TpdsProjectFlusher', function () {
  9. beforeEach(function () {
  10. this.project = { _id: ObjectId() }
  11. this.folder = { _id: ObjectId() }
  12. this.docs = {
  13. '/doc/one': {
  14. _id: 'mock-doc-1',
  15. lines: ['one'],
  16. rev: 5,
  17. folder: this.folder,
  18. },
  19. '/doc/two': {
  20. _id: 'mock-doc-2',
  21. lines: ['two'],
  22. rev: 6,
  23. folder: this.folder,
  24. },
  25. }
  26. this.files = {
  27. '/file/one': { _id: 'mock-file-1', rev: 7, folder: this.folder },
  28. '/file/two': { _id: 'mock-file-2', rev: 8, folder: this.folder },
  29. }
  30. this.DocumentUpdaterHandler = {
  31. promises: {
  32. flushProjectToMongo: sinon.stub().resolves(),
  33. },
  34. }
  35. this.ProjectGetter = {
  36. promises: {
  37. getProject: sinon.stub().resolves(this.project),
  38. },
  39. }
  40. this.ProjectEntityHandler = {
  41. promises: {
  42. getAllDocs: sinon.stub().withArgs(this.project._id).resolves(this.docs),
  43. getAllFiles: sinon
  44. .stub()
  45. .withArgs(this.project._id)
  46. .resolves(this.files),
  47. },
  48. }
  49. this.TpdsUpdateSender = {
  50. promises: {
  51. addDoc: sinon.stub().resolves(),
  52. addFile: sinon.stub().resolves(),
  53. },
  54. }
  55. this.ProjectMock = sinon.mock(Project)
  56. this.TpdsProjectFlusher = SandboxedModule.require(MODULE_PATH, {
  57. requires: {
  58. '../DocumentUpdater/DocumentUpdaterHandler':
  59. this.DocumentUpdaterHandler,
  60. '../Project/ProjectGetter': this.ProjectGetter,
  61. '../Project/ProjectEntityHandler': this.ProjectEntityHandler,
  62. '../../models/Project': { Project },
  63. './TpdsUpdateSender': this.TpdsUpdateSender,
  64. },
  65. })
  66. })
  67. afterEach(function () {
  68. this.ProjectMock.restore()
  69. })
  70. describe('flushProjectToTpds', function () {
  71. describe('usually', function () {
  72. beforeEach(async function () {
  73. await this.TpdsProjectFlusher.promises.flushProjectToTpds(
  74. this.project._id
  75. )
  76. })
  77. it('should flush the project from the doc updater', function () {
  78. expect(
  79. this.DocumentUpdaterHandler.promises.flushProjectToMongo
  80. ).to.have.been.calledWith(this.project._id)
  81. })
  82. it('should flush each doc to the TPDS', function () {
  83. for (const [path, doc] of Object.entries(this.docs)) {
  84. expect(this.TpdsUpdateSender.promises.addDoc).to.have.been.calledWith(
  85. {
  86. projectId: this.project._id,
  87. docId: doc._id,
  88. projectName: this.project.name,
  89. rev: doc.rev,
  90. path,
  91. folderId: this.folder._id,
  92. }
  93. )
  94. }
  95. })
  96. it('should flush each file to the TPDS', function () {
  97. for (const [path, file] of Object.entries(this.files)) {
  98. expect(
  99. this.TpdsUpdateSender.promises.addFile
  100. ).to.have.been.calledWith({
  101. projectId: this.project._id,
  102. fileId: file._id,
  103. projectName: this.project.name,
  104. rev: file.rev,
  105. path,
  106. folderId: this.folder._id,
  107. })
  108. }
  109. })
  110. })
  111. describe('when a TPDS flush is pending', function () {
  112. beforeEach(async function () {
  113. this.project.deferredTpdsFlushCounter = 2
  114. this.ProjectMock.expects('updateOne')
  115. .withArgs(
  116. {
  117. _id: this.project._id,
  118. deferredTpdsFlushCounter: { $lte: 2 },
  119. },
  120. { $set: { deferredTpdsFlushCounter: 0 } }
  121. )
  122. .chain('exec')
  123. .resolves()
  124. await this.TpdsProjectFlusher.promises.flushProjectToTpds(
  125. this.project._id
  126. )
  127. })
  128. it('resets the deferred flush counter', function () {
  129. this.ProjectMock.verify()
  130. })
  131. })
  132. })
  133. describe('deferProjectFlushToTpds', function () {
  134. beforeEach(async function () {
  135. this.ProjectMock.expects('updateOne')
  136. .withArgs(
  137. {
  138. _id: this.project._id,
  139. },
  140. { $inc: { deferredTpdsFlushCounter: 1 } }
  141. )
  142. .chain('exec')
  143. .resolves()
  144. await this.TpdsProjectFlusher.promises.deferProjectFlushToTpds(
  145. this.project._id
  146. )
  147. })
  148. it('increments the deferred flush counter', function () {
  149. this.ProjectMock.verify()
  150. })
  151. })
  152. describe('flushProjectToTpdsIfNeeded', function () {
  153. let cases = [0, undefined]
  154. cases.forEach(counterValue => {
  155. describe(`when the deferred flush counter is ${counterValue}`, function () {
  156. beforeEach(async function () {
  157. this.project.deferredTpdsFlushCounter = counterValue
  158. await this.TpdsProjectFlusher.promises.flushProjectToTpdsIfNeeded(
  159. this.project._id
  160. )
  161. })
  162. it("doesn't flush the project from the doc updater", function () {
  163. expect(this.DocumentUpdaterHandler.promises.flushProjectToMongo).not
  164. .to.have.been.called
  165. })
  166. it("doesn't flush any doc", function () {
  167. expect(this.TpdsUpdateSender.promises.addDoc).not.to.have.been.called
  168. })
  169. it("doesn't flush any file", function () {
  170. expect(this.TpdsUpdateSender.promises.addFile).not.to.have.been.called
  171. })
  172. })
  173. })
  174. cases = [1, 2]
  175. cases.forEach(counterValue => {
  176. describe(`when the deferred flush counter is ${counterValue}`, function () {
  177. beforeEach(async function () {
  178. this.project.deferredTpdsFlushCounter = counterValue
  179. this.ProjectMock.expects('updateOne')
  180. .withArgs(
  181. {
  182. _id: this.project._id,
  183. deferredTpdsFlushCounter: { $lte: counterValue },
  184. },
  185. { $set: { deferredTpdsFlushCounter: 0 } }
  186. )
  187. .chain('exec')
  188. .resolves()
  189. await this.TpdsProjectFlusher.promises.flushProjectToTpdsIfNeeded(
  190. this.project._id
  191. )
  192. })
  193. it('flushes the project from the doc updater', function () {
  194. expect(
  195. this.DocumentUpdaterHandler.promises.flushProjectToMongo
  196. ).to.have.been.calledWith(this.project._id)
  197. })
  198. it('flushes each doc to the TPDS', function () {
  199. for (const [path, doc] of Object.entries(this.docs)) {
  200. expect(
  201. this.TpdsUpdateSender.promises.addDoc
  202. ).to.have.been.calledWith({
  203. projectId: this.project._id,
  204. docId: doc._id,
  205. projectName: this.project.name,
  206. rev: doc.rev,
  207. path,
  208. folderId: this.folder._id,
  209. })
  210. }
  211. })
  212. it('flushes each file to the TPDS', function () {
  213. for (const [path, file] of Object.entries(this.files)) {
  214. expect(
  215. this.TpdsUpdateSender.promises.addFile
  216. ).to.have.been.calledWith({
  217. projectId: this.project._id,
  218. fileId: file._id,
  219. projectName: this.project.name,
  220. rev: file.rev,
  221. path,
  222. folderId: this.folder._id,
  223. })
  224. }
  225. })
  226. it('resets the deferred flush counter', function () {
  227. this.ProjectMock.verify()
  228. })
  229. })
  230. })
  231. })
  232. })