mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-06 22:40:14 -05:00
Merge pull request #3866 from hswolff/config-updates
Move config module to be instance based and merge bootstrap into config.
This commit is contained in:
commit
1ed286d09e
14 changed files with 629 additions and 596 deletions
|
@ -637,9 +637,9 @@ var path = require('path'),
|
|||
// Ghost requires a `config.js` file to specify the database settings etc. Ghost comes with an example file:
|
||||
// `config.example.js` which is copied and renamed to `config.js` by the bootstrap process
|
||||
grunt.registerTask('ensureConfig', function () {
|
||||
var bootstrap = require('./core/bootstrap'),
|
||||
var config = require('./core/server/config'),
|
||||
done = this.async();
|
||||
bootstrap().then(function () {
|
||||
config.load().then(function () {
|
||||
done();
|
||||
}).catch(function (err) {
|
||||
grunt.fail.fatal(err.stack);
|
||||
|
|
140
core/bootstrap.js
vendored
140
core/bootstrap.js
vendored
|
@ -1,140 +0,0 @@
|
|||
// This file manages the root level config.js.
|
||||
// It will create config.js from config.exampe.js
|
||||
// if it doesn't exist and then always attempt to load
|
||||
// config.js into memory, error and quitting if config.js
|
||||
// has an improper format.
|
||||
|
||||
var fs = require('fs'),
|
||||
url = require('url'),
|
||||
Promise = require('bluebird'),
|
||||
validator = require('validator'),
|
||||
errors = require('./server/errors'),
|
||||
config = require('./server/config'),
|
||||
|
||||
appRoot = config.paths.appRoot,
|
||||
configExample = config.paths.configExample,
|
||||
configFile;
|
||||
|
||||
function readConfigFile(envVal) {
|
||||
return require(configFile)[envVal];
|
||||
}
|
||||
|
||||
function writeConfigFile() {
|
||||
/* Check for config file and copy from config.example.js
|
||||
if one doesn't exist. After that, start the server. */
|
||||
return new Promise(function (resolve, reject) {
|
||||
fs.exists(configExample, function checkTemplate(templateExists) {
|
||||
var read,
|
||||
write,
|
||||
error;
|
||||
|
||||
if (!templateExists) {
|
||||
error = new Error('Could not locate a configuration file.');
|
||||
error.context = appRoot;
|
||||
error.help = 'Please check your deployment for config.js or config.example.js.';
|
||||
|
||||
return reject(error);
|
||||
}
|
||||
|
||||
// Copy config.example.js => config.js
|
||||
read = fs.createReadStream(configExample);
|
||||
read.on('error', function (err) {
|
||||
errors.logError(new Error('Could not open config.example.js for read.'), appRoot, 'Please check your deployment for config.js or config.example.js.');
|
||||
|
||||
reject(err);
|
||||
});
|
||||
|
||||
write = fs.createWriteStream(configFile);
|
||||
write.on('error', function (err) {
|
||||
errors.logError(new Error('Could not open config.js for write.'), appRoot, 'Please check your deployment for config.js or config.example.js.');
|
||||
|
||||
reject(err);
|
||||
});
|
||||
|
||||
write.on('finish', resolve);
|
||||
|
||||
read.pipe(write);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function validateConfigEnvironment() {
|
||||
var envVal = process.env.NODE_ENV || undefined,
|
||||
hasHostAndPort,
|
||||
hasSocket,
|
||||
config,
|
||||
parsedUrl;
|
||||
|
||||
try {
|
||||
config = readConfigFile(envVal);
|
||||
}
|
||||
catch (e) {
|
||||
return Promise.reject(e);
|
||||
}
|
||||
|
||||
// Check if we don't even have a config
|
||||
if (!config) {
|
||||
errors.logError(new Error('Cannot find the configuration for the current NODE_ENV'), 'NODE_ENV=' + envVal,
|
||||
'Ensure your config.js has a section for the current NODE_ENV value and is formatted properly.');
|
||||
|
||||
return Promise.reject(new Error('Unable to load config for NODE_ENV=' + envVal));
|
||||
}
|
||||
|
||||
// Check that our url is valid
|
||||
if (!validator.isURL(config.url, { protocols: ['http', 'https'], require_protocol: true })) {
|
||||
errors.logError(new Error('Your site url in config.js is invalid.'), config.url, 'Please make sure this is a valid url before restarting');
|
||||
|
||||
return Promise.reject(new Error('invalid site url'));
|
||||
}
|
||||
|
||||
parsedUrl = url.parse(config.url || 'invalid', false, true);
|
||||
|
||||
if (/\/ghost(\/|$)/.test(parsedUrl.pathname)) {
|
||||
errors.logError(new Error('Your site url in config.js cannot contain a subdirectory called ghost.'), config.url, 'Please rename the subdirectory before restarting');
|
||||
|
||||
return Promise.reject(new Error('ghost subdirectory not allowed'));
|
||||
}
|
||||
|
||||
// Check that we have database values
|
||||
if (!config.database || !config.database.client) {
|
||||
errors.logError(new Error('Your database configuration in config.js is invalid.'), JSON.stringify(config.database), 'Please make sure this is a valid Bookshelf database configuration');
|
||||
|
||||
return Promise.reject(new Error('invalid database configuration'));
|
||||
}
|
||||
|
||||
hasHostAndPort = config.server && !!config.server.host && !!config.server.port;
|
||||
hasSocket = config.server && !!config.server.socket;
|
||||
|
||||
// Check for valid server host and port values
|
||||
if (!config.server || !(hasHostAndPort || hasSocket)) {
|
||||
errors.logError(new Error('Your server values (socket, or host and port) in config.js are invalid.'), JSON.stringify(config.server), 'Please provide them before restarting.');
|
||||
|
||||
return Promise.reject(new Error('invalid server configuration'));
|
||||
}
|
||||
|
||||
return Promise.resolve(config);
|
||||
}
|
||||
|
||||
function loadConfig(configFilePath) {
|
||||
configFile = process.env.GHOST_CONFIG || configFilePath || config.paths.config;
|
||||
|
||||
/* Check for config file and copy from config.example.js
|
||||
if one doesn't exist. After that, start the server. */
|
||||
return new Promise(function (resolve, reject) {
|
||||
fs.exists(configFile, function (exists) {
|
||||
var pendingConfig;
|
||||
|
||||
if (!exists) {
|
||||
pendingConfig = writeConfigFile();
|
||||
}
|
||||
|
||||
Promise.resolve(pendingConfig)
|
||||
.then(validateConfigEnvironment)
|
||||
.then(function (rawConfig) {
|
||||
resolve(config.init(rawConfig));
|
||||
}).catch(reject);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = loadConfig;
|
|
@ -2,17 +2,14 @@
|
|||
// Orchestrates the loading of Ghost
|
||||
// When run from command line.
|
||||
|
||||
var bootstrap = require('./bootstrap'),
|
||||
server = require('./server');
|
||||
var server = require('./server');
|
||||
|
||||
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
|
||||
|
||||
function makeGhost(options) {
|
||||
options = options || {};
|
||||
|
||||
return bootstrap(options.config).then(function () {
|
||||
return server(options.app);
|
||||
});
|
||||
return server(options);
|
||||
}
|
||||
|
||||
module.exports = makeGhost;
|
||||
|
|
|
@ -5,44 +5,90 @@
|
|||
|
||||
var path = require('path'),
|
||||
Promise = require('bluebird'),
|
||||
fs = require('fs'),
|
||||
url = require('url'),
|
||||
_ = require('lodash'),
|
||||
knex = require('knex'),
|
||||
validator = require('validator'),
|
||||
requireTree = require('../require-tree').readAll,
|
||||
errors = require('../errors'),
|
||||
theme = require('./theme'),
|
||||
configUrl = require('./url'),
|
||||
ghostConfig = {},
|
||||
appRoot = path.resolve(__dirname, '../../../'),
|
||||
corePath = path.resolve(appRoot, 'core/'),
|
||||
testingEnvs = ['testing', 'testing-mysql', 'testing-pg'],
|
||||
defaultConfig = {},
|
||||
knexInstance;
|
||||
|
||||
// Are we using sockets? Custom socket or the default?
|
||||
function getSocket() {
|
||||
if (ghostConfig.server.hasOwnProperty('socket')) {
|
||||
return _.isString(ghostConfig.server.socket) ? ghostConfig.server.socket : path.join(ghostConfig.paths.contentPath, process.env.NODE_ENV + '.socket');
|
||||
|
||||
function ConfigManager(config) {
|
||||
/**
|
||||
* Our internal true representation of our current config object.
|
||||
* @private
|
||||
* @type {Object}
|
||||
*/
|
||||
this._config = {};
|
||||
|
||||
// Allow other modules to be externally accessible.
|
||||
this.theme = theme;
|
||||
this.urlFor = configUrl.urlFor;
|
||||
this.urlForPost = configUrl.urlForPost;
|
||||
|
||||
// If we're given an initial config object then we can set it.
|
||||
if (config && _.isObject(config)) {
|
||||
this.set(config);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function updateConfig(config) {
|
||||
// Are we using sockets? Custom socket or the default?
|
||||
ConfigManager.prototype.getSocket = function () {
|
||||
if (this._config.server.hasOwnProperty('socket')) {
|
||||
return _.isString(this._config.server.socket) ?
|
||||
this._config.server.socket :
|
||||
path.join(this._config.paths.contentPath, process.env.NODE_ENV + '.socket');
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
ConfigManager.prototype.init = function (rawConfig) {
|
||||
var self = this;
|
||||
|
||||
// Cache the config.js object's environment
|
||||
// object so we can later refer to it.
|
||||
// Note: this is not the entirety of config.js,
|
||||
// just the object appropriate for this NODE_ENV
|
||||
self.set(rawConfig);
|
||||
|
||||
return Promise.all([requireTree(self._config.paths.themePath), requireTree(self._config.paths.appPath)]).then(function (paths) {
|
||||
self._config.paths.availableThemes = paths[0];
|
||||
self._config.paths.availableApps = paths[1];
|
||||
return self._config;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Allows you to set the config object.
|
||||
* @param {Object} config Only accepts an object at the moment.
|
||||
*/
|
||||
ConfigManager.prototype.set = function (config) {
|
||||
var localPath = '',
|
||||
contentPath,
|
||||
subdir;
|
||||
|
||||
// Merge passed in config object onto
|
||||
// the cached ghostConfig object
|
||||
_.merge(ghostConfig, config);
|
||||
// Merge passed in config object onto our existing config object.
|
||||
// We're using merge here as it doesn't assign `undefined` properties
|
||||
// onto our cached config object. This allows us to only update our
|
||||
// local copy with properties that have been explicitly set.
|
||||
_.merge(this._config, config);
|
||||
|
||||
// Protect against accessing a non-existant object.
|
||||
// This ensures there's always at least a paths object
|
||||
// because it's referenced in multiple places.
|
||||
ghostConfig.paths = ghostConfig.paths || {};
|
||||
this._config.paths = this._config.paths || {};
|
||||
|
||||
// Parse local path location
|
||||
if (ghostConfig.url) {
|
||||
localPath = url.parse(ghostConfig.url).path;
|
||||
if (this._config.url) {
|
||||
localPath = url.parse(this._config.url).path;
|
||||
// Remove trailing slash
|
||||
if (localPath !== '/') {
|
||||
localPath = localPath.replace(/\/$/, '');
|
||||
|
@ -53,20 +99,20 @@ function updateConfig(config) {
|
|||
|
||||
// Allow contentPath to be over-written by passed in config object
|
||||
// Otherwise default to default content path location
|
||||
contentPath = ghostConfig.paths.contentPath || path.resolve(appRoot, 'content');
|
||||
contentPath = this._config.paths.contentPath || path.resolve(appRoot, 'content');
|
||||
|
||||
if (!knexInstance && ghostConfig.database && ghostConfig.database.client) {
|
||||
knexInstance = knex(ghostConfig.database);
|
||||
if (!knexInstance && this._config.database && this._config.database.client) {
|
||||
knexInstance = knex(this._config.database);
|
||||
}
|
||||
|
||||
_.merge(ghostConfig, {
|
||||
_.merge(this._config, {
|
||||
database: {
|
||||
knex: knexInstance
|
||||
},
|
||||
paths: {
|
||||
'appRoot': appRoot,
|
||||
'subdir': subdir,
|
||||
'config': ghostConfig.paths.config || path.join(appRoot, 'config.js'),
|
||||
'config': this._config.paths.config || path.join(appRoot, 'config.js'),
|
||||
'configExample': path.join(appRoot, 'config.example.js'),
|
||||
'corePath': corePath,
|
||||
|
||||
|
@ -82,8 +128,8 @@ function updateConfig(config) {
|
|||
'lang': path.join(corePath, '/shared/lang/'),
|
||||
'debugPath': subdir + '/ghost/debug/',
|
||||
|
||||
'availableThemes': ghostConfig.paths.availableThemes || {},
|
||||
'availableApps': ghostConfig.paths.availableApps || {},
|
||||
'availableThemes': this._config.paths.availableThemes || {},
|
||||
'availableApps': this._config.paths.availableApps || {},
|
||||
'builtScriptPath': path.join(corePath, 'built/scripts/')
|
||||
}
|
||||
});
|
||||
|
@ -91,33 +137,161 @@ function updateConfig(config) {
|
|||
// Also pass config object to
|
||||
// configUrl object to maintain
|
||||
// clean depedency tree
|
||||
configUrl.setConfig(ghostConfig);
|
||||
}
|
||||
configUrl.setConfig(this._config);
|
||||
|
||||
function initConfig(rawConfig) {
|
||||
// Cache the config.js object's environment
|
||||
// object so we can later refer to it.
|
||||
// Note: this is not the entirety of config.js,
|
||||
// just the object appropriate for this NODE_ENV
|
||||
updateConfig(rawConfig);
|
||||
// For now we're going to copy the current state of this._config
|
||||
// so it's directly accessible on the instance.
|
||||
// @TODO: perhaps not do this? Put access of the config object behind
|
||||
// a function?
|
||||
_.extend(this, this._config);
|
||||
};
|
||||
|
||||
return Promise.all([requireTree(ghostConfig.paths.themePath), requireTree(ghostConfig.paths.appPath)]).then(function (paths) {
|
||||
ghostConfig.paths.availableThemes = paths[0];
|
||||
ghostConfig.paths.availableApps = paths[1];
|
||||
return ghostConfig;
|
||||
/**
|
||||
* Allows you to read the config object.
|
||||
* @return {Object} The config object.
|
||||
*/
|
||||
ConfigManager.prototype.get = function () {
|
||||
return this._config;
|
||||
};
|
||||
|
||||
ConfigManager.prototype.load = function (configFilePath) {
|
||||
var self = this;
|
||||
|
||||
self._config.paths.config = process.env.GHOST_CONFIG || configFilePath || self._config.paths.config;
|
||||
|
||||
/* Check for config file and copy from config.example.js
|
||||
if one doesn't exist. After that, start the server. */
|
||||
return new Promise(function (resolve, reject) {
|
||||
fs.exists(self._config.paths.config, function (exists) {
|
||||
var pendingConfig;
|
||||
|
||||
if (!exists) {
|
||||
pendingConfig = self.writeFile();
|
||||
}
|
||||
|
||||
Promise.resolve(pendingConfig).then(function () {
|
||||
return self.validate();
|
||||
}).then(function (rawConfig) {
|
||||
resolve(self.init(rawConfig));
|
||||
}).catch(reject);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/* Check for config file and copy from config.example.js
|
||||
if one doesn't exist. After that, start the server. */
|
||||
ConfigManager.prototype.writeFile = function () {
|
||||
var configPath = this._config.paths.config,
|
||||
configExamplePath = this._config.paths.configExample;
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
fs.exists(configExamplePath, function checkTemplate(templateExists) {
|
||||
var read,
|
||||
write,
|
||||
error;
|
||||
|
||||
if (!templateExists) {
|
||||
error = new Error('Could not locate a configuration file.');
|
||||
error.context = appRoot;
|
||||
error.help = 'Please check your deployment for config.js or config.example.js.';
|
||||
|
||||
return reject(error);
|
||||
}
|
||||
|
||||
// Copy config.example.js => config.js
|
||||
read = fs.createReadStream(configExamplePath);
|
||||
read.on('error', function (err) {
|
||||
errors.logError(new Error('Could not open config.example.js for read.'), appRoot, 'Please check your deployment for config.js or config.example.js.');
|
||||
|
||||
reject(err);
|
||||
});
|
||||
|
||||
write = fs.createWriteStream(configPath);
|
||||
write.on('error', function (err) {
|
||||
errors.logError(new Error('Could not open config.js for write.'), appRoot, 'Please check your deployment for config.js or config.example.js.');
|
||||
|
||||
reject(err);
|
||||
});
|
||||
|
||||
write.on('finish', resolve);
|
||||
|
||||
read.pipe(write);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Read config.js file from file system using node's require
|
||||
* @param {String} envVal Which environment we're in.
|
||||
* @return {Object} The config object.
|
||||
*/
|
||||
ConfigManager.prototype.readFile = function (envVal) {
|
||||
return require(this._config.paths.config)[envVal];
|
||||
};
|
||||
|
||||
/**
|
||||
* Validates the config object has everything we want and in the form we want.
|
||||
* @return {Promise.<Object>} Returns a promise that resolves to the config object.
|
||||
*/
|
||||
ConfigManager.prototype.validate = function () {
|
||||
var envVal = process.env.NODE_ENV || undefined,
|
||||
hasHostAndPort,
|
||||
hasSocket,
|
||||
config,
|
||||
parsedUrl;
|
||||
|
||||
try {
|
||||
config = this.readFile(envVal);
|
||||
}
|
||||
catch (e) {
|
||||
return Promise.reject(e);
|
||||
}
|
||||
|
||||
// Check if we don't even have a config
|
||||
if (!config) {
|
||||
errors.logError(new Error('Cannot find the configuration for the current NODE_ENV'), 'NODE_ENV=' + envVal,
|
||||
'Ensure your config.js has a section for the current NODE_ENV value and is formatted properly.');
|
||||
|
||||
return Promise.reject(new Error('Unable to load config for NODE_ENV=' + envVal));
|
||||
}
|
||||
|
||||
// Check that our url is valid
|
||||
if (!validator.isURL(config.url, { protocols: ['http', 'https'], require_protocol: true })) {
|
||||
errors.logError(new Error('Your site url in config.js is invalid.'), config.url, 'Please make sure this is a valid url before restarting');
|
||||
|
||||
return Promise.reject(new Error('invalid site url'));
|
||||
}
|
||||
|
||||
parsedUrl = url.parse(config.url || 'invalid', false, true);
|
||||
|
||||
if (/\/ghost(\/|$)/.test(parsedUrl.pathname)) {
|
||||
errors.logError(new Error('Your site url in config.js cannot contain a subdirectory called ghost.'), config.url, 'Please rename the subdirectory before restarting');
|
||||
|
||||
return Promise.reject(new Error('ghost subdirectory not allowed'));
|
||||
}
|
||||
|
||||
// Check that we have database values
|
||||
if (!config.database || !config.database.client) {
|
||||
errors.logError(new Error('Your database configuration in config.js is invalid.'), JSON.stringify(config.database), 'Please make sure this is a valid Bookshelf database configuration');
|
||||
|
||||
return Promise.reject(new Error('invalid database configuration'));
|
||||
}
|
||||
|
||||
hasHostAndPort = config.server && !!config.server.host && !!config.server.port;
|
||||
hasSocket = config.server && !!config.server.socket;
|
||||
|
||||
// Check for valid server host and port values
|
||||
if (!config.server || !(hasHostAndPort || hasSocket)) {
|
||||
errors.logError(new Error('Your server values (socket, or host and port) in config.js are invalid.'), JSON.stringify(config.server), 'Please provide them before restarting.');
|
||||
|
||||
return Promise.reject(new Error('invalid server configuration'));
|
||||
}
|
||||
|
||||
return Promise.resolve(config);
|
||||
};
|
||||
|
||||
if (testingEnvs.indexOf(process.env.NODE_ENV) > -1) {
|
||||
defaultConfig = require('../../../config.example')[process.env.NODE_ENV];
|
||||
}
|
||||
|
||||
// Init config
|
||||
updateConfig(defaultConfig);
|
||||
|
||||
module.exports = ghostConfig;
|
||||
module.exports.init = initConfig;
|
||||
module.exports.theme = theme;
|
||||
module.exports.getSocket = getSocket;
|
||||
module.exports.urlFor = configUrl.urlFor;
|
||||
module.exports.urlForPost = configUrl.urlForPost;
|
||||
module.exports = new ConfigManager(defaultConfig);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
/*jslint regexp: true */
|
||||
var _ = require('lodash'),
|
||||
colors = require('colors'),
|
||||
config = require('../config'),
|
||||
path = require('path'),
|
||||
Promise = require('bluebird'),
|
||||
hbs = require('express-hbs'),
|
||||
|
@ -15,21 +14,31 @@ var _ = require('lodash'),
|
|||
UnsupportedMediaTypeError = require('./unsupportedmediaerror'),
|
||||
EmailError = require('./emailerror'),
|
||||
DataImportError = require('./dataimporterror'),
|
||||
config,
|
||||
errors,
|
||||
|
||||
// Paths for views
|
||||
defaultErrorTemplatePath = path.resolve(config.paths.adminViews, 'user-error.hbs'),
|
||||
userErrorTemplateExists = false;
|
||||
|
||||
// This is not useful but required for jshint
|
||||
colors.setTheme({silly: 'rainbow'});
|
||||
|
||||
// Shim right now to deal with circular dependencies.
|
||||
// @TODO: remove circular dependency
|
||||
function getConfigModule() {
|
||||
if (!config) {
|
||||
config = require('../config');
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic error handling helpers
|
||||
*/
|
||||
errors = {
|
||||
updateActiveTheme: function (activeTheme) {
|
||||
userErrorTemplateExists = config.paths.availableThemes[activeTheme].hasOwnProperty('error.hbs');
|
||||
userErrorTemplateExists = getConfigModule().paths.availableThemes[activeTheme].hasOwnProperty('error.hbs');
|
||||
},
|
||||
|
||||
throwError: function (err) {
|
||||
|
@ -185,7 +194,8 @@ errors = {
|
|||
|
||||
renderErrorPage: function (code, err, req, res, next) {
|
||||
/*jshint unused:false*/
|
||||
var self = this;
|
||||
var self = this,
|
||||
defaultErrorTemplatePath = path.resolve(getConfigModule().paths.adminViews, 'user-error.hbs');
|
||||
|
||||
function parseStack(stack) {
|
||||
if (!_.isString(stack)) {
|
||||
|
|
|
@ -129,23 +129,22 @@ function initNotifications() {
|
|||
// Sets up the express server instance.
|
||||
// Instantiates the ghost singleton, helpers, routes, middleware, and apps.
|
||||
// Finally it returns an instance of GhostServer
|
||||
function init(server) {
|
||||
// create a hash for cache busting assets
|
||||
var assetHash = (crypto.createHash('md5').update(packageInfo.version + Date.now()).digest('hex')).substring(0, 10);
|
||||
|
||||
// If no express instance is passed in
|
||||
// then create our own
|
||||
if (!server) {
|
||||
server = express();
|
||||
}
|
||||
function init(options) {
|
||||
// Get reference to an express app instance.
|
||||
var server = options.app ? options.app : express(),
|
||||
// create a hash for cache busting assets
|
||||
assetHash = (crypto.createHash('md5').update(packageInfo.version + Date.now()).digest('hex')).substring(0, 10);
|
||||
|
||||
// ### Initialisation
|
||||
// The server and its dependencies require a populated config
|
||||
// It returns a promise that is resolved when the application
|
||||
// has finished starting up.
|
||||
|
||||
// Make sure javascript files have been built via grunt concat
|
||||
return builtFilesExist().then(function () {
|
||||
// Load our config.js file from the local file system.
|
||||
return config.load(options.config).then(function () {
|
||||
// Make sure javascript files have been built via grunt concat
|
||||
return builtFilesExist();
|
||||
}).then(function () {
|
||||
// Initialise the models
|
||||
return models.init();
|
||||
}).then(function () {
|
||||
|
|
|
@ -11,7 +11,6 @@ var testUtils = require('../utils/index'),
|
|||
|
||||
// Stuff we are testing
|
||||
config = rewire('../../server/config'),
|
||||
configUpdate = config.__get__('updateConfig'),
|
||||
defaultConfig = rewire('../../../config.example')[process.env.NODE_ENV],
|
||||
migration = rewire('../../server/data/migration'),
|
||||
versioning = require('../../server/data/versioning'),
|
||||
|
@ -43,7 +42,7 @@ describe('Import', function () {
|
|||
var newConfig = _.extend(config, defaultConfig);
|
||||
|
||||
migration.__get__('config', newConfig);
|
||||
configUpdate(newConfig);
|
||||
config.set(newConfig);
|
||||
knex = config.database.knex;
|
||||
});
|
||||
|
||||
|
|
323
core/test/unit/bootstrap_spec.js
vendored
323
core/test/unit/bootstrap_spec.js
vendored
|
@ -1,323 +0,0 @@
|
|||
/*globals describe, it, beforeEach, afterEach */
|
||||
/*jshint expr:true*/
|
||||
var should = require('should'),
|
||||
sinon = require('sinon'),
|
||||
Promise = require('bluebird'),
|
||||
path = require('path'),
|
||||
fs = require('fs'),
|
||||
_ = require('lodash'),
|
||||
rewire = require('rewire'),
|
||||
|
||||
// Thing we are testing
|
||||
defaultConfig = require('../../../config.example')[process.env.NODE_ENV],
|
||||
bootstrap = rewire('../../bootstrap'),
|
||||
config = rewire('../../server/config');
|
||||
|
||||
describe('Bootstrap', function () {
|
||||
var sandbox,
|
||||
overrideConfig = function (newConfig) {
|
||||
bootstrap.__set__('readConfigFile', sandbox.stub().returns(
|
||||
_.extend({}, defaultConfig, newConfig)
|
||||
));
|
||||
},
|
||||
expectedError = new Error('expected bootstrap() to throw error but none thrown');
|
||||
|
||||
beforeEach(function () {
|
||||
sandbox = sinon.sandbox.create();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
bootstrap = rewire('../../bootstrap');
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('loads the config file if one exists', function (done) {
|
||||
// the test infrastructure is setup so that there is always config present,
|
||||
// but we want to overwrite the test to actually load config.example.js, so that any local changes
|
||||
// don't break the tests
|
||||
bootstrap.__set__('configFile', path.join(config.paths.appRoot, 'config.example.js'));
|
||||
|
||||
bootstrap().then(function (config) {
|
||||
config.url.should.equal(defaultConfig.url);
|
||||
config.database.client.should.equal(defaultConfig.database.client);
|
||||
config.database.connection.should.eql(defaultConfig.database.connection);
|
||||
config.server.host.should.equal(defaultConfig.server.host);
|
||||
config.server.port.should.equal(defaultConfig.server.port);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('uses the passed in config file location', function (done) {
|
||||
bootstrap(path.join(config.paths.appRoot, 'config.example.js')).then(function (config) {
|
||||
config.url.should.equal(defaultConfig.url);
|
||||
config.database.client.should.equal(defaultConfig.database.client);
|
||||
config.database.connection.should.eql(defaultConfig.database.connection);
|
||||
config.server.host.should.equal(defaultConfig.server.host);
|
||||
config.server.port.should.equal(defaultConfig.server.port);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('creates the config file if one does not exist', function (done) {
|
||||
|
||||
// trick bootstrap into thinking that the config file doesn't exist yet
|
||||
var existsStub = sandbox.stub(fs, 'exists', function (file, cb) { return cb(false); }),
|
||||
// create a method which will return a pre-resolved promise
|
||||
resolvedPromise = sandbox.stub().returns(Promise.resolve());
|
||||
|
||||
// ensure that the file creation is a stub, the tests shouldn't really create a file
|
||||
bootstrap.__set__('writeConfigFile', resolvedPromise);
|
||||
bootstrap.__set__('validateConfigEnvironment', resolvedPromise);
|
||||
|
||||
bootstrap().then(function () {
|
||||
existsStub.calledOnce.should.be.true;
|
||||
resolvedPromise.calledTwice.should.be.true;
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('accepts urls with a valid scheme', function (done) {
|
||||
// replace the config file with invalid data
|
||||
overrideConfig({url: 'http://testurl.com'});
|
||||
|
||||
bootstrap().then(function (localConfig) {
|
||||
localConfig.url.should.equal('http://testurl.com');
|
||||
|
||||
// Next test
|
||||
overrideConfig({url: 'https://testurl.com'});
|
||||
return bootstrap();
|
||||
}).then(function (localConfig) {
|
||||
localConfig.url.should.equal('https://testurl.com');
|
||||
|
||||
// Next test
|
||||
overrideConfig({url: 'http://testurl.com/blog/'});
|
||||
return bootstrap();
|
||||
}).then(function (localConfig) {
|
||||
localConfig.url.should.equal('http://testurl.com/blog/');
|
||||
|
||||
// Next test
|
||||
overrideConfig({url: 'http://testurl.com/ghostly/'});
|
||||
return bootstrap();
|
||||
}).then(function (localConfig) {
|
||||
localConfig.url.should.equal('http://testurl.com/ghostly/');
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('rejects a fqdn without a scheme', function (done) {
|
||||
|
||||
overrideConfig({ url: 'example.com' });
|
||||
|
||||
bootstrap().then(function () {
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('rejects a hostname without a scheme', function (done) {
|
||||
|
||||
overrideConfig({ url: 'example' });
|
||||
|
||||
bootstrap().then(function () {
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('rejects a hostname with a scheme', function (done) {
|
||||
|
||||
overrideConfig({ url: 'https://example' });
|
||||
|
||||
bootstrap().then(function () {
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('rejects a url with an unsupported scheme', function (done) {
|
||||
|
||||
overrideConfig({ url: 'ftp://example.com' });
|
||||
|
||||
bootstrap().then(function () {
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('rejects a url with a protocol relative scheme', function (done) {
|
||||
|
||||
overrideConfig({ url: '//example.com' });
|
||||
|
||||
bootstrap().then(function () {
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('does not permit the word ghost as a url path', function (done) {
|
||||
overrideConfig({ url: 'http://example.com/ghost/' });
|
||||
|
||||
bootstrap().then(function () {
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('does not permit the word ghost to be a component in a url path', function (done) {
|
||||
overrideConfig({ url: 'http://example.com/blog/ghost/' });
|
||||
|
||||
bootstrap().then(function () {
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('does not permit the word ghost to be a component in a url path', function (done) {
|
||||
overrideConfig({ url: 'http://example.com/ghost/blog/' });
|
||||
|
||||
bootstrap().then(function () {
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('does not permit database config to be falsy', function (done) {
|
||||
// replace the config file with invalid data
|
||||
overrideConfig({ database: false });
|
||||
|
||||
bootstrap().then(function () {
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('does not permit database config to be empty', function (done) {
|
||||
// replace the config file with invalid data
|
||||
overrideConfig({ database: {} });
|
||||
|
||||
bootstrap().then(function () {
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
|
||||
it('requires server to be present', function (done) {
|
||||
overrideConfig({ server: false });
|
||||
|
||||
bootstrap().then(function (localConfig) {
|
||||
/*jshint unused:false*/
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('allows server to use a socket', function (done) {
|
||||
overrideConfig({ server: { socket: 'test' } });
|
||||
|
||||
bootstrap().then(function (localConfig) {
|
||||
should.exist(localConfig);
|
||||
localConfig.server.socket.should.equal('test');
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('allows server to have a host and a port', function (done) {
|
||||
overrideConfig({ server: { host: '127.0.0.1', port: '2368' } });
|
||||
|
||||
bootstrap().then(function (localConfig) {
|
||||
should.exist(localConfig);
|
||||
localConfig.server.host.should.equal('127.0.0.1');
|
||||
localConfig.server.port.should.equal('2368');
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('rejects server if there is a host but no port', function (done) {
|
||||
overrideConfig({ server: { host: '127.0.0.1' } });
|
||||
|
||||
bootstrap().then(function () {
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('rejects server if there is a port but no host', function (done) {
|
||||
overrideConfig({ server: { port: '2368' } });
|
||||
|
||||
bootstrap().then(function () {
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('rejects server if configuration is empty', function (done) {
|
||||
overrideConfig({ server: {} });
|
||||
|
||||
bootstrap().then(function () {
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
|
@ -4,6 +4,7 @@ var should = require('should'),
|
|||
sinon = require('sinon'),
|
||||
Promise = require('bluebird'),
|
||||
path = require('path'),
|
||||
fs = require('fs'),
|
||||
_ = require('lodash'),
|
||||
rewire = require('rewire'),
|
||||
|
||||
|
@ -12,8 +13,7 @@ var should = require('should'),
|
|||
// Thing we are testing
|
||||
defaultConfig = require('../../../config.example')[process.env.NODE_ENV],
|
||||
theme = rewire('../../server/config/theme'),
|
||||
config = rewire('../../server/config'),
|
||||
configUpdate = config.__get__('updateConfig');
|
||||
config = rewire('../../server/config');
|
||||
|
||||
// To stop jshint complaining
|
||||
should.equal(true, true);
|
||||
|
@ -76,7 +76,7 @@ describe('Config', function () {
|
|||
// Make a copy of the default config file
|
||||
// so we can restore it after every test.
|
||||
// Using _.merge to recursively apply every property.
|
||||
configUpdate(_.merge({}, config));
|
||||
config.set(_.merge({}, config));
|
||||
});
|
||||
|
||||
it('should have exactly the right keys', function () {
|
||||
|
@ -114,24 +114,24 @@ describe('Config', function () {
|
|||
});
|
||||
|
||||
it('should not return a slash for subdir', function () {
|
||||
configUpdate({url: 'http://my-ghost-blog.com'});
|
||||
config.set({url: 'http://my-ghost-blog.com'});
|
||||
config.paths.should.have.property('subdir', '');
|
||||
|
||||
configUpdate({url: 'http://my-ghost-blog.com/'});
|
||||
config.set({url: 'http://my-ghost-blog.com/'});
|
||||
config.paths.should.have.property('subdir', '');
|
||||
});
|
||||
|
||||
it('should handle subdirectories properly', function () {
|
||||
configUpdate({url: 'http://my-ghost-blog.com/blog'});
|
||||
config.set({url: 'http://my-ghost-blog.com/blog'});
|
||||
config.paths.should.have.property('subdir', '/blog');
|
||||
|
||||
configUpdate({url: 'http://my-ghost-blog.com/blog/'});
|
||||
config.set({url: 'http://my-ghost-blog.com/blog/'});
|
||||
config.paths.should.have.property('subdir', '/blog');
|
||||
|
||||
configUpdate({url: 'http://my-ghost-blog.com/my/blog'});
|
||||
config.set({url: 'http://my-ghost-blog.com/my/blog'});
|
||||
config.paths.should.have.property('subdir', '/my/blog');
|
||||
|
||||
configUpdate({url: 'http://my-ghost-blog.com/my/blog/'});
|
||||
config.set({url: 'http://my-ghost-blog.com/my/blog/'});
|
||||
config.paths.should.have.property('subdir', '/my/blog');
|
||||
});
|
||||
|
||||
|
@ -139,7 +139,7 @@ describe('Config', function () {
|
|||
var contentPath = path.join(config.paths.appRoot, 'otherContent', '/'),
|
||||
configFile = 'configFileDanceParty.js';
|
||||
|
||||
configUpdate({
|
||||
config.set({
|
||||
config: configFile,
|
||||
paths: {
|
||||
contentPath: contentPath
|
||||
|
@ -157,27 +157,27 @@ describe('Config', function () {
|
|||
describe('urlFor', function () {
|
||||
|
||||
before(function () {
|
||||
configUpdate(_.merge({}, defaultConfig));
|
||||
config.set(_.merge({}, defaultConfig));
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
configUpdate({url: defaultConfig.url});
|
||||
config.set({url: defaultConfig.url});
|
||||
});
|
||||
|
||||
it('should return the home url with no options', function () {
|
||||
config.urlFor().should.equal('/');
|
||||
configUpdate({url: 'http://my-ghost-blog.com/blog'});
|
||||
config.set({url: 'http://my-ghost-blog.com/blog'});
|
||||
config.urlFor().should.equal('/blog/');
|
||||
});
|
||||
|
||||
it('should return home url when asked for', function () {
|
||||
var testContext = 'home';
|
||||
|
||||
configUpdate({url: 'http://my-ghost-blog.com'});
|
||||
config.set({url: 'http://my-ghost-blog.com'});
|
||||
config.urlFor(testContext).should.equal('/');
|
||||
config.urlFor(testContext, true).should.equal('http://my-ghost-blog.com/');
|
||||
|
||||
configUpdate({url: 'http://my-ghost-blog.com/blog'});
|
||||
config.set({url: 'http://my-ghost-blog.com/blog'});
|
||||
config.urlFor(testContext).should.equal('/blog/');
|
||||
config.urlFor(testContext, true).should.equal('http://my-ghost-blog.com/blog/');
|
||||
});
|
||||
|
@ -185,11 +185,11 @@ describe('Config', function () {
|
|||
it('should return rss url when asked for', function () {
|
||||
var testContext = 'rss';
|
||||
|
||||
configUpdate({url: 'http://my-ghost-blog.com'});
|
||||
config.set({url: 'http://my-ghost-blog.com'});
|
||||
config.urlFor(testContext).should.equal('/rss/');
|
||||
config.urlFor(testContext, true).should.equal('http://my-ghost-blog.com/rss/');
|
||||
|
||||
configUpdate({url: 'http://my-ghost-blog.com/blog'});
|
||||
config.set({url: 'http://my-ghost-blog.com/blog'});
|
||||
config.urlFor(testContext).should.equal('/blog/rss/');
|
||||
config.urlFor(testContext, true).should.equal('http://my-ghost-blog.com/blog/rss/');
|
||||
});
|
||||
|
@ -197,11 +197,11 @@ describe('Config', function () {
|
|||
it('should return url for a random path when asked for', function () {
|
||||
var testContext = {relativeUrl: '/about/'};
|
||||
|
||||
configUpdate({url: 'http://my-ghost-blog.com'});
|
||||
config.set({url: 'http://my-ghost-blog.com'});
|
||||
config.urlFor(testContext).should.equal('/about/');
|
||||
config.urlFor(testContext, true).should.equal('http://my-ghost-blog.com/about/');
|
||||
|
||||
configUpdate({url: 'http://my-ghost-blog.com/blog'});
|
||||
config.set({url: 'http://my-ghost-blog.com/blog'});
|
||||
config.urlFor(testContext).should.equal('/blog/about/');
|
||||
config.urlFor(testContext, true).should.equal('http://my-ghost-blog.com/blog/about/');
|
||||
});
|
||||
|
@ -210,11 +210,11 @@ describe('Config', function () {
|
|||
var testContext = 'post',
|
||||
testData = {post: testUtils.DataGenerator.Content.posts[2], permalinks: {value: '/:slug/'}};
|
||||
|
||||
configUpdate({url: 'http://my-ghost-blog.com'});
|
||||
config.set({url: 'http://my-ghost-blog.com'});
|
||||
config.urlFor(testContext, testData).should.equal('/short-and-sweet/');
|
||||
config.urlFor(testContext, testData, true).should.equal('http://my-ghost-blog.com/short-and-sweet/');
|
||||
|
||||
configUpdate({url: 'http://my-ghost-blog.com/blog'});
|
||||
config.set({url: 'http://my-ghost-blog.com/blog'});
|
||||
config.urlFor(testContext, testData).should.equal('/blog/short-and-sweet/');
|
||||
config.urlFor(testContext, testData, true).should.equal('http://my-ghost-blog.com/blog/short-and-sweet/');
|
||||
});
|
||||
|
@ -231,11 +231,11 @@ describe('Config', function () {
|
|||
yyyy = today.getFullYear(),
|
||||
postLink = '/' + yyyy + '/' + mm + '/' + dd + '/short-and-sweet/';
|
||||
|
||||
configUpdate({url: 'http://my-ghost-blog.com'});
|
||||
config.set({url: 'http://my-ghost-blog.com'});
|
||||
config.urlFor(testContext, testData).should.equal(postLink);
|
||||
config.urlFor(testContext, testData, true).should.equal('http://my-ghost-blog.com' + postLink);
|
||||
|
||||
configUpdate({url: 'http://my-ghost-blog.com/blog'});
|
||||
config.set({url: 'http://my-ghost-blog.com/blog'});
|
||||
config.urlFor(testContext, testData).should.equal('/blog' + postLink);
|
||||
config.urlFor(testContext, testData, true).should.equal('http://my-ghost-blog.com/blog' + postLink);
|
||||
});
|
||||
|
@ -244,11 +244,11 @@ describe('Config', function () {
|
|||
var testContext = 'tag',
|
||||
testData = {tag: testUtils.DataGenerator.Content.tags[0]};
|
||||
|
||||
configUpdate({url: 'http://my-ghost-blog.com'});
|
||||
config.set({url: 'http://my-ghost-blog.com'});
|
||||
config.urlFor(testContext, testData).should.equal('/tag/kitchen-sink/');
|
||||
config.urlFor(testContext, testData, true).should.equal('http://my-ghost-blog.com/tag/kitchen-sink/');
|
||||
|
||||
configUpdate({url: 'http://my-ghost-blog.com/blog'});
|
||||
config.set({url: 'http://my-ghost-blog.com/blog'});
|
||||
config.urlFor(testContext, testData).should.equal('/blog/tag/kitchen-sink/');
|
||||
config.urlFor(testContext, testData, true).should.equal('http://my-ghost-blog.com/blog/tag/kitchen-sink/');
|
||||
});
|
||||
|
@ -264,7 +264,7 @@ describe('Config', function () {
|
|||
|
||||
afterEach(function () {
|
||||
sandbox.restore();
|
||||
configUpdate({url: defaultConfig.url});
|
||||
config.set({url: defaultConfig.url});
|
||||
});
|
||||
|
||||
it('should output correct url for post', function (done) {
|
||||
|
@ -276,7 +276,7 @@ describe('Config', function () {
|
|||
testData = testUtils.DataGenerator.Content.posts[2],
|
||||
postLink = '/short-and-sweet/';
|
||||
|
||||
configUpdate({url: 'http://my-ghost-blog.com'});
|
||||
config.set({url: 'http://my-ghost-blog.com'});
|
||||
|
||||
// next test
|
||||
config.urlForPost(settings, testData).then(function (url) {
|
||||
|
@ -287,7 +287,7 @@ describe('Config', function () {
|
|||
}).then(function (url) {
|
||||
url.should.equal('http://my-ghost-blog.com' + postLink);
|
||||
|
||||
return configUpdate({url: 'http://my-ghost-blog.com/blog'});
|
||||
return config.set({url: 'http://my-ghost-blog.com/blog'});
|
||||
}).then(function () {
|
||||
|
||||
// next test
|
||||
|
@ -318,7 +318,7 @@ describe('Config', function () {
|
|||
yyyy = today.getFullYear(),
|
||||
postLink = '/' + yyyy + '/' + mm + '/' + dd + '/short-and-sweet/';
|
||||
|
||||
configUpdate({url: 'http://my-ghost-blog.com'});
|
||||
config.set({url: 'http://my-ghost-blog.com'});
|
||||
|
||||
// next test
|
||||
config.urlForPost(settings, testData).then(function (url) {
|
||||
|
@ -329,7 +329,7 @@ describe('Config', function () {
|
|||
}).then(function (url) {
|
||||
url.should.equal('http://my-ghost-blog.com' + postLink);
|
||||
|
||||
return configUpdate({url: 'http://my-ghost-blog.com/blog'});
|
||||
return config.set({url: 'http://my-ghost-blog.com/blog'});
|
||||
}).then(function () {
|
||||
|
||||
// next test
|
||||
|
@ -355,7 +355,7 @@ describe('Config', function () {
|
|||
testData = testUtils.DataGenerator.Content.posts[5],
|
||||
postLink = '/static-page-test/';
|
||||
|
||||
configUpdate({url: 'http://my-ghost-blog.com'});
|
||||
config.set({url: 'http://my-ghost-blog.com'});
|
||||
|
||||
// next test
|
||||
config.urlForPost(settings, testData).then(function (url) {
|
||||
|
@ -366,7 +366,7 @@ describe('Config', function () {
|
|||
}).then(function (url) {
|
||||
url.should.equal('http://my-ghost-blog.com' + postLink);
|
||||
|
||||
return configUpdate({url: 'http://my-ghost-blog.com/blog'});
|
||||
return config.set({url: 'http://my-ghost-blog.com/blog'});
|
||||
}).then(function () {
|
||||
|
||||
// next test
|
||||
|
@ -383,4 +383,327 @@ describe('Config', function () {
|
|||
}).catch(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('File', function () {
|
||||
var sandbox,
|
||||
originalConfig,
|
||||
readFileStub,
|
||||
overrideConfig = function (newConfig) {
|
||||
readFileStub.returns(
|
||||
_.extend({}, defaultConfig, newConfig)
|
||||
);
|
||||
},
|
||||
expectedError = new Error('expected bootstrap() to throw error but none thrown');
|
||||
|
||||
before(function () {
|
||||
originalConfig = _.cloneDeep(rewire('../../server/config')._config);
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
sandbox = sinon.sandbox.create();
|
||||
readFileStub = sandbox.stub(config, 'readFile');
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
config = rewire('../../server/config');
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('loads the config file if one exists', function (done) {
|
||||
// We actually want the real method here.
|
||||
readFileStub.restore();
|
||||
|
||||
// the test infrastructure is setup so that there is always config present,
|
||||
// but we want to overwrite the test to actually load config.example.js, so that any local changes
|
||||
// don't break the tests
|
||||
config.set({
|
||||
paths: {
|
||||
appRoot: path.join(originalConfig.paths.appRoot, 'config.example.js')
|
||||
}
|
||||
});
|
||||
|
||||
config.load().then(function (config) {
|
||||
config.url.should.equal(defaultConfig.url);
|
||||
config.database.client.should.equal(defaultConfig.database.client);
|
||||
config.database.connection.should.eql(defaultConfig.database.connection);
|
||||
config.server.host.should.equal(defaultConfig.server.host);
|
||||
config.server.port.should.equal(defaultConfig.server.port);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('uses the passed in config file location', function (done) {
|
||||
// We actually want the real method here.
|
||||
readFileStub.restore();
|
||||
|
||||
config.load(path.join(originalConfig.paths.appRoot, 'config.example.js')).then(function (config) {
|
||||
config.url.should.equal(defaultConfig.url);
|
||||
config.database.client.should.equal(defaultConfig.database.client);
|
||||
config.database.connection.should.eql(defaultConfig.database.connection);
|
||||
config.server.host.should.equal(defaultConfig.server.host);
|
||||
config.server.port.should.equal(defaultConfig.server.port);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('creates the config file if one does not exist', function (done) {
|
||||
// trick bootstrap into thinking that the config file doesn't exist yet
|
||||
var existsStub = sandbox.stub(fs, 'exists', function (file, cb) { return cb(false); }),
|
||||
// ensure that the file creation is a stub, the tests shouldn't really create a file
|
||||
writeFileStub = sandbox.stub(config, 'writeFile').returns(Promise.resolve()),
|
||||
validateStub = sandbox.stub(config, 'validate').returns(Promise.resolve());
|
||||
|
||||
config.load().then(function () {
|
||||
existsStub.calledOnce.should.be.true;
|
||||
writeFileStub.calledOnce.should.be.true;
|
||||
validateStub.calledOnce.should.be.true;
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('accepts urls with a valid scheme', function (done) {
|
||||
// replace the config file with invalid data
|
||||
overrideConfig({url: 'http://testurl.com'});
|
||||
|
||||
config.load().then(function (localConfig) {
|
||||
localConfig.url.should.equal('http://testurl.com');
|
||||
|
||||
// Next test
|
||||
overrideConfig({url: 'https://testurl.com'});
|
||||
return config.load();
|
||||
}).then(function (localConfig) {
|
||||
localConfig.url.should.equal('https://testurl.com');
|
||||
|
||||
// Next test
|
||||
overrideConfig({url: 'http://testurl.com/blog/'});
|
||||
return config.load();
|
||||
}).then(function (localConfig) {
|
||||
localConfig.url.should.equal('http://testurl.com/blog/');
|
||||
|
||||
// Next test
|
||||
overrideConfig({url: 'http://testurl.com/ghostly/'});
|
||||
return config.load();
|
||||
}).then(function (localConfig) {
|
||||
localConfig.url.should.equal('http://testurl.com/ghostly/');
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('rejects a fqdn without a scheme', function (done) {
|
||||
|
||||
overrideConfig({ url: 'example.com' });
|
||||
|
||||
config.load().then(function () {
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('rejects a hostname without a scheme', function (done) {
|
||||
|
||||
overrideConfig({ url: 'example' });
|
||||
|
||||
config.load().then(function () {
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('rejects a hostname with a scheme', function (done) {
|
||||
|
||||
overrideConfig({ url: 'https://example' });
|
||||
|
||||
config.load().then(function () {
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('rejects a url with an unsupported scheme', function (done) {
|
||||
|
||||
overrideConfig({ url: 'ftp://example.com' });
|
||||
|
||||
config.load().then(function () {
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('rejects a url with a protocol relative scheme', function (done) {
|
||||
|
||||
overrideConfig({ url: '//example.com' });
|
||||
|
||||
config.load().then(function () {
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('does not permit the word ghost as a url path', function (done) {
|
||||
overrideConfig({ url: 'http://example.com/ghost/' });
|
||||
|
||||
config.load().then(function () {
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('does not permit the word ghost to be a component in a url path', function (done) {
|
||||
overrideConfig({ url: 'http://example.com/blog/ghost/' });
|
||||
|
||||
config.load().then(function () {
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('does not permit the word ghost to be a component in a url path', function (done) {
|
||||
overrideConfig({ url: 'http://example.com/ghost/blog/' });
|
||||
|
||||
config.load().then(function () {
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('does not permit database config to be falsy', function (done) {
|
||||
// replace the config file with invalid data
|
||||
overrideConfig({ database: false });
|
||||
|
||||
config.load().then(function () {
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('does not permit database config to be empty', function (done) {
|
||||
// replace the config file with invalid data
|
||||
overrideConfig({ database: {} });
|
||||
|
||||
config.load().then(function () {
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
|
||||
it('requires server to be present', function (done) {
|
||||
overrideConfig({ server: false });
|
||||
|
||||
config.load().then(function (localConfig) {
|
||||
/*jshint unused:false*/
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('allows server to use a socket', function (done) {
|
||||
overrideConfig({ server: { socket: 'test' } });
|
||||
|
||||
config.load().then(function (localConfig) {
|
||||
should.exist(localConfig);
|
||||
localConfig.server.socket.should.equal('test');
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('allows server to have a host and a port', function (done) {
|
||||
overrideConfig({ server: { host: '127.0.0.1', port: '2368' } });
|
||||
|
||||
config.load().then(function (localConfig) {
|
||||
should.exist(localConfig);
|
||||
localConfig.server.host.should.equal('127.0.0.1');
|
||||
localConfig.server.port.should.equal('2368');
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('rejects server if there is a host but no port', function (done) {
|
||||
overrideConfig({ server: { host: '127.0.0.1' } });
|
||||
|
||||
config.load().then(function () {
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('rejects server if there is a port but no host', function (done) {
|
||||
overrideConfig({ server: { port: '2368' } });
|
||||
|
||||
config.load().then(function () {
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('rejects server if configuration is empty', function (done) {
|
||||
overrideConfig({ server: {} });
|
||||
|
||||
config.load().then(function () {
|
||||
done(expectedError);
|
||||
}).catch(function (err) {
|
||||
should.exist(err);
|
||||
err.should.be.an.Error;
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -5,10 +5,12 @@ var should = require('should'),
|
|||
sinon = require('sinon'),
|
||||
express = require('express'),
|
||||
rewire = require('rewire'),
|
||||
_ = require('lodash'),
|
||||
|
||||
// Stuff we are testing
|
||||
|
||||
colors = require('colors'),
|
||||
config = rewire('../../server/config'),
|
||||
errors = rewire('../../server/errors'),
|
||||
// storing current environment
|
||||
currentEnv = process.env.NODE_ENV;
|
||||
|
@ -211,8 +213,8 @@ describe('Error handling', function () {
|
|||
originalConfig;
|
||||
|
||||
before(function () {
|
||||
originalConfig = errors.__get__('config');
|
||||
errors.__set__('config', {
|
||||
originalConfig = _.cloneDeep(config._config);
|
||||
errors.__set__('getConfigModule', sinon.stub().returns(_.merge({}, originalConfig, {
|
||||
'paths': {
|
||||
'themePath': '/content/themes',
|
||||
'availableThemes': {
|
||||
|
@ -228,7 +230,7 @@ describe('Error handling', function () {
|
|||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
})));
|
||||
errors.updateActiveTheme('casper');
|
||||
});
|
||||
|
||||
|
@ -240,10 +242,6 @@ describe('Error handling', function () {
|
|||
sandbox.restore();
|
||||
});
|
||||
|
||||
after(function () {
|
||||
errors.__set__('config', originalConfig);
|
||||
});
|
||||
|
||||
it('Renders end-of-middleware 404 errors correctly', function (done) {
|
||||
var req = {method: 'GET'},
|
||||
res = express.response;
|
||||
|
|
|
@ -1021,10 +1021,9 @@ describe('Frontend Controller', function () {
|
|||
describe('rss redirects', function () {
|
||||
var res,
|
||||
apiUsersStub,
|
||||
configUpdate = config.__get__('updateConfig'),
|
||||
overwriteConfig = function (newConfig) {
|
||||
var existingConfig = frontend.__get__('config');
|
||||
configUpdate(_.extend(existingConfig, newConfig));
|
||||
config.set(_.extend(existingConfig, newConfig));
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
|
|
|
@ -39,10 +39,9 @@ SENDMAIL = {
|
|||
describe('Mail', function () {
|
||||
var overrideConfig = function (newConfig) {
|
||||
var config = rewire('../../server/config'),
|
||||
configUpdate = config.__get__('updateConfig'),
|
||||
existingConfig = mailer.__get__('config');
|
||||
|
||||
configUpdate(_.extend(existingConfig, newConfig));
|
||||
config.set(_.extend(existingConfig, newConfig));
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
|
|
|
@ -12,8 +12,7 @@ var should = require('should'),
|
|||
// Stuff we are testing
|
||||
handlebars = hbs.handlebars,
|
||||
helpers = rewire('../../server/helpers'),
|
||||
config = rewire('../../server/config'),
|
||||
configUpdate = config.__get__('updateConfig');
|
||||
config = rewire('../../server/config');
|
||||
|
||||
describe('Core Helpers', function () {
|
||||
|
||||
|
@ -21,7 +20,7 @@ describe('Core Helpers', function () {
|
|||
apiStub,
|
||||
overrideConfig = function (newConfig) {
|
||||
var existingConfig = helpers.__get__('config');
|
||||
configUpdate(_.extend(existingConfig, newConfig));
|
||||
config.set(_.extend(existingConfig, newConfig));
|
||||
};
|
||||
|
||||
beforeEach(function (done) {
|
||||
|
@ -496,7 +495,7 @@ describe('Core Helpers', function () {
|
|||
var configUrl = config.url;
|
||||
|
||||
afterEach(function () {
|
||||
configUpdate({url: configUrl});
|
||||
config.set({url: configUrl});
|
||||
});
|
||||
|
||||
it('has loaded ghost_head helper', function () {
|
||||
|
@ -504,7 +503,7 @@ describe('Core Helpers', function () {
|
|||
});
|
||||
|
||||
it('returns meta tag string', function (done) {
|
||||
configUpdate({url: 'http://testurl.com/'});
|
||||
config.set({url: 'http://testurl.com/'});
|
||||
helpers.ghost_head.call({version: '0.3.0'}).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.equal('<meta name="generator" content="Ghost 0.3" />\n' +
|
||||
|
@ -516,7 +515,7 @@ describe('Core Helpers', function () {
|
|||
});
|
||||
|
||||
it('returns meta tag string even if version is invalid', function (done) {
|
||||
configUpdate({url: 'http://testurl.com/'});
|
||||
config.set({url: 'http://testurl.com/'});
|
||||
helpers.ghost_head.call({version: '0.9'}).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.equal('<meta name="generator" content="Ghost 0.9" />\n' +
|
||||
|
@ -528,7 +527,7 @@ describe('Core Helpers', function () {
|
|||
});
|
||||
|
||||
it('returns correct rss url with subdirectory', function (done) {
|
||||
configUpdate({url: 'http://testurl.com/blog/'});
|
||||
config.set({url: 'http://testurl.com/blog/'});
|
||||
helpers.ghost_head.call({version: '0.3.0'}).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.equal('<meta name="generator" content="Ghost 0.3" />\n' +
|
||||
|
@ -540,7 +539,7 @@ describe('Core Helpers', function () {
|
|||
});
|
||||
|
||||
it('returns canonical URL', function (done) {
|
||||
configUpdate({url: 'http://testurl.com'});
|
||||
config.set({url: 'http://testurl.com'});
|
||||
helpers.ghost_head.call({version: '0.3.0', relativeUrl: '/about/'}).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.equal('<meta name="generator" content="Ghost 0.3" />\n' +
|
||||
|
@ -552,7 +551,7 @@ describe('Core Helpers', function () {
|
|||
});
|
||||
|
||||
it('returns next & prev URL correctly for middle page', function (done) {
|
||||
configUpdate({url: 'http://testurl.com'});
|
||||
config.set({url: 'http://testurl.com'});
|
||||
helpers.ghost_head.call({version: '0.3.0', relativeUrl: '/page/3/', pagination: {next: '4', prev: '2'}}).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.equal('<meta name="generator" content="Ghost 0.3" />\n' +
|
||||
|
@ -565,7 +564,7 @@ describe('Core Helpers', function () {
|
|||
});
|
||||
|
||||
it('returns next & prev URL correctly for second page', function (done) {
|
||||
configUpdate({url: 'http://testurl.com'});
|
||||
config.set({url: 'http://testurl.com'});
|
||||
helpers.ghost_head.call({version: '0.3.0', relativeUrl: '/page/2/', pagination: {next: '3', prev: '1'}}).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.equal('<meta name="generator" content="Ghost 0.3" />\n' +
|
||||
|
@ -767,7 +766,7 @@ describe('Core Helpers', function () {
|
|||
});
|
||||
|
||||
afterEach(function () {
|
||||
configUpdate({url: configUrl});
|
||||
config.set({url: configUrl});
|
||||
});
|
||||
|
||||
it('has loaded url helper', function () {
|
||||
|
@ -785,7 +784,7 @@ describe('Core Helpers', function () {
|
|||
});
|
||||
|
||||
it('should output an absolute URL if the option is present', function (done) {
|
||||
configUpdate({ url: 'http://testurl.com/' });
|
||||
config.set({ url: 'http://testurl.com/' });
|
||||
|
||||
helpers.url.call(
|
||||
{html: 'content', markdown: 'ff', title: 'title', slug: 'slug', created_at: new Date(0)},
|
||||
|
@ -1711,7 +1710,7 @@ describe('Core Helpers', function () {
|
|||
configUrl = config.url;
|
||||
|
||||
afterEach(function () {
|
||||
configUpdate({url: configUrl});
|
||||
config.set({url: configUrl});
|
||||
});
|
||||
|
||||
|
||||
|
@ -1722,7 +1721,7 @@ describe('Core Helpers', function () {
|
|||
});
|
||||
|
||||
it('should output the path to admin with subdirectory', function () {
|
||||
configUpdate({url: 'http://testurl.com/blog/'});
|
||||
config.set({url: 'http://testurl.com/blog/'});
|
||||
rendered = helpers.admin_url();
|
||||
should.exist(rendered);
|
||||
rendered.should.equal('/blog/ghost');
|
||||
|
@ -1730,21 +1729,21 @@ describe('Core Helpers', function () {
|
|||
|
||||
it('should output absolute path if absolute is set', function () {
|
||||
// no trailing slash
|
||||
configUpdate({url: 'http://testurl.com'});
|
||||
config.set({url: 'http://testurl.com'});
|
||||
|
||||
rendered = helpers.admin_url({'hash': {absolute: true}});
|
||||
should.exist(rendered);
|
||||
rendered.should.equal('http://testurl.com/ghost');
|
||||
|
||||
// test trailing slash
|
||||
configUpdate({url: 'http://testurl.com/'});
|
||||
config.set({url: 'http://testurl.com/'});
|
||||
rendered = helpers.admin_url({'hash': {absolute: true}});
|
||||
should.exist(rendered);
|
||||
rendered.should.equal('http://testurl.com/ghost');
|
||||
});
|
||||
|
||||
it('should output absolute path with subdirectory', function () {
|
||||
configUpdate({url: 'http://testurl.com/blog'});
|
||||
config.set({url: 'http://testurl.com/blog'});
|
||||
rendered = helpers.admin_url({'hash': {absolute: true}});
|
||||
should.exist(rendered);
|
||||
rendered.should.equal('http://testurl.com/blog/ghost');
|
||||
|
@ -1757,27 +1756,27 @@ describe('Core Helpers', function () {
|
|||
});
|
||||
|
||||
it('should output the absolute path to frontend if both are set', function () {
|
||||
configUpdate({url: 'http://testurl.com'});
|
||||
config.set({url: 'http://testurl.com'});
|
||||
|
||||
rendered = helpers.admin_url({'hash': {frontend: true, absolute: true}});
|
||||
should.exist(rendered);
|
||||
rendered.should.equal('http://testurl.com/');
|
||||
|
||||
configUpdate({url: 'http://testurl.com/'});
|
||||
config.set({url: 'http://testurl.com/'});
|
||||
rendered = helpers.admin_url({'hash': {frontend: true, absolute: true}});
|
||||
should.exist(rendered);
|
||||
rendered.should.equal('http://testurl.com/');
|
||||
});
|
||||
|
||||
it('should output the path to frontend with subdirectory', function () {
|
||||
configUpdate({url: 'http://testurl.com/blog/'});
|
||||
config.set({url: 'http://testurl.com/blog/'});
|
||||
rendered = helpers.admin_url({'hash': {frontend: true}});
|
||||
should.exist(rendered);
|
||||
rendered.should.equal('/blog/');
|
||||
});
|
||||
|
||||
it('should output the absolute path to frontend with subdirectory', function () {
|
||||
configUpdate({url: 'http://testurl.com/blog/'});
|
||||
config.set({url: 'http://testurl.com/blog/'});
|
||||
rendered = helpers.admin_url({'hash': {frontend: true, absolute: true}});
|
||||
should.exist(rendered);
|
||||
rendered.should.equal('http://testurl.com/blog/');
|
||||
|
@ -1862,7 +1861,7 @@ describe('Core Helpers', function () {
|
|||
var configUrl = config.url;
|
||||
|
||||
afterEach(function () {
|
||||
configUpdate({url: configUrl});
|
||||
config.set({url: configUrl});
|
||||
});
|
||||
|
||||
it('is loaded', function () {
|
||||
|
|
|
@ -7,7 +7,6 @@ var fs = require('fs-extra'),
|
|||
rewire = require('rewire'),
|
||||
_ = require('lodash'),
|
||||
config = rewire('../../server/config'),
|
||||
configUpdate = config.__get__('updateConfig'),
|
||||
localfilesystem = rewire('../../server/storage/localfilesystem');
|
||||
|
||||
// To stop jshint complaining
|
||||
|
@ -19,7 +18,7 @@ describe('Local File System Storage', function () {
|
|||
overrideConfig = function (newConfig) {
|
||||
var existingConfig = localfilesystem.__get__('config'),
|
||||
updatedConfig = _.extend(existingConfig, newConfig);
|
||||
configUpdate(updatedConfig);
|
||||
config.set(updatedConfig);
|
||||
localfilesystem.__set__('config', updatedConfig);
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue