mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-10 23:36:14 -05:00
refs https://github.com/TryGhost/Toolbox/issues/214 - The values configuration for the settings table need to become configurable to be able to run our test environment with a pre-defined set of configurations (e.g Stripe-related values). - This change makes it possible to define the default settings file location (currently a JSON) - A new key is now exposed through the "paths.defaultSettings" key in settings, which can be overloaded for the needs of the environment
206 lines
8.4 KiB
JavaScript
206 lines
8.4 KiB
JavaScript
const should = require('should');
|
|
const sinon = require('sinon');
|
|
const rewire = require('rewire');
|
|
const Promise = require('bluebird');
|
|
const errors = require('@tryghost/errors');
|
|
const db = require('../../../../../core/server/data/db');
|
|
const exporter = rewire('../../../../../core/server/data/exporter');
|
|
const schema = require('../../../../../core/server/data/schema');
|
|
const models = require('../../../../../core/server/models');
|
|
const schemaTables = Object.keys(schema.tables);
|
|
|
|
describe('Exporter', function () {
|
|
let tablesStub;
|
|
let queryMock;
|
|
let knexMock;
|
|
|
|
before(function () {
|
|
models.init();
|
|
});
|
|
|
|
afterEach(function () {
|
|
sinon.restore();
|
|
});
|
|
|
|
describe('doExport', function () {
|
|
beforeEach(function () {
|
|
tablesStub = sinon.stub(schema.commands, 'getTables').returns(schemaTables);
|
|
|
|
queryMock = {
|
|
whereNot: sinon.stub(),
|
|
select: sinon.stub()
|
|
};
|
|
|
|
knexMock = sinon.stub().returns(queryMock);
|
|
|
|
sinon.stub(db, 'knex').get(function () {
|
|
return knexMock;
|
|
});
|
|
});
|
|
|
|
it('should try to export all the correct tables (without excluded)', function (done) {
|
|
exporter.doExport().then(function (exportData) {
|
|
// NOTE: 10 default tables
|
|
const expectedCallCount = 10;
|
|
|
|
should.exist(exportData);
|
|
|
|
exportData.meta.version.should.match(/\d+.\d+.\d+/gi);
|
|
|
|
tablesStub.calledOnce.should.be.true();
|
|
db.knex.called.should.be.true();
|
|
|
|
knexMock.callCount.should.eql(expectedCallCount);
|
|
queryMock.select.callCount.should.have.eql(expectedCallCount);
|
|
|
|
knexMock.getCall(0).args[0].should.eql('posts');
|
|
knexMock.getCall(1).args[0].should.eql('posts_meta');
|
|
knexMock.getCall(2).args[0].should.eql('users');
|
|
knexMock.getCall(3).args[0].should.eql('posts_authors');
|
|
knexMock.getCall(4).args[0].should.eql('roles');
|
|
knexMock.getCall(5).args[0].should.eql('roles_users');
|
|
knexMock.getCall(6).args[0].should.eql('settings');
|
|
knexMock.getCall(7).args[0].should.eql('tags');
|
|
knexMock.getCall(8).args[0].should.eql('posts_tags');
|
|
knexMock.getCall(9).args[0].should.eql('custom_theme_settings');
|
|
|
|
done();
|
|
}).catch(done);
|
|
});
|
|
|
|
it('should try to export all the correct tables with extra tables', function (done) {
|
|
const include = ['mobiledoc_revisions', 'email_recipients'];
|
|
|
|
exporter.doExport({include}).then(function (exportData) {
|
|
// NOTE: 10 default tables + 2 includes
|
|
const expectedCallCount = 12;
|
|
|
|
should.exist(exportData);
|
|
|
|
exportData.meta.version.should.match(/\d+.\d+.\d+/gi);
|
|
|
|
tablesStub.calledOnce.should.be.true();
|
|
db.knex.called.should.be.true();
|
|
queryMock.select.called.should.be.true();
|
|
|
|
knexMock.callCount.should.eql(expectedCallCount);
|
|
queryMock.select.callCount.should.have.eql(expectedCallCount);
|
|
|
|
knexMock.getCall(0).args[0].should.eql('posts');
|
|
knexMock.getCall(1).args[0].should.eql('posts_meta');
|
|
knexMock.getCall(2).args[0].should.eql('users');
|
|
knexMock.getCall(3).args[0].should.eql('posts_authors');
|
|
knexMock.getCall(4).args[0].should.eql('roles');
|
|
knexMock.getCall(5).args[0].should.eql('roles_users');
|
|
knexMock.getCall(6).args[0].should.eql('settings');
|
|
knexMock.getCall(7).args[0].should.eql('tags');
|
|
knexMock.getCall(8).args[0].should.eql('posts_tags');
|
|
knexMock.getCall(9).args[0].should.eql('mobiledoc_revisions');
|
|
knexMock.getCall(10).args[0].should.eql('email_recipients');
|
|
knexMock.getCall(11).args[0].should.eql('custom_theme_settings');
|
|
|
|
done();
|
|
}).catch(done);
|
|
});
|
|
|
|
it('should catch and log any errors', function (done) {
|
|
// Setup for failure
|
|
queryMock.select.returns(Promise.reject({}));
|
|
|
|
// Execute
|
|
exporter.doExport()
|
|
.then(function () {
|
|
done(new Error('expected error for export'));
|
|
})
|
|
.catch(function (err) {
|
|
(err instanceof errors.DataExportError).should.eql(true);
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('exportFileName', function () {
|
|
it('should return a correctly structured filename', function (done) {
|
|
const settingsStub = sinon.stub(models.Settings, 'findOne').returns(
|
|
new Promise.resolve({
|
|
get: function () {
|
|
return 'testblog';
|
|
}
|
|
})
|
|
);
|
|
|
|
exporter.fileName().then(function (result) {
|
|
should.exist(result);
|
|
settingsStub.calledOnce.should.be.true();
|
|
result.should.match(/^testblog\.ghost\.[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{2}-[0-9]{2}-[0-9]{2}\.json$/);
|
|
|
|
done();
|
|
}).catch(done);
|
|
});
|
|
|
|
it('should return a correctly structured filename if settings is empty', function (done) {
|
|
const settingsStub = sinon.stub(models.Settings, 'findOne').returns(
|
|
new Promise.resolve()
|
|
);
|
|
|
|
exporter.fileName().then(function (result) {
|
|
should.exist(result);
|
|
settingsStub.calledOnce.should.be.true();
|
|
result.should.match(/^ghost\.[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{2}-[0-9]{2}-[0-9]{2}\.json$/);
|
|
|
|
done();
|
|
}).catch(done);
|
|
});
|
|
|
|
it('should return a correctly structured filename if settings errors', function (done) {
|
|
const settingsStub = sinon.stub(models.Settings, 'findOne').returns(
|
|
new Promise.reject()
|
|
);
|
|
|
|
exporter.fileName().then(function (result) {
|
|
should.exist(result);
|
|
settingsStub.calledOnce.should.be.true();
|
|
result.should.match(/^ghost\.[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{2}-[0-9]{2}-[0-9]{2}\.json$/);
|
|
|
|
done();
|
|
}).catch(done);
|
|
});
|
|
});
|
|
|
|
describe('Export table whitelists', function () {
|
|
it('should be fixed when db schema introduces new tables', function () {
|
|
const {
|
|
BACKUP_TABLES,
|
|
TABLES_ALLOWLIST
|
|
} = require('../../../../../core/server/data/exporter/table-lists.js');
|
|
|
|
const nonSchemaTables = ['migrations', 'migrations_lock'];
|
|
const requiredTables = schemaTables.concat(nonSchemaTables);
|
|
// NOTE: You should not add tables to this list unless they are temporary
|
|
const ignoredTables = ['temp_member_analytic_events'];
|
|
|
|
const expectedTables = requiredTables.filter(table => !ignoredTables.includes(table)).sort();
|
|
const actualTables = BACKUP_TABLES.concat(TABLES_ALLOWLIST).sort();
|
|
|
|
// NOTE: this test is serving a role of a reminder to have a look into exported tables allowlists
|
|
// if it failed you probably need to add or remove a table entry from table-lists module
|
|
should.deepEqual(actualTables, expectedTables);
|
|
});
|
|
|
|
it('should be fixed when default settings is changed', function () {
|
|
const {
|
|
SETTING_KEYS_BLOCKLIST
|
|
} = require('../../../../../core/server/data/exporter/table-lists.js');
|
|
const defaultSettings = require('../../../../../core/server/data/schema/default-settings/default-settings.json');
|
|
|
|
const totalKeysLength = Object.keys(defaultSettings).reduce((acc, curr, index) => {
|
|
return acc + Object.keys(defaultSettings[curr]).length;
|
|
}, 0);
|
|
|
|
// NOTE: if default settings changed either modify the settings keys blocklist or increase allowedKeysLength
|
|
// This is a reminder to think about the importer/exporter scenarios ;)
|
|
const allowedKeysLength = 85;
|
|
totalKeysLength.should.eql(SETTING_KEYS_BLOCKLIST.length + allowedKeysLength);
|
|
});
|
|
});
|
|
});
|