diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 0b430b2f3..a4afdbffd 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1425,6 +1425,32 @@ "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz", "dev": true }, + "fs-extra": { + "version": "0.6.4", + "from": "fs-extra@0.6.4", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.6.4.tgz", + "dev": true, + "dependencies": { + "mkdirp": { + "version": "0.3.5", + "from": "mkdirp@>=0.3.0 <0.4.0", + "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", + "dev": true + }, + "ncp": { + "version": "0.4.2", + "from": "ncp@>=0.4.2 <0.5.0", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz", + "dev": true + }, + "rimraf": { + "version": "2.2.8", + "from": "rimraf@>=2.2.0 <2.3.0", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", + "dev": true + } + } + }, "fs.realpath": { "version": "1.0.0", "from": "fs.realpath@>=1.0.0 <2.0.0", @@ -2334,6 +2360,12 @@ "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", "dev": true }, + "jsonfile": { + "version": "1.0.1", + "from": "jsonfile@>=1.0.1 <1.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-1.0.1.tgz", + "dev": true + }, "jsonify": { "version": "0.0.0", "from": "jsonify@>=0.0.0 <0.1.0", @@ -2770,6 +2802,12 @@ } } }, + "mock-aws-s3": { + "version": "2.4.0", + "from": "mock-aws-s3@latest", + "resolved": "https://registry.npmjs.org/mock-aws-s3/-/mock-aws-s3-2.4.0.tgz", + "dev": true + }, "moment": { "version": "2.18.1", "from": "moment@>=2.9.0", diff --git a/package.json b/package.json index 7427bdd38..72ad20064 100644 --- a/package.json +++ b/package.json @@ -87,6 +87,7 @@ "istanbul": "*", "js2xmlparser": "^1.0.0", "mocha": "*", + "mock-aws-s3": "^2.4.0", "nock": "^9.0.2", "node-sass": "^3.0.0-alpha.0", "readdirp": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", diff --git a/src/storage/s3.js b/src/storage/s3.js index 7fa884fb7..31b09fabe 100644 --- a/src/storage/s3.js +++ b/src/storage/s3.js @@ -10,7 +10,11 @@ exports = module.exports = { backupDone: backupDone, - testConfig: testConfig + testConfig: testConfig, + + // Used to mock AWS + _mockInject: mockInject, + _mockRestore: mockRestore }; var archiver = require('archiver'), @@ -29,6 +33,17 @@ var archiver = require('archiver'), var FILE_TYPE = '.tar.gz'; +// test only +var originalAWS; +function mockInject(mock) { + originalAWS = AWS; + AWS = mock; +} + +function mockRestore() { + AWS = originalAWS; +} + // internal only function getBackupCredentials(apiConfig, callback) { assert.strictEqual(typeof apiConfig, 'object'); @@ -159,7 +174,8 @@ function restore(apiConfig, backupId, destinationDirectories, callback) { }); s3get.on('error', function (error) { - if (error.code === 'NoSuchKey') return callback(new BackupsError(BackupsError.NOT_FOUND)); + // TODO ENOENT for the mock, fix upstream! + if (error.code === 'NoSuchKey' || error.code === 'ENOENT') return callback(new BackupsError(BackupsError.NOT_FOUND)); console.error('[%s] restore: s3 stream error.', backupId, error); callback(new BackupsError(BackupsError.EXTERNAL_ERROR, error)); @@ -269,7 +285,8 @@ function getDownloadStream(apiConfig, backupId, callback) { var s3 = new AWS.S3(credentials); s3.headObject(params, function (error, result) { - if (error && error.code === 'NotFound') return callback(new BackupsError(BackupsError.NOT_FOUND)); + // TODO ENOENT for the mock, fix upstream! + if (error && (error.code === 'NotFound' || error.code === 'ENOENT')) return callback(new BackupsError(BackupsError.NOT_FOUND)); if (error) return callback(new BackupsError(BackupsError.EXTERNAL_ERROR, error)); var s3get = s3.getObject(params).createReadStream(); diff --git a/src/test/storage-test.js b/src/test/storage-test.js index e4e05d232..d1597ef68 100644 --- a/src/test/storage-test.js +++ b/src/test/storage-test.js @@ -10,7 +10,9 @@ var async = require('async'), os = require('os'), path = require('path'), readdirp = require('readdirp'), + MockS3 = require('mock-aws-s3'), rimraf = require('rimraf'), + mkdirp = require('mkdirp'), BackupsError = require('../backups.js').BackupsError, config = require('../config.js'), database = require('../database.js'), @@ -236,12 +238,16 @@ describe('Storage', function () { key: 'key', prefix: 'unit.test', bucket: 'cloudron-storage-test', - accessKeyId: '', - secretAccessKey: '', + accessKeyId: 'testkeyid', + secretAccessKey: 'testsecret', region: 'eu-central-1' }; before(function (done) { + MockS3.config.basePath = path.join(os.tmpdir(), 's3-backup-test-buckets/'); + + s3._mockInject(MockS3); + setup(function (error) { expect(error).to.be(null); @@ -258,6 +264,9 @@ describe('Storage', function () { }); after(function (done) { + s3._mockRestore(); + rimraf.sync(MockS3.config.basePath); + cleanup(function (error) { expect(error).to.be(null); rimraf(gTmpFolder, done);