TpdsProjectFlusherTests.js 7.1 KB

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