MongoManagerTests.coffee 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. sinon = require('sinon')
  2. chai = require('chai')
  3. should = chai.should()
  4. expect = chai.expect
  5. modulePath = "../../../../app/js/MongoManager.js"
  6. SandboxedModule = require('sandboxed-module')
  7. {ObjectId} = require("mongojs")
  8. tk = require "timekeeper"
  9. describe "MongoManager", ->
  10. beforeEach ->
  11. tk.freeze(new Date())
  12. @MongoManager = SandboxedModule.require modulePath, requires:
  13. "./mongojs" : { db: @db = {}, ObjectId: ObjectId }
  14. @callback = sinon.stub()
  15. @doc_id = ObjectId().toString()
  16. @project_id = ObjectId().toString()
  17. afterEach ->
  18. tk.reset()
  19. describe "getLastCompressedUpdate", ->
  20. beforeEach ->
  21. @update = "mock-update"
  22. @db.docHistory = {}
  23. @db.docHistory.find = sinon.stub().returns @db.docHistory
  24. @db.docHistory.sort = sinon.stub().returns @db.docHistory
  25. @db.docHistory.limit = sinon.stub().returns @db.docHistory
  26. @db.docHistory.toArray = sinon.stub().callsArgWith(0, null, [@update])
  27. @MongoManager.getLastCompressedUpdate @doc_id, @callback
  28. it "should find the updates for the doc", ->
  29. @db.docHistory.find
  30. .calledWith(doc_id: ObjectId(@doc_id))
  31. .should.equal true
  32. it "should limit to one result", ->
  33. @db.docHistory.limit
  34. .calledWith(1)
  35. .should.equal true
  36. it "should sort in descending version order", ->
  37. @db.docHistory.sort
  38. .calledWith(v: -1)
  39. .should.equal true
  40. it "should call the call back with the update", ->
  41. @callback.calledWith(null, @update).should.equal true
  42. describe "deleteCompressedUpdate", ->
  43. beforeEach ->
  44. @update_id = ObjectId().toString()
  45. @db.docHistory =
  46. remove: sinon.stub().callsArg(1)
  47. @MongoManager.deleteCompressedUpdate(@update_id, @callback)
  48. it "should remove the update", ->
  49. @db.docHistory.remove
  50. .calledWith(_id: ObjectId(@update_id))
  51. .should.equal true
  52. it "should call the callback", ->
  53. @callback.called.should.equal true
  54. describe "popLastCompressedUpdate", ->
  55. describe "when there is no last update", ->
  56. beforeEach ->
  57. @MongoManager.getLastCompressedUpdate = sinon.stub().callsArgWith(1, null, null)
  58. @MongoManager.deleteCompressedUpdate = sinon.stub()
  59. @MongoManager.popLastCompressedUpdate @doc_id, @callback
  60. it "should get the last update", ->
  61. @MongoManager.getLastCompressedUpdate
  62. .calledWith(@doc_id)
  63. .should.equal true
  64. it "should not try to delete the last update", ->
  65. @MongoManager.deleteCompressedUpdate.called.should.equal false
  66. it "should call the callback with no update", ->
  67. @callback.calledWith(null, null).should.equal true
  68. describe "when there is an update", ->
  69. beforeEach ->
  70. @update = { _id: Object() }
  71. @MongoManager.getLastCompressedUpdate = sinon.stub().callsArgWith(1, null, @update)
  72. @MongoManager.deleteCompressedUpdate = sinon.stub().callsArgWith(1, null)
  73. @MongoManager.popLastCompressedUpdate @doc_id, @callback
  74. it "should get the last update", ->
  75. @MongoManager.getLastCompressedUpdate
  76. .calledWith(@doc_id)
  77. .should.equal true
  78. it "should delete the last update", ->
  79. @MongoManager.deleteCompressedUpdate
  80. .calledWith(@update._id)
  81. .should.equal true
  82. it "should call the callback with the update", ->
  83. @callback.calledWith(null, @update).should.equal true
  84. describe "insertCompressedUpdate", ->
  85. beforeEach ->
  86. @update = { op: "op", meta: "meta", v: "v"}
  87. @db.docHistory =
  88. insert: sinon.stub().callsArg(1)
  89. describe "temporarly", ->
  90. beforeEach ->
  91. @MongoManager.insertCompressedUpdate @project_id, @doc_id, @update, true, @callback
  92. it "should insert the update with a expiresAt field one week away", ->
  93. @db.docHistory.insert
  94. .calledWith({
  95. project_id: ObjectId(@project_id),
  96. doc_id: ObjectId(@doc_id),
  97. op: @update.op,
  98. meta: @update.meta,
  99. v: @update.v
  100. expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)
  101. })
  102. .should.equal true
  103. it "should call the callback", ->
  104. @callback.called.should.equal true
  105. describe "permanenty", ->
  106. beforeEach ->
  107. @MongoManager.insertCompressedUpdate @project_id, @doc_id, @update, false, @callback
  108. it "should insert the update with no expiresAt field", ->
  109. @db.docHistory.insert
  110. .calledWith({
  111. project_id: ObjectId(@project_id),
  112. doc_id: ObjectId(@doc_id),
  113. op: @update.op,
  114. meta: @update.meta,
  115. v: @update.v
  116. })
  117. .should.equal true
  118. it "should call the callback", ->
  119. @callback.called.should.equal true
  120. describe "insertCompressedUpdates", ->
  121. beforeEach (done) ->
  122. @updates = [ "mock-update-1", "mock-update-2" ]
  123. @MongoManager.insertCompressedUpdate = sinon.stub().callsArg(4)
  124. @MongoManager.insertCompressedUpdates @project_id, @doc_id, @updates, @temporary = true, (args...) =>
  125. @callback(args...)
  126. done()
  127. it "should insert each update", ->
  128. for update in @updates
  129. @MongoManager.insertCompressedUpdate
  130. .calledWith(@project_id, @doc_id, update, @temporary)
  131. .should.equal true
  132. it "should call the callback", ->
  133. @callback.called.should.equal true
  134. describe "getDocUpdates", ->
  135. beforeEach ->
  136. @updates = ["mock-update"]
  137. @db.docHistory = {}
  138. @db.docHistory.find = sinon.stub().returns @db.docHistory
  139. @db.docHistory.sort = sinon.stub().returns @db.docHistory
  140. @db.docHistory.limit = sinon.stub().returns @db.docHistory
  141. @db.docHistory.toArray = sinon.stub().callsArgWith(0, null, @updates)
  142. @from = 42
  143. @to = 55
  144. describe "with a to version", ->
  145. beforeEach ->
  146. @MongoManager.getDocUpdates @doc_id, from: @from, to: @to, @callback
  147. it "should find the all updates between the to and from versions", ->
  148. @db.docHistory.find
  149. .calledWith({
  150. doc_id: ObjectId(@doc_id)
  151. v: { $gte: @from, $lte: @to }
  152. })
  153. .should.equal true
  154. it "should sort in descending version order", ->
  155. @db.docHistory.sort
  156. .calledWith("v": -1)
  157. .should.equal true
  158. it "should not limit the results", ->
  159. @db.docHistory.limit
  160. .called.should.equal false
  161. it "should call the call back with the updates", ->
  162. @callback.calledWith(null, @updates).should.equal true
  163. describe "without a to version", ->
  164. beforeEach ->
  165. @MongoManager.getDocUpdates @doc_id, from: @from, @callback
  166. it "should find the all updates after the from version", ->
  167. @db.docHistory.find
  168. .calledWith({
  169. doc_id: ObjectId(@doc_id)
  170. v: { $gte: @from }
  171. })
  172. .should.equal true
  173. it "should call the call back with the updates", ->
  174. @callback.calledWith(null, @updates).should.equal true
  175. describe "with a limit", ->
  176. beforeEach ->
  177. @MongoManager.getDocUpdates @doc_id, from: @from, limit: @limit = 10, @callback
  178. it "should limit the results", ->
  179. @db.docHistory.limit
  180. .calledWith(@limit)
  181. .should.equal true
  182. describe "getDocUpdates", ->
  183. beforeEach ->
  184. @updates = ["mock-update"]
  185. @db.docHistory = {}
  186. @db.docHistory.find = sinon.stub().returns @db.docHistory
  187. @db.docHistory.sort = sinon.stub().returns @db.docHistory
  188. @db.docHistory.limit = sinon.stub().returns @db.docHistory
  189. @db.docHistory.toArray = sinon.stub().callsArgWith(0, null, @updates)
  190. @before = Date.now()
  191. describe "with a before timestamp", ->
  192. beforeEach ->
  193. @MongoManager.getProjectUpdates @project_id, before: @before, @callback
  194. it "should find the all updates before the timestamp", ->
  195. @db.docHistory.find
  196. .calledWith({
  197. project_id: ObjectId(@project_id)
  198. "meta.end_ts": { $lt: @before }
  199. })
  200. .should.equal true
  201. it "should sort in descending version order", ->
  202. @db.docHistory.sort
  203. .calledWith("meta.end_ts": -1)
  204. .should.equal true
  205. it "should not limit the results", ->
  206. @db.docHistory.limit
  207. .called.should.equal false
  208. it "should call the call back with the updates", ->
  209. @callback.calledWith(null, @updates).should.equal true
  210. describe "without a before timestamp", ->
  211. beforeEach ->
  212. @MongoManager.getProjectUpdates @project_id, {}, @callback
  213. it "should find the all updates", ->
  214. @db.docHistory.find
  215. .calledWith({
  216. project_id: ObjectId(@project_id)
  217. })
  218. .should.equal true
  219. it "should call the call back with the updates", ->
  220. @callback.calledWith(null, @updates).should.equal true
  221. describe "with a limit", ->
  222. beforeEach ->
  223. @MongoManager.getProjectUpdates @project_id, before: @before, limit: @limit = 10, @callback
  224. it "should limit the results", ->
  225. @db.docHistory.limit
  226. .calledWith(@limit)
  227. .should.equal true
  228. describe "backportProjectId", ->
  229. beforeEach ->
  230. @db.docHistory =
  231. update: sinon.stub().callsArg(3)
  232. @MongoManager.backportProjectId @project_id, @doc_id, @callback
  233. it "should insert the project_id into all entries for the doc_id which don't have it set", ->
  234. @db.docHistory.update
  235. .calledWith({
  236. doc_id: ObjectId(@doc_id)
  237. project_id: { $exists: false }
  238. }, {
  239. $set: { project_id: ObjectId(@project_id) }
  240. }, {
  241. multi: true
  242. })
  243. .should.equal true
  244. it "should call the callback", ->
  245. @callback.called.should.equal true
  246. describe "getProjectMetaData", ->
  247. beforeEach ->
  248. @metadata = { "mock": "metadata" }
  249. @db.projectHistoryMetaData =
  250. find: sinon.stub().callsArgWith(1, null, [@metadata])
  251. @MongoManager.getProjectMetaData @project_id, @callback
  252. it "should look up the meta data in the db", ->
  253. @db.projectHistoryMetaData.find
  254. .calledWith({ project_id: ObjectId(@project_id) })
  255. .should.equal true
  256. it "should return the metadata", ->
  257. @callback.calledWith(null, @metadata).should.equal true
  258. describe "setProjectMetaData", ->
  259. beforeEach ->
  260. @metadata = { "mock": "metadata" }
  261. @db.projectHistoryMetaData =
  262. update: sinon.stub().callsArgWith(3, null, [@metadata])
  263. @MongoManager.setProjectMetaData @project_id, @metadata, @callback
  264. it "should upsert the metadata into the DB", ->
  265. @db.projectHistoryMetaData.update
  266. .calledWith({
  267. project_id: ObjectId(@project_id)
  268. }, {
  269. $set: @metadata
  270. }, {
  271. upsert: true
  272. })
  273. .should.equal true
  274. it "should call the callback", ->
  275. @callback.called.should.equal true