WIP add unit tests

This commit is contained in:
Felix Hammerl 2014-10-07 20:32:23 +02:00
parent c36cd069e0
commit 9bfda73969
40 changed files with 9527 additions and 9675 deletions

2
.gitignore vendored
View File

@ -8,3 +8,5 @@ dist/
release/
test/integration/src/
.elasticbeanstalk/
test/unit/index.js
test/unit/index.js.map

View File

@ -18,19 +18,18 @@
"unused": true,
"predef": [
"self",
"console",
"Notification",
"importScripts",
"process",
"Event",
"process",
"chrome",
"define",
"self",
"Notification",
"Event",
"sinon",
"mocha",
"chai",
"expect",
"describe",
"it",
"chai",
"sinon",
"mocha",
"before",
"beforeEach",
"after",

View File

@ -1,6 +1,8 @@
module.exports = function(grunt) {
'use strict';
require('time-grunt')(grunt);
var version = grunt.option('release'),
zipName = (version) ? version : 'DEV';
@ -24,7 +26,7 @@ module.exports = function(grunt) {
},
jshint: {
all: ['Gruntfile.js', 'src/*.js', 'src/js/**/*.js', 'test/unit/*.js', 'test/integration/*.js'],
all: ['Gruntfile.js', 'src/*.js', 'src/js/**/*.js', 'test/unit/*-test.js', 'test/integration/*.js'],
options: {
jshintrc: '.jshintrc'
}
@ -109,16 +111,22 @@ module.exports = function(grunt) {
'dist/js/app.min.js': ['src/js/app.js']
},
options: {
external: ['node-forge', 'net', 'tls'] // common.js apis not required at build time
external: []
}
},
/* TODO:
tls-worker: {},
mailreader-worker: {},
pbkdf2-worker: {},
unitTest: {},
unitTest: {},
integrationTest: {}
unitTest: {
files: {
'test/unit/index.js': ['test/unit/*-test.js']
},
options: {
external: []
}
},
/*
TODO:
mailreader-worker: {},
pbkdf2-worker: {},
integrationTest: {}
*/
},
@ -126,6 +134,7 @@ module.exports = function(grunt) {
all: {
files: {
'dist/js/app.min.js': [
'src/lib/openpgp/openpgp.js',
'src/lib/underscore/underscore-min.js',
'node_modules/jquery/dist/jquery.min.js',
'src/lib/angular/angular.min.js',
@ -142,6 +151,28 @@ module.exports = function(grunt) {
]
}
},
unitTest: {
files: {
'test/unit/index.js': [
'src/lib/underscore/underscore-min.js',
'node_modules/jquery/dist/jquery.min.js',
'src/lib/openpgp/openpgp.js',
'src/lib/angular/angular.min.js',
'node_modules/angular-mocks/angular-mocks.js',
'src/lib/angular/angular-route.min.js',
'src/lib/angular/angular-animate.min.js',
'src/lib/ngtagsinput/ng-tags-input.min.js',
'src/lib/fastclick/fastclick.js',
'node_modules/ng-infinite-scroll/build/ng-infinite-scroll.min.js',
'src/lib/lawnchair/lawnchair-git.js',
'src/lib/lawnchair/lawnchair-adapter-webkit-sqlite-git.js',
'src/lib/lawnchair/lawnchair-adapter-indexed-db-git.js',
'node_modules/dompurify/purify.js',
'test/lib/angular-mocks.js',
'test/unit/index.js'
]
}
},
options: {
banner: '/*! Copyright © <%= grunt.template.today("yyyy") %>, Whiteout Networks GmbH.*/\n'
}
@ -152,7 +183,7 @@ module.exports = function(grunt) {
expand: true,
flatten: true,
cwd: 'node_modules/',
src: ['requirejs/require.js', 'mocha/mocha.css', 'mocha/mocha.js', 'chai/chai.js', 'sinon/pkg/sinon.js', 'angularjs/src/ngMock/angular-mocks.js', 'browsercrow/src/*.js', 'browsersmtp/src/*.js'],
src: ['mocha/mocha.css', 'mocha/mocha.js', 'chai/chai.js', 'sinon/pkg/sinon.js', 'browsercrow/src/*.js', 'browsersmtp/src/*.js'],
dest: 'test/lib/'
},
font: {

View File

@ -1,70 +1,72 @@
{
"name": "whiteout-mail",
"version": "0.0.1",
"description": "Mail App with integrated OpenPGP encryption.",
"author": "Whiteout Networks",
"homepage": "https://whiteout.io",
"repository": {
"type": "git",
"url": "https://github.com/whiteout-io/mail-html5.git"
},
"keywords": [
"email",
"mail",
"client",
"app",
"openpgp",
"pgp",
"gpg",
"imap",
"smtp"
],
"engines": {
"node": ">=0.10"
},
"scripts": {
"test": "grunt && grunt test",
"start": "node server.js"
},
"dependencies": {
"axe-logger": "~0.0.2",
"compression": "^1.0.11",
"config": "^1.0.2",
"crypto-lib": "~0.2.1",
"dompurify": "~0.4.2",
"express": "^4.8.3",
"imap-client": "~0.4.3",
"jquery": "~2.1.1",
"mailreader": "~0.3.5",
"morgan": "^1.2.3",
"ng-infinite-scroll": "~1.1.2",
"npmlog": "^0.1.1",
"pgpbuilder": "~0.4.0",
"pgpmailer": "~0.4.0",
"socket.io": "^1.0.6",
"tcp-socket": "^0.3.9",
"wo-smtpclient": "^0.3.8"
},
"devDependencies": {
"angularjs": "https://github.com/whiteout-io/angular.js/tarball/npm-version",
"browsercrow": "https://github.com/whiteout-io/browsercrow/tarball/master",
"browsersmtp": "https://github.com/whiteout-io/browsersmtp/tarball/master",
"chai": "~1.7.2",
"grunt": "~0.4.1",
"grunt-autoprefixer": "~0.7.2",
"grunt-browserify": "^3.0.1",
"grunt-contrib-clean": "~0.5.0",
"grunt-contrib-compress": "~0.5.2",
"grunt-contrib-connect": "~0.5.0",
"grunt-contrib-copy": "~0.4.1",
"grunt-contrib-jshint": "~0.6.4",
"grunt-contrib-sass": "~0.7.3",
"grunt-contrib-uglify": "^0.6.0",
"grunt-contrib-watch": "~0.5.3",
"grunt-csso": "~0.6.1",
"grunt-manifest": "^0.4.0",
"grunt-mocha": "~0.4.1",
"mocha": "~1.13.0",
"sinon": "~1.7.3"
}
}
"name": "whiteout-mail",
"version": "0.0.1",
"description": "Mail App with integrated OpenPGP encryption.",
"author": "Whiteout Networks",
"homepage": "https://whiteout.io",
"repository": {
"type": "git",
"url": "https://github.com/whiteout-io/mail-html5.git"
},
"keywords": [
"email",
"mail",
"client",
"app",
"openpgp",
"pgp",
"gpg",
"imap",
"smtp"
],
"engines": {
"node": ">=0.10"
},
"scripts": {
"test": "grunt && grunt test",
"start": "node server.js"
},
"dependencies": {
"axe-logger": "~0.0.2",
"compression": "^1.0.11",
"config": "^1.0.2",
"crypto-lib": "~0.2.1",
"dompurify": "~0.4.2",
"express": "^4.8.3",
"imap-client": "~0.4.3",
"jquery": "~2.1.1",
"mailreader": "~0.3.5",
"morgan": "^1.2.3",
"ng-infinite-scroll": "~1.1.2",
"npmlog": "^0.1.1",
"pgpbuilder": "~0.4.0",
"pgpmailer": "~0.4.0",
"socket.io": "^1.0.6",
"tcp-socket": "^0.3.9",
"wo-smtpclient": "^0.3.8"
},
"devDependencies": {
"angular-mocks": "^1.2.25",
"angularjs": "https://github.com/whiteout-io/angular.js/tarball/npm-version",
"browsercrow": "https://github.com/whiteout-io/browsercrow/tarball/master",
"browsersmtp": "https://github.com/whiteout-io/browsersmtp/tarball/master",
"chai": "~1.7.2",
"grunt": "~0.4.1",
"grunt-autoprefixer": "~0.7.2",
"grunt-browserify": "^3.0.1",
"grunt-contrib-clean": "~0.5.0",
"grunt-contrib-compress": "~0.5.2",
"grunt-contrib-connect": "~0.5.0",
"grunt-contrib-copy": "~0.4.1",
"grunt-contrib-jshint": "~0.6.4",
"grunt-contrib-sass": "~0.7.3",
"grunt-contrib-uglify": "^0.6.0",
"grunt-contrib-watch": "~0.5.3",
"grunt-csso": "~0.6.1",
"grunt-manifest": "^0.4.0",
"grunt-mocha": "~0.4.1",
"mocha": "~1.13.0",
"sinon": "~1.7.3",
"time-grunt": "^1.0.0"
}
}

View File

@ -1,101 +1,97 @@
define(function(require) {
'use strict';
'use strict';
var expect = chai.expect,
angular = require('angular'),
mocks = require('angularMocks'),
AccountCtrl = require('js/controller/account'),
PGP = require('js/crypto/pgp'),
dl = require('js/util/download'),
appController = require('js/app-controller'),
KeychainDAO = require('js/dao/keychain-dao');
var mocks = angular.mocks,
AccountCtrl = require('../../src/js/controller/account'),
PGP = require('../../src/js/crypto/pgp'),
dl = require('../../src/js/util/download'),
appController = require('../../src/js/app-controller'),
KeychainDAO = require('../../src/js/dao/keychain-dao');
describe('Account Controller unit test', function() {
var scope, accountCtrl,
dummyFingerprint, expectedFingerprint,
dummyKeyId, expectedKeyId,
emailAddress, keySize, pgpMock, keychainMock;
describe('Account Controller unit test', function() {
var scope, accountCtrl,
dummyFingerprint, expectedFingerprint,
dummyKeyId, expectedKeyId,
emailAddress, keySize, pgpMock, keychainMock;
beforeEach(function() {
appController._pgp = pgpMock = sinon.createStubInstance(PGP);
appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO);
beforeEach(function() {
appController._pgp = pgpMock = sinon.createStubInstance(PGP);
appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO);
dummyFingerprint = '3A2D39B4E1404190B8B949DE7D7E99036E712926';
expectedFingerprint = '3A2D 39B4 E140 4190 B8B9 49DE 7D7E 9903 6E71 2926';
dummyKeyId = '9FEB47936E712926';
expectedKeyId = '6E712926';
pgpMock.getFingerprint.returns(dummyFingerprint);
pgpMock.getKeyId.returns(dummyKeyId);
emailAddress = 'fred@foo.com';
keySize = 1234;
appController._emailDao = {
_account: {
emailAddress: emailAddress,
asymKeySize: keySize
}
};
pgpMock.getKeyParams.returns({
_id: dummyKeyId,
fingerprint: dummyFingerprint,
userId: emailAddress,
bitSize: keySize
});
angular.module('accounttest', []);
mocks.module('accounttest');
mocks.inject(function($rootScope, $controller) {
scope = $rootScope.$new();
scope.state = {};
accountCtrl = $controller(AccountCtrl, {
$scope: scope
});
});
dummyFingerprint = '3A2D39B4E1404190B8B949DE7D7E99036E712926';
expectedFingerprint = '3A2D 39B4 E140 4190 B8B9 49DE 7D7E 9903 6E71 2926';
dummyKeyId = '9FEB47936E712926';
expectedKeyId = '6E712926';
pgpMock.getFingerprint.returns(dummyFingerprint);
pgpMock.getKeyId.returns(dummyKeyId);
emailAddress = 'fred@foo.com';
keySize = 1234;
appController._emailDao = {
_account: {
emailAddress: emailAddress,
asymKeySize: keySize
}
};
pgpMock.getKeyParams.returns({
_id: dummyKeyId,
fingerprint: dummyFingerprint,
userId: emailAddress,
bitSize: keySize
});
afterEach(function() {});
describe('scope variables', function() {
it('should be set correctly', function() {
expect(scope.eMail).to.equal(emailAddress);
expect(scope.keyId).to.equal(expectedKeyId);
expect(scope.fingerprint).to.equal(expectedFingerprint);
expect(scope.keysize).to.equal(keySize);
});
});
describe('export to key file', function() {
it('should work', function() {
var createDownloadMock = sinon.stub(dl, 'createDownload');
keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, {
publicKey: {
_id: dummyKeyId,
publicKey: 'a'
},
privateKey: {
encryptedKey: 'b'
}
});
createDownloadMock.withArgs(sinon.match(function(arg) {
return arg.content === 'a\r\nb' && arg.filename === 'whiteout_mail_' + emailAddress + '_' + expectedKeyId + '.asc' && arg.contentType === 'text/plain';
})).returns();
scope.exportKeyFile();
expect(scope.state.lightbox).to.equal(undefined);
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
expect(dl.createDownload.calledOnce).to.be.true;
dl.createDownload.restore();
});
it('should not work when key export failed', function(done) {
keychainMock.getUserKeyPair.yields(new Error('Boom!'));
scope.onError = function(err) {
expect(err.message).to.equal('Boom!');
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
done();
};
scope.exportKeyFile();
angular.module('accounttest', []);
mocks.module('accounttest');
mocks.inject(function($rootScope, $controller) {
scope = $rootScope.$new();
scope.state = {};
accountCtrl = $controller(AccountCtrl, {
$scope: scope
});
});
});
afterEach(function() {});
describe('scope variables', function() {
it('should be set correctly', function() {
expect(scope.eMail).to.equal(emailAddress);
expect(scope.keyId).to.equal(expectedKeyId);
expect(scope.fingerprint).to.equal(expectedFingerprint);
expect(scope.keysize).to.equal(keySize);
});
});
describe('export to key file', function() {
it('should work', function() {
var createDownloadMock = sinon.stub(dl, 'createDownload');
keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, {
publicKey: {
_id: dummyKeyId,
publicKey: 'a'
},
privateKey: {
encryptedKey: 'b'
}
});
createDownloadMock.withArgs(sinon.match(function(arg) {
return arg.content === 'a\r\nb' && arg.filename === 'whiteout_mail_' + emailAddress + '_' + expectedKeyId + '.asc' && arg.contentType === 'text/plain';
})).returns();
scope.exportKeyFile();
expect(scope.state.lightbox).to.equal(undefined);
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
expect(dl.createDownload.calledOnce).to.be.true;
dl.createDownload.restore();
});
it('should not work when key export failed', function(done) {
keychainMock.getUserKeyPair.yields(new Error('Boom!'));
scope.onError = function(err) {
expect(err.message).to.equal('Boom!');
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
done();
};
scope.exportKeyFile();
});
});
});

View File

@ -1,216 +1,212 @@
define(function(require) {
'use strict';
'use strict';
var expect = chai.expect,
angular = require('angular'),
mocks = require('angularMocks'),
AddAccountCtrl = require('js/controller/add-account'),
Auth = require('js/bo/auth'),
AdminDao = require('js/dao/admin-dao'),
appController = require('js/app-controller');
var mocks = angular.mocks,
AddAccountCtrl = require('../../src/js/controller/add-account'),
Auth = require('../../src/js/bo/auth'),
AdminDao = require('../../src/js/dao/admin-dao'),
appController = require('../../src/js/app-controller');
describe('Add Account Controller unit test', function() {
var scope, location, ctrl, authStub, origAuth, adminStub;
describe('Add Account Controller unit test', function() {
var scope, location, ctrl, authStub, origAuth, adminStub;
beforeEach(function() {
// remember original module to restore later, then replace it
origAuth = appController._auth;
appController._auth = authStub = sinon.createStubInstance(Auth);
appController._adminDao = adminStub = sinon.createStubInstance(AdminDao);
beforeEach(function() {
// remember original module to restore later, then replace it
origAuth = appController._auth;
appController._auth = authStub = sinon.createStubInstance(Auth);
appController._adminDao = adminStub = sinon.createStubInstance(AdminDao);
angular.module('addaccounttest', []);
mocks.module('addaccounttest');
mocks.inject(function($controller, $rootScope, $location) {
location = $location;
scope = $rootScope.$new();
scope.state = {};
scope.form = {};
scope.formValidate = {};
angular.module('addaccounttest', []);
mocks.module('addaccounttest');
mocks.inject(function($controller, $rootScope, $location) {
location = $location;
scope = $rootScope.$new();
scope.state = {};
scope.form = {};
scope.formValidate = {};
sinon.stub(location, 'path').returns(location);
sinon.stub(location, 'search').returns(location);
sinon.stub(scope, '$apply', function() {});
sinon.stub(location, 'path').returns(location);
sinon.stub(location, 'search').returns(location);
sinon.stub(scope, '$apply', function() {});
ctrl = $controller(AddAccountCtrl, {
$location: location,
$scope: scope,
$routeParams: {}
});
ctrl = $controller(AddAccountCtrl, {
$location: location,
$scope: scope,
$routeParams: {}
});
});
afterEach(function() {
// restore the app controller module
appController._auth = origAuth;
location.path.restore();
location.search.restore();
if (scope.$apply.restore) {
scope.$apply.restore();
}
});
describe('createWhiteoutAccount', function() {
it('should return early for invalid form', function() {
scope.form.$invalid = true;
scope.createWhiteoutAccount();
expect(adminStub.createUser.called).to.be.false;
});
it('should fail to error creating user', function(done) {
scope.form.$invalid = false;
scope.betaCode = 'asfd';
scope.phone = '12345';
adminStub.createUser.yieldsAsync(new Error('asdf'));
scope.$apply = function() {
expect(scope.busy).to.be.false;
expect(scope.errMsg).to.equal('asdf');
expect(adminStub.createUser.calledOnce).to.be.true;
done();
};
scope.createWhiteoutAccount();
expect(scope.busy).to.be.true;
});
it('should work', function(done) {
scope.form.$invalid = false;
scope.betaCode = 'asfd';
scope.phone = '12345';
adminStub.createUser.yieldsAsync();
scope.$apply = function() {
expect(scope.busy).to.be.false;
expect(scope.errMsg).to.be.undefined;
expect(scope.step).to.equal(3);
expect(adminStub.createUser.calledOnce).to.be.true;
done();
};
scope.createWhiteoutAccount();
expect(scope.busy).to.be.true;
});
});
describe('validateUser', function() {
it('should return early for invalid form', function() {
scope.formValidate.$invalid = true;
scope.validateUser();
expect(adminStub.validateUser.called).to.be.false;
});
it('should fail to error creating user', function(done) {
scope.formValidate.$invalid = false;
scope.token = 'asfd';
adminStub.validateUser.yieldsAsync(new Error('asdf'));
scope.$apply = function() {
expect(scope.busyValidate).to.be.false;
expect(scope.errMsgValidate).to.equal('asdf');
expect(adminStub.validateUser.calledOnce).to.be.true;
done();
};
scope.validateUser();
expect(scope.busyValidate).to.be.true;
});
it('should work', function(done) {
scope.formValidate.$invalid = false;
scope.token = 'asfd';
adminStub.validateUser.yieldsAsync();
scope.login = function() {
expect(scope.busyValidate).to.be.true;
expect(scope.errMsgValidate).to.be.undefined;
expect(adminStub.validateUser.calledOnce).to.be.true;
done();
};
scope.validateUser();
expect(scope.busyValidate).to.be.true;
});
});
describe('login', function() {
it('should work', function() {
scope.form.$invalid = false;
authStub.setCredentials.returns();
scope.login();
expect(authStub.setCredentials.calledOnce).to.be.true;
expect(location.path.calledWith('/login')).to.be.true;
});
});
describe('connectToGoogle', function() {
it('should forward to login', function() {
authStub._oauth = {
isSupported: function() {
return true;
}
};
authStub.getOAuthToken.yields();
scope.connectToGoogle();
expect(location.path.calledWith('/login-set-credentials')).to.be.true;
expect(location.search.calledWith({
provider: 'gmail'
})).to.be.true;
expect(authStub.getOAuthToken.calledOnce).to.be.true;
});
it('should not use oauth for gmail', function() {
authStub._oauth = {
isSupported: function() {
return false;
}
};
scope.connectToGoogle();
expect(location.path.calledWith('/login-set-credentials')).to.be.true;
expect(location.search.calledWith({
provider: 'gmail'
})).to.be.true;
expect(authStub.getOAuthToken.called).to.be.false;
});
it('should not forward to login when oauth fails', function(done) {
authStub._oauth = {
isSupported: function() {
return true;
}
};
authStub.getOAuthToken.yields(new Error());
scope.onError = function(err) {
expect(err).to.exist;
expect(location.path.called).to.be.false;
expect(location.search.called).to.be.false;
done();
};
scope.connectToGoogle();
});
});
describe('connectTo', function() {
it('should forward to login', function() {
var provider = 'wmail';
scope.connectTo(provider);
expect(location.path.calledWith('/login-set-credentials')).to.be.true;
expect(location.search.calledWith({
provider: provider
})).to.be.true;
});
});
});
afterEach(function() {
// restore the app controller module
appController._auth = origAuth;
location.path.restore();
location.search.restore();
if (scope.$apply.restore) {
scope.$apply.restore();
}
});
describe('createWhiteoutAccount', function() {
it('should return early for invalid form', function() {
scope.form.$invalid = true;
scope.createWhiteoutAccount();
expect(adminStub.createUser.called).to.be.false;
});
it('should fail to error creating user', function(done) {
scope.form.$invalid = false;
scope.betaCode = 'asfd';
scope.phone = '12345';
adminStub.createUser.yieldsAsync(new Error('asdf'));
scope.$apply = function() {
expect(scope.busy).to.be.false;
expect(scope.errMsg).to.equal('asdf');
expect(adminStub.createUser.calledOnce).to.be.true;
done();
};
scope.createWhiteoutAccount();
expect(scope.busy).to.be.true;
});
it('should work', function(done) {
scope.form.$invalid = false;
scope.betaCode = 'asfd';
scope.phone = '12345';
adminStub.createUser.yieldsAsync();
scope.$apply = function() {
expect(scope.busy).to.be.false;
expect(scope.errMsg).to.be.undefined;
expect(scope.step).to.equal(3);
expect(adminStub.createUser.calledOnce).to.be.true;
done();
};
scope.createWhiteoutAccount();
expect(scope.busy).to.be.true;
});
});
describe('validateUser', function() {
it('should return early for invalid form', function() {
scope.formValidate.$invalid = true;
scope.validateUser();
expect(adminStub.validateUser.called).to.be.false;
});
it('should fail to error creating user', function(done) {
scope.formValidate.$invalid = false;
scope.token = 'asfd';
adminStub.validateUser.yieldsAsync(new Error('asdf'));
scope.$apply = function() {
expect(scope.busyValidate).to.be.false;
expect(scope.errMsgValidate).to.equal('asdf');
expect(adminStub.validateUser.calledOnce).to.be.true;
done();
};
scope.validateUser();
expect(scope.busyValidate).to.be.true;
});
it('should work', function(done) {
scope.formValidate.$invalid = false;
scope.token = 'asfd';
adminStub.validateUser.yieldsAsync();
scope.login = function() {
expect(scope.busyValidate).to.be.true;
expect(scope.errMsgValidate).to.be.undefined;
expect(adminStub.validateUser.calledOnce).to.be.true;
done();
};
scope.validateUser();
expect(scope.busyValidate).to.be.true;
});
});
describe('login', function() {
it('should work', function() {
scope.form.$invalid = false;
authStub.setCredentials.returns();
scope.login();
expect(authStub.setCredentials.calledOnce).to.be.true;
expect(location.path.calledWith('/login')).to.be.true;
});
});
describe('connectToGoogle', function() {
it('should forward to login', function() {
authStub._oauth = {
isSupported: function() {
return true;
}
};
authStub.getOAuthToken.yields();
scope.connectToGoogle();
expect(location.path.calledWith('/login-set-credentials')).to.be.true;
expect(location.search.calledWith({
provider: 'gmail'
})).to.be.true;
expect(authStub.getOAuthToken.calledOnce).to.be.true;
});
it('should not use oauth for gmail', function() {
authStub._oauth = {
isSupported: function() {
return false;
}
};
scope.connectToGoogle();
expect(location.path.calledWith('/login-set-credentials')).to.be.true;
expect(location.search.calledWith({
provider: 'gmail'
})).to.be.true;
expect(authStub.getOAuthToken.called).to.be.false;
});
it('should not forward to login when oauth fails', function(done) {
authStub._oauth = {
isSupported: function() {
return true;
}
};
authStub.getOAuthToken.yields(new Error());
scope.onError = function(err) {
expect(err).to.exist;
expect(location.path.called).to.be.false;
expect(location.search.called).to.be.false;
done();
};
scope.connectToGoogle();
});
});
describe('connectTo', function() {
it('should forward to login', function() {
var provider = 'wmail';
scope.connectTo(provider);
expect(location.path.calledWith('/login-set-credentials')).to.be.true;
expect(location.search.calledWith({
provider: provider
})).to.be.true;
});
});
});

View File

@ -1,146 +1,142 @@
define(function(require) {
'use strict';
'use strict';
var RestDAO = require('js/dao/rest-dao'),
AdminDAO = require('js/dao/admin-dao'),
expect = chai.expect;
var RestDAO = require('../../src/js/dao/rest-dao'),
AdminDAO = require('../../src/js/dao/admin-dao');
describe('Admin DAO unit tests', function() {
describe('Admin DAO unit tests', function() {
var adminDao, restDaoStub,
emailAddress = 'test@example.com',
password = 'secret';
var adminDao, restDaoStub,
emailAddress = 'test@example.com',
password = 'secret';
beforeEach(function() {
restDaoStub = sinon.createStubInstance(RestDAO);
adminDao = new AdminDAO(restDaoStub);
});
beforeEach(function() {
restDaoStub = sinon.createStubInstance(RestDAO);
adminDao = new AdminDAO(restDaoStub);
});
afterEach(function() {});
afterEach(function() {});
describe('createUser', function() {
it('should fail due to incomplete args', function(done) {
var opt = {
emailAddress: emailAddress
};
describe('createUser', function() {
it('should fail due to incomplete args', function(done) {
var opt = {
emailAddress: emailAddress
};
adminDao.createUser(opt, function(err) {
expect(err).to.exist;
done();
});
});
it('should fail if user already exists', function(done) {
var opt = {
emailAddress: emailAddress,
password: password,
phone: '12345'
};
restDaoStub.post.withArgs(opt, '/user').yields({
code: 409
});
adminDao.createUser(opt, function(err) {
expect(err.message).to.contain('already taken');
expect(restDaoStub.post.calledOnce).to.be.true;
done();
});
});
it('should fail due to unknown error', function(done) {
var opt = {
emailAddress: emailAddress,
password: password,
phone: '12345'
};
restDaoStub.post.withArgs(opt, '/user').yields(new Error());
adminDao.createUser(opt, function(err) {
expect(err).to.exist;
expect(restDaoStub.post.calledOnce).to.be.true;
done();
});
});
it('should work', function(done) {
var opt = {
emailAddress: emailAddress,
password: password,
phone: '12345'
};
restDaoStub.post.withArgs(opt, '/user').yields();
adminDao.createUser(opt, function(err) {
expect(err).to.not.exist;
expect(restDaoStub.post.calledOnce).to.be.true;
done();
});
adminDao.createUser(opt, function(err) {
expect(err).to.exist;
done();
});
});
describe('validateUser', function() {
it('should fail due to incomplete args', function(done) {
var opt = {
emailAddress: emailAddress
};
it('should fail if user already exists', function(done) {
var opt = {
emailAddress: emailAddress,
password: password,
phone: '12345'
};
adminDao.validateUser(opt, function(err) {
expect(err).to.exist;
done();
});
restDaoStub.post.withArgs(opt, '/user').yields({
code: 409
});
it('should fail due to error in rest api', function(done) {
var opt = {
emailAddress: emailAddress,
token: 'H45Z6D'
};
restDaoStub.post.withArgs(opt, '/user/validate').yields(new Error());
adminDao.validateUser(opt, function(err) {
expect(err).to.exist;
expect(restDaoStub.post.calledOnce).to.be.true;
done();
});
});
it('should work with no error object', function(done) {
var opt = {
emailAddress: emailAddress,
token: 'H45Z6D'
};
restDaoStub.post.withArgs(opt, '/user/validate').yields();
adminDao.validateUser(opt, function(err) {
expect(err).to.not.exist;
expect(restDaoStub.post.calledOnce).to.be.true;
done();
});
});
it('should work with 202', function(done) {
var opt = {
emailAddress: emailAddress,
token: 'H45Z6D'
};
restDaoStub.post.withArgs(opt, '/user/validate').yields({
code: 202
});
adminDao.validateUser(opt, function(err) {
expect(err).to.not.exist;
expect(restDaoStub.post.calledOnce).to.be.true;
done();
});
adminDao.createUser(opt, function(err) {
expect(err.message).to.contain('already taken');
expect(restDaoStub.post.calledOnce).to.be.true;
done();
});
});
it('should fail due to unknown error', function(done) {
var opt = {
emailAddress: emailAddress,
password: password,
phone: '12345'
};
restDaoStub.post.withArgs(opt, '/user').yields(new Error());
adminDao.createUser(opt, function(err) {
expect(err).to.exist;
expect(restDaoStub.post.calledOnce).to.be.true;
done();
});
});
it('should work', function(done) {
var opt = {
emailAddress: emailAddress,
password: password,
phone: '12345'
};
restDaoStub.post.withArgs(opt, '/user').yields();
adminDao.createUser(opt, function(err) {
expect(err).to.not.exist;
expect(restDaoStub.post.calledOnce).to.be.true;
done();
});
});
});
describe('validateUser', function() {
it('should fail due to incomplete args', function(done) {
var opt = {
emailAddress: emailAddress
};
adminDao.validateUser(opt, function(err) {
expect(err).to.exist;
done();
});
});
it('should fail due to error in rest api', function(done) {
var opt = {
emailAddress: emailAddress,
token: 'H45Z6D'
};
restDaoStub.post.withArgs(opt, '/user/validate').yields(new Error());
adminDao.validateUser(opt, function(err) {
expect(err).to.exist;
expect(restDaoStub.post.calledOnce).to.be.true;
done();
});
});
it('should work with no error object', function(done) {
var opt = {
emailAddress: emailAddress,
token: 'H45Z6D'
};
restDaoStub.post.withArgs(opt, '/user/validate').yields();
adminDao.validateUser(opt, function(err) {
expect(err).to.not.exist;
expect(restDaoStub.post.calledOnce).to.be.true;
done();
});
});
it('should work with 202', function(done) {
var opt = {
emailAddress: emailAddress,
token: 'H45Z6D'
};
restDaoStub.post.withArgs(opt, '/user/validate').yields({
code: 202
});
adminDao.validateUser(opt, function(err) {
expect(err).to.not.exist;
expect(restDaoStub.post.calledOnce).to.be.true;
done();
});
});
});
});

View File

@ -1,212 +1,209 @@
define(function(require) {
'use strict';
'use strict';
var controller = require('js/app-controller'),
EmailDAO = require('js/dao/email-dao'),
OutboxBO = require('js/bo/outbox'),
DeviceStorageDAO = require('js/dao/devicestorage-dao'),
UpdateHandler = require('js/util/update/update-handler'),
Auth = require('js/bo/auth'),
expect = chai.expect;
var controller = require('../../src/js/app-controller'),
EmailDAO = require('../../src/js/dao/email-dao'),
OutboxBO = require('../../src/js/bo/outbox'),
DeviceStorageDAO = require('../../src/js/dao/devicestorage-dao'),
UpdateHandler = require('../../src/js/util/update/update-handler'),
Auth = require('../../src/js/bo/auth');
describe('App Controller unit tests', function() {
var emailDaoStub, outboxStub, updateHandlerStub, appConfigStoreStub, devicestorageStub, isOnlineStub, authStub;
describe('App Controller unit tests', function() {
var emailDaoStub, outboxStub, updateHandlerStub, appConfigStoreStub, devicestorageStub, isOnlineStub, authStub;
beforeEach(function() {
controller._emailDao = emailDaoStub = sinon.createStubInstance(EmailDAO);
controller._outboxBo = outboxStub = sinon.createStubInstance(OutboxBO);
controller._appConfigStore = appConfigStoreStub = sinon.createStubInstance(DeviceStorageDAO);
controller._userStorage = devicestorageStub = sinon.createStubInstance(DeviceStorageDAO);
controller._updateHandler = updateHandlerStub = sinon.createStubInstance(UpdateHandler);
controller._auth = authStub = sinon.createStubInstance(Auth);
isOnlineStub = sinon.stub(controller, 'isOnline');
});
afterEach(function() {
isOnlineStub.restore();
});
describe('buildModules', function() {
it('should work', function() {
controller.buildModules({
onError: function() {}
});
expect(controller._appConfigStore).to.exist;
expect(controller._auth).to.exist;
expect(controller._userStorage).to.exist;
expect(controller._invitationDao).to.exist;
expect(controller._keychain).to.exist;
expect(controller._pgp).to.exist;
expect(controller._pgpbuilder).to.exist;
expect(controller._emailDao).to.exist;
expect(controller._outboxBo).to.exist;
expect(controller._updateHandler).to.exist;
});
});
describe('start', function() {
it('should not explode', function(done) {
controller.start({
onError: function() {}
}, function(err) {
expect(err).to.not.exist;
done();
});
});
});
describe('onDisconnect', function() {
it('should work', function() {
controller.onDisconnect();
expect(emailDaoStub.onDisconnect.calledOnce).to.be.true;
});
});
describe('logout', function() {
it('should work', function(done) {
authStub.logout.yields();
emailDaoStub.onDisconnect.yields(new Error());
controller.onError = function(err) {
expect(err).to.exist;
expect(authStub.logout.calledOnce).to.be.true;
expect(emailDaoStub.onDisconnect.calledOnce).to.be.true;
done();
};
controller.logout();
});
});
describe('onConnect', function() {
beforeEach(function() {
controller._emailDao._account = {};
});
it('should not connect if offline', function(done) {
isOnlineStub.returns(false);
controller.onConnect(function(err) {
expect(err).to.not.exist;
done();
});
});
it('should not connect if account is not initialized', function(done) {
controller._emailDao._account = null;
controller.onConnect(function(err) {
expect(err).to.not.exist;
done();
});
});
it('should fail due to error in auth.getCredentials', function(done) {
isOnlineStub.returns(true);
authStub.getCredentials.yields(new Error());
controller.onConnect(function(err) {
expect(err).to.exist;
expect(authStub.getCredentials.calledOnce).to.be.true;
done();
});
});
it('should work', function(done) {
isOnlineStub.returns(true);
authStub.getCredentials.yields(null, {
emailAddress: 'asdf@example.com',
oauthToken: 'token',
sslCert: 'cert',
imap: {},
smtp: {}
});
emailDaoStub.onConnect.yields();
controller.onConnect(function(err) {
expect(err).to.not.exist;
expect(authStub.getCredentials.calledOnce).to.be.true;
expect(emailDaoStub.onConnect.calledOnce).to.be.true;
done();
});
});
});
describe('init', function() {
var onConnectStub, emailAddress;
beforeEach(function() {
controller._emailDao = emailDaoStub = sinon.createStubInstance(EmailDAO);
controller._outboxBo = outboxStub = sinon.createStubInstance(OutboxBO);
controller._appConfigStore = appConfigStoreStub = sinon.createStubInstance(DeviceStorageDAO);
controller._userStorage = devicestorageStub = sinon.createStubInstance(DeviceStorageDAO);
controller._updateHandler = updateHandlerStub = sinon.createStubInstance(UpdateHandler);
controller._auth = authStub = sinon.createStubInstance(Auth);
emailAddress = 'alice@bob.com';
isOnlineStub = sinon.stub(controller, 'isOnline');
// onConnect
onConnectStub = sinon.stub(controller, 'onConnect');
});
afterEach(function() {
isOnlineStub.restore();
onConnectStub.restore();
});
describe('buildModules', function() {
it('should work', function() {
controller.buildModules({
onError: function() {}
});
expect(controller._appConfigStore).to.exist;
expect(controller._auth).to.exist;
expect(controller._userStorage).to.exist;
expect(controller._invitationDao).to.exist;
expect(controller._keychain).to.exist;
expect(controller._pgp).to.exist;
expect(controller._pgpbuilder).to.exist;
expect(controller._emailDao).to.exist;
expect(controller._outboxBo).to.exist;
expect(controller._updateHandler).to.exist;
it('should fail due to error in storage initialization', function(done) {
devicestorageStub.init.withArgs(undefined).yields({});
controller.init({}, function(err, keypair) {
expect(err).to.exist;
expect(keypair).to.not.exist;
expect(devicestorageStub.init.calledOnce).to.be.true;
expect(updateHandlerStub.update.calledOnce).to.be.false;
done();
});
});
describe('start', function() {
it('should not explode', function(done) {
controller.start({
onError: function() {}
}, function(err) {
expect(err).to.not.exist;
done();
});
it('should fail due to error in update handler', function(done) {
devicestorageStub.init.yields();
updateHandlerStub.update.yields({});
controller.init({
emailAddress: emailAddress
}, function(err, keypair) {
expect(err).to.exist;
expect(keypair).to.not.exist;
expect(updateHandlerStub.update.calledOnce).to.be.true;
expect(devicestorageStub.init.calledOnce).to.be.true;
done();
});
});
describe('onDisconnect', function() {
it('should work', function() {
controller.onDisconnect();
it('should fail due to error in emailDao.init', function(done) {
devicestorageStub.init.yields();
updateHandlerStub.update.yields();
emailDaoStub.init.yields({});
expect(emailDaoStub.onDisconnect.calledOnce).to.be.true;
controller.init({
emailAddress: emailAddress
}, function(err, keypair) {
expect(err).to.exist;
expect(keypair).to.not.exist;
expect(updateHandlerStub.update.calledOnce).to.be.true;
expect(emailDaoStub.init.calledOnce).to.be.true;
expect(devicestorageStub.init.calledOnce).to.be.true;
done();
});
});
describe('logout', function() {
it('should work', function(done) {
authStub.logout.yields();
emailDaoStub.onDisconnect.yields(new Error());
it('should work and return a keypair', function(done) {
devicestorageStub.init.withArgs(emailAddress).yields();
emailDaoStub.init.yields(null, {});
updateHandlerStub.update.yields();
controller.onError = function(err) {
expect(err).to.exist;
expect(authStub.logout.calledOnce).to.be.true;
expect(emailDaoStub.onDisconnect.calledOnce).to.be.true;
done();
};
controller.logout();
});
});
describe('onConnect', function() {
beforeEach(function() {
controller._emailDao._account = {};
});
it('should not connect if offline', function(done) {
isOnlineStub.returns(false);
controller.onConnect(function(err) {
expect(err).to.not.exist;
done();
});
});
it('should not connect if account is not initialized', function(done) {
controller._emailDao._account = null;
controller.onConnect(function(err) {
expect(err).to.not.exist;
done();
});
});
it('should fail due to error in auth.getCredentials', function(done) {
isOnlineStub.returns(true);
authStub.getCredentials.yields(new Error());
controller.onConnect(function(err) {
expect(err).to.exist;
expect(authStub.getCredentials.calledOnce).to.be.true;
done();
});
});
it('should work', function(done) {
isOnlineStub.returns(true);
authStub.getCredentials.yields(null, {
emailAddress: 'asdf@example.com',
oauthToken: 'token',
sslCert: 'cert',
imap: {},
smtp: {}
});
emailDaoStub.onConnect.yields();
controller.onConnect(function(err) {
expect(err).to.not.exist;
expect(authStub.getCredentials.calledOnce).to.be.true;
expect(emailDaoStub.onConnect.calledOnce).to.be.true;
done();
});
});
});
describe('init', function() {
var onConnectStub, emailAddress;
beforeEach(function() {
emailAddress = 'alice@bob.com';
// onConnect
onConnectStub = sinon.stub(controller, 'onConnect');
});
afterEach(function() {
onConnectStub.restore();
});
it('should fail due to error in storage initialization', function(done) {
devicestorageStub.init.withArgs(undefined).yields({});
controller.init({}, function(err, keypair) {
expect(err).to.exist;
expect(keypair).to.not.exist;
expect(devicestorageStub.init.calledOnce).to.be.true;
expect(updateHandlerStub.update.calledOnce).to.be.false;
done();
});
});
it('should fail due to error in update handler', function(done) {
devicestorageStub.init.yields();
updateHandlerStub.update.yields({});
controller.init({
emailAddress: emailAddress
}, function(err, keypair) {
expect(err).to.exist;
expect(keypair).to.not.exist;
expect(updateHandlerStub.update.calledOnce).to.be.true;
expect(devicestorageStub.init.calledOnce).to.be.true;
done();
});
});
it('should fail due to error in emailDao.init', function(done) {
devicestorageStub.init.yields();
updateHandlerStub.update.yields();
emailDaoStub.init.yields({});
controller.init({
emailAddress: emailAddress
}, function(err, keypair) {
expect(err).to.exist;
expect(keypair).to.not.exist;
expect(updateHandlerStub.update.calledOnce).to.be.true;
expect(emailDaoStub.init.calledOnce).to.be.true;
expect(devicestorageStub.init.calledOnce).to.be.true;
done();
});
});
it('should work and return a keypair', function(done) {
devicestorageStub.init.withArgs(emailAddress).yields();
emailDaoStub.init.yields(null, {});
updateHandlerStub.update.yields();
controller.init({
emailAddress: emailAddress
}, function(err, keypair) {
expect(err).to.not.exist;
expect(keypair).to.exist;
expect(updateHandlerStub.update.calledOnce).to.be.true;
expect(emailDaoStub.init.calledOnce).to.be.true;
expect(devicestorageStub.init.calledOnce).to.be.true;
done();
});
controller.init({
emailAddress: emailAddress
}, function(err, keypair) {
expect(err).to.not.exist;
expect(keypair).to.exist;
expect(updateHandlerStub.update.calledOnce).to.be.true;
expect(emailDaoStub.init.calledOnce).to.be.true;
expect(devicestorageStub.init.calledOnce).to.be.true;
done();
});
});
});

View File

@ -1,377 +1,374 @@
define(function(require) {
'use strict';
'use strict';
var Auth = require('js/bo/auth'),
OAuth = require('js/util/oauth'),
PGP = require('js/crypto/pgp'),
DeviceStorageDAO = require('js/dao/devicestorage-dao'),
expect = chai.expect;
var Auth = require('../../src/js/bo/auth'),
OAuth = require('../../src/js/util/oauth'),
PGP = require('../../src/js/crypto/pgp'),
DeviceStorageDAO = require('../../src/js/dao/devicestorage-dao');
describe('Auth unit tests', function() {
// Constancts
var EMAIL_ADDR_DB_KEY = 'emailaddress';
var USERNAME_DB_KEY = 'username';
var REALNAME_DB_KEY = 'realname';
var PASSWD_DB_KEY = 'password';
var PROVIDER_DB_KEY = 'provider';
var IMAP_DB_KEY = 'imap';
var SMTP_DB_KEY = 'smtp';
// SUT
var auth;
describe('Auth unit tests', function() {
// Constancts
var EMAIL_ADDR_DB_KEY = 'emailaddress';
var USERNAME_DB_KEY = 'username';
var REALNAME_DB_KEY = 'realname';
var PASSWD_DB_KEY = 'password';
var PROVIDER_DB_KEY = 'provider';
var IMAP_DB_KEY = 'imap';
var SMTP_DB_KEY = 'smtp';
// SUT
var auth;
// Dependencies
var storageStub, oauthStub, pgpStub;
// Dependencies
var storageStub, oauthStub, pgpStub;
// test data
var emailAddress = 'bla@blubb.com';
var password = 'passwordpasswordpassword';
var encryptedPassword = 'pgppasswordpgppassword';
var oauthToken = 'tokentokentokentoken';
var provider = 'gmail';
var realname = 'Bla Blubb';
var username = 'bla';
var imap = {
host: 'mail.blablubb.com',
port: 123,
secure: true,
ca: 'PEMPEMPEMPEMPEMPEMPEMPEMPEMPEM'
};
var smtp = {
host: 'mail.blablubb.com',
port: 456,
secure: true,
ca: 'PEMPEMPEMPEMPEMPEMPEMPEMPEMPEM'
};
// test data
var emailAddress = 'bla@blubb.com';
var password = 'passwordpasswordpassword';
var encryptedPassword = 'pgppasswordpgppassword';
var oauthToken = 'tokentokentokentoken';
var provider = 'gmail';
var realname = 'Bla Blubb';
var username = 'bla';
var imap = {
host: 'mail.blablubb.com',
port: 123,
secure: true,
ca: 'PEMPEMPEMPEMPEMPEMPEMPEMPEMPEM'
};
var smtp = {
host: 'mail.blablubb.com',
port: 456,
secure: true,
ca: 'PEMPEMPEMPEMPEMPEMPEMPEMPEMPEM'
};
beforeEach(function() {
storageStub = sinon.createStubInstance(DeviceStorageDAO);
oauthStub = sinon.createStubInstance(OAuth);
pgpStub = sinon.createStubInstance(PGP);
auth = new Auth(storageStub, oauthStub, pgpStub);
beforeEach(function() {
storageStub = sinon.createStubInstance(DeviceStorageDAO);
oauthStub = sinon.createStubInstance(OAuth);
pgpStub = sinon.createStubInstance(PGP);
auth = new Auth(storageStub, oauthStub, pgpStub);
});
describe('#getCredentials', function() {
it('should load credentials and retrieve credentials from cfg', function(done) {
storageStub.listItems.withArgs(EMAIL_ADDR_DB_KEY, 0, null).yieldsAsync(null, [emailAddress]);
storageStub.listItems.withArgs(PASSWD_DB_KEY, 0, null).yieldsAsync(null, [encryptedPassword]);
storageStub.listItems.withArgs(PROVIDER_DB_KEY, 0, null).yieldsAsync(null, [provider]);
storageStub.listItems.withArgs(USERNAME_DB_KEY, 0, null).yieldsAsync(null, [username]);
storageStub.listItems.withArgs(REALNAME_DB_KEY, 0, null).yieldsAsync(null, [realname]);
storageStub.listItems.withArgs(IMAP_DB_KEY, 0, null).yieldsAsync(null, [imap]);
storageStub.listItems.withArgs(SMTP_DB_KEY, 0, null).yieldsAsync(null, [smtp]);
pgpStub.decrypt.withArgs(encryptedPassword, undefined).yields(null, password);
auth.getCredentials(function(err, cred) {
expect(err).to.not.exist;
expect(auth.provider).to.equal(provider);
expect(auth.emailAddress).to.equal(emailAddress);
expect(auth.password).to.equal(password);
expect(cred.imap.host).to.equal(imap.host);
expect(cred.imap.port).to.equal(imap.port);
expect(cred.imap.secure).to.equal(imap.secure);
expect(cred.imap.ca).to.equal(imap.ca);
expect(cred.imap.auth.user).to.equal(username);
expect(cred.imap.auth.pass).to.equal(password);
expect(cred.smtp.host).to.equal(smtp.host);
expect(cred.smtp.port).to.equal(smtp.port);
expect(cred.smtp.secure).to.equal(smtp.secure);
expect(cred.smtp.ca).to.equal(smtp.ca);
expect(cred.smtp.auth.user).to.equal(username);
expect(cred.smtp.auth.pass).to.equal(password);
expect(storageStub.listItems.callCount).to.equal(7);
expect(pgpStub.decrypt.calledOnce).to.be.true;
done();
});
});
});
describe('#setCredentials', function() {
it('should set the credentials', function() {
auth.setCredentials({
provider: 'albhsvadlbvsdalbsadflb',
emailAddress: emailAddress,
username: username,
realname: realname,
password: password,
imap: imap,
smtp: smtp
});
expect(auth.provider).to.equal('albhsvadlbvsdalbsadflb');
expect(auth.emailAddress).to.equal(emailAddress);
expect(auth.username).to.equal(username);
expect(auth.realname).to.equal(realname);
expect(auth.password).to.equal(password);
expect(auth.smtp).to.equal(smtp);
expect(auth.imap).to.equal(imap);
expect(auth.credentialsDirty).to.be.true;
});
describe('#getCredentials', function() {
it('should load credentials and retrieve credentials from cfg', function(done) {
storageStub.listItems.withArgs(EMAIL_ADDR_DB_KEY, 0, null).yieldsAsync(null, [emailAddress]);
storageStub.listItems.withArgs(PASSWD_DB_KEY, 0, null).yieldsAsync(null, [encryptedPassword]);
storageStub.listItems.withArgs(PROVIDER_DB_KEY, 0, null).yieldsAsync(null, [provider]);
storageStub.listItems.withArgs(USERNAME_DB_KEY, 0, null).yieldsAsync(null, [username]);
storageStub.listItems.withArgs(REALNAME_DB_KEY, 0, null).yieldsAsync(null, [realname]);
storageStub.listItems.withArgs(IMAP_DB_KEY, 0, null).yieldsAsync(null, [imap]);
storageStub.listItems.withArgs(SMTP_DB_KEY, 0, null).yieldsAsync(null, [smtp]);
pgpStub.decrypt.withArgs(encryptedPassword, undefined).yields(null, password);
});
auth.getCredentials(function(err, cred) {
expect(err).to.not.exist;
describe('#storeCredentials', function() {
it('should persist ALL the things!', function(done) {
auth.credentialsDirty = true;
auth.emailAddress = emailAddress;
auth.username = username;
auth.realname = realname;
auth.password = password;
auth.smtp = smtp;
auth.imap = imap;
auth.provider = provider;
expect(auth.provider).to.equal(provider);
expect(auth.emailAddress).to.equal(emailAddress);
expect(auth.password).to.equal(password);
storageStub.storeList.withArgs([encryptedPassword], PASSWD_DB_KEY).yieldsAsync();
storageStub.storeList.withArgs([emailAddress], EMAIL_ADDR_DB_KEY).yieldsAsync();
storageStub.storeList.withArgs([provider], PROVIDER_DB_KEY).yieldsAsync();
storageStub.storeList.withArgs([username], USERNAME_DB_KEY).yieldsAsync();
storageStub.storeList.withArgs([realname], REALNAME_DB_KEY).yieldsAsync();
storageStub.storeList.withArgs([imap], IMAP_DB_KEY).yieldsAsync();
storageStub.storeList.withArgs([smtp], SMTP_DB_KEY).yieldsAsync();
pgpStub.encrypt.withArgs(password).yields(null, encryptedPassword);
expect(cred.imap.host).to.equal(imap.host);
expect(cred.imap.port).to.equal(imap.port);
expect(cred.imap.secure).to.equal(imap.secure);
expect(cred.imap.ca).to.equal(imap.ca);
expect(cred.imap.auth.user).to.equal(username);
expect(cred.imap.auth.pass).to.equal(password);
auth.storeCredentials(function(err) {
expect(err).to.not.exist;
expect(cred.smtp.host).to.equal(smtp.host);
expect(cred.smtp.port).to.equal(smtp.port);
expect(cred.smtp.secure).to.equal(smtp.secure);
expect(cred.smtp.ca).to.equal(smtp.ca);
expect(cred.smtp.auth.user).to.equal(username);
expect(cred.smtp.auth.pass).to.equal(password);
expect(storageStub.storeList.callCount).to.equal(7);
expect(pgpStub.encrypt.calledOnce).to.be.true;
expect(storageStub.listItems.callCount).to.equal(7);
expect(pgpStub.decrypt.calledOnce).to.be.true;
done();
});
});
});
done();
});
describe('#getOAuthToken', function() {
it('should refresh token with known email address', function(done) {
auth.emailAddress = emailAddress;
auth.oauthToken = 'oldToken';
oauthStub.refreshToken.withArgs({
emailAddress: emailAddress,
oldToken: 'oldToken'
}).yieldsAsync(null, oauthToken);
auth.getOAuthToken(function(err) {
expect(err).to.not.exist;
expect(auth.emailAddress).to.equal(emailAddress);
expect(auth.oauthToken).to.equal(oauthToken);
expect(oauthStub.refreshToken.calledOnce).to.be.true;
done();
});
});
describe('#setCredentials', function() {
it('should set the credentials', function() {
auth.setCredentials({
provider: 'albhsvadlbvsdalbsadflb',
emailAddress: emailAddress,
username: username,
realname: realname,
password: password,
imap: imap,
smtp: smtp
});
it('should fetch token with known email address', function(done) {
auth.emailAddress = emailAddress;
oauthStub.getOAuthToken.withArgs(emailAddress).yieldsAsync(null, oauthToken);
expect(auth.provider).to.equal('albhsvadlbvsdalbsadflb');
auth.getOAuthToken(function(err) {
expect(err).to.not.exist;
expect(auth.emailAddress).to.equal(emailAddress);
expect(auth.oauthToken).to.equal(oauthToken);
expect(oauthStub.getOAuthToken.calledOnce).to.be.true;
done();
});
});
it('should fetch token with unknown email address', function(done) {
oauthStub.getOAuthToken.withArgs(undefined).yieldsAsync(null, oauthToken);
oauthStub.queryEmailAddress.withArgs(oauthToken).yieldsAsync(null, emailAddress);
auth.getOAuthToken(function(err) {
expect(err).to.not.exist;
expect(auth.emailAddress).to.equal(emailAddress);
expect(auth.oauthToken).to.equal(oauthToken);
expect(oauthStub.getOAuthToken.calledOnce).to.be.true;
expect(oauthStub.queryEmailAddress.calledOnce).to.be.true;
done();
});
});
it('should fail when email address fetch fails', function(done) {
oauthStub.getOAuthToken.yieldsAsync(null, oauthToken);
oauthStub.queryEmailAddress.yieldsAsync(new Error());
auth.getOAuthToken(function(err) {
expect(err).to.exist;
expect(auth.emailAddress).to.not.exist;
expect(auth.oauthToken).to.not.exist;
expect(oauthStub.getOAuthToken.calledOnce).to.be.true;
expect(oauthStub.queryEmailAddress.calledOnce).to.be.true;
done();
});
});
it('should fail when oauth fetch fails', function(done) {
oauthStub.getOAuthToken.yieldsAsync(new Error());
auth.getOAuthToken(function(err) {
expect(err).to.exist;
expect(auth.emailAddress).to.not.exist;
expect(auth.oauthToken).to.not.exist;
expect(oauthStub.getOAuthToken.calledOnce).to.be.true;
expect(oauthStub.queryEmailAddress.called).to.be.false;
done();
});
});
});
describe('#_loadCredentials', function() {
it('should work', function(done) {
storageStub.listItems.withArgs(EMAIL_ADDR_DB_KEY, 0, null).yieldsAsync(null, [emailAddress]);
storageStub.listItems.withArgs(PASSWD_DB_KEY, 0, null).yieldsAsync(null, [encryptedPassword]);
storageStub.listItems.withArgs(PROVIDER_DB_KEY, 0, null).yieldsAsync(null, [provider]);
storageStub.listItems.withArgs(USERNAME_DB_KEY, 0, null).yieldsAsync(null, [username]);
storageStub.listItems.withArgs(REALNAME_DB_KEY, 0, null).yieldsAsync(null, [realname]);
storageStub.listItems.withArgs(IMAP_DB_KEY, 0, null).yieldsAsync(null, [imap]);
storageStub.listItems.withArgs(SMTP_DB_KEY, 0, null).yieldsAsync(null, [smtp]);
auth._loadCredentials(function(err) {
expect(err).to.not.exist;
expect(auth.emailAddress).to.equal(emailAddress);
expect(auth.password).to.equal(encryptedPassword);
expect(auth.provider).to.equal(provider);
expect(auth.imap).to.equal(imap);
expect(auth.smtp).to.equal(smtp);
expect(auth.username).to.equal(username);
expect(auth.realname).to.equal(realname);
expect(auth.password).to.equal(password);
expect(auth.smtp).to.equal(smtp);
expect(auth.imap).to.equal(imap);
expect(auth.credentialsDirty).to.be.true;
});
});
expect(auth.passwordNeedsDecryption).to.be.true;
describe('#storeCredentials', function() {
it('should persist ALL the things!', function(done) {
auth.credentialsDirty = true;
auth.emailAddress = emailAddress;
auth.username = username;
auth.realname = realname;
auth.password = password;
auth.smtp = smtp;
auth.imap = imap;
auth.provider = provider;
expect(storageStub.listItems.callCount).to.equal(7);
storageStub.storeList.withArgs([encryptedPassword], PASSWD_DB_KEY).yieldsAsync();
storageStub.storeList.withArgs([emailAddress], EMAIL_ADDR_DB_KEY).yieldsAsync();
storageStub.storeList.withArgs([provider], PROVIDER_DB_KEY).yieldsAsync();
storageStub.storeList.withArgs([username], USERNAME_DB_KEY).yieldsAsync();
storageStub.storeList.withArgs([realname], REALNAME_DB_KEY).yieldsAsync();
storageStub.storeList.withArgs([imap], IMAP_DB_KEY).yieldsAsync();
storageStub.storeList.withArgs([smtp], SMTP_DB_KEY).yieldsAsync();
pgpStub.encrypt.withArgs(password).yields(null, encryptedPassword);
auth.storeCredentials(function(err) {
expect(err).to.not.exist;
expect(storageStub.storeList.callCount).to.equal(7);
expect(pgpStub.encrypt.calledOnce).to.be.true;
done();
});
done();
});
});
describe('#getOAuthToken', function() {
it('should refresh token with known email address', function(done) {
auth.emailAddress = emailAddress;
auth.oauthToken = 'oldToken';
it('should fail', function(done) {
storageStub.listItems.yieldsAsync(new Error());
oauthStub.refreshToken.withArgs({
emailAddress: emailAddress,
oldToken: 'oldToken'
}).yieldsAsync(null, oauthToken);
auth._loadCredentials(function(err) {
expect(err).to.exist;
expect(auth.emailAddress).to.not.exist;
expect(auth.password).to.not.exist;
expect(auth.provider).to.not.exist;
expect(auth.imap).to.not.exist;
expect(auth.smtp).to.not.exist;
expect(auth.username).to.not.exist;
expect(auth.realname).to.not.exist;
auth.getOAuthToken(function(err) {
expect(err).to.not.exist;
expect(auth.emailAddress).to.equal(emailAddress);
expect(auth.oauthToken).to.equal(oauthToken);
expect(storageStub.listItems.calledOnce).to.be.true;
expect(oauthStub.refreshToken.calledOnce).to.be.true;
done();
});
});
it('should fetch token with known email address', function(done) {
auth.emailAddress = emailAddress;
oauthStub.getOAuthToken.withArgs(emailAddress).yieldsAsync(null, oauthToken);
auth.getOAuthToken(function(err) {
expect(err).to.not.exist;
expect(auth.emailAddress).to.equal(emailAddress);
expect(auth.oauthToken).to.equal(oauthToken);
expect(oauthStub.getOAuthToken.calledOnce).to.be.true;
done();
});
});
it('should fetch token with unknown email address', function(done) {
oauthStub.getOAuthToken.withArgs(undefined).yieldsAsync(null, oauthToken);
oauthStub.queryEmailAddress.withArgs(oauthToken).yieldsAsync(null, emailAddress);
auth.getOAuthToken(function(err) {
expect(err).to.not.exist;
expect(auth.emailAddress).to.equal(emailAddress);
expect(auth.oauthToken).to.equal(oauthToken);
expect(oauthStub.getOAuthToken.calledOnce).to.be.true;
expect(oauthStub.queryEmailAddress.calledOnce).to.be.true;
done();
});
});
it('should fail when email address fetch fails', function(done) {
oauthStub.getOAuthToken.yieldsAsync(null, oauthToken);
oauthStub.queryEmailAddress.yieldsAsync(new Error());
auth.getOAuthToken(function(err) {
expect(err).to.exist;
expect(auth.emailAddress).to.not.exist;
expect(auth.oauthToken).to.not.exist;
expect(oauthStub.getOAuthToken.calledOnce).to.be.true;
expect(oauthStub.queryEmailAddress.calledOnce).to.be.true;
done();
});
});
it('should fail when oauth fetch fails', function(done) {
oauthStub.getOAuthToken.yieldsAsync(new Error());
auth.getOAuthToken(function(err) {
expect(err).to.exist;
expect(auth.emailAddress).to.not.exist;
expect(auth.oauthToken).to.not.exist;
expect(oauthStub.getOAuthToken.calledOnce).to.be.true;
expect(oauthStub.queryEmailAddress.called).to.be.false;
done();
});
done();
});
});
});
describe('#_loadCredentials', function() {
it('should work', function(done) {
storageStub.listItems.withArgs(EMAIL_ADDR_DB_KEY, 0, null).yieldsAsync(null, [emailAddress]);
storageStub.listItems.withArgs(PASSWD_DB_KEY, 0, null).yieldsAsync(null, [encryptedPassword]);
storageStub.listItems.withArgs(PROVIDER_DB_KEY, 0, null).yieldsAsync(null, [provider]);
storageStub.listItems.withArgs(USERNAME_DB_KEY, 0, null).yieldsAsync(null, [username]);
storageStub.listItems.withArgs(REALNAME_DB_KEY, 0, null).yieldsAsync(null, [realname]);
storageStub.listItems.withArgs(IMAP_DB_KEY, 0, null).yieldsAsync(null, [imap]);
storageStub.listItems.withArgs(SMTP_DB_KEY, 0, null).yieldsAsync(null, [smtp]);
describe('#handleCertificateUpdate', function() {
var storeCredentialsStub;
var dummyCert = 'cert';
auth._loadCredentials(function(err) {
expect(err).to.not.exist;
expect(auth.emailAddress).to.equal(emailAddress);
expect(auth.password).to.equal(encryptedPassword);
expect(auth.provider).to.equal(provider);
expect(auth.imap).to.equal(imap);
expect(auth.smtp).to.equal(smtp);
expect(auth.username).to.equal(username);
expect(auth.realname).to.equal(realname);
function onConnectDummy() {}
expect(auth.passwordNeedsDecryption).to.be.true;
expect(storageStub.listItems.callCount).to.equal(7);
done();
});
});
it('should fail', function(done) {
storageStub.listItems.yieldsAsync(new Error());
auth._loadCredentials(function(err) {
expect(err).to.exist;
expect(auth.emailAddress).to.not.exist;
expect(auth.password).to.not.exist;
expect(auth.provider).to.not.exist;
expect(auth.imap).to.not.exist;
expect(auth.smtp).to.not.exist;
expect(auth.username).to.not.exist;
expect(auth.realname).to.not.exist;
expect(storageStub.listItems.calledOnce).to.be.true;
done();
});
});
beforeEach(function() {
storeCredentialsStub = sinon.stub(auth, 'storeCredentials');
});
describe('#handleCertificateUpdate', function() {
var storeCredentialsStub;
var dummyCert = 'cert';
it('should work for Trust on first use', function(done) {
auth.imap = {};
storeCredentialsStub.yields();
function onConnectDummy() {}
function callback(err) {
expect(err).to.not.exist;
expect(storeCredentialsStub.callCount).to.equal(1);
done();
}
auth.handleCertificateUpdate('imap', onConnectDummy, callback, dummyCert);
});
beforeEach(function() {
storeCredentialsStub = sinon.stub(auth, 'storeCredentials');
});
it('should work for stored cert', function() {
auth.imap = {
ca: dummyCert
};
storeCredentialsStub.yields();
it('should work for Trust on first use', function(done) {
auth.imap = {};
storeCredentialsStub.yields();
auth.handleCertificateUpdate('imap', onConnectDummy, onConnectDummy, dummyCert);
expect(storeCredentialsStub.callCount).to.equal(0);
});
function callback(err) {
expect(err).to.not.exist;
expect(storeCredentialsStub.callCount).to.equal(1);
done();
}
auth.handleCertificateUpdate('imap', onConnectDummy, callback, dummyCert);
});
it('should work for pinned cert', function(done) {
auth.imap = {
ca: 'other',
pinned: true
};
storeCredentialsStub.yields();
it('should work for stored cert', function() {
auth.imap = {
ca: dummyCert
};
storeCredentialsStub.yields();
auth.handleCertificateUpdate('imap', onConnectDummy, onConnectDummy, dummyCert);
function callback(err) {
expect(err).to.exist;
expect(err.message).to.exist;
expect(storeCredentialsStub.callCount).to.equal(0);
});
done();
}
auth.handleCertificateUpdate('imap', onConnectDummy, callback, dummyCert);
});
it('should work for pinned cert', function(done) {
auth.imap = {
ca: 'other',
pinned: true
};
storeCredentialsStub.yields();
it('should work for updated cert', function(done) {
auth.imap = {
ca: 'other'
};
storeCredentialsStub.yields();
function callback(err) {
function callback(err) {
if (err && err.callback) {
expect(err).to.exist;
expect(err.message).to.exist;
expect(storeCredentialsStub.callCount).to.equal(0);
err.callback(true);
} else {
expect(storeCredentialsStub.callCount).to.equal(1);
done();
}
auth.handleCertificateUpdate('imap', onConnectDummy, callback, dummyCert);
});
}
it('should work for updated cert', function(done) {
auth.imap = {
ca: 'other'
};
storeCredentialsStub.yields();
function onConnect(callback) {
callback();
}
function callback(err) {
if (err && err.callback) {
expect(err).to.exist;
expect(err.message).to.exist;
expect(storeCredentialsStub.callCount).to.equal(0);
err.callback(true);
} else {
expect(storeCredentialsStub.callCount).to.equal(1);
done();
}
}
auth.handleCertificateUpdate('imap', onConnect, callback, dummyCert);
});
});
function onConnect(callback) {
callback();
}
describe('#logout', function() {
it('should fail to to error in calling db clear', function(done) {
storageStub.clear.yields(new Error());
auth.handleCertificateUpdate('imap', onConnect, callback, dummyCert);
auth.logout(function(err) {
expect(err).to.exist;
done();
});
});
describe('#logout', function() {
it('should fail to to error in calling db clear', function(done) {
storageStub.clear.yields(new Error());
it('should work', function(done) {
storageStub.clear.yields();
auth.logout(function(err) {
expect(err).to.exist;
done();
});
});
it('should work', function(done) {
storageStub.clear.yields();
auth.logout(function(err) {
expect(err).to.not.exist;
expect(auth.password).to.be.undefined;
expect(auth.initialized).to.be.undefined;
expect(auth.credentialsDirty).to.be.undefined;
expect(auth.passwordNeedsDecryption).to.be.undefined;
done();
});
auth.logout(function(err) {
expect(err).to.not.exist;
expect(auth.password).to.be.undefined;
expect(auth.initialized).to.be.undefined;
expect(auth.credentialsDirty).to.be.undefined;
expect(auth.passwordNeedsDecryption).to.be.undefined;
done();
});
});
});

View File

@ -1,67 +1,64 @@
define(function(require) {
'use strict';
'use strict';
var btnHandler = require('js/util/backbutton-handler'),
expect = chai.expect;
var btnHandler = require('../../src/js/util/backbutton-handler');
describe('Backbutton Handler', function() {
chai.Assertion.includeStack = true;
describe('Backbutton Handler', function() {
chai.Assertion.includeStack = true;
var scope, event;
var scope, event;
beforeEach(function() {
scope = {
state: {},
$apply: function() {}
};
beforeEach(function() {
scope = {
state: {},
$apply: function() {}
};
event = new CustomEvent('backbutton');
event = new CustomEvent('backbutton');
// this is a precondition for the test. throw an exception
// if this would produce side effects
expect(navigator.app).to.not.exist;
navigator.app = {};
// this is a precondition for the test. throw an exception
// if this would produce side effects
expect(navigator.app).to.not.exist;
navigator.app = {};
btnHandler.attachHandler(scope);
btnHandler.start();
});
btnHandler.attachHandler(scope);
btnHandler.start();
});
afterEach(function() {
btnHandler.stop();
delete navigator.app;
});
afterEach(function() {
btnHandler.stop();
delete navigator.app;
});
it('should close lightbox', function() {
scope.state.lightbox = 'asd';
document.dispatchEvent(event);
expect(scope.state.lightbox).to.be.undefined;
});
it('should close lightbox', function() {
scope.state.lightbox = 'asd';
document.dispatchEvent(event);
expect(scope.state.lightbox).to.be.undefined;
});
it('should close reader', function() {
scope.state.read = {
open: true,
toggle: function(state) {
scope.state.read.open = state;
}
};
document.dispatchEvent(event);
expect(scope.state.read.open).to.be.false;
});
it('should close reader', function() {
scope.state.read = {
open: true,
toggle: function(state) {
scope.state.read.open = state;
}
};
document.dispatchEvent(event);
expect(scope.state.read.open).to.be.false;
});
it('should close navigation', function() {
scope.state.nav = {
open: true,
toggle: function(state) {
scope.state.nav.open = state;
}
};
document.dispatchEvent(event);
expect(scope.state.nav.open).to.be.false;
});
it('should close navigation', function() {
scope.state.nav = {
open: true,
toggle: function(state) {
scope.state.nav.open = state;
}
};
document.dispatchEvent(event);
expect(scope.state.nav.open).to.be.false;
});
it('should close app', function(done) {
navigator.app.exitApp = done;
document.dispatchEvent(event);
});
it('should close app', function(done) {
navigator.app.exitApp = done;
document.dispatchEvent(event);
});
});

View File

@ -1,413 +1,410 @@
define(function(require) {
'use strict';
'use strict';
var ConnectionDoctor = require('js/util/connection-doctor'),
TCPSocket = require('tcp-socket'),
ImapClient = require('imap-client'),
SmtpClient = require('smtpclient'),
cfg = require('js/app-config').config,
expect = chai.expect;
var TCPSocket = require('tcp-socket'),
ImapClient = require('imap-client'),
SmtpClient = require('wo-smtpclient'),
ConnectionDoctor = require('../../src/js/util/connection-doctor'),
cfg = require('../../src/js/app-config').config;
describe('Connection Doctor', function() {
var doctor;
var socketStub, imapStub, smtpStub, credentials;
describe('Connection Doctor', function() {
var doctor;
var socketStub, imapStub, smtpStub, credentials;
beforeEach(function() {
//
// Stubs
//
beforeEach(function() {
//
// Stubs
//
// there is no socket shim for for this use case, use dummy object
socketStub = {
close: function() {
this.onclose();
// there is no socket shim for for this use case, use dummy object
socketStub = {
close: function() {
this.onclose();
}
};
imapStub = sinon.createStubInstance(ImapClient);
smtpStub = sinon.createStubInstance(SmtpClient);
//
// Fixture
//
credentials = {
imap: {
host: 'asd',
port: 1234,
secure: true,
ca: 'cert'
},
smtp: {
host: 'qwe',
port: 5678,
secure: false,
ca: 'cert'
},
username: 'username',
password: 'password'
};
sinon.stub(TCPSocket, 'open').returns(socketStub); // convenience constructors suck
//
// Setup SUT
//
doctor = new ConnectionDoctor();
doctor.configure(credentials);
doctor._imap = imapStub;
doctor._smtp = smtpStub;
});
afterEach(function() {
TCPSocket.open.restore();
});
describe('#_checkOnline', function() {
it('should check if browser is online', function(done) {
doctor._checkOnline(function(error) {
if (navigator.onLine) {
expect(error).to.not.exist;
} else {
expect(error).to.exist;
expect(error.code).to.equal(ConnectionDoctor.OFFLINE);
}
};
done();
});
});
});
imapStub = sinon.createStubInstance(ImapClient);
smtpStub = sinon.createStubInstance(SmtpClient);
describe('#_checkReachable', function() {
it('should be able to reach the host w/o cert', function(done) {
credentials.imap.ca = undefined;
//
// Fixture
//
credentials = {
imap: {
host: 'asd',
port: 1234,
secure: true,
ca: 'cert'
},
smtp: {
host: 'qwe',
port: 5678,
secure: false,
ca: 'cert'
},
username: 'username',
password: 'password'
};
doctor._checkReachable(credentials.imap, function(error) {
expect(error).to.not.exist;
expect(TCPSocket.open.calledOnce).to.be.true;
expect(TCPSocket.open.calledWith(credentials.imap.host, credentials.imap.port, {
binaryType: 'arraybuffer',
useSecureTransport: credentials.imap.secure,
ca: credentials.imap.ca
})).to.be.true;
sinon.stub(TCPSocket, 'open').returns(socketStub); // convenience constructors suck
done();
});
//
// Setup SUT
//
doctor = new ConnectionDoctor();
doctor.configure(credentials);
doctor._imap = imapStub;
doctor._smtp = smtpStub;
socketStub.oncert();
socketStub.onopen();
});
afterEach(function() {
TCPSocket.open.restore();
it('should catch Mozilla TCPSocket exception', function(done) {
// Mozilla forbids extensions to the TCPSocket object
Object.defineProperty(socketStub, 'oncert', {
set: function() {
throw 'Mozilla specific behavior';
}
});
doctor._checkReachable(credentials.imap, function(error) {
expect(error).to.not.exist;
expect(TCPSocket.open.calledOnce).to.be.true;
expect(TCPSocket.open.calledWith(credentials.imap.host, credentials.imap.port, {
binaryType: 'arraybuffer',
useSecureTransport: credentials.imap.secure,
ca: credentials.imap.ca
})).to.be.true;
done();
});
socketStub.onopen();
});
describe('#_checkOnline', function() {
it('should check if browser is online', function(done) {
doctor._checkOnline(function(error) {
if (navigator.onLine) {
expect(error).to.not.exist;
} else {
expect(error).to.exist;
expect(error.code).to.equal(ConnectionDoctor.OFFLINE);
}
done();
});
it('should fail w/ wrong cert', function(done) {
doctor._checkReachable(credentials.imap, function(error) {
expect(error).to.exist;
expect(error.code).to.equal(ConnectionDoctor.TLS_WRONG_CERT);
expect(TCPSocket.open.calledOnce).to.be.true;
expect(TCPSocket.open.calledWith(credentials.imap.host, credentials.imap.port, {
binaryType: 'arraybuffer',
useSecureTransport: credentials.imap.secure,
ca: credentials.imap.ca
})).to.be.true;
done();
});
socketStub.oncert();
socketStub.onerror();
socketStub.onclose();
});
it('should fail w/ host unreachable', function(done) {
doctor._checkReachable(credentials.imap, function(error) {
expect(error).to.exist;
expect(error.code).to.equal(ConnectionDoctor.HOST_UNREACHABLE);
expect(TCPSocket.open.calledOnce).to.be.true;
done();
});
socketStub.onerror({
data: new Error()
});
socketStub.onclose();
});
it('should fail w/ timeout', function(done) {
var origTimeout = cfg.connDocTimeout; // remember timeout from the config to reset it on done
cfg.connDocTimeout = 20; // set to 20ms for the test
doctor._checkReachable(credentials.imap, function(error) {
expect(error).to.exist;
expect(error.code).to.equal(ConnectionDoctor.HOST_TIMEOUT);
expect(TCPSocket.open.calledOnce).to.be.true;
cfg.connDocTimeout = origTimeout;
done();
});
});
});
describe('#_checkImap', function() {
it('should perform IMAP login, list folders, logout', function(done) {
imapStub.login.yieldsAsync();
imapStub.listWellKnownFolders.yieldsAsync(null, {
Inbox: [{}]
});
imapStub.logout.yieldsAsync();
doctor._checkImap(function(error) {
expect(error).to.not.exist;
expect(imapStub.login.calledOnce).to.be.true;
expect(imapStub.listWellKnownFolders.calledOnce).to.be.true;
expect(imapStub.logout.calledOnce).to.be.true;
done();
});
});
describe('#_checkReachable', function() {
it('should be able to reach the host w/o cert', function(done) {
credentials.imap.ca = undefined;
doctor._checkReachable(credentials.imap, function(error) {
expect(error).to.not.exist;
expect(TCPSocket.open.calledOnce).to.be.true;
expect(TCPSocket.open.calledWith(credentials.imap.host, credentials.imap.port, {
binaryType: 'arraybuffer',
useSecureTransport: credentials.imap.secure,
ca: credentials.imap.ca
})).to.be.true;
done();
});
socketStub.oncert();
socketStub.onopen();
it('should fail w/ generic error on logout', function(done) {
imapStub.login.yieldsAsync();
imapStub.listWellKnownFolders.yieldsAsync(null, {
Inbox: [{}]
});
it('should catch Mozilla TCPSocket exception', function(done) {
// Mozilla forbids extensions to the TCPSocket object
Object.defineProperty(socketStub, 'oncert', {
set: function() {
throw 'Mozilla specific behavior';
}
});
doctor._checkImap(function(error) {
expect(error).to.exist;
expect(error.code).to.equal(ConnectionDoctor.GENERIC_ERROR);
expect(error.underlyingError).to.exist;
expect(imapStub.login.calledOnce).to.be.true;
expect(imapStub.listWellKnownFolders.calledOnce).to.be.true;
expect(imapStub.logout.calledOnce).to.be.true;
doctor._checkReachable(credentials.imap, function(error) {
expect(error).to.not.exist;
expect(TCPSocket.open.calledOnce).to.be.true;
expect(TCPSocket.open.calledWith(credentials.imap.host, credentials.imap.port, {
binaryType: 'arraybuffer',
useSecureTransport: credentials.imap.secure,
ca: credentials.imap.ca
})).to.be.true;
done();
});
socketStub.onopen();
done();
});
it('should fail w/ wrong cert', function(done) {
doctor._checkReachable(credentials.imap, function(error) {
expect(error).to.exist;
expect(error.code).to.equal(ConnectionDoctor.TLS_WRONG_CERT);
expect(TCPSocket.open.calledOnce).to.be.true;
expect(TCPSocket.open.calledWith(credentials.imap.host, credentials.imap.port, {
binaryType: 'arraybuffer',
useSecureTransport: credentials.imap.secure,
ca: credentials.imap.ca
})).to.be.true;
setTimeout(function() {
// this error is thrown while we're waiting for the logout
imapStub.onError(new Error());
}, 50);
});
done();
});
socketStub.oncert();
socketStub.onerror();
socketStub.onclose();
it('should fail w/ generic error on inbox missing', function(done) {
imapStub.login.yieldsAsync();
imapStub.listWellKnownFolders.yieldsAsync(null, {
Inbox: []
});
it('should fail w/ host unreachable', function(done) {
doctor._checkReachable(credentials.imap, function(error) {
expect(error).to.exist;
expect(error.code).to.equal(ConnectionDoctor.HOST_UNREACHABLE);
expect(TCPSocket.open.calledOnce).to.be.true;
doctor._checkImap(function(error) {
expect(error).to.exist;
expect(error.code).to.equal(ConnectionDoctor.NO_INBOX);
expect(imapStub.login.calledOnce).to.be.true;
expect(imapStub.listWellKnownFolders.calledOnce).to.be.true;
expect(imapStub.logout.called).to.be.false;
done();
});
socketStub.onerror({
data: new Error()
});
socketStub.onclose();
});
it('should fail w/ timeout', function(done) {
var origTimeout = cfg.connDocTimeout; // remember timeout from the config to reset it on done
cfg.connDocTimeout = 20; // set to 20ms for the test
doctor._checkReachable(credentials.imap, function(error) {
expect(error).to.exist;
expect(error.code).to.equal(ConnectionDoctor.HOST_TIMEOUT);
expect(TCPSocket.open.calledOnce).to.be.true;
cfg.connDocTimeout = origTimeout;
done();
});
done();
});
});
describe('#_checkImap', function() {
it('should perform IMAP login, list folders, logout', function(done) {
imapStub.login.yieldsAsync();
imapStub.listWellKnownFolders.yieldsAsync(null, {
Inbox: [{}]
});
imapStub.logout.yieldsAsync();
it('should fail w/ generic error on listing folders fails', function(done) {
imapStub.login.yieldsAsync();
imapStub.listWellKnownFolders.yieldsAsync(new Error());
doctor._checkImap(function(error) {
expect(error).to.not.exist;
expect(imapStub.login.calledOnce).to.be.true;
expect(imapStub.listWellKnownFolders.calledOnce).to.be.true;
expect(imapStub.logout.calledOnce).to.be.true;
doctor._checkImap(function(error) {
expect(error).to.exist;
expect(error.code).to.equal(ConnectionDoctor.GENERIC_ERROR);
expect(error.underlyingError).to.exist;
expect(imapStub.login.calledOnce).to.be.true;
expect(imapStub.listWellKnownFolders.calledOnce).to.be.true;
expect(imapStub.logout.called).to.be.false;
done();
});
});
it('should fail w/ generic error on logout', function(done) {
imapStub.login.yieldsAsync();
imapStub.listWellKnownFolders.yieldsAsync(null, {
Inbox: [{}]
});
doctor._checkImap(function(error) {
expect(error).to.exist;
expect(error.code).to.equal(ConnectionDoctor.GENERIC_ERROR);
expect(error.underlyingError).to.exist;
expect(imapStub.login.calledOnce).to.be.true;
expect(imapStub.listWellKnownFolders.calledOnce).to.be.true;
expect(imapStub.logout.calledOnce).to.be.true;
done();
});
setTimeout(function() {
// this error is thrown while we're waiting for the logout
imapStub.onError(new Error());
}, 50);
});
it('should fail w/ generic error on inbox missing', function(done) {
imapStub.login.yieldsAsync();
imapStub.listWellKnownFolders.yieldsAsync(null, {
Inbox: []
});
doctor._checkImap(function(error) {
expect(error).to.exist;
expect(error.code).to.equal(ConnectionDoctor.NO_INBOX);
expect(imapStub.login.calledOnce).to.be.true;
expect(imapStub.listWellKnownFolders.calledOnce).to.be.true;
expect(imapStub.logout.called).to.be.false;
done();
});
});
it('should fail w/ generic error on listing folders fails', function(done) {
imapStub.login.yieldsAsync();
imapStub.listWellKnownFolders.yieldsAsync(new Error());
doctor._checkImap(function(error) {
expect(error).to.exist;
expect(error.code).to.equal(ConnectionDoctor.GENERIC_ERROR);
expect(error.underlyingError).to.exist;
expect(imapStub.login.calledOnce).to.be.true;
expect(imapStub.listWellKnownFolders.calledOnce).to.be.true;
expect(imapStub.logout.called).to.be.false;
done();
});
});
it('should fail w/ auth rejected', function(done) {
doctor._checkImap(function(error) {
expect(error).to.exist;
expect(error.code).to.equal(ConnectionDoctor.AUTH_REJECTED);
expect(error.underlyingError).to.exist;
expect(imapStub.login.calledOnce).to.be.true;
expect(imapStub.listWellKnownFolders.called).to.be.false;
expect(imapStub.logout.called).to.be.false;
done();
});
setTimeout(function() {
// this error is thrown while we're waiting for the login
imapStub.onError(new Error());
}, 50);
done();
});
});
describe('#_checkSmtp', function() {
it('should perform SMTP login, logout', function(done) {
doctor._checkSmtp(function(error) {
expect(error).to.not.exist;
expect(smtpStub.connect.calledOnce).to.be.true;
expect(smtpStub.quit.calledOnce).to.be.true;
it('should fail w/ auth rejected', function(done) {
doctor._checkImap(function(error) {
expect(error).to.exist;
expect(error.code).to.equal(ConnectionDoctor.AUTH_REJECTED);
expect(error.underlyingError).to.exist;
expect(imapStub.login.calledOnce).to.be.true;
expect(imapStub.listWellKnownFolders.called).to.be.false;
expect(imapStub.logout.called).to.be.false;
done();
});
smtpStub.onidle();
smtpStub.onclose();
done();
});
it('should fail w/ auth rejected', function(done) {
doctor._checkSmtp(function(error) {
expect(error).to.exist;
expect(error.code).to.equal(ConnectionDoctor.AUTH_REJECTED);
expect(error.underlyingError).to.exist;
expect(smtpStub.connect.calledOnce).to.be.true;
expect(smtpStub.quit.called).to.be.false;
setTimeout(function() {
// this error is thrown while we're waiting for the login
imapStub.onError(new Error());
}, 50);
});
});
done();
});
describe('#_checkSmtp', function() {
it('should perform SMTP login, logout', function(done) {
doctor._checkSmtp(function(error) {
expect(error).to.not.exist;
expect(smtpStub.connect.calledOnce).to.be.true;
expect(smtpStub.quit.calledOnce).to.be.true;
smtpStub.onerror(new Error());
done();
});
smtpStub.onidle();
smtpStub.onclose();
});
it('should fail w/ auth rejected', function(done) {
doctor._checkSmtp(function(error) {
expect(error).to.exist;
expect(error.code).to.equal(ConnectionDoctor.AUTH_REJECTED);
expect(error.underlyingError).to.exist;
expect(smtpStub.connect.calledOnce).to.be.true;
expect(smtpStub.quit.called).to.be.false;
done();
});
smtpStub.onerror(new Error());
});
});
describe('#check', function() {
beforeEach(function() {
sinon.stub(doctor, '_checkOnline');
sinon.stub(doctor, '_checkReachable');
sinon.stub(doctor, '_checkImap');
sinon.stub(doctor, '_checkSmtp');
});
it('should perform all tests', function(done) {
doctor._checkOnline.yieldsAsync();
doctor._checkReachable.withArgs(credentials.imap).yieldsAsync();
doctor._checkReachable.withArgs(credentials.smtp).yieldsAsync();
doctor._checkImap.yieldsAsync();
doctor._checkSmtp.yieldsAsync();
doctor.check(function(err) {
expect(err).to.not.exist;
expect(doctor._checkOnline.calledOnce).to.be.true;
expect(doctor._checkReachable.calledTwice).to.be.true;
expect(doctor._checkImap.calledOnce).to.be.true;
expect(doctor._checkSmtp.calledOnce).to.be.true;
done();
});
});
describe('#check', function() {
beforeEach(function() {
sinon.stub(doctor, '_checkOnline');
sinon.stub(doctor, '_checkReachable');
sinon.stub(doctor, '_checkImap');
sinon.stub(doctor, '_checkSmtp');
it('should fail for smtp', function(done) {
doctor._checkOnline.yieldsAsync();
doctor._checkReachable.withArgs(credentials.imap).yieldsAsync();
doctor._checkReachable.withArgs(credentials.smtp).yieldsAsync();
doctor._checkImap.yieldsAsync();
doctor._checkSmtp.yieldsAsync(new Error());
doctor.check(function(err) {
expect(err).to.exist;
expect(doctor._checkOnline.calledOnce).to.be.true;
expect(doctor._checkReachable.calledTwice).to.be.true;
expect(doctor._checkImap.calledOnce).to.be.true;
expect(doctor._checkSmtp.calledOnce).to.be.true;
done();
});
});
it('should perform all tests', function(done) {
doctor._checkOnline.yieldsAsync();
doctor._checkReachable.withArgs(credentials.imap).yieldsAsync();
doctor._checkReachable.withArgs(credentials.smtp).yieldsAsync();
doctor._checkImap.yieldsAsync();
doctor._checkSmtp.yieldsAsync();
it('should fail for imap', function(done) {
doctor._checkOnline.yieldsAsync();
doctor._checkReachable.withArgs(credentials.imap).yieldsAsync();
doctor._checkReachable.withArgs(credentials.smtp).yieldsAsync();
doctor._checkImap.yieldsAsync(new Error());
doctor.check(function(err) {
expect(err).to.not.exist;
expect(doctor._checkOnline.calledOnce).to.be.true;
expect(doctor._checkReachable.calledTwice).to.be.true;
expect(doctor._checkImap.calledOnce).to.be.true;
expect(doctor._checkSmtp.calledOnce).to.be.true;
doctor.check(function(err) {
expect(err).to.exist;
expect(doctor._checkOnline.calledOnce).to.be.true;
expect(doctor._checkReachable.calledTwice).to.be.true;
expect(doctor._checkImap.calledOnce).to.be.true;
expect(doctor._checkSmtp.called).to.be.false;
done();
});
done();
});
});
it('should fail for smtp', function(done) {
doctor._checkOnline.yieldsAsync();
doctor._checkReachable.withArgs(credentials.imap).yieldsAsync();
doctor._checkReachable.withArgs(credentials.smtp).yieldsAsync();
doctor._checkImap.yieldsAsync();
doctor._checkSmtp.yieldsAsync(new Error());
it('should fail for smtp reachability', function(done) {
doctor._checkOnline.yieldsAsync();
doctor._checkReachable.withArgs(credentials.imap).yieldsAsync();
doctor._checkReachable.withArgs(credentials.smtp).yieldsAsync(new Error());
doctor.check(function(err) {
expect(err).to.exist;
expect(doctor._checkOnline.calledOnce).to.be.true;
expect(doctor._checkReachable.calledTwice).to.be.true;
expect(doctor._checkImap.calledOnce).to.be.true;
expect(doctor._checkSmtp.calledOnce).to.be.true;
doctor.check(function(err) {
expect(err).to.exist;
expect(doctor._checkOnline.calledOnce).to.be.true;
expect(doctor._checkReachable.calledTwice).to.be.true;
expect(doctor._checkImap.called).to.be.false;
expect(doctor._checkSmtp.called).to.be.false;
done();
});
done();
});
});
it('should fail for imap', function(done) {
doctor._checkOnline.yieldsAsync();
doctor._checkReachable.withArgs(credentials.imap).yieldsAsync();
doctor._checkReachable.withArgs(credentials.smtp).yieldsAsync();
doctor._checkImap.yieldsAsync(new Error());
it('should fail for imap reachability', function(done) {
doctor._checkOnline.yieldsAsync();
doctor._checkReachable.withArgs(credentials.imap).yieldsAsync(new Error());
doctor.check(function(err) {
expect(err).to.exist;
expect(doctor._checkOnline.calledOnce).to.be.true;
expect(doctor._checkReachable.calledTwice).to.be.true;
expect(doctor._checkImap.calledOnce).to.be.true;
expect(doctor._checkSmtp.called).to.be.false;
doctor.check(function(err) {
expect(err).to.exist;
expect(doctor._checkOnline.calledOnce).to.be.true;
expect(doctor._checkReachable.calledOnce).to.be.true;
expect(doctor._checkImap.called).to.be.false;
expect(doctor._checkSmtp.called).to.be.false;
done();
});
done();
});
});
it('should fail for smtp reachability', function(done) {
doctor._checkOnline.yieldsAsync();
doctor._checkReachable.withArgs(credentials.imap).yieldsAsync();
doctor._checkReachable.withArgs(credentials.smtp).yieldsAsync(new Error());
it('should fail for offline', function(done) {
doctor._checkOnline.yieldsAsync(new Error());
doctor.check(function(err) {
expect(err).to.exist;
expect(doctor._checkOnline.calledOnce).to.be.true;
expect(doctor._checkReachable.calledTwice).to.be.true;
expect(doctor._checkImap.called).to.be.false;
expect(doctor._checkSmtp.called).to.be.false;
doctor.check(function(err) {
expect(err).to.exist;
expect(doctor._checkOnline.calledOnce).to.be.true;
expect(doctor._checkReachable.called).to.be.false;
expect(doctor._checkImap.called).to.be.false;
expect(doctor._checkSmtp.called).to.be.false;
done();
});
done();
});
});
it('should fail for imap reachability', function(done) {
doctor._checkOnline.yieldsAsync();
doctor._checkReachable.withArgs(credentials.imap).yieldsAsync(new Error());
it('should fail w/o config', function(done) {
doctor.credentials = doctor._imap = doctor._smtp = undefined;
doctor.check(function(err) {
expect(err).to.exist;
expect(doctor._checkOnline.calledOnce).to.be.true;
expect(doctor._checkReachable.calledOnce).to.be.true;
expect(doctor._checkImap.called).to.be.false;
expect(doctor._checkSmtp.called).to.be.false;
doctor.check(function(err) {
expect(err).to.exist;
expect(doctor._checkOnline.called).to.be.false;
expect(doctor._checkReachable.called).to.be.false;
expect(doctor._checkImap.called).to.be.false;
expect(doctor._checkSmtp.called).to.be.false;
done();
});
});
it('should fail for offline', function(done) {
doctor._checkOnline.yieldsAsync(new Error());
doctor.check(function(err) {
expect(err).to.exist;
expect(doctor._checkOnline.calledOnce).to.be.true;
expect(doctor._checkReachable.called).to.be.false;
expect(doctor._checkImap.called).to.be.false;
expect(doctor._checkSmtp.called).to.be.false;
done();
});
});
it('should fail w/o config', function(done) {
doctor.credentials = doctor._imap = doctor._smtp = undefined;
doctor.check(function(err) {
expect(err).to.exist;
expect(doctor._checkOnline.called).to.be.false;
expect(doctor._checkReachable.called).to.be.false;
expect(doctor._checkImap.called).to.be.false;
expect(doctor._checkSmtp.called).to.be.false;
done();
});
done();
});
});
});

View File

@ -1,190 +1,186 @@
define(function(require) {
'use strict';
'use strict';
var expect = chai.expect,
angular = require('angular'),
mocks = require('angularMocks'),
ContactsCtrl = require('js/controller/contacts'),
appController = require('js/app-controller'),
KeychainDAO = require('js/dao/keychain-dao'),
PGP = require('js/crypto/pgp');
var mocks = angular.mocks,
ContactsCtrl = require('../../src/js/controller/contacts'),
appController = require('../../src/js/app-controller'),
KeychainDAO = require('../../src/js/dao/keychain-dao'),
PGP = require('../../src/js/crypto/pgp');
describe('Contacts Controller unit test', function() {
var scope, contactsCtrl,
origKeychain, keychainMock,
origPgp, pgpMock;
describe('Contacts Controller unit test', function() {
var scope, contactsCtrl,
origKeychain, keychainMock,
origPgp, pgpMock;
beforeEach(function() {
origPgp = appController._pgp;
appController._pgp = pgpMock = sinon.createStubInstance(PGP);
origKeychain = appController._keychain;
appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO);
beforeEach(function() {
origPgp = appController._pgp;
appController._pgp = pgpMock = sinon.createStubInstance(PGP);
origKeychain = appController._keychain;
appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO);
angular.module('contactstest', []);
mocks.module('contactstest');
mocks.inject(function($rootScope, $controller) {
scope = $rootScope.$new();
scope.state = {};
contactsCtrl = $controller(ContactsCtrl, {
$scope: scope
});
});
});
afterEach(function() {
// restore the module
appController._pgp = origPgp;
appController._keychain = origKeychain;
});
describe('scope variables', function() {
it('should be set correctly', function() {
expect(scope.fingerprint).to.equal('XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX');
expect(scope.state.contacts.toggle).to.exist;
});
});
describe('listKeys', function() {
it('should fail due to error in keychain.listLocalPublicKeys', function(done) {
keychainMock.listLocalPublicKeys.yields(42);
scope.onError = function(err) {
expect(err).to.equal(42);
done();
};
scope.listKeys();
});
it('should work', function(done) {
keychainMock.listLocalPublicKeys.yields(null, [{
_id: '12345'
}]);
pgpMock.getKeyParams.returns({
fingerprint: 'asdf'
});
scope.$apply = function() {
expect(scope.keys.length).to.equal(1);
expect(scope.keys[0]._id).to.equal('12345');
expect(scope.keys[0].fingerprint).to.equal('asdf');
done();
};
expect(scope.keys).to.not.exist;
scope.listKeys();
});
});
describe('getFingerprint', function() {
it('should work', function() {
var key = {
fingerprint: 'YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'
};
scope.getFingerprint(key);
expect(scope.fingerprint).to.equal('YYYY YYYY YYYY YYYY YYYY ... YYYY YYYY YYYY YYYY YYYY');
});
});
describe('importKey', function() {
it('should work', function(done) {
var keyArmored = '-----BEGIN PGP PUBLIC KEY BLOCK-----';
pgpMock.getKeyParams.returns({
_id: '12345',
userId: 'max@example.com',
userIds: []
});
keychainMock.saveLocalPublicKey.withArgs({
_id: '12345',
userId: 'max@example.com',
userIds: [],
publicKey: '-----BEGIN PGP PUBLIC KEY BLOCK-----',
imported: true
}).yields();
scope.listKeys = function() {
done();
};
scope.importKey(keyArmored);
});
it('should fail due to invalid armored key', function(done) {
var keyArmored = '-----BEGIN PGP PRIVATE KEY BLOCK-----';
scope.onError = function(err) {
expect(err).to.exist;
done();
};
scope.importKey(keyArmored);
});
it('should fail due to error in pgp.getKeyParams', function(done) {
var keyArmored = '-----BEGIN PGP PUBLIC KEY BLOCK-----';
pgpMock.getKeyParams.throws(new Error('WAT'));
scope.onError = function(err) {
expect(err).to.exist;
done();
};
scope.importKey(keyArmored);
});
it('should fail due to error in keychain.saveLocalPublicKey', function(done) {
var keyArmored = '-----BEGIN PGP PUBLIC KEY BLOCK-----';
pgpMock.getKeyParams.returns({
_id: '12345',
userId: 'max@example.com'
});
keychainMock.saveLocalPublicKey.yields(42);
scope.onError = function(err) {
expect(err).to.equal(42);
done();
};
scope.importKey(keyArmored);
});
});
describe('removeKey', function() {
it('should work', function(done) {
var key = {
_id: '12345'
};
keychainMock.removeLocalPublicKey.withArgs('12345').yields();
scope.listKeys = function() {
done();
};
scope.removeKey(key);
});
it('should fail due to error in keychain.removeLocalPublicKey', function(done) {
var key = {
_id: '12345'
};
keychainMock.removeLocalPublicKey.withArgs('12345').yields(42);
scope.onError = function(err) {
expect(err).to.equal(42);
done();
};
scope.removeKey(key);
angular.module('contactstest', []);
mocks.module('contactstest');
mocks.inject(function($rootScope, $controller) {
scope = $rootScope.$new();
scope.state = {};
contactsCtrl = $controller(ContactsCtrl, {
$scope: scope
});
});
});
afterEach(function() {
// restore the module
appController._pgp = origPgp;
appController._keychain = origKeychain;
});
describe('scope variables', function() {
it('should be set correctly', function() {
expect(scope.fingerprint).to.equal('XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX');
expect(scope.state.contacts.toggle).to.exist;
});
});
describe('listKeys', function() {
it('should fail due to error in keychain.listLocalPublicKeys', function(done) {
keychainMock.listLocalPublicKeys.yields(42);
scope.onError = function(err) {
expect(err).to.equal(42);
done();
};
scope.listKeys();
});
it('should work', function(done) {
keychainMock.listLocalPublicKeys.yields(null, [{
_id: '12345'
}]);
pgpMock.getKeyParams.returns({
fingerprint: 'asdf'
});
scope.$apply = function() {
expect(scope.keys.length).to.equal(1);
expect(scope.keys[0]._id).to.equal('12345');
expect(scope.keys[0].fingerprint).to.equal('asdf');
done();
};
expect(scope.keys).to.not.exist;
scope.listKeys();
});
});
describe('getFingerprint', function() {
it('should work', function() {
var key = {
fingerprint: 'YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'
};
scope.getFingerprint(key);
expect(scope.fingerprint).to.equal('YYYY YYYY YYYY YYYY YYYY ... YYYY YYYY YYYY YYYY YYYY');
});
});
describe('importKey', function() {
it('should work', function(done) {
var keyArmored = '-----BEGIN PGP PUBLIC KEY BLOCK-----';
pgpMock.getKeyParams.returns({
_id: '12345',
userId: 'max@example.com',
userIds: []
});
keychainMock.saveLocalPublicKey.withArgs({
_id: '12345',
userId: 'max@example.com',
userIds: [],
publicKey: '-----BEGIN PGP PUBLIC KEY BLOCK-----',
imported: true
}).yields();
scope.listKeys = function() {
done();
};
scope.importKey(keyArmored);
});
it('should fail due to invalid armored key', function(done) {
var keyArmored = '-----BEGIN PGP PRIVATE KEY BLOCK-----';
scope.onError = function(err) {
expect(err).to.exist;
done();
};
scope.importKey(keyArmored);
});
it('should fail due to error in pgp.getKeyParams', function(done) {
var keyArmored = '-----BEGIN PGP PUBLIC KEY BLOCK-----';
pgpMock.getKeyParams.throws(new Error('WAT'));
scope.onError = function(err) {
expect(err).to.exist;
done();
};
scope.importKey(keyArmored);
});
it('should fail due to error in keychain.saveLocalPublicKey', function(done) {
var keyArmored = '-----BEGIN PGP PUBLIC KEY BLOCK-----';
pgpMock.getKeyParams.returns({
_id: '12345',
userId: 'max@example.com'
});
keychainMock.saveLocalPublicKey.yields(42);
scope.onError = function(err) {
expect(err).to.equal(42);
done();
};
scope.importKey(keyArmored);
});
});
describe('removeKey', function() {
it('should work', function(done) {
var key = {
_id: '12345'
};
keychainMock.removeLocalPublicKey.withArgs('12345').yields();
scope.listKeys = function() {
done();
};
scope.removeKey(key);
});
it('should fail due to error in keychain.removeLocalPublicKey', function(done) {
var key = {
_id: '12345'
};
keychainMock.removeLocalPublicKey.withArgs('12345').yields(42);
scope.onError = function(err) {
expect(err).to.equal(42);
done();
};
scope.removeKey(key);
});
});
});

View File

@ -1,58 +1,55 @@
define(function(require) {
'use strict';
'use strict';
var Crypto = require('js/crypto/crypto'),
util = require('js/crypto/util'),
config = require('js/app-config').config,
expect = chai.expect;
var Crypto = require('../../src/js/crypto/crypto'),
config = require('../../src/js/app-config').config,
util = require('crypto-lib').util;
describe('Crypto unit tests', function() {
this.timeout(20000);
describe('Crypto unit tests', function() {
this.timeout(20000);
var crypto,
password = 'password',
keySize = config.symKeySize,
ivSize = config.symIvSize;
var crypto,
password = 'password',
keySize = config.symKeySize,
ivSize = config.symIvSize;
beforeEach(function() {
crypto = new Crypto();
});
beforeEach(function() {
crypto = new Crypto();
});
afterEach(function() {});
afterEach(function() {});
describe('AES encrypt/decrypt', function() {
it('should work', function(done) {
var plaintext = 'Hello, World!';
var key = util.random(keySize);
var iv = util.random(ivSize);
describe('AES encrypt/decrypt', function() {
it('should work', function(done) {
var plaintext = 'Hello, World!';
var key = util.random(keySize);
var iv = util.random(ivSize);
crypto.encrypt(plaintext, key, iv, function(err, ciphertext) {
crypto.encrypt(plaintext, key, iv, function(err, ciphertext) {
expect(err).to.not.exist;
expect(ciphertext).to.exist;
crypto.decrypt(ciphertext, key, iv, function(err, decrypted) {
expect(err).to.not.exist;
expect(ciphertext).to.exist;
crypto.decrypt(ciphertext, key, iv, function(err, decrypted) {
expect(err).to.not.exist;
expect(decrypted).to.equal(plaintext);
done();
});
});
});
});
describe("PBKDF2 (Async/Worker)", function() {
it('should work', function(done) {
var salt = util.random(keySize);
crypto.deriveKey(password, salt, keySize, function(err, key) {
expect(err).to.not.exist;
expect(util.base642Str(key).length * 8).to.equal(keySize);
expect(decrypted).to.equal(plaintext);
done();
});
});
});
});
describe("PBKDF2 (Async/Worker)", function() {
it('should work', function(done) {
var salt = util.random(keySize);
crypto.deriveKey(password, salt, keySize, function(err, key) {
expect(err).to.not.exist;
expect(util.base642Str(key).length * 8).to.equal(keySize);
done();
});
});
});
});

View File

@ -1,105 +1,101 @@
define(function(require) {
'use strict';
'use strict';
var LawnchairDAO = require('js/dao/lawnchair-dao'),
DeviceStorageDAO = require('js/dao/devicestorage-dao'),
expect = chai.expect;
var LawnchairDAO = require('../../src/js/dao/lawnchair-dao'),
DeviceStorageDAO = require('../../src/js/dao/devicestorage-dao');
var testUser = 'test@example.com';
var testUser = 'test@example.com';
describe('Device Storage DAO unit tests', function() {
describe('Device Storage DAO unit tests', function() {
var storageDao, lawnchairDaoStub;
var storageDao, lawnchairDaoStub;
beforeEach(function() {
lawnchairDaoStub = sinon.createStubInstance(LawnchairDAO);
storageDao = new DeviceStorageDAO(lawnchairDaoStub);
beforeEach(function() {
lawnchairDaoStub = sinon.createStubInstance(LawnchairDAO);
storageDao = new DeviceStorageDAO(lawnchairDaoStub);
});
afterEach(function() {});
describe('init', function() {
it('should work', function(done) {
lawnchairDaoStub.init.yields();
storageDao.init(testUser, function(err) {
expect(err).to.not.exist;
expect(lawnchairDaoStub.init.calledOnce).to.be.true;
done();
});
});
});
afterEach(function() {});
describe('store list', function() {
it('should fail', function(done) {
var list = [{}];
describe('init', function() {
it('should work', function(done) {
lawnchairDaoStub.init.yields();
storageDao.init(testUser, function(err) {
expect(err).to.not.exist;
expect(lawnchairDaoStub.init.calledOnce).to.be.true;
done();
});
storageDao.storeList(list, '', function(err) {
expect(err).to.exist;
done();
});
});
describe('store list', function() {
it('should fail', function(done) {
var list = [{}];
it('should work with empty list', function(done) {
var list = [];
storageDao.storeList(list, '', function(err) {
expect(err).to.exist;
done();
});
});
it('should work with empty list', function(done) {
var list = [];
storageDao.storeList(list, 'email', function(err) {
expect(err).to.not.exist;
done();
});
});
it('should work', function(done) {
lawnchairDaoStub.batch.yields();
var list = [{
foo: 'bar'
}];
storageDao.storeList(list, 'email', function(err) {
expect(err).to.not.exist;
expect(lawnchairDaoStub.batch.calledOnce).to.be.true;
done();
});
storageDao.storeList(list, 'email', function(err) {
expect(err).to.not.exist;
done();
});
});
describe('remove list', function() {
it('should work', function(done) {
lawnchairDaoStub.removeList.yields();
it('should work', function(done) {
lawnchairDaoStub.batch.yields();
storageDao.removeList('email', function(err) {
expect(err).to.not.exist;
expect(lawnchairDaoStub.removeList.calledOnce).to.be.true;
done();
});
var list = [{
foo: 'bar'
}];
storageDao.storeList(list, 'email', function(err) {
expect(err).to.not.exist;
expect(lawnchairDaoStub.batch.calledOnce).to.be.true;
done();
});
});
});
describe('list items', function() {
it('should work', function(done) {
lawnchairDaoStub.list.yields();
describe('remove list', function() {
it('should work', function(done) {
lawnchairDaoStub.removeList.yields();
storageDao.listItems('email', 0, null, function(err) {
expect(err).to.not.exist;
expect(lawnchairDaoStub.list.calledOnce).to.be.true;
done();
});
storageDao.removeList('email', function(err) {
expect(err).to.not.exist;
expect(lawnchairDaoStub.removeList.calledOnce).to.be.true;
done();
});
});
});
describe('clear', function() {
it('should work', function(done) {
lawnchairDaoStub.clear.yields();
describe('list items', function() {
it('should work', function(done) {
lawnchairDaoStub.list.yields();
storageDao.clear(function(err) {
expect(err).to.not.exist;
expect(lawnchairDaoStub.clear.calledOnce).to.be.true;
done();
});
storageDao.listItems('email', 0, null, function(err) {
expect(err).to.not.exist;
expect(lawnchairDaoStub.list.calledOnce).to.be.true;
done();
});
});
});
describe('clear', function() {
it('should work', function(done) {
lawnchairDaoStub.clear.yields();
storageDao.clear(function(err) {
expect(err).to.not.exist;
expect(lawnchairDaoStub.clear.calledOnce).to.be.true;
done();
});
});
});
});

View File

@ -1,50 +1,46 @@
define(function(require) {
'use strict';
'use strict';
var expect = chai.expect,
angular = require('angular'),
mocks = require('angularMocks'),
DialogCtrl = require('js/controller/dialog');
var mocks = angular.mocks,
DialogCtrl = require('../../src/js/controller/dialog');
describe('Dialog Controller unit test', function() {
var scope, dialogCtrl;
describe('Dialog Controller unit test', function() {
var scope, dialogCtrl;
beforeEach(function() {
angular.module('dialogtest', []);
mocks.module('dialogtest');
mocks.inject(function($rootScope, $controller) {
scope = $rootScope.$new();
scope.state = {
dialog: {}
};
dialogCtrl = $controller(DialogCtrl, {
$scope: scope
});
});
});
afterEach(function() {});
describe('confirm', function() {
it('should work', function(done) {
scope.state.dialog.callback = function(confirmed) {
expect(confirmed).to.be.true;
expect(scope.state.dialog.open).to.be.false;
done();
};
scope.confirm(true);
});
});
describe('cancel', function() {
it('should work', function(done) {
scope.state.dialog.callback = function(confirmed) {
expect(confirmed).to.be.false;
expect(scope.state.dialog.open).to.be.false;
done();
};
scope.confirm(false);
beforeEach(function() {
angular.module('dialogtest', []);
mocks.module('dialogtest');
mocks.inject(function($rootScope, $controller) {
scope = $rootScope.$new();
scope.state = {
dialog: {}
};
dialogCtrl = $controller(DialogCtrl, {
$scope: scope
});
});
});
afterEach(function() {});
describe('confirm', function() {
it('should work', function(done) {
scope.state.dialog.callback = function(confirmed) {
expect(confirmed).to.be.true;
expect(scope.state.dialog.open).to.be.false;
done();
};
scope.confirm(true);
});
});
describe('cancel', function() {
it('should work', function(done) {
scope.state.dialog.callback = function(confirmed) {
expect(confirmed).to.be.false;
expect(scope.state.dialog.open).to.be.false;
done();
};
scope.confirm(false);
});
});
});

File diff suppressed because it is too large Load Diff

View File

@ -8,12 +8,71 @@
</head>
<body>
<div id="mocha"></div>
<script>
//
// Polyfills
//
(function() {
'use strict';
// Mozilla bind polyfill because phantomjs is stupid
if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== "function") {
// closest thing possible to the ECMAScript 5 internal IsCallable function
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
FNOP = function() {},
fBound = function() {
return fToBind.apply(this instanceof FNOP && oThis ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments)));
};
FNOP.prototype = this.prototype;
fBound.prototype = new FNOP();
return fBound;
};
}
// a warm round of applause for phantomjs for missing events
(function() {
function CustomEvent(event, params) {
params = params || {
bubbles: false,
cancelable: false,
detail: undefined
};
var evt = document.createEvent('CustomEvent');
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
return evt;
}
CustomEvent.prototype = window.Event.prototype;
window.CustomEvent = CustomEvent;
})();
})();
</script>
<script src="../lib/chai.js"></script>
<script src="../lib/sinon.js"></script>
<script src="../lib/mocha.js"></script>
<script src="../lib/sinon.js"></script>
<script data-main="main.js" src="../../src/lib/require.js"></script>
<script>
window.expect = chai.expect;
mocha.setup('bdd');
</script>
<script src="index.js"></script>
<script>
mocha.checkLeaks();
mocha.globals([]);
mocha.run();
</script>
</body>
</html>

View File

@ -1,108 +1,105 @@
define(function(require) {
'use strict';
'use strict';
var RestDAO = require('js/dao/rest-dao'),
InvitationDAO = require('js/dao/invitation-dao'),
expect = chai.expect;
var RestDAO = require('../../src/js/dao/rest-dao'),
InvitationDAO = require('../../src/js/dao/invitation-dao');
describe('Invitation DAO unit tests', function() {
var restDaoStub, invitationDao,
alice = 'zuhause@aol.com',
bob = 'manfred.mustermann@musterdomain.com',
expectedUri = '/invitation/recipient/' + alice + '/sender/' + bob;
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);
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('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({
recipient: alice,
sender: bob
}, function(err, status) {
expect(err).to.not.exist;
expect(status).to.equal(InvitationDAO.INVITE_SUCCESS);
expect(restDaoStub.put.calledWith({}, expectedUri)).to.be.true;
done();
});
});
describe('invite', function() {
it('should invite the recipient', function(done) {
restDaoStub.put.yieldsAsync(null, undefined, 201);
it('should point out already invited recipient', function(done) {
restDaoStub.put.yieldsAsync(null, undefined, 304);
invitationDao.invite({
recipient: alice,
sender: bob
}, function(err, status) {
expect(err).to.not.exist;
expect(status).to.equal(InvitationDAO.INVITE_SUCCESS);
expect(restDaoStub.put.calledWith({}, expectedUri)).to.be.true;
done();
});
invitationDao.invite({
recipient: alice,
sender: 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.'
});
it('should point out already invited recipient', function(done) {
restDaoStub.put.yieldsAsync(null, undefined, 304);
invitationDao.invite({
recipient: alice,
sender: bob
}, function(err, status) {
expect(err).to.not.exist;
expect(status).to.equal(InvitationDAO.INVITE_PENDING);
done();
});
invitationDao.invite({
recipient: alice,
sender: bob
}, function(err, status) {
expect(err).to.exist;
expect(status).to.not.exist;
done();
});
});
it('should not work for http error', function(done) {
restDaoStub.put.yieldsAsync({
errMsg: 'jawollja.'
});
it('should not work for unexpected response', function(done) {
restDaoStub.put.yieldsAsync(null, undefined, 1337);
invitationDao.invite({
recipient: alice,
sender: bob
}, function(err, status) {
expect(err).to.exist;
expect(status).to.not.exist;
done();
});
invitationDao.invite({
recipient: alice,
sender: 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);
it('should report erroneous usage', function() {
invitationDao.invite({
sender: bob
}, expectError);
invitationDao.invite({
recipient: alice,
sender: bob
}, function(err, status) {
expect(err).to.exist;
expect(status).to.not.exist;
done();
});
});
invitationDao.invite({
recipient: alice,
}, expectError);
it('should report erroneous usage', function() {
invitationDao.invite({
sender: bob
}, expectError);
invitationDao.invite({
recipient: 123,
sender: 123
}, expectError);
invitationDao.invite({
recipient: alice,
}, expectError);
invitationDao.invite('asd', expectError);
invitationDao.invite({
recipient: 123,
sender: 123
}, expectError);
invitationDao.invite('asd', expectError);
function expectError(err, status) {
expect(err).to.exist;
expect(status).to.not.exist;
}
});
function expectError(err, status) {
expect(err).to.exist;
expect(status).to.not.exist;
}
});
});
});

File diff suppressed because it is too large Load Diff

View File

@ -1,152 +1,148 @@
define(function(require) {
'use strict';
'use strict';
var LawnchairDAO = require('js/dao/lawnchair-dao'),
expect = chai.expect;
var LawnchairDAO = require('../../src/js/dao/lawnchair-dao');
var dbName = 'lawnchair@test.com';
var dbName = 'lawnchair@test.com';
var key = 'type_1';
var data = {
name: 'testName1',
type: 'testType1'
};
var key = 'type_1';
var data = {
name: 'testName1',
type: 'testType1'
};
var key2 = 'type_2';
var data2 = {
name: 'testName2',
type: 'testType2'
};
var key2 = 'type_2';
var data2 = {
name: 'testName2',
type: 'testType2'
};
describe('Lawnchair DAO unit tests', function() {
var lawnchairDao;
describe('Lawnchair DAO unit tests', function() {
var lawnchairDao;
beforeEach(function(done) {
lawnchairDao = new LawnchairDAO();
lawnchairDao.init(dbName, function(err) {
expect(err).to.not.exist;
expect(lawnchairDao._db).to.exist;
beforeEach(function(done) {
lawnchairDao = new LawnchairDAO();
lawnchairDao.init(dbName, function(err) {
expect(err).to.not.exist;
expect(lawnchairDao._db).to.exist;
done();
});
});
afterEach(function(done) {
lawnchairDao.clear(function(err) {
expect(err).to.not.exist;
done();
});
});
describe('read', function() {
it('should fail', function(done) {
lawnchairDao.read(undefined, function(err) {
expect(err).to.exist;
done();
});
});
});
describe('list', function() {
it('should fail', function(done) {
lawnchairDao.list(undefined, 0, null, function(err) {
expect(err).to.exist;
done();
});
});
});
describe('remove list', function() {
it('should fail', function(done) {
lawnchairDao.removeList(undefined, function(err) {
expect(err).to.exist;
done();
});
});
});
describe('persist/read/remove', function() {
it('should fail', function(done) {
lawnchairDao.persist(undefined, data, function(err) {
expect(err).to.exist;
done();
});
});
it('should fail', function(done) {
lawnchairDao.persist('1234', undefined, function(err) {
expect(err).to.exist;
done();
});
});
afterEach(function(done) {
lawnchairDao.clear(function(err) {
it('should work', function(done) {
lawnchairDao.persist(key, data, function(err) {
expect(err).to.not.exist;
lawnchairDao.read(key, onRead);
});
function onRead(err, fetched) {
expect(err).to.not.exist;
expect(fetched).to.deep.equal(data);
lawnchairDao.remove(key, onRemove);
}
function onRemove(err) {
expect(err).to.not.exist;
lawnchairDao.read(key, onReadAgain);
}
function onReadAgain(err, fetched) {
expect(err).to.not.exist;
expect(fetched).to.not.exist;
done();
}
});
});
describe('batch/list/removeList', function() {
it('should fails', function(done) {
lawnchairDao.batch({}, function(err) {
expect(err).to.exist;
done();
});
});
describe('read', function() {
it('should fail', function(done) {
lawnchairDao.read(undefined, function(err) {
expect(err).to.exist;
done();
});
it('should work', function(done) {
var list = [{
key: key,
object: data
}, {
key: key2,
object: data2
}];
lawnchairDao.batch(list, function(err) {
expect(err).to.not.exist;
lawnchairDao.list('type', 0, null, onList);
});
function onList(err, fetched) {
expect(err).to.not.exist;
expect(fetched.length).to.equal(2);
expect(fetched[0]).to.deep.equal(list[0].object);
lawnchairDao.removeList('type', onRemoveList);
}
function onRemoveList(err) {
expect(err).to.not.exist;
lawnchairDao.list('type', 0, null, onListAgain);
}
function onListAgain(err, fetched) {
expect(err).to.not.exist;
expect(fetched).to.exist;
expect(fetched.length).to.equal(0);
done();
}
});
describe('list', function() {
it('should fail', function(done) {
lawnchairDao.list(undefined, 0, null, function(err) {
expect(err).to.exist;
done();
});
});
});
describe('remove list', function() {
it('should fail', function(done) {
lawnchairDao.removeList(undefined, function(err) {
expect(err).to.exist;
done();
});
});
});
describe('persist/read/remove', function() {
it('should fail', function(done) {
lawnchairDao.persist(undefined, data, function(err) {
expect(err).to.exist;
done();
});
});
it('should fail', function(done) {
lawnchairDao.persist('1234', undefined, function(err) {
expect(err).to.exist;
done();
});
});
it('should work', function(done) {
lawnchairDao.persist(key, data, function(err) {
expect(err).to.not.exist;
lawnchairDao.read(key, onRead);
});
function onRead(err, fetched) {
expect(err).to.not.exist;
expect(fetched).to.deep.equal(data);
lawnchairDao.remove(key, onRemove);
}
function onRemove(err) {
expect(err).to.not.exist;
lawnchairDao.read(key, onReadAgain);
}
function onReadAgain(err, fetched) {
expect(err).to.not.exist;
expect(fetched).to.not.exist;
done();
}
});
});
describe('batch/list/removeList', function() {
it('should fails', function(done) {
lawnchairDao.batch({}, function(err) {
expect(err).to.exist;
done();
});
});
it('should work', function(done) {
var list = [{
key: key,
object: data
}, {
key: key2,
object: data2
}];
lawnchairDao.batch(list, function(err) {
expect(err).to.not.exist;
lawnchairDao.list('type', 0, null, onList);
});
function onList(err, fetched) {
expect(err).to.not.exist;
expect(fetched.length).to.equal(2);
expect(fetched[0]).to.deep.equal(list[0].object);
lawnchairDao.removeList('type', onRemoveList);
}
function onRemoveList(err) {
expect(err).to.not.exist;
lawnchairDao.list('type', 0, null, onListAgain);
}
function onListAgain(err, fetched) {
expect(err).to.not.exist;
expect(fetched).to.exist;
expect(fetched.length).to.equal(0);
done();
}
});
});
});
});

View File

@ -1,236 +1,232 @@
define(function(require) {
'use strict';
'use strict';
var expect = chai.expect,
angular = require('angular'),
mocks = require('angularMocks'),
LoginCtrl = require('js/controller/login'),
EmailDAO = require('js/dao/email-dao'),
Auth = require('js/bo/auth'),
appController = require('js/app-controller'),
KeychainDAO = require('js/dao/keychain-dao');
var mocks = angular.mocks,
LoginCtrl = require('../../src/js/controller/login'),
EmailDAO = require('../../src/js/dao/email-dao'),
Auth = require('../../src/js/bo/auth'),
appController = require('../../src/js/app-controller'),
KeychainDAO = require('../../src/js/dao/keychain-dao');
describe('Login Controller unit test', function() {
var scope, location, ctrl,
origEmailDao, emailDaoMock,
origKeychain, keychainMock,
origAuth, authStub,
emailAddress = 'fred@foo.com',
startAppStub,
checkForUpdateStub,
initStub;
describe('Login Controller unit test', function() {
var scope, location, ctrl,
origEmailDao, emailDaoMock,
origKeychain, keychainMock,
origAuth, authStub,
emailAddress = 'fred@foo.com',
startAppStub,
checkForUpdateStub,
initStub;
describe('initialization', function() {
var hasChrome, hasIdentity;
describe('initialization', function() {
var hasChrome, hasIdentity;
beforeEach(function() {
hasChrome = !!window.chrome;
hasIdentity = !!window.chrome.identity;
window.chrome = window.chrome || {};
window.chrome.identity = window.chrome.identity || {};
beforeEach(function() {
hasChrome = !!window.chrome;
hasIdentity = !!window.chrome.identity;
window.chrome = window.chrome || {};
window.chrome.identity = window.chrome.identity || {};
// remember original module to restore later, then replace it
origEmailDao = appController._emailDao;
origKeychain = appController._keychain;
origAuth = appController._auth;
appController._emailDao = emailDaoMock = sinon.createStubInstance(EmailDAO);
appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO);
appController._auth = authStub = sinon.createStubInstance(Auth);
// remember original module to restore later, then replace it
origEmailDao = appController._emailDao;
origKeychain = appController._keychain;
origAuth = appController._auth;
appController._emailDao = emailDaoMock = sinon.createStubInstance(EmailDAO);
appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO);
appController._auth = authStub = sinon.createStubInstance(Auth);
startAppStub = sinon.stub(appController, 'start');
checkForUpdateStub = sinon.stub(appController, 'checkForUpdate');
initStub = sinon.stub(appController, 'init');
startAppStub = sinon.stub(appController, 'start');
checkForUpdateStub = sinon.stub(appController, 'checkForUpdate');
initStub = sinon.stub(appController, 'init');
});
afterEach(function() {
// restore the browser
if (!hasIdentity) {
delete window.chrome.identity;
}
if (!hasChrome) {
delete window.chrome;
}
// restore the app controller module
appController._emailDao = origEmailDao;
appController._keychain = origKeychain;
appController._auth = origAuth;
appController.start.restore && appController.start.restore();
appController.checkForUpdate.restore && appController.checkForUpdate.restore();
appController.init.restore && appController.init.restore();
location.path.restore && location.path.restore();
startAppStub.restore();
checkForUpdateStub.restore();
initStub.restore();
});
it('should forward directly to desktop for empty passphrase', function(done) {
var testKeys = {
privateKey: 'a',
publicKey: 'b'
};
startAppStub.yields();
authStub.getEmailAddress.yields(null, {
emailAddress: emailAddress,
realname: 'asd'
});
initStub.yields(null, testKeys);
afterEach(function() {
// restore the browser
if (!hasIdentity) {
delete window.chrome.identity;
}
emailDaoMock.unlock.withArgs({
keypair: testKeys,
passphrase: undefined
}).yields();
if (!hasChrome) {
delete window.chrome;
}
// restore the app controller module
appController._emailDao = origEmailDao;
appController._keychain = origKeychain;
appController._auth = origAuth;
appController.start.restore && appController.start.restore();
appController.checkForUpdate.restore && appController.checkForUpdate.restore();
appController.init.restore && appController.init.restore();
location.path.restore && location.path.restore();
startAppStub.restore();
checkForUpdateStub.restore();
initStub.restore();
});
it('should forward directly to desktop for empty passphrase', function(done) {
var testKeys = {
privateKey: 'a',
publicKey: 'b'
};
startAppStub.yields();
authStub.getEmailAddress.yields(null, {
emailAddress: emailAddress,
realname: 'asd'
angular.module('logintest', []);
mocks.module('logintest');
mocks.inject(function($controller, $rootScope, $location) {
location = $location;
sinon.stub(location, 'path', function(path) {
expect(path).to.equal('/desktop');
expect(startAppStub.calledOnce).to.be.true;
expect(checkForUpdateStub.calledOnce).to.be.true;
expect(authStub.getEmailAddress.calledOnce).to.be.true;
done();
});
initStub.yields(null, testKeys);
emailDaoMock.unlock.withArgs({
keypair: testKeys,
passphrase: undefined
}).yields();
angular.module('logintest', []);
mocks.module('logintest');
mocks.inject(function($controller, $rootScope, $location) {
location = $location;
sinon.stub(location, 'path', function(path) {
expect(path).to.equal('/desktop');
expect(startAppStub.calledOnce).to.be.true;
expect(checkForUpdateStub.calledOnce).to.be.true;
expect(authStub.getEmailAddress.calledOnce).to.be.true;
done();
});
scope = $rootScope.$new();
scope.state = {};
ctrl = $controller(LoginCtrl, {
$location: location,
$scope: scope
});
scope = $rootScope.$new();
scope.state = {};
ctrl = $controller(LoginCtrl, {
$location: location,
$scope: scope
});
});
});
it('should forward to existing user login', function(done) {
var testKeys = {
privateKey: 'a',
publicKey: 'b'
};
it('should forward to existing user login', function(done) {
var testKeys = {
privateKey: 'a',
publicKey: 'b'
};
startAppStub.yields();
authStub.getEmailAddress.yields(null, {
emailAddress: emailAddress,
realname: 'asd'
startAppStub.yields();
authStub.getEmailAddress.yields(null, {
emailAddress: emailAddress,
realname: 'asd'
});
initStub.yields(null, testKeys);
emailDaoMock.unlock.withArgs({
keypair: testKeys,
passphrase: undefined
}).yields({});
angular.module('logintest', []);
mocks.module('logintest');
mocks.inject(function($controller, $rootScope, $location) {
location = $location;
sinon.stub(location, 'path', function(path) {
expect(path).to.equal('/login-existing');
expect(startAppStub.calledOnce).to.be.true;
expect(checkForUpdateStub.calledOnce).to.be.true;
expect(authStub.getEmailAddress.calledOnce).to.be.true;
done();
});
initStub.yields(null, testKeys);
emailDaoMock.unlock.withArgs({
keypair: testKeys,
passphrase: undefined
}).yields({});
angular.module('logintest', []);
mocks.module('logintest');
mocks.inject(function($controller, $rootScope, $location) {
location = $location;
sinon.stub(location, 'path', function(path) {
expect(path).to.equal('/login-existing');
expect(startAppStub.calledOnce).to.be.true;
expect(checkForUpdateStub.calledOnce).to.be.true;
expect(authStub.getEmailAddress.calledOnce).to.be.true;
done();
});
scope = $rootScope.$new();
scope.state = {};
ctrl = $controller(LoginCtrl, {
$location: location,
$scope: scope
});
scope = $rootScope.$new();
scope.state = {};
ctrl = $controller(LoginCtrl, {
$location: location,
$scope: scope
});
});
});
it('should forward to privatekey download login', function(done) {
startAppStub.yields();
authStub.getEmailAddress.yields(null, {
emailAddress: emailAddress,
realname: 'asd'
});
initStub.yields(null, {
publicKey: 'b'
});
keychainMock.requestPrivateKeyDownload.yields(null, {});
it('should forward to privatekey download login', function(done) {
startAppStub.yields();
authStub.getEmailAddress.yields(null, {
emailAddress: emailAddress,
realname: 'asd'
});
initStub.yields(null, {
publicKey: 'b'
});
keychainMock.requestPrivateKeyDownload.yields(null, {});
angular.module('logintest', []);
mocks.module('logintest');
mocks.inject(function($controller, $rootScope, $location) {
location = $location;
sinon.stub(location, 'path', function(path) {
expect(path).to.equal('/login-privatekey-download');
expect(startAppStub.calledOnce).to.be.true;
expect(checkForUpdateStub.calledOnce).to.be.true;
expect(authStub.getEmailAddress.calledOnce).to.be.true;
expect(keychainMock.requestPrivateKeyDownload.calledOnce).to.be.true;
done();
});
scope = $rootScope.$new();
scope.state = {};
ctrl = $controller(LoginCtrl, {
$location: location,
$scope: scope
});
angular.module('logintest', []);
mocks.module('logintest');
mocks.inject(function($controller, $rootScope, $location) {
location = $location;
sinon.stub(location, 'path', function(path) {
expect(path).to.equal('/login-privatekey-download');
expect(startAppStub.calledOnce).to.be.true;
expect(checkForUpdateStub.calledOnce).to.be.true;
expect(authStub.getEmailAddress.calledOnce).to.be.true;
expect(keychainMock.requestPrivateKeyDownload.calledOnce).to.be.true;
done();
});
scope = $rootScope.$new();
scope.state = {};
ctrl = $controller(LoginCtrl, {
$location: location,
$scope: scope
});
});
});
it('should forward to new device login', function(done) {
startAppStub.yields();
authStub.getEmailAddress.yields(null, {
emailAddress: emailAddress,
realname: 'asd'
});
initStub.yields(null, {
publicKey: 'b'
});
keychainMock.requestPrivateKeyDownload.yields();
it('should forward to new device login', function(done) {
startAppStub.yields();
authStub.getEmailAddress.yields(null, {
emailAddress: emailAddress,
realname: 'asd'
});
initStub.yields(null, {
publicKey: 'b'
});
keychainMock.requestPrivateKeyDownload.yields();
angular.module('logintest', []);
mocks.module('logintest');
mocks.inject(function($controller, $rootScope, $location) {
location = $location;
sinon.stub(location, 'path', function(path) {
expect(path).to.equal('/login-new-device');
expect(startAppStub.calledOnce).to.be.true;
expect(checkForUpdateStub.calledOnce).to.be.true;
expect(authStub.getEmailAddress.calledOnce).to.be.true;
expect(keychainMock.requestPrivateKeyDownload.calledOnce).to.be.true;
done();
});
scope = $rootScope.$new();
scope.state = {};
ctrl = $controller(LoginCtrl, {
$location: location,
$scope: scope
});
angular.module('logintest', []);
mocks.module('logintest');
mocks.inject(function($controller, $rootScope, $location) {
location = $location;
sinon.stub(location, 'path', function(path) {
expect(path).to.equal('/login-new-device');
expect(startAppStub.calledOnce).to.be.true;
expect(checkForUpdateStub.calledOnce).to.be.true;
expect(authStub.getEmailAddress.calledOnce).to.be.true;
expect(keychainMock.requestPrivateKeyDownload.calledOnce).to.be.true;
done();
});
scope = $rootScope.$new();
scope.state = {};
ctrl = $controller(LoginCtrl, {
$location: location,
$scope: scope
});
});
});
it('should forward to initial login', function(done) {
startAppStub.yields();
authStub.getEmailAddress.yields(null, {
emailAddress: emailAddress,
realname: 'asd'
it('should forward to initial login', function(done) {
startAppStub.yields();
authStub.getEmailAddress.yields(null, {
emailAddress: emailAddress,
realname: 'asd'
});
initStub.yields();
angular.module('logintest', []);
mocks.module('logintest');
mocks.inject(function($controller, $rootScope, $location) {
location = $location;
sinon.stub(location, 'path', function(path) {
expect(path).to.equal('/login-initial');
expect(startAppStub.calledOnce).to.be.true;
expect(checkForUpdateStub.calledOnce).to.be.true;
expect(authStub.getEmailAddress.calledOnce).to.be.true;
done();
});
initStub.yields();
angular.module('logintest', []);
mocks.module('logintest');
mocks.inject(function($controller, $rootScope, $location) {
location = $location;
sinon.stub(location, 'path', function(path) {
expect(path).to.equal('/login-initial');
expect(startAppStub.calledOnce).to.be.true;
expect(checkForUpdateStub.calledOnce).to.be.true;
expect(authStub.getEmailAddress.calledOnce).to.be.true;
done();
});
scope = $rootScope.$new();
scope.state = {};
ctrl = $controller(LoginCtrl, {
$location: location,
$scope: scope
});
scope = $rootScope.$new();
scope.state = {};
ctrl = $controller(LoginCtrl, {
$location: location,
$scope: scope
});
});
});

View File

@ -1,116 +1,112 @@
define(function(require) {
'use strict';
'use strict';
var expect = chai.expect,
angular = require('angular'),
Auth = require('js/bo/auth'),
mocks = require('angularMocks'),
LoginExistingCtrl = require('js/controller/login-existing'),
EmailDAO = require('js/dao/email-dao'),
KeychainDAO = require('js/dao/keychain-dao'),
appController = require('js/app-controller');
var Auth = require('../../src/js/bo/auth'),
mocks = angular.mocks,
LoginExistingCtrl = require('../../src/js/controller/login-existing'),
EmailDAO = require('../../src/js/dao/email-dao'),
KeychainDAO = require('../../src/js/dao/keychain-dao'),
appController = require('../../src/js/app-controller');
describe('Login (existing user) Controller unit test', function() {
var scope, location, ctrl, origEmailDao, emailDaoMock,
origAuth, authMock,
emailAddress = 'fred@foo.com',
passphrase = 'asd',
keychainMock;
describe('Login (existing user) Controller unit test', function() {
var scope, location, ctrl, origEmailDao, emailDaoMock,
origAuth, authMock,
emailAddress = 'fred@foo.com',
passphrase = 'asd',
keychainMock;
beforeEach(function() {
// remember original module to restore later
origEmailDao = appController._emailDao;
origAuth = appController._auth;
beforeEach(function() {
// remember original module to restore later
origEmailDao = appController._emailDao;
origAuth = appController._auth;
appController._emailDao = emailDaoMock = sinon.createStubInstance(EmailDAO);
appController._auth = authMock = sinon.createStubInstance(Auth);
appController._emailDao = emailDaoMock = sinon.createStubInstance(EmailDAO);
appController._auth = authMock = sinon.createStubInstance(Auth);
keychainMock = sinon.createStubInstance(KeychainDAO);
emailDaoMock._keychain = keychainMock;
keychainMock = sinon.createStubInstance(KeychainDAO);
emailDaoMock._keychain = keychainMock;
emailDaoMock._account = {
emailAddress: emailAddress,
};
emailDaoMock._account = {
emailAddress: emailAddress,
};
angular.module('loginexistingtest', []);
mocks.module('loginexistingtest');
mocks.inject(function($rootScope, $controller, $location) {
location = $location;
scope = $rootScope.$new();
scope.state = {};
ctrl = $controller(LoginExistingCtrl, {
$scope: scope,
$routeParams: {}
});
angular.module('loginexistingtest', []);
mocks.module('loginexistingtest');
mocks.inject(function($rootScope, $controller, $location) {
location = $location;
scope = $rootScope.$new();
scope.state = {};
ctrl = $controller(LoginExistingCtrl, {
$scope: scope,
$routeParams: {}
});
});
});
afterEach(function() {
// restore the module
appController._emailDao = origEmailDao;
appController._auth = origAuth;
afterEach(function() {
// restore the module
appController._emailDao = origEmailDao;
appController._auth = origAuth;
});
describe('initial state', function() {
it('should be well defined', function() {
expect(scope.buttonEnabled).to.be.true;
expect(scope.incorrect).to.be.false;
expect(scope.change).to.exist;
expect(scope.confirmPassphrase).to.exist;
});
});
describe('initial state', function() {
it('should be well defined', function() {
expect(scope.buttonEnabled).to.be.true;
describe('functionality', function() {
describe('change', function() {
it('should set incorrect to false', function() {
scope.incorrect = true;
scope.change();
expect(scope.incorrect).to.be.false;
expect(scope.change).to.exist;
expect(scope.confirmPassphrase).to.exist;
});
});
describe('functionality', function() {
describe('change', function() {
it('should set incorrect to false', function() {
scope.incorrect = true;
describe('confirm passphrase', function() {
it('should unlock crypto and start', function() {
var keypair = {},
pathSpy = sinon.spy(location, 'path');
scope.passphrase = passphrase;
keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, keypair);
emailDaoMock.unlock.withArgs({
keypair: keypair,
passphrase: passphrase
}).yields();
authMock.storeCredentials.yields();
scope.change();
expect(scope.incorrect).to.be.false;
});
scope.confirmPassphrase();
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
expect(emailDaoMock.unlock.calledOnce).to.be.true;
expect(pathSpy.calledOnce).to.be.true;
expect(pathSpy.calledWith('/desktop')).to.be.true;
});
describe('confirm passphrase', function() {
it('should unlock crypto and start', function() {
var keypair = {},
pathSpy = sinon.spy(location, 'path');
scope.passphrase = passphrase;
keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, keypair);
emailDaoMock.unlock.withArgs({
keypair: keypair,
passphrase: passphrase
}).yields();
authMock.storeCredentials.yields();
it('should not do anything without passphrase', function() {
var pathSpy = sinon.spy(location, 'path');
scope.passphrase = '';
scope.confirmPassphrase();
expect(pathSpy.callCount).to.equal(0);
});
scope.confirmPassphrase();
it('should not work when keypair unavailable', function(done) {
scope.passphrase = passphrase;
keychainMock.getUserKeyPair.withArgs(emailAddress).yields(new Error('asd'));
scope.onError = function(err) {
expect(err.message).to.equal('asd');
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
expect(emailDaoMock.unlock.calledOnce).to.be.true;
expect(pathSpy.calledOnce).to.be.true;
expect(pathSpy.calledWith('/desktop')).to.be.true;
});
done();
};
it('should not do anything without passphrase', function() {
var pathSpy = sinon.spy(location, 'path');
scope.passphrase = '';
scope.confirmPassphrase();
expect(pathSpy.callCount).to.equal(0);
});
it('should not work when keypair unavailable', function(done) {
scope.passphrase = passphrase;
keychainMock.getUserKeyPair.withArgs(emailAddress).yields(new Error('asd'));
scope.onError = function(err) {
expect(err.message).to.equal('asd');
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
done();
};
scope.confirmPassphrase();
});
scope.confirmPassphrase();
});
});
});

View File

@ -1,202 +1,197 @@
define(function(require) {
'use strict';
'use strict';
var expect = chai.expect,
angular = require('angular'),
Auth = require('js/bo/auth'),
mocks = require('angularMocks'),
LoginInitialCtrl = require('js/controller/login-initial'),
PGP = require('js/crypto/pgp'),
EmailDAO = require('js/dao/email-dao'),
appController = require('js/app-controller');
var Auth = require('../../src/js/bo/auth'),
mocks = angular.mocks,
LoginInitialCtrl = require('../../src/js/controller/login-initial'),
PGP = require('../../src/js/crypto/pgp'),
EmailDAO = require('../../src/js/dao/email-dao'),
appController = require('../../src/js/app-controller');
describe('Login (initial user) Controller unit test', function() {
var scope, ctrl, location, origEmailDao, emailDaoMock,
origAuth, authMock,
emailAddress = 'fred@foo.com',
keyId, expectedKeyId,
cryptoMock;
describe('Login (initial user) Controller unit test', function() {
var scope, ctrl, location, origEmailDao, emailDaoMock,
origAuth, authMock,
emailAddress = 'fred@foo.com',
keyId, expectedKeyId,
cryptoMock;
beforeEach(function() {
// remember original module to restore later
origEmailDao = appController._emailDao;
origAuth = appController._auth;
appController._emailDao = emailDaoMock = sinon.createStubInstance(EmailDAO);
appController._auth = authMock = sinon.createStubInstance(Auth);
keyId = '9FEB47936E712926';
expectedKeyId = '6E712926';
cryptoMock = sinon.createStubInstance(PGP);
emailDaoMock._crypto = cryptoMock;
emailDaoMock._account = {
emailAddress: emailAddress,
};
angular.module('logininitialtest', []);
mocks.module('logininitialtest');
mocks.inject(function($rootScope, $controller, $location) {
scope = $rootScope.$new();
location = $location;
scope.state = {
ui: {}
};
ctrl = $controller(LoginInitialCtrl, {
$scope: scope,
$routeParams: {}
});
});
});
afterEach(function() {
// restore the module
appController._emailDao = origEmailDao;
appController._auth = origAuth;
});
describe('initial state', function() {
it('should be well defined', function() {
expect(scope.state.ui).to.equal(1);
});
});
describe('signUpToNewsletter', function() {
var xhrMock, requests;
beforeEach(function() {
// remember original module to restore later
origEmailDao = appController._emailDao;
origAuth = appController._auth;
xhrMock = sinon.useFakeXMLHttpRequest();
requests = [];
appController._emailDao = emailDaoMock = sinon.createStubInstance(EmailDAO);
appController._auth = authMock = sinon.createStubInstance(Auth);
keyId = '9FEB47936E712926';
expectedKeyId = '6E712926';
cryptoMock = sinon.createStubInstance(PGP);
emailDaoMock._crypto = cryptoMock;
emailDaoMock._account = {
emailAddress: emailAddress,
xhrMock.onCreate = function(xhr) {
requests.push(xhr);
};
angular.module('logininitialtest', []);
mocks.module('logininitialtest');
mocks.inject(function($rootScope, $controller, $location) {
scope = $rootScope.$new();
location = $location;
scope.state = {
ui: {}
};
ctrl = $controller(LoginInitialCtrl, {
$scope: scope,
$routeParams: {}
});
});
});
afterEach(function() {
// restore the module
appController._emailDao = origEmailDao;
appController._auth = origAuth;
xhrMock.restore();
});
describe('initial state', function() {
it('should be well defined', function() {
it('should not signup', function() {
scope.state.newsletter = false;
scope.signUpToNewsletter();
expect(requests.length).to.equal(0);
});
it('should fail', function(done) {
scope.state.newsletter = true;
scope.signUpToNewsletter(function(err, xhr) {
expect(err).to.exist;
expect(xhr).to.not.exist;
done();
});
expect(requests.length).to.equal(1);
requests[0].onerror('err');
});
it('should work without callback', function() {
scope.state.newsletter = true;
scope.signUpToNewsletter();
expect(requests.length).to.equal(1);
requests[0].respond(200, {
"Content-Type": "text/plain"
}, 'foobar!');
});
});
describe('go to import key', function() {
var signUpToNewsletterStub;
beforeEach(function() {
signUpToNewsletterStub = sinon.stub(scope, 'signUpToNewsletter');
});
afterEach(function() {
signUpToNewsletterStub.restore();
});
it('should not continue if terms are not accepted', function(done) {
scope.state.agree = undefined;
scope.onError = function(err) {
expect(err.message).to.contain('Terms');
expect(signUpToNewsletterStub.called).to.be.false;
done();
};
scope.importKey();
});
it('should work', function() {
scope.state.agree = true;
scope.importKey();
expect(signUpToNewsletterStub.calledOnce).to.be.true;
expect(location.$$path).to.equal('/login-new-device');
});
});
describe('generate key', function() {
var signUpToNewsletterStub;
beforeEach(function() {
signUpToNewsletterStub = sinon.stub(scope, 'signUpToNewsletter');
});
afterEach(function() {
signUpToNewsletterStub.restore();
});
it('should not continue if terms are not accepted', function(done) {
scope.state.agree = undefined;
scope.onError = function(err) {
expect(err.message).to.contain('Terms');
expect(scope.state.ui).to.equal(1);
});
expect(signUpToNewsletterStub.called).to.be.false;
done();
};
scope.generateKey();
});
describe('signUpToNewsletter', function() {
var xhrMock, requests;
it('should fail due to error in emailDao.unlock', function(done) {
scope.state.agree = true;
beforeEach(function() {
xhrMock = sinon.useFakeXMLHttpRequest();
requests = [];
emailDaoMock.unlock.withArgs({
passphrase: undefined
}).yields(new Error());
authMock.storeCredentials.yields();
xhrMock.onCreate = function(xhr) {
requests.push(xhr);
};
});
scope.onError = function(err) {
expect(err).to.exist;
expect(scope.state.ui).to.equal(1);
expect(signUpToNewsletterStub.called).to.be.true;
done();
};
afterEach(function() {
xhrMock.restore();
});
it('should not signup', function() {
scope.state.newsletter = false;
scope.signUpToNewsletter();
expect(requests.length).to.equal(0);
});
it('should fail', function(done) {
scope.state.newsletter = true;
scope.signUpToNewsletter(function(err, xhr) {
expect(err).to.exist;
expect(xhr).to.not.exist;
done();
});
expect(requests.length).to.equal(1);
requests[0].onerror('err');
});
it('should work without callback', function() {
scope.state.newsletter = true;
scope.signUpToNewsletter();
expect(requests.length).to.equal(1);
requests[0].respond(200, {
"Content-Type": "text/plain"
}, 'foobar!');
});
scope.generateKey();
expect(scope.state.ui).to.equal(2);
});
describe('go to import key', function() {
var signUpToNewsletterStub;
beforeEach(function() {
signUpToNewsletterStub = sinon.stub(scope, 'signUpToNewsletter');
});
afterEach(function() {
signUpToNewsletterStub.restore();
});
it('should unlock crypto', function(done) {
scope.state.agree = true;
it('should not continue if terms are not accepted', function(done) {
scope.state.agree = undefined;
emailDaoMock.unlock.withArgs({
passphrase: undefined
}).yields();
authMock.storeCredentials.yields();
scope.onError = function(err) {
expect(err.message).to.contain('Terms');
expect(signUpToNewsletterStub.called).to.be.false;
done();
};
scope.importKey();
});
it('should work', function() {
scope.state.agree = true;
scope.importKey();
expect(signUpToNewsletterStub.calledOnce).to.be.true;
expect(location.$$path).to.equal('/login-new-device');
});
});
describe('generate key', function() {
var signUpToNewsletterStub;
beforeEach(function() {
signUpToNewsletterStub = sinon.stub(scope, 'signUpToNewsletter');
});
afterEach(function() {
signUpToNewsletterStub.restore();
});
it('should not continue if terms are not accepted', function(done) {
scope.state.agree = undefined;
scope.onError = function(err) {
expect(err.message).to.contain('Terms');
expect(scope.state.ui).to.equal(1);
expect(signUpToNewsletterStub.called).to.be.false;
done();
};
scope.generateKey();
});
it('should fail due to error in emailDao.unlock', function(done) {
scope.state.agree = true;
emailDaoMock.unlock.withArgs({
passphrase: undefined
}).yields(new Error());
authMock.storeCredentials.yields();
scope.onError = function(err) {
expect(err).to.exist;
expect(scope.state.ui).to.equal(1);
expect(signUpToNewsletterStub.called).to.be.true;
done();
};
scope.generateKey();
scope.$apply = function() {
expect(scope.state.ui).to.equal(2);
});
expect(location.$$path).to.equal('/desktop');
expect(emailDaoMock.unlock.calledOnce).to.be.true;
done();
};
it('should unlock crypto', function(done) {
scope.state.agree = true;
emailDaoMock.unlock.withArgs({
passphrase: undefined
}).yields();
authMock.storeCredentials.yields();
scope.$apply = function() {
expect(scope.state.ui).to.equal(2);
expect(location.$$path).to.equal('/desktop');
expect(emailDaoMock.unlock.calledOnce).to.be.true;
done();
};
scope.generateKey();
});
scope.generateKey();
});
});
});

View File

@ -1,190 +1,186 @@
define(function(require) {
'use strict';
'use strict';
var expect = chai.expect,
angular = require('angular'),
mocks = require('angularMocks'),
PGP = require('js/crypto/pgp'),
LoginNewDeviceCtrl = require('js/controller/login-new-device'),
KeychainDAO = require('js/dao/keychain-dao'),
EmailDAO = require('js/dao/email-dao'),
appController = require('js/app-controller');
var mocks = angular.mocks,
PGP = require('../../src/js/crypto/pgp'),
LoginNewDeviceCtrl = require('../../src/js/controller/login-new-device'),
KeychainDAO = require('../../src/js/dao/keychain-dao'),
EmailDAO = require('../../src/js/dao/email-dao'),
appController = require('../../src/js/app-controller');
describe('Login (new device) Controller unit test', function() {
var scope, ctrl, origEmailDao, emailDaoMock, pgpMock,
emailAddress = 'fred@foo.com',
passphrase = 'asd',
keyId,
keychainMock;
describe('Login (new device) Controller unit test', function() {
var scope, ctrl, origEmailDao, emailDaoMock, pgpMock,
emailAddress = 'fred@foo.com',
passphrase = 'asd',
keyId,
keychainMock;
beforeEach(function() {
// remember original module to restore later
origEmailDao = appController._emailDao;
beforeEach(function() {
// remember original module to restore later
origEmailDao = appController._emailDao;
emailDaoMock = sinon.createStubInstance(EmailDAO);
appController._emailDao = emailDaoMock;
emailDaoMock = sinon.createStubInstance(EmailDAO);
appController._emailDao = emailDaoMock;
keyId = '9FEB47936E712926';
emailDaoMock._keychain = keychainMock = sinon.createStubInstance(KeychainDAO);
appController._pgp = pgpMock = sinon.createStubInstance(PGP);
pgpMock.extractPublicKey.returns('publicKeyArmored');
keyId = '9FEB47936E712926';
emailDaoMock._keychain = keychainMock = sinon.createStubInstance(KeychainDAO);
appController._pgp = pgpMock = sinon.createStubInstance(PGP);
pgpMock.extractPublicKey.returns('publicKeyArmored');
emailDaoMock._account = {
emailAddress: emailAddress,
emailDaoMock._account = {
emailAddress: emailAddress,
};
angular.module('loginnewdevicetest', []);
mocks.module('loginnewdevicetest');
mocks.inject(function($rootScope, $controller) {
scope = $rootScope.$new();
scope.state = {
ui: {}
};
angular.module('loginnewdevicetest', []);
mocks.module('loginnewdevicetest');
mocks.inject(function($rootScope, $controller) {
scope = $rootScope.$new();
scope.state = {
ui: {}
};
ctrl = $controller(LoginNewDeviceCtrl, {
$scope: scope,
$routeParams: {}
});
});
});
afterEach(function() {
// restore the module
appController._emailDao = origEmailDao;
});
describe('initial state', function() {
it('should be well defined', function() {
expect(scope.incorrect).to.be.false;
expect(scope.confirmPassphrase).to.exist;
});
});
describe('confirm passphrase', function() {
it('should unlock crypto with a public key on the server', function() {
scope.passphrase = passphrase;
scope.key = {
privateKeyArmored: 'b'
};
pgpMock.getKeyParams.returns({
_id: 'id',
userIds: []
});
keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, {
_id: keyId,
publicKey: 'a'
});
emailDaoMock.unlock.withArgs(sinon.match.any, passphrase).yields();
keychainMock.putUserKeyPair.yields();
scope.confirmPassphrase();
expect(emailDaoMock.unlock.calledOnce).to.be.true;
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
});
it('should unlock crypto with no key on the server', function() {
scope.passphrase = passphrase;
scope.key = {
privateKeyArmored: 'b',
publicKeyArmored: 'a'
};
pgpMock.getKeyParams.returns({
_id: 'id',
userIds: []
});
keychainMock.getUserKeyPair.withArgs(emailAddress).yields();
emailDaoMock.unlock.withArgs(sinon.match.any, passphrase).yields();
keychainMock.putUserKeyPair.yields();
scope.confirmPassphrase();
expect(emailDaoMock.unlock.calledOnce).to.be.true;
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
});
it('should not work when keypair upload fails', function(done) {
scope.passphrase = passphrase;
scope.key = {
privateKeyArmored: 'b'
};
pgpMock.getKeyParams.returns({
_id: 'id',
userIds: []
});
keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, {
_id: keyId,
publicKey: 'a'
});
emailDaoMock.unlock.yields();
keychainMock.putUserKeyPair.yields({
errMsg: 'yo mamma.'
});
scope.onError = function(err) {
expect(err.errMsg).to.equal('yo mamma.');
done();
};
scope.confirmPassphrase();
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
expect(emailDaoMock.unlock.calledOnce).to.be.true;
expect(keychainMock.putUserKeyPair.calledOnce).to.be.true;
});
it('should not work when unlock fails', function(done) {
scope.passphrase = passphrase;
scope.key = {
privateKeyArmored: 'b'
};
pgpMock.getKeyParams.returns({
_id: 'id',
userIds: []
});
keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, {
_id: keyId,
publicKey: 'a'
});
emailDaoMock.unlock.yields({
errMsg: 'yo mamma.'
});
scope.onError = function(err) {
expect(err.errMsg).to.equal('yo mamma.');
done();
};
scope.confirmPassphrase();
expect(scope.incorrect).to.be.true;
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
expect(emailDaoMock.unlock.calledOnce).to.be.true;
});
it('should not work when keypair retrieval', function(done) {
scope.passphrase = passphrase;
keychainMock.getUserKeyPair.withArgs(emailAddress).yields({
errMsg: 'yo mamma.'
});
scope.onError = function(err) {
expect(err.errMsg).to.equal('yo mamma.');
done();
};
scope.confirmPassphrase();
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
ctrl = $controller(LoginNewDeviceCtrl, {
$scope: scope,
$routeParams: {}
});
});
});
afterEach(function() {
// restore the module
appController._emailDao = origEmailDao;
});
describe('initial state', function() {
it('should be well defined', function() {
expect(scope.incorrect).to.be.false;
expect(scope.confirmPassphrase).to.exist;
});
});
describe('confirm passphrase', function() {
it('should unlock crypto with a public key on the server', function() {
scope.passphrase = passphrase;
scope.key = {
privateKeyArmored: 'b'
};
pgpMock.getKeyParams.returns({
_id: 'id',
userIds: []
});
keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, {
_id: keyId,
publicKey: 'a'
});
emailDaoMock.unlock.withArgs(sinon.match.any, passphrase).yields();
keychainMock.putUserKeyPair.yields();
scope.confirmPassphrase();
expect(emailDaoMock.unlock.calledOnce).to.be.true;
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
});
it('should unlock crypto with no key on the server', function() {
scope.passphrase = passphrase;
scope.key = {
privateKeyArmored: 'b',
publicKeyArmored: 'a'
};
pgpMock.getKeyParams.returns({
_id: 'id',
userIds: []
});
keychainMock.getUserKeyPair.withArgs(emailAddress).yields();
emailDaoMock.unlock.withArgs(sinon.match.any, passphrase).yields();
keychainMock.putUserKeyPair.yields();
scope.confirmPassphrase();
expect(emailDaoMock.unlock.calledOnce).to.be.true;
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
});
it('should not work when keypair upload fails', function(done) {
scope.passphrase = passphrase;
scope.key = {
privateKeyArmored: 'b'
};
pgpMock.getKeyParams.returns({
_id: 'id',
userIds: []
});
keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, {
_id: keyId,
publicKey: 'a'
});
emailDaoMock.unlock.yields();
keychainMock.putUserKeyPair.yields({
errMsg: 'yo mamma.'
});
scope.onError = function(err) {
expect(err.errMsg).to.equal('yo mamma.');
done();
};
scope.confirmPassphrase();
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
expect(emailDaoMock.unlock.calledOnce).to.be.true;
expect(keychainMock.putUserKeyPair.calledOnce).to.be.true;
});
it('should not work when unlock fails', function(done) {
scope.passphrase = passphrase;
scope.key = {
privateKeyArmored: 'b'
};
pgpMock.getKeyParams.returns({
_id: 'id',
userIds: []
});
keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, {
_id: keyId,
publicKey: 'a'
});
emailDaoMock.unlock.yields({
errMsg: 'yo mamma.'
});
scope.onError = function(err) {
expect(err.errMsg).to.equal('yo mamma.');
done();
};
scope.confirmPassphrase();
expect(scope.incorrect).to.be.true;
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
expect(emailDaoMock.unlock.calledOnce).to.be.true;
});
it('should not work when keypair retrieval', function(done) {
scope.passphrase = passphrase;
keychainMock.getUserKeyPair.withArgs(emailAddress).yields({
errMsg: 'yo mamma.'
});
scope.onError = function(err) {
expect(err.errMsg).to.equal('yo mamma.');
done();
};
scope.confirmPassphrase();
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
});
});
});

View File

@ -1,39 +1,250 @@
define(function(require) {
'use strict';
'use strict';
var expect = chai.expect,
angular = require('angular'),
mocks = require('angularMocks'),
Auth = require('js/bo/auth'),
LoginPrivateKeyDownloadCtrl = require('js/controller/login-privatekey-download'),
EmailDAO = require('js/dao/email-dao'),
appController = require('js/app-controller'),
KeychainDAO = require('js/dao/keychain-dao');
var mocks = angular.mocks,
Auth = require('../../src/js/bo/auth'),
LoginPrivateKeyDownloadCtrl = require('../../src/js/controller/login-privatekey-download'),
EmailDAO = require('../../src/js/dao/email-dao'),
appController = require('../../src/js/app-controller'),
KeychainDAO = require('../../src/js/dao/keychain-dao');
describe('Login Private Key Download Controller unit test', function() {
var scope, location, ctrl,
origEmailDao, emailDaoMock,
origAuth, authMock,
origKeychain, keychainMock,
emailAddress = 'fred@foo.com';
describe('Login Private Key Download Controller unit test', function() {
var scope, location, ctrl,
origEmailDao, emailDaoMock,
origAuth, authMock,
origKeychain, keychainMock,
emailAddress = 'fred@foo.com';
beforeEach(function(done) {
// remember original module to restore later, then replace it
origEmailDao = appController._emailDao;
origKeychain = appController._keychain;
origAuth = appController._auth;
beforeEach(function(done) {
// remember original module to restore later, then replace it
origEmailDao = appController._emailDao;
origKeychain = appController._keychain;
origAuth = appController._auth;
appController._emailDao = emailDaoMock = sinon.createStubInstance(EmailDAO);
appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO);
appController._auth = authMock = sinon.createStubInstance(Auth);
appController._emailDao = emailDaoMock = sinon.createStubInstance(EmailDAO);
appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO);
appController._auth = authMock = sinon.createStubInstance(Auth);
emailDaoMock._account = {
emailAddress: emailAddress
emailDaoMock._account = {
emailAddress: emailAddress
};
angular.module('login-privatekey-download-test', []);
mocks.module('login-privatekey-download-test');
mocks.inject(function($controller, $rootScope) {
scope = $rootScope.$new();
scope.state = {};
ctrl = $controller(LoginPrivateKeyDownloadCtrl, {
$location: location,
$scope: scope,
$routeParams: {}
});
done();
});
});
afterEach(function() {
// restore the app controller module
appController._emailDao = origEmailDao;
appController._keychain = origKeychain;
appController._auth = origAuth;
});
describe('initialization', function() {
it('should work', function() {
expect(scope.step).to.equal(1);
});
});
describe('verifyRecoveryToken', function() {
var testKeypair = {
publicKey: {
_id: 'id'
}
};
it('should fail for empty recovery token', function(done) {
scope.onError = function(err) {
expect(err).to.exist;
done();
};
angular.module('login-privatekey-download-test', []);
mocks.module('login-privatekey-download-test');
mocks.inject(function($controller, $rootScope) {
scope.recoveryToken = undefined;
scope.verifyRecoveryToken();
});
it('should fail in keychain.getUserKeyPair', function(done) {
keychainMock.getUserKeyPair.yields(42);
scope.onError = function(err) {
expect(err).to.exist;
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
done();
};
scope.recoveryToken = 'token';
scope.verifyRecoveryToken();
});
it('should fail in keychain.downloadPrivateKey', function(done) {
keychainMock.getUserKeyPair.yields(null, testKeypair);
keychainMock.downloadPrivateKey.yields(42);
scope.onError = function(err) {
expect(err).to.exist;
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
expect(keychainMock.downloadPrivateKey.calledOnce).to.be.true;
done();
};
scope.recoveryToken = 'token';
scope.verifyRecoveryToken();
});
it('should work', function(done) {
keychainMock.getUserKeyPair.yields(null, testKeypair);
keychainMock.downloadPrivateKey.yields(null, 'encryptedPrivateKey');
scope.recoveryToken = 'token';
scope.verifyRecoveryToken(function() {
expect(scope.encryptedPrivateKey).to.equal('encryptedPrivateKey');
done();
});
});
});
describe('handlePaste', function() {
it('should work', function() {
scope.handlePaste({
clipboardData: {
getData: function(val) {
expect(val).to.equal('text/plain');
return '1qaz-2wsx-3edc-4rfv-5tgb-6yhn';
}
}
});
expect(scope.code0).to.equal('1qaz');
expect(scope.code1).to.equal('2wsx');
expect(scope.code2).to.equal('3edc');
expect(scope.code3).to.equal('4rfv');
expect(scope.code4).to.equal('5tgb');
expect(scope.code5).to.equal('6yhn');
});
});
describe('decryptAndStorePrivateKeyLocally', function() {
beforeEach(function() {
scope.code0 = '0';
scope.code1 = '1';
scope.code2 = '2';
scope.code3 = '3';
scope.code4 = '4';
scope.code5 = '5';
scope.encryptedPrivateKey = {
encryptedPrivateKey: 'encryptedPrivateKey'
};
scope.cachedKeypair = {
publicKey: {
_id: 'keyId'
}
};
});
it('should fail on empty code', function(done) {
scope.code0 = '';
scope.code1 = '';
scope.code2 = '';
scope.code3 = '';
scope.code4 = '';
scope.code5 = '';
scope.onError = function(err) {
expect(err).to.exist;
done();
};
scope.decryptAndStorePrivateKeyLocally();
});
it('should fail on decryptAndStorePrivateKeyLocally', function(done) {
keychainMock.decryptAndStorePrivateKeyLocally.yields(42);
scope.onError = function(err) {
expect(err).to.exist;
expect(keychainMock.decryptAndStorePrivateKeyLocally.calledOnce).to.be.true;
done();
};
scope.decryptAndStorePrivateKeyLocally();
});
it('should goto /login-existing on emailDao.unlock fail', function(done) {
keychainMock.decryptAndStorePrivateKeyLocally.yields(null, {
encryptedKey: 'keyArmored'
});
emailDaoMock.unlock.yields(42);
scope.goTo = function(location) {
expect(location).to.equal('/login-existing');
expect(keychainMock.decryptAndStorePrivateKeyLocally.calledOnce).to.be.true;
expect(emailDaoMock.unlock.calledOnce).to.be.true;
done();
};
scope.decryptAndStorePrivateKeyLocally();
});
it('should goto /desktop on emailDao.unlock success', function(done) {
keychainMock.decryptAndStorePrivateKeyLocally.yields(null, {
encryptedKey: 'keyArmored'
});
emailDaoMock.unlock.yields();
authMock.storeCredentials.yields();
scope.goTo = function(location) {
expect(location).to.equal('/desktop');
expect(keychainMock.decryptAndStorePrivateKeyLocally.calledOnce).to.be.true;
expect(emailDaoMock.unlock.calledOnce).to.be.true;
done();
};
scope.decryptAndStorePrivateKeyLocally();
});
});
describe('goForward', function() {
it('should work in step 1', function() {
var verifyRecoveryTokenStub = sinon.stub(scope, 'verifyRecoveryToken');
verifyRecoveryTokenStub.yields();
scope.step = 1;
scope.goForward();
expect(verifyRecoveryTokenStub.calledOnce).to.be.true;
expect(scope.step).to.equal(2);
verifyRecoveryTokenStub.restore();
});
it('should work in step 2', function() {
var decryptAndStorePrivateKeyLocallyStub = sinon.stub(scope, 'decryptAndStorePrivateKeyLocally');
decryptAndStorePrivateKeyLocallyStub.returns();
scope.step = 2;
scope.goForward();
expect(decryptAndStorePrivateKeyLocallyStub.calledOnce).to.be.true;
decryptAndStorePrivateKeyLocallyStub.restore();
});
});
describe('goTo', function() {
it('should work', function(done) {
mocks.inject(function($controller, $rootScope, $location) {
location = $location;
sinon.stub(location, 'path', function(path) {
expect(path).to.equal('/desktop');
done();
});
scope = $rootScope.$new();
scope.state = {};
ctrl = $controller(LoginPrivateKeyDownloadCtrl, {
@ -41,224 +252,9 @@ define(function(require) {
$scope: scope,
$routeParams: {}
});
done();
});
});
afterEach(function() {
// restore the app controller module
appController._emailDao = origEmailDao;
appController._keychain = origKeychain;
appController._auth = origAuth;
});
describe('initialization', function() {
it('should work', function() {
expect(scope.step).to.equal(1);
});
});
describe('verifyRecoveryToken', function() {
var testKeypair = {
publicKey: {
_id: 'id'
}
};
it('should fail for empty recovery token', function(done) {
scope.onError = function(err) {
expect(err).to.exist;
done();
};
scope.recoveryToken = undefined;
scope.verifyRecoveryToken();
});
it('should fail in keychain.getUserKeyPair', function(done) {
keychainMock.getUserKeyPair.yields(42);
scope.onError = function(err) {
expect(err).to.exist;
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
done();
};
scope.recoveryToken = 'token';
scope.verifyRecoveryToken();
});
it('should fail in keychain.downloadPrivateKey', function(done) {
keychainMock.getUserKeyPair.yields(null, testKeypair);
keychainMock.downloadPrivateKey.yields(42);
scope.onError = function(err) {
expect(err).to.exist;
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
expect(keychainMock.downloadPrivateKey.calledOnce).to.be.true;
done();
};
scope.recoveryToken = 'token';
scope.verifyRecoveryToken();
});
it('should work', function(done) {
keychainMock.getUserKeyPair.yields(null, testKeypair);
keychainMock.downloadPrivateKey.yields(null, 'encryptedPrivateKey');
scope.recoveryToken = 'token';
scope.verifyRecoveryToken(function() {
expect(scope.encryptedPrivateKey).to.equal('encryptedPrivateKey');
done();
});
});
});
describe('handlePaste', function() {
it('should work', function() {
scope.handlePaste({
clipboardData: {
getData: function(val) {
expect(val).to.equal('text/plain');
return '1qaz-2wsx-3edc-4rfv-5tgb-6yhn';
}
}
});
expect(scope.code0).to.equal('1qaz');
expect(scope.code1).to.equal('2wsx');
expect(scope.code2).to.equal('3edc');
expect(scope.code3).to.equal('4rfv');
expect(scope.code4).to.equal('5tgb');
expect(scope.code5).to.equal('6yhn');
});
});
describe('decryptAndStorePrivateKeyLocally', function() {
beforeEach(function() {
scope.code0 = '0';
scope.code1 = '1';
scope.code2 = '2';
scope.code3 = '3';
scope.code4 = '4';
scope.code5 = '5';
scope.encryptedPrivateKey = {
encryptedPrivateKey: 'encryptedPrivateKey'
};
scope.cachedKeypair = {
publicKey: {
_id: 'keyId'
}
};
});
it('should fail on empty code', function(done) {
scope.code0 = '';
scope.code1 = '';
scope.code2 = '';
scope.code3 = '';
scope.code4 = '';
scope.code5 = '';
scope.onError = function(err) {
expect(err).to.exist;
done();
};
scope.decryptAndStorePrivateKeyLocally();
});
it('should fail on decryptAndStorePrivateKeyLocally', function(done) {
keychainMock.decryptAndStorePrivateKeyLocally.yields(42);
scope.onError = function(err) {
expect(err).to.exist;
expect(keychainMock.decryptAndStorePrivateKeyLocally.calledOnce).to.be.true;
done();
};
scope.decryptAndStorePrivateKeyLocally();
});
it('should goto /login-existing on emailDao.unlock fail', function(done) {
keychainMock.decryptAndStorePrivateKeyLocally.yields(null, {
encryptedKey: 'keyArmored'
});
emailDaoMock.unlock.yields(42);
scope.goTo = function(location) {
expect(location).to.equal('/login-existing');
expect(keychainMock.decryptAndStorePrivateKeyLocally.calledOnce).to.be.true;
expect(emailDaoMock.unlock.calledOnce).to.be.true;
done();
};
scope.decryptAndStorePrivateKeyLocally();
});
it('should goto /desktop on emailDao.unlock success', function(done) {
keychainMock.decryptAndStorePrivateKeyLocally.yields(null, {
encryptedKey: 'keyArmored'
});
emailDaoMock.unlock.yields();
authMock.storeCredentials.yields();
scope.goTo = function(location) {
expect(location).to.equal('/desktop');
expect(keychainMock.decryptAndStorePrivateKeyLocally.calledOnce).to.be.true;
expect(emailDaoMock.unlock.calledOnce).to.be.true;
done();
};
scope.decryptAndStorePrivateKeyLocally();
});
});
describe('goForward', function() {
it('should work in step 1', function() {
var verifyRecoveryTokenStub = sinon.stub(scope, 'verifyRecoveryToken');
verifyRecoveryTokenStub.yields();
scope.step = 1;
scope.goForward();
expect(verifyRecoveryTokenStub.calledOnce).to.be.true;
expect(scope.step).to.equal(2);
verifyRecoveryTokenStub.restore();
});
it('should work in step 2', function() {
var decryptAndStorePrivateKeyLocallyStub = sinon.stub(scope, 'decryptAndStorePrivateKeyLocally');
decryptAndStorePrivateKeyLocallyStub.returns();
scope.step = 2;
scope.goForward();
expect(decryptAndStorePrivateKeyLocallyStub.calledOnce).to.be.true;
decryptAndStorePrivateKeyLocallyStub.restore();
});
});
describe('goTo', function() {
it('should work', function(done) {
mocks.inject(function($controller, $rootScope, $location) {
location = $location;
sinon.stub(location, 'path', function(path) {
expect(path).to.equal('/desktop');
done();
});
scope = $rootScope.$new();
scope.state = {};
ctrl = $controller(LoginPrivateKeyDownloadCtrl, {
$location: location,
$scope: scope,
$routeParams: {}
});
});
scope.goTo('/desktop');
});
scope.goTo('/desktop');
});
});
});

View File

@ -1,101 +1,97 @@
define(function(require) {
'use strict';
'use strict';
var expect = chai.expect,
angular = require('angular'),
mocks = require('angularMocks'),
Auth = require('js/bo/auth'),
ConnectionDoctor = require('js/util/connection-doctor'),
SetCredentialsCtrl = require('js/controller/login-set-credentials'),
appController = require('js/app-controller');
var mocks = angular.mocks,
Auth = require('../../src/js/bo/auth'),
ConnectionDoctor = require('../../src/js/util/connection-doctor'),
SetCredentialsCtrl = require('../../src/js/controller/login-set-credentials'),
appController = require('../../src/js/app-controller');
describe('Login (Set Credentials) Controller unit test', function() {
// Angular parameters
var scope, location, provider;
describe('Login (Set Credentials) Controller unit test', function() {
// Angular parameters
var scope, location, provider;
// Stubs
var auth, origAuth, doctor, origDoctor;
// Stubs
var auth, origAuth, doctor, origDoctor;
// SUT
var setCredentialsCtrl;
// SUT
var setCredentialsCtrl;
beforeEach(function() {
// remeber pre-test state to restore later
origAuth = appController._auth;
origDoctor = appController._doctor;
auth = appController._auth = sinon.createStubInstance(Auth);
doctor = appController._doctor = sinon.createStubInstance(ConnectionDoctor);
beforeEach(function() {
// remeber pre-test state to restore later
origAuth = appController._auth;
origDoctor = appController._doctor;
auth = appController._auth = sinon.createStubInstance(Auth);
doctor = appController._doctor = sinon.createStubInstance(ConnectionDoctor);
// setup the controller
angular.module('setcredentialstest', []);
mocks.module('setcredentialstest');
mocks.inject(function($rootScope, $controller, $location) {
scope = $rootScope.$new();
location = $location;
location.search({
provider: provider
});
scope.state = {};
setCredentialsCtrl = $controller(SetCredentialsCtrl, {
$scope: scope,
$routeParams: {}
});
// setup the controller
angular.module('setcredentialstest', []);
mocks.module('setcredentialstest');
mocks.inject(function($rootScope, $controller, $location) {
scope = $rootScope.$new();
location = $location;
location.search({
provider: provider
});
});
afterEach(function() {
// restore pre-test state
appController._auth = origAuth;
appController._doctor = origDoctor;
});
describe('set credentials', function() {
it('should work', function() {
scope.emailAddress = 'emailemailemailemail';
scope.password = 'passwdpasswdpasswdpasswd';
scope.smtpHost = 'hosthosthost';
scope.smtpPort = 1337;
scope.smtpEncryption = '1'; // STARTTLS
scope.imapHost = 'hosthosthost';
scope.imapPort = 1337;
scope.imapEncryption = '2'; // TLS
scope.realname = 'peter pan';
var expectedCredentials = {
provider: provider,
emailAddress: scope.emailAddress,
username: scope.username || scope.emailAddress,
realname: scope.realname,
password: scope.password,
xoauth2: undefined,
imap: {
host: scope.imapHost.toLowerCase(),
port: scope.imapPort,
secure: true,
ignoreTLS: false,
ca: undefined,
pinned: false
},
smtp: {
host: scope.smtpHost.toLowerCase(),
port: scope.smtpPort,
secure: false,
ignoreTLS: false,
ca: undefined,
pinned: false
}
};
doctor.check.yields(); // synchronous yields!
scope.test();
expect(doctor.check.calledOnce).to.be.true;
expect(doctor.configure.calledOnce).to.be.true;
expect(doctor.configure.calledWith(expectedCredentials)).to.be.true;
expect(auth.setCredentials.calledOnce).to.be.true;
scope.state = {};
setCredentialsCtrl = $controller(SetCredentialsCtrl, {
$scope: scope,
$routeParams: {}
});
});
});
afterEach(function() {
// restore pre-test state
appController._auth = origAuth;
appController._doctor = origDoctor;
});
describe('set credentials', function() {
it('should work', function() {
scope.emailAddress = 'emailemailemailemail';
scope.password = 'passwdpasswdpasswdpasswd';
scope.smtpHost = 'hosthosthost';
scope.smtpPort = 1337;
scope.smtpEncryption = '1'; // STARTTLS
scope.imapHost = 'hosthosthost';
scope.imapPort = 1337;
scope.imapEncryption = '2'; // TLS
scope.realname = 'peter pan';
var expectedCredentials = {
provider: provider,
emailAddress: scope.emailAddress,
username: scope.username || scope.emailAddress,
realname: scope.realname,
password: scope.password,
xoauth2: undefined,
imap: {
host: scope.imapHost.toLowerCase(),
port: scope.imapPort,
secure: true,
ignoreTLS: false,
ca: undefined,
pinned: false
},
smtp: {
host: scope.smtpHost.toLowerCase(),
port: scope.smtpPort,
secure: false,
ignoreTLS: false,
ca: undefined,
pinned: false
}
};
doctor.check.yields(); // synchronous yields!
scope.test();
expect(doctor.check.calledOnce).to.be.true;
expect(doctor.configure.calledOnce).to.be.true;
expect(doctor.configure.calledWith(expectedCredentials)).to.be.true;
expect(auth.setCredentials.calledOnce).to.be.true;
});
});
});

View File

@ -1,451 +1,447 @@
define(function(require) {
'use strict';
'use strict';
var expect = chai.expect,
angular = require('angular'),
mocks = require('angularMocks'),
MailListCtrl = require('js/controller/mail-list'),
EmailDAO = require('js/dao/email-dao'),
DeviceStorageDAO = require('js/dao/devicestorage-dao'),
KeychainDAO = require('js/dao/keychain-dao'),
appController = require('js/app-controller'),
notification = require('js/util/notification');
var mocks = angular.mocks,
MailListCtrl = require('../../src/js/controller/mail-list'),
EmailDAO = require('../../src/js/dao/email-dao'),
DeviceStorageDAO = require('../../src/js/dao/devicestorage-dao'),
KeychainDAO = require('../../src/js/dao/keychain-dao'),
appController = require('../../src/js/app-controller'),
notification = require('../../src/js/util/notification');
chai.Assertion.includeStack = true;
chai.Assertion.includeStack = true;
describe('Mail List controller unit test', function() {
var scope, ctrl, origEmailDao, emailDaoMock, keychainMock, deviceStorageMock,
emailAddress, emails,
hasChrome, hasSocket, hasRuntime, hasIdentity;
describe('Mail List controller unit test', function() {
var scope, ctrl, origEmailDao, emailDaoMock, keychainMock, deviceStorageMock,
emailAddress, emails,
hasChrome, hasSocket, hasRuntime, hasIdentity;
beforeEach(function() {
hasChrome = !!window.chrome;
hasSocket = !!window.chrome.socket;
hasIdentity = !!window.chrome.identity;
if (!hasChrome) {
window.chrome = {};
}
if (!hasSocket) {
window.chrome.socket = {};
}
if (!hasRuntime) {
window.chrome.runtime = {
getURL: function() {}
};
}
if (!hasIdentity) {
window.chrome.identity = {};
}
beforeEach(function() {
hasChrome = !!window.chrome;
hasSocket = !!window.chrome.socket;
hasIdentity = !!window.chrome.identity;
if (!hasChrome) {
window.chrome = {};
}
if (!hasSocket) {
window.chrome.socket = {};
}
if (!hasRuntime) {
window.chrome.runtime = {
getURL: function() {}
};
}
if (!hasIdentity) {
window.chrome.identity = {};
}
emails = [{
unread: true
}, {
unread: true
}, {
unread: true
}];
appController._outboxBo = {
pendingEmails: emails
emails = [{
unread: true
}, {
unread: true
}, {
unread: true
}];
appController._outboxBo = {
pendingEmails: emails
};
origEmailDao = appController._emailDao;
emailDaoMock = sinon.createStubInstance(EmailDAO);
appController._emailDao = emailDaoMock;
emailAddress = 'fred@foo.com';
emailDaoMock._account = {
emailAddress: emailAddress,
};
keychainMock = sinon.createStubInstance(KeychainDAO);
appController._keychain = keychainMock;
deviceStorageMock = sinon.createStubInstance(DeviceStorageDAO);
emailDaoMock._devicestorage = deviceStorageMock;
angular.module('maillisttest', []);
mocks.module('maillisttest');
mocks.inject(function($rootScope, $controller) {
scope = $rootScope.$new();
scope.state = {
read: {
toggle: function() {}
}
};
origEmailDao = appController._emailDao;
emailDaoMock = sinon.createStubInstance(EmailDAO);
appController._emailDao = emailDaoMock;
emailAddress = 'fred@foo.com';
emailDaoMock._account = {
emailAddress: emailAddress,
};
keychainMock = sinon.createStubInstance(KeychainDAO);
appController._keychain = keychainMock;
deviceStorageMock = sinon.createStubInstance(DeviceStorageDAO);
emailDaoMock._devicestorage = deviceStorageMock;
angular.module('maillisttest', []);
mocks.module('maillisttest');
mocks.inject(function($rootScope, $controller) {
scope = $rootScope.$new();
scope.state = {
read: {
toggle: function() {}
}
};
scope.loadVisibleBodies = function() {};
ctrl = $controller(MailListCtrl, {
$scope: scope,
$routeParams: {}
});
});
});
afterEach(function() {
if (!hasSocket) {
delete window.chrome.socket;
}
if (!hasRuntime) {
delete window.chrome.runtime;
}
if (!hasChrome) {
delete window.chrome;
}
if (!hasIdentity) {
delete window.chrome.identity;
}
// restore the module
appController._emailDao = origEmailDao;
});
describe('displayMore', function() {
beforeEach(function() {
scope.state.nav = {
currentFolder: {
messages: ['a', 'b']
}
};
});
it('should not do anything when display length equals messages length', function() {
scope.displayMessages = ['a', 'b'];
scope.displayMore();
expect(scope.displayMessages.length).to.equal(scope.state.nav.currentFolder.messages.length);
});
it('should append next message interval', function() {
scope.displayMessages = ['a'];
scope.displayMore();
expect(scope.displayMessages.length).to.equal(scope.state.nav.currentFolder.messages.length);
});
});
describe('displaySearchResults', function() {
var clock;
beforeEach(function() {
scope.state.nav = {
currentFolder: {
messages: ['a', 'b']
}
};
scope.watchMessages();
scope.watchOnline();
clock = sinon.useFakeTimers();
});
afterEach(function() {
clock.restore();
});
it('should show initial message on empty', function() {
scope.displaySearchResults();
expect(scope.searching).to.be.false;
expect(scope.lastUpdateLbl).to.equal('Online');
expect(scope.displayMessages.length).to.equal(2);
});
it('should show initial message on empty', function() {
var searchStub = sinon.stub(scope, 'search');
searchStub.returns(['a']);
scope.displaySearchResults('query');
expect(scope.searching).to.be.true;
expect(scope.lastUpdateLbl).to.equal('Searching ...');
clock.tick(500);
expect(scope.displayMessages).to.deep.equal(['a']);
expect(scope.searching).to.be.false;
expect(scope.lastUpdateLbl).to.equal('Matches in this folder');
});
});
describe('search', function() {
var message1 = {
to: [{
name: 'name1',
address: 'address1'
}],
subject: 'subject1',
body: 'body1',
html: 'html1'
},
message2 = {
to: [{
name: 'name2',
address: 'address2'
}],
subject: 'subject2',
body: 'body2',
html: 'html2'
},
message3 = {
to: [{
name: 'name3',
address: 'address3'
}],
subject: 'subject3',
body: 'body1',
html: 'html1',
encrypted: true
},
message4 = {
to: [{
name: 'name4',
address: 'address4'
}],
subject: 'subject4',
body: 'body1',
html: 'html1',
encrypted: true,
decrypted: true
},
testMessages = [message1, message2, message3, message4];
it('return same messages array on empty query string', function() {
var result = scope.search(testMessages, '');
expect(result).to.equal(testMessages);
});
it('return message1 on matching subject', function() {
var result = scope.search(testMessages, 'subject1');
expect(result.length).to.equal(1);
expect(result[0]).to.equal(message1);
});
it('return message1 on matching name', function() {
var result = scope.search(testMessages, 'name1');
expect(result.length).to.equal(1);
expect(result[0]).to.equal(message1);
});
it('return message1 on matching address', function() {
var result = scope.search(testMessages, 'address1');
expect(result.length).to.equal(1);
expect(result[0]).to.equal(message1);
});
it('return plaintext and decrypted messages on matching body', function() {
var result = scope.search(testMessages, 'body1');
expect(result.length).to.equal(2);
expect(result[0]).to.equal(message1);
expect(result[1]).to.equal(message4);
});
it('return plaintext and decrypted messages on matching html', function() {
var result = scope.search(testMessages, 'html1');
expect(result.length).to.equal(2);
expect(result[0]).to.equal(message1);
expect(result[1]).to.equal(message4);
});
});
describe('scope variables', function() {
it('should be set correctly', function() {
expect(scope.select).to.exist;
expect(scope.remove).to.exist;
expect(scope.state.mailList).to.exist;
});
});
describe('push notification', function() {
beforeEach(function() {
scope._stopWatchTask();
});
afterEach(function() {
notification.create.restore();
});
it('should succeed for single mail', function(done) {
var mail = {
uid: 123,
from: [{
address: 'asd'
}],
subject: 'this is the subject!',
unread: true
};
sinon.stub(notification, 'create', function(opts) {
expect(opts.title).to.equal(mail.from[0].address);
expect(opts.message).to.equal(mail.subject);
opts.onClick();
expect(scope.state.mailList.selected).to.equal(mail);
done();
});
scope.state.nav = {
currentFolder: {
type: 'asd',
messages: [mail]
}
};
emailDaoMock.onIncomingMessage([mail]);
});
it('should succeed for multiple mails', function(done) {
var mails = [{
uid: 1,
from: [{
address: 'asd'
}],
subject: 'this is the subject!',
unread: true
}, {
uid: 2,
from: [{
address: 'qwe'
}],
subject: 'this is the other subject!',
unread: true
}, {
uid: 3,
from: [{
address: 'qwe'
}],
subject: 'this is the other subject!',
unread: false
}];
sinon.stub(notification, 'create', function(opts) {
expect(opts.title).to.equal('2 new messages');
expect(opts.message).to.equal(mails[0].subject + '\n' + mails[1].subject);
opts.onClick();
expect(scope.state.mailList.selected).to.equal(mails[0]);
done();
});
scope.state.nav = {
currentFolder: {
type: 'asd',
messages: mails
}
};
emailDaoMock.onIncomingMessage(mails);
});
});
describe('getBody', function() {
it('should get the mail content', function() {
scope.state.nav = {
currentFolder: {
type: 'asd',
}
};
scope.getBody();
expect(emailDaoMock.getBody.calledOnce).to.be.true;
});
});
describe('select', function() {
it('should decrypt, focus mark an unread mail as read', function() {
scope.pendingNotifications = ['asd'];
sinon.stub(notification, 'close');
var mail = {
from: [{
address: 'asd'
}],
unread: true,
};
scope.state = {
nav: {
currentFolder: {
type: 'Inbox'
}
},
mailList: {},
read: {
toggle: function() {}
}
};
keychainMock.refreshKeyForUserId.withArgs(mail.from[0].address).yields();
scope.select(mail);
expect(emailDaoMock.decryptBody.calledOnce).to.be.true;
expect(keychainMock.refreshKeyForUserId.calledOnce).to.be.true;
expect(scope.state.mailList.selected).to.equal(mail);
expect(notification.close.calledWith('asd')).to.be.true;
expect(notification.close.calledOnce).to.be.true;
notification.close.restore();
});
it('should decrypt and focus a read mail', function() {
var mail = {
from: [{
address: 'asd'
}],
unread: false
};
scope.state = {
mailList: {},
read: {
toggle: function() {}
},
nav: {
currentFolder: {
type: 'asd'
}
}
};
keychainMock.refreshKeyForUserId.withArgs(mail.from[0].address).yields();
scope.select(mail);
expect(emailDaoMock.decryptBody.calledOnce).to.be.true;
expect(keychainMock.refreshKeyForUserId.calledOnce).to.be.true;
expect(scope.state.mailList.selected).to.equal(mail);
});
});
describe('remove', function() {
it('should not delete without a selected mail', function() {
scope.remove();
});
it('should delete the selected mail', function() {
var uid, mail, currentFolder;
scope._stopWatchTask();
scope.account = {};
uid = 123;
mail = {
uid: uid,
from: [{
address: 'asd'
}],
subject: '[whiteout] asdasd',
unread: true
};
currentFolder = {
type: 'Inbox',
path: 'INBOX',
messages: [mail]
};
scope.account.folders = [currentFolder];
scope.state.nav = {
currentFolder: currentFolder
};
emailDaoMock.deleteMessage.yields();
scope.remove(mail);
expect(emailDaoMock.deleteMessage.calledOnce).to.be.true;
expect(scope.state.mailList.selected).to.exist;
scope.loadVisibleBodies = function() {};
ctrl = $controller(MailListCtrl, {
$scope: scope,
$routeParams: {}
});
});
});
afterEach(function() {
if (!hasSocket) {
delete window.chrome.socket;
}
if (!hasRuntime) {
delete window.chrome.runtime;
}
if (!hasChrome) {
delete window.chrome;
}
if (!hasIdentity) {
delete window.chrome.identity;
}
// restore the module
appController._emailDao = origEmailDao;
});
describe('displayMore', function() {
beforeEach(function() {
scope.state.nav = {
currentFolder: {
messages: ['a', 'b']
}
};
});
it('should not do anything when display length equals messages length', function() {
scope.displayMessages = ['a', 'b'];
scope.displayMore();
expect(scope.displayMessages.length).to.equal(scope.state.nav.currentFolder.messages.length);
});
it('should append next message interval', function() {
scope.displayMessages = ['a'];
scope.displayMore();
expect(scope.displayMessages.length).to.equal(scope.state.nav.currentFolder.messages.length);
});
});
describe('displaySearchResults', function() {
var clock;
beforeEach(function() {
scope.state.nav = {
currentFolder: {
messages: ['a', 'b']
}
};
scope.watchMessages();
scope.watchOnline();
clock = sinon.useFakeTimers();
});
afterEach(function() {
clock.restore();
});
it('should show initial message on empty', function() {
scope.displaySearchResults();
expect(scope.searching).to.be.false;
expect(scope.lastUpdateLbl).to.equal('Online');
expect(scope.displayMessages.length).to.equal(2);
});
it('should show initial message on empty', function() {
var searchStub = sinon.stub(scope, 'search');
searchStub.returns(['a']);
scope.displaySearchResults('query');
expect(scope.searching).to.be.true;
expect(scope.lastUpdateLbl).to.equal('Searching ...');
clock.tick(500);
expect(scope.displayMessages).to.deep.equal(['a']);
expect(scope.searching).to.be.false;
expect(scope.lastUpdateLbl).to.equal('Matches in this folder');
});
});
describe('search', function() {
var message1 = {
to: [{
name: 'name1',
address: 'address1'
}],
subject: 'subject1',
body: 'body1',
html: 'html1'
},
message2 = {
to: [{
name: 'name2',
address: 'address2'
}],
subject: 'subject2',
body: 'body2',
html: 'html2'
},
message3 = {
to: [{
name: 'name3',
address: 'address3'
}],
subject: 'subject3',
body: 'body1',
html: 'html1',
encrypted: true
},
message4 = {
to: [{
name: 'name4',
address: 'address4'
}],
subject: 'subject4',
body: 'body1',
html: 'html1',
encrypted: true,
decrypted: true
},
testMessages = [message1, message2, message3, message4];
it('return same messages array on empty query string', function() {
var result = scope.search(testMessages, '');
expect(result).to.equal(testMessages);
});
it('return message1 on matching subject', function() {
var result = scope.search(testMessages, 'subject1');
expect(result.length).to.equal(1);
expect(result[0]).to.equal(message1);
});
it('return message1 on matching name', function() {
var result = scope.search(testMessages, 'name1');
expect(result.length).to.equal(1);
expect(result[0]).to.equal(message1);
});
it('return message1 on matching address', function() {
var result = scope.search(testMessages, 'address1');
expect(result.length).to.equal(1);
expect(result[0]).to.equal(message1);
});
it('return plaintext and decrypted messages on matching body', function() {
var result = scope.search(testMessages, 'body1');
expect(result.length).to.equal(2);
expect(result[0]).to.equal(message1);
expect(result[1]).to.equal(message4);
});
it('return plaintext and decrypted messages on matching html', function() {
var result = scope.search(testMessages, 'html1');
expect(result.length).to.equal(2);
expect(result[0]).to.equal(message1);
expect(result[1]).to.equal(message4);
});
});
describe('scope variables', function() {
it('should be set correctly', function() {
expect(scope.select).to.exist;
expect(scope.remove).to.exist;
expect(scope.state.mailList).to.exist;
});
});
describe('push notification', function() {
beforeEach(function() {
scope._stopWatchTask();
});
afterEach(function() {
notification.create.restore();
});
it('should succeed for single mail', function(done) {
var mail = {
uid: 123,
from: [{
address: 'asd'
}],
subject: 'this is the subject!',
unread: true
};
sinon.stub(notification, 'create', function(opts) {
expect(opts.title).to.equal(mail.from[0].address);
expect(opts.message).to.equal(mail.subject);
opts.onClick();
expect(scope.state.mailList.selected).to.equal(mail);
done();
});
scope.state.nav = {
currentFolder: {
type: 'asd',
messages: [mail]
}
};
emailDaoMock.onIncomingMessage([mail]);
});
it('should succeed for multiple mails', function(done) {
var mails = [{
uid: 1,
from: [{
address: 'asd'
}],
subject: 'this is the subject!',
unread: true
}, {
uid: 2,
from: [{
address: 'qwe'
}],
subject: 'this is the other subject!',
unread: true
}, {
uid: 3,
from: [{
address: 'qwe'
}],
subject: 'this is the other subject!',
unread: false
}];
sinon.stub(notification, 'create', function(opts) {
expect(opts.title).to.equal('2 new messages');
expect(opts.message).to.equal(mails[0].subject + '\n' + mails[1].subject);
opts.onClick();
expect(scope.state.mailList.selected).to.equal(mails[0]);
done();
});
scope.state.nav = {
currentFolder: {
type: 'asd',
messages: mails
}
};
emailDaoMock.onIncomingMessage(mails);
});
});
describe('getBody', function() {
it('should get the mail content', function() {
scope.state.nav = {
currentFolder: {
type: 'asd',
}
};
scope.getBody();
expect(emailDaoMock.getBody.calledOnce).to.be.true;
});
});
describe('select', function() {
it('should decrypt, focus mark an unread mail as read', function() {
scope.pendingNotifications = ['asd'];
sinon.stub(notification, 'close');
var mail = {
from: [{
address: 'asd'
}],
unread: true,
};
scope.state = {
nav: {
currentFolder: {
type: 'Inbox'
}
},
mailList: {},
read: {
toggle: function() {}
}
};
keychainMock.refreshKeyForUserId.withArgs(mail.from[0].address).yields();
scope.select(mail);
expect(emailDaoMock.decryptBody.calledOnce).to.be.true;
expect(keychainMock.refreshKeyForUserId.calledOnce).to.be.true;
expect(scope.state.mailList.selected).to.equal(mail);
expect(notification.close.calledWith('asd')).to.be.true;
expect(notification.close.calledOnce).to.be.true;
notification.close.restore();
});
it('should decrypt and focus a read mail', function() {
var mail = {
from: [{
address: 'asd'
}],
unread: false
};
scope.state = {
mailList: {},
read: {
toggle: function() {}
},
nav: {
currentFolder: {
type: 'asd'
}
}
};
keychainMock.refreshKeyForUserId.withArgs(mail.from[0].address).yields();
scope.select(mail);
expect(emailDaoMock.decryptBody.calledOnce).to.be.true;
expect(keychainMock.refreshKeyForUserId.calledOnce).to.be.true;
expect(scope.state.mailList.selected).to.equal(mail);
});
});
describe('remove', function() {
it('should not delete without a selected mail', function() {
scope.remove();
});
it('should delete the selected mail', function() {
var uid, mail, currentFolder;
scope._stopWatchTask();
scope.account = {};
uid = 123;
mail = {
uid: uid,
from: [{
address: 'asd'
}],
subject: '[whiteout] asdasd',
unread: true
};
currentFolder = {
type: 'Inbox',
path: 'INBOX',
messages: [mail]
};
scope.account.folders = [currentFolder];
scope.state.nav = {
currentFolder: currentFolder
};
emailDaoMock.deleteMessage.yields();
scope.remove(mail);
expect(emailDaoMock.deleteMessage.calledOnce).to.be.true;
expect(scope.state.mailList.selected).to.exist;
});
});
});

View File

@ -1,113 +0,0 @@
'use strict';
// Mozilla bind polyfill because phantomjs is stupid
if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== "function") {
// closest thing possible to the ECMAScript 5 internal IsCallable function
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
FNOP = function() {},
fBound = function() {
return fToBind.apply(this instanceof FNOP && oThis ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments)));
};
FNOP.prototype = this.prototype;
fBound.prototype = new FNOP();
return fBound;
};
}
// a warm round of applause for phantomjs for missing events
(function() {
function CustomEvent(event, params) {
params = params || {
bubbles: false,
cancelable: false,
detail: undefined
};
var evt = document.createEvent('CustomEvent');
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
return evt;
}
CustomEvent.prototype = window.Event.prototype;
window.CustomEvent = CustomEvent;
})();
require(['../../src/require-config'], function() {
require.config({
baseUrl: '../../src/lib',
paths: {
angularMocks: '../../test/lib/angular-mocks'
},
shim: {
angularMocks: {
exports: 'angular.mock',
deps: ['angular']
}
}
});
// Start the main app logic.
require(['js/app-config', 'axe'], function(app, axe) {
app.config.workerPath = '../../src/js';
// turn off logging in the test
axe.removeAppender(axe.defaultAppender);
startTests();
});
});
function startTests() {
mocha.setup('bdd');
require(
[
'test/unit/oauth-test',
'test/unit/auth-test',
'test/unit/email-dao-test',
'test/unit/app-controller-test',
'test/unit/pgp-test',
'test/unit/crypto-test',
'test/unit/backbutton-handler-test',
'test/unit/rest-dao-test',
'test/unit/admin-dao-test',
'test/unit/publickey-dao-test',
'test/unit/privatekey-dao-test',
'test/unit/lawnchair-dao-test',
'test/unit/keychain-dao-test',
'test/unit/devicestorage-dao-test',
'test/unit/dialog-ctrl-test',
'test/unit/add-account-ctrl-test',
'test/unit/account-ctrl-test',
'test/unit/set-passphrase-ctrl-test',
'test/unit/contacts-ctrl-test',
'test/unit/login-existing-ctrl-test',
'test/unit/login-initial-ctrl-test',
'test/unit/login-new-device-ctrl-test',
'test/unit/login-privatekey-download-ctrl-test',
'test/unit/login-set-credentials-ctrl-test',
'test/unit/privatekey-upload-ctrl-test',
'test/unit/login-ctrl-test',
'test/unit/read-ctrl-test',
'test/unit/navigation-ctrl-test',
'test/unit/mail-list-ctrl-test',
'test/unit/write-ctrl-test',
'test/unit/outbox-bo-test',
'test/unit/invitation-dao-test',
'test/unit/update-handler-test',
'test/unit/connection-doctor-test'
], function() {
//Tests loaded, run tests
mocha.run();
}
);
}

View File

@ -1,101 +1,97 @@
define(function(require) {
'use strict';
'use strict';
var expect = chai.expect,
angular = require('angular'),
mocks = require('angularMocks'),
NavigationCtrl = require('js/controller/navigation'),
EmailDAO = require('js/dao/email-dao'),
OutboxBO = require('js/bo/outbox'),
appController = require('js/app-controller');
var mocks = angular.mocks,
NavigationCtrl = require('../../src/js/controller/navigation'),
EmailDAO = require('../../src/js/dao/email-dao'),
OutboxBO = require('../../src/js/bo/outbox'),
appController = require('../../src/js/app-controller');
describe('Navigation Controller unit test', function() {
var scope, ctrl, origEmailDao, emailDaoMock, outboxBoMock, outboxFolder, onConnectStub;
describe('Navigation Controller unit test', function() {
var scope, ctrl, origEmailDao, emailDaoMock, outboxBoMock, outboxFolder, onConnectStub;
beforeEach(function(done) {
// remember original module to restore later
origEmailDao = appController._emailDao;
emailDaoMock = sinon.createStubInstance(EmailDAO);
emailDaoMock._account = {
folders: [{
type: 'Inbox',
count: 2,
path: 'INBOX'
}, {
type: 'Outbox',
count: 0,
path: 'OUTBOX'
}]
};
outboxFolder = emailDaoMock._account.folders[1];
appController._emailDao = emailDaoMock;
outboxBoMock = sinon.createStubInstance(OutboxBO);
appController._outboxBo = outboxBoMock;
outboxBoMock.startChecking.returns();
onConnectStub = sinon.stub(appController, 'onConnect');
onConnectStub.yields();
beforeEach(function(done) {
// remember original module to restore later
origEmailDao = appController._emailDao;
emailDaoMock = sinon.createStubInstance(EmailDAO);
emailDaoMock._account = {
folders: [{
type: 'Inbox',
count: 2,
path: 'INBOX'
}, {
type: 'Outbox',
count: 0,
path: 'OUTBOX'
}]
};
outboxFolder = emailDaoMock._account.folders[1];
appController._emailDao = emailDaoMock;
outboxBoMock = sinon.createStubInstance(OutboxBO);
appController._outboxBo = outboxBoMock;
outboxBoMock.startChecking.returns();
onConnectStub = sinon.stub(appController, 'onConnect');
onConnectStub.yields();
angular.module('navigationtest', []);
mocks.module('navigationtest');
mocks.inject(function($rootScope, $controller) {
scope = $rootScope.$new();
scope.state = {};
ctrl = $controller(NavigationCtrl, {
$scope: scope,
$routeParams: {}
});
done();
angular.module('navigationtest', []);
mocks.module('navigationtest');
mocks.inject(function($rootScope, $controller) {
scope = $rootScope.$new();
scope.state = {};
ctrl = $controller(NavigationCtrl, {
$scope: scope,
$routeParams: {}
});
done();
});
});
afterEach(function() {
// restore the module
appController._emailDao = origEmailDao;
onConnectStub.restore();
afterEach(function() {
// restore the module
appController._emailDao = origEmailDao;
onConnectStub.restore();
});
describe('initial state', function() {
it('should be well defined', function() {
expect(scope.state).to.exist;
expect(scope.state.lightbox).to.be.undefined;
expect(scope.account.folders).to.not.be.empty;
expect(scope.openFolder).to.exist;
});
});
describe('initial state', function() {
it('should be well defined', function() {
expect(scope.state).to.exist;
expect(scope.state.lightbox).to.be.undefined;
expect(scope.account.folders).to.not.be.empty;
expect(scope.openFolder).to.exist;
});
describe('open/close nav view', function() {
it('should open/close', function() {
expect(scope.state.nav.open).to.be.false;
scope.state.nav.toggle(true);
expect(scope.state.nav.open).to.be.true;
scope.state.nav.toggle(false);
expect(scope.state.nav.open).to.be.false;
});
});
describe('open/close nav view', function() {
it('should open/close', function() {
expect(scope.state.nav.open).to.be.false;
scope.state.nav.toggle(true);
expect(scope.state.nav.open).to.be.true;
scope.state.nav.toggle(false);
expect(scope.state.nav.open).to.be.false;
});
describe('open folder', function() {
it('should work', function() {
scope.state.nav.open = true;
scope.openFolder('asd');
expect(scope.state.nav.currentFolder).to.equal('asd');
expect(scope.state.nav.open).to.be.false;
});
});
describe('open folder', function() {
it('should work', function() {
scope.state.nav.open = true;
describe('empty outbox', function() {
it('should work', function() {
var callback;
scope.openFolder('asd');
expect(scope.state.nav.currentFolder).to.equal('asd');
expect(scope.state.nav.open).to.be.false;
});
});
expect(outboxBoMock.startChecking.callCount).to.equal(1);
describe('empty outbox', function() {
it('should work', function() {
var callback;
outboxBoMock.startChecking.calledWith(sinon.match(function(cb) {
callback = cb;
}));
expect(outboxBoMock.startChecking.callCount).to.equal(1);
outboxBoMock.startChecking.calledWith(sinon.match(function(cb) {
callback = cb;
}));
callback(null, 5);
expect(outboxFolder.count).to.equal(5);
});
callback(null, 5);
expect(outboxFolder.count).to.equal(5);
});
});
});

View File

@ -1,201 +1,198 @@
define(function(require) {
'use strict';
'use strict';
var OAuth = require('js/util/oauth'),
RestDAO = require('js/dao/rest-dao'),
expect = chai.expect;
var OAuth = require('../../src/js/util/oauth'),
RestDAO = require('../../src/js/dao/rest-dao');
describe('OAuth unit tests', function() {
var oauth, googleApiStub, identityStub, getPlatformInfoStub, removeCachedStub,
testEmail = 'test@example.com';
describe('OAuth unit tests', function() {
var oauth, googleApiStub, identityStub, getPlatformInfoStub, removeCachedStub,
testEmail = 'test@example.com';
beforeEach(function() {
googleApiStub = sinon.createStubInstance(RestDAO);
oauth = new OAuth(googleApiStub);
window.chrome = window.chrome || {};
window.chrome.identity = window.chrome.identity || {};
if (typeof window.chrome.identity.getAuthToken !== 'function') {
window.chrome.identity.getAuthToken = function() {};
}
identityStub = sinon.stub(window.chrome.identity, 'getAuthToken');
if (typeof window.chrome.identity.removeCachedAuthToken !== 'function') {
window.chrome.identity.removeCachedAuthToken = function() {};
}
removeCachedStub = sinon.stub(window.chrome.identity, 'removeCachedAuthToken');
window.chrome.runtime = window.chrome.runtime || {};
if (typeof window.chrome.runtime.getPlatformInfo !== 'function') {
window.chrome.runtime.getPlatformInfo = function() {};
}
getPlatformInfoStub = sinon.stub(window.chrome.runtime, 'getPlatformInfo');
});
afterEach(function() {
identityStub.restore();
getPlatformInfoStub.restore();
removeCachedStub.restore();
});
describe('isSupported', function() {
it('should work', function() {
expect(oauth.isSupported()).to.be.true;
});
});
describe('refreshToken', function() {
var getOAuthTokenStub;
beforeEach(function() {
googleApiStub = sinon.createStubInstance(RestDAO);
oauth = new OAuth(googleApiStub);
window.chrome = window.chrome || {};
window.chrome.identity = window.chrome.identity || {};
if (typeof window.chrome.identity.getAuthToken !== 'function') {
window.chrome.identity.getAuthToken = function() {};
}
identityStub = sinon.stub(window.chrome.identity, 'getAuthToken');
if (typeof window.chrome.identity.removeCachedAuthToken !== 'function') {
window.chrome.identity.removeCachedAuthToken = function() {};
}
removeCachedStub = sinon.stub(window.chrome.identity, 'removeCachedAuthToken');
window.chrome.runtime = window.chrome.runtime || {};
if (typeof window.chrome.runtime.getPlatformInfo !== 'function') {
window.chrome.runtime.getPlatformInfo = function() {};
}
getPlatformInfoStub = sinon.stub(window.chrome.runtime, 'getPlatformInfo');
getOAuthTokenStub = sinon.stub(oauth, 'getOAuthToken');
});
afterEach(function() {
identityStub.restore();
getPlatformInfoStub.restore();
removeCachedStub.restore();
getOAuthTokenStub.restore();
});
describe('isSupported', function() {
it('should work', function() {
expect(oauth.isSupported()).to.be.true;
it('should work', function() {
removeCachedStub.withArgs({
token: 'oldToken'
}).yields();
getOAuthTokenStub.withArgs(testEmail).yields();
oauth.refreshToken({
oldToken: 'oldToken',
emailAddress: testEmail
}, function(err) {
expect(err).to.not.exist;
expect(removeCachedStub.calledOnce).to.be.true;
expect(getOAuthTokenStub.calledOnce).to.be.true;
});
});
describe('refreshToken', function() {
var getOAuthTokenStub;
it('should work without email', function() {
removeCachedStub.withArgs({
token: 'oldToken'
}).yields();
beforeEach(function() {
getOAuthTokenStub = sinon.stub(oauth, 'getOAuthToken');
});
afterEach(function() {
getOAuthTokenStub.restore();
});
getOAuthTokenStub.withArgs(undefined).yields();
it('should work', function() {
removeCachedStub.withArgs({
token: 'oldToken'
}).yields();
getOAuthTokenStub.withArgs(testEmail).yields();
oauth.refreshToken({
oldToken: 'oldToken',
emailAddress: testEmail
}, function(err) {
expect(err).to.not.exist;
expect(removeCachedStub.calledOnce).to.be.true;
expect(getOAuthTokenStub.calledOnce).to.be.true;
});
});
it('should work without email', function() {
removeCachedStub.withArgs({
token: 'oldToken'
}).yields();
getOAuthTokenStub.withArgs(undefined).yields();
oauth.refreshToken({
oldToken: 'oldToken',
}, function(err) {
expect(err).to.not.exist;
expect(removeCachedStub.calledOnce).to.be.true;
expect(getOAuthTokenStub.calledOnce).to.be.true;
expect(getOAuthTokenStub.calledWith(undefined)).to.be.true;
});
});
it('should fail without all options', function() {
oauth.refreshToken({
emailAddress: testEmail
}, function(err) {
expect(err).to.exist;
expect(removeCachedStub.called).to.be.false;
expect(getOAuthTokenStub.called).to.be.false;
});
oauth.refreshToken({
oldToken: 'oldToken',
}, function(err) {
expect(err).to.not.exist;
expect(removeCachedStub.calledOnce).to.be.true;
expect(getOAuthTokenStub.calledOnce).to.be.true;
expect(getOAuthTokenStub.calledWith(undefined)).to.be.true;
});
});
describe('getOAuthToken', function() {
it('should work for empty emailAddress', function(done) {
getPlatformInfoStub.yields({
os: 'android'
});
identityStub.withArgs({
interactive: true
}).yields('token');
oauth.getOAuthToken(undefined, function(err, token) {
expect(err).to.not.exist;
expect(token).to.equal('token');
done();
});
});
it('should work on android app', function(done) {
getPlatformInfoStub.yields({
os: 'android'
});
identityStub.withArgs({
interactive: true,
accountHint: testEmail
}).yields('token');
oauth.getOAuthToken(testEmail, function(err, token) {
expect(err).to.not.exist;
expect(token).to.equal('token');
done();
});
});
it('should work on desktop chrome', function(done) {
getPlatformInfoStub.yields({
os: 'mac'
});
identityStub.withArgs({
interactive: true
}).yields('token');
oauth.getOAuthToken(testEmail, function(err, token) {
expect(err).to.not.exist;
expect(token).to.equal('token');
done();
});
});
it('should fail', function(done) {
getPlatformInfoStub.yields({
os: 'android'
});
identityStub.yields();
oauth.getOAuthToken(testEmail, function(err, token) {
expect(err).to.exist;
expect(token).to.not.exist;
done();
});
it('should fail without all options', function() {
oauth.refreshToken({
emailAddress: testEmail
}, function(err) {
expect(err).to.exist;
expect(removeCachedStub.called).to.be.false;
expect(getOAuthTokenStub.called).to.be.false;
});
});
describe('queryEmailAddress', function() {
it('should work', function(done) {
googleApiStub.get.withArgs({
uri: '/oauth2/v3/userinfo?access_token=token'
}).yields(null, {
email: 'asdf@example.com'
});
oauth.queryEmailAddress('token', function(err, emailAddress) {
expect(err).to.not.exist;
expect(emailAddress).to.equal('asdf@example.com');
done();
});
});
it('should fail due to invalid token', function(done) {
oauth.queryEmailAddress('', function(err, emailAddress) {
expect(err).to.exist;
expect(emailAddress).to.not.exist;
done();
});
});
it('should fail due to error in rest api', function(done) {
googleApiStub.get.withArgs({
uri: '/oauth2/v3/userinfo?access_token=token'
}).yields(new Error());
oauth.queryEmailAddress('token', function(err, emailAddress) {
expect(err).to.exist;
expect(emailAddress).to.not.exist;
done();
});
});
});
});
describe('getOAuthToken', function() {
it('should work for empty emailAddress', function(done) {
getPlatformInfoStub.yields({
os: 'android'
});
identityStub.withArgs({
interactive: true
}).yields('token');
oauth.getOAuthToken(undefined, function(err, token) {
expect(err).to.not.exist;
expect(token).to.equal('token');
done();
});
});
it('should work on android app', function(done) {
getPlatformInfoStub.yields({
os: 'android'
});
identityStub.withArgs({
interactive: true,
accountHint: testEmail
}).yields('token');
oauth.getOAuthToken(testEmail, function(err, token) {
expect(err).to.not.exist;
expect(token).to.equal('token');
done();
});
});
it('should work on desktop chrome', function(done) {
getPlatformInfoStub.yields({
os: 'mac'
});
identityStub.withArgs({
interactive: true
}).yields('token');
oauth.getOAuthToken(testEmail, function(err, token) {
expect(err).to.not.exist;
expect(token).to.equal('token');
done();
});
});
it('should fail', function(done) {
getPlatformInfoStub.yields({
os: 'android'
});
identityStub.yields();
oauth.getOAuthToken(testEmail, function(err, token) {
expect(err).to.exist;
expect(token).to.not.exist;
done();
});
});
});
describe('queryEmailAddress', function() {
it('should work', function(done) {
googleApiStub.get.withArgs({
uri: '/oauth2/v3/userinfo?access_token=token'
}).yields(null, {
email: 'asdf@example.com'
});
oauth.queryEmailAddress('token', function(err, emailAddress) {
expect(err).to.not.exist;
expect(emailAddress).to.equal('asdf@example.com');
done();
});
});
it('should fail due to invalid token', function(done) {
oauth.queryEmailAddress('', function(err, emailAddress) {
expect(err).to.exist;
expect(emailAddress).to.not.exist;
done();
});
});
it('should fail due to error in rest api', function(done) {
googleApiStub.get.withArgs({
uri: '/oauth2/v3/userinfo?access_token=token'
}).yields(new Error());
oauth.queryEmailAddress('token', function(err, emailAddress) {
expect(err).to.exist;
expect(emailAddress).to.not.exist;
done();
});
});
});
});

View File

@ -1,279 +1,276 @@
define(function(require) {
'use strict';
'use strict';
var expect = chai.expect,
OutboxBO = require('js/bo/outbox'),
KeychainDAO = require('js/dao/keychain-dao'),
EmailDAO = require('js/dao/email-dao'),
DeviceStorageDAO = require('js/dao/devicestorage-dao');
var OutboxBO = require('../../src/js/bo/outbox'),
KeychainDAO = require('../../src/js/dao/keychain-dao'),
EmailDAO = require('../../src/js/dao/email-dao'),
DeviceStorageDAO = require('../../src/js/dao/devicestorage-dao');
chai.Assertion.includeStack = true;
chai.Assertion.includeStack = true;
describe('Outbox Business Object unit test', function() {
var outbox, emailDaoStub, devicestorageStub, keychainStub,
dummyUser = 'spiderpig@springfield.com';
describe('Outbox Business Object unit test', function() {
var outbox, emailDaoStub, devicestorageStub, keychainStub,
dummyUser = 'spiderpig@springfield.com';
beforeEach(function() {
emailDaoStub = sinon.createStubInstance(EmailDAO);
emailDaoStub._account = {
emailAddress: dummyUser,
folders: [{
type: 'Outbox'
}],
online: true
beforeEach(function() {
emailDaoStub = sinon.createStubInstance(EmailDAO);
emailDaoStub._account = {
emailAddress: dummyUser,
folders: [{
type: 'Outbox'
}],
online: true
};
devicestorageStub = sinon.createStubInstance(DeviceStorageDAO);
keychainStub = sinon.createStubInstance(KeychainDAO);
outbox = new OutboxBO(emailDaoStub, keychainStub, devicestorageStub);
});
afterEach(function() {});
describe('start/stop checking', function() {
it('should work', function() {
function onOutboxUpdate(err) {
expect(err).to.not.exist;
}
outbox.startChecking(onOutboxUpdate);
expect(outbox._intervalId).to.exist;
outbox.stopChecking();
expect(outbox._intervalId).to.not.exist;
});
});
describe('put', function() {
it('should not encrypt and store a mail', function(done) {
var mail, senderKey, receiverKey;
senderKey = {
publicKey: 'SENDER PUBLIC KEY'
};
devicestorageStub = sinon.createStubInstance(DeviceStorageDAO);
keychainStub = sinon.createStubInstance(KeychainDAO);
outbox = new OutboxBO(emailDaoStub, keychainStub, devicestorageStub);
});
afterEach(function() {});
describe('start/stop checking', function() {
it('should work', function() {
function onOutboxUpdate(err) {
expect(err).to.not.exist;
}
outbox.startChecking(onOutboxUpdate);
expect(outbox._intervalId).to.exist;
outbox.stopChecking();
expect(outbox._intervalId).to.not.exist;
});
});
describe('put', function() {
it('should not encrypt and store a mail', function(done) {
var mail, senderKey, receiverKey;
senderKey = {
publicKey: 'SENDER PUBLIC KEY'
};
receiverKey = {
publicKey: 'RECEIVER PUBLIC KEY'
};
mail = {
from: [{
name: 'member',
address: 'member@whiteout.io'
}],
to: [{
name: 'member',
address: 'member'
}, {
name: 'notamember',
address: 'notamember'
}],
cc: [],
bcc: []
};
keychainStub.getReceiverPublicKey.withArgs(mail.from[0].address).yieldsAsync(null, senderKey);
keychainStub.getReceiverPublicKey.withArgs(mail.to[0].address).yieldsAsync(null, receiverKey);
keychainStub.getReceiverPublicKey.withArgs(mail.to[1].address).yieldsAsync();
devicestorageStub.storeList.withArgs([mail]).yieldsAsync();
outbox.put(mail, function(error) {
expect(error).to.not.exist;
expect(mail.publicKeysArmored.length).to.equal(2);
expect(emailDaoStub.encrypt.called).to.be.false;
expect(devicestorageStub.storeList.calledOnce).to.be.true;
done();
});
});
it('should not encrypt a mail with bcc and store a mail', function(done) {
var mail;
mail = {
from: [{
name: 'member',
address: 'member@whiteout.io'
}],
to: [{
name: 'member',
address: 'member@whiteout.io'
}],
cc: [],
bcc: [{
name: 'member',
address: 'member@whiteout.io'
}]
};
devicestorageStub.storeList.withArgs([mail]).yieldsAsync();
outbox.put(mail, function(error) {
expect(error).to.not.exist;
expect(mail.publicKeysArmored.length).to.equal(0);
expect(keychainStub.getReceiverPublicKey.called).to.be.false;
expect(emailDaoStub.encrypt.called).to.be.false;
expect(devicestorageStub.storeList.calledOnce).to.be.true;
done();
});
});
it('should encrypt and store a mail', function(done) {
var mail, senderKey, receiverKey;
senderKey = {
publicKey: 'SENDER PUBLIC KEY'
};
receiverKey = {
publicKey: 'RECEIVER PUBLIC KEY'
};
mail = {
from: [{
name: 'member',
address: 'member@whiteout.io'
}],
to: [{
name: 'member',
address: 'member'
}, {
name: 'notamember',
address: 'notamember'
}],
cc: [],
bcc: []
};
keychainStub.getReceiverPublicKey.withArgs(mail.from[0].address).yieldsAsync(null, senderKey);
keychainStub.getReceiverPublicKey.withArgs(mail.to[0].address).yieldsAsync(null, receiverKey);
keychainStub.getReceiverPublicKey.withArgs(mail.to[1].address).yieldsAsync(null, receiverKey);
emailDaoStub.encrypt.withArgs({
mail: mail,
publicKeysArmored: [senderKey.publicKey, receiverKey.publicKey, receiverKey.publicKey]
}).yieldsAsync();
devicestorageStub.storeList.withArgs([mail]).yieldsAsync();
outbox.put(mail, function(error) {
expect(error).to.not.exist;
expect(mail.publicKeysArmored.length).to.equal(3);
expect(emailDaoStub.encrypt.calledOnce).to.be.true;
expect(devicestorageStub.storeList.calledOnce).to.be.true;
done();
});
});
});
describe('process outbox', function() {
it('should send to registered users and update pending mails', function(done) {
var from, member, invited, notinvited, newlyjoined, dummyMails, newlyjoinedKey;
from = [{
receiverKey = {
publicKey: 'RECEIVER PUBLIC KEY'
};
mail = {
from: [{
name: 'member',
address: 'member@whiteout.io'
}];
member = {
id: '12',
from: from,
to: [{
name: 'member',
address: 'member'
}],
encrypted: true,
publicKeysArmored: ['ARMORED KEY OF MEMBER'],
unregisteredUsers: []
};
invited = {
id: '34',
from: from,
to: [{
name: 'invited',
address: 'invited'
}],
publicKeysArmored: [],
unregisteredUsers: [{
name: 'invited',
address: 'invited'
}]
};
notinvited = {
id: '56',
from: from,
to: [{
name: 'notinvited',
address: 'notinvited'
}],
publicKeysArmored: [],
unregisteredUsers: [{
name: 'notinvited',
address: 'notinvited'
}]
};
newlyjoined = {
id: '78',
from: from,
to: [{
name: 'newlyjoined',
address: 'newlyjoined'
}],
encrypted: true,
publicKeysArmored: [],
unregisteredUsers: [{
name: 'newlyjoined',
address: 'newlyjoined'
}]
};
newlyjoinedKey = {
publicKey: 'THIS IS THE NEWLY JOINED PUBLIC KEY!'
};
}],
to: [{
name: 'member',
address: 'member'
}, {
name: 'notamember',
address: 'notamember'
}],
cc: [],
bcc: []
};
dummyMails = [member, invited, notinvited, newlyjoined];
keychainStub.getReceiverPublicKey.withArgs(mail.from[0].address).yieldsAsync(null, senderKey);
keychainStub.getReceiverPublicKey.withArgs(mail.to[0].address).yieldsAsync(null, receiverKey);
keychainStub.getReceiverPublicKey.withArgs(mail.to[1].address).yieldsAsync();
devicestorageStub.listItems.yieldsAsync(null, dummyMails);
devicestorageStub.storeList.withArgs([mail]).yieldsAsync();
emailDaoStub.sendPlaintext.yieldsAsync();
outbox.put(mail, function(error) {
expect(error).to.not.exist;
emailDaoStub.sendEncrypted.withArgs({
email: newlyjoined
}).yieldsAsync();
expect(mail.publicKeysArmored.length).to.equal(2);
expect(emailDaoStub.encrypt.called).to.be.false;
expect(devicestorageStub.storeList.calledOnce).to.be.true;
emailDaoStub.sendEncrypted.withArgs({
email: member
}).yieldsAsync();
devicestorageStub.removeList.yieldsAsync();
function onOutboxUpdate(err, count) {
expect(err).to.not.exist;
expect(count).to.equal(0);
expect(outbox._outboxBusy).to.be.false;
expect(emailDaoStub.sendEncrypted.callCount).to.equal(2);
expect(emailDaoStub.sendPlaintext.callCount).to.equal(2);
expect(devicestorageStub.listItems.callCount).to.equal(1);
expect(devicestorageStub.removeList.callCount).to.equal(4);
expect(keychainStub.getReceiverPublicKey.callCount).to.equal(0);
done();
}
outbox._processOutbox(onOutboxUpdate);
done();
});
});
it('should not process outbox in offline mode', function(done) {
emailDaoStub._account.online = false;
devicestorageStub.listItems.yieldsAsync(null, [{}]);
it('should not encrypt a mail with bcc and store a mail', function(done) {
var mail;
outbox._processOutbox(function(err, count) {
expect(err).to.not.exist;
expect(count).to.equal(1);
expect(devicestorageStub.listItems.callCount).to.equal(1);
expect(outbox._outboxBusy).to.be.false;
done();
});
mail = {
from: [{
name: 'member',
address: 'member@whiteout.io'
}],
to: [{
name: 'member',
address: 'member@whiteout.io'
}],
cc: [],
bcc: [{
name: 'member',
address: 'member@whiteout.io'
}]
};
devicestorageStub.storeList.withArgs([mail]).yieldsAsync();
outbox.put(mail, function(error) {
expect(error).to.not.exist;
expect(mail.publicKeysArmored.length).to.equal(0);
expect(keychainStub.getReceiverPublicKey.called).to.be.false;
expect(emailDaoStub.encrypt.called).to.be.false;
expect(devicestorageStub.storeList.calledOnce).to.be.true;
done();
});
});
it('should encrypt and store a mail', function(done) {
var mail, senderKey, receiverKey;
senderKey = {
publicKey: 'SENDER PUBLIC KEY'
};
receiverKey = {
publicKey: 'RECEIVER PUBLIC KEY'
};
mail = {
from: [{
name: 'member',
address: 'member@whiteout.io'
}],
to: [{
name: 'member',
address: 'member'
}, {
name: 'notamember',
address: 'notamember'
}],
cc: [],
bcc: []
};
keychainStub.getReceiverPublicKey.withArgs(mail.from[0].address).yieldsAsync(null, senderKey);
keychainStub.getReceiverPublicKey.withArgs(mail.to[0].address).yieldsAsync(null, receiverKey);
keychainStub.getReceiverPublicKey.withArgs(mail.to[1].address).yieldsAsync(null, receiverKey);
emailDaoStub.encrypt.withArgs({
mail: mail,
publicKeysArmored: [senderKey.publicKey, receiverKey.publicKey, receiverKey.publicKey]
}).yieldsAsync();
devicestorageStub.storeList.withArgs([mail]).yieldsAsync();
outbox.put(mail, function(error) {
expect(error).to.not.exist;
expect(mail.publicKeysArmored.length).to.equal(3);
expect(emailDaoStub.encrypt.calledOnce).to.be.true;
expect(devicestorageStub.storeList.calledOnce).to.be.true;
done();
});
});
});
describe('process outbox', function() {
it('should send to registered users and update pending mails', function(done) {
var from, member, invited, notinvited, newlyjoined, dummyMails, newlyjoinedKey;
from = [{
name: 'member',
address: 'member@whiteout.io'
}];
member = {
id: '12',
from: from,
to: [{
name: 'member',
address: 'member'
}],
encrypted: true,
publicKeysArmored: ['ARMORED KEY OF MEMBER'],
unregisteredUsers: []
};
invited = {
id: '34',
from: from,
to: [{
name: 'invited',
address: 'invited'
}],
publicKeysArmored: [],
unregisteredUsers: [{
name: 'invited',
address: 'invited'
}]
};
notinvited = {
id: '56',
from: from,
to: [{
name: 'notinvited',
address: 'notinvited'
}],
publicKeysArmored: [],
unregisteredUsers: [{
name: 'notinvited',
address: 'notinvited'
}]
};
newlyjoined = {
id: '78',
from: from,
to: [{
name: 'newlyjoined',
address: 'newlyjoined'
}],
encrypted: true,
publicKeysArmored: [],
unregisteredUsers: [{
name: 'newlyjoined',
address: 'newlyjoined'
}]
};
newlyjoinedKey = {
publicKey: 'THIS IS THE NEWLY JOINED PUBLIC KEY!'
};
dummyMails = [member, invited, notinvited, newlyjoined];
devicestorageStub.listItems.yieldsAsync(null, dummyMails);
emailDaoStub.sendPlaintext.yieldsAsync();
emailDaoStub.sendEncrypted.withArgs({
email: newlyjoined
}).yieldsAsync();
emailDaoStub.sendEncrypted.withArgs({
email: member
}).yieldsAsync();
devicestorageStub.removeList.yieldsAsync();
function onOutboxUpdate(err, count) {
expect(err).to.not.exist;
expect(count).to.equal(0);
expect(outbox._outboxBusy).to.be.false;
expect(emailDaoStub.sendEncrypted.callCount).to.equal(2);
expect(emailDaoStub.sendPlaintext.callCount).to.equal(2);
expect(devicestorageStub.listItems.callCount).to.equal(1);
expect(devicestorageStub.removeList.callCount).to.equal(4);
expect(keychainStub.getReceiverPublicKey.callCount).to.equal(0);
done();
}
outbox._processOutbox(onOutboxUpdate);
});
it('should not process outbox in offline mode', function(done) {
emailDaoStub._account.online = false;
devicestorageStub.listItems.yieldsAsync(null, [{}]);
outbox._processOutbox(function(err, count) {
expect(err).to.not.exist;
expect(count).to.equal(1);
expect(devicestorageStub.listItems.callCount).to.equal(1);
expect(outbox._outboxBusy).to.be.false;
done();
});
});
});

View File

@ -1,464 +1,460 @@
define(function(require) {
'use strict';
'use strict';
var PGP = require('js/crypto/pgp'),
openpgp = require('openpgp'),
expect = chai.expect;
var PGP = require('../../src/js/crypto/pgp');
describe('PGP Crypto Api unit tests', function() {
this.timeout(20000);
describe('PGP Crypto Api unit tests', function() {
this.timeout(20000);
var pgp,
user = 'whiteout.test@t-online.de',
passphrase = 'asdf',
keySize = 512,
keyId = 'F6F60E9B42CDFF4C',
pubkey = '-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n' +
'Version: OpenPGP.js v0.7.2\r\n' +
'Comment: Whiteout Mail - https://whiteout.io\r\n' +
'\r\n' +
'xk0EUlhMvAEB/2MZtCUOAYvyLFjDp3OBMGn3Ev8FwjzyPbIF0JUw+L7y2XR5\r\n' +
'RVGvbK88unV3cU/1tOYdNsXI6pSp/Ztjyv7vbBUAEQEAAc0pV2hpdGVvdXQg\r\n' +
'VXNlciA8d2hpdGVvdXQudGVzdEB0LW9ubGluZS5kZT7CXAQQAQgAEAUCUlhM\r\n' +
'vQkQ9vYOm0LN/0wAAAW4Af9C+kYW1AvNWmivdtr0M0iYCUjM9DNOQH1fcvXq\r\n' +
'IiN602mWrkd8jcEzLsW5IUNzVPLhrFIuKyBDTpLnC07Loce1\r\n' +
'=6XMW\r\n' +
'-----END PGP PUBLIC KEY BLOCK-----\r\n\r\n',
privkey = '-----BEGIN PGP PRIVATE KEY BLOCK-----\r\n' +
'Version: OpenPGP.js v0.7.2\r\n' +
'Comment: Whiteout Mail - https://whiteout.io\r\n' +
'\r\n' +
'xcBeBFJYTLwBAf9jGbQlDgGL8ixYw6dzgTBp9xL/BcI88j2yBdCVMPi+8tl0\r\n' +
'eUVRr2yvPLp1d3FP9bTmHTbFyOqUqf2bY8r+72wVABEBAAH+AwMIhNB4ivtv\r\n' +
'Y2xg6VeMcjjHxZayESHACV+nQx5Tx6ev6xzIF1Qh72fNPDppLhFSFOuTTMsU\r\n' +
'kTN4c+BVYt29spH+cA1jcDAxQ2ULrNAXo+hheOqhpedTs8aCbcLFkJAS16hk\r\n' +
'YSk4OnJgp/z24rVju1SHRSFbgundPzmNgXeX9e8IkviGhhQ11Wc5YwVkx03t\r\n' +
'Z3MdDMF0jyhopbPIoBdyJB0dhvBh98w3JmwpYh9wjUA9MBHD1tvHpRmSZ3BM\r\n' +
'UCmATn2ZLWBRWiYqFbgDnL1GM80pV2hpdGVvdXQgVXNlciA8d2hpdGVvdXQu\r\n' +
'dGVzdEB0LW9ubGluZS5kZT7CXAQQAQgAEAUCUlhMvQkQ9vYOm0LN/0wAAAW4\r\n' +
'Af9C+kYW1AvNWmivdtr0M0iYCUjM9DNOQH1fcvXqIiN602mWrkd8jcEzLsW5\r\n' +
'IUNzVPLhrFIuKyBDTpLnC07Loce1\r\n' +
'=ULta\r\n' +
'-----END PGP PRIVATE KEY BLOCK-----\r\n';
var pgp,
user = 'whiteout.test@t-online.de',
passphrase = 'asdf',
keySize = 512,
keyId = 'F6F60E9B42CDFF4C',
pubkey = '-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n' +
'Version: OpenPGP.js v0.7.2\r\n' +
'Comment: Whiteout Mail - https://whiteout.io\r\n' +
'\r\n' +
'xk0EUlhMvAEB/2MZtCUOAYvyLFjDp3OBMGn3Ev8FwjzyPbIF0JUw+L7y2XR5\r\n' +
'RVGvbK88unV3cU/1tOYdNsXI6pSp/Ztjyv7vbBUAEQEAAc0pV2hpdGVvdXQg\r\n' +
'VXNlciA8d2hpdGVvdXQudGVzdEB0LW9ubGluZS5kZT7CXAQQAQgAEAUCUlhM\r\n' +
'vQkQ9vYOm0LN/0wAAAW4Af9C+kYW1AvNWmivdtr0M0iYCUjM9DNOQH1fcvXq\r\n' +
'IiN602mWrkd8jcEzLsW5IUNzVPLhrFIuKyBDTpLnC07Loce1\r\n' +
'=6XMW\r\n' +
'-----END PGP PUBLIC KEY BLOCK-----\r\n\r\n',
privkey = '-----BEGIN PGP PRIVATE KEY BLOCK-----\r\n' +
'Version: OpenPGP.js v0.7.2\r\n' +
'Comment: Whiteout Mail - https://whiteout.io\r\n' +
'\r\n' +
'xcBeBFJYTLwBAf9jGbQlDgGL8ixYw6dzgTBp9xL/BcI88j2yBdCVMPi+8tl0\r\n' +
'eUVRr2yvPLp1d3FP9bTmHTbFyOqUqf2bY8r+72wVABEBAAH+AwMIhNB4ivtv\r\n' +
'Y2xg6VeMcjjHxZayESHACV+nQx5Tx6ev6xzIF1Qh72fNPDppLhFSFOuTTMsU\r\n' +
'kTN4c+BVYt29spH+cA1jcDAxQ2ULrNAXo+hheOqhpedTs8aCbcLFkJAS16hk\r\n' +
'YSk4OnJgp/z24rVju1SHRSFbgundPzmNgXeX9e8IkviGhhQ11Wc5YwVkx03t\r\n' +
'Z3MdDMF0jyhopbPIoBdyJB0dhvBh98w3JmwpYh9wjUA9MBHD1tvHpRmSZ3BM\r\n' +
'UCmATn2ZLWBRWiYqFbgDnL1GM80pV2hpdGVvdXQgVXNlciA8d2hpdGVvdXQu\r\n' +
'dGVzdEB0LW9ubGluZS5kZT7CXAQQAQgAEAUCUlhMvQkQ9vYOm0LN/0wAAAW4\r\n' +
'Af9C+kYW1AvNWmivdtr0M0iYCUjM9DNOQH1fcvXqIiN602mWrkd8jcEzLsW5\r\n' +
'IUNzVPLhrFIuKyBDTpLnC07Loce1\r\n' +
'=ULta\r\n' +
'-----END PGP PRIVATE KEY BLOCK-----\r\n';
beforeEach(function() {
pgp = new PGP();
beforeEach(function() {
pgp = new PGP();
});
afterEach(function() {});
describe('Generate key pair', function() {
it('should fail', function(done) {
pgp.generateKeys({
emailAddress: 'whiteout.test@t-onlinede',
keySize: keySize,
passphrase: passphrase
}, function(err, keys) {
expect(err).to.exist;
expect(keys).to.not.exist;
done();
});
});
afterEach(function() {});
describe('Generate key pair', function() {
it('should fail', function(done) {
pgp.generateKeys({
emailAddress: 'whiteout.test@t-onlinede',
keySize: keySize,
passphrase: passphrase
}, function(err, keys) {
expect(err).to.exist;
expect(keys).to.not.exist;
done();
});
it('should fail', function(done) {
pgp.generateKeys({
emailAddress: 'whiteout.testt-online.de',
keySize: keySize,
passphrase: passphrase
}, function(err, keys) {
expect(err).to.exist;
expect(keys).to.not.exist;
done();
});
it('should fail', function(done) {
pgp.generateKeys({
emailAddress: 'whiteout.testt-online.de',
keySize: keySize,
passphrase: passphrase
}, function(err, keys) {
expect(err).to.exist;
expect(keys).to.not.exist;
done();
});
});
it('should work with passphrase', function(done) {
pgp.generateKeys({
emailAddress: user,
keySize: keySize,
passphrase: passphrase
}, function(err, keys) {
});
it('should work with passphrase', function(done) {
pgp.generateKeys({
emailAddress: user,
keySize: keySize,
passphrase: passphrase
}, function(err, keys) {
expect(err).to.not.exist;
expect(keys.keyId).to.exist;
expect(keys.privateKeyArmored).to.exist;
expect(keys.publicKeyArmored).to.exist;
// test encrypt/decrypt
pgp.importKeys({
passphrase: passphrase,
privateKeyArmored: keys.privateKeyArmored,
publicKeyArmored: keys.publicKeyArmored
}, function(err) {
expect(err).to.not.exist;
expect(keys.keyId).to.exist;
expect(keys.privateKeyArmored).to.exist;
expect(keys.publicKeyArmored).to.exist;
// test encrypt/decrypt
pgp.importKeys({
passphrase: passphrase,
privateKeyArmored: keys.privateKeyArmored,
publicKeyArmored: keys.publicKeyArmored
}, function(err) {
pgp.encrypt('secret', [keys.publicKeyArmored], function(err, ct) {
expect(err).to.not.exist;
expect(ct).to.exist;
pgp.encrypt('secret', [keys.publicKeyArmored], function(err, ct) {
pgp.decrypt(ct, keys.publicKeyArmored, function(err, pt, signValid) {
expect(err).to.not.exist;
expect(ct).to.exist;
pgp.decrypt(ct, keys.publicKeyArmored, function(err, pt, signValid) {
expect(err).to.not.exist;
expect(pt).to.equal('secret');
expect(signValid).to.be.true;
done();
});
});
});
});
});
it('should work without passphrase', function(done) {
pgp.generateKeys({
emailAddress: user,
keySize: keySize,
passphrase: ''
}, function(err, keys) {
expect(err).to.not.exist;
expect(keys.keyId).to.exist;
expect(keys.privateKeyArmored).to.exist;
expect(keys.publicKeyArmored).to.exist;
// test encrypt/decrypt
pgp.importKeys({
passphrase: undefined,
privateKeyArmored: keys.privateKeyArmored,
publicKeyArmored: keys.publicKeyArmored
}, function(err) {
expect(err).to.not.exist;
pgp.encrypt('secret', [keys.publicKeyArmored], function(err, ct) {
expect(err).to.not.exist;
expect(ct).to.exist;
pgp.decrypt(ct, keys.publicKeyArmored, function(err, pt, signValid) {
expect(err).to.not.exist;
expect(pt).to.equal('secret');
expect(signValid).to.be.true;
done();
});
expect(pt).to.equal('secret');
expect(signValid).to.be.true;
done();
});
});
});
});
});
it('should work without passphrase', function(done) {
pgp.generateKeys({
emailAddress: user,
keySize: keySize,
passphrase: ''
}, function(err, keys) {
expect(err).to.not.exist;
expect(keys.keyId).to.exist;
expect(keys.privateKeyArmored).to.exist;
expect(keys.publicKeyArmored).to.exist;
describe('Import/Export key pair', function() {
it('should fail', function(done) {
// test encrypt/decrypt
pgp.importKeys({
passphrase: 'asd',
privateKeyArmored: privkey,
publicKeyArmored: pubkey
}, function(err) {
expect(err).to.exist;
expect(err.message).to.equal('Incorrect passphrase!');
pgp.exportKeys(function(err, keys) {
expect(err).to.exist;
expect(keys).to.not.exist;
done();
});
});
});
it('should work', function(done) {
pgp.importKeys({
passphrase: passphrase,
privateKeyArmored: privkey,
publicKeyArmored: pubkey
passphrase: undefined,
privateKeyArmored: keys.privateKeyArmored,
publicKeyArmored: keys.publicKeyArmored
}, function(err) {
expect(err).to.not.exist;
pgp.exportKeys(function(err, keys) {
expect(err).to.not.exist;
expect(keys.keyId).to.equal(keyId);
expect(keys.privateKeyArmored.replace(/\r/g, '')).to.equal(privkey.replace(/\r/g, ''));
expect(keys.publicKeyArmored.replace(/\r/g, '')).to.equal(pubkey.replace(/\r/g, ''));
done();
});
});
});
});
describe('Change passphrase of private key', function() {
it('should work with new passphrase', function(done) {
pgp.changePassphrase({
privateKeyArmored: privkey,
oldPassphrase: passphrase,
newPassphrase: 'yxcv'
}, function(err, reEncryptedKey) {
expect(err).to.not.exist;
expect(reEncryptedKey).to.exist;
pgp.importKeys({
passphrase: 'yxcv',
privateKeyArmored: reEncryptedKey,
publicKeyArmored: pubkey
}, function(err) {
expect(err).to.not.exist;
done();
});
});
});
it('should work with empty passphrase', function(done) {
pgp.changePassphrase({
privateKeyArmored: privkey,
oldPassphrase: passphrase,
newPassphrase: undefined
}, function(err, reEncryptedKey) {
expect(err).to.not.exist;
expect(reEncryptedKey).to.exist;
pgp.importKeys({
passphrase: undefined,
privateKeyArmored: reEncryptedKey,
publicKeyArmored: pubkey
}, function(err) {
expect(err).to.not.exist;
done();
});
});
});
it('should fail when passphrases are equal', function(done) {
pgp.changePassphrase({
privateKeyArmored: privkey,
oldPassphrase: passphrase,
newPassphrase: passphrase
}, function(err, reEncryptedKey) {
expect(err).to.exist;
expect(reEncryptedKey).to.not.exist;
done();
});
});
it('should fail when old passphrase is incorrect', function(done) {
pgp.changePassphrase({
privateKeyArmored: privkey,
oldPassphrase: 'asd',
newPassphrase: 'yxcv'
}, function(err, reEncryptedKey) {
expect(err).to.exist;
expect(reEncryptedKey).to.not.exist;
done();
});
});
});
describe('Encrypt/Sign/Decrypt/Verify', function() {
var message = 'asdfs\n\nThursday, Nov 21, 2013 7:38 PM asdf@example.com wrote:\n' +
'> asdf\n' +
'> \n' +
'> Thursday, Nov 21, 2013 7:32 PM asdf@example.com wrote:\n' +
'> > secret 3';
var wrongPubkey = '-----BEGIN PGP PUBLIC KEY BLOCK-----\r\nVersion: OpenPGP.js v.1.20131116\r\nComment: Whiteout Mail - http://whiteout.io\r\n\r\nxsBNBFKODs4BB/9iOF4THsjQMY+WEpT7ShgKxj4bHzRRaQkqczS4nZvP0U3g\r\nqeqCnbpagyeKXA+bhWFQW4GmXtgAoeD5PXs6AZYrw3tWNxLKu2Oe6Tp9K/XI\r\nxTMQ2wl4qZKDXHvuPsJ7cmgaWqpPyXtxA4zHHS3WrkI/6VzHAcI/y6x4szSB\r\nKgSuhI3hjh3s7TybUC1U6AfoQGx/S7e3WwlCOrK8GTClirN/2mCPRC5wuIft\r\nnkoMfA6jK8d2OPrJ63shy5cgwHOjQg/xuk46dNS7tkvGmbaa+X0PgqSKB+Hf\r\nYPPNS/ylg911DH9qa8BqYU2QpNh9jUKXSF+HbaOM+plWkCSAL7czV+R3ABEB\r\nAAHNLVdoaXRlb3V0IFVzZXIgPHNhZmV3aXRobWUudGVzdHVzZXJAZ21haWwu\r\nY29tPsLAXAQQAQgAEAUCUo4O2gkQ1/uT/N+/wjwAAN2cB/9gFRmAfvEQ2qz+\r\nWubmT2EsSSnjPMxzG4uyykFoa+TaZCWo2Xa2tQghmU103kEkQb1OEjRjpgwJ\r\nYX9Kghnl8DByM686L5AXnRyHP78qRJCLXSXl0AGicboUDp5sovaa4rswQceH\r\nvcdWgZ/mgHTRoiQeJddy9k+H6MPFiyFaVcFwegVsmpc+dCcC8yT+qh8ZIbyG\r\nRJU60PmKKN7LUusP+8DbSv39zCGJCBlVVKyA4MzdF5uM+sqTdXbKzOrT5DGd\r\nCZaox4s+w16Sq1rHzZKFWfQPfKLDB9pyA0ufCVRA3AF6BUi7G3ZqhZiHNhMP\r\nNvE45V/hS1PbZcfPVoUjE2qc1Ix1\r\n=7Wpe\r\n-----END PGP PUBLIC KEY BLOCK-----';
beforeEach(function(done) {
pgp.importKeys({
passphrase: passphrase,
privateKeyArmored: privkey,
publicKeyArmored: pubkey
}, function(err) {
expect(err).to.not.exist;
done();
});
});
describe('Get KeyId', function() {
it('should work without param', function() {
var keyId = pgp.getKeyId();
expect(keyId).to.equal('F6F60E9B42CDFF4C');
});
it('should work with param', function() {
var keyId = pgp.getKeyId(pubkey);
expect(keyId).to.equal('F6F60E9B42CDFF4C');
});
});
describe('Get Fingerprint', function() {
it('should work without param', function() {
var fingerprint = pgp.getFingerprint();
expect(fingerprint).to.equal('5856CEF789C3A307E8A1B976F6F60E9B42CDFF4C');
});
it('should work with param', function() {
var fingerprint = pgp.getFingerprint(pubkey);
expect(fingerprint).to.equal('5856CEF789C3A307E8A1B976F6F60E9B42CDFF4C');
});
});
describe('getKeyParams', function() {
it('should work with param', function() {
var params = pgp.getKeyParams(pubkey);
expect(params.fingerprint).to.equal('5856CEF789C3A307E8A1B976F6F60E9B42CDFF4C');
expect(params._id).to.equal("F6F60E9B42CDFF4C");
expect(params.bitSize).to.equal(keySize);
expect(params.userId).to.equal("whiteout.test@t-online.de");
expect(params.userIds[0].name).to.equal("Whiteout User");
expect(params.userIds[0].emailAddress).to.equal("whiteout.test@t-online.de");
expect(params.algorithm).to.equal("rsa_encrypt_sign");
});
it('should work without param', function() {
var params = pgp.getKeyParams();
expect(params.fingerprint).to.equal('5856CEF789C3A307E8A1B976F6F60E9B42CDFF4C');
expect(params._id).to.equal("F6F60E9B42CDFF4C");
expect(params.bitSize).to.equal(keySize);
expect(params.userId).to.equal("whiteout.test@t-online.de");
expect(params.userIds[0].name).to.equal("Whiteout User");
expect(params.userIds[0].emailAddress).to.equal("whiteout.test@t-online.de");
expect(params.algorithm).to.equal("rsa_encrypt_sign");
});
});
describe('extractPublicKey', function() {
it('should work', function() {
var pk = pgp.extractPublicKey(privkey);
expect(pk).to.exist;
expect(pk).to.contain('-----BEGIN PGP PUBLIC KEY BLOCK-----');
});
});
describe('Encrypt and sign', function() {
it('should fail', function(done) {
var input = null;
pgp.encrypt(input, [pubkey], function(err, ct) {
expect(err).to.exist;
expect(ct).to.not.exist;
done();
});
});
it('should work', function(done) {
pgp.encrypt(message, [pubkey], function(err, ct) {
pgp.encrypt('secret', [keys.publicKeyArmored], function(err, ct) {
expect(err).to.not.exist;
expect(ct).to.exist;
done();
});
});
it('should encrypt to myself if public keys are empty', function(done) {
pgp.encrypt(message, undefined, function(err, ct) {
expect(err).to.not.exist;
expect(ct).to.exist;
done();
});
});
});
describe('Decrypt and verify', function() {
var ciphertext;
beforeEach(function(done) {
pgp.encrypt(message, [pubkey], function(err, ct) {
expect(err).to.not.exist;
expect(ct).to.exist;
ciphertext = ct;
done();
});
});
it('should fail', function(done) {
var input = 'asdfa\rsdf';
pgp.decrypt(input, pubkey, function(err, pt) {
expect(err).to.exist;
expect(pt).to.not.exist;
done();
});
});
it('should work', function(done) {
pgp.decrypt(ciphertext, pubkey, function(err, pt, signValid) {
expect(err).to.not.exist;
expect(pt).to.equal(message);
expect(signValid).to.be.true;
done();
});
});
it('should work without signature', function(done) {
var ct = openpgp.encryptMessage([pgp._publicKey], message);
pgp.decrypt(ct, undefined, function(err, pt, signValid) {
expect(err).to.not.exist;
expect(pt).to.equal(message);
expect(signValid).to.be.undefined;
done();
});
});
it('should fail to verify if public keys are empty', function(done) {
// setup another public key so that signature verification fails
pgp._publicKey = openpgp.key.readArmored(wrongPubkey).keys[0];
pgp.decrypt(ciphertext, undefined, function(err, pt, signValid) {
expect(err).to.not.exist;
expect(pt).to.equal(message);
expect(signValid).to.be.null;
done();
});
});
it('should decrypt but signValid should be null for wrong public key', function(done) {
pgp.decrypt(ciphertext, wrongPubkey, function(err, pt, signValid) {
expect(err).to.not.exist;
expect(pt).to.equal(message);
expect(signValid).to.be.null;
done();
});
});
});
describe('Verify clearsigned message', function() {
var clearsigned;
beforeEach(function() {
clearsigned = openpgp.signClearMessage(pgp._privateKey, 'this is a clearsigned message');
});
it('should work', function(done) {
pgp.verifyClearSignedMessage(clearsigned, pubkey, function(err, signaturesValid) {
expect(err).to.not.exist;
expect(signaturesValid).to.be.true;
done();
});
});
it('should fail', function(done) {
pgp.verifyClearSignedMessage(clearsigned.replace('clearsigned', 'invalid'), pubkey, function(err, signaturesValid) {
expect(err).to.not.exist;
expect(signaturesValid).to.be.false;
done();
});
});
it('should be null for wrong public key', function(done) {
pgp.verifyClearSignedMessage(clearsigned, wrongPubkey, function(err, signaturesValid) {
expect(err).to.not.exist;
expect(signaturesValid).to.be.null;
done();
});
});
});
describe('Verify detached signature', function() {
var signedMessage, signature;
beforeEach(function() {
signedMessage = 'this is a signed message';
var clearsigned = openpgp.signClearMessage(pgp._privateKey, signedMessage);
var signatureHeader = '-----BEGIN PGP SIGNATURE-----';
signature = signatureHeader + clearsigned.split(signatureHeader).pop();
});
it('should work', function(done) {
pgp.verifySignedMessage(signedMessage, signature, pubkey, function(err, signaturesValid) {
expect(err).to.not.exist;
expect(signaturesValid).to.be.true;
done();
});
});
it('should fail', function(done) {
pgp.verifySignedMessage(signedMessage.replace('signed', 'invalid'), signature, pubkey, function(err, signaturesValid) {
expect(err).to.not.exist;
expect(signaturesValid).to.be.false;
done();
});
});
it('should be null for wrong public key', function(done) {
pgp.verifySignedMessage(signedMessage, signature, wrongPubkey, function(err, signaturesValid) {
expect(err).to.not.exist;
expect(signaturesValid).to.be.null;
done();
pgp.decrypt(ct, keys.publicKeyArmored, function(err, pt, signValid) {
expect(err).to.not.exist;
expect(pt).to.equal('secret');
expect(signValid).to.be.true;
done();
});
});
});
});
});
});
describe('Import/Export key pair', function() {
it('should fail', function(done) {
pgp.importKeys({
passphrase: 'asd',
privateKeyArmored: privkey,
publicKeyArmored: pubkey
}, function(err) {
expect(err).to.exist;
expect(err.message).to.equal('Incorrect passphrase!');
pgp.exportKeys(function(err, keys) {
expect(err).to.exist;
expect(keys).to.not.exist;
done();
});
});
});
it('should work', function(done) {
pgp.importKeys({
passphrase: passphrase,
privateKeyArmored: privkey,
publicKeyArmored: pubkey
}, function(err) {
expect(err).to.not.exist;
pgp.exportKeys(function(err, keys) {
expect(err).to.not.exist;
expect(keys.keyId).to.equal(keyId);
expect(keys.privateKeyArmored.replace(/\r/g, '')).to.equal(privkey.replace(/\r/g, ''));
expect(keys.publicKeyArmored.replace(/\r/g, '')).to.equal(pubkey.replace(/\r/g, ''));
done();
});
});
});
});
describe('Change passphrase of private key', function() {
it('should work with new passphrase', function(done) {
pgp.changePassphrase({
privateKeyArmored: privkey,
oldPassphrase: passphrase,
newPassphrase: 'yxcv'
}, function(err, reEncryptedKey) {
expect(err).to.not.exist;
expect(reEncryptedKey).to.exist;
pgp.importKeys({
passphrase: 'yxcv',
privateKeyArmored: reEncryptedKey,
publicKeyArmored: pubkey
}, function(err) {
expect(err).to.not.exist;
done();
});
});
});
it('should work with empty passphrase', function(done) {
pgp.changePassphrase({
privateKeyArmored: privkey,
oldPassphrase: passphrase,
newPassphrase: undefined
}, function(err, reEncryptedKey) {
expect(err).to.not.exist;
expect(reEncryptedKey).to.exist;
pgp.importKeys({
passphrase: undefined,
privateKeyArmored: reEncryptedKey,
publicKeyArmored: pubkey
}, function(err) {
expect(err).to.not.exist;
done();
});
});
});
it('should fail when passphrases are equal', function(done) {
pgp.changePassphrase({
privateKeyArmored: privkey,
oldPassphrase: passphrase,
newPassphrase: passphrase
}, function(err, reEncryptedKey) {
expect(err).to.exist;
expect(reEncryptedKey).to.not.exist;
done();
});
});
it('should fail when old passphrase is incorrect', function(done) {
pgp.changePassphrase({
privateKeyArmored: privkey,
oldPassphrase: 'asd',
newPassphrase: 'yxcv'
}, function(err, reEncryptedKey) {
expect(err).to.exist;
expect(reEncryptedKey).to.not.exist;
done();
});
});
});
describe('Encrypt/Sign/Decrypt/Verify', function() {
var message = 'asdfs\n\nThursday, Nov 21, 2013 7:38 PM asdf@example.com wrote:\n' +
'> asdf\n' +
'> \n' +
'> Thursday, Nov 21, 2013 7:32 PM asdf@example.com wrote:\n' +
'> > secret 3';
var wrongPubkey = '-----BEGIN PGP PUBLIC KEY BLOCK-----\r\nVersion: OpenPGP.js v.1.20131116\r\nComment: Whiteout Mail - http://whiteout.io\r\n\r\nxsBNBFKODs4BB/9iOF4THsjQMY+WEpT7ShgKxj4bHzRRaQkqczS4nZvP0U3g\r\nqeqCnbpagyeKXA+bhWFQW4GmXtgAoeD5PXs6AZYrw3tWNxLKu2Oe6Tp9K/XI\r\nxTMQ2wl4qZKDXHvuPsJ7cmgaWqpPyXtxA4zHHS3WrkI/6VzHAcI/y6x4szSB\r\nKgSuhI3hjh3s7TybUC1U6AfoQGx/S7e3WwlCOrK8GTClirN/2mCPRC5wuIft\r\nnkoMfA6jK8d2OPrJ63shy5cgwHOjQg/xuk46dNS7tkvGmbaa+X0PgqSKB+Hf\r\nYPPNS/ylg911DH9qa8BqYU2QpNh9jUKXSF+HbaOM+plWkCSAL7czV+R3ABEB\r\nAAHNLVdoaXRlb3V0IFVzZXIgPHNhZmV3aXRobWUudGVzdHVzZXJAZ21haWwu\r\nY29tPsLAXAQQAQgAEAUCUo4O2gkQ1/uT/N+/wjwAAN2cB/9gFRmAfvEQ2qz+\r\nWubmT2EsSSnjPMxzG4uyykFoa+TaZCWo2Xa2tQghmU103kEkQb1OEjRjpgwJ\r\nYX9Kghnl8DByM686L5AXnRyHP78qRJCLXSXl0AGicboUDp5sovaa4rswQceH\r\nvcdWgZ/mgHTRoiQeJddy9k+H6MPFiyFaVcFwegVsmpc+dCcC8yT+qh8ZIbyG\r\nRJU60PmKKN7LUusP+8DbSv39zCGJCBlVVKyA4MzdF5uM+sqTdXbKzOrT5DGd\r\nCZaox4s+w16Sq1rHzZKFWfQPfKLDB9pyA0ufCVRA3AF6BUi7G3ZqhZiHNhMP\r\nNvE45V/hS1PbZcfPVoUjE2qc1Ix1\r\n=7Wpe\r\n-----END PGP PUBLIC KEY BLOCK-----';
beforeEach(function(done) {
pgp.importKeys({
passphrase: passphrase,
privateKeyArmored: privkey,
publicKeyArmored: pubkey
}, function(err) {
expect(err).to.not.exist;
done();
});
});
describe('Get KeyId', function() {
it('should work without param', function() {
var keyId = pgp.getKeyId();
expect(keyId).to.equal('F6F60E9B42CDFF4C');
});
it('should work with param', function() {
var keyId = pgp.getKeyId(pubkey);
expect(keyId).to.equal('F6F60E9B42CDFF4C');
});
});
describe('Get Fingerprint', function() {
it('should work without param', function() {
var fingerprint = pgp.getFingerprint();
expect(fingerprint).to.equal('5856CEF789C3A307E8A1B976F6F60E9B42CDFF4C');
});
it('should work with param', function() {
var fingerprint = pgp.getFingerprint(pubkey);
expect(fingerprint).to.equal('5856CEF789C3A307E8A1B976F6F60E9B42CDFF4C');
});
});
describe('getKeyParams', function() {
it('should work with param', function() {
var params = pgp.getKeyParams(pubkey);
expect(params.fingerprint).to.equal('5856CEF789C3A307E8A1B976F6F60E9B42CDFF4C');
expect(params._id).to.equal("F6F60E9B42CDFF4C");
expect(params.bitSize).to.equal(keySize);
expect(params.userId).to.equal("whiteout.test@t-online.de");
expect(params.userIds[0].name).to.equal("Whiteout User");
expect(params.userIds[0].emailAddress).to.equal("whiteout.test@t-online.de");
expect(params.algorithm).to.equal("rsa_encrypt_sign");
});
it('should work without param', function() {
var params = pgp.getKeyParams();
expect(params.fingerprint).to.equal('5856CEF789C3A307E8A1B976F6F60E9B42CDFF4C');
expect(params._id).to.equal("F6F60E9B42CDFF4C");
expect(params.bitSize).to.equal(keySize);
expect(params.userId).to.equal("whiteout.test@t-online.de");
expect(params.userIds[0].name).to.equal("Whiteout User");
expect(params.userIds[0].emailAddress).to.equal("whiteout.test@t-online.de");
expect(params.algorithm).to.equal("rsa_encrypt_sign");
});
});
describe('extractPublicKey', function() {
it('should work', function() {
var pk = pgp.extractPublicKey(privkey);
expect(pk).to.exist;
expect(pk).to.contain('-----BEGIN PGP PUBLIC KEY BLOCK-----');
});
});
describe('Encrypt and sign', function() {
it('should fail', function(done) {
var input = null;
pgp.encrypt(input, [pubkey], function(err, ct) {
expect(err).to.exist;
expect(ct).to.not.exist;
done();
});
});
it('should work', function(done) {
pgp.encrypt(message, [pubkey], function(err, ct) {
expect(err).to.not.exist;
expect(ct).to.exist;
done();
});
});
it('should encrypt to myself if public keys are empty', function(done) {
pgp.encrypt(message, undefined, function(err, ct) {
expect(err).to.not.exist;
expect(ct).to.exist;
done();
});
});
});
describe('Decrypt and verify', function() {
var ciphertext;
beforeEach(function(done) {
pgp.encrypt(message, [pubkey], function(err, ct) {
expect(err).to.not.exist;
expect(ct).to.exist;
ciphertext = ct;
done();
});
});
it('should fail', function(done) {
var input = 'asdfa\rsdf';
pgp.decrypt(input, pubkey, function(err, pt) {
expect(err).to.exist;
expect(pt).to.not.exist;
done();
});
});
it('should work', function(done) {
pgp.decrypt(ciphertext, pubkey, function(err, pt, signValid) {
expect(err).to.not.exist;
expect(pt).to.equal(message);
expect(signValid).to.be.true;
done();
});
});
it('should work without signature', function(done) {
var ct = openpgp.encryptMessage([pgp._publicKey], message);
pgp.decrypt(ct, undefined, function(err, pt, signValid) {
expect(err).to.not.exist;
expect(pt).to.equal(message);
expect(signValid).to.be.undefined;
done();
});
});
it('should fail to verify if public keys are empty', function(done) {
// setup another public key so that signature verification fails
pgp._publicKey = openpgp.key.readArmored(wrongPubkey).keys[0];
pgp.decrypt(ciphertext, undefined, function(err, pt, signValid) {
expect(err).to.not.exist;
expect(pt).to.equal(message);
expect(signValid).to.be.null;
done();
});
});
it('should decrypt but signValid should be null for wrong public key', function(done) {
pgp.decrypt(ciphertext, wrongPubkey, function(err, pt, signValid) {
expect(err).to.not.exist;
expect(pt).to.equal(message);
expect(signValid).to.be.null;
done();
});
});
});
describe('Verify clearsigned message', function() {
var clearsigned;
beforeEach(function() {
clearsigned = openpgp.signClearMessage(pgp._privateKey, 'this is a clearsigned message');
});
it('should work', function(done) {
pgp.verifyClearSignedMessage(clearsigned, pubkey, function(err, signaturesValid) {
expect(err).to.not.exist;
expect(signaturesValid).to.be.true;
done();
});
});
it('should fail', function(done) {
pgp.verifyClearSignedMessage(clearsigned.replace('clearsigned', 'invalid'), pubkey, function(err, signaturesValid) {
expect(err).to.not.exist;
expect(signaturesValid).to.be.false;
done();
});
});
it('should be null for wrong public key', function(done) {
pgp.verifyClearSignedMessage(clearsigned, wrongPubkey, function(err, signaturesValid) {
expect(err).to.not.exist;
expect(signaturesValid).to.be.null;
done();
});
});
});
describe('Verify detached signature', function() {
var signedMessage, signature;
beforeEach(function() {
signedMessage = 'this is a signed message';
var clearsigned = openpgp.signClearMessage(pgp._privateKey, signedMessage);
var signatureHeader = '-----BEGIN PGP SIGNATURE-----';
signature = signatureHeader + clearsigned.split(signatureHeader).pop();
});
it('should work', function(done) {
pgp.verifySignedMessage(signedMessage, signature, pubkey, function(err, signaturesValid) {
expect(err).to.not.exist;
expect(signaturesValid).to.be.true;
done();
});
});
it('should fail', function(done) {
pgp.verifySignedMessage(signedMessage.replace('signed', 'invalid'), signature, pubkey, function(err, signaturesValid) {
expect(err).to.not.exist;
expect(signaturesValid).to.be.false;
done();
});
});
it('should be null for wrong public key', function(done) {
pgp.verifySignedMessage(signedMessage, signature, wrongPubkey, function(err, signaturesValid) {
expect(err).to.not.exist;
expect(signaturesValid).to.be.null;
done();
});
});
});
});
});

View File

@ -1,226 +1,222 @@
define(function(require) {
'use strict';
'use strict';
var RestDAO = require('js/dao/rest-dao'),
PrivateKeyDAO = require('js/dao/privatekey-dao'),
expect = chai.expect;
var RestDAO = require('../../src/js/dao/rest-dao'),
PrivateKeyDAO = require('../../src/js/dao/privatekey-dao');
describe('Private Key DAO unit tests', function() {
describe('Private Key DAO unit tests', function() {
var privkeyDao, restDaoStub,
emailAddress = 'test@example.com',
deviceName = 'iPhone Work';
var privkeyDao, restDaoStub,
emailAddress = 'test@example.com',
deviceName = 'iPhone Work';
beforeEach(function() {
restDaoStub = sinon.createStubInstance(RestDAO);
privkeyDao = new PrivateKeyDAO(restDaoStub);
});
beforeEach(function() {
restDaoStub = sinon.createStubInstance(RestDAO);
privkeyDao = new PrivateKeyDAO(restDaoStub);
});
afterEach(function() {});
afterEach(function() {});
describe('requestDeviceRegistration', function() {
it('should fail due to invalid args', function(done) {
privkeyDao.requestDeviceRegistration({}, function(err, sessionKey) {
expect(err).to.exist;
expect(sessionKey).to.not.exist;
done();
});
});
it('should work', function(done) {
restDaoStub.post.yields(null, {
encryptedRegSessionKey: 'asdf'
});
privkeyDao.requestDeviceRegistration({
userId: emailAddress,
deviceName: deviceName
}, function(err, sessionKey) {
expect(err).to.not.exist;
expect(sessionKey).to.exist;
done();
});
describe('requestDeviceRegistration', function() {
it('should fail due to invalid args', function(done) {
privkeyDao.requestDeviceRegistration({}, function(err, sessionKey) {
expect(err).to.exist;
expect(sessionKey).to.not.exist;
done();
});
});
describe('uploadDeviceSecret', function() {
it('should fail due to invalid args', function(done) {
privkeyDao.uploadDeviceSecret({}, function(err) {
expect(err).to.exist;
done();
});
it('should work', function(done) {
restDaoStub.post.yields(null, {
encryptedRegSessionKey: 'asdf'
});
it('should work', function(done) {
restDaoStub.put.yields();
privkeyDao.requestDeviceRegistration({
userId: emailAddress,
deviceName: deviceName
}, function(err, sessionKey) {
expect(err).to.not.exist;
expect(sessionKey).to.exist;
done();
});
});
});
privkeyDao.uploadDeviceSecret({
userId: emailAddress,
deviceName: deviceName,
encryptedDeviceSecret: 'asdf',
iv: 'iv'
}, function(err) {
expect(err).to.not.exist;
done();
});
describe('uploadDeviceSecret', function() {
it('should fail due to invalid args', function(done) {
privkeyDao.uploadDeviceSecret({}, function(err) {
expect(err).to.exist;
done();
});
});
describe('requestAuthSessionKey', function() {
it('should fail due to invalid args', function(done) {
privkeyDao.requestAuthSessionKey({}, function(err) {
expect(err).to.exist;
done();
});
it('should work', function(done) {
restDaoStub.put.yields();
privkeyDao.uploadDeviceSecret({
userId: emailAddress,
deviceName: deviceName,
encryptedDeviceSecret: 'asdf',
iv: 'iv'
}, function(err) {
expect(err).to.not.exist;
done();
});
});
});
it('should work', function(done) {
restDaoStub.post.withArgs(undefined, '/auth/user/' + emailAddress).yields();
privkeyDao.requestAuthSessionKey({
userId: emailAddress
}, function(err) {
expect(err).to.not.exist;
done();
});
describe('requestAuthSessionKey', function() {
it('should fail due to invalid args', function(done) {
privkeyDao.requestAuthSessionKey({}, function(err) {
expect(err).to.exist;
done();
});
});
describe('verifyAuthentication', function() {
it('should fail due to invalid args', function(done) {
privkeyDao.verifyAuthentication({}, function(err) {
expect(err).to.exist;
done();
});
it('should work', function(done) {
restDaoStub.post.withArgs(undefined, '/auth/user/' + emailAddress).yields();
privkeyDao.requestAuthSessionKey({
userId: emailAddress
}, function(err) {
expect(err).to.not.exist;
done();
});
});
});
it('should work', function(done) {
var sessionId = '1';
var options = {
userId: emailAddress,
sessionId: sessionId,
encryptedChallenge: 'asdf',
encryptedDeviceSecret: 'qwer',
iv: ' iv'
};
restDaoStub.put.withArgs(options, '/auth/user/' + emailAddress + '/session/' + sessionId).yields();
privkeyDao.verifyAuthentication(options, function(err) {
expect(err).to.not.exist;
done();
});
describe('verifyAuthentication', function() {
it('should fail due to invalid args', function(done) {
privkeyDao.verifyAuthentication({}, function(err) {
expect(err).to.exist;
done();
});
});
describe('upload', function() {
it('should fail due to invalid args', function(done) {
privkeyDao.upload({}, function(err) {
expect(err).to.exist;
done();
});
it('should work', function(done) {
var sessionId = '1';
var options = {
userId: emailAddress,
sessionId: sessionId,
encryptedChallenge: 'asdf',
encryptedDeviceSecret: 'qwer',
iv: ' iv'
};
restDaoStub.put.withArgs(options, '/auth/user/' + emailAddress + '/session/' + sessionId).yields();
privkeyDao.verifyAuthentication(options, function(err) {
expect(err).to.not.exist;
done();
});
});
});
it('should work', function(done) {
var options = {
_id: '12345',
userId: emailAddress,
encryptedPrivateKey: 'asdf',
sessionId: '1',
salt: 'salt',
iv: 'iv'
};
restDaoStub.post.withArgs(options, '/privatekey/user/' + emailAddress + '/session/' + options.sessionId).yields();
privkeyDao.upload(options, function(err) {
expect(err).to.not.exist;
done();
});
describe('upload', function() {
it('should fail due to invalid args', function(done) {
privkeyDao.upload({}, function(err) {
expect(err).to.exist;
done();
});
});
describe('requestDownload', function() {
it('should fail due to invalid args', function(done) {
privkeyDao.requestDownload({}, function(err) {
expect(err).to.exist;
done();
});
it('should work', function(done) {
var options = {
_id: '12345',
userId: emailAddress,
encryptedPrivateKey: 'asdf',
sessionId: '1',
salt: 'salt',
iv: 'iv'
};
restDaoStub.post.withArgs(options, '/privatekey/user/' + emailAddress + '/session/' + options.sessionId).yields();
privkeyDao.upload(options, function(err) {
expect(err).to.not.exist;
done();
});
});
});
it('should work', function(done) {
var keyId = '12345';
restDaoStub.get.withArgs({
uri: '/privatekey/user/' + emailAddress + '/key/' + keyId
}).yields();
privkeyDao.requestDownload({
userId: emailAddress,
keyId: keyId
}, function(err, found) {
expect(err).to.not.exist;
expect(found).to.be.true;
done();
});
describe('requestDownload', function() {
it('should fail due to invalid args', function(done) {
privkeyDao.requestDownload({}, function(err) {
expect(err).to.exist;
done();
});
});
describe('hasPrivateKey', function() {
it('should fail due to invalid args', function(done) {
privkeyDao.hasPrivateKey({}, function(err) {
expect(err).to.exist;
done();
});
it('should work', function(done) {
var keyId = '12345';
restDaoStub.get.withArgs({
uri: '/privatekey/user/' + emailAddress + '/key/' + keyId
}).yields();
privkeyDao.requestDownload({
userId: emailAddress,
keyId: keyId
}, function(err, found) {
expect(err).to.not.exist;
expect(found).to.be.true;
done();
});
});
});
it('should work', function(done) {
var keyId = '12345';
restDaoStub.get.withArgs({
uri: '/privatekey/user/' + emailAddress + '/key/' + keyId + '?ignoreRecovery=true'
}).yields();
privkeyDao.hasPrivateKey({
userId: emailAddress,
keyId: keyId
}, function(err, found) {
expect(err).to.not.exist;
expect(found).to.be.true;
done();
});
describe('hasPrivateKey', function() {
it('should fail due to invalid args', function(done) {
privkeyDao.hasPrivateKey({}, function(err) {
expect(err).to.exist;
done();
});
});
describe('download', function() {
it('should fail due to invalid args', function(done) {
privkeyDao.download({}, function(err) {
expect(err).to.exist;
done();
});
it('should work', function(done) {
var keyId = '12345';
restDaoStub.get.withArgs({
uri: '/privatekey/user/' + emailAddress + '/key/' + keyId + '?ignoreRecovery=true'
}).yields();
privkeyDao.hasPrivateKey({
userId: emailAddress,
keyId: keyId
}, function(err, found) {
expect(err).to.not.exist;
expect(found).to.be.true;
done();
});
});
});
it('should work', function(done) {
var key = {
_id: '12345'
};
restDaoStub.get.withArgs({
uri: '/privatekey/user/' + emailAddress + '/key/' + key._id + '/recovery/token'
}).yields();
privkeyDao.download({
userId: emailAddress,
keyId: key._id,
recoveryToken: 'token'
}, function(err) {
expect(err).to.not.exist;
done();
});
describe('download', function() {
it('should fail due to invalid args', function(done) {
privkeyDao.download({}, function(err) {
expect(err).to.exist;
done();
});
});
it('should work', function(done) {
var key = {
_id: '12345'
};
restDaoStub.get.withArgs({
uri: '/privatekey/user/' + emailAddress + '/key/' + key._id + '/recovery/token'
}).yields();
privkeyDao.download({
userId: emailAddress,
keyId: key._id,
recoveryToken: 'token'
}, function(err) {
expect(err).to.not.exist;
done();
});
});
});
});

View File

@ -1,286 +1,281 @@
define(function(require) {
'use strict';
'use strict';
var expect = chai.expect,
angular = require('angular'),
mocks = require('angularMocks'),
PrivateKeyUploadCtrl = require('js/controller/privatekey-upload'),
appController = require('js/app-controller'),
KeychainDAO = require('js/dao/keychain-dao'),
PGP = require('js/crypto/pgp');
var mocks = angular.mocks,
PrivateKeyUploadCtrl = require('../../src/js/controller/privatekey-upload'),
appController = require('../../src/js/app-controller'),
KeychainDAO = require('../../src/js/dao/keychain-dao'),
PGP = require('../../src/js/crypto/pgp');
describe('Private Key Upload Controller unit test', function() {
var scope, location, ctrl,
origEmailDao, emailDaoMock,
origKeychain, keychainMock,
pgpStub,
emailAddress = 'fred@foo.com';
describe('Private Key Upload Controller unit test', function() {
var scope, location, ctrl,
origEmailDao, emailDaoMock,
origKeychain, keychainMock,
pgpStub,
emailAddress = 'fred@foo.com';
beforeEach(function(done) {
// remember original module to restore later, then replace it
origEmailDao = appController._emailDao;
appController._emailDao = emailDaoMock = {
_account: {
emailAddress: emailAddress
}
beforeEach(function(done) {
// remember original module to restore later, then replace it
origEmailDao = appController._emailDao;
appController._emailDao = emailDaoMock = {
_account: {
emailAddress: emailAddress
}
};
origKeychain = appController._keychain;
appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO);
keychainMock._pgp = pgpStub = sinon.createStubInstance(PGP);
angular.module('login-privatekey-download-test', []);
mocks.module('login-privatekey-download-test');
mocks.inject(function($controller, $rootScope) {
scope = $rootScope.$new();
scope.state = {};
ctrl = $controller(PrivateKeyUploadCtrl, {
$location: location,
$scope: scope
});
done();
});
});
afterEach(function() {
// restore the app controller module
appController._keychain = origKeychain;
appController._emailDao = origEmailDao;
});
describe('checkServerForKey', function() {
var keyParams = {
userId: emailAddress,
_id: 'keyId',
};
it('should fail', function(done) {
pgpStub.getKeyParams.returns(keyParams);
keychainMock.hasPrivateKey.yields(42);
scope.onError = function(err) {
expect(err).to.exist;
expect(keychainMock.hasPrivateKey.calledOnce).to.be.true;
done();
};
origKeychain = appController._keychain;
appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO);
keychainMock._pgp = pgpStub = sinon.createStubInstance(PGP);
angular.module('login-privatekey-download-test', []);
mocks.module('login-privatekey-download-test');
mocks.inject(function($controller, $rootScope) {
scope = $rootScope.$new();
scope.state = {};
ctrl = $controller(PrivateKeyUploadCtrl, {
$location: location,
$scope: scope
});
scope.checkServerForKey();
});
it('should return true', function(done) {
pgpStub.getKeyParams.returns(keyParams);
keychainMock.hasPrivateKey.withArgs({
userId: keyParams.userId,
keyId: keyParams._id
}).yields(null, true);
scope.checkServerForKey(function(privateKeySynced) {
expect(privateKeySynced).to.be.true;
done();
});
});
afterEach(function() {
// restore the app controller module
appController._keychain = origKeychain;
appController._emailDao = origEmailDao;
it('should return undefined', function(done) {
pgpStub.getKeyParams.returns(keyParams);
keychainMock.hasPrivateKey.withArgs({
userId: keyParams.userId,
keyId: keyParams._id
}).yields(null, false);
scope.checkServerForKey(function(privateKeySynced) {
expect(privateKeySynced).to.be.undefined;
done();
});
});
});
describe('handlePaste', function() {
it('should work', function() {
scope.handlePaste({
clipboardData: {
getData: function(val) {
expect(val).to.equal('text/plain');
return '1qaz-2wsx-3edc-4rfv-5tgb-6yhn';
}
}
});
expect(scope.code0).to.equal('1qaz');
expect(scope.code1).to.equal('2wsx');
expect(scope.code2).to.equal('3edc');
expect(scope.code3).to.equal('4rfv');
expect(scope.code4).to.equal('5tgb');
expect(scope.code5).to.equal('6yhn');
});
});
describe('displayUploadUi', function() {
it('should work', function() {
// add some artifacts from a previous key input
scope.code0 = scope.code1 = scope.code2 = scope.code3 = scope.code4 = scope.code5 = 'asdasd';
scope.displayUploadUi();
expect(scope.step).to.equal(1);
expect(scope.code.length).to.equal(24);
// artifacts should be cleared
expect(scope.code0).to.be.empty;
expect(scope.code1).to.be.empty;
expect(scope.code2).to.be.empty;
expect(scope.code3).to.be.empty;
expect(scope.code4).to.be.empty;
expect(scope.code5).to.be.empty;
});
});
describe('verifyCode', function() {
it('should fail for wrong code', function() {
scope.code0 = 'b';
scope.code1 = 'b';
scope.code2 = 'b';
scope.code3 = 'b';
scope.code4 = 'b';
scope.code5 = 'b';
scope.code = 'aaaaaa';
scope.onError = function() {};
expect(scope.verifyCode()).to.be.false;
});
describe('checkServerForKey', function() {
var keyParams = {
userId: emailAddress,
_id: 'keyId',
it('should work', function() {
scope.code0 = 'a';
scope.code1 = 'a';
scope.code2 = 'a';
scope.code3 = 'a';
scope.code4 = 'a';
scope.code5 = 'a';
scope.code = 'aaaaaa';
scope.onError = function() {};
expect(scope.verifyCode()).to.be.false;
});
});
describe('setDeviceName', function() {
it('should work', function(done) {
keychainMock.setDeviceName.yields();
scope.setDeviceName(done);
});
});
describe('encryptAndUploadKey', function() {
it('should fail due to keychain.registerDevice', function(done) {
keychainMock.registerDevice.yields(42);
scope.onError = function(err) {
expect(err).to.exist;
expect(keychainMock.registerDevice.calledOnce).to.be.true;
done();
};
it('should fail', function(done) {
pgpStub.getKeyParams.returns(keyParams);
keychainMock.hasPrivateKey.yields(42);
scope.onError = function(err) {
expect(err).to.exist;
expect(keychainMock.hasPrivateKey.calledOnce).to.be.true;
done();
};
scope.checkServerForKey();
});
it('should return true', function(done) {
pgpStub.getKeyParams.returns(keyParams);
keychainMock.hasPrivateKey.withArgs({
userId: keyParams.userId,
keyId: keyParams._id
}).yields(null, true);
scope.checkServerForKey(function(privateKeySynced) {
expect(privateKeySynced).to.be.true;
done();
});
});
it('should return undefined', function(done) {
pgpStub.getKeyParams.returns(keyParams);
keychainMock.hasPrivateKey.withArgs({
userId: keyParams.userId,
keyId: keyParams._id
}).yields(null, false);
scope.checkServerForKey(function(privateKeySynced) {
expect(privateKeySynced).to.be.undefined;
done();
});
});
scope.encryptAndUploadKey();
});
describe('handlePaste', function() {
it('should work', function() {
scope.handlePaste({
clipboardData: {
getData: function(val) {
expect(val).to.equal('text/plain');
return '1qaz-2wsx-3edc-4rfv-5tgb-6yhn';
}
}
});
it('should work', function(done) {
keychainMock.registerDevice.yields();
keychainMock.uploadPrivateKey.yields();
expect(scope.code0).to.equal('1qaz');
expect(scope.code1).to.equal('2wsx');
expect(scope.code2).to.equal('3edc');
expect(scope.code3).to.equal('4rfv');
expect(scope.code4).to.equal('5tgb');
expect(scope.code5).to.equal('6yhn');
scope.encryptAndUploadKey(function(err) {
expect(err).to.not.exist;
expect(keychainMock.registerDevice.calledOnce).to.be.true;
expect(keychainMock.uploadPrivateKey.calledOnce).to.be.true;
done();
});
});
});
describe('displayUploadUi', function() {
it('should work', function() {
// add some artifacts from a previous key input
scope.code0 = scope.code1 = scope.code2 = scope.code3 = scope.code4 = scope.code5 = 'asdasd';
scope.displayUploadUi();
expect(scope.step).to.equal(1);
expect(scope.code.length).to.equal(24);
// artifacts should be cleared
expect(scope.code0).to.be.empty;
expect(scope.code1).to.be.empty;
expect(scope.code2).to.be.empty;
expect(scope.code3).to.be.empty;
expect(scope.code4).to.be.empty;
expect(scope.code5).to.be.empty;
});
describe('goBack', function() {
it('should work', function() {
scope.step = 2;
scope.goBack();
expect(scope.step).to.equal(1);
});
describe('verifyCode', function() {
it('should fail for wrong code', function() {
scope.code0 = 'b';
scope.code1 = 'b';
scope.code2 = 'b';
scope.code3 = 'b';
scope.code4 = 'b';
scope.code5 = 'b';
scope.code = 'aaaaaa';
it('should not work for < 2', function() {
scope.step = 1;
scope.goBack();
expect(scope.step).to.equal(1);
});
});
scope.onError = function() {};
expect(scope.verifyCode()).to.be.false;
});
it('should work', function() {
scope.code0 = 'a';
scope.code1 = 'a';
scope.code2 = 'a';
scope.code3 = 'a';
scope.code4 = 'a';
scope.code5 = 'a';
scope.code = 'aaaaaa';
scope.onError = function() {};
expect(scope.verifyCode()).to.be.false;
});
describe('goForward', function() {
var verifyCodeStub, setDeviceNameStub, encryptAndUploadKeyStub;
beforeEach(function() {
verifyCodeStub = sinon.stub(scope, 'verifyCode');
setDeviceNameStub = sinon.stub(scope, 'setDeviceName');
encryptAndUploadKeyStub = sinon.stub(scope, 'encryptAndUploadKey');
});
afterEach(function() {
verifyCodeStub.restore();
setDeviceNameStub.restore();
encryptAndUploadKeyStub.restore();
});
describe('setDeviceName', function() {
it('should work', function(done) {
keychainMock.setDeviceName.yields();
scope.setDeviceName(done);
});
it('should work for < 2', function() {
scope.step = 1;
scope.goForward();
expect(scope.step).to.equal(2);
});
describe('encryptAndUploadKey', function() {
it('should fail due to keychain.registerDevice', function(done) {
keychainMock.registerDevice.yields(42);
scope.onError = function(err) {
expect(err).to.exist;
expect(keychainMock.registerDevice.calledOnce).to.be.true;
done();
};
scope.encryptAndUploadKey();
});
it('should work', function(done) {
keychainMock.registerDevice.yields();
keychainMock.uploadPrivateKey.yields();
scope.encryptAndUploadKey(function(err) {
expect(err).to.not.exist;
expect(keychainMock.registerDevice.calledOnce).to.be.true;
expect(keychainMock.uploadPrivateKey.calledOnce).to.be.true;
done();
});
});
it('should work for 2', function() {
verifyCodeStub.returns(true);
scope.step = 2;
scope.goForward();
expect(scope.step).to.equal(3);
});
describe('goBack', function() {
it('should work', function() {
scope.step = 2;
scope.goBack();
expect(scope.step).to.equal(1);
});
it('should not work for < 2', function() {
scope.step = 1;
scope.goBack();
expect(scope.step).to.equal(1);
});
it('should not work for 2 when code invalid', function() {
verifyCodeStub.returns(false);
scope.step = 2;
scope.goForward();
expect(scope.step).to.equal(2);
});
describe('goForward', function() {
var verifyCodeStub, setDeviceNameStub, encryptAndUploadKeyStub;
beforeEach(function() {
verifyCodeStub = sinon.stub(scope, 'verifyCode');
setDeviceNameStub = sinon.stub(scope, 'setDeviceName');
encryptAndUploadKeyStub = sinon.stub(scope, 'encryptAndUploadKey');
});
afterEach(function() {
verifyCodeStub.restore();
setDeviceNameStub.restore();
encryptAndUploadKeyStub.restore();
});
it('should fail for 3 due to error in setDeviceName', function(done) {
scope.step = 3;
setDeviceNameStub.yields(42);
it('should work for < 2', function() {
scope.step = 1;
scope.goForward();
expect(scope.step).to.equal(2);
});
it('should work for 2', function() {
verifyCodeStub.returns(true);
scope.step = 2;
scope.goForward();
scope.onError = function(err) {
expect(err).to.exist;
expect(scope.step).to.equal(3);
});
done();
};
it('should not work for 2 when code invalid', function() {
verifyCodeStub.returns(false);
scope.step = 2;
scope.goForward();
expect(scope.step).to.equal(2);
});
it('should fail for 3 due to error in setDeviceName', function(done) {
scope.step = 3;
setDeviceNameStub.yields(42);
scope.onError = function(err) {
expect(err).to.exist;
expect(scope.step).to.equal(3);
done();
};
scope.goForward();
});
it('should fail for 3 due to error in encryptAndUploadKey', function(done) {
scope.step = 3;
setDeviceNameStub.yields();
encryptAndUploadKeyStub.yields(42);
scope.onError = function(err) {
expect(err).to.exist;
expect(scope.step).to.equal(4);
done();
};
scope.goForward();
});
it('should work for 3', function(done) {
scope.step = 3;
setDeviceNameStub.yields();
encryptAndUploadKeyStub.yields();
scope.onError = function(err) {
expect(err.title).to.equal('Success');
expect(scope.step).to.equal(4);
done();
};
scope.goForward();
});
scope.goForward();
});
it('should fail for 3 due to error in encryptAndUploadKey', function(done) {
scope.step = 3;
setDeviceNameStub.yields();
encryptAndUploadKeyStub.yields(42);
scope.onError = function(err) {
expect(err).to.exist;
expect(scope.step).to.equal(4);
done();
};
scope.goForward();
});
it('should work for 3', function(done) {
scope.step = 3;
setDeviceNameStub.yields();
encryptAndUploadKeyStub.yields();
scope.onError = function(err) {
expect(err.title).to.equal('Success');
expect(scope.step).to.equal(4);
done();
};
scope.goForward();
});
});
});

View File

@ -1,165 +1,161 @@
define(function(require) {
'use strict';
'use strict';
var RestDAO = require('js/dao/rest-dao'),
PublicKeyDAO = require('js/dao/publickey-dao'),
expect = chai.expect;
var RestDAO = require('../../src/js/dao/rest-dao'),
PublicKeyDAO = require('../../src/js/dao/publickey-dao');
describe('Public Key DAO unit tests', function() {
describe('Public Key DAO unit tests', function() {
var pubkeyDao, restDaoStub;
var pubkeyDao, restDaoStub;
beforeEach(function() {
restDaoStub = sinon.createStubInstance(RestDAO);
pubkeyDao = new PublicKeyDAO(restDaoStub);
});
beforeEach(function() {
restDaoStub = sinon.createStubInstance(RestDAO);
pubkeyDao = new PublicKeyDAO(restDaoStub);
});
afterEach(function() {});
afterEach(function() {});
describe('get', function() {
it('should fail', function(done) {
restDaoStub.get.yields(42);
describe('get', function() {
it('should fail', function(done) {
restDaoStub.get.yields(42);
pubkeyDao.get('id', function(err, key) {
expect(err).to.exist;
expect(key).to.not.exist;
expect(restDaoStub.get.calledOnce).to.be.true;
done();
});
});
it('should work', function(done) {
restDaoStub.get.yields(null, {
_id: '12345',
publicKey: 'asdf'
});
pubkeyDao.get('id', function(err, key) {
expect(err).to.not.exist;
expect(key).to.exist;
expect(key._id).to.exist;
expect(key.publicKey).to.exist;
expect(restDaoStub.get.calledOnce).to.be.true;
done();
});
pubkeyDao.get('id', function(err, key) {
expect(err).to.exist;
expect(key).to.not.exist;
expect(restDaoStub.get.calledOnce).to.be.true;
done();
});
});
describe('verify', function() {
it('should fail', function(done) {
restDaoStub.get.yields(42);
pubkeyDao.verify('id', function(err) {
expect(err).to.exist;
done();
});
it('should work', function(done) {
restDaoStub.get.yields(null, {
_id: '12345',
publicKey: 'asdf'
});
it('should not error for 400', function(done) {
restDaoStub.get.yields({
code: 400
});
pubkeyDao.verify('id', function(err) {
expect(err).to.not.exist;
done();
});
pubkeyDao.get('id', function(err, key) {
expect(err).to.not.exist;
expect(key).to.exist;
expect(key._id).to.exist;
expect(key.publicKey).to.exist;
expect(restDaoStub.get.calledOnce).to.be.true;
done();
});
});
});
it('should work', function(done) {
var uuid = 'c621e328-8548-40a1-8309-adf1955e98a9';
restDaoStub.get.yields(null);
describe('verify', function() {
it('should fail', function(done) {
restDaoStub.get.yields(42);
pubkeyDao.verify(uuid, function(err) {
expect(err).to.not.exist;
expect(restDaoStub.get.calledWith(sinon.match(function(arg){
return arg.uri === '/verify/' + uuid && arg.type === 'text';
}))).to.be.true;
done();
});
pubkeyDao.verify('id', function(err) {
expect(err).to.exist;
done();
});
});
describe('get by userId', function() {
it('should fail', function(done) {
restDaoStub.get.yields(42);
pubkeyDao.getByUserId('userId', function(err, key) {
expect(err).to.exist;
expect(key).to.not.exist;
expect(restDaoStub.get.calledOnce).to.be.true;
done();
});
it('should not error for 400', function(done) {
restDaoStub.get.yields({
code: 400
});
it('should react to 404', function(done) {
restDaoStub.get.yields({
code: 404
});
pubkeyDao.getByUserId('userId', function(err, key) {
expect(err).to.not.exist;
expect(key).to.not.exist;
expect(restDaoStub.get.calledOnce).to.be.true;
done();
});
});
it('should return empty array', function(done) {
restDaoStub.get.yields(null, []);
pubkeyDao.getByUserId('userId', function(err, key) {
expect(err).to.not.exist;
expect(key).to.not.exist;
expect(restDaoStub.get.calledOnce).to.be.true;
done();
});
});
it('should work', function(done) {
restDaoStub.get.yields(null, [{
_id: '12345',
publicKey: 'asdf'
}]);
pubkeyDao.getByUserId('userId', function(err, key) {
expect(err).to.not.exist;
expect(key).to.exist;
expect(key._id).to.exist;
expect(key.publicKey).to.exist;
expect(restDaoStub.get.calledOnce).to.be.true;
done();
});
pubkeyDao.verify('id', function(err) {
expect(err).to.not.exist;
done();
});
});
describe('put', function() {
it('should fail', function(done) {
restDaoStub.put.yields();
it('should work', function(done) {
var uuid = 'c621e328-8548-40a1-8309-adf1955e98a9';
restDaoStub.get.yields(null);
pubkeyDao.put({
_id: '12345',
publicKey: 'asdf'
}, function(err) {
expect(err).to.not.exist;
expect(restDaoStub.put.calledOnce).to.be.true;
done();
});
pubkeyDao.verify(uuid, function(err) {
expect(err).to.not.exist;
expect(restDaoStub.get.calledWith(sinon.match(function(arg) {
return arg.uri === '/verify/' + uuid && arg.type === 'text';
}))).to.be.true;
done();
});
});
});
describe('get by userId', function() {
it('should fail', function(done) {
restDaoStub.get.yields(42);
pubkeyDao.getByUserId('userId', function(err, key) {
expect(err).to.exist;
expect(key).to.not.exist;
expect(restDaoStub.get.calledOnce).to.be.true;
done();
});
});
describe('remove', function() {
it('should fail', function(done) {
restDaoStub.remove.yields();
it('should react to 404', function(done) {
restDaoStub.get.yields({
code: 404
});
pubkeyDao.remove('12345', function(err) {
expect(err).to.not.exist;
expect(restDaoStub.remove.calledOnce).to.be.true;
done();
});
pubkeyDao.getByUserId('userId', function(err, key) {
expect(err).to.not.exist;
expect(key).to.not.exist;
expect(restDaoStub.get.calledOnce).to.be.true;
done();
});
});
it('should return empty array', function(done) {
restDaoStub.get.yields(null, []);
pubkeyDao.getByUserId('userId', function(err, key) {
expect(err).to.not.exist;
expect(key).to.not.exist;
expect(restDaoStub.get.calledOnce).to.be.true;
done();
});
});
it('should work', function(done) {
restDaoStub.get.yields(null, [{
_id: '12345',
publicKey: 'asdf'
}]);
pubkeyDao.getByUserId('userId', function(err, key) {
expect(err).to.not.exist;
expect(key).to.exist;
expect(key._id).to.exist;
expect(key.publicKey).to.exist;
expect(restDaoStub.get.calledOnce).to.be.true;
done();
});
});
});
describe('put', function() {
it('should fail', function(done) {
restDaoStub.put.yields();
pubkeyDao.put({
_id: '12345',
publicKey: 'asdf'
}, function(err) {
expect(err).to.not.exist;
expect(restDaoStub.put.calledOnce).to.be.true;
done();
});
});
});
describe('remove', function() {
it('should fail', function(done) {
restDaoStub.remove.yields();
pubkeyDao.remove('12345', function(err) {
expect(err).to.not.exist;
expect(restDaoStub.remove.calledOnce).to.be.true;
done();
});
});
});
});

View File

@ -1,197 +1,193 @@
define(function(require) {
'use strict';
'use strict';
var expect = chai.expect,
angular = require('angular'),
mocks = require('angularMocks'),
KeychainDAO = require('js/dao/keychain-dao'),
InvitationDAO = require('js/dao/invitation-dao'),
PGP = require('js/crypto/pgp'),
ReadCtrl = require('js/controller/read'),
OutboxBO = require('js/bo/outbox'),
appController = require('js/app-controller');
var mocks = angular.mocks,
KeychainDAO = require('../../src/js/dao/keychain-dao'),
InvitationDAO = require('../../src/js/dao/invitation-dao'),
PGP = require('../../src/js/crypto/pgp'),
ReadCtrl = require('../../src/js/controller/read'),
OutboxBO = require('../../src/js/bo/outbox'),
appController = require('../../src/js/app-controller');
describe('Read Controller unit test', function() {
var scope, ctrl,
origKeychain, keychainMock,
origInvitation, invitationMock,
origCrypto, cryptoMock,
origOutbox, outboxMock,
origEmailDao;
describe('Read Controller unit test', function() {
var scope, ctrl,
origKeychain, keychainMock,
origInvitation, invitationMock,
origCrypto, cryptoMock,
origOutbox, outboxMock,
origEmailDao;
beforeEach(function() {
origKeychain = appController._keychain;
appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO);
beforeEach(function() {
origKeychain = appController._keychain;
appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO);
origInvitation = appController._invitationDao;
appController._invitationDao = invitationMock = sinon.createStubInstance(InvitationDAO);
origInvitation = appController._invitationDao;
appController._invitationDao = invitationMock = sinon.createStubInstance(InvitationDAO);
origCrypto = appController._pgp;
appController._pgp = cryptoMock = sinon.createStubInstance(PGP);
origCrypto = appController._pgp;
appController._pgp = cryptoMock = sinon.createStubInstance(PGP);
origOutbox = appController._outboxBo;
appController._outboxBo = outboxMock = sinon.createStubInstance(OutboxBO);
origOutbox = appController._outboxBo;
appController._outboxBo = outboxMock = sinon.createStubInstance(OutboxBO);
origEmailDao = appController._emailDao;
appController._emailDao = {
_account: 'sender@example.com'
origEmailDao = appController._emailDao;
appController._emailDao = {
_account: 'sender@example.com'
};
angular.module('readtest', []);
mocks.module('readtest');
mocks.inject(function($rootScope, $controller) {
scope = $rootScope.$new();
scope.state = {};
ctrl = $controller(ReadCtrl, {
$scope: scope
});
});
});
afterEach(function() {
appController._keychain = origKeychain;
appController._invitationDao = origInvitation;
appController._pgp = origCrypto;
appController._outboxBo = origOutbox;
appController._emailDao = origEmailDao;
});
describe('scope variables', function() {
it('should be set correctly', function() {
expect(scope.state.read).to.exist;
expect(scope.state.read.open).to.be.false;
expect(scope.state.read.toggle).to.exist;
});
});
describe('open/close read view', function() {
it('should open/close', function() {
expect(scope.state.read.open).to.be.false;
scope.state.read.toggle(true);
expect(scope.state.read.open).to.be.true;
scope.state.read.toggle(false);
expect(scope.state.read.open).to.be.false;
});
});
describe('getKeyId', function() {
var address = 'asfd@asdf.com';
it('should show searching on error', function() {
expect(scope.keyId).to.equal('No key found.');
keychainMock.getReceiverPublicKey.yields(42);
scope.onError = function(err) {
expect(err).to.equal(42);
expect(scope.keyId).to.equal('Searching...');
};
angular.module('readtest', []);
mocks.module('readtest');
mocks.inject(function($rootScope, $controller) {
scope = $rootScope.$new();
scope.state = {};
ctrl = $controller(ReadCtrl, {
$scope: scope
});
});
scope.getKeyId(address);
});
afterEach(function() {
appController._keychain = origKeychain;
appController._invitationDao = origInvitation;
appController._pgp = origCrypto;
appController._outboxBo = origOutbox;
appController._emailDao = origEmailDao;
it('should allow invitation on empty key', function() {
keychainMock.getReceiverPublicKey.yields();
scope.onError = function(err) {
expect(err).not.exist;
expect(scope.keyId).to.equal('User has no key. Click to invite.');
};
scope.getKeyId(address);
});
describe('scope variables', function() {
it('should be set correctly', function() {
expect(scope.state.read).to.exist;
expect(scope.state.read.open).to.be.false;
expect(scope.state.read.toggle).to.exist;
it('should show searching on error', function() {
keychainMock.getReceiverPublicKey.yields(null, {
publicKey: 'PUBLIC KEY'
});
cryptoMock.getFingerprint.returns('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
scope.onError = function(err) {
expect(err).to.not.exist;
expect(scope.keyId).to.equal('PGP key: XXXXXXXX');
};
scope.getKeyId(address);
});
describe('open/close read view', function() {
it('should open/close', function() {
expect(scope.state.read.open).to.be.false;
scope.state.read.toggle(true);
expect(scope.state.read.open).to.be.true;
scope.state.read.toggle(false);
expect(scope.state.read.open).to.be.false;
});
});
describe('getKeyId', function() {
var address = 'asfd@asdf.com';
it('should show searching on error', function() {
expect(scope.keyId).to.equal('No key found.');
keychainMock.getReceiverPublicKey.yields(42);
scope.onError = function(err) {
expect(err).to.equal(42);
expect(scope.keyId).to.equal('Searching...');
};
scope.getKeyId(address);
});
it('should allow invitation on empty key', function() {
keychainMock.getReceiverPublicKey.yields();
scope.onError = function(err) {
expect(err).not.exist;
expect(scope.keyId).to.equal('User has no key. Click to invite.');
};
scope.getKeyId(address);
});
it('should show searching on error', function() {
keychainMock.getReceiverPublicKey.yields(null, {
publicKey: 'PUBLIC KEY'
});
cryptoMock.getFingerprint.returns('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
scope.onError = function(err) {
expect(err).to.not.exist;
expect(scope.keyId).to.equal('PGP key: XXXXXXXX');
};
scope.getKeyId(address);
});
});
describe('invite', function() {
it('not allow invitation for secure users', function() {
expect(scope.keyId).to.equal('No key found.');
scope.invite({
secure: true,
address: 'asdf@asdf.de'
});
expect(scope.keyId).to.equal('No key found.');
});
it('should show error on invitation dao invite error', function() {
invitationMock.invite.yields(42);
scope.onError = function(err) {
expect(err).to.equal(42);
};
scope.invite({
address: 'asdf@asdf.de'
});
});
it('should show error on outbox put error', function() {
invitationMock.invite.yields();
outboxMock.put.yields(42);
scope.onError = function(err) {
expect(err).to.equal(42);
};
scope.invite({
address: 'asdf@asdf.de'
});
});
it('should work', function() {
invitationMock.invite.yields();
outboxMock.put.yields();
scope.onError = function(err) {
expect(err).to.not.exist;
};
scope.invite({
address: 'asdf@asdf.de'
});
});
});
describe('parseConversation', function() {
it.skip('should work', function() {
var body = 'foo\n' +
'\n' +
'> bar\n' +
'>\n' +
'> foofoo\n' +
'>> foofoobar\n' +
'\ncomment\n' +
'>> barbar';
var nodes = scope.parseConversation({
body: body
});
expect(nodes).to.exist;
var expectedJson = '{"children":["foo\\n",{"children":["bar\\n\\nfoofoo",{"children":["foofoobar"]}]},"\\ncomment",{"children":[{"children":["barbar"]}]}]}';
var json = JSON.stringify(nodes);
expect(json).to.equal(expectedJson);
var expectedHtml = '<div class="view-read-body"><div class="line"><span>foo</span><br></div><div class="line empty-line"><span></span><br></div><div class="prev-message"><div class="line"><span>bar</span><br></div><div class="line empty-line"><span></span><br></div><div class="line"><span>foofoo</span><br></div></div><div class="prev-message"><div class="prev-message"><div class="line"><span>foofoobar</span><br></div></div></div><div class="line empty-line"><span></span><br></div><div class="line"><span>comment</span><br></div><div class="prev-message"><div class="prev-message"><div class="line"><span>barbar</span><br></div></div></div></div>';
var html = scope.renderNodes(nodes);
expect(html).to.equal(expectedHtml);
});
});
});
describe('invite', function() {
it('not allow invitation for secure users', function() {
expect(scope.keyId).to.equal('No key found.');
scope.invite({
secure: true,
address: 'asdf@asdf.de'
});
expect(scope.keyId).to.equal('No key found.');
});
it('should show error on invitation dao invite error', function() {
invitationMock.invite.yields(42);
scope.onError = function(err) {
expect(err).to.equal(42);
};
scope.invite({
address: 'asdf@asdf.de'
});
});
it('should show error on outbox put error', function() {
invitationMock.invite.yields();
outboxMock.put.yields(42);
scope.onError = function(err) {
expect(err).to.equal(42);
};
scope.invite({
address: 'asdf@asdf.de'
});
});
it('should work', function() {
invitationMock.invite.yields();
outboxMock.put.yields();
scope.onError = function(err) {
expect(err).to.not.exist;
};
scope.invite({
address: 'asdf@asdf.de'
});
});
});
describe('parseConversation', function() {
it.skip('should work', function() {
var body = 'foo\n' +
'\n' +
'> bar\n' +
'>\n' +
'> foofoo\n' +
'>> foofoobar\n' +
'\ncomment\n' +
'>> barbar';
var nodes = scope.parseConversation({
body: body
});
expect(nodes).to.exist;
var expectedJson = '{"children":["foo\\n",{"children":["bar\\n\\nfoofoo",{"children":["foofoobar"]}]},"\\ncomment",{"children":[{"children":["barbar"]}]}]}';
var json = JSON.stringify(nodes);
expect(json).to.equal(expectedJson);
var expectedHtml = '<div class="view-read-body"><div class="line"><span>foo</span><br></div><div class="line empty-line"><span></span><br></div><div class="prev-message"><div class="line"><span>bar</span><br></div><div class="line empty-line"><span></span><br></div><div class="line"><span>foofoo</span><br></div></div><div class="prev-message"><div class="prev-message"><div class="line"><span>foofoobar</span><br></div></div></div><div class="line empty-line"><span></span><br></div><div class="line"><span>comment</span><br></div><div class="prev-message"><div class="prev-message"><div class="line"><span>barbar</span><br></div></div></div></div>';
var html = scope.renderNodes(nodes);
expect(html).to.equal(expectedHtml);
});
});
});

View File

@ -1,225 +1,221 @@
define(function(require) {
'use strict';
'use strict';
var RestDAO = require('js/dao/rest-dao'),
expect = chai.expect;
var RestDAO = require('../../src/js/dao/rest-dao');
describe('Rest DAO unit tests', function() {
describe('Rest DAO unit tests', function() {
var restDao, xhrMock, requests;
var restDao, xhrMock, requests;
beforeEach(function() {
beforeEach(function() {
restDao = new RestDAO();
xhrMock = sinon.useFakeXMLHttpRequest();
requests = [];
xhrMock.onCreate = function(xhr) {
requests.push(xhr);
};
});
afterEach(function() {
xhrMock.restore();
});
describe('contructor', function() {
it('should set default base uri', function() {
restDao = new RestDAO();
xhrMock = sinon.useFakeXMLHttpRequest();
requests = [];
xhrMock.onCreate = function(xhr) {
requests.push(xhr);
};
expect(restDao).to.exist;
expect(restDao._baseUri).to.exist;
});
afterEach(function() {
xhrMock.restore();
});
it('should accept default base uri', function() {
var baseUri = 'http://custom.com';
describe('contructor', function() {
it('should set default base uri', function() {
restDao = new RestDAO();
expect(restDao).to.exist;
expect(restDao._baseUri).to.exist;
restDao = new RestDAO(baseUri);
expect(restDao).to.exist;
expect(restDao._baseUri).to.equal(baseUri);
});
});
describe('get', function() {
it('should work with json as default type', function() {
restDao.get({
uri: '/asdf'
}, function(err, data, status) {
expect(err).to.not.exist;
expect(data.foo).to.equal('bar');
var req = requests[0];
expect(req.requestHeaders.Accept).to.equal('application/json');
expect(status).to.equal(200);
});
it('should accept default base uri', function() {
var baseUri = 'http://custom.com';
expect(requests.length).to.equal(1);
requests[0].respond(200, {
"Content-Type": "application/json"
}, '{"foo": "bar"}');
});
restDao = new RestDAO(baseUri);
expect(restDao).to.exist;
expect(restDao._baseUri).to.equal(baseUri);
it('should work with jsonz', function() {
restDao.get({
uri: '/asdf',
type: 'json'
}, function(err, data, status) {
expect(err).to.not.exist;
expect(data.foo).to.equal('bar');
var req = requests[0];
expect(req.requestHeaders.Accept).to.equal('application/json');
expect(status).to.equal(200);
});
expect(requests.length).to.equal(1);
requests[0].respond(200, {
"Content-Type": "application/json"
}, '{"foo": "bar"}');
});
it('should work with plain text', function() {
restDao.get({
uri: '/asdf',
type: 'text'
}, function(err, data, status) {
expect(err).to.not.exist;
expect(data).to.equal('foobar!');
var req = requests[0];
expect(req.requestHeaders.Accept).to.equal('text/plain');
expect(status).to.equal(200);
});
expect(requests.length).to.equal(1);
requests[0].respond(200, {
"Content-Type": "text/plain"
}, 'foobar!');
});
it('should work with xml', function() {
restDao.get({
uri: '/asdf',
type: 'xml'
}, function(err, data, status) {
expect(err).to.not.exist;
expect(data).to.equal('<foo>bar</foo>');
var req = requests[0];
expect(req.requestHeaders.Accept).to.equal('application/xml');
expect(status).to.equal(200);
});
expect(requests.length).to.equal(1);
requests[0].respond(200, {
"Content-Type": "application/xml"
}, '<foo>bar</foo>');
});
it('should fail for missing uri parameter', function() {
restDao.get({}, function(err, data) {
expect(err).to.exist;
expect(err.code).to.equal(400);
expect(data).to.not.exist;
});
});
describe('get', function() {
it('should work with json as default type', function() {
restDao.get({
uri: '/asdf'
}, function(err, data, status) {
expect(err).to.not.exist;
expect(data.foo).to.equal('bar');
var req = requests[0];
expect(req.requestHeaders.Accept).to.equal('application/json');
expect(status).to.equal(200);
});
expect(requests.length).to.equal(1);
requests[0].respond(200, {
"Content-Type": "application/json"
}, '{"foo": "bar"}');
});
it('should work with jsonz', function() {
restDao.get({
uri: '/asdf',
type: 'json'
}, function(err, data, status) {
expect(err).to.not.exist;
expect(data.foo).to.equal('bar');
var req = requests[0];
expect(req.requestHeaders.Accept).to.equal('application/json');
expect(status).to.equal(200);
});
expect(requests.length).to.equal(1);
requests[0].respond(200, {
"Content-Type": "application/json"
}, '{"foo": "bar"}');
});
it('should work with plain text', function() {
restDao.get({
uri: '/asdf',
type: 'text'
}, function(err, data, status) {
expect(err).to.not.exist;
expect(data).to.equal('foobar!');
var req = requests[0];
expect(req.requestHeaders.Accept).to.equal('text/plain');
expect(status).to.equal(200);
});
expect(requests.length).to.equal(1);
requests[0].respond(200, {
"Content-Type": "text/plain"
}, 'foobar!');
});
it('should work with xml', function() {
restDao.get({
uri: '/asdf',
type: 'xml'
}, function(err, data, status) {
expect(err).to.not.exist;
expect(data).to.equal('<foo>bar</foo>');
var req = requests[0];
expect(req.requestHeaders.Accept).to.equal('application/xml');
expect(status).to.equal(200);
});
expect(requests.length).to.equal(1);
requests[0].respond(200, {
"Content-Type": "application/xml"
}, '<foo>bar</foo>');
});
it('should fail for missing uri parameter', function() {
restDao.get({}, function(err, data) {
expect(err).to.exist;
expect(err.code).to.equal(400);
expect(data).to.not.exist;
});
});
it('should fail for unhandled data type', function() {
restDao.get({
uri: '/asdf',
type: 'snafu'
}, function(err, data) {
expect(err).to.exist;
expect(err.code).to.equal(400);
expect(data).to.not.exist;
});
});
it('should fail for server error', function() {
restDao.get({
uri: '/asdf'
}, function(err, data) {
expect(err).to.exist;
expect(err.code).to.equal(500);
expect(data).to.not.exist;
});
expect(requests.length).to.equal(1);
requests[0].respond(500, {
"Content-Type": "text/plain"
}, 'Internal error');
it('should fail for unhandled data type', function() {
restDao.get({
uri: '/asdf',
type: 'snafu'
}, function(err, data) {
expect(err).to.exist;
expect(err.code).to.equal(400);
expect(data).to.not.exist;
});
});
describe('post', function() {
it('should fail', function() {
restDao.post('/asdf', {}, function(err) {
expect(err).to.exist;
expect(err.code).to.equal(500);
});
expect(requests.length).to.equal(1);
requests[0].respond(500, {
"Content-Type": "text/plain"
}, 'Internal error');
it('should fail for server error', function() {
restDao.get({
uri: '/asdf'
}, function(err, data) {
expect(err).to.exist;
expect(err.code).to.equal(500);
expect(data).to.not.exist;
});
it('should work', function() {
restDao.post('/asdf', {}, function(err, res, status) {
expect(err).to.not.exist;
expect(res).to.equal('');
expect(status).to.equal(201);
});
expect(requests.length).to.equal(1);
requests[0].respond(500, {
"Content-Type": "text/plain"
}, 'Internal error');
});
});
expect(requests.length).to.equal(1);
requests[0].respond(201);
describe('post', function() {
it('should fail', function() {
restDao.post('/asdf', {}, function(err) {
expect(err).to.exist;
expect(err.code).to.equal(500);
});
expect(requests.length).to.equal(1);
requests[0].respond(500, {
"Content-Type": "text/plain"
}, 'Internal error');
});
describe('put', function() {
it('should fail', function() {
restDao.put('/asdf', {}, function(err) {
expect(err).to.exist;
expect(err.code).to.equal(500);
});
expect(requests.length).to.equal(1);
requests[0].respond(500, {
"Content-Type": "text/plain"
}, 'Internal error');
it('should work', function() {
restDao.post('/asdf', {}, function(err, res, status) {
expect(err).to.not.exist;
expect(res).to.equal('');
expect(status).to.equal(201);
});
it('should work', function() {
restDao.put('/asdf', {}, function(err, res, status) {
expect(err).to.not.exist;
expect(res).to.equal('');
expect(status).to.equal(201);
});
expect(requests.length).to.equal(1);
requests[0].respond(201);
});
});
expect(requests.length).to.equal(1);
requests[0].respond(201);
describe('put', function() {
it('should fail', function() {
restDao.put('/asdf', {}, function(err) {
expect(err).to.exist;
expect(err.code).to.equal(500);
});
expect(requests.length).to.equal(1);
requests[0].respond(500, {
"Content-Type": "text/plain"
}, 'Internal error');
});
describe('remove', function() {
it('should fail', function() {
restDao.remove('/asdf', function(err) {
expect(err).to.exist;
expect(err.code).to.equal(500);
});
expect(requests.length).to.equal(1);
requests[0].respond(500, {
"Content-Type": "text/plain"
}, 'Internal error');
it('should work', function() {
restDao.put('/asdf', {}, function(err, res, status) {
expect(err).to.not.exist;
expect(res).to.equal('');
expect(status).to.equal(201);
});
it('should work', function() {
restDao.remove('/asdf', function(err, res, status) {
expect(err).to.not.exist;
expect(res).to.equal('');
expect(status).to.equal(200);
});
expect(requests.length).to.equal(1);
requests[0].respond(201);
});
});
expect(requests.length).to.equal(1);
requests[0].respond(200);
describe('remove', function() {
it('should fail', function() {
restDao.remove('/asdf', function(err) {
expect(err).to.exist;
expect(err.code).to.equal(500);
});
expect(requests.length).to.equal(1);
requests[0].respond(500, {
"Content-Type": "text/plain"
}, 'Internal error');
});
it('should work', function() {
restDao.remove('/asdf', function(err, res, status) {
expect(err).to.not.exist;
expect(res).to.equal('');
expect(status).to.equal(200);
});
expect(requests.length).to.equal(1);
requests[0].respond(200);
});
});
});

View File

@ -1,126 +1,122 @@
define(function(require) {
'use strict';
'use strict';
var expect = chai.expect,
angular = require('angular'),
mocks = require('angularMocks'),
SetPassphraseCtrl = require('js/controller/set-passphrase'),
PGP = require('js/crypto/pgp'),
appController = require('js/app-controller'),
KeychainDAO = require('js/dao/keychain-dao');
var mocks = angular.mocks,
SetPassphraseCtrl = require('../../src/js/controller/set-passphrase'),
PGP = require('../../src/js/crypto/pgp'),
appController = require('../../src/js/app-controller'),
KeychainDAO = require('../../src/js/dao/keychain-dao');
describe('Set Passphrase Controller unit test', function() {
var scope, setPassphraseCtrl,
dummyFingerprint, expectedFingerprint,
dummyKeyId, expectedKeyId,
emailAddress, keySize, cryptoMock, keychainMock;
describe('Set Passphrase Controller unit test', function() {
var scope, setPassphraseCtrl,
dummyFingerprint, expectedFingerprint,
dummyKeyId, expectedKeyId,
emailAddress, keySize, cryptoMock, keychainMock;
beforeEach(function() {
appController._pgp = cryptoMock = sinon.createStubInstance(PGP);
appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO);
beforeEach(function() {
appController._pgp = cryptoMock = sinon.createStubInstance(PGP);
appController._keychain = keychainMock = sinon.createStubInstance(KeychainDAO);
dummyFingerprint = '3A2D39B4E1404190B8B949DE7D7E99036E712926';
expectedFingerprint = '3A2D 39B4 E140 4190 B8B9 49DE 7D7E 9903 6E71 2926';
dummyKeyId = '9FEB47936E712926';
expectedKeyId = '6E712926';
cryptoMock.getFingerprint.returns(dummyFingerprint);
cryptoMock.getKeyId.returns(dummyKeyId);
emailAddress = 'fred@foo.com';
keySize = 1234;
dummyFingerprint = '3A2D39B4E1404190B8B949DE7D7E99036E712926';
expectedFingerprint = '3A2D 39B4 E140 4190 B8B9 49DE 7D7E 9903 6E71 2926';
dummyKeyId = '9FEB47936E712926';
expectedKeyId = '6E712926';
cryptoMock.getFingerprint.returns(dummyFingerprint);
cryptoMock.getKeyId.returns(dummyKeyId);
emailAddress = 'fred@foo.com';
keySize = 1234;
cryptoMock.getKeyParams.returns({
cryptoMock.getKeyParams.returns({
_id: dummyKeyId,
fingerprint: dummyFingerprint,
userId: emailAddress,
userIds: [],
bitSize: keySize
});
angular.module('setpassphrasetest', []);
mocks.module('setpassphrasetest');
mocks.inject(function($rootScope, $controller) {
scope = $rootScope.$new();
scope.state = {};
setPassphraseCtrl = $controller(SetPassphraseCtrl, {
$scope: scope
});
});
});
afterEach(function() {});
describe('setPassphrase', function() {
it('should work', function(done) {
scope.oldPassphrase = 'old';
scope.newPassphrase = 'new';
keychainMock.lookupPrivateKey.withArgs(dummyKeyId).yields(null, {
encryptedKey: 'encrypted'
});
cryptoMock.changePassphrase.withArgs({
privateKeyArmored: 'encrypted',
oldPassphrase: 'old',
newPassphrase: 'new'
}).yields(null, 'newArmoredKey');
keychainMock.saveLocalPrivateKey.withArgs({
_id: dummyKeyId,
fingerprint: dummyFingerprint,
userId: emailAddress,
userIds: [],
bitSize: keySize
});
encryptedKey: 'newArmoredKey'
}).yields();
angular.module('setpassphrasetest', []);
mocks.module('setpassphrasetest');
mocks.inject(function($rootScope, $controller) {
scope = $rootScope.$new();
scope.state = {};
setPassphraseCtrl = $controller(SetPassphraseCtrl, {
$scope: scope
});
});
scope.onError = function(err) {
expect(err.title).to.equal('Success');
done();
};
scope.setPassphrase();
});
afterEach(function() {});
describe('setPassphrase', function() {
it('should work', function(done) {
scope.oldPassphrase = 'old';
scope.newPassphrase = 'new';
keychainMock.lookupPrivateKey.withArgs(dummyKeyId).yields(null, {
encryptedKey: 'encrypted'
});
cryptoMock.changePassphrase.withArgs({
privateKeyArmored: 'encrypted',
oldPassphrase: 'old',
newPassphrase: 'new'
}).yields(null, 'newArmoredKey');
keychainMock.saveLocalPrivateKey.withArgs({
_id: dummyKeyId,
userId: emailAddress,
userIds: [],
encryptedKey: 'newArmoredKey'
}).yields();
scope.onError = function(err) {
expect(err.title).to.equal('Success');
done();
};
scope.setPassphrase();
});
});
describe('check passphrase quality', function() {
it('should be too short', function() {
scope.newPassphrase = '&§DG36';
scope.checkPassphraseQuality();
expect(scope.passphraseMsg).to.equal('Very weak');
expect(scope.passphraseRating).to.equal(0);
});
it('should be very weak', function() {
scope.newPassphrase = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
scope.checkPassphraseQuality();
expect(scope.passphraseMsg).to.equal('Very weak');
expect(scope.passphraseRating).to.equal(0);
});
it('should be weak', function() {
scope.newPassphrase = 'asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf';
scope.checkPassphraseQuality();
expect(scope.passphraseMsg).to.equal('Weak');
expect(scope.passphraseRating).to.equal(1);
});
it('should be good', function() {
scope.newPassphrase = 'asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf5';
scope.checkPassphraseQuality();
expect(scope.passphraseMsg).to.equal('Good');
expect(scope.passphraseRating).to.equal(2);
});
it('should be strong', function() {
scope.newPassphrase = '&§DG36abcd';
scope.checkPassphraseQuality();
expect(scope.passphraseMsg).to.equal('Strong');
expect(scope.passphraseRating).to.equal(3);
});
});
});
describe('check passphrase quality', function() {
it('should be too short', function() {
scope.newPassphrase = '&§DG36';
scope.checkPassphraseQuality();
expect(scope.passphraseMsg).to.equal('Very weak');
expect(scope.passphraseRating).to.equal(0);
});
it('should be very weak', function() {
scope.newPassphrase = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
scope.checkPassphraseQuality();
expect(scope.passphraseMsg).to.equal('Very weak');
expect(scope.passphraseRating).to.equal(0);
});
it('should be weak', function() {
scope.newPassphrase = 'asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf';
scope.checkPassphraseQuality();
expect(scope.passphraseMsg).to.equal('Weak');
expect(scope.passphraseRating).to.equal(1);
});
it('should be good', function() {
scope.newPassphrase = 'asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf5';
scope.checkPassphraseQuality();
expect(scope.passphraseMsg).to.equal('Good');
expect(scope.passphraseRating).to.equal(2);
});
it('should be strong', function() {
scope.newPassphrase = '&§DG36abcd';
scope.checkPassphraseQuality();
expect(scope.passphraseMsg).to.equal('Strong');
expect(scope.passphraseRating).to.equal(3);
});
});
});

View File

@ -1,472 +1,469 @@
define(function(require) {
'use strict';
'use strict';
var DeviceStorageDAO = require('js/dao/devicestorage-dao'),
Auth = require('js/bo/auth'),
cfg = require('js/app-config').config,
UpdateHandler = require('js/util/update/update-handler'),
config = require('js/app-config').config,
expect = chai.expect;
var DeviceStorageDAO = require('../../src/js/dao/devicestorage-dao'),
Auth = require('../../src/js/bo/auth'),
cfg = require('../../src/js/app-config').config,
UpdateHandler = require('../../src/js/util/update/update-handler'),
config = require('../../src/js/app-config').config;
describe('UpdateHandler', function() {
var updateHandler, appConfigStorageStub, authStub, userStorageStub, origDbVersion;
describe('UpdateHandler', function() {
var updateHandler, appConfigStorageStub, authStub, userStorageStub, origDbVersion;
chai.Assertion.includeStack = true;
chai.Assertion.includeStack = true;
beforeEach(function() {
origDbVersion = cfg.dbVersion;
appConfigStorageStub = sinon.createStubInstance(DeviceStorageDAO);
userStorageStub = sinon.createStubInstance(DeviceStorageDAO);
authStub = sinon.createStubInstance(Auth);
updateHandler = new UpdateHandler(appConfigStorageStub, userStorageStub, authStub);
beforeEach(function() {
origDbVersion = cfg.dbVersion;
appConfigStorageStub = sinon.createStubInstance(DeviceStorageDAO);
userStorageStub = sinon.createStubInstance(DeviceStorageDAO);
authStub = sinon.createStubInstance(Auth);
updateHandler = new UpdateHandler(appConfigStorageStub, userStorageStub, authStub);
});
afterEach(function() {
cfg.dbVersion = origDbVersion;
});
describe('#constructor', function() {
it('should create instance', function() {
expect(updateHandler).to.exist;
expect(updateHandler._appConfigStorage).to.equal(appConfigStorageStub);
expect(updateHandler._userStorage).to.equal(userStorageStub);
// the update handler must contain as many db update sripts as there are database versions
expect(updateHandler._updateScripts.length).to.equal(cfg.dbVersion);
});
});
afterEach(function() {
cfg.dbVersion = origDbVersion;
});
describe('#update', function() {
var versionDbType = 'dbVersion';
describe('#constructor', function() {
it('should create instance', function() {
expect(updateHandler).to.exist;
expect(updateHandler._appConfigStorage).to.equal(appConfigStorageStub);
expect(updateHandler._userStorage).to.equal(userStorageStub);
it('should not update when up to date', function(done) {
cfg.dbVersion = 10; // app requires database version 10
appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(null, ['10']); // database version is 10
// the update handler must contain as many db update sripts as there are database versions
expect(updateHandler._updateScripts.length).to.equal(cfg.dbVersion);
updateHandler.update(function(error) {
expect(error).to.not.exist;
expect(appConfigStorageStub.listItems.calledOnce).to.be.true;
done();
});
});
describe('#update', function() {
var versionDbType = 'dbVersion';
describe('dummy updates for v2 to v4', function() {
var updateCounter;
it('should not update when up to date', function(done) {
cfg.dbVersion = 10; // app requires database version 10
appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(null, ['10']); // database version is 10
beforeEach(function() {
updateCounter = 0;
appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(null, ['2']); // database version is 0
});
afterEach(function() {
expect(appConfigStorageStub.listItems.calledOnce).to.be.true;
});
it('should work', function(done) {
cfg.dbVersion = 4; // app requires database version 4
// a simple dummy update to executed that only increments the update counter
function dummyUpdate(options, callback) {
updateCounter++;
callback();
}
// inject the dummy updates instead of live ones
updateHandler._updateScripts = [dummyUpdate, dummyUpdate, dummyUpdate, dummyUpdate];
// execute test
updateHandler.update(function(error) {
expect(error).to.not.exist;
expect(appConfigStorageStub.listItems.calledOnce).to.be.true;
expect(updateCounter).to.equal(2);
done();
});
});
describe('dummy updates for v2 to v4', function() {
var updateCounter;
it('should fail while updating to v3', function(done) {
cfg.dbVersion = 4; // app requires database version 4
beforeEach(function() {
updateCounter = 0;
appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(null, ['2']); // database version is 0
});
function dummyUpdate(options, callback) {
updateCounter++;
callback();
}
afterEach(function() {
expect(appConfigStorageStub.listItems.calledOnce).to.be.true;
});
function failingUpdate(options, callback) {
callback({});
}
// inject the dummy updates instead of live ones
updateHandler._updateScripts = [dummyUpdate, dummyUpdate, failingUpdate, dummyUpdate];
it('should work', function(done) {
cfg.dbVersion = 4; // app requires database version 4
// execute test
updateHandler.update(function(error) {
expect(error).to.exist;
expect(updateCounter).to.equal(0);
// a simple dummy update to executed that only increments the update counter
function dummyUpdate(options, callback) {
updateCounter++;
callback();
}
// inject the dummy updates instead of live ones
updateHandler._updateScripts = [dummyUpdate, dummyUpdate, dummyUpdate, dummyUpdate];
// execute test
updateHandler.update(function(error) {
expect(error).to.not.exist;
expect(updateCounter).to.equal(2);
done();
});
});
it('should fail while updating to v3', function(done) {
cfg.dbVersion = 4; // app requires database version 4
function dummyUpdate(options, callback) {
updateCounter++;
callback();
}
function failingUpdate(options, callback) {
callback({});
}
// inject the dummy updates instead of live ones
updateHandler._updateScripts = [dummyUpdate, dummyUpdate, failingUpdate, dummyUpdate];
// execute test
updateHandler.update(function(error) {
expect(error).to.exist;
expect(updateCounter).to.equal(0);
done();
});
});
});
describe('v0 -> v1', function() {
var emailDbType = 'email_';
beforeEach(function() {
cfg.dbVersion = 1; // app requires database version 1
appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(); // database version is 0
});
afterEach(function() {
// database version is only queried for version checking prior to the update script
// so no need to check this in case-specific tests
expect(appConfigStorageStub.listItems.calledOnce).to.be.true;
});
it('should work', function(done) {
userStorageStub.removeList.withArgs(emailDbType).yieldsAsync();
appConfigStorageStub.storeList.withArgs([1], versionDbType).yieldsAsync();
updateHandler.update(function(error) {
expect(error).to.not.exist;
expect(userStorageStub.removeList.calledOnce).to.be.true;
expect(appConfigStorageStub.storeList.calledOnce).to.be.true;
done();
});
});
it('should fail when persisting database version fails', function(done) {
userStorageStub.removeList.yieldsAsync();
appConfigStorageStub.storeList.yieldsAsync(new Error());
updateHandler.update(function(error) {
expect(error).to.exist;
expect(userStorageStub.removeList.calledOnce).to.be.true;
expect(appConfigStorageStub.storeList.calledOnce).to.be.true;
done();
});
});
it('should fail when wiping emails from database fails', function(done) {
userStorageStub.removeList.yieldsAsync(new Error());
updateHandler.update(function(error) {
expect(error).to.exist;
expect(userStorageStub.removeList.calledOnce).to.be.true;
expect(appConfigStorageStub.storeList.called).to.be.false;
done();
});
done();
});
});
describe('v1 -> v2', function() {
var emailDbType = 'email_';
});
beforeEach(function() {
cfg.dbVersion = 2; // app requires database version 2
appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(null, [1]); // database version is 0
});
describe('v0 -> v1', function() {
var emailDbType = 'email_';
afterEach(function() {
// database version is only queried for version checking prior to the update script
// so no need to check this in case-specific tests
expect(appConfigStorageStub.listItems.calledOnce).to.be.true;
});
beforeEach(function() {
cfg.dbVersion = 1; // app requires database version 1
appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(); // database version is 0
});
it('should work', function(done) {
userStorageStub.removeList.withArgs(emailDbType).yieldsAsync();
appConfigStorageStub.storeList.withArgs([2], versionDbType).yieldsAsync();
afterEach(function() {
// database version is only queried for version checking prior to the update script
// so no need to check this in case-specific tests
expect(appConfigStorageStub.listItems.calledOnce).to.be.true;
});
updateHandler.update(function(error) {
expect(error).to.not.exist;
expect(userStorageStub.removeList.calledOnce).to.be.true;
expect(appConfigStorageStub.storeList.calledOnce).to.be.true;
it('should work', function(done) {
userStorageStub.removeList.withArgs(emailDbType).yieldsAsync();
appConfigStorageStub.storeList.withArgs([1], versionDbType).yieldsAsync();
done();
});
});
updateHandler.update(function(error) {
expect(error).to.not.exist;
expect(userStorageStub.removeList.calledOnce).to.be.true;
expect(appConfigStorageStub.storeList.calledOnce).to.be.true;
it('should fail when persisting database version fails', function(done) {
userStorageStub.removeList.yieldsAsync();
appConfigStorageStub.storeList.yieldsAsync(new Error());
updateHandler.update(function(error) {
expect(error).to.exist;
expect(userStorageStub.removeList.calledOnce).to.be.true;
expect(appConfigStorageStub.storeList.calledOnce).to.be.true;
done();
});
});
it('should fail when wiping emails from database fails', function(done) {
userStorageStub.removeList.yieldsAsync(new Error());
updateHandler.update(function(error) {
expect(error).to.exist;
expect(userStorageStub.removeList.calledOnce).to.be.true;
expect(appConfigStorageStub.storeList.called).to.be.false;
done();
});
done();
});
});
describe('v2 -> v3', function() {
var emailDbType = 'email_';
it('should fail when persisting database version fails', function(done) {
userStorageStub.removeList.yieldsAsync();
appConfigStorageStub.storeList.yieldsAsync(new Error());
beforeEach(function() {
cfg.dbVersion = 3; // app requires database version 2
appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(null, [2]); // database version is 0
});
updateHandler.update(function(error) {
expect(error).to.exist;
expect(userStorageStub.removeList.calledOnce).to.be.true;
expect(appConfigStorageStub.storeList.calledOnce).to.be.true;
afterEach(function() {
// database version is only queried for version checking prior to the update script
// so no need to check this in case-specific tests
expect(appConfigStorageStub.listItems.calledOnce).to.be.true;
});
it('should work', function(done) {
userStorageStub.removeList.withArgs(emailDbType).yieldsAsync();
appConfigStorageStub.storeList.withArgs([3], versionDbType).yieldsAsync();
updateHandler.update(function(error) {
expect(error).to.not.exist;
expect(userStorageStub.removeList.calledOnce).to.be.true;
expect(appConfigStorageStub.storeList.calledOnce).to.be.true;
done();
});
});
it('should fail when persisting database version fails', function(done) {
userStorageStub.removeList.yieldsAsync();
appConfigStorageStub.storeList.yieldsAsync(new Error());
updateHandler.update(function(error) {
expect(error).to.exist;
expect(userStorageStub.removeList.calledOnce).to.be.true;
expect(appConfigStorageStub.storeList.calledOnce).to.be.true;
done();
});
});
it('should fail when wiping emails from database fails', function(done) {
userStorageStub.removeList.yieldsAsync(new Error());
updateHandler.update(function(error) {
expect(error).to.exist;
expect(userStorageStub.removeList.calledOnce).to.be.true;
expect(appConfigStorageStub.storeList.called).to.be.false;
done();
});
});
});
describe('v3 -> v4', function() {
var EMAIL_ADDR_DB_KEY = 'emailaddress';
var USERNAME_DB_KEY = 'username';
var PROVIDER_DB_KEY = 'provider';
var IMAP_DB_KEY = 'imap';
var SMTP_DB_KEY = 'smtp';
var REALNAME_DB_KEY = 'realname';
var emailaddress = 'bla@blubb.io';
var imap = config.gmail.imap,
smtp = config.gmail.smtp;
beforeEach(function() {
cfg.dbVersion = 4; // app requires database version 4
appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(null, [3]); // database version is 3
});
it('should add gmail as mail service provider with email address and no provider present in db', function(done) {
appConfigStorageStub.listItems.withArgs(EMAIL_ADDR_DB_KEY).yieldsAsync(null, [emailaddress]);
appConfigStorageStub.listItems.withArgs(PROVIDER_DB_KEY).yieldsAsync(null, []);
appConfigStorageStub.storeList.withArgs([4], versionDbType).yieldsAsync();
appConfigStorageStub.storeList.withArgs(['gmail'], PROVIDER_DB_KEY).yieldsAsync();
appConfigStorageStub.storeList.withArgs([emailaddress], USERNAME_DB_KEY).yieldsAsync();
appConfigStorageStub.storeList.withArgs([imap], IMAP_DB_KEY).yieldsAsync();
appConfigStorageStub.storeList.withArgs([smtp], SMTP_DB_KEY).yieldsAsync();
appConfigStorageStub.storeList.withArgs([''], REALNAME_DB_KEY).yieldsAsync();
authStub._loadCredentials.yieldsAsync();
updateHandler.update(function(error) {
expect(error).to.not.exist;
expect(appConfigStorageStub.storeList.callCount).to.equal(6);
expect(appConfigStorageStub.listItems.calledThrice).to.be.true;
expect(authStub._loadCredentials.calledOnce).to.be.true;
done();
});
});
it('should not add a provider when no email adress is in db', function(done) {
appConfigStorageStub.listItems.withArgs(EMAIL_ADDR_DB_KEY).yieldsAsync(null, []);
appConfigStorageStub.listItems.withArgs(PROVIDER_DB_KEY).yieldsAsync(null, []);
appConfigStorageStub.storeList.withArgs([4], versionDbType).yieldsAsync();
updateHandler.update(function(error) {
expect(error).to.not.exist;
expect(appConfigStorageStub.storeList.calledOnce).to.be.true;
expect(appConfigStorageStub.listItems.calledThrice).to.be.true;
done();
});
});
it('should fail when appConfigStore write fails', function(done) {
appConfigStorageStub.listItems.yieldsAsync(null, []);
appConfigStorageStub.storeList.yieldsAsync(new Error());
updateHandler.update(function(error) {
expect(error).to.exist;
expect(appConfigStorageStub.listItems.calledThrice).to.be.true;
expect(appConfigStorageStub.storeList.calledOnce).to.be.true;
done();
});
});
it('should fail when appConfigStore read fails', function(done) {
appConfigStorageStub.listItems.withArgs(EMAIL_ADDR_DB_KEY).yieldsAsync(new Error());
appConfigStorageStub.storeList.yieldsAsync(new Error());
updateHandler.update(function(error) {
expect(error).to.exist;
expect(appConfigStorageStub.listItems.calledTwice).to.be.true;
expect(appConfigStorageStub.storeList.called).to.be.false;
done();
});
done();
});
});
describe('v4 -> v5', function() {
var FOLDER_TYPE_INBOX = 'Inbox';
var FOLDER_TYPE_SENT = 'Sent';
var FOLDER_TYPE_DRAFTS = 'Drafts';
var FOLDER_TYPE_TRASH = 'Trash';
it('should fail when wiping emails from database fails', function(done) {
userStorageStub.removeList.yieldsAsync(new Error());
var FOLDER_DB_TYPE = 'folders';
var VERSION_DB_TYPE = 'dbVersion';
updateHandler.update(function(error) {
expect(error).to.exist;
expect(userStorageStub.removeList.calledOnce).to.be.true;
expect(appConfigStorageStub.storeList.called).to.be.false;
var POST_UPDATE_DB_VERSION = 5;
beforeEach(function() {
cfg.dbVersion = 5; // app requires database version 4
appConfigStorageStub.listItems.withArgs(VERSION_DB_TYPE).yieldsAsync(null, [4]); // database version is 4
done();
});
});
});
afterEach(function() {
// database version is only queried for version checking prior to the update script
// so no need to check this in case-specific tests
expect(appConfigStorageStub.listItems.calledOnce).to.be.true;
describe('v1 -> v2', function() {
var emailDbType = 'email_';
beforeEach(function() {
cfg.dbVersion = 2; // app requires database version 2
appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(null, [1]); // database version is 0
});
afterEach(function() {
// database version is only queried for version checking prior to the update script
// so no need to check this in case-specific tests
expect(appConfigStorageStub.listItems.calledOnce).to.be.true;
});
it('should work', function(done) {
userStorageStub.removeList.withArgs(emailDbType).yieldsAsync();
appConfigStorageStub.storeList.withArgs([2], versionDbType).yieldsAsync();
updateHandler.update(function(error) {
expect(error).to.not.exist;
expect(userStorageStub.removeList.calledOnce).to.be.true;
expect(appConfigStorageStub.storeList.calledOnce).to.be.true;
done();
});
});
it('should work', function(done) {
userStorageStub.listItems.withArgs(FOLDER_DB_TYPE).yieldsAsync(null, [
[{
name: 'inbox1',
type: FOLDER_TYPE_INBOX
}, {
name: 'inbox2',
type: FOLDER_TYPE_INBOX
}, {
name: 'sent1',
type: FOLDER_TYPE_SENT
}, {
name: 'sent2',
type: FOLDER_TYPE_SENT
}, {
name: 'drafts1',
type: FOLDER_TYPE_DRAFTS
}, {
name: 'drafts2',
type: FOLDER_TYPE_DRAFTS
}, {
name: 'trash1',
type: FOLDER_TYPE_TRASH
}, {
name: 'trash2',
type: FOLDER_TYPE_TRASH
}]
]);
it('should fail when persisting database version fails', function(done) {
userStorageStub.removeList.yieldsAsync();
appConfigStorageStub.storeList.yieldsAsync(new Error());
userStorageStub.storeList.withArgs([
[{
name: 'inbox1',
type: FOLDER_TYPE_INBOX
}, {
name: 'sent1',
type: FOLDER_TYPE_SENT
}, {
name: 'drafts1',
type: FOLDER_TYPE_DRAFTS
}, {
name: 'trash1',
type: FOLDER_TYPE_TRASH
}]
], FOLDER_DB_TYPE).yieldsAsync();
updateHandler.update(function(error) {
expect(error).to.exist;
expect(userStorageStub.removeList.calledOnce).to.be.true;
expect(appConfigStorageStub.storeList.calledOnce).to.be.true;
appConfigStorageStub.storeList.withArgs([POST_UPDATE_DB_VERSION], VERSION_DB_TYPE).yieldsAsync();
updateHandler.update(function(error) {
expect(error).to.not.exist;
expect(userStorageStub.listItems.calledOnce).to.be.true;
expect(userStorageStub.storeList.calledOnce).to.be.true;
expect(appConfigStorageStub.storeList.calledOnce).to.be.true;
done();
});
done();
});
});
it('should fail when persisting database version fails', function(done) {
userStorageStub.listItems.yieldsAsync(null, []);
userStorageStub.storeList.yieldsAsync();
appConfigStorageStub.storeList.yieldsAsync(new Error());
it('should fail when wiping emails from database fails', function(done) {
userStorageStub.removeList.yieldsAsync(new Error());
updateHandler.update(function(error) {
expect(error).to.exist;
expect(userStorageStub.listItems.calledOnce).to.be.true;
expect(userStorageStub.storeList.calledOnce).to.be.true;
expect(appConfigStorageStub.storeList.calledOnce).to.be.true;
updateHandler.update(function(error) {
expect(error).to.exist;
expect(userStorageStub.removeList.calledOnce).to.be.true;
expect(appConfigStorageStub.storeList.called).to.be.false;
done();
});
done();
});
});
});
it('should fail when persisting folders fails', function(done) {
userStorageStub.listItems.yieldsAsync(null, []);
userStorageStub.storeList.yieldsAsync(new Error());
describe('v2 -> v3', function() {
var emailDbType = 'email_';
updateHandler.update(function(error) {
expect(error).to.exist;
expect(userStorageStub.listItems.calledOnce).to.be.true;
expect(userStorageStub.storeList.calledOnce).to.be.true;
expect(appConfigStorageStub.storeList.called).to.be.false;
beforeEach(function() {
cfg.dbVersion = 3; // app requires database version 2
appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(null, [2]); // database version is 0
});
done();
});
afterEach(function() {
// database version is only queried for version checking prior to the update script
// so no need to check this in case-specific tests
expect(appConfigStorageStub.listItems.calledOnce).to.be.true;
});
it('should work', function(done) {
userStorageStub.removeList.withArgs(emailDbType).yieldsAsync();
appConfigStorageStub.storeList.withArgs([3], versionDbType).yieldsAsync();
updateHandler.update(function(error) {
expect(error).to.not.exist;
expect(userStorageStub.removeList.calledOnce).to.be.true;
expect(appConfigStorageStub.storeList.calledOnce).to.be.true;
done();
});
});
it('should fail when listing folders fails', function(done) {
userStorageStub.listItems.yieldsAsync(new Error());
it('should fail when persisting database version fails', function(done) {
userStorageStub.removeList.yieldsAsync();
appConfigStorageStub.storeList.yieldsAsync(new Error());
updateHandler.update(function(error) {
expect(error).to.exist;
expect(userStorageStub.listItems.calledOnce).to.be.true;
expect(userStorageStub.storeList.called).to.be.false;
expect(appConfigStorageStub.storeList.called).to.be.false;
updateHandler.update(function(error) {
expect(error).to.exist;
expect(userStorageStub.removeList.calledOnce).to.be.true;
expect(appConfigStorageStub.storeList.calledOnce).to.be.true;
done();
});
done();
});
});
it('should fail when wiping emails from database fails', function(done) {
userStorageStub.removeList.yieldsAsync(new Error());
updateHandler.update(function(error) {
expect(error).to.exist;
expect(userStorageStub.removeList.calledOnce).to.be.true;
expect(appConfigStorageStub.storeList.called).to.be.false;
done();
});
});
});
describe('v3 -> v4', function() {
var EMAIL_ADDR_DB_KEY = 'emailaddress';
var USERNAME_DB_KEY = 'username';
var PROVIDER_DB_KEY = 'provider';
var IMAP_DB_KEY = 'imap';
var SMTP_DB_KEY = 'smtp';
var REALNAME_DB_KEY = 'realname';
var emailaddress = 'bla@blubb.io';
var imap = config.gmail.imap,
smtp = config.gmail.smtp;
beforeEach(function() {
cfg.dbVersion = 4; // app requires database version 4
appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(null, [3]); // database version is 3
});
it('should add gmail as mail service provider with email address and no provider present in db', function(done) {
appConfigStorageStub.listItems.withArgs(EMAIL_ADDR_DB_KEY).yieldsAsync(null, [emailaddress]);
appConfigStorageStub.listItems.withArgs(PROVIDER_DB_KEY).yieldsAsync(null, []);
appConfigStorageStub.storeList.withArgs([4], versionDbType).yieldsAsync();
appConfigStorageStub.storeList.withArgs(['gmail'], PROVIDER_DB_KEY).yieldsAsync();
appConfigStorageStub.storeList.withArgs([emailaddress], USERNAME_DB_KEY).yieldsAsync();
appConfigStorageStub.storeList.withArgs([imap], IMAP_DB_KEY).yieldsAsync();
appConfigStorageStub.storeList.withArgs([smtp], SMTP_DB_KEY).yieldsAsync();
appConfigStorageStub.storeList.withArgs([''], REALNAME_DB_KEY).yieldsAsync();
authStub._loadCredentials.yieldsAsync();
updateHandler.update(function(error) {
expect(error).to.not.exist;
expect(appConfigStorageStub.storeList.callCount).to.equal(6);
expect(appConfigStorageStub.listItems.calledThrice).to.be.true;
expect(authStub._loadCredentials.calledOnce).to.be.true;
done();
});
});
it('should not add a provider when no email adress is in db', function(done) {
appConfigStorageStub.listItems.withArgs(EMAIL_ADDR_DB_KEY).yieldsAsync(null, []);
appConfigStorageStub.listItems.withArgs(PROVIDER_DB_KEY).yieldsAsync(null, []);
appConfigStorageStub.storeList.withArgs([4], versionDbType).yieldsAsync();
updateHandler.update(function(error) {
expect(error).to.not.exist;
expect(appConfigStorageStub.storeList.calledOnce).to.be.true;
expect(appConfigStorageStub.listItems.calledThrice).to.be.true;
done();
});
});
it('should fail when appConfigStore write fails', function(done) {
appConfigStorageStub.listItems.yieldsAsync(null, []);
appConfigStorageStub.storeList.yieldsAsync(new Error());
updateHandler.update(function(error) {
expect(error).to.exist;
expect(appConfigStorageStub.listItems.calledThrice).to.be.true;
expect(appConfigStorageStub.storeList.calledOnce).to.be.true;
done();
});
});
it('should fail when appConfigStore read fails', function(done) {
appConfigStorageStub.listItems.withArgs(EMAIL_ADDR_DB_KEY).yieldsAsync(new Error());
appConfigStorageStub.storeList.yieldsAsync(new Error());
updateHandler.update(function(error) {
expect(error).to.exist;
expect(appConfigStorageStub.listItems.calledTwice).to.be.true;
expect(appConfigStorageStub.storeList.called).to.be.false;
done();
});
});
});
describe('v4 -> v5', function() {
var FOLDER_TYPE_INBOX = 'Inbox';
var FOLDER_TYPE_SENT = 'Sent';
var FOLDER_TYPE_DRAFTS = 'Drafts';
var FOLDER_TYPE_TRASH = 'Trash';
var FOLDER_DB_TYPE = 'folders';
var VERSION_DB_TYPE = 'dbVersion';
var POST_UPDATE_DB_VERSION = 5;
beforeEach(function() {
cfg.dbVersion = 5; // app requires database version 4
appConfigStorageStub.listItems.withArgs(VERSION_DB_TYPE).yieldsAsync(null, [4]); // database version is 4
});
afterEach(function() {
// database version is only queried for version checking prior to the update script
// so no need to check this in case-specific tests
expect(appConfigStorageStub.listItems.calledOnce).to.be.true;
});
it('should work', function(done) {
userStorageStub.listItems.withArgs(FOLDER_DB_TYPE).yieldsAsync(null, [
[{
name: 'inbox1',
type: FOLDER_TYPE_INBOX
}, {
name: 'inbox2',
type: FOLDER_TYPE_INBOX
}, {
name: 'sent1',
type: FOLDER_TYPE_SENT
}, {
name: 'sent2',
type: FOLDER_TYPE_SENT
}, {
name: 'drafts1',
type: FOLDER_TYPE_DRAFTS
}, {
name: 'drafts2',
type: FOLDER_TYPE_DRAFTS
}, {
name: 'trash1',
type: FOLDER_TYPE_TRASH
}, {
name: 'trash2',
type: FOLDER_TYPE_TRASH
}]
]);
userStorageStub.storeList.withArgs([
[{
name: 'inbox1',
type: FOLDER_TYPE_INBOX
}, {
name: 'sent1',
type: FOLDER_TYPE_SENT
}, {
name: 'drafts1',
type: FOLDER_TYPE_DRAFTS
}, {
name: 'trash1',
type: FOLDER_TYPE_TRASH
}]
], FOLDER_DB_TYPE).yieldsAsync();
appConfigStorageStub.storeList.withArgs([POST_UPDATE_DB_VERSION], VERSION_DB_TYPE).yieldsAsync();
updateHandler.update(function(error) {
expect(error).to.not.exist;
expect(userStorageStub.listItems.calledOnce).to.be.true;
expect(userStorageStub.storeList.calledOnce).to.be.true;
expect(appConfigStorageStub.storeList.calledOnce).to.be.true;
done();
});
});
it('should fail when persisting database version fails', function(done) {
userStorageStub.listItems.yieldsAsync(null, []);
userStorageStub.storeList.yieldsAsync();
appConfigStorageStub.storeList.yieldsAsync(new Error());
updateHandler.update(function(error) {
expect(error).to.exist;
expect(userStorageStub.listItems.calledOnce).to.be.true;
expect(userStorageStub.storeList.calledOnce).to.be.true;
expect(appConfigStorageStub.storeList.calledOnce).to.be.true;
done();
});
});
it('should fail when persisting folders fails', function(done) {
userStorageStub.listItems.yieldsAsync(null, []);
userStorageStub.storeList.yieldsAsync(new Error());
updateHandler.update(function(error) {
expect(error).to.exist;
expect(userStorageStub.listItems.calledOnce).to.be.true;
expect(userStorageStub.storeList.calledOnce).to.be.true;
expect(appConfigStorageStub.storeList.called).to.be.false;
done();
});
});
it('should fail when listing folders fails', function(done) {
userStorageStub.listItems.yieldsAsync(new Error());
updateHandler.update(function(error) {
expect(error).to.exist;
expect(userStorageStub.listItems.calledOnce).to.be.true;
expect(userStorageStub.storeList.called).to.be.false;
expect(appConfigStorageStub.storeList.called).to.be.false;
done();
});
});
});

View File

@ -1,401 +1,397 @@
define(function(require) {
'use strict';
'use strict';
var expect = chai.expect,
angular = require('angular'),
mocks = require('angularMocks'),
WriteCtrl = require('js/controller/write'),
EmailDAO = require('js/dao/email-dao'),
OutboxBO = require('js/bo/outbox'),
KeychainDAO = require('js/dao/keychain-dao'),
appController = require('js/app-controller');
var mocks = angular.mocks,
WriteCtrl = require('../../src/js/controller/write'),
EmailDAO = require('../../src/js/dao/email-dao'),
OutboxBO = require('../../src/js/bo/outbox'),
KeychainDAO = require('../../src/js/dao/keychain-dao'),
appController = require('../../src/js/app-controller');
describe('Write controller unit test', function() {
var ctrl, scope,
origEmailDao, origOutbox, origKeychain,
emailDaoMock, keychainMock, outboxMock, emailAddress, realname;
describe('Write controller unit test', function() {
var ctrl, scope,
origEmailDao, origOutbox, origKeychain,
emailDaoMock, keychainMock, outboxMock, emailAddress, realname;
beforeEach(function() {
// the app controller is a singleton, we need to remember the
// outbox and email dao to restore it after the tests
origEmailDao = appController._emailDao;
origOutbox = appController._outboxBo;
origKeychain = appController._keychain;
beforeEach(function() {
// the app controller is a singleton, we need to remember the
// outbox and email dao to restore it after the tests
origEmailDao = appController._emailDao;
origOutbox = appController._outboxBo;
origKeychain = appController._keychain;
outboxMock = sinon.createStubInstance(OutboxBO);
appController._outboxBo = outboxMock;
outboxMock = sinon.createStubInstance(OutboxBO);
appController._outboxBo = outboxMock;
emailDaoMock = sinon.createStubInstance(EmailDAO);
appController._emailDao = emailDaoMock;
emailDaoMock = sinon.createStubInstance(EmailDAO);
appController._emailDao = emailDaoMock;
emailAddress = 'fred@foo.com';
realname = 'Fred Foo';
emailDaoMock._account = {
emailAddress: emailAddress,
realname: realname
};
emailAddress = 'fred@foo.com';
realname = 'Fred Foo';
emailDaoMock._account = {
emailAddress: emailAddress,
realname: realname
};
keychainMock = sinon.createStubInstance(KeychainDAO);
appController._keychain = keychainMock;
keychainMock = sinon.createStubInstance(KeychainDAO);
appController._keychain = keychainMock;
angular.module('writetest', []);
mocks.module('writetest');
mocks.inject(function($rootScope, $controller) {
scope = $rootScope.$new();
scope.state = {};
ctrl = $controller(WriteCtrl, {
$scope: scope
});
angular.module('writetest', []);
mocks.module('writetest');
mocks.inject(function($rootScope, $controller) {
scope = $rootScope.$new();
scope.state = {};
ctrl = $controller(WriteCtrl, {
$scope: scope
});
});
});
afterEach(function() {
// restore the app controller
appController._emailDao = origEmailDao;
appController._outboxBo = origOutbox;
appController._keychain = origKeychain;
afterEach(function() {
// restore the app controller
appController._emailDao = origEmailDao;
appController._outboxBo = origOutbox;
appController._keychain = origKeychain;
});
describe('scope variables', function() {
it('should be set correctly', function() {
expect(scope.state.writer).to.exist;
expect(scope.state.lightbox).to.be.undefined;
expect(scope.state.writer.write).to.exist;
expect(scope.state.writer.close).to.exist;
expect(scope.verify).to.exist;
expect(scope.checkSendStatus).to.exist;
expect(scope.sendToOutbox).to.exist;
expect(scope.tagStyle).to.exist;
expect(scope.lookupAddressBook).to.exist;
});
});
describe('close', function() {
it('should close the writer', function() {
scope.state.lightbox = 'write';
scope.state.writer.close();
expect(scope.state.lightbox).to.be.undefined;
});
});
describe('write', function() {
it('should prepare write view', function() {
var verifyMock = sinon.stub(scope, 'verify');
scope.state.writer.write();
expect(scope.writerTitle).to.equal('New email');
expect(scope.to).to.deep.equal([]);
expect(scope.subject).to.equal('');
expect(scope.body).to.equal('');
expect(verifyMock.calledOnce).to.be.true;
scope.verify.restore();
});
describe('scope variables', function() {
it('should be set correctly', function() {
expect(scope.state.writer).to.exist;
expect(scope.state.lightbox).to.be.undefined;
expect(scope.state.writer.write).to.exist;
expect(scope.state.writer.close).to.exist;
expect(scope.verify).to.exist;
expect(scope.checkSendStatus).to.exist;
expect(scope.sendToOutbox).to.exist;
expect(scope.tagStyle).to.exist;
expect(scope.lookupAddressBook).to.exist;
});
it('should prefill write view for response', function() {
var verifyMock = sinon.stub(scope, 'verify'),
address = 'pity@dafool',
subject = 'Ermahgerd!',
body = 'so much body!',
re = {
id: 'abc',
from: [{
address: address
}],
subject: subject,
sentDate: new Date(),
body: body,
references: ['ghi', 'def']
};
scope.sendBtnSecure = true;
scope.state.writer.write(re);
expect(scope.writerTitle).to.equal('Reply');
expect(scope.to).to.deep.equal([{
address: address,
}]);
expect(scope.subject).to.equal('Re: ' + subject);
expect(scope.body).to.contain(body);
expect(scope.references).to.deep.equal(['ghi', 'def', 'abc']);
expect(verifyMock.called).to.be.true;
scope.verify.restore();
});
describe('close', function() {
it('should close the writer', function() {
scope.state.lightbox = 'write';
scope.state.writer.close();
expect(scope.state.lightbox).to.be.undefined;
});
});
describe('write', function() {
it('should prepare write view', function() {
var verifyMock = sinon.stub(scope, 'verify');
scope.state.writer.write();
expect(scope.writerTitle).to.equal('New email');
expect(scope.to).to.deep.equal([]);
expect(scope.subject).to.equal('');
expect(scope.body).to.equal('');
expect(verifyMock.calledOnce).to.be.true;
scope.verify.restore();
});
it('should prefill write view for response', function() {
var verifyMock = sinon.stub(scope, 'verify'),
address = 'pity@dafool',
subject = 'Ermahgerd!',
body = 'so much body!',
re = {
id: 'abc',
from: [{
address: address
}],
subject: subject,
sentDate: new Date(),
body: body,
references: ['ghi', 'def']
};
scope.sendBtnSecure = true;
scope.state.writer.write(re);
expect(scope.writerTitle).to.equal('Reply');
expect(scope.to).to.deep.equal([{
address: address,
}]);
expect(scope.subject).to.equal('Re: ' + subject);
expect(scope.body).to.contain(body);
expect(scope.references).to.deep.equal(['ghi', 'def', 'abc']);
expect(verifyMock.called).to.be.true;
scope.verify.restore();
});
it('should prefill write view for forward', function() {
var verifyMock = sinon.stub(scope, 'verify'),
address = 'pity@dafool',
subject = 'Ermahgerd!',
body = 'so much body!',
re = {
from: [{
address: address
}],
to: [{
address: address
}],
subject: subject,
sentDate: new Date(),
body: body,
attachments: [{}]
};
scope.sendBtnSecure = false;
scope.state.writer.write(re, null, true);
expect(scope.writerTitle).to.equal('Forward');
expect(scope.to).to.deep.equal([]);
expect(scope.subject).to.equal('Fwd: ' + subject);
expect(scope.body).to.contain(body);
expect(verifyMock.called).to.be.true;
expect(scope.attachments).to.not.equal(re.attachments); // not the same reference
expect(scope.attachments).to.deep.equal(re.attachments); // but the same content
scope.verify.restore();
});
});
describe('verify', function() {
var checkSendStatusMock;
beforeEach(function() {
checkSendStatusMock = sinon.stub(scope, 'checkSendStatus');
});
afterEach(function() {
scope.checkSendStatus.restore();
});
it('should do nothing if recipient is not provided', function() {
scope.verify(undefined);
});
it('should not work for invalid email addresses', function() {
var recipient = {
address: ''
it('should prefill write view for forward', function() {
var verifyMock = sinon.stub(scope, 'verify'),
address = 'pity@dafool',
subject = 'Ermahgerd!',
body = 'so much body!',
re = {
from: [{
address: address
}],
to: [{
address: address
}],
subject: subject,
sentDate: new Date(),
body: body,
attachments: [{}]
};
scope.verify(recipient);
scope.sendBtnSecure = false;
expect(recipient.key).to.be.undefined;
expect(recipient.secure).to.be.undefined;
expect(scope.checkSendStatus.callCount).to.equal(2);
expect(keychainMock.getReceiverPublicKey.called).to.be.false;
});
scope.state.writer.write(re, null, true);
it('should not work for error in keychain', function(done) {
var recipient = {
address: 'asds@example.com'
};
expect(scope.writerTitle).to.equal('Forward');
expect(scope.to).to.deep.equal([]);
expect(scope.subject).to.equal('Fwd: ' + subject);
expect(scope.body).to.contain(body);
expect(verifyMock.called).to.be.true;
expect(scope.attachments).to.not.equal(re.attachments); // not the same reference
expect(scope.attachments).to.deep.equal(re.attachments); // but the same content
keychainMock.refreshKeyForUserId.withArgs(recipient.address).yields({
errMsg: '404 not found yadda yadda'
});
scope.onError = function() {
expect(recipient.key).to.be.undefined;
expect(recipient.secure).to.be.false;
expect(scope.checkSendStatus.callCount).to.equal(1);
expect(keychainMock.refreshKeyForUserId.calledOnce).to.be.true;
done();
};
scope.verify(recipient);
});
it('should work for main userId', function(done) {
var recipient = {
address: 'asdf@example.com'
};
keychainMock.refreshKeyForUserId.withArgs(recipient.address).yields(null, {
userId: 'asdf@example.com'
});
scope.$digest = function() {
expect(recipient.key).to.deep.equal({
userId: 'asdf@example.com'
});
expect(recipient.secure).to.be.true;
expect(scope.checkSendStatus.callCount).to.equal(2);
expect(keychainMock.refreshKeyForUserId.calledOnce).to.be.true;
done();
};
scope.verify(recipient);
});
it('should work for secondary userId', function(done) {
var recipient = {
address: 'asdf@example.com'
};
var key = {
userId: 'qwer@example.com',
userIds: [{
emailAddress: 'asdf@example.com'
}]
};
keychainMock.refreshKeyForUserId.withArgs(recipient.address).yields(null, key);
scope.$digest = function() {
expect(recipient.key).to.deep.equal(key);
expect(recipient.secure).to.be.true;
expect(scope.checkSendStatus.callCount).to.equal(2);
expect(keychainMock.refreshKeyForUserId.calledOnce).to.be.true;
done();
};
scope.verify(recipient);
});
});
describe('checkSendStatus', function() {
beforeEach(function() {
scope.state.writer.write();
});
afterEach(function() {});
it('should not be able to send with no recipients', function() {
scope.checkSendStatus();
expect(scope.okToSend).to.be.false;
expect(scope.sendBtnText).to.be.undefined;
expect(scope.sendBtnSecure).to.be.undefined;
});
it('should be able to send plaintext', function() {
scope.to = [{
address: 'asdf@asdf.de'
}];
scope.checkSendStatus();
expect(scope.okToSend).to.be.true;
expect(scope.sendBtnText).to.equal('Send');
expect(scope.sendBtnSecure).to.be.false;
});
it('should send plaintext if one receiver is not secure', function() {
scope.to = [{
address: 'asdf@asdf.de',
secure: true
}, {
address: 'asdf@asdfg.de'
}];
scope.checkSendStatus();
expect(scope.okToSend).to.be.true;
expect(scope.sendBtnText).to.equal('Send');
expect(scope.sendBtnSecure).to.be.false;
});
it('should be able to send securely to multiple recipients', function() {
scope.to = [{
address: 'asdf@asdf.de',
secure: true
}, {
address: 'asdf@asdfg.de',
secure: true
}];
scope.checkSendStatus();
expect(scope.okToSend).to.be.true;
expect(scope.sendBtnText).to.equal('Send securely');
expect(scope.sendBtnSecure).to.be.true;
});
});
describe('send to outbox', function() {
it('should work', function() {
scope.to = [{
address: 'pity@dafool'
}];
scope.cc = [];
scope.bcc = [];
scope.subject = 'Ermahgerd!';
scope.body = 'wow. much body! very text!';
scope.attachments = [];
scope.state.nav = {
currentFolder: 'currentFolder'
};
scope.replyTo = {};
outboxMock.put.withArgs(sinon.match(function(mail) {
expect(mail.from).to.deep.equal([{
address: emailAddress,
name: realname
}]);
expect(mail.to).to.deep.equal(scope.to);
expect(mail.cc).to.deep.equal(scope.cc);
expect(mail.bcc).to.deep.equal(scope.bcc);
expect(mail.body).to.contain(scope.body);
expect(mail.subject).to.equal(scope.subject);
expect(mail.attachments).to.be.empty;
expect(mail.sentDate).to.exist;
return true;
})).yields();
emailDaoMock.setFlags.yields();
scope.onError = function(err) {
expect(err).to.not.exist;
};
scope.sendToOutbox();
expect(outboxMock.put.calledOnce).to.be.true;
expect(emailDaoMock.setFlags.calledOnce).to.be.true;
expect(scope.state.lightbox).to.be.undefined;
expect(scope.replyTo.answered).to.be.true;
});
});
describe('lookupAddressBook', function() {
it('should work', function(done) {
keychainMock.listLocalPublicKeys.yields(null, [{
userId: 'test@asdf.com',
publicKey: 'KEY'
}]);
var result = scope.lookupAddressBook('test');
result.then(function(response) {
expect(response).to.deep.equal([{
address: 'test@asdf.com'
}]);
done();
});
scope.$digest();
});
it('should work with cache', function(done) {
scope.addressBookCache = [{
address: 'test@asdf.com'
}, {
address: 'tes@asdf.com'
}];
var result = scope.lookupAddressBook('test');
result.then(function(response) {
expect(response).to.deep.equal([{
address: 'test@asdf.com'
}]);
done();
});
scope.$digest();
});
scope.verify.restore();
});
});
describe('verify', function() {
var checkSendStatusMock;
beforeEach(function() {
checkSendStatusMock = sinon.stub(scope, 'checkSendStatus');
});
afterEach(function() {
scope.checkSendStatus.restore();
});
it('should do nothing if recipient is not provided', function() {
scope.verify(undefined);
});
it('should not work for invalid email addresses', function() {
var recipient = {
address: ''
};
scope.verify(recipient);
expect(recipient.key).to.be.undefined;
expect(recipient.secure).to.be.undefined;
expect(scope.checkSendStatus.callCount).to.equal(2);
expect(keychainMock.getReceiverPublicKey.called).to.be.false;
});
it('should not work for error in keychain', function(done) {
var recipient = {
address: 'asds@example.com'
};
keychainMock.refreshKeyForUserId.withArgs(recipient.address).yields({
errMsg: '404 not found yadda yadda'
});
scope.onError = function() {
expect(recipient.key).to.be.undefined;
expect(recipient.secure).to.be.false;
expect(scope.checkSendStatus.callCount).to.equal(1);
expect(keychainMock.refreshKeyForUserId.calledOnce).to.be.true;
done();
};
scope.verify(recipient);
});
it('should work for main userId', function(done) {
var recipient = {
address: 'asdf@example.com'
};
keychainMock.refreshKeyForUserId.withArgs(recipient.address).yields(null, {
userId: 'asdf@example.com'
});
scope.$digest = function() {
expect(recipient.key).to.deep.equal({
userId: 'asdf@example.com'
});
expect(recipient.secure).to.be.true;
expect(scope.checkSendStatus.callCount).to.equal(2);
expect(keychainMock.refreshKeyForUserId.calledOnce).to.be.true;
done();
};
scope.verify(recipient);
});
it('should work for secondary userId', function(done) {
var recipient = {
address: 'asdf@example.com'
};
var key = {
userId: 'qwer@example.com',
userIds: [{
emailAddress: 'asdf@example.com'
}]
};
keychainMock.refreshKeyForUserId.withArgs(recipient.address).yields(null, key);
scope.$digest = function() {
expect(recipient.key).to.deep.equal(key);
expect(recipient.secure).to.be.true;
expect(scope.checkSendStatus.callCount).to.equal(2);
expect(keychainMock.refreshKeyForUserId.calledOnce).to.be.true;
done();
};
scope.verify(recipient);
});
});
describe('checkSendStatus', function() {
beforeEach(function() {
scope.state.writer.write();
});
afterEach(function() {});
it('should not be able to send with no recipients', function() {
scope.checkSendStatus();
expect(scope.okToSend).to.be.false;
expect(scope.sendBtnText).to.be.undefined;
expect(scope.sendBtnSecure).to.be.undefined;
});
it('should be able to send plaintext', function() {
scope.to = [{
address: 'asdf@asdf.de'
}];
scope.checkSendStatus();
expect(scope.okToSend).to.be.true;
expect(scope.sendBtnText).to.equal('Send');
expect(scope.sendBtnSecure).to.be.false;
});
it('should send plaintext if one receiver is not secure', function() {
scope.to = [{
address: 'asdf@asdf.de',
secure: true
}, {
address: 'asdf@asdfg.de'
}];
scope.checkSendStatus();
expect(scope.okToSend).to.be.true;
expect(scope.sendBtnText).to.equal('Send');
expect(scope.sendBtnSecure).to.be.false;
});
it('should be able to send securely to multiple recipients', function() {
scope.to = [{
address: 'asdf@asdf.de',
secure: true
}, {
address: 'asdf@asdfg.de',
secure: true
}];
scope.checkSendStatus();
expect(scope.okToSend).to.be.true;
expect(scope.sendBtnText).to.equal('Send securely');
expect(scope.sendBtnSecure).to.be.true;
});
});
describe('send to outbox', function() {
it('should work', function() {
scope.to = [{
address: 'pity@dafool'
}];
scope.cc = [];
scope.bcc = [];
scope.subject = 'Ermahgerd!';
scope.body = 'wow. much body! very text!';
scope.attachments = [];
scope.state.nav = {
currentFolder: 'currentFolder'
};
scope.replyTo = {};
outboxMock.put.withArgs(sinon.match(function(mail) {
expect(mail.from).to.deep.equal([{
address: emailAddress,
name: realname
}]);
expect(mail.to).to.deep.equal(scope.to);
expect(mail.cc).to.deep.equal(scope.cc);
expect(mail.bcc).to.deep.equal(scope.bcc);
expect(mail.body).to.contain(scope.body);
expect(mail.subject).to.equal(scope.subject);
expect(mail.attachments).to.be.empty;
expect(mail.sentDate).to.exist;
return true;
})).yields();
emailDaoMock.setFlags.yields();
scope.onError = function(err) {
expect(err).to.not.exist;
};
scope.sendToOutbox();
expect(outboxMock.put.calledOnce).to.be.true;
expect(emailDaoMock.setFlags.calledOnce).to.be.true;
expect(scope.state.lightbox).to.be.undefined;
expect(scope.replyTo.answered).to.be.true;
});
});
describe('lookupAddressBook', function() {
it('should work', function(done) {
keychainMock.listLocalPublicKeys.yields(null, [{
userId: 'test@asdf.com',
publicKey: 'KEY'
}]);
var result = scope.lookupAddressBook('test');
result.then(function(response) {
expect(response).to.deep.equal([{
address: 'test@asdf.com'
}]);
done();
});
scope.$digest();
});
it('should work with cache', function(done) {
scope.addressBookCache = [{
address: 'test@asdf.com'
}, {
address: 'tes@asdf.com'
}];
var result = scope.lookupAddressBook('test');
result.then(function(response) {
expect(response).to.deep.equal([{
address: 'test@asdf.com'
}]);
done();
});
scope.$digest();
});
});
});