UpdatingDocsTests.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. const { ObjectId } = require('mongodb-legacy')
  2. const DocstoreApp = require('./helpers/DocstoreApp')
  3. const DocstoreClient = require('./helpers/DocstoreClient')
  4. describe('Applying updates to a doc', function () {
  5. beforeEach(async function () {
  6. this.project_id = new ObjectId()
  7. this.doc_id = new ObjectId()
  8. this.originalLines = ['original', 'lines']
  9. this.newLines = ['new', 'lines']
  10. this.originalRanges = {
  11. changes: [
  12. {
  13. id: new ObjectId().toString(),
  14. op: { i: 'foo', p: 3 },
  15. meta: {
  16. user_id: new ObjectId().toString(),
  17. ts: new Date().toString(),
  18. },
  19. },
  20. ],
  21. }
  22. this.newRanges = {
  23. changes: [
  24. {
  25. id: new ObjectId().toString(),
  26. op: { i: 'bar', p: 6 },
  27. meta: {
  28. user_id: new ObjectId().toString(),
  29. ts: new Date().toString(),
  30. },
  31. },
  32. ],
  33. }
  34. this.version = 42
  35. await DocstoreApp.ensureRunning()
  36. await DocstoreClient.createDoc(
  37. this.project_id,
  38. this.doc_id,
  39. this.originalLines,
  40. this.version,
  41. this.originalRanges
  42. )
  43. })
  44. describe('when nothing has been updated', function () {
  45. beforeEach(async function () {
  46. this.body = await DocstoreClient.updateDoc(
  47. this.project_id,
  48. this.doc_id,
  49. this.originalLines,
  50. this.version,
  51. this.originalRanges
  52. )
  53. })
  54. it('should return modified = false', function () {
  55. this.body.modified.should.equal(false)
  56. })
  57. it('should not update the doc in the API', async function () {
  58. const doc = await DocstoreClient.getDoc(this.project_id, this.doc_id)
  59. doc.lines.should.deep.equal(this.originalLines)
  60. doc.version.should.equal(this.version)
  61. doc.ranges.should.deep.equal(this.originalRanges)
  62. })
  63. })
  64. describe('when the lines have changed', function () {
  65. beforeEach(async function () {
  66. this.body = await DocstoreClient.updateDoc(
  67. this.project_id,
  68. this.doc_id,
  69. this.newLines,
  70. this.version,
  71. this.originalRanges
  72. )
  73. })
  74. it('should return modified = true', function () {
  75. this.body.modified.should.equal(true)
  76. })
  77. it('should return the rev', function () {
  78. this.body.rev.should.equal(2)
  79. })
  80. it('should update the doc in the API', async function () {
  81. const doc = await DocstoreClient.getDoc(this.project_id, this.doc_id)
  82. doc.lines.should.deep.equal(this.newLines)
  83. doc.version.should.equal(this.version)
  84. doc.ranges.should.deep.equal(this.originalRanges)
  85. })
  86. })
  87. describe('when the version has changed', function () {
  88. beforeEach(async function () {
  89. this.body = await DocstoreClient.updateDoc(
  90. this.project_id,
  91. this.doc_id,
  92. this.originalLines,
  93. this.version + 1,
  94. this.originalRanges
  95. )
  96. })
  97. it('should return modified = true', function () {
  98. this.body.modified.should.equal(true)
  99. })
  100. it('should return the rev', function () {
  101. this.body.rev.should.equal(1)
  102. })
  103. it('should update the doc in the API', async function () {
  104. const doc = await DocstoreClient.getDoc(this.project_id, this.doc_id)
  105. doc.lines.should.deep.equal(this.originalLines)
  106. doc.version.should.equal(this.version + 1)
  107. doc.ranges.should.deep.equal(this.originalRanges)
  108. })
  109. })
  110. describe('when the version was decremented', function () {
  111. let statusCode
  112. beforeEach(async function () {
  113. try {
  114. this.body = await DocstoreClient.updateDoc(
  115. this.project_id,
  116. this.doc_id,
  117. this.newLines,
  118. this.version - 1,
  119. this.newRanges
  120. )
  121. } catch (error) {
  122. statusCode = error.info.status
  123. }
  124. })
  125. it('should return 409', function () {
  126. statusCode.should.equal(409)
  127. })
  128. it('should not update the doc in the API', async function () {
  129. const doc = await DocstoreClient.getDoc(this.project_id, this.doc_id)
  130. doc.lines.should.deep.equal(this.originalLines)
  131. doc.version.should.equal(this.version)
  132. doc.ranges.should.deep.equal(this.originalRanges)
  133. })
  134. })
  135. describe('when the ranges have changed', function () {
  136. beforeEach(async function () {
  137. this.body = await DocstoreClient.updateDoc(
  138. this.project_id,
  139. this.doc_id,
  140. this.originalLines,
  141. this.version,
  142. this.newRanges
  143. )
  144. })
  145. it('should return modified = true', function () {
  146. this.body.modified.should.equal(true)
  147. })
  148. it('should return the rev', function () {
  149. this.body.rev.should.equal(2)
  150. })
  151. it('should update the doc in the API', async function () {
  152. const doc = await DocstoreClient.getDoc(this.project_id, this.doc_id)
  153. doc.lines.should.deep.equal(this.originalLines)
  154. doc.version.should.equal(this.version)
  155. doc.ranges.should.deep.equal(this.newRanges)
  156. })
  157. })
  158. describe('when the doc does not exist', function () {
  159. beforeEach(async function () {
  160. this.missing_doc_id = new ObjectId()
  161. this.body = await DocstoreClient.updateDoc(
  162. this.project_id,
  163. this.missing_doc_id,
  164. this.originalLines,
  165. 0,
  166. this.originalRanges
  167. )
  168. })
  169. it('should create the doc', function () {
  170. this.body.rev.should.equal(1)
  171. })
  172. it('should be retreivable', async function () {
  173. const doc = await DocstoreClient.getDoc(
  174. this.project_id,
  175. this.missing_doc_id
  176. )
  177. doc.lines.should.deep.equal(this.originalLines)
  178. doc.version.should.equal(0)
  179. doc.ranges.should.deep.equal(this.originalRanges)
  180. })
  181. })
  182. describe('when malformed doc lines are provided', function () {
  183. describe('when the lines are not an array', function () {
  184. let statusCode
  185. beforeEach(async function () {
  186. try {
  187. this.body = await DocstoreClient.updateDoc(
  188. this.project_id,
  189. this.doc_id,
  190. { foo: 'bar' },
  191. this.version,
  192. this.originalRanges
  193. )
  194. } catch (error) {
  195. statusCode = error.info.status
  196. }
  197. })
  198. it('should return 400', function () {
  199. statusCode.should.equal(400)
  200. })
  201. it('should not update the doc in the API', async function () {
  202. const doc = await DocstoreClient.getDoc(this.project_id, this.doc_id)
  203. doc.lines.should.deep.equal(this.originalLines)
  204. })
  205. })
  206. describe('when the lines are not present', function () {
  207. let statusCode
  208. beforeEach(async function () {
  209. try {
  210. this.body = await DocstoreClient.updateDoc(
  211. this.project_id,
  212. this.doc_id,
  213. null,
  214. this.version,
  215. this.originalRanges
  216. )
  217. } catch (error) {
  218. statusCode = error.info.status
  219. }
  220. })
  221. it('should return 400', function () {
  222. statusCode.should.equal(400)
  223. })
  224. it('should not update the doc in the API', async function () {
  225. const doc = await DocstoreClient.getDoc(this.project_id, this.doc_id)
  226. doc.lines.should.deep.equal(this.originalLines)
  227. })
  228. })
  229. })
  230. describe('when no version is provided', function () {
  231. let statusCode
  232. beforeEach(async function () {
  233. try {
  234. this.body = await DocstoreClient.updateDoc(
  235. this.project_id,
  236. this.doc_id,
  237. this.originalLines,
  238. null,
  239. this.originalRanges
  240. )
  241. } catch (error) {
  242. statusCode = error.info.status
  243. }
  244. })
  245. it('should return 400', function () {
  246. statusCode.should.equal(400)
  247. })
  248. it('should not update the doc in the API', async function () {
  249. const doc = await DocstoreClient.getDoc(this.project_id, this.doc_id)
  250. doc.lines.should.deep.equal(this.originalLines)
  251. doc.version.should.equal(this.version)
  252. })
  253. })
  254. describe('when the content is large', function () {
  255. beforeEach(async function () {
  256. const line = new Array(1025).join('x') // 1kb
  257. this.largeLines = Array.apply(null, Array(1024)).map(() => line) // 1mb
  258. this.body = await DocstoreClient.updateDoc(
  259. this.project_id,
  260. this.doc_id,
  261. this.largeLines,
  262. this.version,
  263. this.originalRanges
  264. )
  265. })
  266. it('should return modified = true', function () {
  267. this.body.modified.should.equal(true)
  268. })
  269. it('should update the doc in the API', async function () {
  270. const doc = await DocstoreClient.getDoc(this.project_id, this.doc_id)
  271. doc.lines.should.deep.equal(this.largeLines)
  272. })
  273. })
  274. describe('when there is a large json payload', function () {
  275. beforeEach(async function () {
  276. const line = new Array(1025).join('x') // 1kb
  277. this.largeLines = Array.apply(null, Array(1024)).map(() => line) // 1kb
  278. this.originalRanges.padding = Array.apply(null, Array(2049)).map(
  279. () => line
  280. ) // 2mb + 1kb
  281. this.body = await DocstoreClient.updateDoc(
  282. this.project_id,
  283. this.doc_id,
  284. this.largeLines,
  285. this.version,
  286. this.originalRanges
  287. )
  288. })
  289. it('should return modified = true', function () {
  290. this.body.modified.should.equal(true)
  291. })
  292. it('should update the doc in the API', async function () {
  293. const doc = await DocstoreClient.getDoc(this.project_id, this.doc_id)
  294. doc.lines.should.deep.equal(this.largeLines)
  295. })
  296. })
  297. describe('when the document body is too large', function () {
  298. let statusCode, body
  299. beforeEach(async function () {
  300. const line = new Array(1025).join('x') // 1kb
  301. this.largeLines = Array.apply(null, Array(2049)).map(() => line) // 2mb + 1kb
  302. try {
  303. this.body = await DocstoreClient.updateDoc(
  304. this.project_id,
  305. this.doc_id,
  306. this.largeLines,
  307. this.version,
  308. this.originalRanges
  309. )
  310. } catch (error) {
  311. statusCode = error.info.status
  312. body = error.body
  313. }
  314. })
  315. it('should return 413', function () {
  316. statusCode.should.equal(413)
  317. })
  318. it('should report body too large', function () {
  319. body.should.equal('document body too large')
  320. })
  321. it('should not update the doc in the API', async function () {
  322. const doc = await DocstoreClient.getDoc(this.project_id, this.doc_id)
  323. doc.lines.should.deep.equal(this.originalLines)
  324. })
  325. })
  326. describe('when the json payload is too large', function () {
  327. beforeEach(async function () {
  328. const line = new Array(1024).join('x') // 1 KB
  329. this.largeLines = new Array(8192).fill(line) // 8 MB
  330. this.originalRanges.padding = new Array(6144).fill(line) // 6 MB
  331. try {
  332. this.body = await DocstoreClient.updateDoc(
  333. this.project_id,
  334. this.doc_id,
  335. this.largeLines,
  336. this.version,
  337. this.originalRanges
  338. )
  339. } catch (error) {
  340. // ignore error response
  341. }
  342. })
  343. it('should not update the doc in the API', async function () {
  344. const doc = await DocstoreClient.getDoc(this.project_id, this.doc_id)
  345. doc.lines.should.deep.equal(this.originalLines)
  346. })
  347. })
  348. })