[WO-61] introduce invitation DAO

This commit is contained in:
Felix Hammerl 2013-11-20 12:17:21 +01:00
parent e71ee471f6
commit 6ad8683380
5 changed files with 249 additions and 26 deletions

View File

@ -1,9 +1,92 @@
define(function() {
'use strict';
/**
* The InvitationDAO is a high level Data Access Object that access the invitation service REST endpoint.
* @param {Object} restDao The REST Data Access Object abstraction
*/
var InvitationDAO = function(restDao) {
this._restDao = restDao;
};
//
// Constants
//
InvitationDAO.INVITE_MISSING = 1;
InvitationDAO.INVITE_PENDING = 2;
InvitationDAO.INVITE_SUCCESS = 4;
//
// API
//
/**
* Notes an invite for the recipient by the sender in the invitation web service
* @param {String} recipient User ID of the recipient
* @param {String} sender User ID of the sender
* @param {Function} callback(error, status) Returns information if the invitation worked (INVITE_SUCCESS), if an invitation is already pendin (INVITE_PENDING), or information if an error occurred.
*/
InvitationDAO.prototype.invite = function(recipient, sender, callback) {
this._restDao.put(null, uri(recipient, sender), completed);
function completed(error, res, status) {
if (error) {
callback(error);
return;
}
if (status === 201) {
callback(null, InvitationDAO.INVITE_SUCCESS);
return;
} else if (status === 304) {
callback(null, InvitationDAO.INVITE_PENDING);
return;
}
callback({
errMsg: 'unexpected invitation state'
});
}
};
/**
* Checks if an invitation for the recipient by the sender is present in the invitation web service
* @param {String} recipient User ID of the recipient
* @param {String} sender User ID of the sender
* @param {Function} callback(error, status) Returns information about the invitation status, either an invitation is already on place (INVITE_PENDING), or not (INVITE_MISSING), or information if an error occurred.
*/
InvitationDAO.prototype.check = function(recipient, sender, callback) {
this._restDao.get(null, uri(recipient, sender), completed);
function completed(error, res, status) {
// 404 is a meaningful return value from the web service
if (error && error.code !== 404) {
callback(error);
return;
}
if (error && error.code === 404) {
callback(null, InvitationDAO.INVITE_MISSING);
return;
} else if (status === 200) {
callback(null, InvitationDAO.INVITE_PENDING);
return;
}
callback({
errMsg: 'unexpected invitation state'
});
}
};
//
// Helper functions
//
function uri(a, b) {
return '/invitation/recipient/' + a + '/sender/' + b;
}
return InvitationDAO;
});

View File

@ -51,8 +51,8 @@ define(function(require) {
headers: {
'Accept': acceptHeader
},
success: function(res) {
callback(null, res);
success: function(res, textStatus, xhr) {
callback(null, res, xhr.status);
},
error: function(xhr, textStatus, err) {
callback({
@ -73,8 +73,8 @@ define(function(require) {
type: 'PUT',
data: JSON.stringify(item),
contentType: 'application/json',
success: function() {
callback();
success: function(res, textStatus, xhr) {
callback(null, res, xhr.status);
},
error: function(xhr, textStatus, err) {
callback({
@ -93,8 +93,8 @@ define(function(require) {
$.ajax({
url: this._baseUri + uri,
type: 'DELETE',
success: function() {
callback();
success: function(res, textStatus, xhr) {
callback(null, res, xhr.status);
},
error: function(xhr, textStatus, err) {
callback({

View File

@ -0,0 +1,122 @@
define(function(require) {
'use strict';
var RestDAO = require('js/dao/rest-dao'),
InvitationDAO = require('js/dao/invitation-dao'),
expect = chai.expect;
describe('Invitation DAO unit tests', function() {
var restDaoStub, invitationDao,
alice = 'zuhause@aol.com',
bob = 'manfred.mustermann@musterdomain.com',
expectedUri = '/invitation/recipient/' + alice + '/sender/' + bob;
beforeEach(function() {
restDaoStub = sinon.createStubInstance(RestDAO);
invitationDao = new InvitationDAO(restDaoStub);
});
describe('initialization', function() {
it('should wire up correctly', function() {
expect(invitationDao._restDao).to.equal(restDaoStub);
expect(invitationDao.invite).to.exist;
expect(InvitationDAO.INVITE_MISSING).to.equal(1);
expect(InvitationDAO.INVITE_PENDING).to.equal(2);
expect(InvitationDAO.INVITE_SUCCESS).to.equal(4);
});
});
describe('invite', function() {
it('should invite the recipient', function(done) {
restDaoStub.put.yieldsAsync(null, undefined, 201);
invitationDao.invite(alice, bob, function(err, status) {
expect(err).to.not.exist;
expect(status).to.equal(InvitationDAO.INVITE_SUCCESS);
expect(restDaoStub.put.calledWith(null, expectedUri)).to.be.true;
done();
});
});
it('should point out already invited recipient', function(done) {
restDaoStub.put.yieldsAsync(null, undefined, 304);
invitationDao.invite(alice, bob, function(err, status) {
expect(err).to.not.exist;
expect(status).to.equal(InvitationDAO.INVITE_PENDING);
done();
});
});
it('should not work for http error', function(done) {
restDaoStub.put.yieldsAsync({
errMsg: 'jawollja.'
});
invitationDao.invite(alice, bob, function(err, status) {
expect(err).to.exist;
expect(status).to.not.exist;
done();
});
});
it('should not work for unexpected response', function(done) {
restDaoStub.put.yieldsAsync(null, undefined, 1337);
invitationDao.invite(alice, bob, function(err, status) {
expect(err).to.exist;
expect(status).to.not.exist;
done();
});
});
});
describe('check', function() {
it('should return pending invite', function(done) {
restDaoStub.get.yieldsAsync(null, undefined, 200);
invitationDao.check(alice, bob, function(err, status) {
expect(err).to.not.exist;
expect(status).to.equal(InvitationDAO.INVITE_PENDING);
expect(restDaoStub.get.calledWith(null, expectedUri)).to.be.true;
done();
});
});
it('should return missing invite', function(done) {
restDaoStub.get.yieldsAsync({
code: 404
});
invitationDao.check(alice, bob, function(err, status) {
expect(err).to.not.exist;
expect(status).to.equal(InvitationDAO.INVITE_MISSING);
done();
});
});
it('should not work for http error', function(done) {
restDaoStub.get.yieldsAsync({
code: 1337,
errMsg: 'jawollja.'
});
invitationDao.check(alice, bob, function(err, status) {
expect(err).to.exist;
expect(status).to.not.exist;
done();
});
});
it('should not work for unexpected response', function(done) {
restDaoStub.get.yieldsAsync(null, undefined, 1337);
invitationDao.check(alice, bob, function(err, status) {
expect(err).to.exist;
expect(status).to.not.exist;
done();
});
});
});
});
});

View File

@ -48,7 +48,8 @@ function startTests() {
'test/new-unit/navigation-ctrl-test',
'test/new-unit/mail-list-ctrl-test',
'test/new-unit/write-ctrl-test',
'test/new-unit/outbox-bo-test'
'test/new-unit/outbox-bo-test',
'test/new-unit/invitation-dao-test'
], function() {
//Tests loaded, run tests
mocha.run();

View File

@ -10,14 +10,13 @@ define(function(require) {
var restDao;
beforeEach(function() {
sinon.stub($, 'ajax').yieldsTo('success', {
foo: 'bar'
});
restDao = new RestDAO();
});
afterEach(function() {
$.ajax.restore();
if (typeof $.ajax.callCount !== 'undefined') {
$.ajax.restore();
}
});
describe('contructor', function() {
@ -40,73 +39,81 @@ define(function(require) {
describe('get', function() {
it('should work with json as default type', function(done) {
$.ajax.restore();
var spy = sinon.stub($, 'ajax').yieldsTo('success', {
foo: 'bar'
}, 'success', {
status: 200
});
restDao.get({
uri: '/asdf',
type: 'json'
}, function(err, data) {
}, function(err, data, status) {
expect(err).to.not.exist;
expect(data.foo).to.equal('bar');
expect(spy.calledWith(sinon.match(function(request) {
return request.headers.Accept === 'application/json' && request.dataType === 'json';
}))).to.be.true;
expect(status).to.equal(200);
done();
});
});
it('should work with json', function(done) {
$.ajax.restore();
var spy = sinon.stub($, 'ajax').yieldsTo('success', {
foo: 'bar'
}, 'success', {
status: 200
});
restDao.get({
uri: '/asdf',
type: 'json'
}, function(err, data) {
}, function(err, data, status) {
expect(err).to.not.exist;
expect(data.foo).to.equal('bar');
expect(spy.calledWith(sinon.match(function(request) {
return request.headers.Accept === 'application/json' && request.dataType === 'json';
}))).to.be.true;
expect(status).to.equal(200);
done();
});
});
it('should work with plain text', function(done) {
$.ajax.restore();
var spy = sinon.stub($, 'ajax').yieldsTo('success', 'foobar!');
var spy = sinon.stub($, 'ajax').yieldsTo('success', 'foobar!', 'success', {
status: 200
});
restDao.get({
uri: '/asdf',
type: 'text'
}, function(err, data) {
}, function(err, data, status) {
expect(err).to.not.exist;
expect(data).to.equal('foobar!');
expect(spy.calledWith(sinon.match(function(request) {
return request.headers.Accept === 'text/plain' && request.dataType === 'text';
}))).to.be.true;
expect(status).to.equal(200);
done();
});
});
it('should work with xml', function(done) {
$.ajax.restore();
var spy = sinon.stub($, 'ajax').yieldsTo('success', '<foo>bar</foo>');
var spy = sinon.stub($, 'ajax').yieldsTo('success', '<foo>bar</foo>', 'success', {
status: 200
});
restDao.get({
uri: '/asdf',
type: 'xml'
}, function(err, data) {
}, function(err, data, status) {
expect(err).to.not.exist;
expect(data).to.equal('<foo>bar</foo>'); // that's probably not right, but in the unit test, it is :)
expect(spy.calledWith(sinon.match(function(request) {
return request.headers.Accept === 'application/xml' && request.dataType === 'xml';
}))).to.be.true;
expect(status).to.equal(200);
done();
});
});
@ -133,7 +140,6 @@ define(function(require) {
});
it('should fail for server error', function(done) {
$.ajax.restore();
sinon.stub($, 'ajax').yieldsTo('error', {
status: 500
}, {
@ -153,7 +159,6 @@ define(function(require) {
describe('put', function() {
it('should fail', function(done) {
$.ajax.restore();
sinon.stub($, 'ajax').yieldsTo('error', {
status: 500
}, {
@ -168,8 +173,15 @@ define(function(require) {
});
it('should work', function(done) {
restDao.put('/asdf', {}, function(err) {
var spy = sinon.stub($, 'ajax').yieldsTo('success', undefined, 'success', {
status: 201
});
restDao.put('/asdf', {}, function(err, res, status) {
expect(err).to.not.exist;
expect(res).to.not.exist;
expect(spy.callCount).to.equal(1);
expect(status).to.equal(201);
done();
});
});
@ -177,7 +189,6 @@ define(function(require) {
describe('remove', function() {
it('should fail', function(done) {
$.ajax.restore();
sinon.stub($, 'ajax').yieldsTo('error', {
status: 500
}, {
@ -192,8 +203,14 @@ define(function(require) {
});
it('should work', function(done) {
restDao.remove('/asdf', function(err) {
var spy = sinon.stub($, 'ajax').yieldsTo('success', undefined, 'success', {
status: 204
});
restDao.remove('/asdf', function(err, res, status) {
expect(err).to.not.exist;
expect(res).to.not.exist;
expect(spy.callCount).to.equal(1);
expect(status).to.equal(204);
done();
});
});