decaffeinate: Convert AWSSDKPersistorManagerTests.coffee and 12 other files to JS

This commit is contained in:
decaffeinate 2019-12-16 11:20:22 +00:00 committed by Simon Detheridge
parent 72c83bdaff
commit 5cf7138ef1
13 changed files with 2167 additions and 1554 deletions

View file

@ -1,272 +1,353 @@
sinon = require 'sinon'
chai = require 'chai'
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const sinon = require('sinon');
const chai = require('chai');
should = chai.should()
expect = chai.expect
const should = chai.should();
const {
expect
} = chai;
modulePath = "../../../app/js/AWSSDKPersistorManager.js"
SandboxedModule = require 'sandboxed-module'
const modulePath = "../../../app/js/AWSSDKPersistorManager.js";
const SandboxedModule = require('sandboxed-module');
describe "AWSSDKPersistorManager", ->
beforeEach ->
@settings =
filestore:
describe("AWSSDKPersistorManager", function() {
beforeEach(function() {
this.settings = {
filestore: {
backend: "aws-sdk"
@s3 =
upload: sinon.stub()
getObject: sinon.stub()
copyObject: sinon.stub()
deleteObject: sinon.stub()
listObjects: sinon.stub()
deleteObjects: sinon.stub()
}
};
this.s3 = {
upload: sinon.stub(),
getObject: sinon.stub(),
copyObject: sinon.stub(),
deleteObject: sinon.stub(),
listObjects: sinon.stub(),
deleteObjects: sinon.stub(),
headObject: sinon.stub()
@awssdk =
S3: sinon.stub().returns @s3
};
this.awssdk =
{S3: sinon.stub().returns(this.s3)};
@requires =
"aws-sdk": @awssdk
"settings-sharelatex": @settings
"logger-sharelatex":
log:->
err:->
"fs": @fs =
createReadStream: sinon.stub()
"./Errors": @Errors =
NotFoundError: sinon.stub()
@key = "my/key"
@bucketName = "my-bucket"
@error = "my error"
@AWSSDKPersistorManager = SandboxedModule.require modulePath, requires: @requires
this.requires = {
"aws-sdk": this.awssdk,
"settings-sharelatex": this.settings,
"logger-sharelatex": {
log() {},
err() {}
},
"fs": (this.fs =
{createReadStream: sinon.stub()}),
"./Errors": (this.Errors =
{NotFoundError: sinon.stub()})
};
this.key = "my/key";
this.bucketName = "my-bucket";
this.error = "my error";
return this.AWSSDKPersistorManager = SandboxedModule.require(modulePath, {requires: this.requires});
});
describe "sendFile", ->
beforeEach ->
@stream = {}
@fsPath = "/usr/local/some/file"
@fs.createReadStream.returns @stream
describe("sendFile", function() {
beforeEach(function() {
this.stream = {};
this.fsPath = "/usr/local/some/file";
return this.fs.createReadStream.returns(this.stream);
});
it "should put the file with s3.upload", (done) ->
@s3.upload.callsArgWith 1
@AWSSDKPersistorManager.sendFile @bucketName, @key, @fsPath, (err) =>
expect(err).to.not.be.ok
expect(@s3.upload.calledOnce, "called only once").to.be.true
expect((@s3.upload.calledWith Bucket: @bucketName, Key: @key, Body: @stream)
, "called with correct arguments").to.be.true
done()
it("should put the file with s3.upload", function(done) {
this.s3.upload.callsArgWith(1);
return this.AWSSDKPersistorManager.sendFile(this.bucketName, this.key, this.fsPath, err => {
expect(err).to.not.be.ok;
expect(this.s3.upload.calledOnce, "called only once").to.be.true;
expect((this.s3.upload.calledWith({Bucket: this.bucketName, Key: this.key, Body: this.stream}))
, "called with correct arguments").to.be.true;
return done();
});
});
it "should dispatch the error from s3.upload", (done) ->
@s3.upload.callsArgWith 1, @error
@AWSSDKPersistorManager.sendFile @bucketName, @key, @fsPath, (err) =>
expect(err).to.equal @error
done()
return it("should dispatch the error from s3.upload", function(done) {
this.s3.upload.callsArgWith(1, this.error);
return this.AWSSDKPersistorManager.sendFile(this.bucketName, this.key, this.fsPath, err => {
expect(err).to.equal(this.error);
return done();
});
});
});
describe "sendStream", ->
beforeEach ->
@stream = {}
describe("sendStream", function() {
beforeEach(function() {
return this.stream = {};});
it "should put the file with s3.upload", (done) ->
@s3.upload.callsArgWith 1
@AWSSDKPersistorManager.sendStream @bucketName, @key, @stream, (err) =>
expect(err).to.not.be.ok
expect(@s3.upload.calledOnce, "called only once").to.be.true
expect((@s3.upload.calledWith Bucket: @bucketName, Key: @key, Body: @stream),
"called with correct arguments").to.be.true
done()
it("should put the file with s3.upload", function(done) {
this.s3.upload.callsArgWith(1);
return this.AWSSDKPersistorManager.sendStream(this.bucketName, this.key, this.stream, err => {
expect(err).to.not.be.ok;
expect(this.s3.upload.calledOnce, "called only once").to.be.true;
expect((this.s3.upload.calledWith({Bucket: this.bucketName, Key: this.key, Body: this.stream})),
"called with correct arguments").to.be.true;
return done();
});
});
it "should dispatch the error from s3.upload", (done) ->
@s3.upload.callsArgWith 1, @error
@AWSSDKPersistorManager.sendStream @bucketName, @key, @stream, (err) =>
expect(err).to.equal @error
done()
return it("should dispatch the error from s3.upload", function(done) {
this.s3.upload.callsArgWith(1, this.error);
return this.AWSSDKPersistorManager.sendStream(this.bucketName, this.key, this.stream, err => {
expect(err).to.equal(this.error);
return done();
});
});
});
describe "getFileStream", ->
beforeEach ->
@opts = {}
@stream = {}
@read_stream =
on: @read_stream_on = sinon.stub()
@object =
createReadStream: sinon.stub().returns @read_stream
@s3.getObject.returns @object
describe("getFileStream", function() {
beforeEach(function() {
this.opts = {};
this.stream = {};
this.read_stream =
{on: (this.read_stream_on = sinon.stub())};
this.object =
{createReadStream: sinon.stub().returns(this.read_stream)};
return this.s3.getObject.returns(this.object);
});
it "should return a stream from s3.getObject", (done) ->
@read_stream_on.withArgs('readable').callsArgWith 1
it("should return a stream from s3.getObject", function(done) {
this.read_stream_on.withArgs('readable').callsArgWith(1);
@AWSSDKPersistorManager.getFileStream @bucketName, @key, @opts, (err, stream) =>
expect(@read_stream_on.calledTwice)
expect(err).to.not.be.ok
expect(stream, "returned the stream").to.equal @read_stream
expect((@s3.getObject.calledWith Bucket: @bucketName, Key: @key),
"called with correct arguments").to.be.true
done()
return this.AWSSDKPersistorManager.getFileStream(this.bucketName, this.key, this.opts, (err, stream) => {
expect(this.read_stream_on.calledTwice);
expect(err).to.not.be.ok;
expect(stream, "returned the stream").to.equal(this.read_stream);
expect((this.s3.getObject.calledWith({Bucket: this.bucketName, Key: this.key})),
"called with correct arguments").to.be.true;
return done();
});
});
describe "with start and end options", ->
beforeEach ->
@opts =
start: 0
describe("with start and end options", function() {
beforeEach(function() {
return this.opts = {
start: 0,
end: 8
it "should pass headers to the s3.GetObject", (done) ->
@read_stream_on.withArgs('readable').callsArgWith 1
@AWSSDKPersistorManager.getFileStream @bucketName, @key, @opts, (err, stream) =>
expect((@s3.getObject.calledWith Bucket: @bucketName, Key: @key, Range: 'bytes=0-8'),
"called with correct arguments").to.be.true
done()
};
});
return it("should pass headers to the s3.GetObject", function(done) {
this.read_stream_on.withArgs('readable').callsArgWith(1);
this.AWSSDKPersistorManager.getFileStream(this.bucketName, this.key, this.opts, (err, stream) => {
return expect((this.s3.getObject.calledWith({Bucket: this.bucketName, Key: this.key, Range: 'bytes=0-8'})),
"called with correct arguments").to.be.true;
});
return done();
});
});
describe "error conditions", ->
describe "when the file doesn't exist", ->
beforeEach ->
@error = new Error()
@error.code = 'NoSuchKey'
it "should produce a NotFoundError", (done) ->
@read_stream_on.withArgs('error').callsArgWith 1, @error
@AWSSDKPersistorManager.getFileStream @bucketName, @key, @opts, (err, stream) =>
expect(stream).to.not.be.ok
expect(err).to.be.ok
expect(err instanceof @Errors.NotFoundError, "error is a correct instance").to.equal true
done()
return describe("error conditions", function() {
describe("when the file doesn't exist", function() {
beforeEach(function() {
this.error = new Error();
return this.error.code = 'NoSuchKey';
});
return it("should produce a NotFoundError", function(done) {
this.read_stream_on.withArgs('error').callsArgWith(1, this.error);
return this.AWSSDKPersistorManager.getFileStream(this.bucketName, this.key, this.opts, (err, stream) => {
expect(stream).to.not.be.ok;
expect(err).to.be.ok;
expect(err instanceof this.Errors.NotFoundError, "error is a correct instance").to.equal(true);
return done();
});
});
});
describe "when there is some other error", ->
beforeEach ->
@error = new Error()
it "should dispatch the error from s3 object stream", (done) ->
@read_stream_on.withArgs('error').callsArgWith 1, @error
@AWSSDKPersistorManager.getFileStream @bucketName, @key, @opts, (err, stream) =>
expect(stream).to.not.be.ok
expect(err).to.be.ok
expect(err).to.equal @error
done()
return describe("when there is some other error", function() {
beforeEach(function() {
return this.error = new Error();
});
return it("should dispatch the error from s3 object stream", function(done) {
this.read_stream_on.withArgs('error').callsArgWith(1, this.error);
return this.AWSSDKPersistorManager.getFileStream(this.bucketName, this.key, this.opts, (err, stream) => {
expect(stream).to.not.be.ok;
expect(err).to.be.ok;
expect(err).to.equal(this.error);
return done();
});
});
});
});
});
describe "copyFile", ->
beforeEach ->
@destKey = "some/key"
@stream = {}
describe("copyFile", function() {
beforeEach(function() {
this.destKey = "some/key";
return this.stream = {};});
it "should copy the file with s3.copyObject", (done) ->
@s3.copyObject.callsArgWith 1
@AWSSDKPersistorManager.copyFile @bucketName, @key, @destKey, (err) =>
expect(err).to.not.be.ok
expect(@s3.copyObject.calledOnce, "called only once").to.be.true
expect((@s3.copyObject.calledWith Bucket: @bucketName, Key: @destKey, CopySource: @bucketName + '/' + @key),
"called with correct arguments").to.be.true
done()
it("should copy the file with s3.copyObject", function(done) {
this.s3.copyObject.callsArgWith(1);
return this.AWSSDKPersistorManager.copyFile(this.bucketName, this.key, this.destKey, err => {
expect(err).to.not.be.ok;
expect(this.s3.copyObject.calledOnce, "called only once").to.be.true;
expect((this.s3.copyObject.calledWith({Bucket: this.bucketName, Key: this.destKey, CopySource: this.bucketName + '/' + this.key})),
"called with correct arguments").to.be.true;
return done();
});
});
it "should dispatch the error from s3.copyObject", (done) ->
@s3.copyObject.callsArgWith 1, @error
@AWSSDKPersistorManager.copyFile @bucketName, @key, @destKey, (err) =>
expect(err).to.equal @error
done()
return it("should dispatch the error from s3.copyObject", function(done) {
this.s3.copyObject.callsArgWith(1, this.error);
return this.AWSSDKPersistorManager.copyFile(this.bucketName, this.key, this.destKey, err => {
expect(err).to.equal(this.error);
return done();
});
});
});
describe "deleteFile", ->
it "should delete the file with s3.deleteObject", (done) ->
@s3.deleteObject.callsArgWith 1
@AWSSDKPersistorManager.deleteFile @bucketName, @key, (err) =>
expect(err).to.not.be.ok
expect(@s3.deleteObject.calledOnce, "called only once").to.be.true
expect((@s3.deleteObject.calledWith Bucket: @bucketName, Key: @key),
"called with correct arguments").to.be.true
done()
describe("deleteFile", function() {
it("should delete the file with s3.deleteObject", function(done) {
this.s3.deleteObject.callsArgWith(1);
return this.AWSSDKPersistorManager.deleteFile(this.bucketName, this.key, err => {
expect(err).to.not.be.ok;
expect(this.s3.deleteObject.calledOnce, "called only once").to.be.true;
expect((this.s3.deleteObject.calledWith({Bucket: this.bucketName, Key: this.key})),
"called with correct arguments").to.be.true;
return done();
});
});
it "should dispatch the error from s3.deleteObject", (done) ->
@s3.deleteObject.callsArgWith 1, @error
@AWSSDKPersistorManager.deleteFile @bucketName, @key, (err) =>
expect(err).to.equal @error
done()
return it("should dispatch the error from s3.deleteObject", function(done) {
this.s3.deleteObject.callsArgWith(1, this.error);
return this.AWSSDKPersistorManager.deleteFile(this.bucketName, this.key, err => {
expect(err).to.equal(this.error);
return done();
});
});
});
describe "deleteDirectory", ->
describe("deleteDirectory", function() {
it "should list the directory content using s3.listObjects", (done) ->
@s3.listObjects.callsArgWith 1, null, Contents: []
@AWSSDKPersistorManager.deleteDirectory @bucketName, @key, (err) =>
expect(err).to.not.be.ok
expect(@s3.listObjects.calledOnce, "called only once").to.be.true
expect((@s3.listObjects.calledWith Bucket: @bucketName, Prefix: @key),
"called with correct arguments").to.be.true
done()
it("should list the directory content using s3.listObjects", function(done) {
this.s3.listObjects.callsArgWith(1, null, {Contents: []});
return this.AWSSDKPersistorManager.deleteDirectory(this.bucketName, this.key, err => {
expect(err).to.not.be.ok;
expect(this.s3.listObjects.calledOnce, "called only once").to.be.true;
expect((this.s3.listObjects.calledWith({Bucket: this.bucketName, Prefix: this.key})),
"called with correct arguments").to.be.true;
return done();
});
});
it "should dispatch the error from s3.listObjects", (done) ->
@s3.listObjects.callsArgWith 1, @error
@AWSSDKPersistorManager.deleteDirectory @bucketName, @key, (err) =>
expect(err).to.equal @error
done()
it("should dispatch the error from s3.listObjects", function(done) {
this.s3.listObjects.callsArgWith(1, this.error);
return this.AWSSDKPersistorManager.deleteDirectory(this.bucketName, this.key, err => {
expect(err).to.equal(this.error);
return done();
});
});
describe "with directory content", ->
beforeEach ->
@fileList = [
Key: 'foo'
, Key: 'bar'
return describe("with directory content", function() {
beforeEach(function() {
return this.fileList = [
{Key: 'foo'}
, { Key: 'bar'
, Key: 'baz'
]
}
];});
it "should forward the file keys to s3.deleteObjects", (done) ->
@s3.listObjects.callsArgWith 1, null, Contents: @fileList
@s3.deleteObjects.callsArgWith 1
@AWSSDKPersistorManager.deleteDirectory @bucketName, @key, (err) =>
expect(err).to.not.be.ok
expect(@s3.deleteObjects.calledOnce, "called only once").to.be.true
expect((@s3.deleteObjects.calledWith
Bucket: @bucketName
Delete:
Quiet: true
Objects: @fileList),
"called with correct arguments").to.be.true
done()
it("should forward the file keys to s3.deleteObjects", function(done) {
this.s3.listObjects.callsArgWith(1, null, {Contents: this.fileList});
this.s3.deleteObjects.callsArgWith(1);
return this.AWSSDKPersistorManager.deleteDirectory(this.bucketName, this.key, err => {
expect(err).to.not.be.ok;
expect(this.s3.deleteObjects.calledOnce, "called only once").to.be.true;
expect((this.s3.deleteObjects.calledWith({
Bucket: this.bucketName,
Delete: {
Quiet: true,
Objects: this.fileList
}})),
"called with correct arguments").to.be.true;
return done();
});
});
it "should dispatch the error from s3.deleteObjects", (done) ->
@s3.listObjects.callsArgWith 1, null, Contents: @fileList
@s3.deleteObjects.callsArgWith 1, @error
@AWSSDKPersistorManager.deleteDirectory @bucketName, @key, (err) =>
expect(err).to.equal @error
done()
return it("should dispatch the error from s3.deleteObjects", function(done) {
this.s3.listObjects.callsArgWith(1, null, {Contents: this.fileList});
this.s3.deleteObjects.callsArgWith(1, this.error);
return this.AWSSDKPersistorManager.deleteDirectory(this.bucketName, this.key, err => {
expect(err).to.equal(this.error);
return done();
});
});
});
});
describe "checkIfFileExists", ->
describe("checkIfFileExists", function() {
it "should check for the file with s3.headObject", (done) ->
@s3.headObject.callsArgWith 1, null, {}
@AWSSDKPersistorManager.checkIfFileExists @bucketName, @key, (err, exists) =>
expect(err).to.not.be.ok
expect(@s3.headObject.calledOnce, "called only once").to.be.true
expect((@s3.headObject.calledWith Bucket: @bucketName, Key: @key),
"called with correct arguments").to.be.true
done()
it("should check for the file with s3.headObject", function(done) {
this.s3.headObject.callsArgWith(1, null, {});
return this.AWSSDKPersistorManager.checkIfFileExists(this.bucketName, this.key, (err, exists) => {
expect(err).to.not.be.ok;
expect(this.s3.headObject.calledOnce, "called only once").to.be.true;
expect((this.s3.headObject.calledWith({Bucket: this.bucketName, Key: this.key})),
"called with correct arguments").to.be.true;
return done();
});
});
it "should return false on an inexistant file", (done) ->
@s3.headObject.callsArgWith 1, null, {}
@AWSSDKPersistorManager.checkIfFileExists @bucketName, @key, (err, exists) =>
expect(exists).to.be.false
done()
it("should return false on an inexistant file", function(done) {
this.s3.headObject.callsArgWith(1, null, {});
return this.AWSSDKPersistorManager.checkIfFileExists(this.bucketName, this.key, (err, exists) => {
expect(exists).to.be.false;
return done();
});
});
it "should return true on an existing file", (done) ->
@s3.headObject.callsArgWith 1, null, ETag: "etag"
@AWSSDKPersistorManager.checkIfFileExists @bucketName, @key, (err, exists) =>
expect(exists).to.be.true
done()
it("should return true on an existing file", function(done) {
this.s3.headObject.callsArgWith(1, null, {ETag: "etag"});
return this.AWSSDKPersistorManager.checkIfFileExists(this.bucketName, this.key, (err, exists) => {
expect(exists).to.be.true;
return done();
});
});
it "should dispatch the error from s3.headObject", (done) ->
@s3.headObject.callsArgWith 1, @error
@AWSSDKPersistorManager.checkIfFileExists @bucketName, @key, (err, exists) =>
expect(err).to.equal @error
done()
return it("should dispatch the error from s3.headObject", function(done) {
this.s3.headObject.callsArgWith(1, this.error);
return this.AWSSDKPersistorManager.checkIfFileExists(this.bucketName, this.key, (err, exists) => {
expect(err).to.equal(this.error);
return done();
});
});
});
describe "directorySize", ->
return describe("directorySize", function() {
it "should list the directory content using s3.listObjects", (done) ->
@s3.listObjects.callsArgWith 1, null, Contents: []
@AWSSDKPersistorManager.directorySize @bucketName, @key, (err) =>
expect(err).to.not.be.ok
expect(@s3.listObjects.calledOnce, "called only once").to.be.true
expect((@s3.listObjects.calledWith Bucket: @bucketName, Prefix: @key),
"called with correct arguments").to.be.true
done()
it("should list the directory content using s3.listObjects", function(done) {
this.s3.listObjects.callsArgWith(1, null, {Contents: []});
return this.AWSSDKPersistorManager.directorySize(this.bucketName, this.key, err => {
expect(err).to.not.be.ok;
expect(this.s3.listObjects.calledOnce, "called only once").to.be.true;
expect((this.s3.listObjects.calledWith({Bucket: this.bucketName, Prefix: this.key})),
"called with correct arguments").to.be.true;
return done();
});
});
it "should dispatch the error from s3.listObjects", (done) ->
@s3.listObjects.callsArgWith 1, @error
@AWSSDKPersistorManager.directorySize @bucketName, @key, (err) =>
expect(err).to.equal @error
done()
it("should dispatch the error from s3.listObjects", function(done) {
this.s3.listObjects.callsArgWith(1, this.error);
return this.AWSSDKPersistorManager.directorySize(this.bucketName, this.key, err => {
expect(err).to.equal(this.error);
return done();
});
});
it "should sum directory files sizes", (done) ->
@s3.listObjects.callsArgWith 1, null, Contents: [ { Size: 1024 }, { Size: 2048 }]
@AWSSDKPersistorManager.directorySize @bucketName, @key, (err, size) =>
expect(size).to.equal 3072
done()
return it("should sum directory files sizes", function(done) {
this.s3.listObjects.callsArgWith(1, null, {Contents: [ { Size: 1024 }, { Size: 2048 }]});
return this.AWSSDKPersistorManager.directorySize(this.bucketName, this.key, (err, size) => {
expect(size).to.equal(3072);
return done();
});
});
});
});

View file

@ -1,71 +1,100 @@
assert = require("chai").assert
sinon = require('sinon')
chai = require('chai')
should = chai.should()
expect = chai.expect
modulePath = "../../../app/js/BucketController.js"
SandboxedModule = require('sandboxed-module')
/*
* decaffeinate suggestions:
* 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/BucketController.js";
const SandboxedModule = require('sandboxed-module');
describe "BucketController", ->
describe("BucketController", function() {
beforeEach ->
@PersistorManager =
sendStream: sinon.stub()
copyFile: sinon.stub()
beforeEach(function() {
this.PersistorManager = {
sendStream: sinon.stub(),
copyFile: sinon.stub(),
deleteFile:sinon.stub()
};
@settings =
s3:
buckets:
this.settings = {
s3: {
buckets: {
user_files:"user_files"
filestore:
backend: "s3"
s3:
secret: "secret"
}
},
filestore: {
backend: "s3",
s3: {
secret: "secret",
key: "this_key"
}
}
};
@FileHandler =
getFile: sinon.stub()
deleteFile: sinon.stub()
insertFile: sinon.stub()
this.FileHandler = {
getFile: sinon.stub(),
deleteFile: sinon.stub(),
insertFile: sinon.stub(),
getDirectorySize: sinon.stub()
@LocalFileWriter = {}
@controller = SandboxedModule.require modulePath, requires:
"./LocalFileWriter":@LocalFileWriter
"./FileHandler": @FileHandler
"./PersistorManager":@PersistorManager
"settings-sharelatex": @settings
"metrics-sharelatex":
inc:->
"logger-sharelatex":
log:->
err:->
@project_id = "project_id"
@file_id = "file_id"
@bucket = "user_files"
@key = "#{@project_id}/#{@file_id}"
@req =
query:{}
params:
bucket: @bucket
0: @key
};
this.LocalFileWriter = {};
this.controller = SandboxedModule.require(modulePath, { requires: {
"./LocalFileWriter":this.LocalFileWriter,
"./FileHandler": this.FileHandler,
"./PersistorManager":this.PersistorManager,
"settings-sharelatex": this.settings,
"metrics-sharelatex": {
inc() {}
},
"logger-sharelatex": {
log() {},
err() {}
}
}
}
);
this.project_id = "project_id";
this.file_id = "file_id";
this.bucket = "user_files";
this.key = `${this.project_id}/${this.file_id}`;
this.req = {
query:{},
params: {
bucket: this.bucket,
0: this.key
},
headers: {}
@res =
setHeader: ->
@fileStream = {}
};
this.res =
{setHeader() {}};
return this.fileStream = {};});
describe "getFile", ->
return describe("getFile", function() {
it "should pipe the stream", (done)->
@FileHandler.getFile.callsArgWith(3, null, @fileStream)
@fileStream.pipe = (res)=>
res.should.equal @res
done()
@controller.getFile @req, @res
it("should pipe the stream", function(done){
this.FileHandler.getFile.callsArgWith(3, null, this.fileStream);
this.fileStream.pipe = res=> {
res.should.equal(this.res);
return done();
};
return this.controller.getFile(this.req, this.res);
});
it "should send a 500 if there is a problem", (done)->
@FileHandler.getFile.callsArgWith(3, "error")
@res.send = (code)=>
code.should.equal 500
done()
@controller.getFile @req, @res
return it("should send a 500 if there is a problem", function(done){
this.FileHandler.getFile.callsArgWith(3, "error");
this.res.send = code=> {
code.should.equal(500);
return done();
};
return this.controller.getFile(this.req, this.res);
});
});
});

View file

@ -1,281 +1,372 @@
assert = require("chai").assert
sinon = require('sinon')
chai = require('chai')
should = chai.should
expect = chai.expect
modulePath = "../../../app/js/FSPersistorManager.js"
SandboxedModule = require('sandboxed-module')
fs = require("fs")
response = require("response")
/*
* 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 {
assert
} = require("chai");
const sinon = require('sinon');
const chai = require('chai');
const {
should
} = chai;
const {
expect
} = chai;
const modulePath = "../../../app/js/FSPersistorManager.js";
const SandboxedModule = require('sandboxed-module');
const fs = require("fs");
const response = require("response");
describe "FSPersistorManagerTests", ->
describe("FSPersistorManagerTests", function() {
beforeEach ->
@Fs =
rename:sinon.stub()
createReadStream:sinon.stub()
createWriteStream:sinon.stub()
unlink:sinon.stub()
rmdir:sinon.stub()
exists:sinon.stub()
readdir:sinon.stub()
open:sinon.stub()
openSync:sinon.stub()
fstatSync:sinon.stub()
closeSync:sinon.stub()
beforeEach(function() {
this.Fs = {
rename:sinon.stub(),
createReadStream:sinon.stub(),
createWriteStream:sinon.stub(),
unlink:sinon.stub(),
rmdir:sinon.stub(),
exists:sinon.stub(),
readdir:sinon.stub(),
open:sinon.stub(),
openSync:sinon.stub(),
fstatSync:sinon.stub(),
closeSync:sinon.stub(),
stat:sinon.stub()
@Rimraf = sinon.stub()
@LocalFileWriter =
writeStream: sinon.stub()
};
this.Rimraf = sinon.stub();
this.LocalFileWriter = {
writeStream: sinon.stub(),
deleteFile: sinon.stub()
@requires =
"./LocalFileWriter":@LocalFileWriter
"fs":@Fs
"logger-sharelatex":
log:->
err:->
"response":response
"rimraf":@Rimraf
"./Errors": @Errors =
NotFoundError: sinon.stub()
@location = "/tmp"
@name1 = "530f2407e7ef165704000007/530f838b46d9a9e859000008"
@name1Filtered ="530f2407e7ef165704000007_530f838b46d9a9e859000008"
@name2 = "second_file"
@error = "error_message"
@FSPersistorManager = SandboxedModule.require modulePath, requires: @requires
};
this.requires = {
"./LocalFileWriter":this.LocalFileWriter,
"fs":this.Fs,
"logger-sharelatex": {
log() {},
err() {}
},
"response":response,
"rimraf":this.Rimraf,
"./Errors": (this.Errors =
{NotFoundError: sinon.stub()})
};
this.location = "/tmp";
this.name1 = "530f2407e7ef165704000007/530f838b46d9a9e859000008";
this.name1Filtered ="530f2407e7ef165704000007_530f838b46d9a9e859000008";
this.name2 = "second_file";
this.error = "error_message";
return this.FSPersistorManager = SandboxedModule.require(modulePath, {requires: this.requires});
});
describe "sendFile", ->
beforeEach ->
@Fs.createReadStream = sinon.stub().returns({
on: ->
pipe: ->
})
describe("sendFile", function() {
beforeEach(function() {
return this.Fs.createReadStream = sinon.stub().returns({
on() {},
pipe() {}
});
});
it "should copy the file", (done) ->
@Fs.createWriteStream =sinon.stub().returns({
on: (event, handler) ->
process.nextTick(handler) if event is 'finish'
})
@FSPersistorManager.sendFile @location, @name1, @name2, (err)=>
@Fs.createReadStream.calledWith(@name2).should.equal true
@Fs.createWriteStream.calledWith("#{@location}/#{@name1Filtered}" ).should.equal true
done()
it("should copy the file", function(done) {
this.Fs.createWriteStream =sinon.stub().returns({
on(event, handler) {
if (event === 'finish') { return process.nextTick(handler); }
}
});
return this.FSPersistorManager.sendFile(this.location, this.name1, this.name2, err=> {
this.Fs.createReadStream.calledWith(this.name2).should.equal(true);
this.Fs.createWriteStream.calledWith(`${this.location}/${this.name1Filtered}` ).should.equal(true);
return done();
});
});
it "should return an error if the file cannot be stored", (done) ->
@Fs.createWriteStream =sinon.stub().returns({
on: (event, handler) =>
if event is 'error'
process.nextTick () =>
handler(@error)
})
@FSPersistorManager.sendFile @location, @name1, @name2, (err)=>
@Fs.createReadStream.calledWith(@name2).should.equal true
@Fs.createWriteStream.calledWith("#{@location}/#{@name1Filtered}" ).should.equal true
err.should.equal @error
done()
return it("should return an error if the file cannot be stored", function(done) {
this.Fs.createWriteStream =sinon.stub().returns({
on: (event, handler) => {
if (event === 'error') {
return process.nextTick(() => {
return handler(this.error);
});
}
}
});
return this.FSPersistorManager.sendFile(this.location, this.name1, this.name2, err=> {
this.Fs.createReadStream.calledWith(this.name2).should.equal(true);
this.Fs.createWriteStream.calledWith(`${this.location}/${this.name1Filtered}` ).should.equal(true);
err.should.equal(this.error);
return done();
});
});
});
describe "sendStream", ->
beforeEach ->
@FSPersistorManager.sendFile = sinon.stub().callsArgWith(3)
@LocalFileWriter.writeStream.callsArgWith(2, null, @name1)
@LocalFileWriter.deleteFile.callsArg(1)
@SourceStream =
on:->
describe("sendStream", function() {
beforeEach(function() {
this.FSPersistorManager.sendFile = sinon.stub().callsArgWith(3);
this.LocalFileWriter.writeStream.callsArgWith(2, null, this.name1);
this.LocalFileWriter.deleteFile.callsArg(1);
return this.SourceStream =
{on() {}};
});
it "should sent stream to LocalFileWriter", (done)->
@FSPersistorManager.sendStream @location, @name1, @SourceStream, =>
@LocalFileWriter.writeStream.calledWith(@SourceStream).should.equal true
done()
it("should sent stream to LocalFileWriter", function(done){
return this.FSPersistorManager.sendStream(this.location, this.name1, this.SourceStream, () => {
this.LocalFileWriter.writeStream.calledWith(this.SourceStream).should.equal(true);
return done();
});
});
it "should return the error from LocalFileWriter", (done)->
@LocalFileWriter.writeStream.callsArgWith(2, @error)
@FSPersistorManager.sendStream @location, @name1, @SourceStream, (err)=>
err.should.equal @error
done()
it("should return the error from LocalFileWriter", function(done){
this.LocalFileWriter.writeStream.callsArgWith(2, this.error);
return this.FSPersistorManager.sendStream(this.location, this.name1, this.SourceStream, err=> {
err.should.equal(this.error);
return done();
});
});
it "should send the file to the filestore", (done)->
@LocalFileWriter.writeStream.callsArgWith(2)
@FSPersistorManager.sendStream @location, @name1, @SourceStream, (err)=>
@FSPersistorManager.sendFile.called.should.equal true
done()
return it("should send the file to the filestore", function(done){
this.LocalFileWriter.writeStream.callsArgWith(2);
return this.FSPersistorManager.sendStream(this.location, this.name1, this.SourceStream, err=> {
this.FSPersistorManager.sendFile.called.should.equal(true);
return done();
});
});
});
describe "getFileStream", ->
beforeEach ->
@opts = {}
describe("getFileStream", function() {
beforeEach(function() {
return this.opts = {};});
it "should use correct file location", (done) ->
@FSPersistorManager.getFileStream @location, @name1, @opts, (err,res) =>
@Fs.open.calledWith("#{@location}/#{@name1Filtered}").should.equal true
done()
it("should use correct file location", function(done) {
this.FSPersistorManager.getFileStream(this.location, this.name1, this.opts, (err,res) => {});
this.Fs.open.calledWith(`${this.location}/${this.name1Filtered}`).should.equal(true);
return done();
});
describe "with start and end options", ->
describe("with start and end options", function() {
beforeEach ->
@fd = 2019
@opts_in = {start: 0, end: 8}
@opts = {start: 0, end: 8, fd: @fd}
@Fs.open.callsArgWith(2, null, @fd)
beforeEach(function() {
this.fd = 2019;
this.opts_in = {start: 0, end: 8};
this.opts = {start: 0, end: 8, fd: this.fd};
return this.Fs.open.callsArgWith(2, null, this.fd);
});
it 'should pass the options to createReadStream', (done) ->
@FSPersistorManager.getFileStream @location, @name1, @opts_in, (err,res)=>
@Fs.createReadStream.calledWith(null, @opts).should.equal true
done()
return it('should pass the options to createReadStream', function(done) {
this.FSPersistorManager.getFileStream(this.location, this.name1, this.opts_in, (err,res)=> {});
this.Fs.createReadStream.calledWith(null, this.opts).should.equal(true);
return done();
});
});
describe "error conditions", ->
return describe("error conditions", function() {
describe "when the file does not exist", ->
describe("when the file does not exist", function() {
beforeEach ->
@fakeCode = 'ENOENT'
err = new Error()
err.code = @fakeCode
@Fs.open.callsArgWith(2, err, null)
beforeEach(function() {
this.fakeCode = 'ENOENT';
const err = new Error();
err.code = this.fakeCode;
return this.Fs.open.callsArgWith(2, err, null);
});
it "should give a NotFoundError", (done) ->
@FSPersistorManager.getFileStream @location, @name1, @opts, (err,res)=>
expect(res).to.equal null
expect(err).to.not.equal null
expect(err instanceof @Errors.NotFoundError).to.equal true
done()
return it("should give a NotFoundError", function(done) {
return this.FSPersistorManager.getFileStream(this.location, this.name1, this.opts, (err,res)=> {
expect(res).to.equal(null);
expect(err).to.not.equal(null);
expect(err instanceof this.Errors.NotFoundError).to.equal(true);
return done();
});
});
});
describe "when some other error happens", ->
return describe("when some other error happens", function() {
beforeEach ->
@fakeCode = 'SOMETHINGHORRIBLE'
err = new Error()
err.code = @fakeCode
@Fs.open.callsArgWith(2, err, null)
beforeEach(function() {
this.fakeCode = 'SOMETHINGHORRIBLE';
const err = new Error();
err.code = this.fakeCode;
return this.Fs.open.callsArgWith(2, err, null);
});
it "should give an Error", (done) ->
@FSPersistorManager.getFileStream @location, @name1, @opts, (err,res)=>
expect(res).to.equal null
expect(err).to.not.equal null
expect(err instanceof Error).to.equal true
done()
return it("should give an Error", function(done) {
return this.FSPersistorManager.getFileStream(this.location, this.name1, this.opts, (err,res)=> {
expect(res).to.equal(null);
expect(err).to.not.equal(null);
expect(err instanceof Error).to.equal(true);
return done();
});
});
});
});
});
describe "getFileSize", ->
it "should return the file size", (done) ->
expectedFileSize = 75382
@Fs.stat.yields(new Error("fs.stat got unexpected arguments"))
@Fs.stat.withArgs("#{@location}/#{@name1Filtered}")
.yields(null, { size: expectedFileSize })
describe("getFileSize", function() {
it("should return the file size", function(done) {
const expectedFileSize = 75382;
this.Fs.stat.yields(new Error("fs.stat got unexpected arguments"));
this.Fs.stat.withArgs(`${this.location}/${this.name1Filtered}`)
.yields(null, { size: expectedFileSize });
@FSPersistorManager.getFileSize @location, @name1, (err, fileSize) =>
if err?
return done(err)
expect(fileSize).to.equal(expectedFileSize)
done()
return this.FSPersistorManager.getFileSize(this.location, this.name1, (err, fileSize) => {
if (err != null) {
return done(err);
}
expect(fileSize).to.equal(expectedFileSize);
return done();
});
});
it "should throw a NotFoundError if the file does not exist", (done) ->
error = new Error()
error.code = "ENOENT"
@Fs.stat.yields(error)
it("should throw a NotFoundError if the file does not exist", function(done) {
const error = new Error();
error.code = "ENOENT";
this.Fs.stat.yields(error);
@FSPersistorManager.getFileSize @location, @name1, (err, fileSize) =>
expect(err).to.be.instanceof(@Errors.NotFoundError)
done()
return this.FSPersistorManager.getFileSize(this.location, this.name1, (err, fileSize) => {
expect(err).to.be.instanceof(this.Errors.NotFoundError);
return done();
});
});
it "should rethrow any other error", (done) ->
error = new Error()
@Fs.stat.yields(error)
return it("should rethrow any other error", function(done) {
const error = new Error();
this.Fs.stat.yields(error);
@FSPersistorManager.getFileSize @location, @name1, (err, fileSize) =>
expect(err).to.equal(error)
done()
return this.FSPersistorManager.getFileSize(this.location, this.name1, (err, fileSize) => {
expect(err).to.equal(error);
return done();
});
});
});
describe "copyFile", ->
beforeEach ->
@ReadStream=
on:->
describe("copyFile", function() {
beforeEach(function() {
this.ReadStream= {
on() {},
pipe:sinon.stub()
@WriteStream=
on:->
@Fs.createReadStream.returns(@ReadStream)
@Fs.createWriteStream.returns(@WriteStream)
};
this.WriteStream=
{on() {}};
this.Fs.createReadStream.returns(this.ReadStream);
return this.Fs.createWriteStream.returns(this.WriteStream);
});
it "Should open the source for reading", (done) ->
@FSPersistorManager.copyFile @location, @name1, @name2, ->
@Fs.createReadStream.calledWith("#{@location}/#{@name1Filtered}").should.equal true
done()
it("Should open the source for reading", function(done) {
this.FSPersistorManager.copyFile(this.location, this.name1, this.name2, function() {});
this.Fs.createReadStream.calledWith(`${this.location}/${this.name1Filtered}`).should.equal(true);
return done();
});
it "Should open the target for writing", (done) ->
@FSPersistorManager.copyFile @location, @name1, @name2, ->
@Fs.createWriteStream.calledWith("#{@location}/#{@name2}").should.equal true
done()
it("Should open the target for writing", function(done) {
this.FSPersistorManager.copyFile(this.location, this.name1, this.name2, function() {});
this.Fs.createWriteStream.calledWith(`${this.location}/${this.name2}`).should.equal(true);
return done();
});
it "Should pipe the source to the target", (done) ->
@FSPersistorManager.copyFile @location, @name1, @name2, ->
@ReadStream.pipe.calledWith(@WriteStream).should.equal true
done()
return it("Should pipe the source to the target", function(done) {
this.FSPersistorManager.copyFile(this.location, this.name1, this.name2, function() {});
this.ReadStream.pipe.calledWith(this.WriteStream).should.equal(true);
return done();
});
});
describe "deleteFile", ->
beforeEach ->
@Fs.unlink.callsArgWith(1,@error)
describe("deleteFile", function() {
beforeEach(function() {
return this.Fs.unlink.callsArgWith(1,this.error);
});
it "Should call unlink with correct options", (done) ->
@FSPersistorManager.deleteFile @location, @name1, (err) =>
@Fs.unlink.calledWith("#{@location}/#{@name1Filtered}").should.equal true
done()
it("Should call unlink with correct options", function(done) {
return this.FSPersistorManager.deleteFile(this.location, this.name1, err => {
this.Fs.unlink.calledWith(`${this.location}/${this.name1Filtered}`).should.equal(true);
return done();
});
});
it "Should propogate the error", (done) ->
@FSPersistorManager.deleteFile @location, @name1, (err) =>
err.should.equal @error
done()
return it("Should propogate the error", function(done) {
return this.FSPersistorManager.deleteFile(this.location, this.name1, err => {
err.should.equal(this.error);
return done();
});
});
});
describe "deleteDirectory", ->
beforeEach ->
@Rimraf.callsArgWith(1,@error)
describe("deleteDirectory", function() {
beforeEach(function() {
return this.Rimraf.callsArgWith(1,this.error);
});
it "Should call rmdir(rimraf) with correct options", (done) ->
@FSPersistorManager.deleteDirectory @location, @name1, (err) =>
@Rimraf.calledWith("#{@location}/#{@name1Filtered}").should.equal true
done()
it("Should call rmdir(rimraf) with correct options", function(done) {
return this.FSPersistorManager.deleteDirectory(this.location, this.name1, err => {
this.Rimraf.calledWith(`${this.location}/${this.name1Filtered}`).should.equal(true);
return done();
});
});
it "Should propogate the error", (done) ->
@FSPersistorManager.deleteDirectory @location, @name1, (err) =>
err.should.equal @error
done()
return it("Should propogate the error", function(done) {
return this.FSPersistorManager.deleteDirectory(this.location, this.name1, err => {
err.should.equal(this.error);
return done();
});
});
});
describe "checkIfFileExists", ->
beforeEach ->
@Fs.exists.callsArgWith(1,true)
describe("checkIfFileExists", function() {
beforeEach(function() {
return this.Fs.exists.callsArgWith(1,true);
});
it "Should call exists with correct options", (done) ->
@FSPersistorManager.checkIfFileExists @location, @name1, (exists) =>
@Fs.exists.calledWith("#{@location}/#{@name1Filtered}").should.equal true
done()
it("Should call exists with correct options", function(done) {
return this.FSPersistorManager.checkIfFileExists(this.location, this.name1, exists => {
this.Fs.exists.calledWith(`${this.location}/${this.name1Filtered}`).should.equal(true);
return done();
});
});
# fs.exists simply returns false on any error, so...
it "should not return an error", (done) ->
@FSPersistorManager.checkIfFileExists @location, @name1, (err,exists) =>
expect(err).to.be.null
done()
// fs.exists simply returns false on any error, so...
it("should not return an error", function(done) {
return this.FSPersistorManager.checkIfFileExists(this.location, this.name1, (err,exists) => {
expect(err).to.be.null;
return done();
});
});
it "Should return true for existing files", (done) ->
@Fs.exists.callsArgWith(1,true)
@FSPersistorManager.checkIfFileExists @location, @name1, (err,exists) =>
exists.should.be.true
done()
it("Should return true for existing files", function(done) {
this.Fs.exists.callsArgWith(1,true);
return this.FSPersistorManager.checkIfFileExists(this.location, this.name1, (err,exists) => {
exists.should.be.true;
return done();
});
});
it "Should return false for non-existing files", (done) ->
@Fs.exists.callsArgWith(1,false)
@FSPersistorManager.checkIfFileExists @location, @name1, (err,exists) =>
exists.should.be.false
done()
return it("Should return false for non-existing files", function(done) {
this.Fs.exists.callsArgWith(1,false);
return this.FSPersistorManager.checkIfFileExists(this.location, this.name1, (err,exists) => {
exists.should.be.false;
return done();
});
});
});
describe "directorySize", ->
return describe("directorySize", function() {
it "should propogate the error", (done) ->
@Fs.readdir.callsArgWith(1, @error)
@FSPersistorManager.directorySize @location, @name1, (err, totalsize) =>
err.should.equal @error
done()
it("should propogate the error", function(done) {
this.Fs.readdir.callsArgWith(1, this.error);
return this.FSPersistorManager.directorySize(this.location, this.name1, (err, totalsize) => {
err.should.equal(this.error);
return done();
});
});
it "should sum directory files size", (done) ->
@Fs.readdir.callsArgWith(1, null, [ {'file1'}, {'file2'} ])
@Fs.fstatSync.returns({size : 1024})
@FSPersistorManager.directorySize @location, @name1, (err, totalsize) =>
expect(totalsize).to.equal 2048
done()
return it("should sum directory files size", function(done) {
this.Fs.readdir.callsArgWith(1, null, [ {'file1': 'file1'}, {'file2': 'file2'} ]);
this.Fs.fstatSync.returns({size : 1024});
return this.FSPersistorManager.directorySize(this.location, this.name1, (err, totalsize) => {
expect(totalsize).to.equal(2048);
return done();
});
});
});
});

View file

@ -1,216 +1,283 @@
assert = require("chai").assert
sinon = require('sinon')
chai = require('chai')
should = chai.should()
expect = chai.expect
modulePath = "../../../app/js/FileController.js"
SandboxedModule = require('sandboxed-module')
/*
* decaffeinate suggestions:
* 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/FileController.js";
const SandboxedModule = require('sandboxed-module');
describe "FileController", ->
describe("FileController", function() {
beforeEach ->
@PersistorManager =
sendStream: sinon.stub()
copyFile: sinon.stub()
beforeEach(function() {
this.PersistorManager = {
sendStream: sinon.stub(),
copyFile: sinon.stub(),
deleteFile:sinon.stub()
};
@settings =
s3:
buckets:
this.settings = {
s3: {
buckets: {
user_files:"user_files"
@FileHandler =
getFile: sinon.stub()
getFileSize: sinon.stub()
deleteFile: sinon.stub()
insertFile: sinon.stub()
}
}
};
this.FileHandler = {
getFile: sinon.stub(),
getFileSize: sinon.stub(),
deleteFile: sinon.stub(),
insertFile: sinon.stub(),
getDirectorySize: sinon.stub()
@LocalFileWriter = {}
@controller = SandboxedModule.require modulePath, requires:
"./LocalFileWriter":@LocalFileWriter
"./FileHandler": @FileHandler
"./PersistorManager":@PersistorManager
"./Errors": @Errors =
NotFoundError: sinon.stub()
"settings-sharelatex": @settings
"metrics-sharelatex":
inc:->
"logger-sharelatex":
log:->
err:->
@project_id = "project_id"
@file_id = "file_id"
@bucket = "user_files"
@key = "#{@project_id}/#{@file_id}"
@req =
key:@key
bucket:@bucket
query:{}
params:
project_id:@project_id
file_id:@file_id
};
this.LocalFileWriter = {};
this.controller = SandboxedModule.require(modulePath, { requires: {
"./LocalFileWriter":this.LocalFileWriter,
"./FileHandler": this.FileHandler,
"./PersistorManager":this.PersistorManager,
"./Errors": (this.Errors =
{NotFoundError: sinon.stub()}),
"settings-sharelatex": this.settings,
"metrics-sharelatex": {
inc() {}
},
"logger-sharelatex": {
log() {},
err() {}
}
}
}
);
this.project_id = "project_id";
this.file_id = "file_id";
this.bucket = "user_files";
this.key = `${this.project_id}/${this.file_id}`;
this.req = {
key:this.key,
bucket:this.bucket,
query:{},
params: {
project_id:this.project_id,
file_id:this.file_id
},
headers: {}
@res =
set: sinon.stub().returnsThis()
};
this.res = {
set: sinon.stub().returnsThis(),
status: sinon.stub().returnsThis()
@fileStream = {}
};
return this.fileStream = {};});
describe "getFile", ->
describe("getFile", function() {
it "should pipe the stream", (done)->
@FileHandler.getFile.callsArgWith(3, null, @fileStream)
@fileStream.pipe = (res)=>
res.should.equal @res
done()
@controller.getFile @req, @res
it("should pipe the stream", function(done){
this.FileHandler.getFile.callsArgWith(3, null, this.fileStream);
this.fileStream.pipe = res=> {
res.should.equal(this.res);
return done();
};
return this.controller.getFile(this.req, this.res);
});
it "should send a 200 if the cacheWarm param is true", (done)->
@req.query.cacheWarm = true
@FileHandler.getFile.callsArgWith(3, null, @fileStream)
@res.send = (statusCode)=>
statusCode.should.equal 200
done()
@controller.getFile @req, @res
it("should send a 200 if the cacheWarm param is true", function(done){
this.req.query.cacheWarm = true;
this.FileHandler.getFile.callsArgWith(3, null, this.fileStream);
this.res.send = statusCode=> {
statusCode.should.equal(200);
return done();
};
return this.controller.getFile(this.req, this.res);
});
it "should send a 500 if there is a problem", (done)->
@FileHandler.getFile.callsArgWith(3, "error")
@res.send = (code)=>
code.should.equal 500
done()
@controller.getFile @req, @res
it("should send a 500 if there is a problem", function(done){
this.FileHandler.getFile.callsArgWith(3, "error");
this.res.send = code=> {
code.should.equal(500);
return done();
};
return this.controller.getFile(this.req, this.res);
});
describe "with a 'Range' header set", ->
return describe("with a 'Range' header set", function() {
beforeEach ->
@req.headers.range = 'bytes=0-8'
beforeEach(function() {
return this.req.headers.range = 'bytes=0-8';
});
it "should pass 'start' and 'end' options to FileHandler", (done) ->
@FileHandler.getFile.callsArgWith(3, null, @fileStream)
@fileStream.pipe = (res)=>
expect(@FileHandler.getFile.lastCall.args[2].start).to.equal 0
expect(@FileHandler.getFile.lastCall.args[2].end).to.equal 8
done()
@controller.getFile @req, @res
return it("should pass 'start' and 'end' options to FileHandler", function(done) {
this.FileHandler.getFile.callsArgWith(3, null, this.fileStream);
this.fileStream.pipe = res=> {
expect(this.FileHandler.getFile.lastCall.args[2].start).to.equal(0);
expect(this.FileHandler.getFile.lastCall.args[2].end).to.equal(8);
return done();
};
return this.controller.getFile(this.req, this.res);
});
});
});
describe "getFileHead", ->
it "should return the file size in a Content-Length header", (done) ->
expectedFileSize = 84921
@FileHandler.getFileSize.yields(
describe("getFileHead", function() {
it("should return the file size in a Content-Length header", function(done) {
const expectedFileSize = 84921;
this.FileHandler.getFileSize.yields(
new Error("FileHandler.getFileSize: unexpected arguments")
)
@FileHandler.getFileSize.withArgs(@bucket, @key).yields(null, expectedFileSize)
);
this.FileHandler.getFileSize.withArgs(this.bucket, this.key).yields(null, expectedFileSize);
@res.end = () =>
expect(@res.status.lastCall.args[0]).to.equal(200)
expect(@res.set.calledWith("Content-Length", expectedFileSize)).to.equal(true)
done()
this.res.end = () => {
expect(this.res.status.lastCall.args[0]).to.equal(200);
expect(this.res.set.calledWith("Content-Length", expectedFileSize)).to.equal(true);
return done();
};
@controller.getFileHead(@req, @res)
return this.controller.getFileHead(this.req, this.res);
});
it "should return a 404 is the file is not found", (done) ->
@FileHandler.getFileSize.yields(new @Errors.NotFoundError())
it("should return a 404 is the file is not found", function(done) {
this.FileHandler.getFileSize.yields(new this.Errors.NotFoundError());
@res.end = () =>
expect(@res.status.lastCall.args[0]).to.equal(404)
done()
this.res.end = () => {
expect(this.res.status.lastCall.args[0]).to.equal(404);
return done();
};
@controller.getFileHead(@req, @res)
return this.controller.getFileHead(this.req, this.res);
});
it "should return a 500 on internal errors", (done) ->
@FileHandler.getFileSize.yields(new Error())
return it("should return a 500 on internal errors", function(done) {
this.FileHandler.getFileSize.yields(new Error());
@res.end = () =>
expect(@res.status.lastCall.args[0]).to.equal(500)
done()
this.res.end = () => {
expect(this.res.status.lastCall.args[0]).to.equal(500);
return done();
};
@controller.getFileHead(@req, @res)
return this.controller.getFileHead(this.req, this.res);
});
});
describe "insertFile", ->
describe("insertFile", () => it("should send bucket name key and res to PersistorManager", function(done){
this.FileHandler.insertFile.callsArgWith(3);
this.res.send = () => {
this.FileHandler.insertFile.calledWith(this.bucket, this.key, this.req).should.equal(true);
return done();
};
return this.controller.insertFile(this.req, this.res);
}));
it "should send bucket name key and res to PersistorManager", (done)->
@FileHandler.insertFile.callsArgWith(3)
@res.send = =>
@FileHandler.insertFile.calledWith(@bucket, @key, @req).should.equal true
done()
@controller.insertFile @req, @res
describe("copyFile", function() {
beforeEach(function() {
this.oldFile_id = "old_file_id";
this.oldProject_id = "old_project_id";
return this.req.body = {
source: {
project_id: this.oldProject_id,
file_id: this.oldFile_id
}
};
});
describe "copyFile", ->
beforeEach ->
@oldFile_id = "old_file_id"
@oldProject_id = "old_project_id"
@req.body =
source:
project_id: @oldProject_id
file_id: @oldFile_id
it("should send bucket name and both keys to PersistorManager", function(done){
this.PersistorManager.copyFile.callsArgWith(3);
this.res.send = code=> {
code.should.equal(200);
this.PersistorManager.copyFile.calledWith(this.bucket, `${this.oldProject_id}/${this.oldFile_id}`, this.key).should.equal(true);
return done();
};
return this.controller.copyFile(this.req, this.res);
});
it "should send bucket name and both keys to PersistorManager", (done)->
@PersistorManager.copyFile.callsArgWith(3)
@res.send = (code)=>
code.should.equal 200
@PersistorManager.copyFile.calledWith(@bucket, "#{@oldProject_id}/#{@oldFile_id}", @key).should.equal true
done()
@controller.copyFile @req, @res
it("should send a 404 if the original file was not found", function(done) {
this.PersistorManager.copyFile.callsArgWith(3, new this.Errors.NotFoundError());
this.res.send = code=> {
code.should.equal(404);
return done();
};
return this.controller.copyFile(this.req, this.res);
});
it "should send a 404 if the original file was not found", (done) ->
@PersistorManager.copyFile.callsArgWith(3, new @Errors.NotFoundError())
@res.send = (code)=>
code.should.equal 404
done()
@controller.copyFile @req, @res
return it("should send a 500 if there was an error", function(done){
this.PersistorManager.copyFile.callsArgWith(3, "error");
this.res.send = code=> {
code.should.equal(500);
return done();
};
return this.controller.copyFile(this.req, this.res);
});
});
it "should send a 500 if there was an error", (done)->
@PersistorManager.copyFile.callsArgWith(3, "error")
@res.send = (code)=>
code.should.equal 500
done()
@controller.copyFile @req, @res
describe("delete file", function() {
describe "delete file", ->
it("should tell the file handler", function(done){
this.FileHandler.deleteFile.callsArgWith(2);
this.res.send = code=> {
code.should.equal(204);
this.FileHandler.deleteFile.calledWith(this.bucket, this.key).should.equal(true);
return done();
};
return this.controller.deleteFile(this.req, this.res);
});
it "should tell the file handler", (done)->
@FileHandler.deleteFile.callsArgWith(2)
@res.send = (code)=>
code.should.equal 204
@FileHandler.deleteFile.calledWith(@bucket, @key).should.equal true
done()
@controller.deleteFile @req, @res
return it("should send a 500 if there was an error", function(done){
this.FileHandler.deleteFile.callsArgWith(2, "error");
this.res.send = function(code){
code.should.equal(500);
return done();
};
return this.controller.deleteFile(this.req, this.res);
});
});
it "should send a 500 if there was an error", (done)->
@FileHandler.deleteFile.callsArgWith(2, "error")
@res.send = (code)->
code.should.equal 500
done()
@controller.deleteFile @req, @res
describe("_get_range", function() {
describe "_get_range", ->
it("should parse a valid Range header", function(done) {
const result = this.controller._get_range('bytes=0-200');
expect(result).to.not.equal(null);
expect(result.start).to.equal(0);
expect(result.end).to.equal(200);
return done();
});
it "should parse a valid Range header", (done) ->
result = @controller._get_range('bytes=0-200')
expect(result).to.not.equal null
expect(result.start).to.equal 0
expect(result.end).to.equal 200
done()
it("should return null for an invalid Range header", function(done) {
const result = this.controller._get_range('wat');
expect(result).to.equal(null);
return done();
});
it "should return null for an invalid Range header", (done) ->
result = @controller._get_range('wat')
expect(result).to.equal null
done()
return it("should return null for any type other than 'bytes'", function(done) {
const result = this.controller._get_range('carrots=0-200');
expect(result).to.equal(null);
return done();
});
});
it "should return null for any type other than 'bytes'", (done) ->
result = @controller._get_range('carrots=0-200')
expect(result).to.equal null
done()
return describe("directorySize", function() {
describe "directorySize", ->
it("should return total directory size bytes", function(done) {
this.FileHandler.getDirectorySize.callsArgWith(2, null, 1024);
return this.controller.directorySize(this.req, { json:result=> {
expect(result['total bytes']).to.equal(1024);
return done();
}
}
);
});
it "should return total directory size bytes", (done) ->
@FileHandler.getDirectorySize.callsArgWith(2, null, 1024)
@controller.directorySize @req, json:(result)=>
expect(result['total bytes']).to.equal 1024
done()
it "should send a 500 if there was an error", (done)->
@FileHandler.getDirectorySize.callsArgWith(2, "error")
@res.send = (code)->
code.should.equal 500
done()
@controller.directorySize @req, @res
return it("should send a 500 if there was an error", function(done){
this.FileHandler.getDirectorySize.callsArgWith(2, "error");
this.res.send = function(code){
code.should.equal(500);
return done();
};
return this.controller.directorySize(this.req, this.res);
});
});
});

View file

@ -1,81 +1,112 @@
assert = require("chai").assert
sinon = require('sinon')
chai = require('chai')
should = chai.should()
expect = chai.expect
modulePath = "../../../app/js/FileConverter.js"
SandboxedModule = require('sandboxed-module')
/*
* decaffeinate suggestions:
* 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/FileConverter.js";
const SandboxedModule = require('sandboxed-module');
describe "FileConverter", ->
describe("FileConverter", function() {
beforeEach ->
beforeEach(function() {
@safe_exec = sinon.stub()
@converter = SandboxedModule.require modulePath, requires:
"./SafeExec": @safe_exec
"logger-sharelatex":
log:->
err:->
"metrics-sharelatex":
inc:->
Timer:->
done:->
"settings-sharelatex": @Settings =
commands:
this.safe_exec = sinon.stub();
this.converter = SandboxedModule.require(modulePath, { requires: {
"./SafeExec": this.safe_exec,
"logger-sharelatex": {
log() {},
err() {}
},
"metrics-sharelatex": {
inc() {},
Timer() {
return {done() {}};
}
},
"settings-sharelatex": (this.Settings = {
commands: {
convertCommandPrefix: []
}
})
}
});
@sourcePath = "/this/path/here.eps"
@format = "png"
@error = "Error"
this.sourcePath = "/this/path/here.eps";
this.format = "png";
return this.error = "Error";
});
describe "convert", ->
describe("convert", function() {
it "should convert the source to the requested format", (done)->
@safe_exec.callsArgWith(2)
@converter.convert @sourcePath, @format, (err)=>
args = @safe_exec.args[0][0]
args.indexOf("#{@sourcePath}[0]").should.not.equal -1
args.indexOf("#{@sourcePath}.#{@format}").should.not.equal -1
done()
it("should convert the source to the requested format", function(done){
this.safe_exec.callsArgWith(2);
return this.converter.convert(this.sourcePath, this.format, err=> {
const args = this.safe_exec.args[0][0];
args.indexOf(`${this.sourcePath}[0]`).should.not.equal(-1);
args.indexOf(`${this.sourcePath}.${this.format}`).should.not.equal(-1);
return done();
});
});
it "should return the dest path", (done)->
@safe_exec.callsArgWith(2)
@converter.convert @sourcePath, @format, (err, destPath)=>
destPath.should.equal "#{@sourcePath}.#{@format}"
done()
it("should return the dest path", function(done){
this.safe_exec.callsArgWith(2);
return this.converter.convert(this.sourcePath, this.format, (err, destPath)=> {
destPath.should.equal(`${this.sourcePath}.${this.format}`);
return done();
});
});
it "should return the error from convert", (done)->
@safe_exec.callsArgWith(2, @error)
@converter.convert @sourcePath, @format, (err)=>
err.should.equal @error
done()
it("should return the error from convert", function(done){
this.safe_exec.callsArgWith(2, this.error);
return this.converter.convert(this.sourcePath, this.format, err=> {
err.should.equal(this.error);
return done();
});
});
it "should not accapt an non aproved format", (done)->
@safe_exec.callsArgWith(2)
@converter.convert @sourcePath, "ahhhhh", (err)=>
expect(err).to.exist
done()
it("should not accapt an non aproved format", function(done){
this.safe_exec.callsArgWith(2);
return this.converter.convert(this.sourcePath, "ahhhhh", err=> {
expect(err).to.exist;
return done();
});
});
it "should prefix the command with Settings.commands.convertCommandPrefix", (done) ->
@safe_exec.callsArgWith(2)
@Settings.commands.convertCommandPrefix = ["nice"]
@converter.convert @sourcePath, @format, (err)=>
command = @safe_exec.args[0][0]
command[0].should.equal "nice"
done()
return it("should prefix the command with Settings.commands.convertCommandPrefix", function(done) {
this.safe_exec.callsArgWith(2);
this.Settings.commands.convertCommandPrefix = ["nice"];
return this.converter.convert(this.sourcePath, this.format, err=> {
const command = this.safe_exec.args[0][0];
command[0].should.equal("nice");
return done();
});
});
});
describe "thumbnail", ->
it "should call converter resize with args", (done)->
@safe_exec.callsArgWith(2)
@converter.thumbnail @sourcePath, (err)=>
args = @safe_exec.args[0][0]
args.indexOf("#{@sourcePath}[0]").should.not.equal -1
done()
describe("thumbnail", () => it("should call converter resize with args", function(done){
this.safe_exec.callsArgWith(2);
return this.converter.thumbnail(this.sourcePath, err=> {
const args = this.safe_exec.args[0][0];
args.indexOf(`${this.sourcePath}[0]`).should.not.equal(-1);
return done();
});
}));
describe "preview", ->
it "should call converter resize with args", (done)->
@safe_exec.callsArgWith(2)
@converter.preview @sourcePath, (err)=>
args = @safe_exec.args[0][0]
args.indexOf("#{@sourcePath}[0]").should.not.equal -1
done()
return describe("preview", () => it("should call converter resize with args", function(done){
this.safe_exec.callsArgWith(2);
return this.converter.preview(this.sourcePath, err=> {
const args = this.safe_exec.args[0][0];
args.indexOf(`${this.sourcePath}[0]`).should.not.equal(-1);
return done();
});
}));
});

View file

@ -1,208 +1,275 @@
assert = require("chai").assert
sinon = require('sinon')
chai = require('chai')
should = chai.should()
expect = chai.expect
modulePath = "../../../app/js/FileHandler.js"
SandboxedModule = require('sandboxed-module')
/*
* decaffeinate suggestions:
* 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/FileHandler.js";
const SandboxedModule = require('sandboxed-module');
describe "FileHandler", ->
describe("FileHandler", function() {
beforeEach ->
@settings =
s3:
buckets:
beforeEach(function() {
this.settings = {
s3: {
buckets: {
user_files:"user_files"
@PersistorManager =
getFileStream: sinon.stub()
checkIfFileExists: sinon.stub()
deleteFile: sinon.stub()
deleteDirectory: sinon.stub()
sendStream: sinon.stub()
insertFile: sinon.stub()
directorySize: sinon.stub()
@LocalFileWriter =
writeStream: sinon.stub()
getStream: sinon.stub()
deleteFile: sinon.stub()
@FileConverter =
convert: sinon.stub()
thumbnail: sinon.stub()
preview: sinon.stub()
@keyBuilder =
addCachingToKey: sinon.stub()
getConvertedFolderKey: sinon.stub()
@ImageOptimiser =
compressPng: sinon.stub()
@handler = SandboxedModule.require modulePath, requires:
"settings-sharelatex": @settings
"./PersistorManager":@PersistorManager
"./LocalFileWriter":@LocalFileWriter
"./FileConverter":@FileConverter
"./KeyBuilder": @keyBuilder
"./ImageOptimiser":@ImageOptimiser
"logger-sharelatex":
log:->
err:->
@bucket = "my_bucket"
@key = "key/here"
@stubbedPath = "/var/somewhere/path"
@format = "png"
@formattedStubbedPath = "#{@stubbedPath}.#{@format}"
describe "insertFile", ->
beforeEach ->
@stream = {}
@PersistorManager.deleteDirectory.callsArgWith(2)
@PersistorManager.sendStream.callsArgWith(3)
it "should send file to the filestore", (done)->
@handler.insertFile @bucket, @key, @stream, =>
@PersistorManager.sendStream.calledWith(@bucket, @key, @stream).should.equal true
done()
it "should delete the convetedKey folder", (done)->
@keyBuilder.getConvertedFolderKey.returns(@stubbedConvetedKey)
@handler.insertFile @bucket, @key, @stream, =>
@PersistorManager.deleteDirectory.calledWith(@bucket, @stubbedConvetedKey).should.equal true
done()
describe "deleteFile", ->
beforeEach ->
@keyBuilder.getConvertedFolderKey.returns(@stubbedConvetedKey)
@PersistorManager.deleteFile.callsArgWith(2)
@PersistorManager.deleteDirectory.callsArgWith(2)
it "should tell the filestore manager to delete the file", (done)->
@handler.deleteFile @bucket, @key, =>
@PersistorManager.deleteFile.calledWith(@bucket, @key).should.equal true
done()
it "should tell the filestore manager to delete the cached foler", (done)->
@handler.deleteFile @bucket, @key, =>
@PersistorManager.deleteDirectory.calledWith(@bucket, @stubbedConvetedKey).should.equal true
done()
describe "getFile", ->
beforeEach ->
@handler._getStandardFile = sinon.stub().callsArgWith(3)
@handler._getConvertedFile = sinon.stub().callsArgWith(3)
it "should call _getStandardFile if no format or style are defined", (done)->
@handler.getFile @bucket, @key, null, =>
@handler._getStandardFile.called.should.equal true
@handler._getConvertedFile.called.should.equal false
done()
it "should pass options to _getStandardFile", (done) ->
options = {start: 0, end: 8}
@handler.getFile @bucket, @key, options, =>
expect(@handler._getStandardFile.lastCall.args[2].start).to.equal 0
expect(@handler._getStandardFile.lastCall.args[2].end).to.equal 8
done()
it "should call _getConvertedFile if a format is defined", (done)->
@handler.getFile @bucket, @key, format:"png", =>
@handler._getStandardFile.called.should.equal false
@handler._getConvertedFile.called.should.equal true
done()
describe "_getStandardFile", ->
beforeEach ->
@fileStream = {on:->}
@PersistorManager.getFileStream.callsArgWith(3, "err", @fileStream)
it "should get the stream", (done)->
@handler.getFile @bucket, @key, null, =>
@PersistorManager.getFileStream.calledWith(@bucket, @key).should.equal true
done()
it "should return the stream and error", (done)->
@handler.getFile @bucket, @key, null, (err, stream)=>
err.should.equal "err"
stream.should.equal @fileStream
done()
it "should pass options to PersistorManager", (done) ->
@handler.getFile @bucket, @key, {start: 0, end: 8}, =>
expect(@PersistorManager.getFileStream.lastCall.args[2].start).to.equal 0
expect(@PersistorManager.getFileStream.lastCall.args[2].end).to.equal 8
done()
describe "_getConvertedFile", ->
it "should getFileStream if it does exists", (done)->
@PersistorManager.checkIfFileExists.callsArgWith(2, null, true)
@PersistorManager.getFileStream.callsArgWith(3)
@handler._getConvertedFile @bucket, @key, {}, =>
@PersistorManager.getFileStream.calledWith(@bucket).should.equal true
done()
it "should call _getConvertedFileAndCache if it does exists", (done)->
@PersistorManager.checkIfFileExists.callsArgWith(2, null, false)
@handler._getConvertedFileAndCache = sinon.stub().callsArgWith(4)
@handler._getConvertedFile @bucket, @key, {}, =>
@handler._getConvertedFileAndCache.calledWith(@bucket, @key).should.equal true
done()
describe "_getConvertedFileAndCache", ->
it "should _convertFile ", (done)->
@stubbedStream = {"something":"here"}
@localStream = {
on: ->
}
}
@PersistorManager.sendFile = sinon.stub().callsArgWith(3)
@LocalFileWriter.getStream = sinon.stub().callsArgWith(1, null, @localStream)
@convetedKey = @key+"converted"
@handler._convertFile = sinon.stub().callsArgWith(3, null, @stubbedPath)
@ImageOptimiser.compressPng = sinon.stub().callsArgWith(1)
@handler._getConvertedFileAndCache @bucket, @key, @convetedKey, {}, (err, fsStream)=>
@handler._convertFile.called.should.equal true
@PersistorManager.sendFile.calledWith(@bucket, @convetedKey, @stubbedPath).should.equal true
@ImageOptimiser.compressPng.calledWith(@stubbedPath).should.equal true
@LocalFileWriter.getStream.calledWith(@stubbedPath).should.equal true
fsStream.should.equal @localStream
done()
};
this.PersistorManager = {
getFileStream: sinon.stub(),
checkIfFileExists: sinon.stub(),
deleteFile: sinon.stub(),
deleteDirectory: sinon.stub(),
sendStream: sinon.stub(),
insertFile: sinon.stub(),
directorySize: sinon.stub()
};
this.LocalFileWriter = {
writeStream: sinon.stub(),
getStream: sinon.stub(),
deleteFile: sinon.stub()
};
this.FileConverter = {
convert: sinon.stub(),
thumbnail: sinon.stub(),
preview: sinon.stub()
};
this.keyBuilder = {
addCachingToKey: sinon.stub(),
getConvertedFolderKey: sinon.stub()
};
this.ImageOptimiser =
{compressPng: sinon.stub()};
this.handler = SandboxedModule.require(modulePath, { requires: {
"settings-sharelatex": this.settings,
"./PersistorManager":this.PersistorManager,
"./LocalFileWriter":this.LocalFileWriter,
"./FileConverter":this.FileConverter,
"./KeyBuilder": this.keyBuilder,
"./ImageOptimiser":this.ImageOptimiser,
"logger-sharelatex": {
log() {},
err() {}
}
}
}
);
this.bucket = "my_bucket";
this.key = "key/here";
this.stubbedPath = "/var/somewhere/path";
this.format = "png";
return this.formattedStubbedPath = `${this.stubbedPath}.${this.format}`;
});
describe "_convertFile", ->
beforeEach ->
@FileConverter.convert.callsArgWith(2, null, @formattedStubbedPath)
@FileConverter.thumbnail.callsArgWith(1, null, @formattedStubbedPath)
@FileConverter.preview.callsArgWith(1, null, @formattedStubbedPath)
@handler._writeS3FileToDisk = sinon.stub().callsArgWith(3, null, @stubbedPath)
@LocalFileWriter.deleteFile.callsArgWith(1)
describe("insertFile", function() {
beforeEach(function() {
this.stream = {};
this.PersistorManager.deleteDirectory.callsArgWith(2);
return this.PersistorManager.sendStream.callsArgWith(3);
});
it "should call thumbnail on the writer path if style was thumbnail was specified", (done)->
@handler._convertFile @bucket, @key, style:"thumbnail", (err, path)=>
path.should.equal @formattedStubbedPath
@FileConverter.thumbnail.calledWith(@stubbedPath).should.equal true
@LocalFileWriter.deleteFile.calledWith(@stubbedPath).should.equal true
done()
it("should send file to the filestore", function(done){
return this.handler.insertFile(this.bucket, this.key, this.stream, () => {
this.PersistorManager.sendStream.calledWith(this.bucket, this.key, this.stream).should.equal(true);
return done();
});
});
it "should call preview on the writer path if style was preview was specified", (done)->
@handler._convertFile @bucket, @key, style:"preview", (err, path)=>
path.should.equal @formattedStubbedPath
@FileConverter.preview.calledWith(@stubbedPath).should.equal true
@LocalFileWriter.deleteFile.calledWith(@stubbedPath).should.equal true
done()
return it("should delete the convetedKey folder", function(done){
this.keyBuilder.getConvertedFolderKey.returns(this.stubbedConvetedKey);
return this.handler.insertFile(this.bucket, this.key, this.stream, () => {
this.PersistorManager.deleteDirectory.calledWith(this.bucket, this.stubbedConvetedKey).should.equal(true);
return done();
});
});
});
it "should call convert on the writer path if a format was specified", (done)->
@handler._convertFile @bucket, @key, format:@format, (err, path)=>
path.should.equal @formattedStubbedPath
@FileConverter.convert.calledWith(@stubbedPath, @format).should.equal true
@LocalFileWriter.deleteFile.calledWith(@stubbedPath).should.equal true
done()
describe("deleteFile", function() {
beforeEach(function() {
this.keyBuilder.getConvertedFolderKey.returns(this.stubbedConvetedKey);
this.PersistorManager.deleteFile.callsArgWith(2);
return this.PersistorManager.deleteDirectory.callsArgWith(2);
});
describe "getDirectorySize", ->
it("should tell the filestore manager to delete the file", function(done){
return this.handler.deleteFile(this.bucket, this.key, () => {
this.PersistorManager.deleteFile.calledWith(this.bucket, this.key).should.equal(true);
return done();
});
});
beforeEach ->
@PersistorManager.directorySize.callsArgWith(2)
return it("should tell the filestore manager to delete the cached foler", function(done){
return this.handler.deleteFile(this.bucket, this.key, () => {
this.PersistorManager.deleteDirectory.calledWith(this.bucket, this.stubbedConvetedKey).should.equal(true);
return done();
});
});
});
it "should call the filestore manager to get directory size", (done)->
@handler.getDirectorySize @bucket, @key, =>
@PersistorManager.directorySize.calledWith(@bucket, @key).should.equal true
done()
describe("getFile", function() {
beforeEach(function() {
this.handler._getStandardFile = sinon.stub().callsArgWith(3);
return this.handler._getConvertedFile = sinon.stub().callsArgWith(3);
});
it("should call _getStandardFile if no format or style are defined", function(done){
return this.handler.getFile(this.bucket, this.key, null, () => {
this.handler._getStandardFile.called.should.equal(true);
this.handler._getConvertedFile.called.should.equal(false);
return done();
});
});
it("should pass options to _getStandardFile", function(done) {
const options = {start: 0, end: 8};
return this.handler.getFile(this.bucket, this.key, options, () => {
expect(this.handler._getStandardFile.lastCall.args[2].start).to.equal(0);
expect(this.handler._getStandardFile.lastCall.args[2].end).to.equal(8);
return done();
});
});
return it("should call _getConvertedFile if a format is defined", function(done){
return this.handler.getFile(this.bucket, this.key, {format:"png"}, () => {
this.handler._getStandardFile.called.should.equal(false);
this.handler._getConvertedFile.called.should.equal(true);
return done();
});
});
});
describe("_getStandardFile", function() {
beforeEach(function() {
this.fileStream = {on() {}};
return this.PersistorManager.getFileStream.callsArgWith(3, "err", this.fileStream);
});
it("should get the stream", function(done){
return this.handler.getFile(this.bucket, this.key, null, () => {
this.PersistorManager.getFileStream.calledWith(this.bucket, this.key).should.equal(true);
return done();
});
});
it("should return the stream and error", function(done){
return this.handler.getFile(this.bucket, this.key, null, (err, stream)=> {
err.should.equal("err");
stream.should.equal(this.fileStream);
return done();
});
});
return it("should pass options to PersistorManager", function(done) {
return this.handler.getFile(this.bucket, this.key, {start: 0, end: 8}, () => {
expect(this.PersistorManager.getFileStream.lastCall.args[2].start).to.equal(0);
expect(this.PersistorManager.getFileStream.lastCall.args[2].end).to.equal(8);
return done();
});
});
});
describe("_getConvertedFile", function() {
it("should getFileStream if it does exists", function(done){
this.PersistorManager.checkIfFileExists.callsArgWith(2, null, true);
this.PersistorManager.getFileStream.callsArgWith(3);
return this.handler._getConvertedFile(this.bucket, this.key, {}, () => {
this.PersistorManager.getFileStream.calledWith(this.bucket).should.equal(true);
return done();
});
});
return it("should call _getConvertedFileAndCache if it does exists", function(done){
this.PersistorManager.checkIfFileExists.callsArgWith(2, null, false);
this.handler._getConvertedFileAndCache = sinon.stub().callsArgWith(4);
return this.handler._getConvertedFile(this.bucket, this.key, {}, () => {
this.handler._getConvertedFileAndCache.calledWith(this.bucket, this.key).should.equal(true);
return done();
});
});
});
describe("_getConvertedFileAndCache", () => it("should _convertFile ", function(done){
this.stubbedStream = {"something":"here"};
this.localStream = {
on() {}
};
this.PersistorManager.sendFile = sinon.stub().callsArgWith(3);
this.LocalFileWriter.getStream = sinon.stub().callsArgWith(1, null, this.localStream);
this.convetedKey = this.key+"converted";
this.handler._convertFile = sinon.stub().callsArgWith(3, null, this.stubbedPath);
this.ImageOptimiser.compressPng = sinon.stub().callsArgWith(1);
return this.handler._getConvertedFileAndCache(this.bucket, this.key, this.convetedKey, {}, (err, fsStream)=> {
this.handler._convertFile.called.should.equal(true);
this.PersistorManager.sendFile.calledWith(this.bucket, this.convetedKey, this.stubbedPath).should.equal(true);
this.ImageOptimiser.compressPng.calledWith(this.stubbedPath).should.equal(true);
this.LocalFileWriter.getStream.calledWith(this.stubbedPath).should.equal(true);
fsStream.should.equal(this.localStream);
return done();
});
}));
describe("_convertFile", function() {
beforeEach(function() {
this.FileConverter.convert.callsArgWith(2, null, this.formattedStubbedPath);
this.FileConverter.thumbnail.callsArgWith(1, null, this.formattedStubbedPath);
this.FileConverter.preview.callsArgWith(1, null, this.formattedStubbedPath);
this.handler._writeS3FileToDisk = sinon.stub().callsArgWith(3, null, this.stubbedPath);
return this.LocalFileWriter.deleteFile.callsArgWith(1);
});
it("should call thumbnail on the writer path if style was thumbnail was specified", function(done){
return this.handler._convertFile(this.bucket, this.key, {style:"thumbnail"}, (err, path)=> {
path.should.equal(this.formattedStubbedPath);
this.FileConverter.thumbnail.calledWith(this.stubbedPath).should.equal(true);
this.LocalFileWriter.deleteFile.calledWith(this.stubbedPath).should.equal(true);
return done();
});
});
it("should call preview on the writer path if style was preview was specified", function(done){
return this.handler._convertFile(this.bucket, this.key, {style:"preview"}, (err, path)=> {
path.should.equal(this.formattedStubbedPath);
this.FileConverter.preview.calledWith(this.stubbedPath).should.equal(true);
this.LocalFileWriter.deleteFile.calledWith(this.stubbedPath).should.equal(true);
return done();
});
});
return it("should call convert on the writer path if a format was specified", function(done){
return this.handler._convertFile(this.bucket, this.key, {format:this.format}, (err, path)=> {
path.should.equal(this.formattedStubbedPath);
this.FileConverter.convert.calledWith(this.stubbedPath, this.format).should.equal(true);
this.LocalFileWriter.deleteFile.calledWith(this.stubbedPath).should.equal(true);
return done();
});
});
});
return describe("getDirectorySize", function() {
beforeEach(function() {
return this.PersistorManager.directorySize.callsArgWith(2);
});
return it("should call the filestore manager to get directory size", function(done){
return this.handler.getDirectorySize(this.bucket, this.key, () => {
this.PersistorManager.directorySize.calledWith(this.bucket, this.key).should.equal(true);
return done();
});
});
});
});

View file

@ -1,64 +1,84 @@
assert = require("chai").assert
sinon = require('sinon')
chai = require('chai')
should = chai.should()
expect = chai.expect
modulePath = "../../../app/js/ImageOptimiser.js"
SandboxedModule = require('sandboxed-module')
/*
* decaffeinate suggestions:
* 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/ImageOptimiser.js";
const SandboxedModule = require('sandboxed-module');
describe "ImageOptimiser", ->
describe("ImageOptimiser", function() {
beforeEach ->
@child_process =
exec : sinon.stub()
@settings =
enableConversions:true
@optimiser = SandboxedModule.require modulePath, requires:
'child_process': @child_process
"logger-sharelatex":
log:->
err:->
warn:->
"settings-sharelatex": @settings
beforeEach(function() {
this.child_process =
{exec : sinon.stub()};
this.settings =
{enableConversions:true};
this.optimiser = SandboxedModule.require(modulePath, { requires: {
'child_process': this.child_process,
"logger-sharelatex": {
log() {},
err() {},
warn() {}
},
"settings-sharelatex": this.settings
}
}
);
@sourcePath = "/this/path/here.eps"
@error = "Error"
this.sourcePath = "/this/path/here.eps";
return this.error = "Error";
});
describe "compressPng", ->
describe("compressPng", function() {
it "convert the file", (done)->
@child_process.exec.callsArgWith(2)
@optimiser.compressPng @sourcePath, (err)=>
args = @child_process.exec.args[0][0]
args.should.equal "optipng #{@sourcePath}"
done()
it("convert the file", function(done){
this.child_process.exec.callsArgWith(2);
return this.optimiser.compressPng(this.sourcePath, err=> {
const args = this.child_process.exec.args[0][0];
args.should.equal(`optipng ${this.sourcePath}`);
return done();
});
});
it "should return the error", (done)->
@child_process.exec.callsArgWith(2, @error)
@optimiser.compressPng @sourcePath, (err)=>
err.should.equal @error
done()
return it("should return the error", function(done){
this.child_process.exec.callsArgWith(2, this.error);
return this.optimiser.compressPng(this.sourcePath, err=> {
err.should.equal(this.error);
return done();
});
});
});
describe 'when enableConversions is disabled', ->
it 'should produce an error', (done) ->
@settings.enableConversions = false
@child_process.exec.callsArgWith(2)
@optimiser.compressPng @sourcePath, (err)=>
@child_process.exec.called.should.equal false
expect(err).to.exist
done()
describe('when enableConversions is disabled', () => it('should produce an error', function(done) {
this.settings.enableConversions = false;
this.child_process.exec.callsArgWith(2);
return this.optimiser.compressPng(this.sourcePath, err=> {
this.child_process.exec.called.should.equal(false);
expect(err).to.exist;
return done();
});
}));
describe 'when optimiser is sigkilled', ->
it 'should not produce an error', (done) ->
@error = new Error('woops')
@error.signal = 'SIGKILL'
@child_process.exec.callsArgWith(2, @error)
@optimiser.compressPng @sourcePath, (err)=>
expect(err).to.equal(null)
done()
return describe('when optimiser is sigkilled', () => it('should not produce an error', function(done) {
this.error = new Error('woops');
this.error.signal = 'SIGKILL';
this.child_process.exec.callsArgWith(2, this.error);
return this.optimiser.compressPng(this.sourcePath, err=> {
expect(err).to.equal(null);
return done();
});
}));
});

View file

@ -1,39 +1,59 @@
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
assert = require("chai").assert
sinon = require('sinon')
chai = require('chai')
should = chai.should()
expect = chai.expect
modulePath = "../../../app/js/KeyBuilder.js"
SandboxedModule = require('sandboxed-module')
const {
assert
} = require("chai");
const sinon = require('sinon');
const chai = require('chai');
const should = chai.should();
const {
expect
} = chai;
const modulePath = "../../../app/js/KeyBuilder.js";
const SandboxedModule = require('sandboxed-module');
describe "LocalFileWriter", ->
describe("LocalFileWriter", function() {
beforeEach ->
beforeEach(function() {
@keyBuilder = SandboxedModule.require modulePath, requires:
"logger-sharelatex":
log:->
err:->
@key = "123/456"
this.keyBuilder = SandboxedModule.require(modulePath, { requires: {
"logger-sharelatex": {
log() {},
err() {}
}
}
}
);
return this.key = "123/456";
});
describe "cachedKey", ->
return describe("cachedKey", function() {
it "should add the fomat on", ->
opts =
it("should add the fomat on", function() {
const opts =
{format: "png"};
const newKey = this.keyBuilder.addCachingToKey(this.key, opts);
return newKey.should.equal(`${this.key}-converted-cache/format-png`);
});
it("should add the style on", function() {
const opts =
{style: "thumbnail"};
const newKey = this.keyBuilder.addCachingToKey(this.key, opts);
return newKey.should.equal(`${this.key}-converted-cache/style-thumbnail`);
});
return it("should add format on first", function() {
const opts = {
style: "thumbnail",
format: "png"
newKey = @keyBuilder.addCachingToKey @key, opts
newKey.should.equal "#{@key}-converted-cache/format-png"
it "should add the style on", ->
opts =
style: "thumbnail"
newKey = @keyBuilder.addCachingToKey @key, opts
newKey.should.equal "#{@key}-converted-cache/style-thumbnail"
it "should add format on first", ->
opts =
style: "thumbnail"
format: "png"
newKey = @keyBuilder.addCachingToKey @key, opts
newKey.should.equal "#{@key}-converted-cache/format-png-style-thumbnail"
};
const newKey = this.keyBuilder.addCachingToKey(this.key, opts);
return newKey.should.equal(`${this.key}-converted-cache/format-png-style-thumbnail`);
});
});
});

View file

@ -1,83 +1,121 @@
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
assert = require("chai").assert
sinon = require('sinon')
chai = require('chai')
should = chai.should()
expect = chai.expect
modulePath = "../../../app/js/LocalFileWriter.js"
SandboxedModule = require('sandboxed-module')
const {
assert
} = require("chai");
const sinon = require('sinon');
const chai = require('chai');
const should = chai.should();
const {
expect
} = chai;
const modulePath = "../../../app/js/LocalFileWriter.js";
const SandboxedModule = require('sandboxed-module');
describe "LocalFileWriter", ->
describe("LocalFileWriter", function() {
beforeEach ->
beforeEach(function() {
@writeStream =
on: (type, cb)->
if type == "finish"
cb()
@readStream =
on: ->
@fs =
createWriteStream : sinon.stub().returns(@writeStream)
createReadStream: sinon.stub().returns(@readStream)
this.writeStream = {
on(type, cb){
if (type === "finish") {
return cb();
}
}
};
this.readStream =
{on() {}};
this.fs = {
createWriteStream : sinon.stub().returns(this.writeStream),
createReadStream: sinon.stub().returns(this.readStream),
unlink: sinon.stub()
@settings =
path:
};
this.settings = {
path: {
uploadFolder:"somewhere"
@writer = SandboxedModule.require modulePath, requires:
"fs": @fs
"logger-sharelatex":
log:->
err:->
"settings-sharelatex":@settings
"metrics-sharelatex":
inc:->
Timer:->
done:->
}
};
this.writer = SandboxedModule.require(modulePath, { requires: {
"fs": this.fs,
"logger-sharelatex": {
log() {},
err() {}
},
"settings-sharelatex":this.settings,
"metrics-sharelatex": {
inc() {},
Timer() {
return {done() {}};
}
}
}
}
);
@stubbedFsPath = "something/uploads/eio2k1j3"
return this.stubbedFsPath = "something/uploads/eio2k1j3";
});
describe "writeStrem", ->
beforeEach ->
@writer._getPath = sinon.stub().returns(@stubbedFsPath)
describe("writeStrem", function() {
beforeEach(function() {
return this.writer._getPath = sinon.stub().returns(this.stubbedFsPath);
});
it "write the stream to ./uploads", (done)->
stream =
pipe: (dest)=>
dest.should.equal @writeStream
done()
on: ->
@writer.writeStream stream, null, ()=>
it("write the stream to ./uploads", function(done){
const stream = {
pipe: dest=> {
dest.should.equal(this.writeStream);
return done();
},
on() {}
};
return this.writer.writeStream(stream, null, ()=> {});
});
it "should send the path in the callback", (done)->
stream =
pipe: (dest)=>
on: (type, cb)->
if type == "end"
cb()
@writer.writeStream stream, null, (err, fsPath)=>
fsPath.should.equal @stubbedFsPath
done()
return it("should send the path in the callback", function(done){
const stream = {
pipe: dest=> {},
on(type, cb){
if (type === "end") {
return cb();
}
}
};
return this.writer.writeStream(stream, null, (err, fsPath)=> {
fsPath.should.equal(this.stubbedFsPath);
return done();
});
});
});
describe "getStream", ->
describe("getStream", function() {
it "should read the stream from the file ", (done)->
@writer.getStream @stubbedFsPath, (err, stream)=>
@fs.createReadStream.calledWith(@stubbedFsPath).should.equal true
done()
it("should read the stream from the file ", function(done){
return this.writer.getStream(this.stubbedFsPath, (err, stream)=> {
this.fs.createReadStream.calledWith(this.stubbedFsPath).should.equal(true);
return done();
});
});
it "should send the stream in the callback", (done)->
@writer.getStream @stubbedFsPath, (err, readStream)=>
readStream.should.equal @readStream
done()
return it("should send the stream in the callback", function(done){
return this.writer.getStream(this.stubbedFsPath, (err, readStream)=> {
readStream.should.equal(this.readStream);
return done();
});
});
});
describe "delete file", ->
it "should unlink the file", (done)->
error = "my error"
@fs.unlink.callsArgWith(1, error)
@writer.deleteFile @stubbedFsPath, (err)=>
@fs.unlink.calledWith(@stubbedFsPath).should.equal true
err.should.equal error
done()
return describe("delete file", () => it("should unlink the file", function(done){
const error = "my error";
this.fs.unlink.callsArgWith(1, error);
return this.writer.deleteFile(this.stubbedFsPath, err=> {
this.fs.unlink.calledWith(this.stubbedFsPath).should.equal(true);
err.should.equal(error);
return done();
});
}));
});

View file

@ -1,101 +1,131 @@
logger = require("logger-sharelatex")
assert = require("chai").assert
sinon = require('sinon')
chai = require('chai')
should = chai.should()
expect = chai.expect
modulePath = "../../../app/js/PersistorManager.js"
SandboxedModule = require('sandboxed-module')
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const logger = require("logger-sharelatex");
const {
assert
} = require("chai");
const sinon = require('sinon');
const chai = require('chai');
const should = chai.should();
const {
expect
} = chai;
const modulePath = "../../../app/js/PersistorManager.js";
const SandboxedModule = require('sandboxed-module');
describe "PersistorManagerTests", ->
describe("PersistorManagerTests", function() {
beforeEach ->
@S3PersistorManager =
getFileStream: sinon.stub()
checkIfFileExists: sinon.stub()
deleteFile: sinon.stub()
deleteDirectory: sinon.stub()
sendStream: sinon.stub()
beforeEach(function() {
return this.S3PersistorManager = {
getFileStream: sinon.stub(),
checkIfFileExists: sinon.stub(),
deleteFile: sinon.stub(),
deleteDirectory: sinon.stub(),
sendStream: sinon.stub(),
insertFile: sinon.stub()
};
});
describe "test s3 mixin", ->
beforeEach ->
@settings =
filestore:
describe("test s3 mixin", function() {
beforeEach(function() {
this.settings = {
filestore: {
backend: "s3"
@requires =
"./S3PersistorManager": @S3PersistorManager
"settings-sharelatex": @settings
"logger-sharelatex":
log:->
err:->
@PersistorManager = SandboxedModule.require modulePath, requires: @requires
}
};
this.requires = {
"./S3PersistorManager": this.S3PersistorManager,
"settings-sharelatex": this.settings,
"logger-sharelatex": {
log() {},
err() {}
}
};
return this.PersistorManager = SandboxedModule.require(modulePath, {requires: this.requires});
});
it "should load getFileStream", (done) ->
@PersistorManager.should.respondTo("getFileStream")
@PersistorManager.getFileStream()
@S3PersistorManager.getFileStream.calledOnce.should.equal true
done()
it("should load getFileStream", function(done) {
this.PersistorManager.should.respondTo("getFileStream");
this.PersistorManager.getFileStream();
this.S3PersistorManager.getFileStream.calledOnce.should.equal(true);
return done();
});
it "should load checkIfFileExists", (done) ->
@PersistorManager.checkIfFileExists()
@S3PersistorManager.checkIfFileExists.calledOnce.should.equal true
done()
it("should load checkIfFileExists", function(done) {
this.PersistorManager.checkIfFileExists();
this.S3PersistorManager.checkIfFileExists.calledOnce.should.equal(true);
return done();
});
it "should load deleteFile", (done) ->
@PersistorManager.deleteFile()
@S3PersistorManager.deleteFile.calledOnce.should.equal true
done()
it("should load deleteFile", function(done) {
this.PersistorManager.deleteFile();
this.S3PersistorManager.deleteFile.calledOnce.should.equal(true);
return done();
});
it "should load deleteDirectory", (done) ->
@PersistorManager.deleteDirectory()
@S3PersistorManager.deleteDirectory.calledOnce.should.equal true
done()
it("should load deleteDirectory", function(done) {
this.PersistorManager.deleteDirectory();
this.S3PersistorManager.deleteDirectory.calledOnce.should.equal(true);
return done();
});
it "should load sendStream", (done) ->
@PersistorManager.sendStream()
@S3PersistorManager.sendStream.calledOnce.should.equal true
done()
it("should load sendStream", function(done) {
this.PersistorManager.sendStream();
this.S3PersistorManager.sendStream.calledOnce.should.equal(true);
return done();
});
it "should load insertFile", (done) ->
@PersistorManager.insertFile()
@S3PersistorManager.insertFile.calledOnce.should.equal true
done()
return it("should load insertFile", function(done) {
this.PersistorManager.insertFile();
this.S3PersistorManager.insertFile.calledOnce.should.equal(true);
return done();
});
});
describe "test unspecified mixins", ->
describe("test unspecified mixins", () => it("should load s3 when no wrapper specified", function(done) {
this.settings = {filestore:{}};
this.requires = {
"./S3PersistorManager": this.S3PersistorManager,
"settings-sharelatex": this.settings,
"logger-sharelatex": {
log() {},
err() {}
}
};
this.PersistorManager = SandboxedModule.require(modulePath, {requires: this.requires});
this.PersistorManager.should.respondTo("getFileStream");
this.PersistorManager.getFileStream();
this.S3PersistorManager.getFileStream.calledOnce.should.equal(true);
return done();
}));
it "should load s3 when no wrapper specified", (done) ->
@settings = {filestore:{}}
@requires =
"./S3PersistorManager": @S3PersistorManager
"settings-sharelatex": @settings
"logger-sharelatex":
log:->
err:->
@PersistorManager = SandboxedModule.require modulePath, requires: @requires
@PersistorManager.should.respondTo("getFileStream")
@PersistorManager.getFileStream()
@S3PersistorManager.getFileStream.calledOnce.should.equal true
done()
describe "test invalid mixins", ->
it "should not load an invalid wrapper", (done) ->
@settings =
filestore:
backend:"magic"
@requires =
"./S3PersistorManager": @S3PersistorManager
"settings-sharelatex": @settings
"logger-sharelatex":
log:->
err:->
@fsWrapper=null
try
@PersistorManager=SandboxedModule.require modulePath, requires: @requires
catch error
assert.equal("Unknown filestore backend: magic",error.message)
assert.isNull(@fsWrapper)
done()
return describe("test invalid mixins", () => it("should not load an invalid wrapper", function(done) {
this.settings = {
filestore: {
backend:"magic"
}
};
this.requires = {
"./S3PersistorManager": this.S3PersistorManager,
"settings-sharelatex": this.settings,
"logger-sharelatex": {
log() {},
err() {}
}
};
this.fsWrapper=null;
try {
this.PersistorManager=SandboxedModule.require(modulePath, {requires: this.requires});
} catch (error) {
assert.equal("Unknown filestore backend: magic",error.message);
}
assert.isNull(this.fsWrapper);
return done();
}));
});

View file

@ -1,343 +1,447 @@
assert = require("chai").assert
sinon = require('sinon')
chai = require('chai')
should = chai.should()
expect = chai.expect
modulePath = "../../../app/js/S3PersistorManager.js"
SandboxedModule = require('sandboxed-module')
/*
* 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 {
assert
} = require("chai");
const sinon = require('sinon');
const chai = require('chai');
const should = chai.should();
const {
expect
} = chai;
const modulePath = "../../../app/js/S3PersistorManager.js";
const SandboxedModule = require('sandboxed-module');
describe "S3PersistorManagerTests", ->
describe("S3PersistorManagerTests", function() {
beforeEach ->
@settings =
filestore:
backend: "s3"
s3:
secret: "secret"
beforeEach(function() {
this.settings = {
filestore: {
backend: "s3",
s3: {
secret: "secret",
key: "this_key"
stores:
},
stores: {
user_files:"sl_user_files"
@knoxClient =
putFile:sinon.stub()
copyFile:sinon.stub()
list: sinon.stub()
deleteMultiple: sinon.stub()
get: sinon.stub()
@knox =
createClient: sinon.stub().returns(@knoxClient)
@s3EventHandlers = {}
@s3Request =
on: sinon.stub().callsFake (event, callback) =>
@s3EventHandlers[event] = callback
send: sinon.stub()
@s3Response =
httpResponse:
createUnbufferedStream: sinon.stub()
@s3Client =
copyObject: sinon.stub()
headObject: sinon.stub()
getObject: sinon.stub().returns(@s3Request)
@awsS3 = sinon.stub().returns(@s3Client)
@LocalFileWriter =
writeStream: sinon.stub()
deleteFile: sinon.stub()
@request = sinon.stub()
@requires =
"knox": @knox
"aws-sdk/clients/s3": @awsS3
"settings-sharelatex": @settings
"./LocalFileWriter":@LocalFileWriter
"logger-sharelatex":
log:->
err:->
"request": @request
"./Errors": @Errors =
NotFoundError: sinon.stub()
@key = "my/key"
@bucketName = "my-bucket"
@error = "my errror"
@S3PersistorManager = SandboxedModule.require modulePath, requires: @requires
describe "getFileStream", ->
describe "success", ->
beforeEach () ->
@expectedStream = { expectedStream: true }
@expectedStream.on = sinon.stub()
@s3Request.send.callsFake () =>
@s3EventHandlers.httpHeaders(200, {}, @s3Response, "OK")
@s3Response.httpResponse.createUnbufferedStream.returns(@expectedStream)
it "returns a stream", (done) ->
@S3PersistorManager.getFileStream @bucketName, @key, {}, (err, stream) =>
if err?
return done(err)
expect(stream).to.equal(@expectedStream)
done()
it "sets the AWS client up with credentials from settings", (done) ->
@S3PersistorManager.getFileStream @bucketName, @key, {}, (err, stream) =>
if err?
return done(err)
expect(@awsS3.lastCall.args).to.deep.equal([{
credentials:
accessKeyId: @settings.filestore.s3.key
secretAccessKey: @settings.filestore.s3.secret
}])
done()
it "fetches the right key from the right bucket", (done) ->
@S3PersistorManager.getFileStream @bucketName, @key, {}, (err, stream) =>
if err?
return done(err)
expect(@s3Client.getObject.lastCall.args).to.deep.equal([{
Bucket: @bucketName,
Key: @key
}])
done()
it "accepts alternative credentials", (done) ->
accessKeyId = "that_key"
secret = "that_secret"
opts = {
credentials:
auth_key: accessKeyId
auth_secret: secret
}
@S3PersistorManager.getFileStream @bucketName, @key, opts, (err, stream) =>
if err?
return done(err)
expect(@awsS3.lastCall.args).to.deep.equal([{
credentials:
accessKeyId: accessKeyId
}
};
this.knoxClient = {
putFile:sinon.stub(),
copyFile:sinon.stub(),
list: sinon.stub(),
deleteMultiple: sinon.stub(),
get: sinon.stub()
};
this.knox =
{createClient: sinon.stub().returns(this.knoxClient)};
this.s3EventHandlers = {};
this.s3Request = {
on: sinon.stub().callsFake((event, callback) => {
return this.s3EventHandlers[event] = callback;
}),
send: sinon.stub()
};
this.s3Response = {
httpResponse: {
createUnbufferedStream: sinon.stub()
}
};
this.s3Client = {
copyObject: sinon.stub(),
headObject: sinon.stub(),
getObject: sinon.stub().returns(this.s3Request)
};
this.awsS3 = sinon.stub().returns(this.s3Client);
this.LocalFileWriter = {
writeStream: sinon.stub(),
deleteFile: sinon.stub()
};
this.request = sinon.stub();
this.requires = {
"knox": this.knox,
"aws-sdk/clients/s3": this.awsS3,
"settings-sharelatex": this.settings,
"./LocalFileWriter":this.LocalFileWriter,
"logger-sharelatex": {
log() {},
err() {}
},
"request": this.request,
"./Errors": (this.Errors =
{NotFoundError: sinon.stub()})
};
this.key = "my/key";
this.bucketName = "my-bucket";
this.error = "my errror";
return this.S3PersistorManager = SandboxedModule.require(modulePath, {requires: this.requires});
});
describe("getFileStream", function() {
describe("success", function() {
beforeEach(function() {
this.expectedStream = { expectedStream: true };
this.expectedStream.on = sinon.stub();
this.s3Request.send.callsFake(() => {
return this.s3EventHandlers.httpHeaders(200, {}, this.s3Response, "OK");
});
return this.s3Response.httpResponse.createUnbufferedStream.returns(this.expectedStream);
});
it("returns a stream", function(done) {
return this.S3PersistorManager.getFileStream(this.bucketName, this.key, {}, (err, stream) => {
if (err != null) {
return done(err);
}
expect(stream).to.equal(this.expectedStream);
return done();
});
});
it("sets the AWS client up with credentials from settings", function(done) {
return this.S3PersistorManager.getFileStream(this.bucketName, this.key, {}, (err, stream) => {
if (err != null) {
return done(err);
}
expect(this.awsS3.lastCall.args).to.deep.equal([{
credentials: {
accessKeyId: this.settings.filestore.s3.key,
secretAccessKey: this.settings.filestore.s3.secret
}
}]);
return done();
});
});
it("fetches the right key from the right bucket", function(done) {
return this.S3PersistorManager.getFileStream(this.bucketName, this.key, {}, (err, stream) => {
if (err != null) {
return done(err);
}
expect(this.s3Client.getObject.lastCall.args).to.deep.equal([{
Bucket: this.bucketName,
Key: this.key
}]);
return done();
});
});
it("accepts alternative credentials", function(done) {
const accessKeyId = "that_key";
const secret = "that_secret";
const opts = {
credentials: {
auth_key: accessKeyId,
auth_secret: secret
}
};
return this.S3PersistorManager.getFileStream(this.bucketName, this.key, opts, (err, stream) => {
if (err != null) {
return done(err);
}
expect(this.awsS3.lastCall.args).to.deep.equal([{
credentials: {
accessKeyId,
secretAccessKey: secret
}])
expect(stream).to.equal(@expectedStream)
done()
}
}]);
expect(stream).to.equal(this.expectedStream);
return done();
});
});
it "accepts byte range", (done) ->
start = 0
end = 8
opts = { start: start, end: end }
@S3PersistorManager.getFileStream @bucketName, @key, opts, (err, stream) =>
if err?
return done(err)
expect(@s3Client.getObject.lastCall.args).to.deep.equal([{
Bucket: @bucketName
Key: @key
Range: "bytes=#{start}-#{end}"
}])
expect(stream).to.equal(@expectedStream)
done()
return it("accepts byte range", function(done) {
const start = 0;
const end = 8;
const opts = { start, end };
return this.S3PersistorManager.getFileStream(this.bucketName, this.key, opts, (err, stream) => {
if (err != null) {
return done(err);
}
expect(this.s3Client.getObject.lastCall.args).to.deep.equal([{
Bucket: this.bucketName,
Key: this.key,
Range: `bytes=${start}-${end}`
}]);
expect(stream).to.equal(this.expectedStream);
return done();
});
});
});
describe "errors", ->
describe "when the file doesn't exist", ->
beforeEach ->
@s3Request.send.callsFake () =>
@s3EventHandlers.httpHeaders(404, {}, @s3Response, "Not found")
return describe("errors", function() {
describe("when the file doesn't exist", function() {
beforeEach(function() {
return this.s3Request.send.callsFake(() => {
return this.s3EventHandlers.httpHeaders(404, {}, this.s3Response, "Not found");
});
});
it "returns a NotFoundError that indicates the bucket and key", (done) ->
@S3PersistorManager.getFileStream @bucketName, @key, {}, (err, stream) =>
expect(err).to.be.instanceof(@Errors.NotFoundError)
errMsg = @Errors.NotFoundError.lastCall.args[0]
expect(errMsg).to.match(new RegExp(".*#{@bucketName}.*"))
expect(errMsg).to.match(new RegExp(".*#{@key}.*"))
done()
return it("returns a NotFoundError that indicates the bucket and key", function(done) {
return this.S3PersistorManager.getFileStream(this.bucketName, this.key, {}, (err, stream) => {
expect(err).to.be.instanceof(this.Errors.NotFoundError);
const errMsg = this.Errors.NotFoundError.lastCall.args[0];
expect(errMsg).to.match(new RegExp(`.*${this.bucketName}.*`));
expect(errMsg).to.match(new RegExp(`.*${this.key}.*`));
return done();
});
});
});
describe "when S3 encounters an unkown error", ->
beforeEach ->
@s3Request.send.callsFake () =>
@s3EventHandlers.httpHeaders(500, {}, @s3Response, "Internal server error")
describe("when S3 encounters an unkown error", function() {
beforeEach(function() {
return this.s3Request.send.callsFake(() => {
return this.s3EventHandlers.httpHeaders(500, {}, this.s3Response, "Internal server error");
});
});
it "returns an error", (done) ->
@S3PersistorManager.getFileStream @bucketName, @key, {}, (err, stream) =>
expect(err).to.be.instanceof(Error)
done()
return it("returns an error", function(done) {
return this.S3PersistorManager.getFileStream(this.bucketName, this.key, {}, (err, stream) => {
expect(err).to.be.instanceof(Error);
return done();
});
});
});
describe "when the S3 request errors out before receiving HTTP headers", ->
beforeEach ->
@s3Request.send.callsFake () =>
@s3EventHandlers.error(new Error("connection failed"))
return describe("when the S3 request errors out before receiving HTTP headers", function() {
beforeEach(function() {
return this.s3Request.send.callsFake(() => {
return this.s3EventHandlers.error(new Error("connection failed"));
});
});
it "returns an error", (done) ->
@S3PersistorManager.getFileStream @bucketName, @key, {}, (err, stream) =>
expect(err).to.be.instanceof(Error)
done()
return it("returns an error", function(done) {
return this.S3PersistorManager.getFileStream(this.bucketName, this.key, {}, (err, stream) => {
expect(err).to.be.instanceof(Error);
return done();
});
});
});
});
});
describe "getFileSize", ->
it "should obtain the file size from S3", (done) ->
expectedFileSize = 123
@s3Client.headObject.yields(new Error(
describe("getFileSize", function() {
it("should obtain the file size from S3", function(done) {
const expectedFileSize = 123;
this.s3Client.headObject.yields(new Error(
"s3Client.headObject got unexpected arguments"
))
@s3Client.headObject.withArgs({
Bucket: @bucketName
Key: @key
}).yields(null, { ContentLength: expectedFileSize })
));
this.s3Client.headObject.withArgs({
Bucket: this.bucketName,
Key: this.key
}).yields(null, { ContentLength: expectedFileSize });
@S3PersistorManager.getFileSize @bucketName, @key, (err, fileSize) =>
if err?
return done(err)
expect(fileSize).to.equal(expectedFileSize)
done()
return this.S3PersistorManager.getFileSize(this.bucketName, this.key, (err, fileSize) => {
if (err != null) {
return done(err);
}
expect(fileSize).to.equal(expectedFileSize);
return done();
});
});
[403, 404].forEach (statusCode) ->
it "should throw NotFoundError when S3 responds with #{statusCode}", (done) ->
error = new Error()
error.statusCode = statusCode
@s3Client.headObject.yields(error)
[403, 404].forEach(statusCode => it(`should throw NotFoundError when S3 responds with ${statusCode}`, function(done) {
const error = new Error();
error.statusCode = statusCode;
this.s3Client.headObject.yields(error);
@S3PersistorManager.getFileSize @bucketName, @key, (err, fileSize) =>
expect(err).to.be.an.instanceof(@Errors.NotFoundError)
done()
return this.S3PersistorManager.getFileSize(this.bucketName, this.key, (err, fileSize) => {
expect(err).to.be.an.instanceof(this.Errors.NotFoundError);
return done();
});
}));
it "should rethrow any other error", (done) ->
error = new Error()
@s3Client.headObject.yields(error)
@s3Client.headObject.yields(error)
return it("should rethrow any other error", function(done) {
const error = new Error();
this.s3Client.headObject.yields(error);
this.s3Client.headObject.yields(error);
@S3PersistorManager.getFileSize @bucketName, @key, (err, fileSize) =>
expect(err).to.equal(error)
done()
return this.S3PersistorManager.getFileSize(this.bucketName, this.key, (err, fileSize) => {
expect(err).to.equal(error);
return done();
});
});
});
describe "sendFile", ->
describe("sendFile", function() {
beforeEach ->
@knoxClient.putFile.returns on:->
beforeEach(function() {
return this.knoxClient.putFile.returns({on() {}});
});
it "should put file with knox", (done)->
@LocalFileWriter.deleteFile.callsArgWith(1)
@knoxClient.putFile.callsArgWith(2, @error)
@S3PersistorManager.sendFile @bucketName, @key, @fsPath, (err)=>
@knoxClient.putFile.calledWith(@fsPath, @key).should.equal true
err.should.equal @error
done()
it("should put file with knox", function(done){
this.LocalFileWriter.deleteFile.callsArgWith(1);
this.knoxClient.putFile.callsArgWith(2, this.error);
return this.S3PersistorManager.sendFile(this.bucketName, this.key, this.fsPath, err=> {
this.knoxClient.putFile.calledWith(this.fsPath, this.key).should.equal(true);
err.should.equal(this.error);
return done();
});
});
it "should delete the file and pass the error with it", (done)->
@LocalFileWriter.deleteFile.callsArgWith(1)
@knoxClient.putFile.callsArgWith(2, @error)
@S3PersistorManager.sendFile @bucketName, @key, @fsPath, (err)=>
@knoxClient.putFile.calledWith(@fsPath, @key).should.equal true
err.should.equal @error
done()
return it("should delete the file and pass the error with it", function(done){
this.LocalFileWriter.deleteFile.callsArgWith(1);
this.knoxClient.putFile.callsArgWith(2, this.error);
return this.S3PersistorManager.sendFile(this.bucketName, this.key, this.fsPath, err=> {
this.knoxClient.putFile.calledWith(this.fsPath, this.key).should.equal(true);
err.should.equal(this.error);
return done();
});
});
});
describe "sendStream", ->
beforeEach ->
@fsPath = "to/some/where"
@origin =
on:->
@S3PersistorManager.sendFile = sinon.stub().callsArgWith(3)
describe("sendStream", function() {
beforeEach(function() {
this.fsPath = "to/some/where";
this.origin =
{on() {}};
return this.S3PersistorManager.sendFile = sinon.stub().callsArgWith(3);
});
it "should send stream to LocalFileWriter", (done)->
@LocalFileWriter.deleteFile.callsArgWith(1)
@LocalFileWriter.writeStream.callsArgWith(2, null, @fsPath)
@S3PersistorManager.sendStream @bucketName, @key, @origin, =>
@LocalFileWriter.writeStream.calledWith(@origin).should.equal true
done()
it("should send stream to LocalFileWriter", function(done){
this.LocalFileWriter.deleteFile.callsArgWith(1);
this.LocalFileWriter.writeStream.callsArgWith(2, null, this.fsPath);
return this.S3PersistorManager.sendStream(this.bucketName, this.key, this.origin, () => {
this.LocalFileWriter.writeStream.calledWith(this.origin).should.equal(true);
return done();
});
});
it "should return the error from LocalFileWriter", (done)->
@LocalFileWriter.deleteFile.callsArgWith(1)
@LocalFileWriter.writeStream.callsArgWith(2, @error)
@S3PersistorManager.sendStream @bucketName, @key, @origin, (err)=>
err.should.equal @error
done()
it("should return the error from LocalFileWriter", function(done){
this.LocalFileWriter.deleteFile.callsArgWith(1);
this.LocalFileWriter.writeStream.callsArgWith(2, this.error);
return this.S3PersistorManager.sendStream(this.bucketName, this.key, this.origin, err=> {
err.should.equal(this.error);
return done();
});
});
it "should send the file to the filestore", (done)->
@LocalFileWriter.deleteFile.callsArgWith(1)
@LocalFileWriter.writeStream.callsArgWith(2)
@S3PersistorManager.sendStream @bucketName, @key, @origin, (err)=>
@S3PersistorManager.sendFile.called.should.equal true
done()
return it("should send the file to the filestore", function(done){
this.LocalFileWriter.deleteFile.callsArgWith(1);
this.LocalFileWriter.writeStream.callsArgWith(2);
return this.S3PersistorManager.sendStream(this.bucketName, this.key, this.origin, err=> {
this.S3PersistorManager.sendFile.called.should.equal(true);
return done();
});
});
});
describe "copyFile", ->
beforeEach ->
@sourceKey = "my/key"
@destKey = "my/dest/key"
describe("copyFile", function() {
beforeEach(function() {
this.sourceKey = "my/key";
return this.destKey = "my/dest/key";
});
it "should use AWS SDK to copy file", (done)->
@s3Client.copyObject.callsArgWith(1, @error)
@S3PersistorManager.copyFile @bucketName, @sourceKey, @destKey, (err)=>
err.should.equal @error
@s3Client.copyObject.calledWith({Bucket: @bucketName, Key: @destKey, CopySource: @bucketName + '/' + @key}).should.equal true
done()
it("should use AWS SDK to copy file", function(done){
this.s3Client.copyObject.callsArgWith(1, this.error);
return this.S3PersistorManager.copyFile(this.bucketName, this.sourceKey, this.destKey, err=> {
err.should.equal(this.error);
this.s3Client.copyObject.calledWith({Bucket: this.bucketName, Key: this.destKey, CopySource: this.bucketName + '/' + this.key}).should.equal(true);
return done();
});
});
it "should return a NotFoundError object if the original file does not exist", (done)->
NoSuchKeyError = {code: "NoSuchKey"}
@s3Client.copyObject.callsArgWith(1, NoSuchKeyError)
@S3PersistorManager.copyFile @bucketName, @sourceKey, @destKey, (err)=>
expect(err instanceof @Errors.NotFoundError).to.equal true
done()
return it("should return a NotFoundError object if the original file does not exist", function(done){
const NoSuchKeyError = {code: "NoSuchKey"};
this.s3Client.copyObject.callsArgWith(1, NoSuchKeyError);
return this.S3PersistorManager.copyFile(this.bucketName, this.sourceKey, this.destKey, err=> {
expect(err instanceof this.Errors.NotFoundError).to.equal(true);
return done();
});
});
});
describe "deleteDirectory", ->
describe("deleteDirectory", () => it("should list the contents passing them onto multi delete", function(done){
const data =
{Contents: [{Key:"1234"}, {Key: "456"}]};
this.knoxClient.list.callsArgWith(1, null, data);
this.knoxClient.deleteMultiple.callsArgWith(1);
return this.S3PersistorManager.deleteDirectory(this.bucketName, this.key, err=> {
this.knoxClient.deleteMultiple.calledWith(["1234","456"]).should.equal(true);
return done();
});
}));
it "should list the contents passing them onto multi delete", (done)->
data =
Contents: [{Key:"1234"}, {Key: "456"}]
@knoxClient.list.callsArgWith(1, null, data)
@knoxClient.deleteMultiple.callsArgWith(1)
@S3PersistorManager.deleteDirectory @bucketName, @key, (err)=>
@knoxClient.deleteMultiple.calledWith(["1234","456"]).should.equal true
done()
describe("deleteFile", function() {
describe "deleteFile", ->
it("should use correct options", function(done){
this.request.callsArgWith(1);
it "should use correct options", (done)->
@request.callsArgWith(1)
return this.S3PersistorManager.deleteFile(this.bucketName, this.key, err=> {
const opts = this.request.args[0][0];
assert.deepEqual(opts.aws, {key:this.settings.filestore.s3.key, secret:this.settings.filestore.s3.secret, bucket:this.bucketName});
opts.method.should.equal("delete");
opts.timeout.should.equal((30*1000));
opts.uri.should.equal(`https://${this.bucketName}.s3.amazonaws.com/${this.key}`);
return done();
});
});
@S3PersistorManager.deleteFile @bucketName, @key, (err)=>
opts = @request.args[0][0]
assert.deepEqual(opts.aws, {key:@settings.filestore.s3.key, secret:@settings.filestore.s3.secret, bucket:@bucketName})
opts.method.should.equal "delete"
opts.timeout.should.equal (30*1000)
opts.uri.should.equal "https://#{@bucketName}.s3.amazonaws.com/#{@key}"
done()
return it("should return the error", function(done){
this.request.callsArgWith(1, this.error);
it "should return the error", (done)->
@request.callsArgWith(1, @error)
return this.S3PersistorManager.deleteFile(this.bucketName, this.key, err=> {
err.should.equal(this.error);
return done();
});
});
});
@S3PersistorManager.deleteFile @bucketName, @key, (err)=>
err.should.equal @error
done()
describe("checkIfFileExists", function() {
describe "checkIfFileExists", ->
it("should use correct options", function(done){
this.request.callsArgWith(1, null, {statusCode:200});
it "should use correct options", (done)->
@request.callsArgWith(1, null, statusCode:200)
return this.S3PersistorManager.checkIfFileExists(this.bucketName, this.key, err=> {
const opts = this.request.args[0][0];
assert.deepEqual(opts.aws, {key:this.settings.filestore.s3.key, secret:this.settings.filestore.s3.secret, bucket:this.bucketName});
opts.method.should.equal("head");
opts.timeout.should.equal((30*1000));
opts.uri.should.equal(`https://${this.bucketName}.s3.amazonaws.com/${this.key}`);
return done();
});
});
@S3PersistorManager.checkIfFileExists @bucketName, @key, (err)=>
opts = @request.args[0][0]
assert.deepEqual(opts.aws, {key:@settings.filestore.s3.key, secret:@settings.filestore.s3.secret, bucket:@bucketName})
opts.method.should.equal "head"
opts.timeout.should.equal (30*1000)
opts.uri.should.equal "https://#{@bucketName}.s3.amazonaws.com/#{@key}"
done()
it("should return true for a 200", function(done){
this.request.callsArgWith(1, null, {statusCode:200});
it "should return true for a 200", (done)->
@request.callsArgWith(1, null, statusCode:200)
return this.S3PersistorManager.checkIfFileExists(this.bucketName, this.key, (err, exists)=> {
exists.should.equal(true);
return done();
});
});
@S3PersistorManager.checkIfFileExists @bucketName, @key, (err, exists)=>
exists.should.equal true
done()
it("should return false for a non 200", function(done){
this.request.callsArgWith(1, null, {statusCode:404});
it "should return false for a non 200", (done)->
@request.callsArgWith(1, null, statusCode:404)
return this.S3PersistorManager.checkIfFileExists(this.bucketName, this.key, (err, exists)=> {
exists.should.equal(false);
return done();
});
});
@S3PersistorManager.checkIfFileExists @bucketName, @key, (err, exists)=>
exists.should.equal false
done()
return it("should return the error", function(done){
this.request.callsArgWith(1, this.error, {});
it "should return the error", (done)->
@request.callsArgWith(1, @error, {})
return this.S3PersistorManager.checkIfFileExists(this.bucketName, this.key, err=> {
err.should.equal(this.error);
return done();
});
});
});
@S3PersistorManager.checkIfFileExists @bucketName, @key, (err)=>
err.should.equal @error
done()
describe "directorySize", ->
it "should sum directory files size", (done) ->
data =
Contents: [ {Size: 1024}, {Size: 2048} ]
@knoxClient.list.callsArgWith(1, null, data)
@S3PersistorManager.directorySize @bucketName, @key, (err, totalSize)=>
totalSize.should.equal 3072
done()
return describe("directorySize", () => it("should sum directory files size", function(done) {
const data =
{Contents: [ {Size: 1024}, {Size: 2048} ]};
this.knoxClient.list.callsArgWith(1, null, data);
return this.S3PersistorManager.directorySize(this.bucketName, this.key, (err, totalSize)=> {
totalSize.should.equal(3072);
return done();
});
}));
});

View file

@ -1,50 +1,75 @@
assert = require("chai").assert
sinon = require('sinon')
chai = require('chai')
should = chai.should()
expect = chai.expect
modulePath = "../../../app/js/SafeExec.js"
SandboxedModule = require('sandboxed-module')
/*
* decaffeinate suggestions:
* 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/SafeExec.js";
const SandboxedModule = require('sandboxed-module');
describe "SafeExec", ->
describe("SafeExec", function() {
beforeEach ->
@settings =
enableConversions:true
@safe_exec = SandboxedModule.require modulePath, requires:
"logger-sharelatex":
log:->
err:->
"settings-sharelatex": @settings
@options = {timeout: 10*1000, killSignal: "SIGTERM" }
beforeEach(function() {
this.settings =
{enableConversions:true};
this.safe_exec = SandboxedModule.require(modulePath, { requires: {
"logger-sharelatex": {
log() {},
err() {}
},
"settings-sharelatex": this.settings
}
}
);
return this.options = {timeout: 10*1000, killSignal: "SIGTERM" };});
describe "safe_exec", ->
return describe("safe_exec", function() {
it "should execute a valid command", (done) ->
@safe_exec ["/bin/echo", "hello"], @options, (err, stdout, stderr) =>
stdout.should.equal "hello\n"
should.not.exist(err)
done()
it("should execute a valid command", function(done) {
return this.safe_exec(["/bin/echo", "hello"], this.options, (err, stdout, stderr) => {
stdout.should.equal("hello\n");
should.not.exist(err);
return done();
});
});
it "should error when conversions are disabled", (done) ->
@settings.enableConversions = false
@safe_exec ["/bin/echo", "hello"], @options, (err, stdout, stderr) =>
expect(err).to.exist
done()
it("should error when conversions are disabled", function(done) {
this.settings.enableConversions = false;
return this.safe_exec(["/bin/echo", "hello"], this.options, (err, stdout, stderr) => {
expect(err).to.exist;
return done();
});
});
it "should execute a command with non-zero exit status", (done) ->
@safe_exec ["/usr/bin/env", "false"], @options, (err, stdout, stderr) =>
stdout.should.equal ""
stderr.should.equal ""
err.message.should.equal "exit status 1"
done()
it("should execute a command with non-zero exit status", function(done) {
return this.safe_exec(["/usr/bin/env", "false"], this.options, (err, stdout, stderr) => {
stdout.should.equal("");
stderr.should.equal("");
err.message.should.equal("exit status 1");
return done();
});
});
it "should handle an invalid command", (done) ->
@safe_exec ["/bin/foobar"], @options, (err, stdout, stderr) =>
err.code.should.equal "ENOENT"
done()
it("should handle an invalid command", function(done) {
return this.safe_exec(["/bin/foobar"], this.options, (err, stdout, stderr) => {
err.code.should.equal("ENOENT");
return done();
});
});
it "should handle a command that runs too long", (done) ->
@safe_exec ["/bin/sleep", "10"], {timeout: 500, killSignal: "SIGTERM"}, (err, stdout, stderr) =>
err.should.equal "SIGTERM"
done()
return it("should handle a command that runs too long", function(done) {
return this.safe_exec(["/bin/sleep", "10"], {timeout: 500, killSignal: "SIGTERM"}, (err, stdout, stderr) => {
err.should.equal("SIGTERM");
return done();
});
});
});
});

View file

@ -1,19 +1,29 @@
assert = require("chai").assert
sinon = require('sinon')
chai = require('chai')
should = chai.should()
expect = chai.expect
modulePath = "../../../app/js/BucketController.js"
/*
* decaffeinate suggestions:
* 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/BucketController.js";
describe "Settings", ->
describe "s3", ->
it "should use JSONified env var if present", (done)->
s3_settings =
bucket1:
auth_key: 'bucket1_key'
auth_secret: 'bucket1_secret'
process.env['S3_BUCKET_CREDENTIALS'] = JSON.stringify s3_settings
describe("Settings", () => describe("s3", () => it("should use JSONified env var if present", function(done){
const s3_settings = {
bucket1: {
auth_key: 'bucket1_key',
auth_secret: 'bucket1_secret'
}
};
process.env['S3_BUCKET_CREDENTIALS'] = JSON.stringify(s3_settings);
settings = require("settings-sharelatex")
expect(settings.filestore.s3BucketCreds).to.deep.equal s3_settings
done()
const settings = require("settings-sharelatex");
expect(settings.filestore.s3BucketCreds).to.deep.equal(s3_settings);
return done();
})));