Ghost/test/unit/server/adapters/storage/LocalFileStorage.test.js
Hannah Wolfe 9e96b04542
Moved server unit tests into the server folder
- this is a small part of a bit of cleanup of our test files
- the goal is to make the existing tests clearer with a view to making it easier to write more tests
- this makes the test structure follow the codebase structure more closely
- eventually we will colocate the tests as we break the codebase down further
2021-10-06 12:01:09 +01:00

255 lines
9.1 KiB
JavaScript

const errors = require('@tryghost/errors');
const should = require('should');
const sinon = require('sinon');
const fs = require('fs-extra');
const moment = require('moment');
const Promise = require('bluebird');
const path = require('path');
const LocalFileStore = require('../../../../../core/server/adapters/storage/LocalFileStorage');
let localFileStore;
const configUtils = require('../../../../utils/configUtils');
describe('Local File System Storage', function () {
let image;
let momentStub;
function fakeDate(mm, yyyy) {
const month = parseInt(mm, 10);
const year = parseInt(yyyy, 10);
momentStub.withArgs('YYYY').returns(year.toString());
momentStub.withArgs('MM').returns(month < 10 ? '0' + month.toString() : month.toString());
}
beforeEach(function () {
// Fake a date, do this once for all tests in this file
momentStub = sinon.stub(moment.fn, 'format');
});
afterEach(function () {
sinon.restore();
configUtils.restore();
});
beforeEach(function () {
sinon.stub(fs, 'mkdirs').resolves();
sinon.stub(fs, 'copy').resolves();
sinon.stub(fs, 'stat').rejects();
sinon.stub(fs, 'unlink').resolves();
image = {
path: 'tmp/123456.jpg',
name: 'IMAGE.jpg',
type: 'image/jpeg'
};
localFileStore = new LocalFileStore();
fakeDate(9, 2013);
});
it('should send correct path to image when date is in Sep 2013', function (done) {
localFileStore.save(image).then(function (url) {
url.should.equal('/content/images/2013/09/IMAGE.jpg');
done();
}).catch(done);
});
it('should send correct path to image when original file has spaces', function (done) {
image.name = 'AN IMAGE.jpg';
localFileStore.save(image).then(function (url) {
url.should.equal('/content/images/2013/09/AN-IMAGE.jpg');
done();
}).catch(done);
});
it('should allow "@" symbol to image for Apple hi-res (retina) modifier', function (done) {
image.name = 'photo@2x.jpg';
localFileStore.save(image).then(function (url) {
url.should.equal('/content/images/2013/09/photo@2x.jpg');
done();
}).catch(done);
});
it('should send correct path to image when date is in Jan 2014', function (done) {
fakeDate(1, 2014);
localFileStore.save(image).then(function (url) {
url.should.equal('/content/images/2014/01/IMAGE.jpg');
done();
}).catch(done);
});
it('should create month and year directory', function (done) {
localFileStore.save(image).then(function () {
fs.mkdirs.calledOnce.should.be.true();
fs.mkdirs.args[0][0].should.equal(path.resolve('./content/images/2013/09'));
done();
}).catch(done);
});
it('should copy temp file to new location', function (done) {
localFileStore.save(image).then(function () {
fs.copy.calledOnce.should.be.true();
fs.copy.args[0][0].should.equal('tmp/123456.jpg');
fs.copy.args[0][1].should.equal(path.resolve('./content/images/2013/09/IMAGE.jpg'));
done();
}).catch(done);
});
it('can upload two different images with the same name without overwriting the first', function (done) {
fs.stat.withArgs(path.resolve('./content/images/2013/09/IMAGE.jpg')).resolves();
fs.stat.withArgs(path.resolve('./content/images/2013/09/IMAGE-1.jpg')).rejects();
// if on windows need to setup with back slashes
// doesn't hurt for the test to cope with both
fs.stat.withArgs(path.resolve('.\\content\\images\\2013\\Sep\\IMAGE.jpg')).resolves();
fs.stat.withArgs(path.resolve('.\\content\\images\\2013\\Sep\\IMAGE-1.jpg')).rejects();
localFileStore.save(image).then(function (url) {
url.should.equal('/content/images/2013/09/IMAGE-1.jpg');
done();
}).catch(done);
});
it('can upload five different images with the same name without overwriting the first', function (done) {
fs.stat.withArgs(path.resolve('./content/images/2013/09/IMAGE.jpg')).resolves();
fs.stat.withArgs(path.resolve('./content/images/2013/09/IMAGE-1.jpg')).resolves();
fs.stat.withArgs(path.resolve('./content/images/2013/09/IMAGE-2.jpg')).resolves();
fs.stat.withArgs(path.resolve('./content/images/2013/09/IMAGE-3.jpg')).resolves();
fs.stat.withArgs(path.resolve('./content/images/2013/09/IMAGE-4.jpg')).rejects();
// windows setup
fs.stat.withArgs(path.resolve('.\\content\\images\\2013\\Sep\\IMAGE.jpg')).resolves();
fs.stat.withArgs(path.resolve('.\\content\\images\\2013\\Sep\\IMAGE-1.jpg')).resolves();
fs.stat.withArgs(path.resolve('.\\content\\images\\2013\\Sep\\IMAGE-2.jpg')).resolves();
fs.stat.withArgs(path.resolve('.\\content\\images\\2013\\Sep\\IMAGE-3.jpg')).resolves();
fs.stat.withArgs(path.resolve('.\\content\\images\\2013\\Sep\\IMAGE-4.jpg')).rejects();
localFileStore.save(image).then(function (url) {
url.should.equal('/content/images/2013/09/IMAGE-4.jpg');
done();
}).catch(done);
});
describe('read image', function () {
beforeEach(function () {
// we have some example images in our test utils folder
localFileStore.storagePath = path.join(__dirname, '../../../../utils/fixtures/images/');
});
it('success', function (done) {
localFileStore.read({path: 'ghost-logo.png'})
.then(function (bytes) {
bytes.length.should.eql(8638);
done();
});
});
it('success', function (done) {
localFileStore.read({path: '/ghost-logo.png/'})
.then(function (bytes) {
bytes.length.should.eql(8638);
done();
});
});
it('image does not exist', function (done) {
localFileStore.read({path: 'does-not-exist.png'})
.then(function () {
done(new Error('image should not exist'));
})
.catch(function (err) {
(err instanceof errors.NotFoundError).should.eql(true);
err.code.should.eql('ENOENT');
done();
});
});
});
describe('validate extentions', function () {
it('name contains a .\d as extension', function (done) {
localFileStore.save({
name: 'test-1.1.1'
}).then(function (url) {
should.exist(url.match(/test-1.1.1/));
done();
}).catch(done);
});
it('name contains a .zip as extension', function (done) {
localFileStore.save({
name: 'test-1.1.1.zip'
}).then(function (url) {
should.exist(url.match(/test-1.1.1.zip/));
done();
}).catch(done);
});
it('name contains a .jpeg as extension', function (done) {
localFileStore.save({
name: 'test-1.1.1.jpeg'
}).then(function (url) {
should.exist(url.match(/test-1.1.1.jpeg/));
done();
}).catch(done);
});
});
describe('when a custom content path is used', function () {
beforeEach(function () {
const configPaths = configUtils.defaultConfig.paths;
configUtils.set('paths:contentPath', configPaths.appRoot + '/var/ghostcms');
});
it('should send the correct path to image', function (done) {
localFileStore.save(image).then(function (url) {
url.should.equal('/content/images/2013/09/IMAGE.jpg');
done();
}).catch(done);
});
});
// @TODO: remove path.join mock...
describe('on Windows', function () {
const truePathSep = path.sep;
beforeEach(function () {
sinon.stub(path, 'join');
sinon.stub(configUtils.config, 'getContentPath').returns('content/images/');
});
afterEach(function () {
path.sep = truePathSep;
});
it('should return url in proper format for windows', function (done) {
path.sep = '\\';
path.join.returns('content\\images\\2013\\09\\IMAGE.jpg');
localFileStore.save(image).then(function (url) {
if (truePathSep === '\\') {
url.should.equal('/content/images/2013/09/IMAGE.jpg');
} else {
// if this unit test is run on an OS that uses forward slash separators,
// localfilesystem.save() will use a path.relative() call on
// one path with backslash separators and one path with forward
// slashes and it returns a path that needs to be normalized
path.normalize(url).should.equal('/content/images/2013/09/IMAGE.jpg');
}
done();
}).catch(done);
});
});
});