| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574 |
- /* eslint-disable
- camelcase,
- handle-callback-err,
- no-return-assign,
- 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
- * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
- */
- const { assert } = require('chai')
- const sinon = require('sinon')
- const chai = require('chai')
- const should = chai.should()
- const { expect } = chai
- const modulePath = '../../../app/js/DocArchiveManager.js'
- const SandboxedModule = require('sandboxed-module')
- const { ObjectId } = require('mongojs')
- const Errors = require('../../../app/js/Errors')
- const crypto = require('crypto')
- describe('DocArchiveManager', function () {
- beforeEach(function () {
- this.settings = {
- docstore: {
- s3: {
- secret: 'secret',
- key: 'this_key',
- bucket: 'doc-archive-unit-test'
- }
- }
- }
- this.request = {
- put: {},
- get: {},
- del: {}
- }
- this.archivedDocs = [
- {
- _id: ObjectId(),
- inS3: true,
- rev: 2
- },
- {
- _id: ObjectId(),
- inS3: true,
- rev: 4
- },
- {
- _id: ObjectId(),
- inS3: true,
- rev: 6
- }
- ]
- this.mongoDocs = [
- {
- _id: ObjectId(),
- lines: ['one', 'two', 'three'],
- rev: 2
- },
- {
- _id: ObjectId(),
- lines: ['aaa', 'bbb', 'ccc'],
- rev: 4
- },
- {
- _id: ObjectId(),
- inS3: true,
- rev: 6
- },
- {
- _id: ObjectId(),
- inS3: true,
- rev: 6
- },
- {
- _id: ObjectId(),
- lines: ['111', '222', '333'],
- rev: 6
- }
- ]
- this.unarchivedDocs = [
- {
- _id: ObjectId(),
- lines: ['wombat', 'potato', 'banana'],
- rev: 2
- },
- {
- _id: ObjectId(),
- lines: ['llama', 'turnip', 'apple'],
- rev: 4
- },
- {
- _id: ObjectId(),
- lines: ['elephant', 'swede', 'nectarine'],
- rev: 6
- }
- ]
- this.mixedDocs = this.archivedDocs.concat(this.unarchivedDocs)
- this.MongoManager = {
- markDocAsArchived: sinon.stub().callsArgWith(2, null),
- upsertIntoDocCollection: sinon.stub().callsArgWith(3, null),
- getProjectsDocs: sinon.stub().callsArgWith(3, null, this.mongoDocs),
- getArchivedProjectDocs: sinon.stub().callsArgWith(2, null, this.mongoDocs)
- }
- this.requires = {
- 'settings-sharelatex': this.settings,
- './MongoManager': this.MongoManager,
- request: this.request,
- './RangeManager': (this.RangeManager = {}),
- 'logger-sharelatex': {
- log() {},
- err() {}
- }
- }
- this.globals = { JSON }
- this.error = 'my errror'
- this.project_id = ObjectId().toString()
- this.stubbedError = new Errors.NotFoundError('Error in S3 request')
- return (this.DocArchiveManager = SandboxedModule.require(modulePath, {
- requires: this.requires,
- globals: this.globals
- }))
- })
- describe('archiveDoc', function () {
- it('should use correct options', function (done) {
- this.request.put = sinon
- .stub()
- .callsArgWith(1, null, { statusCode: 200, headers: { etag: '' } })
- return this.DocArchiveManager.archiveDoc(
- this.project_id,
- this.mongoDocs[0],
- (err) => {
- const opts = this.request.put.args[0][0]
- assert.deepEqual(opts.aws, {
- key: this.settings.docstore.s3.key,
- secret: this.settings.docstore.s3.secret,
- bucket: this.settings.docstore.s3.bucket
- })
- opts.body.should.equal(
- JSON.stringify({
- lines: this.mongoDocs[0].lines,
- ranges: this.mongoDocs[0].ranges,
- schema_v: 1
- })
- )
- opts.timeout.should.equal(30 * 1000)
- opts.uri.should.equal(
- `https://${this.settings.docstore.s3.bucket}.s3.amazonaws.com/${this.project_id}/${this.mongoDocs[0]._id}`
- )
- return done()
- }
- )
- })
- it('should return no md5 error', function (done) {
- const data = JSON.stringify({
- lines: this.mongoDocs[0].lines,
- ranges: this.mongoDocs[0].ranges,
- schema_v: 1
- })
- this.md5 = crypto.createHash('md5').update(data).digest('hex')
- this.request.put = sinon
- .stub()
- .callsArgWith(1, null, { statusCode: 200, headers: { etag: this.md5 } })
- return this.DocArchiveManager.archiveDoc(
- this.project_id,
- this.mongoDocs[0],
- (err) => {
- should.not.exist(err)
- return done()
- }
- )
- })
- return it('should return the error', function (done) {
- this.request.put = sinon.stub().callsArgWith(1, this.stubbedError, {
- statusCode: 400,
- headers: { etag: '' }
- })
- return this.DocArchiveManager.archiveDoc(
- this.project_id,
- this.mongoDocs[0],
- (err) => {
- should.exist(err)
- return done()
- }
- )
- })
- })
- describe('unarchiveDoc', function () {
- it('should use correct options', function (done) {
- this.request.get = sinon
- .stub()
- .callsArgWith(1, null, { statusCode: 200 }, this.mongoDocs[0].lines)
- this.request.del = sinon
- .stub()
- .callsArgWith(1, null, { statusCode: 204 }, {})
- return this.DocArchiveManager.unarchiveDoc(
- this.project_id,
- this.mongoDocs[0]._id,
- (err) => {
- const opts = this.request.get.args[0][0]
- assert.deepEqual(opts.aws, {
- key: this.settings.docstore.s3.key,
- secret: this.settings.docstore.s3.secret,
- bucket: this.settings.docstore.s3.bucket
- })
- opts.json.should.equal(true)
- opts.timeout.should.equal(30 * 1000)
- opts.uri.should.equal(
- `https://${this.settings.docstore.s3.bucket}.s3.amazonaws.com/${this.project_id}/${this.mongoDocs[0]._id}`
- )
- return done()
- }
- )
- })
- it('should return the error', function (done) {
- this.request.get = sinon.stub().callsArgWith(1, this.stubbedError, {}, {})
- return this.DocArchiveManager.unarchiveDoc(
- this.project_id,
- this.mongoDocs[0],
- (err) => {
- should.exist(err)
- return done()
- }
- )
- })
- return it('should error if the doc lines are a string not an array', function (done) {
- this.request.get = sinon
- .stub()
- .callsArgWith(1, null, { statusCode: 200 }, 'this is a string')
- this.request.del = sinon.stub()
- return this.DocArchiveManager.unarchiveDoc(
- this.project_id,
- this.mongoDocs[0],
- (err) => {
- should.exist(err)
- this.request.del.called.should.equal(false)
- return done()
- }
- )
- })
- })
- describe('archiveAllDocs', function () {
- it('should archive all project docs which are not in s3', function (done) {
- this.MongoManager.getProjectsDocs = sinon
- .stub()
- .callsArgWith(3, null, this.mongoDocs)
- this.DocArchiveManager.archiveDoc = sinon.stub().callsArgWith(2, null)
- return this.DocArchiveManager.archiveAllDocs(this.project_id, (err) => {
- this.DocArchiveManager.archiveDoc
- .calledWith(this.project_id, this.mongoDocs[0])
- .should.equal(true)
- this.DocArchiveManager.archiveDoc
- .calledWith(this.project_id, this.mongoDocs[1])
- .should.equal(true)
- this.DocArchiveManager.archiveDoc
- .calledWith(this.project_id, this.mongoDocs[4])
- .should.equal(true)
- this.DocArchiveManager.archiveDoc
- .calledWith(this.project_id, this.mongoDocs[2])
- .should.equal(false)
- this.DocArchiveManager.archiveDoc
- .calledWith(this.project_id, this.mongoDocs[3])
- .should.equal(false)
- should.not.exist(err)
- return done()
- })
- })
- it('should return error if have no docs', function (done) {
- this.MongoManager.getProjectsDocs = sinon
- .stub()
- .callsArgWith(3, null, null)
- return this.DocArchiveManager.archiveAllDocs(this.project_id, (err) => {
- should.exist(err)
- return done()
- })
- })
- it('should return the error', function (done) {
- this.MongoManager.getProjectsDocs = sinon
- .stub()
- .callsArgWith(3, this.error, null)
- return this.DocArchiveManager.archiveAllDocs(this.project_id, (err) => {
- err.should.equal(this.error)
- return done()
- })
- })
- return describe('when most have been already put in s3', function () {
- beforeEach(function () {
- let numberOfDocs = 10 * 1000
- this.mongoDocs = []
- while (--numberOfDocs !== 0) {
- this.mongoDocs.push({ inS3: true, _id: ObjectId() })
- }
- this.MongoManager.getProjectsDocs = sinon
- .stub()
- .callsArgWith(3, null, this.mongoDocs)
- return (this.DocArchiveManager.archiveDoc = sinon
- .stub()
- .callsArgWith(2, null))
- })
- return it('should not throw and error', function (done) {
- return this.DocArchiveManager.archiveAllDocs(this.project_id, (err) => {
- should.not.exist(err)
- return done()
- })
- })
- })
- })
- describe('unArchiveAllDocs', function () {
- it('should unarchive all inS3 docs', function (done) {
- this.MongoManager.getArchivedProjectDocs = sinon
- .stub()
- .callsArgWith(1, null, this.archivedDocs)
- this.DocArchiveManager.unarchiveDoc = sinon.stub().callsArgWith(2, null)
- return this.DocArchiveManager.unArchiveAllDocs(this.project_id, (err) => {
- for (const doc of Array.from(this.archivedDocs)) {
- this.DocArchiveManager.unarchiveDoc
- .calledWith(this.project_id, doc._id)
- .should.equal(true)
- }
- should.not.exist(err)
- return done()
- })
- })
- it('should return error if have no docs', function (done) {
- this.MongoManager.getArchivedProjectDocs = sinon
- .stub()
- .callsArgWith(1, null, null)
- return this.DocArchiveManager.unArchiveAllDocs(this.project_id, (err) => {
- should.exist(err)
- return done()
- })
- })
- return it('should return the error', function (done) {
- this.MongoManager.getArchivedProjectDocs = sinon
- .stub()
- .callsArgWith(1, this.error, null)
- return this.DocArchiveManager.unArchiveAllDocs(this.project_id, (err) => {
- err.should.equal(this.error)
- return done()
- })
- })
- })
- describe('destroyAllDocs', function () {
- beforeEach(function () {
- this.request.del = sinon
- .stub()
- .callsArgWith(1, null, { statusCode: 204 }, {})
- this.MongoManager.getProjectsDocs = sinon
- .stub()
- .callsArgWith(3, null, this.mixedDocs)
- this.MongoManager.findDoc = sinon.stub().callsArgWith(3, null, null)
- this.MongoManager.destroyDoc = sinon.stub().yields()
- return Array.from(this.mixedDocs).map((doc) =>
- this.MongoManager.findDoc
- .withArgs(this.project_id, doc._id)
- .callsArgWith(3, null, doc)
- )
- })
- it('should destroy all the docs', function (done) {
- this.DocArchiveManager.destroyDoc = sinon.stub().callsArgWith(2, null)
- return this.DocArchiveManager.destroyAllDocs(this.project_id, (err) => {
- for (const doc of Array.from(this.mixedDocs)) {
- this.DocArchiveManager.destroyDoc
- .calledWith(this.project_id, doc._id)
- .should.equal(true)
- }
- should.not.exist(err)
- return done()
- })
- })
- it('should only the s3 docs from s3', function (done) {
- const docOpts = (doc) => {
- return JSON.parse(
- JSON.stringify({
- aws: {
- key: this.settings.docstore.s3.key,
- secret: this.settings.docstore.s3.secret,
- bucket: this.settings.docstore.s3.bucket
- },
- json: true,
- timeout: 30 * 1000,
- uri: `https://${this.settings.docstore.s3.bucket}.s3.amazonaws.com/${this.project_id}/${doc._id}`
- })
- )
- }
- return this.DocArchiveManager.destroyAllDocs(this.project_id, (err) => {
- let doc
- expect(err).not.to.exist
- for (doc of Array.from(this.archivedDocs)) {
- sinon.assert.calledWith(this.request.del, docOpts(doc))
- }
- for (doc of Array.from(this.unarchivedDocs)) {
- expect(this.request.del.calledWith(docOpts(doc))).to.equal(false)
- } // no notCalledWith
- return done()
- })
- })
- return it('should remove the docs from mongo', function (done) {
- this.DocArchiveManager.destroyAllDocs(this.project_id, (err) => {
- return expect(err).not.to.exist
- })
- for (const doc of Array.from(this.mixedDocs)) {
- sinon.assert.calledWith(this.MongoManager.destroyDoc, doc._id)
- }
- return done()
- })
- })
- describe('_s3DocToMongoDoc', function () {
- describe('with the old schema', function () {
- return it('should return the docs lines', function (done) {
- return this.DocArchiveManager._s3DocToMongoDoc(
- ['doc', 'lines'],
- (error, doc) => {
- expect(doc).to.deep.equal({
- lines: ['doc', 'lines']
- })
- return done()
- }
- )
- })
- })
- describe('with the new schema', function () {
- it('should return the doc lines and ranges', function (done) {
- this.RangeManager.jsonRangesToMongo = sinon
- .stub()
- .returns({ mongo: 'ranges' })
- return this.DocArchiveManager._s3DocToMongoDoc(
- {
- lines: ['doc', 'lines'],
- ranges: { json: 'ranges' },
- schema_v: 1
- },
- (error, doc) => {
- expect(doc).to.deep.equal({
- lines: ['doc', 'lines'],
- ranges: { mongo: 'ranges' }
- })
- return done()
- }
- )
- })
- return it('should return just the doc lines when there are no ranges', function (done) {
- return this.DocArchiveManager._s3DocToMongoDoc(
- {
- lines: ['doc', 'lines'],
- schema_v: 1
- },
- (error, doc) => {
- expect(doc).to.deep.equal({
- lines: ['doc', 'lines']
- })
- return done()
- }
- )
- })
- })
- return describe('with an unrecognised schema', function () {
- return it('should return an error', function (done) {
- return this.DocArchiveManager._s3DocToMongoDoc(
- {
- schema_v: 2
- },
- (error, doc) => {
- expect(error).to.exist
- return done()
- }
- )
- })
- })
- })
- return describe('_mongoDocToS3Doc', function () {
- describe('with a valid doc', function () {
- return it('should return the json version', function (done) {
- let doc
- return this.DocArchiveManager._mongoDocToS3Doc(
- (doc = {
- lines: ['doc', 'lines'],
- ranges: { mock: 'ranges' }
- }),
- (err, s3_doc) => {
- expect(s3_doc).to.equal(
- JSON.stringify({
- lines: ['doc', 'lines'],
- ranges: { mock: 'ranges' },
- schema_v: 1
- })
- )
- return done()
- }
- )
- })
- })
- describe('with null bytes in the result', function () {
- beforeEach(function () {
- this._stringify = JSON.stringify
- return (JSON.stringify = sinon.stub().returns('{"bad": "\u0000"}'))
- })
- afterEach(function () {
- return (JSON.stringify = this._stringify)
- })
- return it('should return an error', function (done) {
- return this.DocArchiveManager._mongoDocToS3Doc(
- {
- lines: ['doc', 'lines'],
- ranges: { mock: 'ranges' }
- },
- (err, s3_doc) => {
- expect(err).to.exist
- return done()
- }
- )
- })
- })
- return describe('without doc lines', function () {
- return it('should return an error', function (done) {
- return this.DocArchiveManager._mongoDocToS3Doc({}, (err, s3_doc) => {
- expect(err).to.exist
- return done()
- })
- })
- })
- })
- })
|