Replace cookieSession with session

- changed cookieSession to session
- added session.regenerate for login and logout
- added bookshelf session store
- added session table to database
- added import for databaseVersion 001
- added grunt task test-api
- cleanup of gruntfile to start express when needed only
- moved api tests to functional tests
This commit is contained in:
Sebastian Gierlinger 2013-11-24 15:29:36 +01:00
parent 7d98fab6c1
commit 3f2258e95b
23 changed files with 394 additions and 161 deletions

View File

@ -197,14 +197,10 @@ var path = require('path'),
timeout: '15000'
},
all: {
unit: {
src: ['core/test/unit/**/*_spec.js']
},
api: {
src: ['core/test/integration/**/api*_spec.js']
},
model: {
src: ['core/test/integration/**/model*_spec.js']
},
@ -233,10 +229,11 @@ var path = require('path'),
},
integration: {
src: [
'core/test/integration/**/model*_spec.js',
'core/test/integration/**/api*_spec.js'
]
src: ['core/test/integration/**/model*_spec.js']
},
api: {
src: ['core/test/functional/api/*_test.js']
}
},
@ -872,13 +869,15 @@ var path = require('path'),
// ## Running the test suites
grunt.registerTask('test-unit', 'Run unit tests', ['clean:test', 'setTestEnv', 'loadConfig', 'express:test', 'mochacli:all', 'express:test:stop']);
grunt.registerTask('test-unit', 'Run unit tests', ['clean:test', 'setTestEnv', 'loadConfig', 'mochacli:unit']);
grunt.registerTask('test-integration', 'Run integration tests', ['clean:test', 'setTestEnv', 'loadConfig', 'express:test', 'mochacli:integration', 'express:test:stop']);
grunt.registerTask('test-integration', 'Run integration tests', ['clean:test', 'setTestEnv', 'loadConfig', 'mochacli:integration']);
grunt.registerTask('test-functional', 'Run casperjs tests only', ['clean:test', 'setTestEnv', 'loadConfig', 'express:test', 'spawn-casperjs', 'express:test:stop']);
grunt.registerTask('validate', 'Run tests and lint code', ['jslint', 'test-unit', 'test-integration', 'test-functional']);
grunt.registerTask('test-api', 'Run functional api tests only', ['clean:test', 'setTestEnv', 'loadConfig', 'express:test', 'mochacli:api', 'express:test:stop']);
grunt.registerTask('validate', 'Run tests and lint code', ['jslint', 'test-unit', 'test-integration', 'test-api', 'test-functional']);
// ## Coverage report for Unit and Integration Tests

106
core/bookshelf-session.js Normal file
View File

@ -0,0 +1,106 @@
var Store = require('express').session.Store,
time12h = 12 * 60 * 60 * 1000,
BSStore,
dataProvider,
db,
client;
// Initialize store and clean old sessions
BSStore = function BSStore(dataProvider, options) {
var self = this;
this.dataProvider = dataProvider;
options = options || {};
Store.call(this, options);
this.dataProvider.Session.findAll()
.then(function (model) {
var i,
now = new Date().getTime();
for (i = 0; i < model.length; i = i + 1) {
if (now > model.at(i).get('expires')) {
self.destroy(model.at(i).get('id'));
}
}
});
};
BSStore.prototype = new Store();
// store a given session
BSStore.prototype.set = function (sid, sessData, callback) {
var maxAge = sessData.cookie.maxAge,
now = new Date().getTime(),
expires = maxAge ? now + maxAge : now + time12h,
sessionModel = this.dataProvider.Session;
sessData = JSON.stringify(sessData);
//necessary since bookshelf updates models if id is set
sessionModel.forge({id: sid}).fetch()
.then(function (model) {
if (model) {
sessionModel.forge({id: sid, expires: expires, sess: sessData }).save();
} else {
sessionModel.forge({id: sid, expires: expires, sess: sessData })
.save(null, {method: 'insert'});
}
callback();
});
};
// fetch a session, if session is expired delete it
BSStore.prototype.get = function (sid, callback) {
var now = new Date().getTime(),
self = this,
sess,
expires;
this.dataProvider.Session.forge({id: sid})
.fetch()
.then(function (model) {
if (model) {
sess = JSON.parse(model.get('sess'));
expires = model.get('expires');
if (now < expires) {
callback(null, sess);
} else {
self.destroy(sid, callback);
}
} else {
callback();
}
});
};
// delete a given sessions
BSStore.prototype.destroy = function (sid, callback) {
this.dataProvider.Session.forge({id: sid})
.destroy()
.then(function () {
// check if callback is null
// session.regenerate doesn't provide callback
// cleanup at startup does neither
if (callback) {
callback();
}
});
};
// get the count of all stored sessions
BSStore.prototype.length = function (callback) {
this.dataProvider.Session.findAll()
.then(function (model) {
callback(null, model.length);
});
};
// delete all sessions
BSStore.prototype.clear = function (callback) {
this.dataProvider.Session.destroyAll()
.then(function () {
callback();
});
};
module.exports = BSStore;

View File

@ -133,7 +133,7 @@ db = {
};
return api.notifications.add(notification).then(function () {
delete req.session.user;
req.session.destroy();
res.set({
"X-Cache-Invalidate": "/*"
});

View File

@ -84,9 +84,13 @@ adminControllers = {
if (!denied) {
loginSecurity.push({ip: req.connection.remoteAddress, time: process.hrtime()[0]});
api.users.check({email: req.body.email, pw: req.body.password}).then(function (user) {
req.session.user = user.id;
res.json(200, {redirect: req.body.redirect ? '/ghost/'
+ decodeURIComponent(req.body.redirect) : '/ghost/'});
req.session.regenerate(function (err) {
if (!err) {
req.session.user = user.id;
res.json(200, {redirect: req.body.redirect ? '/ghost/'
+ decodeURIComponent(req.body.redirect) : '/ghost/'});
}
});
}, function (error) {
res.json(401, {error: error.message});
});
@ -125,10 +129,14 @@ adminControllers = {
password: password
}).then(function (user) {
api.settings.edit('email', email).then(function () {
if (req.session.user === undefined) {
req.session.user = user.id;
}
res.json(200, {redirect: '/ghost/'});
req.session.regenerate(function (err) {
if (!err) {
if (req.session.user === undefined) {
req.session.user = user.id;
}
res.json(200, {redirect: '/ghost/'});
}
});
});
}).otherwise(function (error) {
res.json(401, {error: error.message});
@ -230,7 +238,7 @@ adminControllers = {
});
},
'logout': function (req, res) {
req.session = null;
req.session.destroy();
var notification = {
type: 'success',
message: 'You were successfully signed out',

View File

@ -1,7 +1,7 @@
{
"core": {
"databaseVersion": {
"defaultValue": "000"
"defaultValue": "001"
}
},
"blog": {

View File

@ -4,6 +4,7 @@ var when = require('when'),
knex = require('../../models/base').knex,
schema = require('../schema'),
excludedTables = ['sessions'],
exporter;
exporter = function () {
@ -13,7 +14,9 @@ exporter = function () {
var version = results[0],
tables = results[1],
selectOps = _.map(tables, function (name) {
return knex(name).select();
if (excludedTables.indexOf(name) < 0) {
return knex(name).select();
}
});
return when.all(selectOps).then(function (tableData) {

View File

@ -12,8 +12,7 @@ Importer000 = function () {
this.importFrom = {
'000': this.basicImport,
'001': this.tempImport,
'002': this.tempImport
'001': this.basicImport
};
};

View File

@ -0,0 +1,8 @@
var Importer000 = require('./000');
module.exports = {
Importer001: Importer000,
importData: function (data) {
return new Importer000.importData(data);
}
};

View File

@ -81,6 +81,11 @@ var db = {
role_id: {type: 'integer', nullable: false},
permission_id: {type: 'integer', nullable: false}
},
sessions: {
id: {type: 'string', nullable: false, primary: true},
expires: {type: 'bigInteger', nullable: false},
sess: {type: 'string', maxlength: 4096, nullable: false}
},
settings: {
id: {type: 'increments', nullable: false, primary: true},
uuid: {type: 'string', maxlength: 36, nullable: false},
@ -113,5 +118,4 @@ var db = {
}
};
module.exports = db;

View File

@ -9,6 +9,7 @@ var middleware = require('./middleware'),
Ghost = require('../../ghost'),
storage = require('../storage'),
packageInfo = require('../../../package.json'),
BSStore = require('../../bookshelf-session'),
ghost = new Ghost();
@ -166,8 +167,14 @@ module.exports = function (server) {
server.use('/ghost/upload/', express.multipart());
server.use('/ghost/upload/', express.multipart({uploadDir: corePath + '/content/images'}));
server.use('/ghost/api/v0.1/db/', express.multipart());
server.use(express.cookieParser(ghost.dbHash));
server.use(express.cookieSession({ cookie : { maxAge: 12 * 60 * 60 * 1000 }}));
// Session handling
server.use(express.cookieParser());
server.use(express.session({
store: new BSStore(ghost.dataProvider),
secret: ghost.dbHash,
cookie: { maxAge: 12 * 60 * 60 * 1000 }
}));
//enable express csrf protection
server.use(express.csrf());

View File

@ -8,6 +8,8 @@ module.exports = {
Settings: require('./settings').Settings,
Tag: require('./tag').Tag,
Base: require('./base'),
Session: require('./session').Session,
init: function () {
return migrations.init();
},

View File

@ -0,0 +1,32 @@
var ghostBookshelf = require('./base'),
Session,
Sessions;
Session = ghostBookshelf.Model.extend({
tableName: 'sessions',
permittedAttributes: ['id', 'expires', 'sess'],
saving: function () {
// Remove any properties which don't belong on the session model
this.attributes = this.pick(this.permittedAttributes);
}
}, {
destroyAll: function (options) {
options = options || {};
return ghostBookshelf.Collection.forge([], {model: this}).fetch().
then(function (collection) {
collection.invokeThen('destroy', options);
});
}
});
Sessions = ghostBookshelf.Collection.extend({
model: Session
});
module.exports = {
Session: Session,
Sessions: Sessions
};

View File

@ -14,17 +14,12 @@ describe('Post API', function () {
before(function (done) {
testUtils.clearData()
.then(function () {
done();
}, done);
});
beforeEach(function (done) {
testUtils.initData()
return testUtils.initData();
})
.then(function () {
return testUtils.insertDefaultFixtures();
})
.then(function () {
// do a get request to get the CSRF token first
request.get(testUtils.API.getSigninURL(), function (error, response, body) {
response.should.have.status(200);
var pattern_meta = /<meta.*?name="csrf-param".*?content="(.*?)".*?>/i;
@ -32,21 +27,19 @@ describe('Post API', function () {
csrfToken = body.match(pattern_meta)[1];
setTimeout((function () {
request.post({uri: testUtils.API.getSigninURL(),
headers: {'X-CSRF-Token': csrfToken}}, function (error, response, body) {
headers: {'X-CSRF-Token': csrfToken}}, function (error, response, body) {
response.should.have.status(200);
done();
request.get(testUtils.API.getAdminURL(), function (error, response, body) {
response.should.have.status(200);
csrfToken = body.match(pattern_meta)[1];
done();
});
}).form({email: user.email, password: user.password});
}), 2000);
});
}, done);
});
afterEach(function (done) {
testUtils.clearData().then(function () {
done();
}, done);
});
it('can retrieve all posts', function (done) {
request.get(testUtils.API.getApiURL('posts/'), function (error, response, body) {
response.should.have.status(200);
@ -114,6 +107,60 @@ describe('Post API', function () {
});
});
it('can\'t retrieve non existent post', function (done) {
request.get(testUtils.API.getApiURL('posts/99/'), function (error, response, body) {
response.should.have.status(404);
should.not.exist(response.headers['x-cache-invalidate']);
response.should.be.json;
var jsonResponse = JSON.parse(body);
jsonResponse.should.exist;
testUtils.API.checkResponseValue(jsonResponse, ['error']);
done();
});
});
it('can edit a post', function (done) {
request.get(testUtils.API.getApiURL('posts/1/'), function (error, response, body) {
var jsonResponse = JSON.parse(body),
changedValue = 'My new Title';
jsonResponse.should.exist;
jsonResponse.title = changedValue;
request.put({uri: testUtils.API.getApiURL('posts/1/'),
headers: {'X-CSRF-Token': csrfToken},
json: jsonResponse}, function (error, response, putBody) {
response.should.have.status(200);
response.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /' + putBody.slug + '/');
response.should.be.json;
putBody.should.exist;
putBody.title.should.eql(changedValue);
testUtils.API.checkResponse(putBody, 'post');
done();
});
});
});
it('can\'t edit non existent post', function (done) {
request.get(testUtils.API.getApiURL('posts/1/'), function (error, response, body) {
var jsonResponse = JSON.parse(body),
changedValue = 'My new Title';
jsonResponse.title.exist;
jsonResponse.testvalue = changedValue;
jsonResponse.id = 99;
request.put({uri: testUtils.API.getApiURL('posts/99/'),
headers: {'X-CSRF-Token': csrfToken},
json: jsonResponse}, function (error, response, putBody) {
response.should.have.status(404);
should.not.exist(response.headers['x-cache-invalidate']);
response.should.be.json;
testUtils.API.checkResponseValue(putBody, ['error']);
done();
});
});
});
it('can delete a post', function (done) {
var deletePostId = 1;
request.del({uri: testUtils.API.getApiURL('posts/' + deletePostId + '/'),
@ -171,57 +218,4 @@ describe('Post API', function () {
});
it('can\'t retrieve non existent post', function (done) {
request.get(testUtils.API.getApiURL('posts/99/'), function (error, response, body) {
response.should.have.status(404);
should.not.exist(response.headers['x-cache-invalidate']);
response.should.be.json;
var jsonResponse = JSON.parse(body);
jsonResponse.should.exist;
testUtils.API.checkResponseValue(jsonResponse, ['error']);
done();
});
});
it('can edit a post', function (done) {
request.get(testUtils.API.getApiURL('posts/1/'), function (error, response, body) {
var jsonResponse = JSON.parse(body),
changedValue = 'My new Title';
jsonResponse.should.exist;
jsonResponse.title = changedValue;
request.put({uri: testUtils.API.getApiURL('posts/1/'),
headers: {'X-CSRF-Token': csrfToken},
json: jsonResponse}, function (error, response, putBody) {
response.should.have.status(200);
response.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /' + putBody.slug + '/');
response.should.be.json;
putBody.should.exist;
putBody.title.should.eql(changedValue);
testUtils.API.checkResponse(putBody, 'post');
done();
});
});
});
it('can\'t edit non existent post', function (done) {
request.get(testUtils.API.getApiURL('posts/1/'), function (error, response, body) {
var jsonResponse = JSON.parse(body),
changedValue = 'My new Title';
jsonResponse.title.exist;
jsonResponse.testvalue = changedValue;
jsonResponse.id = 99;
request.put({uri: testUtils.API.getApiURL('posts/99/'),
headers: {'X-CSRF-Token': csrfToken},
json: jsonResponse}, function (error, response, putBody) {
response.should.have.status(404);
should.not.exist(response.headers['x-cache-invalidate']);
response.should.be.json;
testUtils.API.checkResponseValue(putBody, ['error']);
done();
});
});
});
});

View File

@ -14,17 +14,12 @@ describe('Settings API', function () {
before(function (done) {
testUtils.clearData()
.then(function () {
done();
}, done);
});
beforeEach(function (done) {
testUtils.initData()
return testUtils.initData();
})
.then(function () {
return testUtils.insertDefaultFixtures();
})
.then(function () {
// do a get request to get the CSRF token first
request.get(testUtils.API.getSigninURL(), function (error, response, body) {
response.should.have.status(200);
var pattern_meta = /<meta.*?name="csrf-param".*?content="(.*?)".*?>/i;
@ -32,21 +27,19 @@ describe('Settings API', function () {
csrfToken = body.match(pattern_meta)[1];
setTimeout((function () {
request.post({uri: testUtils.API.getSigninURL(),
headers: {'X-CSRF-Token': csrfToken}}, function (error, response, body) {
headers: {'X-CSRF-Token': csrfToken}}, function (error, response, body) {
response.should.have.status(200);
done();
request.get(testUtils.API.getAdminURL(), function (error, response, body) {
response.should.have.status(200);
csrfToken = body.match(pattern_meta)[1];
done();
});
}).form({email: user.email, password: user.password});
}), 2000);
});
}, done);
});
afterEach(function (done) {
testUtils.clearData().then(function () {
done();
}, done);
});
// TODO: currently includes values of type=core
it('can retrieve all settings', function (done) {
request.get(testUtils.API.getApiURL('settings/'), function (error, response, body) {

View File

@ -14,17 +14,12 @@ describe('Tag API', function () {
before(function (done) {
testUtils.clearData()
.then(function () {
done();
}, done);
});
beforeEach(function (done) {
testUtils.initData()
return testUtils.initData();
})
.then(function () {
return testUtils.insertDefaultFixtures();
})
.then(function () {
// do a get request to get the CSRF token first
request.get(testUtils.API.getSigninURL(), function (error, response, body) {
response.should.have.status(200);
var pattern_meta = /<meta.*?name="csrf-param".*?content="(.*?)".*?>/i;
@ -34,19 +29,17 @@ describe('Tag API', function () {
request.post({uri: testUtils.API.getSigninURL(),
headers: {'X-CSRF-Token': csrfToken}}, function (error, response, body) {
response.should.have.status(200);
done();
request.get(testUtils.API.getAdminURL(), function (error, response, body) {
response.should.have.status(200);
csrfToken = body.match(pattern_meta)[1];
done();
});
}).form({email: user.email, password: user.password});
}), 2000);
});
}, done);
});
afterEach(function (done) {
testUtils.clearData().then(function () {
done();
}, done);
});
it('can retrieve all tags', function (done) {
request.get(testUtils.API.getApiURL('tags/'), function (error, response, body) {
response.should.have.status(200);

View File

@ -14,17 +14,12 @@ describe('User API', function () {
before(function (done) {
testUtils.clearData()
.then(function () {
done();
}, done);
});
beforeEach(function (done) {
testUtils.initData()
return testUtils.initData();
})
.then(function () {
return testUtils.insertDefaultFixtures();
})
.then(function () {
// do a get request to get the CSRF token first
request.get(testUtils.API.getSigninURL(), function (error, response, body) {
response.should.have.status(200);
var pattern_meta = /<meta.*?name="csrf-param".*?content="(.*?)".*?>/i;
@ -34,19 +29,17 @@ describe('User API', function () {
request.post({uri: testUtils.API.getSigninURL(),
headers: {'X-CSRF-Token': csrfToken}}, function (error, response, body) {
response.should.have.status(200);
done();
request.get(testUtils.API.getAdminURL(), function (error, response, body) {
response.should.have.status(200);
csrfToken = body.match(pattern_meta)[1];
done();
});
}).form({email: user.email, password: user.password});
}), 2000);
});
}, done);
});
afterEach(function (done) {
testUtils.clearData().then(function () {
done();
}, done);
});
it('can retrieve all users', function (done) {
request.get(testUtils.API.getApiURL('users/'), function (error, response, body) {
response.should.have.status(200);

View File

@ -24,7 +24,7 @@
var host = casper.cli.options.host || 'localhost',
noPort = casper.cli.options.noPort || false,
port = casper.cli.options.port || '2368',
email = casper.cli.options.email || 'ghost@tryghost.org',
email = casper.cli.options.email || 'jbloggs@example.com',
password = casper.cli.options.password || 'Sl1m3rson',
url = "http://" + host + (noPort ? '/' : ":" + port + "/"),
newUser = {

View File

@ -29,6 +29,12 @@ describe('Settings Model', function () {
}, done);
});
after(function (done) {
testUtils.clearData().then(function () {
done();
}, done);
});
describe('API', function () {
it('can browse', function (done) {
@ -67,7 +73,6 @@ describe('Settings Model', function () {
});
it('can edit single', function (done) {
var firstSetting;
SettingsModel.browse().then(function (results) {
@ -149,7 +154,7 @@ describe('Settings Model', function () {
});
it('can delete', function (done) {
var firstSettingId;
var settingId;
SettingsModel.browse().then(function (results) {
@ -157,9 +162,11 @@ describe('Settings Model', function () {
results.length.should.be.above(0);
firstSettingId = results.models[0].id;
// dont't use results.models[0], since it will delete databaseversion
// which is used for testUtils.reset()
settingId = results.models[1].id;
return SettingsModel.destroy(firstSettingId);
return SettingsModel.destroy(settingId);
}).then(function () {
@ -172,7 +179,7 @@ describe('Settings Model', function () {
ids = _.pluck(newResults.models, "id");
hasDeletedId = _.any(ids, function (id) {
return id === firstSettingId;
return id === settingId;
});
hasDeletedId.should.equal(false);

View File

@ -36,7 +36,7 @@ describe("Exporter", function () {
it("exports data", function (done) {
// Stub migrations to return 000 as the current database version
var migrationStub = sinon.stub(migration, "getDatabaseVersion", function () {
return when.resolve("000");
return when.resolve("001");
});
exporter().then(function (exportData) {
@ -48,8 +48,8 @@ describe("Exporter", function () {
should.exist(exportData.meta);
should.exist(exportData.data);
exportData.meta.version.should.equal("000");
_.findWhere(exportData.data.settings, {key: "databaseVersion"}).value.should.equal("000");
exportData.meta.version.should.equal("001");
_.findWhere(exportData.data.settings, {key: "databaseVersion"}).value.should.equal("001");
_.each(tables, function (name) {
should.exist(exportData.data[name]);

View File

@ -34,6 +34,12 @@ describe("Ghost API", function () {
sandbox.restore();
});
after(function (done) {
testUtils.clearData().then(function () {
done();
}, done);
});
it("is a singleton", function () {
var ghost2 = new Ghost();

View File

@ -12,6 +12,7 @@ var testUtils = require('../utils'),
exporter = require('../../server/data/export'),
importer = require('../../server/data/import'),
Importer000 = require('../../server/data/import/000'),
Importer001 = require('../../server/data/import/001'),
fixtures = require('../../server/data/fixtures'),
Settings = require('../../server/models/settings').Settings;
@ -42,11 +43,29 @@ describe("Import", function () {
}).then(null, done);
});
it("resolves 001", function (done) {
var importStub = sinon.stub(Importer001, "importData", function () {
return when.resolve();
}),
fakeData = { test: true };
importer("001", fakeData).then(function () {
importStub.calledWith(fakeData).should.equal(true);
importStub.restore();
done();
}).then(null, done);
});
describe("000", function () {
should.exist(Importer000);
it("imports data from 000", function (done) {
it("imports data from 001", function (done) {
var exportData;
var migrationStub = sinon.stub(migration, "getDatabaseVersion", function () {
return when.resolve("000");
});
// migrate to current version
migration.migrateUp().then(function () {
@ -83,7 +102,58 @@ describe("Import", function () {
// test settings
importedData[2].length.should.be.above(0, 'Wrong number of settings');
_.findWhere(importedData[2], {key: "databaseVersion"}).value.should.equal("000", 'Wrong database version');
_.findWhere(importedData[2], {key: "databaseVersion"}).value.should.equal("001", 'Wrong database version');
// test tags
importedData[3].length.should.equal(exportData.data.tags.length, 'no new tags');
done();
}).then(null, done);
});
});
describe("001", function () {
should.exist(Importer001);
it("imports data from 001", function (done) {
var exportData;
// Migrate to version 001
migration.migrateUp().then(function () {
// Load the fixtures
return fixtures.populateFixtures();
}).then(function () {
// Initialise the default settings
return Settings.populateDefaults();
}).then(function () {
// export the version 000 data ready to import
// TODO: Should have static test data here?
return exporter();
}).then(function (exported) {
exportData = exported;
return importer("001", exportData);
}).then(function () {
// Grab the data from tables
return when.all([
knex("users").select(),
knex("posts").select(),
knex("settings").select(),
knex("tags").select()
]);
}).then(function (importedData) {
should.exist(importedData);
importedData.length.should.equal(4, 'Did not get data successfully');
// we always have 0 users as there isn't one in fixtures
importedData[0].length.should.equal(0, 'There should not be a user');
// import no longer requires all data to be dropped, and adds posts
importedData[1].length.should.equal(exportData.data.posts.length + 1, 'Wrong number of posts');
// test settings
importedData[2].length.should.be.above(0, 'Wrong number of settings');
_.findWhere(importedData[2], {key: "databaseVersion"}).value.should.equal("001", 'Wrong database version');
// test tags
importedData[3].length.should.equal(exportData.data.tags.length, 'no new tags');
@ -92,9 +162,8 @@ describe("Import", function () {
}).then(null, done);
});
it("doesn't imports invalid post data from 000", function (done) {
it("doesn't import invalid post data from 001", function (done) {
var exportData;
// migrate to current version
migration.migrateUp().then(function () {
// Load the fixtures
@ -111,11 +180,12 @@ describe("Import", function () {
//change title to 151 characters
exportData.data.posts[0].title = new Array(152).join('a');
exportData.data.posts[0].tags = 'Tag';
return importer("000", exportData);
return importer("001", exportData);
}).then(function () {
(1).should.eql(0, 'Data import should not resolve promise.');
}, function (error) {
error.should.eql('Error importing data: Post title maximum length is 150 characters.');
when.all([
knex("users").select(),
knex("posts").select(),
@ -132,7 +202,7 @@ describe("Import", function () {
// test settings
importedData[2].length.should.be.above(0, 'Wrong number of settings');
_.findWhere(importedData[2], {key: "databaseVersion"}).value.should.equal("000", 'Wrong database version');
_.findWhere(importedData[2], {key: "databaseVersion"}).value.should.equal("001", 'Wrong database version');
// test tags
importedData[3].length.should.equal(exportData.data.tags.length, 'no new tags');
@ -142,7 +212,7 @@ describe("Import", function () {
}).then(null, done);
});
it("doesn't imports invalid settings data from 000", function (done) {
it("doesn't import invalid settings data from 001", function (done) {
var exportData;
// migrate to current version
@ -160,7 +230,7 @@ describe("Import", function () {
exportData = exported;
//change to blank settings key
exportData.data.settings[3].key = null;
return importer("000", exportData);
return importer("001", exportData);
}).then(function () {
(1).should.eql(0, 'Data import should not resolve promise.');
}, function (error) {
@ -181,7 +251,7 @@ describe("Import", function () {
// test settings
importedData[2].length.should.be.above(0, 'Wrong number of settings');
_.findWhere(importedData[2], {key: "databaseVersion"}).value.should.equal("000", 'Wrong database version');
_.findWhere(importedData[2], {key: "databaseVersion"}).value.should.equal("001", 'Wrong database version');
// test tags
importedData[3].length.should.equal(exportData.data.tags.length, 'no new tags');
@ -192,4 +262,5 @@ describe("Import", function () {
}).then(null, done);
});
});
});

View File

@ -16,16 +16,14 @@ var testUtils = require('../utils'),
describe('Permissions', function () {
before(function (done) {
testUtils.clearData()
.then(function () {
testUtils.clearData().then(function () {
done();
}, done);
});
beforeEach(function (done) {
testUtils.initData()
.then(testUtils.insertDefaultUser)
.then(function () {
.then(testUtils.insertDefaultUser).then(function () {
done();
}, done);
});
@ -37,6 +35,12 @@ describe('Permissions', function () {
}, done);
});
after(function (done) {
testUtils.clearData().then(function () {
done();
}, done);
});
var testPerms = [
{ act: "edit", obj: "post" },
{ act: "edit", obj: "tag" },

View File

@ -27,6 +27,9 @@ function getApiURL (route) {
function getSigninURL () {
return url.resolve(schema + host + ':' + port, 'ghost/signin/');
}
function getAdminURL () {
return url.resolve(schema + host + ':' + port, 'ghost/');
}
// make sure the API only returns expected properties only
function checkResponse (jsonResponse, objectType) {
@ -42,6 +45,7 @@ function checkResponseValue (jsonResponse, properties) {
module.exports = {
getApiURL: getApiURL,
getSigninURL: getSigninURL,
getAdminURL: getAdminURL,
checkResponse: checkResponse,
checkResponseValue: checkResponseValue,
};