Просмотр исходного кода

Merge pull request #28868 from overleaf/msm-async-docstore-acceptance

[docstore] async/await migration in acceptance tests + `request` removal

GitOrigin-RevId: af1fe2b3de3d0b449ba3dad3555b309af3d35b62
Miguel Serrano 10 месяцев назад
Родитель
Сommit
9723800b68

+ 1 - 2
package-lock.json

@@ -51041,8 +51041,7 @@
         "express": "^4.21.2",
         "lodash": "^4.17.21",
         "mongodb-legacy": "6.1.3",
-        "p-map": "^4.0.0",
-        "request": "^2.88.2"
+        "p-map": "^4.0.0"
       },
       "devDependencies": {
         "@google-cloud/storage": "^6.10.1",

+ 1 - 2
services/docstore/package.json

@@ -33,8 +33,7 @@
     "express": "^4.21.2",
     "lodash": "^4.17.21",
     "mongodb-legacy": "6.1.3",
-    "p-map": "^4.0.0",
-    "request": "^2.88.2"
+    "p-map": "^4.0.0"
   },
   "devDependencies": {
     "@google-cloud/storage": "^6.10.1",

+ 213 - 531
services/docstore/test/acceptance/js/ArchiveDocsTests.js

@@ -1,16 +1,3 @@
-/* eslint-disable
-    no-unused-vars,
-*/
-// TODO: This file was created by bulk-decaffeinate.
-// Fix any style issues and re-enable lint.
-/*
- * decaffeinate suggestions:
- * DS101: Remove unnecessary use of Array.from
- * DS102: Remove unnecessary code created because of implicit returns
- * DS207: Consider shorter variations of null checks
- * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
- */
-
 const Settings = require('@overleaf/settings')
 const { expect } = require('chai')
 const { db, ObjectId } = require('../../../app/js/mongodb')
@@ -20,17 +7,16 @@ const DocstoreClient = require('./helpers/DocstoreClient')
 const { Storage } = require('@google-cloud/storage')
 const Persistor = require('../../../app/js/PersistorManager')
 const { ReadableString } = require('@overleaf/stream-utils')
+const { callbackify } = require('node:util')
 
-function uploadContent(path, json, callback) {
+async function uploadContent(path, json) {
   const stream = new ReadableString(JSON.stringify(json))
-  Persistor.sendStream(Settings.docstore.bucket, path, stream)
-    .then(() => callback())
-    .catch(callback)
+  await Persistor.sendStream(Settings.docstore.bucket, path, stream)
 }
 
 describe('Archiving', function () {
-  before(function (done) {
-    return DocstoreApp.ensureRunning(done)
+  before(async function () {
+    await DocstoreApp.ensureRunning()
   })
 
   before(async function () {
@@ -65,118 +51,100 @@ describe('Archiving', function () {
           version: 4,
         },
       ]
-      const jobs = Array.from(this.docs).map(doc =>
-        (doc => {
-          return callback => {
-            return DocstoreClient.createDoc(
-              this.project_id,
-              doc._id,
-              doc.lines,
-              doc.version,
-              doc.ranges,
-              callback
-            )
-          }
+      const jobs = this.docs.map(doc =>
+        (doc => callback => {
+          callbackify(DocstoreClient.createDoc)(
+            this.project_id,
+            doc._id,
+            doc.lines,
+            doc.version,
+            doc.ranges,
+            callback
+          )
         })(doc)
       )
 
-      return async.series(jobs, error => {
+      async.series(jobs, error => {
         if (error != null) {
           throw error
         }
-        return DocstoreClient.archiveAllDoc(this.project_id, (error, res) => {
-          if (error) return done(error)
-          this.res = res
-          return done()
-        })
+        DocstoreClient.archiveAllDoc(this.project_id)
+          .then(res => {
+            this.res = res
+            done()
+          })
+          .catch(done)
       })
     })
 
-    it('should archive all the docs', function (done) {
-      this.res.statusCode.should.equal(204)
-      return done()
+    it('should archive all the docs', function () {
+      this.res.status.should.equal(204)
     })
 
     it('should set inS3 and unset lines and ranges in each doc', function (done) {
-      const jobs = Array.from(this.docs).map(doc =>
-        (doc => {
-          return callback => {
-            return db.docs.findOne({ _id: doc._id }, (error, doc) => {
+      const jobs = this.docs.map(doc =>
+        (
+          doc => callback =>
+            db.docs.findOne({ _id: doc._id }, (error, doc) => {
               if (error) return callback(error)
               expect(doc.lines).not.to.exist
               expect(doc.ranges).not.to.exist
               doc.inS3.should.equal(true)
-              return callback()
+              callback()
             })
-          }
-        })(doc)
+        )(doc)
       )
-      return async.series(jobs, done)
+      async.series(jobs, done)
     })
 
     it('should set the docs in s3 correctly', function (done) {
-      const jobs = Array.from(this.docs).map(doc =>
-        (doc => {
-          return callback => {
-            return DocstoreClient.getS3Doc(
-              this.project_id,
-              doc._id,
-              (error, s3Doc) => {
-                if (error) return callback(error)
+      const jobs = this.docs.map(doc =>
+        (
+          doc => callback =>
+            DocstoreClient.getS3Doc(this.project_id, doc._id)
+              .then(s3Doc => {
                 s3Doc.lines.should.deep.equal(doc.lines)
                 s3Doc.ranges.should.deep.equal(doc.ranges)
                 callback()
-              }
-            )
-          }
-        })(doc)
+              })
+              .catch(callback)
+        )(doc)
       )
-      return async.series(jobs, done)
+      async.series(jobs, done)
     })
 
-    return describe('after unarchiving from a request for the project', function () {
-      before(function (done) {
-        return DocstoreClient.getAllDocs(
-          this.project_id,
-          (error, res, fetchedDocs) => {
-            this.fetched_docs = fetchedDocs
-            if (error != null) {
-              throw error
-            }
-            return done()
-          }
-        )
+    describe('after unarchiving from a request for the project', function () {
+      before(async function () {
+        this.fetched_docs = await DocstoreClient.getAllDocs(this.project_id)
       })
 
-      it('should return the docs', function (done) {
+      it('should return the docs', function () {
         for (let i = 0; i < this.fetched_docs.length; i++) {
           const doc = this.fetched_docs[i]
           doc.lines.should.deep.equal(this.docs[i].lines)
         }
-        return done()
       })
 
-      return it('should restore the docs to mongo', function (done) {
-        const jobs = Array.from(this.docs).map((doc, i) =>
-          ((doc, i) => {
-            return callback => {
-              return db.docs.findOne({ _id: doc._id }, (error, doc) => {
+      it('should restore the docs to mongo', function (done) {
+        const jobs = this.docs.map((doc, i) =>
+          (
+            (doc, i) => callback =>
+              db.docs.findOne({ _id: doc._id }, (error, doc) => {
                 if (error) return callback(error)
                 doc.lines.should.deep.equal(this.docs[i].lines)
                 doc.ranges.should.deep.equal(this.docs[i].ranges)
                 expect(doc.inS3).not.to.exist
-                return callback()
+                callback()
               })
-            }
-          })(doc, i)
+          )(doc, i)
         )
-        return async.series(jobs, done)
+        async.series(jobs, done)
       })
     })
   })
 
   describe('a deleted doc', function () {
-    beforeEach(function (done) {
+    beforeEach(async function () {
       this.project_id = new ObjectId()
       this.doc = {
         _id: new ObjectId(),
@@ -184,102 +152,51 @@ describe('Archiving', function () {
         ranges: {},
         version: 2,
       }
-      return DocstoreClient.createDoc(
+
+      await DocstoreClient.createDoc(
         this.project_id,
         this.doc._id,
         this.doc.lines,
         this.doc.version,
-        this.doc.ranges,
-        error => {
-          if (error != null) {
-            throw error
-          }
-          return DocstoreClient.deleteDoc(
-            this.project_id,
-            this.doc._id,
-            error => {
-              if (error != null) {
-                throw error
-              }
-              return DocstoreClient.archiveAllDoc(
-                this.project_id,
-                (error, res) => {
-                  this.res = res
-                  if (error != null) {
-                    throw error
-                  }
-                  return done()
-                }
-              )
-            }
-          )
-        }
+        this.doc.ranges
       )
+      await DocstoreClient.deleteDoc(this.project_id, this.doc._id)
+      this.res = await DocstoreClient.archiveAllDoc(this.project_id)
     })
 
-    it('should successully archive the docs', function (done) {
-      this.res.statusCode.should.equal(204)
-      return done()
+    it('should successully archive the docs', function () {
+      this.res.status.should.equal(204)
     })
 
-    it('should set inS3 and unset lines and ranges in each doc', function (done) {
-      return db.docs.findOne({ _id: this.doc._id }, (error, doc) => {
-        if (error != null) {
-          throw error
-        }
-        expect(doc.lines).not.to.exist
-        expect(doc.ranges).not.to.exist
-        doc.inS3.should.equal(true)
-        doc.deleted.should.equal(true)
-        return done()
-      })
+    it('should set inS3 and unset lines and ranges in each doc', async function () {
+      const doc = await db.docs.findOne({ _id: this.doc._id })
+      expect(doc.lines).not.to.exist
+      expect(doc.ranges).not.to.exist
+      doc.inS3.should.equal(true)
+      doc.deleted.should.equal(true)
     })
 
-    it('should set the doc in s3 correctly', function (done) {
-      return DocstoreClient.getS3Doc(
-        this.project_id,
-        this.doc._id,
-        (error, s3Doc) => {
-          if (error != null) {
-            throw error
-          }
-          s3Doc.lines.should.deep.equal(this.doc.lines)
-          s3Doc.ranges.should.deep.equal(this.doc.ranges)
-          return done()
-        }
-      )
+    it('should set the doc in s3 correctly', async function () {
+      const s3Doc = await DocstoreClient.getS3Doc(this.project_id, this.doc._id)
+      s3Doc.lines.should.deep.equal(this.doc.lines)
+      s3Doc.ranges.should.deep.equal(this.doc.ranges)
     })
 
     describe('after unarchiving from a request for the project', function () {
-      beforeEach(function (done) {
-        return DocstoreClient.getAllDocs(
-          this.project_id,
-          (error, res, fetchedDocs) => {
-            this.fetched_docs = fetchedDocs
-            if (error != null) {
-              throw error
-            }
-            return done()
-          }
-        )
+      beforeEach(async function () {
+        this.fetched_docs = await DocstoreClient.getAllDocs(this.project_id)
       })
 
-      it('should not included the deleted', function (done) {
+      it('should not included the deleted', function () {
         this.fetched_docs.length.should.equal(0)
-        return done()
       })
 
-      return it('should restore the doc to mongo', function (done) {
-        return db.docs.findOne({ _id: this.doc._id }, (error, doc) => {
-          if (error != null) {
-            throw error
-          }
-          doc.lines.should.deep.equal(this.doc.lines)
-          doc.ranges.should.deep.equal(this.doc.ranges)
-          expect(doc.inS3).not.to.exist
-          doc.deleted.should.equal(true)
-          return done()
-        })
+      it('should restore the doc to mongo', async function () {
+        const doc = await db.docs.findOne({ _id: this.doc._id })
+        doc.lines.should.deep.equal(this.doc.lines)
+        doc.ranges.should.deep.equal(this.doc.ranges)
+        expect(doc.inS3).not.to.exist
+        doc.deleted.should.equal(true)
       })
     })
 
@@ -296,42 +213,27 @@ describe('Archiving', function () {
       })
 
       describe('after unarchiving from a request for the project', function () {
-        beforeEach(function (done) {
-          DocstoreClient.getAllDocs(
-            this.project_id,
-            (error, res, fetchedDocs) => {
-              this.fetched_docs = fetchedDocs
-              if (error) {
-                return done(error)
-              }
-              done()
-            }
-          )
+        beforeEach(async function () {
+          this.fetched_docs = await DocstoreClient.getAllDocs(this.project_id)
         })
 
-        it('should not included the deleted', function (done) {
+        it('should not included the deleted', function () {
           this.fetched_docs.length.should.equal(0)
-          done()
         })
 
-        it('should not have restored the deleted doc to mongo', function (done) {
-          db.docs.findOne({ _id: this.doc._id }, (error, doc) => {
-            if (error) {
-              return done(error)
-            }
-            expect(doc.lines).to.not.exist
-            expect(doc.ranges).to.not.exist
-            expect(doc.inS3).to.equal(true)
-            expect(doc.deleted).to.equal(true)
-            done()
-          })
+        it('should not have restored the deleted doc to mongo', async function () {
+          const doc = await db.docs.findOne({ _id: this.doc._id })
+          expect(doc.lines).to.not.exist
+          expect(doc.ranges).to.not.exist
+          expect(doc.inS3).to.equal(true)
+          expect(doc.deleted).to.equal(true)
         })
       })
     })
   })
 
   describe('archiving a single doc', function () {
-    before(function (done) {
+    before(async function () {
       this.project_id = new ObjectId()
       this.timeout(1000 * 30)
       this.doc = {
@@ -340,62 +242,36 @@ describe('Archiving', function () {
         ranges: {},
         version: 2,
       }
-      DocstoreClient.createDoc(
+      await DocstoreClient.createDoc(
         this.project_id,
         this.doc._id,
         this.doc.lines,
         this.doc.version,
-        this.doc.ranges,
-        error => {
-          if (error) {
-            return done(error)
-          }
-          DocstoreClient.archiveDoc(
-            this.project_id,
-            this.doc._id,
-            (error, res) => {
-              this.res = res
-              if (error) {
-                return done(error)
-              }
-              done()
-            }
-          )
-        }
+        this.doc.ranges
       )
+      this.res = await DocstoreClient.archiveDoc(this.project_id, this.doc._id)
     })
 
-    it('should successully archive the doc', function (done) {
-      this.res.statusCode.should.equal(204)
-      done()
+    it('should successully archive the doc', function () {
+      this.res.status.should.equal(204)
     })
 
-    it('should set inS3 and unset lines and ranges in the doc', function (done) {
-      db.docs.findOne({ _id: this.doc._id }, (error, doc) => {
-        if (error) {
-          return done(error)
-        }
-        expect(doc.lines).not.to.exist
-        expect(doc.ranges).not.to.exist
-        doc.inS3.should.equal(true)
-        done()
-      })
+    it('should set inS3 and unset lines and ranges in the doc', async function () {
+      const doc = await db.docs.findOne({ _id: this.doc._id })
+      expect(doc.lines).not.to.exist
+      expect(doc.ranges).not.to.exist
+      doc.inS3.should.equal(true)
     })
 
-    it('should set the doc in s3 correctly', function (done) {
-      DocstoreClient.getS3Doc(this.project_id, this.doc._id, (error, s3Doc) => {
-        if (error) {
-          return done(error)
-        }
-        s3Doc.lines.should.deep.equal(this.doc.lines)
-        s3Doc.ranges.should.deep.equal(this.doc.ranges)
-        done()
-      })
+    it('should set the doc in s3 correctly', async function () {
+      const s3Doc = await DocstoreClient.getS3Doc(this.project_id, this.doc._id)
+      s3Doc.lines.should.deep.equal(this.doc.lines)
+      s3Doc.ranges.should.deep.equal(this.doc.ranges)
     })
   })
 
   describe('a doc with large lines', function () {
-    before(function (done) {
+    before(async function () {
       this.project_id = new ObjectId()
       this.timeout(1000 * 30)
       const quarterMegInBytes = 250000
@@ -408,89 +284,49 @@ describe('Archiving', function () {
         ranges: {},
         version: 2,
       }
-      return DocstoreClient.createDoc(
+      await DocstoreClient.createDoc(
         this.project_id,
         this.doc._id,
         this.doc.lines,
         this.doc.version,
-        this.doc.ranges,
-        error => {
-          if (error != null) {
-            throw error
-          }
-          return DocstoreClient.archiveAllDoc(this.project_id, (error, res) => {
-            this.res = res
-            if (error != null) {
-              throw error
-            }
-            return done()
-          })
-        }
+        this.doc.ranges
       )
+      this.res = await DocstoreClient.archiveAllDoc(this.project_id)
     })
 
-    it('should successully archive the docs', function (done) {
-      this.res.statusCode.should.equal(204)
-      return done()
+    it('should successully archive the docs', function () {
+      this.res.status.should.equal(204)
     })
 
-    it('should set inS3 and unset lines and ranges in each doc', function (done) {
-      return db.docs.findOne({ _id: this.doc._id }, (error, doc) => {
-        if (error != null) {
-          throw error
-        }
-        expect(doc.lines).not.to.exist
-        expect(doc.ranges).not.to.exist
-        doc.inS3.should.equal(true)
-        return done()
-      })
+    it('should set inS3 and unset lines and ranges in each doc', async function () {
+      const doc = await db.docs.findOne({ _id: this.doc._id })
+      expect(doc.lines).not.to.exist
+      expect(doc.ranges).not.to.exist
+      doc.inS3.should.equal(true)
     })
 
-    it('should set the doc in s3 correctly', function (done) {
-      return DocstoreClient.getS3Doc(
-        this.project_id,
-        this.doc._id,
-        (error, s3Doc) => {
-          if (error != null) {
-            throw error
-          }
-          s3Doc.lines.should.deep.equal(this.doc.lines)
-          s3Doc.ranges.should.deep.equal(this.doc.ranges)
-          return done()
-        }
-      )
+    it('should set the doc in s3 correctly', async function () {
+      const s3Doc = await DocstoreClient.getS3Doc(this.project_id, this.doc._id)
+      s3Doc.lines.should.deep.equal(this.doc.lines)
+      s3Doc.ranges.should.deep.equal(this.doc.ranges)
     })
 
-    return describe('after unarchiving from a request for the project', function () {
-      before(function (done) {
-        return DocstoreClient.getAllDocs(
-          this.project_id,
-          (error, res, fetchedDocs) => {
-            this.fetched_docs = fetchedDocs
-            if (error != null) {
-              throw error
-            }
-            return done()
-          }
-        )
+    describe('after unarchiving from a request for the project', function () {
+      before(async function () {
+        this.fetched_docs = await DocstoreClient.getAllDocs(this.project_id)
       })
 
-      return it('should restore the doc to mongo', function (done) {
-        return db.docs.findOne({ _id: this.doc._id }, (error, doc) => {
-          if (error != null) {
-            throw error
-          }
-          doc.lines.should.deep.equal(this.doc.lines)
-          doc.ranges.should.deep.equal(this.doc.ranges)
-          expect(doc.inS3).not.to.exist
-          return done()
-        })
+      it('should restore the doc to mongo', async function () {
+        const doc = await db.docs.findOne({ _id: this.doc._id })
+        doc.lines.should.deep.equal(this.doc.lines)
+        doc.ranges.should.deep.equal(this.doc.ranges)
+        expect(doc.inS3).not.to.exist
       })
     })
   })
 
   describe('a doc with naughty strings', function () {
-    before(function (done) {
+    before(async function () {
       this.project_id = new ObjectId()
       this.doc = {
         _id: new ObjectId(),
@@ -882,89 +718,48 @@ describe('Archiving', function () {
         ranges: {},
         version: 2,
       }
-      return DocstoreClient.createDoc(
+      await DocstoreClient.createDoc(
         this.project_id,
         this.doc._id,
         this.doc.lines,
         this.doc.version,
-        this.doc.ranges,
-        error => {
-          if (error != null) {
-            throw error
-          }
-          return DocstoreClient.archiveAllDoc(this.project_id, (error, res) => {
-            this.res = res
-            if (error != null) {
-              throw error
-            }
-            return done()
-          })
-        }
+        this.doc.ranges
       )
+      this.res = await DocstoreClient.archiveAllDoc(this.project_id)
     })
 
-    it('should successully archive the docs', function (done) {
-      this.res.statusCode.should.equal(204)
-      return done()
+    it('should successully archive the docs', function () {
+      this.res.status.should.equal(204)
     })
 
-    it('should set inS3 and unset lines and ranges in each doc', function (done) {
-      return db.docs.findOne({ _id: this.doc._id }, (error, doc) => {
-        if (error != null) {
-          throw error
-        }
-        expect(doc.lines).not.to.exist
-        expect(doc.ranges).not.to.exist
-        doc.inS3.should.equal(true)
-        return done()
-      })
+    it('should set inS3 and unset lines and ranges in each doc', async function () {
+      const doc = await db.docs.findOne({ _id: this.doc._id })
+      expect(doc.lines).not.to.exist
+      expect(doc.ranges).not.to.exist
+      doc.inS3.should.equal(true)
     })
 
-    it('should set the doc in s3 correctly', function (done) {
-      return DocstoreClient.getS3Doc(
-        this.project_id,
-        this.doc._id,
-        (error, s3Doc) => {
-          if (error != null) {
-            throw error
-          }
-          s3Doc.lines.should.deep.equal(this.doc.lines)
-          s3Doc.ranges.should.deep.equal(this.doc.ranges)
-          return done()
-        }
-      )
+    it('should set the doc in s3 correctly', async function () {
+      const s3Doc = await DocstoreClient.getS3Doc(this.project_id, this.doc._id)
+      s3Doc.lines.should.deep.equal(this.doc.lines)
+      s3Doc.ranges.should.deep.equal(this.doc.ranges)
     })
 
-    return describe('after unarchiving from a request for the project', function () {
-      before(function (done) {
-        return DocstoreClient.getAllDocs(
-          this.project_id,
-          (error, res, fetchedDocs) => {
-            this.fetched_docs = fetchedDocs
-            if (error != null) {
-              throw error
-            }
-            return done()
-          }
-        )
+    describe('after unarchiving from a request for the project', function () {
+      before(async function () {
+        this.fetched_docs = await DocstoreClient.getAllDocs(this.project_id)
       })
 
-      return it('should restore the doc to mongo', function (done) {
-        return db.docs.findOne({ _id: this.doc._id }, (error, doc) => {
-          if (error != null) {
-            throw error
-          }
-          doc.lines.should.deep.equal(this.doc.lines)
-          doc.ranges.should.deep.equal(this.doc.ranges)
-          expect(doc.inS3).not.to.exist
-          return done()
-        })
+      it('should restore the doc to mongo', async function () {
+        const doc = await db.docs.findOne({ _id: this.doc._id })
+        doc.lines.should.deep.equal(this.doc.lines)
+        doc.ranges.should.deep.equal(this.doc.ranges)
       })
     })
   })
 
   describe('a doc with ranges', function () {
-    before(function (done) {
+    before(async function () {
       this.project_id = new ObjectId()
       this.doc = {
         _id: new ObjectId(),
@@ -1010,90 +805,50 @@ describe('Archiving', function () {
           },
         ],
       }
-      return DocstoreClient.createDoc(
+      await DocstoreClient.createDoc(
         this.project_id,
         this.doc._id,
         this.doc.lines,
         this.doc.version,
-        this.doc.ranges,
-        error => {
-          if (error != null) {
-            throw error
-          }
-          return DocstoreClient.archiveAllDoc(this.project_id, (error, res) => {
-            this.res = res
-            if (error != null) {
-              throw error
-            }
-            return done()
-          })
-        }
+        this.doc.ranges
       )
+      this.res = await DocstoreClient.archiveAllDoc(this.project_id)
     })
 
-    it('should successully archive the docs', function (done) {
-      this.res.statusCode.should.equal(204)
-      return done()
+    it('should successully archive the docs', function () {
+      this.res.status.should.equal(204)
     })
 
-    it('should set inS3 and unset lines and ranges in each doc', function (done) {
-      return db.docs.findOne({ _id: this.doc._id }, (error, doc) => {
-        if (error != null) {
-          throw error
-        }
-        expect(doc.lines).not.to.exist
-        expect(doc.ranges).not.to.exist
-        doc.inS3.should.equal(true)
-        return done()
-      })
+    it('should set inS3 and unset lines and ranges in each doc', async function () {
+      const doc = await db.docs.findOne({ _id: this.doc._id })
+      expect(doc.lines).not.to.exist
+      expect(doc.ranges).not.to.exist
+      doc.inS3.should.equal(true)
     })
 
-    it('should set the doc in s3 correctly', function (done) {
-      return DocstoreClient.getS3Doc(
-        this.project_id,
-        this.doc._id,
-        (error, s3Doc) => {
-          if (error != null) {
-            throw error
-          }
-          s3Doc.lines.should.deep.equal(this.doc.lines)
-          const ranges = JSON.parse(JSON.stringify(this.fixedRanges)) // ObjectId -> String
-          s3Doc.ranges.should.deep.equal(ranges)
-          return done()
-        }
-      )
+    it('should set the doc in s3 correctly', async function () {
+      const s3Doc = await DocstoreClient.getS3Doc(this.project_id, this.doc._id)
+      s3Doc.lines.should.deep.equal(this.doc.lines)
+      const ranges = JSON.parse(JSON.stringify(this.fixedRanges)) // ObjectId -> String
+      s3Doc.ranges.should.deep.equal(ranges)
     })
 
-    return describe('after unarchiving from a request for the project', function () {
-      before(function (done) {
-        return DocstoreClient.getAllDocs(
-          this.project_id,
-          (error, res, fetchedDocs) => {
-            this.fetched_docs = fetchedDocs
-            if (error != null) {
-              throw error
-            }
-            return done()
-          }
-        )
+    describe('after unarchiving from a request for the project', function () {
+      before(async function () {
+        this.fetched_docs = await DocstoreClient.getAllDocs(this.project_id)
       })
 
-      return it('should restore the doc to mongo', function (done) {
-        return db.docs.findOne({ _id: this.doc._id }, (error, doc) => {
-          if (error != null) {
-            throw error
-          }
-          doc.lines.should.deep.equal(this.doc.lines)
-          doc.ranges.should.deep.equal(this.fixedRanges)
-          expect(doc.inS3).not.to.exist
-          return done()
-        })
+      it('should restore the doc to mongo', async function () {
+        const doc = await db.docs.findOne({ _id: this.doc._id })
+        doc.lines.should.deep.equal(this.doc.lines)
+        doc.ranges.should.deep.equal(this.fixedRanges)
+        expect(doc.inS3).not.to.exist
       })
     })
   })
 
   describe('a doc that is archived twice', function () {
-    before(function (done) {
+    before(async function () {
       this.project_id = new ObjectId()
       this.doc = {
         _id: new ObjectId(),
@@ -1101,95 +856,50 @@ describe('Archiving', function () {
         ranges: {},
         version: 2,
       }
-      return DocstoreClient.createDoc(
+      await DocstoreClient.createDoc(
         this.project_id,
         this.doc._id,
         this.doc.lines,
         this.doc.version,
-        this.doc.ranges,
-        error => {
-          if (error != null) {
-            throw error
-          }
-          return DocstoreClient.archiveAllDoc(this.project_id, (error, res) => {
-            this.res = res
-            if (error != null) {
-              throw error
-            }
-            this.res.statusCode.should.equal(204)
-            return DocstoreClient.archiveAllDoc(
-              this.project_id,
-              (error, res1) => {
-                this.res = res1
-                if (error != null) {
-                  throw error
-                }
-                this.res.statusCode.should.equal(204)
-                return done()
-              }
-            )
-          })
-        }
+        this.doc.ranges
       )
+
+      this.res = await DocstoreClient.archiveAllDoc(this.project_id)
+      this.res.status.should.equal(204)
+
+      this.res = await DocstoreClient.archiveAllDoc(this.project_id)
+      this.res.status.should.equal(204)
     })
 
-    it('should set inS3 and unset lines and ranges in each doc', function (done) {
-      return db.docs.findOne({ _id: this.doc._id }, (error, doc) => {
-        if (error != null) {
-          throw error
-        }
-        expect(doc.lines).not.to.exist
-        expect(doc.ranges).not.to.exist
-        doc.inS3.should.equal(true)
-        return done()
-      })
+    it('should set inS3 and unset lines and ranges in each doc', async function () {
+      const doc = await db.docs.findOne({ _id: this.doc._id })
+      expect(doc.lines).not.to.exist
+      expect(doc.ranges).not.to.exist
+      doc.inS3.should.equal(true)
     })
 
-    it('should set the doc in s3 correctly', function (done) {
-      return DocstoreClient.getS3Doc(
-        this.project_id,
-        this.doc._id,
-        (error, s3Doc) => {
-          if (error != null) {
-            throw error
-          }
-          s3Doc.lines.should.deep.equal(this.doc.lines)
-          s3Doc.ranges.should.deep.equal(this.doc.ranges)
-          return done()
-        }
-      )
+    it('should set the doc in s3 correctly', async function () {
+      const s3Doc = await DocstoreClient.getS3Doc(this.project_id, this.doc._id)
+      s3Doc.lines.should.deep.equal(this.doc.lines)
+      s3Doc.ranges.should.deep.equal(this.doc.ranges)
     })
 
-    return describe('after unarchiving from a request for the project', function () {
-      before(function (done) {
-        return DocstoreClient.getAllDocs(
-          this.project_id,
-          (error, res, fetchedDocs) => {
-            this.fetched_docs = fetchedDocs
-            if (error != null) {
-              throw error
-            }
-            return done()
-          }
-        )
+    describe('after unarchiving from a request for the project', function () {
+      before(async function () {
+        this.fetched_docs = await DocstoreClient.getAllDocs(this.project_id)
       })
 
-      return it('should restore the doc to mongo', function (done) {
-        return db.docs.findOne({ _id: this.doc._id }, (error, doc) => {
-          if (error != null) {
-            throw error
-          }
-          doc.lines.should.deep.equal(this.doc.lines)
-          doc.ranges.should.deep.equal(this.doc.ranges)
-          expect(doc.inS3).not.to.exist
-          return done()
-        })
+      it('should restore the doc to mongo', async function () {
+        const doc = await db.docs.findOne({ _id: this.doc._id })
+        doc.lines.should.deep.equal(this.doc.lines)
+        doc.ranges.should.deep.equal(this.doc.ranges)
+        expect(doc.inS3).not.to.exist
       })
     })
   })
 
-  return describe('a doc with the old schema (just an array of lines)', function () {
-    before(function (done) {
+  describe('a doc with the old schema (just an array of lines)', function () {
+    before(async function () {
       this.project_id = new ObjectId()
       this.doc = {
         _id: new ObjectId(),
@@ -1197,52 +907,24 @@ describe('Archiving', function () {
         ranges: {},
         version: 2,
       }
-      uploadContent(
-        `${this.project_id}/${this.doc._id}`,
-        this.doc.lines,
-        error => {
-          expect(error).not.to.exist
-          db.docs.insertOne(
-            {
-              project_id: this.project_id,
-              _id: this.doc._id,
-              rev: this.doc.version,
-              inS3: true,
-            },
-            error => {
-              if (error != null) {
-                throw error
-              }
-              DocstoreClient.getAllDocs(
-                this.project_id,
-                (error, res, fetchedDocs) => {
-                  this.fetched_docs = fetchedDocs
-                  if (error != null) {
-                    throw error
-                  }
-                  return done()
-                }
-              )
-            }
-          )
-        }
-      )
+      await uploadContent(`${this.project_id}/${this.doc._id}`, this.doc.lines)
+      await db.docs.insertOne({
+        project_id: this.project_id,
+        _id: this.doc._id,
+        rev: this.doc.version,
+        inS3: true,
+      })
+      this.fetched_docs = await DocstoreClient.getAllDocs(this.project_id)
     })
 
-    it('should restore the doc to mongo', function (done) {
-      return db.docs.findOne({ _id: this.doc._id }, (error, doc) => {
-        if (error != null) {
-          throw error
-        }
-        doc.lines.should.deep.equal(this.doc.lines)
-        expect(doc.inS3).not.to.exist
-        return done()
-      })
+    it('should restore the doc to mongo', async function () {
+      const doc = await db.docs.findOne({ _id: this.doc._id })
+      doc.lines.should.deep.equal(this.doc.lines)
+      expect(doc.inS3).not.to.exist
     })
 
-    return it('should return the doc', function (done) {
+    it('should return the doc', function () {
       this.fetched_docs[0].lines.should.deep.equal(this.doc.lines)
-      return done()
     })
   })
 })

+ 182 - 295
services/docstore/test/acceptance/js/DeletingDocsTests.js

@@ -4,6 +4,9 @@ const DocstoreApp = require('./helpers/DocstoreApp')
 const Errors = require('../../../app/js/Errors')
 const Settings = require('@overleaf/settings')
 const { Storage } = require('@google-cloud/storage')
+const { promisify } = require('node:util')
+
+const sleep = promisify(setTimeout)
 
 const DocstoreClient = require('./helpers/DocstoreClient')
 
@@ -24,85 +27,63 @@ function deleteTestSuite(deleteDoc) {
     await storage.bucket(`${Settings.docstore.bucket}-deleted`).delete()
   })
 
-  beforeEach(function (done) {
+  beforeEach(async function () {
     this.project_id = new ObjectId()
     this.doc_id = new ObjectId()
     this.lines = ['original', 'lines']
     this.version = 42
     this.ranges = []
-    DocstoreApp.ensureRunning(() => {
-      DocstoreClient.createDoc(
-        this.project_id,
-        this.doc_id,
-        this.lines,
-        this.version,
-        this.ranges,
-        error => {
-          if (error) {
-            throw error
-          }
-          done()
-        }
-      )
-    })
+    await DocstoreApp.ensureRunning()
+    await DocstoreClient.createDoc(
+      this.project_id,
+      this.doc_id,
+      this.lines,
+      this.version,
+      this.ranges
+    )
   })
 
-  it('should show as not deleted on /deleted', function (done) {
-    DocstoreClient.isDocDeleted(
+  it('should show as not deleted on /deleted', async function () {
+    const { res, body } = await DocstoreClient.isDocDeleted(
       this.project_id,
-      this.doc_id,
-      (error, res, body) => {
-        if (error) return done(error)
-        expect(res.statusCode).to.equal(200)
-        expect(body).to.have.property('deleted').to.equal(false)
-        done()
-      }
+      this.doc_id
     )
+    expect(res.status).to.equal(200)
+    expect(body).to.have.property('deleted').to.equal(false)
   })
 
   describe('when the doc exists', function () {
-    beforeEach(function (done) {
-      deleteDoc(this.project_id, this.doc_id, (error, res, doc) => {
-        if (error) return done(error)
-        this.res = res
-        done()
-      })
+    beforeEach(async function () {
+      this.res = await deleteDoc(this.project_id, this.doc_id)
     })
 
-    afterEach(function (done) {
-      db.docs.deleteOne({ _id: this.doc_id }, done)
+    afterEach(async function () {
+      await db.docs.deleteOne({ _id: this.doc_id })
     })
 
-    it('should mark the doc as deleted on /deleted', function (done) {
-      DocstoreClient.isDocDeleted(
+    it('should mark the doc as deleted on /deleted', async function () {
+      const { res, body } = await DocstoreClient.isDocDeleted(
         this.project_id,
-        this.doc_id,
-        (error, res, body) => {
-          if (error) return done(error)
-          expect(res.statusCode).to.equal(200)
-          expect(body).to.have.property('deleted').to.equal(true)
-          done()
-        }
+        this.doc_id
       )
+      expect(res.status).to.equal(200)
+      expect(body).to.have.property('deleted').to.equal(true)
     })
 
-    it('should insert a deleted doc into the docs collection', function (done) {
-      db.docs.find({ _id: this.doc_id }).toArray((error, docs) => {
-        if (error) return done(error)
-        docs[0]._id.should.deep.equal(this.doc_id)
-        docs[0].lines.should.deep.equal(this.lines)
-        docs[0].deleted.should.equal(true)
-        done()
-      })
+    it('should insert a deleted doc into the docs collection', async function () {
+      const docs = await db.docs.find({ _id: this.doc_id }).toArray()
+      docs[0]._id.should.deep.equal(this.doc_id)
+      docs[0].lines.should.deep.equal(this.lines)
+      docs[0].deleted.should.equal(true)
     })
 
-    it('should not export the doc to s3', function (done) {
-      setTimeout(() => {
-        DocstoreClient.getS3Doc(this.project_id, this.doc_id, error => {
-          expect(error).to.be.instanceOf(Errors.NotFoundError)
-          done()
-        })
-      }, 1000)
+    it('should not export the doc to s3', async function () {
+      await sleep(1000)
+      try {
+        await DocstoreClient.getS3Doc(this.project_id, this.doc_id)
+      } catch (error) {
+        expect(error).to.be.instanceOf(Errors.NotFoundError)
+      }
     })
   })
 
@@ -116,12 +97,8 @@ function deleteTestSuite(deleteDoc) {
       Settings.docstore.archiveOnSoftDelete = archiveOnSoftDelete
     })
 
-    beforeEach('delete Doc', function (done) {
-      deleteDoc(this.project_id, this.doc_id, (error, res) => {
-        if (error) return done(error)
-        this.res = res
-        done()
-      })
+    beforeEach('delete Doc', async function () {
+      this.res = await deleteDoc(this.project_id, this.doc_id)
     })
 
     beforeEach(function waitForBackgroundFlush(done) {
@@ -132,81 +109,54 @@ function deleteTestSuite(deleteDoc) {
       db.docs.deleteOne({ _id: this.doc_id }, done)
     })
 
-    it('should set the deleted flag in the doc', function (done) {
-      db.docs.findOne({ _id: this.doc_id }, (error, doc) => {
-        if (error) {
-          return done(error)
-        }
-        expect(doc.deleted).to.equal(true)
-        done()
-      })
+    it('should set the deleted flag in the doc', async function () {
+      const doc = await db.docs.findOne({ _id: this.doc_id })
+      expect(doc.deleted).to.equal(true)
     })
 
-    it('should set inS3 and unset lines and ranges in the doc', function (done) {
-      db.docs.findOne({ _id: this.doc_id }, (error, doc) => {
-        if (error) {
-          return done(error)
-        }
-        expect(doc.lines).to.not.exist
-        expect(doc.ranges).to.not.exist
-        expect(doc.inS3).to.equal(true)
-        done()
-      })
+    it('should set inS3 and unset lines and ranges in the doc', async function () {
+      const doc = await db.docs.findOne({ _id: this.doc_id })
+      expect(doc.lines).to.not.exist
+      expect(doc.ranges).to.not.exist
+      expect(doc.inS3).to.equal(true)
     })
 
-    it('should set the doc in s3 correctly', function (done) {
-      DocstoreClient.getS3Doc(this.project_id, this.doc_id, (error, s3doc) => {
-        if (error) {
-          return done(error)
-        }
-        expect(s3doc.lines).to.deep.equal(this.lines)
-        expect(s3doc.ranges).to.deep.equal(this.ranges)
-        done()
-      })
+    it('should set the doc in s3 correctly', async function () {
+      const s3doc = await DocstoreClient.getS3Doc(this.project_id, this.doc_id)
+      expect(s3doc.lines).to.deep.equal(this.lines)
+      expect(s3doc.ranges).to.deep.equal(this.ranges)
     })
   })
 
   describe('when the doc exists in another project', function () {
     const otherProjectId = new ObjectId()
 
-    it('should show as not existing on /deleted', function (done) {
-      DocstoreClient.isDocDeleted(otherProjectId, this.doc_id, (error, res) => {
-        if (error) return done(error)
-        expect(res.statusCode).to.equal(404)
-        done()
-      })
+    it('should show as not existing on /deleted', async function () {
+      expect(DocstoreClient.isDocDeleted(otherProjectId, this.doc_id))
+        .to.eventually.be.rejected.and.have.property('info')
+        .to.contain({ status: 404 })
     })
 
-    it('should return a 404 when trying to delete', function (done) {
-      deleteDoc(otherProjectId, this.doc_id, (error, res) => {
-        if (error) return done(error)
-        expect(res.statusCode).to.equal(404)
-        done()
-      })
+    it('should return a 404 when trying to delete', async function () {
+      expect(deleteDoc(otherProjectId, this.doc_id))
+        .to.eventually.be.rejected.and.have.property('info')
+        .to.contain({ status: 404 })
     })
   })
 
   describe('when the doc does not exist', function () {
-    it('should show as not existing on /deleted', function (done) {
+    it('should show as not existing on /deleted', async function () {
       const missingDocId = new ObjectId()
-      DocstoreClient.isDocDeleted(
-        this.project_id,
-        missingDocId,
-        (error, res) => {
-          if (error) return done(error)
-          expect(res.statusCode).to.equal(404)
-          done()
-        }
-      )
+      expect(DocstoreClient.isDocDeleted(this.project_id, missingDocId))
+        .to.eventually.be.rejected.and.have.property('info')
+        .to.contain({ status: 404 })
     })
 
-    it('should return a 404', function (done) {
+    it('should return a 404', async function () {
       const missingDocId = new ObjectId()
-      deleteDoc(this.project_id, missingDocId, (error, res, doc) => {
-        if (error) return done(error)
-        res.statusCode.should.equal(404)
-        done()
-      })
+      await expect(deleteDoc(this.project_id, missingDocId))
+        .to.eventually.be.rejected.and.have.property('info')
+        .to.contain({ status: 404 })
     })
   })
 }
@@ -215,21 +165,17 @@ describe('Delete via PATCH', function () {
   deleteTestSuite(DocstoreClient.deleteDoc)
 
   describe('when providing a custom doc name in the delete request', function () {
-    beforeEach(function (done) {
-      DocstoreClient.deleteDocWithName(
+    beforeEach(async function () {
+      await DocstoreClient.deleteDocWithName(
         this.project_id,
         this.doc_id,
-        'wombat.tex',
-        done
+        'wombat.tex'
       )
     })
 
-    it('should insert the doc name into the docs collection', function (done) {
-      db.docs.find({ _id: this.doc_id }).toArray((error, docs) => {
-        if (error) return done(error)
-        expect(docs[0].name).to.equal('wombat.tex')
-        done()
-      })
+    it('should insert the doc name into the docs collection', async function () {
+      const docs = await db.docs.find({ _id: this.doc_id }).toArray()
+      expect(docs[0].name).to.equal('wombat.tex')
     })
   })
 
@@ -239,172 +185,130 @@ describe('Delete via PATCH', function () {
       setTimeout(done, 5)
     })
 
-    beforeEach('perform deletion with past date', function (done) {
-      DocstoreClient.deleteDocWithDate(
+    beforeEach('perform deletion with past date', async function () {
+      await DocstoreClient.deleteDocWithDate(
         this.project_id,
         this.doc_id,
-        this.deletedAt,
-        done
+        this.deletedAt
       )
     })
 
-    it('should insert the date into the docs collection', function (done) {
-      db.docs.find({ _id: this.doc_id }).toArray((error, docs) => {
-        if (error) return done(error)
-        expect(docs[0].deletedAt.toISOString()).to.equal(
-          this.deletedAt.toISOString()
-        )
-        done()
-      })
+    it('should insert the date into the docs collection', async function () {
+      const docs = await db.docs.find({ _id: this.doc_id }).toArray()
+      expect(docs[0].deletedAt.toISOString()).to.equal(
+        this.deletedAt.toISOString()
+      )
     })
   })
 
   describe('when providing no doc name in the delete request', function () {
-    beforeEach(function (done) {
-      DocstoreClient.deleteDocWithName(
-        this.project_id,
-        this.doc_id,
-        '',
-        (error, res) => {
-          this.res = res
-          done(error)
-        }
-      )
-    })
-
     it('should reject the request', function () {
-      expect(this.res.statusCode).to.equal(400)
+      expect(DocstoreClient.deleteDocWithName(this.project_id, this.doc_id))
+        .to.eventually.be.rejected.and.have.property('info')
+        .to.contain({ status: 400 })
     })
   })
 
   describe('when providing no date in the delete request', function () {
-    beforeEach(function (done) {
-      DocstoreClient.deleteDocWithDate(
-        this.project_id,
-        this.doc_id,
-        '',
-        (error, res) => {
-          this.res = res
-          done(error)
-        }
-      )
-    })
-
     it('should reject the request', function () {
-      expect(this.res.statusCode).to.equal(400)
+      expect(DocstoreClient.deleteDocWithDate(this.project_id, this.doc_id))
+        .to.eventually.be.rejected.and.have.property('info')
+        .to.contain({ status: 400 })
     })
   })
 
   describe('before deleting anything', function () {
-    it('should show nothing in deleted docs response', function (done) {
-      DocstoreClient.getAllDeletedDocs(
-        this.project_id,
-        (error, deletedDocs) => {
-          if (error) return done(error)
-          expect(deletedDocs).to.deep.equal([])
-          done()
-        }
+    it('should show nothing in deleted docs response', async function () {
+      const deletedDocs = await DocstoreClient.getAllDeletedDocs(
+        this.project_id
       )
+      expect(deletedDocs).to.deep.equal([])
     })
   })
 
   describe('when the doc gets a name on delete', function () {
-    beforeEach(function (done) {
+    beforeEach(async function () {
       this.deletedAt = new Date()
-      DocstoreClient.deleteDocWithDate(
+      await DocstoreClient.deleteDocWithDate(
         this.project_id,
         this.doc_id,
-        this.deletedAt,
-        done
+        this.deletedAt
       )
     })
 
-    it('should show the doc in deleted docs response', function (done) {
-      DocstoreClient.getAllDeletedDocs(
-        this.project_id,
-        (error, deletedDocs) => {
-          if (error) return done(error)
-          expect(deletedDocs).to.deep.equal([
-            {
-              _id: this.doc_id.toString(),
-              name: 'main.tex',
-              deletedAt: this.deletedAt.toISOString(),
-            },
-          ])
-          done()
-        }
+    it('should show the doc in deleted docs response', async function () {
+      const deletedDocs = await DocstoreClient.getAllDeletedDocs(
+        this.project_id
       )
+      expect(deletedDocs).to.deep.equal([
+        {
+          _id: this.doc_id.toString(),
+          name: 'main.tex',
+          deletedAt: this.deletedAt.toISOString(),
+        },
+      ])
     })
 
     describe('after deleting multiple docs', function () {
-      beforeEach('create doc2', function (done) {
+      beforeEach('create doc2', async function () {
         this.doc_id2 = new ObjectId()
-        DocstoreClient.createDoc(
+        await DocstoreClient.createDoc(
           this.project_id,
           this.doc_id2,
           this.lines,
           this.version,
-          this.ranges,
-          done
+          this.ranges
         )
       })
-      beforeEach('delete doc2', function (done) {
+      beforeEach('delete doc2', async function () {
         this.deletedAt2 = new Date()
-        DocstoreClient.deleteDocWithDateAndName(
+        await DocstoreClient.deleteDocWithDateAndName(
           this.project_id,
           this.doc_id2,
           this.deletedAt2,
-          'two.tex',
-          done
+          'two.tex'
         )
       })
-      beforeEach('create doc3', function (done) {
+      beforeEach('create doc3', async function () {
         this.doc_id3 = new ObjectId()
-        DocstoreClient.createDoc(
+        await DocstoreClient.createDoc(
           this.project_id,
           this.doc_id3,
           this.lines,
           this.version,
-          this.ranges,
-          done
+          this.ranges
         )
       })
-      beforeEach('delete doc3', function (done) {
+      beforeEach('delete doc3', async function () {
         this.deletedAt3 = new Date()
-        DocstoreClient.deleteDocWithDateAndName(
+        await DocstoreClient.deleteDocWithDateAndName(
           this.project_id,
           this.doc_id3,
           this.deletedAt3,
-          'three.tex',
-          done
+          'three.tex'
         )
       })
-      it('should show all the docs as deleted', function (done) {
-        DocstoreClient.getAllDeletedDocs(
-          this.project_id,
-          (error, deletedDocs) => {
-            if (error) return done(error)
-
-            expect(deletedDocs).to.deep.equal([
-              {
-                _id: this.doc_id3.toString(),
-                name: 'three.tex',
-                deletedAt: this.deletedAt3.toISOString(),
-              },
-              {
-                _id: this.doc_id2.toString(),
-                name: 'two.tex',
-                deletedAt: this.deletedAt2.toISOString(),
-              },
-              {
-                _id: this.doc_id.toString(),
-                name: 'main.tex',
-                deletedAt: this.deletedAt.toISOString(),
-              },
-            ])
-            done()
-          }
+      it('should show all the docs as deleted', async function () {
+        const deletedDocs = await DocstoreClient.getAllDeletedDocs(
+          this.project_id
         )
+        expect(deletedDocs).to.deep.equal([
+          {
+            _id: this.doc_id3.toString(),
+            name: 'three.tex',
+            deletedAt: this.deletedAt3.toISOString(),
+          },
+          {
+            _id: this.doc_id2.toString(),
+            name: 'two.tex',
+            deletedAt: this.deletedAt2.toISOString(),
+          },
+          {
+            _id: this.doc_id.toString(),
+            name: 'main.tex',
+            deletedAt: this.deletedAt.toISOString(),
+          },
+        ])
       })
 
       describe('with one more than max_deleted_docs permits', function () {
@@ -417,28 +321,23 @@ describe('Delete via PATCH', function () {
           Settings.max_deleted_docs = maxDeletedDocsBefore
         })
 
-        it('should omit the first deleted doc', function (done) {
-          DocstoreClient.getAllDeletedDocs(
-            this.project_id,
-            (error, deletedDocs) => {
-              if (error) return done(error)
-
-              expect(deletedDocs).to.deep.equal([
-                {
-                  _id: this.doc_id3.toString(),
-                  name: 'three.tex',
-                  deletedAt: this.deletedAt3.toISOString(),
-                },
-                {
-                  _id: this.doc_id2.toString(),
-                  name: 'two.tex',
-                  deletedAt: this.deletedAt2.toISOString(),
-                },
-                // dropped main.tex
-              ])
-              done()
-            }
+        it('should omit the first deleted doc', async function () {
+          const deletedDocs = await DocstoreClient.getAllDeletedDocs(
+            this.project_id
           )
+          expect(deletedDocs).to.deep.equal([
+            {
+              _id: this.doc_id3.toString(),
+              name: 'three.tex',
+              deletedAt: this.deletedAt3.toISOString(),
+            },
+            {
+              _id: this.doc_id2.toString(),
+              name: 'two.tex',
+              deletedAt: this.deletedAt2.toISOString(),
+            },
+            // dropped main.tex
+          ])
         })
       })
     })
@@ -446,66 +345,54 @@ describe('Delete via PATCH', function () {
 })
 
 describe("Destroying a project's documents", function () {
-  beforeEach(function (done) {
+  beforeEach(async function () {
     this.project_id = new ObjectId()
     this.doc_id = new ObjectId()
     this.lines = ['original', 'lines']
     this.version = 42
     this.ranges = []
-    DocstoreApp.ensureRunning(() => {
-      DocstoreClient.createDoc(
-        this.project_id,
-        this.doc_id,
-        this.lines,
-        this.version,
-        this.ranges,
-        error => {
-          if (error) {
-            throw error
-          }
-          done()
-        }
-      )
-    })
+    await DocstoreApp.ensureRunning()
+    await DocstoreClient.createDoc(
+      this.project_id,
+      this.doc_id,
+      this.lines,
+      this.version,
+      this.ranges
+    )
   })
 
   describe('when the doc exists', function () {
-    beforeEach(function (done) {
-      DocstoreClient.destroyAllDoc(this.project_id, done)
+    beforeEach(async function () {
+      await DocstoreClient.destroyAllDoc(this.project_id)
     })
 
-    it('should remove the doc from the docs collection', function (done) {
-      db.docs.find({ _id: this.doc_id }).toArray((err, docs) => {
-        expect(err).not.to.exist
-        expect(docs).to.deep.equal([])
-        done()
-      })
+    it('should remove the doc from the docs collection', async function () {
+      const docs = await db.docs.find({ _id: this.doc_id }).toArray()
+      expect(docs).to.deep.equal([])
     })
   })
 
   describe('when the doc is archived', function () {
-    beforeEach(function (done) {
-      DocstoreClient.archiveAllDoc(this.project_id, err => {
-        if (err) {
-          return done(err)
-        }
-        DocstoreClient.destroyAllDoc(this.project_id, done)
-      })
+    beforeEach(async function () {
+      try {
+        await DocstoreClient.archiveAllDoc(this.project_id)
+      } catch (error) {
+        // noop
+      }
+      await DocstoreClient.destroyAllDoc(this.project_id)
     })
 
-    it('should remove the doc from the docs collection', function (done) {
-      db.docs.find({ _id: this.doc_id }).toArray((err, docs) => {
-        expect(err).not.to.exist
-        expect(docs).to.deep.equal([])
-        done()
-      })
+    it('should remove the doc from the docs collection', async function () {
+      const docs = await db.docs.find({ _id: this.doc_id }).toArray()
+      expect(docs).to.deep.equal([])
     })
 
-    it('should remove the doc contents from s3', function (done) {
-      DocstoreClient.getS3Doc(this.project_id, this.doc_id, error => {
+    it('should remove the doc contents from s3', async function () {
+      try {
+        await DocstoreClient.getS3Doc(this.project_id, this.doc_id)
+      } catch (error) {
         expect(error).to.be.instanceOf(Errors.NotFoundError)
-        done()
-      })
+      }
     })
   })
 })

+ 36 - 73
services/docstore/test/acceptance/js/GettingAllDocsTests.js

@@ -1,19 +1,7 @@
-/* eslint-disable
-    no-unused-vars,
-*/
-// TODO: This file was created by bulk-decaffeinate.
-// Fix any style issues and re-enable lint.
-/*
- * decaffeinate suggestions:
- * DS101: Remove unnecessary use of Array.from
- * DS102: Remove unnecessary code created because of implicit returns
- * DS207: Consider shorter variations of null checks
- * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
- */
-const sinon = require('sinon')
 const { ObjectId } = require('mongodb-legacy')
 const async = require('async')
 const DocstoreApp = require('./helpers/DocstoreApp')
+const { callbackify } = require('node:util')
 
 const DocstoreClient = require('./helpers/DocstoreClient')
 
@@ -90,10 +78,10 @@ describe('Getting all docs', function () {
       rev: 8,
     }
     const version = 42
-    const jobs = Array.from(this.docs).map(doc =>
-      (doc => {
-        return callback => {
-          return DocstoreClient.createDoc(
+    const jobs = this.docs.map(doc =>
+      (
+        doc => callback =>
+          callbackify(DocstoreClient.createDoc)(
             this.project_id,
             doc._id,
             doc.lines,
@@ -101,11 +89,10 @@ describe('Getting all docs', function () {
             doc.ranges,
             callback
           )
-        }
-      })(doc)
+      )(doc)
     )
-    jobs.push(cb => {
-      return DocstoreClient.createDoc(
+    jobs.push(cb =>
+      callbackify(DocstoreClient.createDoc)(
         this.project_id,
         this.deleted_doc._id,
         this.deleted_doc.lines,
@@ -113,72 +100,48 @@ describe('Getting all docs', function () {
         this.deleted_doc.ranges,
         err => {
           if (err) return done(err)
-          return DocstoreClient.deleteDoc(
+          callbackify(DocstoreClient.deleteDoc)(
             this.project_id,
             this.deleted_doc._id,
             cb
           )
         }
       )
-    })
-    jobs.unshift(cb => DocstoreApp.ensureRunning(cb))
-    return async.series(jobs, done)
+    )
+    jobs.unshift(cb => callbackify(DocstoreApp.ensureRunning)(cb))
+    async.series(jobs, done)
   })
 
-  it('getAllDocs should return all the (non-deleted) docs', function (done) {
-    return DocstoreClient.getAllDocs(this.project_id, (error, res, docs) => {
-      if (error != null) {
-        throw error
-      }
-      docs.length.should.equal(this.docs.length)
-      for (let i = 0; i < docs.length; i++) {
-        const doc = docs[i]
-        doc.lines.should.deep.equal(this.docs[i].lines)
-      }
-      return done()
-    })
+  it('getAllDocs should return all the (non-deleted) docs', async function () {
+    const docs = await DocstoreClient.getAllDocs(this.project_id)
+    docs.length.should.equal(this.docs.length)
+    for (let i = 0; i < docs.length; i++) {
+      const doc = docs[i]
+      doc.lines.should.deep.equal(this.docs[i].lines)
+    }
   })
 
-  it('getAllRanges should return all the (non-deleted) doc ranges', function (done) {
-    return DocstoreClient.getAllRanges(this.project_id, (error, res, docs) => {
-      if (error != null) {
-        throw error
-      }
-      docs.length.should.equal(this.docs.length)
-      for (let i = 0; i < docs.length; i++) {
-        const doc = docs[i]
-        doc.ranges.should.deep.equal(this.fixedRanges[i])
-      }
-      return done()
-    })
+  it('getAllRanges should return all the (non-deleted) doc ranges', async function () {
+    const docs = await DocstoreClient.getAllRanges(this.project_id)
+    docs.length.should.equal(this.docs.length)
+    for (let i = 0; i < docs.length; i++) {
+      const doc = docs[i]
+      doc.ranges.should.deep.equal(this.fixedRanges[i])
+    }
   })
 
-  it('getTrackedChangesUserIds should return all the user ids from (non-deleted) ranges', function (done) {
-    DocstoreClient.getTrackedChangesUserIds(
-      this.project_id,
-      (error, res, userIds) => {
-        if (error != null) {
-          throw error
-        }
-        userIds.should.deep.equal(['user-id-1', 'user-id-2'])
-        done()
-      }
+  it('getTrackedChangesUserIds should return all the user ids from (non-deleted) ranges', async function () {
+    const userIds = await DocstoreClient.getTrackedChangesUserIds(
+      this.project_id
     )
+    userIds.should.deep.equal(['user-id-1', 'user-id-2'])
   })
 
-  it('getCommentThreadIds should return all the thread ids from (non-deleted) ranges', function (done) {
-    DocstoreClient.getCommentThreadIds(
-      this.project_id,
-      (error, res, threadIds) => {
-        if (error != null) {
-          throw error
-        }
-        threadIds.should.deep.equal({
-          [this.docs[0]._id.toString()]: [this.threadId1],
-          [this.docs[2]._id.toString()]: [this.threadId2],
-        })
-        done()
-      }
-    )
+  it('getCommentThreadIds should return all the thread ids from (non-deleted) ranges', async function () {
+    const threadIds = await DocstoreClient.getCommentThreadIds(this.project_id)
+    threadIds.should.deep.equal({
+      [this.docs[0]._id.toString()]: [this.threadId1],
+      [this.docs[2]._id.toString()]: [this.threadId2],
+    })
   })
 })

+ 35 - 67
services/docstore/test/acceptance/js/GettingDocsFromArchiveTest.js

@@ -5,8 +5,8 @@ const DocstoreClient = require('./helpers/DocstoreClient')
 const { Storage } = require('@google-cloud/storage')
 
 describe('Getting A Doc from Archive', function () {
-  before(function (done) {
-    return DocstoreApp.ensureRunning(done)
+  before(async function () {
+    await DocstoreApp.ensureRunning()
   })
 
   before(async function () {
@@ -25,7 +25,7 @@ describe('Getting A Doc from Archive', function () {
   })
 
   describe('for an archived doc', function () {
-    before(function (done) {
+    before(async function () {
       this.project_id = new ObjectId()
       this.timeout(1000 * 30)
       this.doc = {
@@ -34,72 +34,46 @@ describe('Getting A Doc from Archive', function () {
         ranges: {},
         version: 2,
       }
-      DocstoreClient.createDoc(
+      await DocstoreClient.createDoc(
         this.project_id,
         this.doc._id,
         this.doc.lines,
         this.doc.version,
-        this.doc.ranges,
-        error => {
-          if (error) {
-            return done(error)
-          }
-          DocstoreClient.archiveDoc(
-            this.project_id,
-            this.doc._id,
-            (error, res) => {
-              this.res = res
-              if (error) {
-                return done(error)
-              }
-              done()
-            }
-          )
-        }
+        this.doc.ranges
       )
+      this.res = await DocstoreClient.archiveDoc(this.project_id, this.doc._id)
     })
 
-    it('should successully archive the doc', function (done) {
-      this.res.statusCode.should.equal(204)
-      done()
+    it('should successully archive the doc', function () {
+      this.res.status.should.equal(204)
     })
 
-    it('should return the doc lines and version from persistent storage', function (done) {
-      return DocstoreClient.peekDoc(
+    it('should return the doc lines and version from persistent storage', async function () {
+      const { res, doc } = await DocstoreClient.peekDoc(
         this.project_id,
-        this.doc._id,
-        {},
-        (error, res, doc) => {
-          if (error) return done(error)
-          res.statusCode.should.equal(200)
-          res.headers['x-doc-status'].should.equal('archived')
-          doc.lines.should.deep.equal(this.doc.lines)
-          doc.version.should.equal(this.doc.version)
-          doc.ranges.should.deep.equal(this.doc.ranges)
-          return done()
-        }
+        this.doc._id
       )
+      res.status.should.equal(200)
+      res.headers.get('x-doc-status').should.equal('archived')
+      doc.lines.should.deep.equal(this.doc.lines)
+      doc.version.should.equal(this.doc.version)
+      doc.ranges.should.deep.equal(this.doc.ranges)
     })
 
-    it('should return the doc lines and version from persistent storage on subsequent requests', function (done) {
-      return DocstoreClient.peekDoc(
+    it('should return the doc lines and version from persistent storage on subsequent requests', async function () {
+      const { res, doc } = await DocstoreClient.peekDoc(
         this.project_id,
-        this.doc._id,
-        {},
-        (error, res, doc) => {
-          if (error) return done(error)
-          res.statusCode.should.equal(200)
-          res.headers['x-doc-status'].should.equal('archived')
-          doc.lines.should.deep.equal(this.doc.lines)
-          doc.version.should.equal(this.doc.version)
-          doc.ranges.should.deep.equal(this.doc.ranges)
-          return done()
-        }
+        this.doc._id
       )
+      res.status.should.equal(200)
+      res.headers.get('x-doc-status').should.equal('archived')
+      doc.lines.should.deep.equal(this.doc.lines)
+      doc.version.should.equal(this.doc.version)
+      doc.ranges.should.deep.equal(this.doc.ranges)
     })
 
     describe('for an non-archived doc', function () {
-      before(function (done) {
+      before(async function () {
         this.project_id = new ObjectId()
         this.timeout(1000 * 30)
         this.doc = {
@@ -108,31 +82,25 @@ describe('Getting A Doc from Archive', function () {
           ranges: {},
           version: 2,
         }
-        DocstoreClient.createDoc(
+        await DocstoreClient.createDoc(
           this.project_id,
           this.doc._id,
           this.doc.lines,
           this.doc.version,
-          this.doc.ranges,
-          done
+          this.doc.ranges
         )
       })
 
-      it('should return the doc lines and version from mongo', function (done) {
-        return DocstoreClient.peekDoc(
+      it('should return the doc lines and version from mongo', async function () {
+        const { res, doc } = await DocstoreClient.peekDoc(
           this.project_id,
-          this.doc._id,
-          {},
-          (error, res, doc) => {
-            if (error) return done(error)
-            res.statusCode.should.equal(200)
-            res.headers['x-doc-status'].should.equal('active')
-            doc.lines.should.deep.equal(this.doc.lines)
-            doc.version.should.equal(this.doc.version)
-            doc.ranges.should.deep.equal(this.doc.ranges)
-            return done()
-          }
+          this.doc._id
         )
+        res.status.should.equal(200)
+        res.headers.get('x-doc-status').should.equal('active')
+        doc.lines.should.deep.equal(this.doc.lines)
+        doc.version.should.equal(this.doc.version)
+        doc.ranges.should.deep.equal(this.doc.ranges)
       })
     })
   })

+ 35 - 88
services/docstore/test/acceptance/js/GettingDocsTests.js

@@ -1,22 +1,11 @@
-/* eslint-disable
-    no-unused-vars,
-*/
-// TODO: This file was created by bulk-decaffeinate.
-// Fix any style issues and re-enable lint.
-/*
- * decaffeinate suggestions:
- * DS102: Remove unnecessary code created because of implicit returns
- * DS207: Consider shorter variations of null checks
- * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
- */
-const sinon = require('sinon')
 const { ObjectId } = require('mongodb-legacy')
+const { expect } = require('chai')
 const DocstoreApp = require('./helpers/DocstoreApp')
 
 const DocstoreClient = require('./helpers/DocstoreClient')
 
 describe('Getting a doc', function () {
-  beforeEach(function (done) {
+  beforeEach(async function () {
     this.project_id = new ObjectId()
     this.doc_id = new ObjectId()
     this.lines = ['original', 'lines']
@@ -49,105 +38,63 @@ describe('Getting a doc', function () {
         { ...this.ranges.comments[0], id: this.ranges.comments[0].op.t },
       ],
     }
-    return DocstoreApp.ensureRunning(() => {
-      return DocstoreClient.createDoc(
-        this.project_id,
-        this.doc_id,
-        this.lines,
-        this.version,
-        this.ranges,
-        error => {
-          if (error != null) {
-            throw error
-          }
-          return done()
-        }
-      )
-    })
+    await DocstoreApp.ensureRunning()
+    await DocstoreClient.createDoc(
+      this.project_id,
+      this.doc_id,
+      this.lines,
+      this.version,
+      this.ranges
+    )
   })
 
   describe('when the doc exists', function () {
-    return it('should get the doc lines and version', function (done) {
-      return DocstoreClient.getDoc(
-        this.project_id,
-        this.doc_id,
-        {},
-        (error, res, doc) => {
-          if (error) return done(error)
-          doc.lines.should.deep.equal(this.lines)
-          doc.version.should.equal(this.version)
-          doc.ranges.should.deep.equal(this.fixedRanges)
-          return done()
-        }
-      )
+    it('should get the doc lines and version', async function () {
+      const doc = await DocstoreClient.getDoc(this.project_id, this.doc_id)
+      doc.lines.should.deep.equal(this.lines)
+      doc.version.should.equal(this.version)
+      doc.ranges.should.deep.equal(this.fixedRanges)
     })
   })
 
   describe('when the doc does not exist', function () {
-    return it('should return a 404', function (done) {
+    it('should return a 404', async function () {
       const missingDocId = new ObjectId()
-      return DocstoreClient.getDoc(
-        this.project_id,
-        missingDocId,
-        {},
-        (error, res, doc) => {
-          if (error) return done(error)
-          res.statusCode.should.equal(404)
-          return done()
-        }
-      )
+      await expect(DocstoreClient.getDoc(this.project_id, missingDocId))
+        .to.eventually.be.rejected.and.have.property('info')
+        .to.contain({ status: 404 })
     })
   })
 
-  return describe('when the doc is a deleted doc', function () {
-    beforeEach(function (done) {
+  describe('when the doc is a deleted doc', function () {
+    beforeEach(async function () {
       this.deleted_doc_id = new ObjectId()
-      return DocstoreClient.createDoc(
+      await DocstoreClient.createDoc(
         this.project_id,
         this.deleted_doc_id,
         this.lines,
         this.version,
-        this.ranges,
-        error => {
-          if (error != null) {
-            throw error
-          }
-          return DocstoreClient.deleteDoc(
-            this.project_id,
-            this.deleted_doc_id,
-            done
-          )
-        }
+        this.ranges
       )
+      await DocstoreClient.deleteDoc(this.project_id, this.deleted_doc_id)
     })
 
-    it('should return the doc', function (done) {
-      return DocstoreClient.getDoc(
+    it('should return the doc', async function () {
+      const doc = await DocstoreClient.getDoc(
         this.project_id,
         this.deleted_doc_id,
-        { include_deleted: true },
-        (error, res, doc) => {
-          if (error) return done(error)
-          doc.lines.should.deep.equal(this.lines)
-          doc.version.should.equal(this.version)
-          doc.ranges.should.deep.equal(this.fixedRanges)
-          doc.deleted.should.equal(true)
-          return done()
-        }
+        { include_deleted: true }
       )
+      doc.lines.should.deep.equal(this.lines)
+      doc.version.should.equal(this.version)
+      doc.ranges.should.deep.equal(this.fixedRanges)
+      doc.deleted.should.equal(true)
     })
 
-    return it('should return a 404 when the query string is not set', function (done) {
-      return DocstoreClient.getDoc(
-        this.project_id,
-        this.deleted_doc_id,
-        {},
-        (error, res, doc) => {
-          if (error) return done(error)
-          res.statusCode.should.equal(404)
-          return done()
-        }
-      )
+    it('should return a 404 when the query string is not set', async function () {
+      await expect(DocstoreClient.getDoc(this.project_id, this.deleted_doc_id))
+        .to.eventually.be.rejected.and.have.property('info')
+        .to.contain({ status: 404 })
     })
   })
 })

+ 5 - 8
services/docstore/test/acceptance/js/HealthCheckerTest.js

@@ -4,22 +4,19 @@ const DocstoreClient = require('./helpers/DocstoreClient')
 const { expect } = require('chai')
 
 describe('HealthChecker', function () {
-  beforeEach('start', function (done) {
-    DocstoreApp.ensureRunning(done)
+  beforeEach('start', async function () {
+    await DocstoreApp.ensureRunning()
   })
   beforeEach('clear docs collection', async function () {
     await db.docs.deleteMany({})
   })
   let res
-  beforeEach('run health check', function (done) {
-    DocstoreClient.healthCheck((err, _res) => {
-      res = _res
-      done(err)
-    })
+  beforeEach('run health check', async function () {
+    res = await DocstoreClient.healthCheck()
   })
 
   it('should return 200', function () {
-    res.statusCode.should.equal(200)
+    res.status.should.equal(200)
   })
 
   it('should not leave any cruft behind', async function () {

+ 181 - 342
services/docstore/test/acceptance/js/UpdatingDocsTests.js

@@ -1,22 +1,10 @@
-/* eslint-disable
-    no-unused-vars,
-*/
-// TODO: This file was created by bulk-decaffeinate.
-// Fix any style issues and re-enable lint.
-/*
- * decaffeinate suggestions:
- * DS102: Remove unnecessary code created because of implicit returns
- * DS207: Consider shorter variations of null checks
- * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
- */
-const sinon = require('sinon')
 const { ObjectId } = require('mongodb-legacy')
 const DocstoreApp = require('./helpers/DocstoreApp')
 
 const DocstoreClient = require('./helpers/DocstoreClient')
 
 describe('Applying updates to a doc', function () {
-  beforeEach(function (done) {
+  beforeEach(async function () {
     this.project_id = new ObjectId()
     this.doc_id = new ObjectId()
     this.originalLines = ['original', 'lines']
@@ -45,511 +33,362 @@ describe('Applying updates to a doc', function () {
         },
       ],
     }
+
     this.version = 42
-    return DocstoreApp.ensureRunning(() => {
-      return DocstoreClient.createDoc(
-        this.project_id,
-        this.doc_id,
-        this.originalLines,
-        this.version,
-        this.originalRanges,
-        error => {
-          if (error != null) {
-            throw error
-          }
-          return done()
-        }
-      )
-    })
+    await DocstoreApp.ensureRunning()
+    await DocstoreClient.createDoc(
+      this.project_id,
+      this.doc_id,
+      this.originalLines,
+      this.version,
+      this.originalRanges
+    )
   })
 
   describe('when nothing has been updated', function () {
-    beforeEach(function (done) {
-      return DocstoreClient.updateDoc(
+    beforeEach(async function () {
+      this.body = await DocstoreClient.updateDoc(
         this.project_id,
         this.doc_id,
         this.originalLines,
         this.version,
-        this.originalRanges,
-        (error, res, body) => {
-          if (error) return done(error)
-          this.body = body
-          return done()
-        }
+        this.originalRanges
       )
     })
 
     it('should return modified = false', function () {
-      return this.body.modified.should.equal(false)
+      this.body.modified.should.equal(false)
     })
 
-    return it('should not update the doc in the API', function (done) {
-      return DocstoreClient.getDoc(
-        this.project_id,
-        this.doc_id,
-        {},
-        (error, res, doc) => {
-          if (error) return done(error)
-          doc.lines.should.deep.equal(this.originalLines)
-          doc.version.should.equal(this.version)
-          doc.ranges.should.deep.equal(this.originalRanges)
-          return done()
-        }
-      )
+    it('should not update the doc in the API', async function () {
+      const doc = await DocstoreClient.getDoc(this.project_id, this.doc_id)
+      doc.lines.should.deep.equal(this.originalLines)
+      doc.version.should.equal(this.version)
+      doc.ranges.should.deep.equal(this.originalRanges)
     })
   })
 
   describe('when the lines have changed', function () {
-    beforeEach(function (done) {
-      return DocstoreClient.updateDoc(
+    beforeEach(async function () {
+      this.body = await DocstoreClient.updateDoc(
         this.project_id,
         this.doc_id,
         this.newLines,
         this.version,
-        this.originalRanges,
-        (error, res, body) => {
-          if (error) return done(error)
-          this.body = body
-          return done()
-        }
+        this.originalRanges
       )
     })
 
     it('should return modified = true', function () {
-      return this.body.modified.should.equal(true)
+      this.body.modified.should.equal(true)
     })
 
     it('should return the rev', function () {
-      return this.body.rev.should.equal(2)
+      this.body.rev.should.equal(2)
     })
 
-    return it('should update the doc in the API', function (done) {
-      return DocstoreClient.getDoc(
-        this.project_id,
-        this.doc_id,
-        {},
-        (error, res, doc) => {
-          if (error) return done(error)
-          doc.lines.should.deep.equal(this.newLines)
-          doc.version.should.equal(this.version)
-          doc.ranges.should.deep.equal(this.originalRanges)
-          return done()
-        }
-      )
+    it('should update the doc in the API', async function () {
+      const doc = await DocstoreClient.getDoc(this.project_id, this.doc_id)
+      doc.lines.should.deep.equal(this.newLines)
+      doc.version.should.equal(this.version)
+      doc.ranges.should.deep.equal(this.originalRanges)
     })
   })
 
   describe('when the version has changed', function () {
-    beforeEach(function (done) {
-      return DocstoreClient.updateDoc(
+    beforeEach(async function () {
+      this.body = await DocstoreClient.updateDoc(
         this.project_id,
         this.doc_id,
         this.originalLines,
         this.version + 1,
-        this.originalRanges,
-        (error, res, body) => {
-          if (error) return done(error)
-          this.body = body
-          return done()
-        }
+        this.originalRanges
       )
     })
 
     it('should return modified = true', function () {
-      return this.body.modified.should.equal(true)
+      this.body.modified.should.equal(true)
     })
 
     it('should return the rev', function () {
-      return this.body.rev.should.equal(1)
+      this.body.rev.should.equal(1)
     })
 
-    return it('should update the doc in the API', function (done) {
-      return DocstoreClient.getDoc(
-        this.project_id,
-        this.doc_id,
-        {},
-        (error, res, doc) => {
-          if (error) return done(error)
-          doc.lines.should.deep.equal(this.originalLines)
-          doc.version.should.equal(this.version + 1)
-          doc.ranges.should.deep.equal(this.originalRanges)
-          return done()
-        }
-      )
+    it('should update the doc in the API', async function () {
+      const doc = await DocstoreClient.getDoc(this.project_id, this.doc_id)
+      doc.lines.should.deep.equal(this.originalLines)
+      doc.version.should.equal(this.version + 1)
+      doc.ranges.should.deep.equal(this.originalRanges)
     })
   })
 
   describe('when the version was decremented', function () {
-    beforeEach(function (done) {
-      DocstoreClient.updateDoc(
-        this.project_id,
-        this.doc_id,
-        this.newLines,
-        this.version - 1,
-        this.newRanges,
-        (error, res, body) => {
-          if (error) return done(error)
-          this.res = res
-          this.body = body
-          done()
-        }
-      )
+    let statusCode
+    beforeEach(async function () {
+      try {
+        this.body = await DocstoreClient.updateDoc(
+          this.project_id,
+          this.doc_id,
+          this.newLines,
+          this.version - 1,
+          this.newRanges
+        )
+      } catch (error) {
+        statusCode = error.info.status
+      }
     })
 
     it('should return 409', function () {
-      this.res.statusCode.should.equal(409)
+      statusCode.should.equal(409)
     })
 
-    it('should not update the doc in the API', function (done) {
-      DocstoreClient.getDoc(
-        this.project_id,
-        this.doc_id,
-        {},
-        (error, res, doc) => {
-          if (error) return done(error)
-          doc.lines.should.deep.equal(this.originalLines)
-          doc.version.should.equal(this.version)
-          doc.ranges.should.deep.equal(this.originalRanges)
-          done()
-        }
-      )
+    it('should not update the doc in the API', async function () {
+      const doc = await DocstoreClient.getDoc(this.project_id, this.doc_id)
+      doc.lines.should.deep.equal(this.originalLines)
+      doc.version.should.equal(this.version)
+      doc.ranges.should.deep.equal(this.originalRanges)
     })
   })
 
   describe('when the ranges have changed', function () {
-    beforeEach(function (done) {
-      return DocstoreClient.updateDoc(
+    beforeEach(async function () {
+      this.body = await DocstoreClient.updateDoc(
         this.project_id,
         this.doc_id,
         this.originalLines,
         this.version,
-        this.newRanges,
-        (error, res, body) => {
-          if (error) return done(error)
-          this.body = body
-          return done()
-        }
+        this.newRanges
       )
     })
 
     it('should return modified = true', function () {
-      return this.body.modified.should.equal(true)
+      this.body.modified.should.equal(true)
     })
 
     it('should return the rev', function () {
-      return this.body.rev.should.equal(2)
+      this.body.rev.should.equal(2)
     })
 
-    return it('should update the doc in the API', function (done) {
-      return DocstoreClient.getDoc(
-        this.project_id,
-        this.doc_id,
-        {},
-        (error, res, doc) => {
-          if (error) return done(error)
-          doc.lines.should.deep.equal(this.originalLines)
-          doc.version.should.equal(this.version)
-          doc.ranges.should.deep.equal(this.newRanges)
-          return done()
-        }
-      )
+    it('should update the doc in the API', async function () {
+      const doc = await DocstoreClient.getDoc(this.project_id, this.doc_id)
+      doc.lines.should.deep.equal(this.originalLines)
+      doc.version.should.equal(this.version)
+      doc.ranges.should.deep.equal(this.newRanges)
     })
   })
 
   describe('when the doc does not exist', function () {
-    beforeEach(function (done) {
+    beforeEach(async function () {
       this.missing_doc_id = new ObjectId()
-      return DocstoreClient.updateDoc(
+      this.body = await DocstoreClient.updateDoc(
         this.project_id,
         this.missing_doc_id,
         this.originalLines,
         0,
-        this.originalRanges,
-        (error, res, body) => {
-          if (error) return done(error)
-          this.res = res
-          this.body = body
-          return done()
-        }
+        this.originalRanges
       )
     })
 
     it('should create the doc', function () {
-      return this.body.rev.should.equal(1)
+      this.body.rev.should.equal(1)
     })
 
-    return it('should be retreivable', function (done) {
-      return DocstoreClient.getDoc(
+    it('should be retreivable', async function () {
+      const doc = await DocstoreClient.getDoc(
         this.project_id,
-        this.missing_doc_id,
-        {},
-        (error, res, doc) => {
-          if (error) return done(error)
-          doc.lines.should.deep.equal(this.originalLines)
-          doc.version.should.equal(0)
-          doc.ranges.should.deep.equal(this.originalRanges)
-          return done()
-        }
+        this.missing_doc_id
       )
+      doc.lines.should.deep.equal(this.originalLines)
+      doc.version.should.equal(0)
+      doc.ranges.should.deep.equal(this.originalRanges)
     })
   })
 
   describe('when malformed doc lines are provided', function () {
     describe('when the lines are not an array', function () {
-      beforeEach(function (done) {
-        return DocstoreClient.updateDoc(
-          this.project_id,
-          this.doc_id,
-          { foo: 'bar' },
-          this.version,
-          this.originalRanges,
-          (error, res, body) => {
-            if (error) return done(error)
-            this.res = res
-            this.body = body
-            return done()
-          }
-        )
+      let statusCode
+      beforeEach(async function () {
+        try {
+          this.body = await DocstoreClient.updateDoc(
+            this.project_id,
+            this.doc_id,
+            { foo: 'bar' },
+            this.version,
+            this.originalRanges
+          )
+        } catch (error) {
+          statusCode = error.info.status
+        }
       })
 
       it('should return 400', function () {
-        return this.res.statusCode.should.equal(400)
+        statusCode.should.equal(400)
       })
 
-      return it('should not update the doc in the API', function (done) {
-        return DocstoreClient.getDoc(
-          this.project_id,
-          this.doc_id,
-          {},
-          (error, res, doc) => {
-            if (error) return done(error)
-            doc.lines.should.deep.equal(this.originalLines)
-            return done()
-          }
-        )
+      it('should not update the doc in the API', async function () {
+        const doc = await DocstoreClient.getDoc(this.project_id, this.doc_id)
+        doc.lines.should.deep.equal(this.originalLines)
       })
     })
 
-    return describe('when the lines are not present', function () {
-      beforeEach(function (done) {
-        return DocstoreClient.updateDoc(
-          this.project_id,
-          this.doc_id,
-          null,
-          this.version,
-          this.originalRanges,
-          (error, res, body) => {
-            if (error) return done(error)
-            this.res = res
-            this.body = body
-            return done()
-          }
-        )
+    describe('when the lines are not present', function () {
+      let statusCode
+      beforeEach(async function () {
+        try {
+          this.body = await DocstoreClient.updateDoc(
+            this.project_id,
+            this.doc_id,
+            null,
+            this.version,
+            this.originalRanges
+          )
+        } catch (error) {
+          statusCode = error.info.status
+        }
       })
 
       it('should return 400', function () {
-        return this.res.statusCode.should.equal(400)
+        statusCode.should.equal(400)
       })
 
-      return it('should not update the doc in the API', function (done) {
-        return DocstoreClient.getDoc(
-          this.project_id,
-          this.doc_id,
-          {},
-          (error, res, doc) => {
-            if (error) return done(error)
-            doc.lines.should.deep.equal(this.originalLines)
-            return done()
-          }
-        )
+      it('should not update the doc in the API', async function () {
+        const doc = await DocstoreClient.getDoc(this.project_id, this.doc_id)
+        doc.lines.should.deep.equal(this.originalLines)
       })
     })
   })
 
   describe('when no version is provided', function () {
-    beforeEach(function (done) {
-      return DocstoreClient.updateDoc(
-        this.project_id,
-        this.doc_id,
-        this.originalLines,
-        null,
-        this.originalRanges,
-        (error, res, body) => {
-          if (error) return done(error)
-          this.res = res
-          this.body = body
-          return done()
-        }
-      )
+    let statusCode
+    beforeEach(async function () {
+      try {
+        this.body = await DocstoreClient.updateDoc(
+          this.project_id,
+          this.doc_id,
+          this.originalLines,
+          null,
+          this.originalRanges
+        )
+      } catch (error) {
+        statusCode = error.info.status
+      }
     })
 
     it('should return 400', function () {
-      return this.res.statusCode.should.equal(400)
+      statusCode.should.equal(400)
     })
 
-    return it('should not update the doc in the API', function (done) {
-      return DocstoreClient.getDoc(
-        this.project_id,
-        this.doc_id,
-        {},
-        (error, res, doc) => {
-          if (error) return done(error)
-          doc.lines.should.deep.equal(this.originalLines)
-          doc.version.should.equal(this.version)
-          return done()
-        }
-      )
+    it('should not update the doc in the API', async function () {
+      const doc = await DocstoreClient.getDoc(this.project_id, this.doc_id)
+      doc.lines.should.deep.equal(this.originalLines)
+      doc.version.should.equal(this.version)
     })
   })
 
   describe('when the content is large', function () {
-    beforeEach(function (done) {
+    beforeEach(async function () {
       const line = new Array(1025).join('x') // 1kb
       this.largeLines = Array.apply(null, Array(1024)).map(() => line) // 1mb
-      return DocstoreClient.updateDoc(
+      this.body = await DocstoreClient.updateDoc(
         this.project_id,
         this.doc_id,
         this.largeLines,
         this.version,
-        this.originalRanges,
-        (error, res, body) => {
-          if (error) return done(error)
-          this.body = body
-          return done()
-        }
+        this.originalRanges
       )
     })
 
     it('should return modified = true', function () {
-      return this.body.modified.should.equal(true)
+      this.body.modified.should.equal(true)
     })
 
-    return it('should update the doc in the API', function (done) {
-      return DocstoreClient.getDoc(
-        this.project_id,
-        this.doc_id,
-        {},
-        (error, res, doc) => {
-          if (error) return done(error)
-          doc.lines.should.deep.equal(this.largeLines)
-          return done()
-        }
-      )
+    it('should update the doc in the API', async function () {
+      const doc = await DocstoreClient.getDoc(this.project_id, this.doc_id)
+      doc.lines.should.deep.equal(this.largeLines)
     })
   })
 
   describe('when there is a large json payload', function () {
-    beforeEach(function (done) {
+    beforeEach(async function () {
       const line = new Array(1025).join('x') // 1kb
       this.largeLines = Array.apply(null, Array(1024)).map(() => line) // 1kb
       this.originalRanges.padding = Array.apply(null, Array(2049)).map(
         () => line
       ) // 2mb + 1kb
-      return DocstoreClient.updateDoc(
+      this.body = await DocstoreClient.updateDoc(
         this.project_id,
         this.doc_id,
         this.largeLines,
         this.version,
-        this.originalRanges,
-        (error, res, body) => {
-          if (error) return done(error)
-          this.res = res
-          this.body = body
-          return done()
-        }
+        this.originalRanges
       )
     })
 
     it('should return modified = true', function () {
-      return this.body.modified.should.equal(true)
+      this.body.modified.should.equal(true)
     })
 
-    return it('should update the doc in the API', function (done) {
-      return DocstoreClient.getDoc(
-        this.project_id,
-        this.doc_id,
-        {},
-        (error, res, doc) => {
-          if (error) return done(error)
-          doc.lines.should.deep.equal(this.largeLines)
-          return done()
-        }
-      )
+    it('should update the doc in the API', async function () {
+      const doc = await DocstoreClient.getDoc(this.project_id, this.doc_id)
+      doc.lines.should.deep.equal(this.largeLines)
     })
   })
 
   describe('when the document body is too large', function () {
-    beforeEach(function (done) {
+    let statusCode, body
+    beforeEach(async function () {
       const line = new Array(1025).join('x') // 1kb
       this.largeLines = Array.apply(null, Array(2049)).map(() => line) // 2mb + 1kb
-      return DocstoreClient.updateDoc(
-        this.project_id,
-        this.doc_id,
-        this.largeLines,
-        this.version,
-        this.originalRanges,
-        (error, res, body) => {
-          if (error) return done(error)
-          this.res = res
-          this.body = body
-          return done()
-        }
-      )
+      try {
+        this.body = await DocstoreClient.updateDoc(
+          this.project_id,
+          this.doc_id,
+          this.largeLines,
+          this.version,
+          this.originalRanges
+        )
+      } catch (error) {
+        statusCode = error.info.status
+        body = error.body
+      }
     })
 
     it('should return 413', function () {
-      return this.res.statusCode.should.equal(413)
+      statusCode.should.equal(413)
     })
 
     it('should report body too large', function () {
-      return this.res.body.should.equal('document body too large')
+      body.should.equal('document body too large')
     })
 
-    return it('should not update the doc in the API', function (done) {
-      return DocstoreClient.getDoc(
-        this.project_id,
-        this.doc_id,
-        {},
-        (error, res, doc) => {
-          if (error) return done(error)
-          doc.lines.should.deep.equal(this.originalLines)
-          return done()
-        }
-      )
+    it('should not update the doc in the API', async function () {
+      const doc = await DocstoreClient.getDoc(this.project_id, this.doc_id)
+      doc.lines.should.deep.equal(this.originalLines)
     })
   })
 
-  return describe('when the json payload is too large', function () {
-    beforeEach(function (done) {
+  describe('when the json payload is too large', function () {
+    beforeEach(async function () {
       const line = new Array(1024).join('x') // 1 KB
       this.largeLines = new Array(8192).fill(line) // 8 MB
       this.originalRanges.padding = new Array(6144).fill(line) // 6 MB
-      return DocstoreClient.updateDoc(
-        this.project_id,
-        this.doc_id,
-        this.largeLines,
-        this.version,
-        this.originalRanges,
-        (error, res, body) => {
-          if (error) return done(error)
-          this.res = res
-          this.body = body
-          return done()
-        }
-      )
+
+      try {
+        this.body = await DocstoreClient.updateDoc(
+          this.project_id,
+          this.doc_id,
+          this.largeLines,
+          this.version,
+          this.originalRanges
+        )
+      } catch (error) {
+        // ignore error response
+      }
     })
 
-    return it('should not update the doc in the API', function (done) {
-      return DocstoreClient.getDoc(
-        this.project_id,
-        this.doc_id,
-        {},
-        (error, res, doc) => {
-          if (error) return done(error)
-          doc.lines.should.deep.equal(this.originalLines)
-          return done()
-        }
-      )
+    it('should not update the doc in the API', async function () {
+      const doc = await DocstoreClient.getDoc(this.project_id, this.doc_id)
+      doc.lines.should.deep.equal(this.originalLines)
     })
   })
 })

+ 27 - 22
services/docstore/test/acceptance/js/helpers/DocstoreApp.js

@@ -1,26 +1,31 @@
 const app = require('../../../../app')
-const settings = require('@overleaf/settings')
+const Settings = require('@overleaf/settings')
 
-module.exports = {
-  running: false,
-  initing: false,
-  callbacks: [],
-  ensureRunning(callback) {
-    if (this.running) {
-      return callback()
-    } else if (this.initing) {
-      return this.callbacks.push(callback)
-    }
-    this.initing = true
-    this.callbacks.push(callback)
-    app.listen(settings.internal.docstore.port, '127.0.0.1', error => {
-      if (error != null) {
-        throw error
-      }
-      this.running = true
-      for (callback of Array.from(this.callbacks)) {
-        callback()
+function startApp() {
+  return new Promise((resolve, reject) => {
+    app.listen(
+      Settings.internal.docstore.port,
+      Settings.internal.docstore.host,
+      error => {
+        if (error) {
+          reject(error)
+        } else {
+          resolve()
+        }
       }
-    })
-  },
+    )
+  })
+}
+
+let appStartedPromise
+
+async function ensureRunning() {
+  if (!appStartedPromise) {
+    appStartedPromise = startApp()
+  }
+  await appStartedPromise
+}
+
+module.exports = {
+  ensureRunning,
 }

+ 79 - 123
services/docstore/test/acceptance/js/helpers/DocstoreClient.js

@@ -1,5 +1,9 @@
 let DocstoreClient
-const request = require('request').defaults({ jar: false })
+const {
+  fetchNothing,
+  fetchJson,
+  fetchJsonWithResponse,
+} = require('@overleaf/fetch-utils')
 const settings = require('@overleaf/settings')
 const Persistor = require('../../../../app/js/PersistorManager')
 
@@ -19,204 +23,156 @@ async function getStringFromPersistor(persistor, bucket, key) {
 }
 
 module.exports = DocstoreClient = {
-  createDoc(projectId, docId, lines, version, ranges, callback) {
-    return DocstoreClient.updateDoc(
+  async createDoc(projectId, docId, lines, version, ranges) {
+    return await DocstoreClient.updateDoc(
       projectId,
       docId,
       lines,
       version,
-      ranges,
-      callback
+      ranges
     )
   },
 
-  getDoc(projectId, docId, qs, callback) {
-    request.get(
-      {
-        url: `http://127.0.0.1:${settings.internal.docstore.port}/project/${projectId}/doc/${docId}`,
-        json: true,
-        qs,
-      },
-      callback
+  async getDoc(projectId, docId, qs = {}) {
+    const url = new URL(
+      `http://127.0.0.1:${settings.internal.docstore.port}/project/${projectId}/doc/${docId}`
     )
+    for (const [key, value] of Object.entries(qs)) {
+      url.searchParams.append(key, value)
+    }
+    return await fetchJson(url)
   },
 
-  peekDoc(projectId, docId, qs, callback) {
-    request.get(
-      {
-        url: `http://127.0.0.1:${settings.internal.docstore.port}/project/${projectId}/doc/${docId}/peek`,
-        json: true,
-        qs,
-      },
-      callback
+  async peekDoc(projectId, docId, qs = {}) {
+    const url = new URL(
+      `http://127.0.0.1:${settings.internal.docstore.port}/project/${projectId}/doc/${docId}/peek`
     )
+    for (const [key, value] of Object.entries(qs)) {
+      url.searchParams.append(key, value)
+    }
+    const { response, json } = await fetchJsonWithResponse(url)
+    return { res: response, doc: json }
   },
 
-  isDocDeleted(projectId, docId, callback) {
-    request.get(
-      {
-        url: `http://127.0.0.1:${settings.internal.docstore.port}/project/${projectId}/doc/${docId}/deleted`,
-        json: true,
-      },
-      callback
+  async isDocDeleted(projectId, docId) {
+    const { response, json } = await fetchJsonWithResponse(
+      `http://127.0.0.1:${settings.internal.docstore.port}/project/${projectId}/doc/${docId}/deleted`
     )
+    return { res: response, body: json }
   },
 
-  getAllDocs(projectId, callback) {
-    request.get(
-      {
-        url: `http://127.0.0.1:${settings.internal.docstore.port}/project/${projectId}/doc`,
-        json: true,
-      },
-      (req, res, body) => {
-        callback(req, res, body)
-      }
+  async getAllDocs(projectId) {
+    return await fetchJson(
+      `http://127.0.0.1:${settings.internal.docstore.port}/project/${projectId}/doc`
     )
   },
 
-  getAllDeletedDocs(projectId, callback) {
-    request.get(
-      {
-        url: `http://127.0.0.1:${settings.internal.docstore.port}/project/${projectId}/doc-deleted`,
-        json: true,
-      },
-      (error, res, body) => {
-        if (error) return callback(error)
-        if (res.statusCode !== 200) {
-          return callback(new Error('unexpected statusCode'))
-        }
-        callback(null, body)
-      }
+  async getAllDeletedDocs(projectId, callback) {
+    return await fetchJson(
+      `http://127.0.0.1:${settings.internal.docstore.port}/project/${projectId}/doc-deleted`
     )
   },
 
-  getAllRanges(projectId, callback) {
-    request.get(
-      {
-        url: `http://127.0.0.1:${settings.internal.docstore.port}/project/${projectId}/ranges`,
-        json: true,
-      },
-      callback
+  async getAllRanges(projectId) {
+    return await fetchJson(
+      `http://127.0.0.1:${settings.internal.docstore.port}/project/${projectId}/ranges`
     )
   },
 
-  getCommentThreadIds(projectId, callback) {
-    request.get(
-      {
-        url: `http://127.0.0.1:${settings.internal.docstore.port}/project/${projectId}/comment-thread-ids`,
-        json: true,
-      },
-      callback
+  async getCommentThreadIds(projectId, callback) {
+    return await fetchJson(
+      `http://127.0.0.1:${settings.internal.docstore.port}/project/${projectId}/comment-thread-ids`
     )
   },
 
-  getTrackedChangesUserIds(projectId, callback) {
-    request.get(
-      {
-        url: `http://127.0.0.1:${settings.internal.docstore.port}/project/${projectId}/tracked-changes-user-ids`,
-        json: true,
-      },
-      callback
+  async getTrackedChangesUserIds(projectId) {
+    return await fetchJson(
+      `http://127.0.0.1:${settings.internal.docstore.port}/project/${projectId}/tracked-changes-user-ids`
     )
   },
 
-  updateDoc(projectId, docId, lines, version, ranges, callback) {
-    return request.post(
+  async updateDoc(projectId, docId, lines, version, ranges) {
+    const res = await fetchJson(
+      `http://127.0.0.1:${settings.internal.docstore.port}/project/${projectId}/doc/${docId}`,
       {
-        url: `http://127.0.0.1:${settings.internal.docstore.port}/project/${projectId}/doc/${docId}`,
+        method: 'POST',
         json: {
           lines,
           version,
           ranges,
         },
-      },
-      callback
+      }
     )
+    return res
   },
 
-  deleteDoc(projectId, docId, callback) {
-    DocstoreClient.deleteDocWithDateAndName(
+  async deleteDoc(projectId, docId) {
+    return await DocstoreClient.deleteDocWithDateAndName(
       projectId,
       docId,
       new Date(),
-      'main.tex',
-      callback
+      'main.tex'
     )
   },
 
-  deleteDocWithDate(projectId, docId, date, callback) {
-    DocstoreClient.deleteDocWithDateAndName(
+  async deleteDocWithDate(projectId, docId, date) {
+    return await DocstoreClient.deleteDocWithDateAndName(
       projectId,
       docId,
       date,
-      'main.tex',
-      callback
+      'main.tex'
     )
   },
 
-  deleteDocWithName(projectId, docId, name, callback) {
-    DocstoreClient.deleteDocWithDateAndName(
+  async deleteDocWithName(projectId, docId, name) {
+    return await DocstoreClient.deleteDocWithDateAndName(
       projectId,
       docId,
       new Date(),
-      name,
-      callback
+      name
     )
   },
 
-  deleteDocWithDateAndName(projectId, docId, deletedAt, name, callback) {
-    request.patch(
-      {
-        url: `http://127.0.0.1:${settings.internal.docstore.port}/project/${projectId}/doc/${docId}`,
-        json: { name, deleted: true, deletedAt },
-      },
-      callback
+  async deleteDocWithDateAndName(projectId, docId, deletedAt, name) {
+    return await fetchNothing(
+      `http://127.0.0.1:${settings.internal.docstore.port}/project/${projectId}/doc/${docId}`,
+      { method: 'PATCH', json: { name, deleted: true, deletedAt } }
     )
   },
 
-  archiveAllDoc(projectId, callback) {
-    request.post(
-      {
-        url: `http://127.0.0.1:${settings.internal.docstore.port}/project/${projectId}/archive`,
-      },
-      callback
+  async archiveAllDoc(projectId) {
+    return await fetchNothing(
+      `http://127.0.0.1:${settings.internal.docstore.port}/project/${projectId}/archive`,
+      { method: 'POST' }
     )
   },
 
-  archiveDoc(projectId, docId, callback) {
-    request.post(
-      {
-        url: `http://127.0.0.1:${settings.internal.docstore.port}/project/${projectId}/doc/${docId}/archive`,
-      },
-      callback
+  async archiveDoc(projectId, docId) {
+    return await fetchNothing(
+      `http://127.0.0.1:${settings.internal.docstore.port}/project/${projectId}/doc/${docId}/archive`,
+      { method: 'POST' }
     )
   },
 
-  destroyAllDoc(projectId, callback) {
-    request.post(
-      {
-        url: `http://127.0.0.1:${settings.internal.docstore.port}/project/${projectId}/destroy`,
-      },
-      callback
+  async destroyAllDoc(projectId) {
+    await fetchNothing(
+      `http://127.0.0.1:${settings.internal.docstore.port}/project/${projectId}/destroy`,
+      { method: 'POST' }
     )
   },
 
-  healthCheck(callback) {
-    request.get(
-      `http://127.0.0.1:${settings.internal.docstore.port}/health_check`,
-      callback
+  async healthCheck() {
+    return await fetchNothing(
+      `http://127.0.0.1:${settings.internal.docstore.port}/health_check`
     )
   },
 
-  getS3Doc(projectId, docId, callback) {
-    getStringFromPersistor(
+  async getS3Doc(projectId, docId) {
+    const data = await getStringFromPersistor(
       Persistor,
       settings.docstore.bucket,
       `${projectId}/${docId}`
     )
-      .then(data => {
-        callback(null, JSON.parse(data))
-      })
-      .catch(callback)
+    return JSON.parse(data)
   },
 }