aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Lal <james@lightsofapollo.com>2013-05-06 21:18:31 -0700
committerJames Lal <james@lightsofapollo.com>2013-05-06 21:18:31 -0700
commit0b4733ebb28368198b747079d51033a7eeb1f276 (patch)
tree0d48aca900256baf82f0aa599d455a978780fa19
parentc81e925aa6dada192db75dccd4287ab1e9e09ab2 (diff)
downloadjsCalDAV-0b4733ebb28368198b747079d51033a7eeb1f276.tar.gz
Initial error refactoring (make errors less HTTP specific)
-rw-r--r--Makefile2
-rw-r--r--caldav.js147
-rw-r--r--lib/caldav/errors.js40
-rw-r--r--lib/caldav/index.js1
-rw-r--r--lib/caldav/request/abstract.js30
-rw-r--r--lib/caldav/request/calendar_home.js31
-rw-r--r--lib/caldav/request/errors.js49
-rw-r--r--test/caldav/errors_test.js27
-rw-r--r--test/caldav/http/basic_auth_test.js31
-rw-r--r--test/caldav/index_test.js1
-rw-r--r--test/caldav/request/abstract_test.js22
-rw-r--r--test/caldav/request/calendar_home_test.js28
-rw-r--r--test/helper.js4
-rw-r--r--test/support/fake_xhr.js3
14 files changed, 257 insertions, 159 deletions
diff --git a/Makefile b/Makefile
index 15e64d4..32c2b5b 100644
--- a/Makefile
+++ b/Makefile
@@ -17,6 +17,7 @@ package: test-agent-config
echo '/* caldav.js - https://github.com/mozilla-b2g/caldav */' >> $(WEB_FILE)
cat $(LIB_ROOT)/caldav.js >> $(WEB_FILE)
cat $(LIB_ROOT)/responder.js >> $(WEB_FILE)
+ cat $(LIB_ROOT)/errors.js >> $(WEB_FILE)
cat $(LIB_ROOT)/querystring.js >> $(WEB_FILE)
cat $(LIB_ROOT)/sax.js >> $(WEB_FILE)
cat $(LIB_ROOT)/template.js >> $(WEB_FILE)
@@ -29,7 +30,6 @@ package: test-agent-config
cat $(LIB_ROOT)/sax/base.js >> $(WEB_FILE)
cat $(LIB_ROOT)/sax/calendar_data_handler.js >> $(WEB_FILE)
cat $(LIB_ROOT)/sax/dav_response.js >> $(WEB_FILE)
- cat $(LIB_ROOT)/request/errors.js >> $(WEB_FILE)
cat $(LIB_ROOT)/request/abstract.js >> $(WEB_FILE)
cat $(LIB_ROOT)/request/asset.js >> $(WEB_FILE)
cat $(LIB_ROOT)/request/propfind.js >> $(WEB_FILE)
diff --git a/caldav.js b/caldav.js
index dfb2d70..6947e17 100644
--- a/caldav.js
+++ b/caldav.js
@@ -1321,6 +1321,46 @@ function write (chunk) {
[Caldav('responder'), Caldav] :
[module, require('./caldav')]
));
+(function(module, ns) {
+
+ Errors = {};
+
+ /**
+ * Errors typically are for front-end routing purposes so the important
+ * part really is just the name and (maybe) the symbol... These are really
+ * intended to be consumed by name... So once a name has been assigned it
+ * should never be modified.
+ */
+ [
+ { symbol: 'Authentication', name: 'authentication' },
+ { symbol: 'InvalidEntrypoint', name: 'invalid-entrypoint' },
+ { symbol: 'ServerFailure', name: 'server-failure' },
+ { symbol: 'Unknown', name: 'unknown' }
+ ].forEach(function createError(def) {
+ var obj = Errors[def.symbol] = function(message) {
+ this.message = message;
+ this.name = 'caldav-' + def.name;
+
+ try {
+ throw new Error();
+ } catch (e) {
+ this.stack = e.stack;
+ }
+ };
+
+ // just so instanceof Error works
+ obj.prototype = Object.create(Error.prototype);
+ });
+
+ module.exports = Errors;
+
+}.apply(
+ this,
+ (this.Caldav) ?
+ [Caldav('errors'), Caldav] :
+ [module, require('./caldav')]
+));
+
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
@@ -3124,58 +3164,22 @@ function write (chunk) {
));
(function(module, ns) {
- function CaldavHttpError(code) {
- this.code = code;
- var message;
- switch(this.code) {
- case 401:
- message = 'Wrong username or/and password';
- break;
- case 404:
- message = 'Url not found';
- break;
- case 500:
- message = 'Server error';
- break;
- default:
- message = this.code;
- }
- Error.call(this, message);
- }
-
- CaldavHttpError.prototype = {
- __proto__: Error.prototype,
- constructor: CaldavHttpError
- }
-
- // Unauthenticated error for
- // Google Calendar
- function UnauthenticatedError() {
- var message = "Wrong username or/and password";
- Error.call(this, message);
- }
+ var SAX = ns.require('sax');
+ var XHR = ns.require('xhr');
+ var Errors = ns.require('errors');
- UnauthenticatedError.prototype = {
- __proto__: Error.prototype,
- constructor: UnauthenticatedError
- }
+ function determineHttpStatusError(status) {
+ var message = 'Cannot handle request due to server response';
+ var err = 'Unknown';
- module.exports = {
- CaldavHttpError: CaldavHttpError,
- UnauthenticatedError: UnauthenticatedError
- };
+ if (status === 500)
+ err = 'ServerFailure';
-}.apply(
- this,
- (this.Caldav) ?
- [Caldav('request/errors'), Caldav] :
- [module, require('../caldav')]
-));
-(function(module, ns) {
+ if (status === 401)
+ err = 'Authentication';
- var SAX = ns.require('sax');
- var XHR = ns.require('xhr');
- var Errors = ns.require('request/errors');
+ return new Errors[err](message);
+ }
/**
* Creates an (Web/Cal)Dav request.
@@ -3245,14 +3249,19 @@ function write (chunk) {
return callback(err);
}
+ // handle the success case
if (xhr.status > 199 && xhr.status < 300) {
- // success
self.sax.close();
- self._processResult(req, callback);
- } else {
- // fail
- callback(new Errors.CaldavHttpError(xhr.status));
+ return self._processResult(req, callback);
}
+
+ // probable error cases
+ callback(
+ determineHttpStatusError(xhr.status),
+ xhr
+ );
+
+
});
return req;
@@ -3587,8 +3596,8 @@ function write (chunk) {
));
(function(module, ns) {
- var Errors = ns.require('request/errors');
-
+ var RequestErrors = ns.require('errors');
+
/**
* Creates a propfind request.
*
@@ -3659,19 +3668,32 @@ function write (chunk) {
return;
}
- principal = findProperty('current-user-principal', data, true);
+ // some fairly dumb allowances
+ principal =
+ findProperty('current-user-principal', data, true) ||
+ findProperty('principal-URL', data, true);
if (!principal) {
- principal = findProperty('principal-URL', data, true);
+ return callback(new Errors.InvalidEntrypoint(
+ 'both current-user-principal and principal-URL are missing'
+ ));
}
+ // per http://tools.ietf.org/html/rfc6638 we get unauthenticated
if ('unauthenticated' in principal) {
- callback(new Errors.UnauthenticatedError());
- } else if (principal.href) {
- callback(null, principal.href);
- } else {
- callback(new Errors.CaldavHttpError(404));
+ return callback(
+ new Errors.Authentication('caldav response is unauthenticated')
+ );
+ }
+
+ // we might have both principal.href & unauthenticated
+ if (principal.href) {
+ return callback(null, principal.href);
}
+
+ callback(
+ new Errors.InvalidEntrypoint('no useful location information found')
+ );
});
},
@@ -4036,6 +4058,7 @@ function write (chunk) {
exports.Resources = ns.require('resources');
exports.Http = ns.require('http');
exports.OAuth2 = ns.require('oauth2');
+ exports.Errors = ns.require('errors');
}.apply(
this,
diff --git a/lib/caldav/errors.js b/lib/caldav/errors.js
new file mode 100644
index 0000000..1b58a6f
--- /dev/null
+++ b/lib/caldav/errors.js
@@ -0,0 +1,40 @@
+(function(module, ns) {
+
+ Errors = {};
+
+ /**
+ * Errors typically are for front-end routing purposes so the important
+ * part really is just the name and (maybe) the symbol... These are really
+ * intended to be consumed by name... So once a name has been assigned it
+ * should never be modified.
+ */
+ [
+ { symbol: 'Authentication', name: 'authentication' },
+ { symbol: 'InvalidEntrypoint', name: 'invalid-entrypoint' },
+ { symbol: 'ServerFailure', name: 'server-failure' },
+ { symbol: 'Unknown', name: 'unknown' }
+ ].forEach(function createError(def) {
+ var obj = Errors[def.symbol] = function(message) {
+ this.message = message;
+ this.name = 'caldav-' + def.name;
+
+ try {
+ throw new Error();
+ } catch (e) {
+ this.stack = e.stack;
+ }
+ };
+
+ // just so instanceof Error works
+ obj.prototype = Object.create(Error.prototype);
+ });
+
+ module.exports = Errors;
+
+}.apply(
+ this,
+ (this.Caldav) ?
+ [Caldav('errors'), Caldav] :
+ [module, require('./caldav')]
+));
+
diff --git a/lib/caldav/index.js b/lib/caldav/index.js
index 636fc18..3e3dd51 100644
--- a/lib/caldav/index.js
+++ b/lib/caldav/index.js
@@ -12,6 +12,7 @@
exports.Resources = ns.require('resources');
exports.Http = ns.require('http');
exports.OAuth2 = ns.require('oauth2');
+ exports.Errors = ns.require('errors');
}.apply(
this,
diff --git a/lib/caldav/request/abstract.js b/lib/caldav/request/abstract.js
index 4db3883..6f33af4 100644
--- a/lib/caldav/request/abstract.js
+++ b/lib/caldav/request/abstract.js
@@ -2,7 +2,20 @@
var SAX = ns.require('sax');
var XHR = ns.require('xhr');
- var Errors = ns.require('request/errors');
+ var Errors = ns.require('errors');
+
+ function determineHttpStatusError(status) {
+ var message = 'Cannot handle request due to server response';
+ var err = 'Unknown';
+
+ if (status === 500)
+ err = 'ServerFailure';
+
+ if (status === 401)
+ err = 'Authentication';
+
+ return new Errors[err](message);
+ }
/**
* Creates an (Web/Cal)Dav request.
@@ -72,14 +85,19 @@
return callback(err);
}
+ // handle the success case
if (xhr.status > 199 && xhr.status < 300) {
- // success
self.sax.close();
- self._processResult(req, callback);
- } else {
- // fail
- callback(new Errors.CaldavHttpError(xhr.status));
+ return self._processResult(req, callback);
}
+
+ // probable error cases
+ callback(
+ determineHttpStatusError(xhr.status),
+ xhr
+ );
+
+
});
return req;
diff --git a/lib/caldav/request/calendar_home.js b/lib/caldav/request/calendar_home.js
index d0659bb..e7bed35 100644
--- a/lib/caldav/request/calendar_home.js
+++ b/lib/caldav/request/calendar_home.js
@@ -1,7 +1,7 @@
(function(module, ns) {
- var Errors = ns.require('request/errors');
-
+ var RequestErrors = ns.require('errors');
+
/**
* Creates a propfind request.
*
@@ -72,19 +72,32 @@
return;
}
- principal = findProperty('current-user-principal', data, true);
+ // some fairly dumb allowances
+ principal =
+ findProperty('current-user-principal', data, true) ||
+ findProperty('principal-URL', data, true);
if (!principal) {
- principal = findProperty('principal-URL', data, true);
+ return callback(new Errors.InvalidEntrypoint(
+ 'both current-user-principal and principal-URL are missing'
+ ));
}
+ // per http://tools.ietf.org/html/rfc6638 we get unauthenticated
if ('unauthenticated' in principal) {
- callback(new Errors.UnauthenticatedError());
- } else if (principal.href) {
- callback(null, principal.href);
- } else {
- callback(new Errors.CaldavHttpError(404));
+ return callback(
+ new Errors.Authentication('caldav response is unauthenticated')
+ );
+ }
+
+ // we might have both principal.href & unauthenticated
+ if (principal.href) {
+ return callback(null, principal.href);
}
+
+ callback(
+ new Errors.InvalidEntrypoint('no useful location information found')
+ );
});
},
diff --git a/lib/caldav/request/errors.js b/lib/caldav/request/errors.js
deleted file mode 100644
index 700cfba..0000000
--- a/lib/caldav/request/errors.js
+++ /dev/null
@@ -1,49 +0,0 @@
-(function(module, ns) {
-
- function CaldavHttpError(code) {
- this.code = code;
- var message;
- switch(this.code) {
- case 401:
- message = 'Wrong username or/and password';
- break;
- case 404:
- message = 'Url not found';
- break;
- case 500:
- message = 'Server error';
- break;
- default:
- message = this.code;
- }
- Error.call(this, message);
- }
-
- CaldavHttpError.prototype = {
- __proto__: Error.prototype,
- constructor: CaldavHttpError
- }
-
- // Unauthenticated error for
- // Google Calendar
- function UnauthenticatedError() {
- var message = "Wrong username or/and password";
- Error.call(this, message);
- }
-
- UnauthenticatedError.prototype = {
- __proto__: Error.prototype,
- constructor: UnauthenticatedError
- }
-
- module.exports = {
- CaldavHttpError: CaldavHttpError,
- UnauthenticatedError: UnauthenticatedError
- };
-
-}.apply(
- this,
- (this.Caldav) ?
- [Caldav('request/errors'), Caldav] :
- [module, require('../caldav')]
-));
diff --git a/test/caldav/errors_test.js b/test/caldav/errors_test.js
new file mode 100644
index 0000000..e02ea84
--- /dev/null
+++ b/test/caldav/errors_test.js
@@ -0,0 +1,27 @@
+testSupport.lib('errors');
+
+suite('errors/authentication', function() {
+ var Errors;
+
+ suiteSetup(function() {
+ Errors = Caldav.require('errors');
+ });
+
+ function verifyErrorExists(symbol) {
+ test(symbol, function() {
+ var error = new Errors[symbol]('oops');
+ assert.equal(error.message, 'oops');
+ assert.ok(error.name, 'has name');
+ assert.ok(error.stack, 'has stack');
+ });
+ }
+
+ // why grouped? gjslint hates us otherwise
+ ([
+ 'Authentication',
+ 'InvalidEntrypoint',
+ 'ServerFailure',
+ 'Unknown'
+ ]).forEach(verifyErrorExists);
+
+});
diff --git a/test/caldav/http/basic_auth_test.js b/test/caldav/http/basic_auth_test.js
index 566de08..a264d1b 100644
--- a/test/caldav/http/basic_auth_test.js
+++ b/test/caldav/http/basic_auth_test.js
@@ -39,19 +39,24 @@ suite('http/basic_auth', function() {
assert.equal(subject.url, url);
});
- test('#send', function() {
- var xhr = subject.send();
-
- assert.deepEqual(
- xhr.openArgs,
- [
- 'GET',
- url,
- subject.async,
- connection.user,
- connection.password
- ]
- );
+ suite('#send', function() {
+ test('success', function() {
+ var xhr = subject.send();
+
+ assert.deepEqual(
+ xhr.openArgs,
+ [
+ 'GET',
+ url,
+ subject.async,
+ connection.user,
+ connection.password
+ ]
+ );
+ });
+
+
+
});
});
diff --git a/test/caldav/index_test.js b/test/caldav/index_test.js
index baad822..d8f25b9 100644
--- a/test/caldav/index_test.js
+++ b/test/caldav/index_test.js
@@ -33,6 +33,7 @@ suite('caldav', function() {
assert.ok(root.Resources.Calendar, 'Calendar.Resources.Calendar');
assert.ok(root.OAuth2, 'OAuth2');
assert.ok(root.Http, 'Http');
+ assert.ok(root.Errors, 'Errors');
});
});
diff --git a/test/caldav/request/abstract_test.js b/test/caldav/request/abstract_test.js
index e2fb3d1..18d6bc3 100644
--- a/test/caldav/request/abstract_test.js
+++ b/test/caldav/request/abstract_test.js
@@ -77,22 +77,26 @@ suite('caldav/request/abstract.js', function() {
assert.deepEqual(con.password, req.password);
});
- suite('error', function() {
+ suite('errors', function() {
var calledWith;
- setup(function(done) {
+ setup(function() {
subject.send(function() {
calledWith = arguments;
- done();
});
-
- xhr = getXhr();
- xhr.respond('NOT XML <div>', 500);
});
- test('on response', function() {
- assert.equal(calledWith[0].code, 500);
- });
+ function verifyStatusFailure(status, name) {
+ test('status ' + status, function() {
+ xhr = getXhr();
+ xhr.respond('', status);
+ assert.equal(calledWith[0].name, name);
+ });
+ }
+
+ verifyStatusFailure(403, 'caldav-unknown');
+ verifyStatusFailure(401, 'caldav-authentication');
+ verifyStatusFailure(500, 'caldav-server-failure');
});
suite('success', function() {
diff --git a/test/caldav/request/calendar_home_test.js b/test/caldav/request/calendar_home_test.js
index 13483ad..6ed65fb 100644
--- a/test/caldav/request/calendar_home_test.js
+++ b/test/caldav/request/calendar_home_test.js
@@ -20,7 +20,7 @@ suite('caldav/request/propfind', function() {
Connection = Caldav.require('connection');
Home = Caldav.require('request/calendar_home');
MockRequest = Caldav.require('support/mock_request');
- Errors = Caldav.require('request/errors');
+ Errors = Caldav.require('errors');
});
suiteSetup(function() {
@@ -76,7 +76,7 @@ suite('caldav/request/propfind', function() {
response[url] = {
'current-user-principal': {
status: '200',
- value: { href:'foo.com/' }
+ value: { href: 'foo.com/' }
}
};
@@ -104,7 +104,7 @@ suite('caldav/request/propfind', function() {
assert.equal(data, 'bar.com/');
});
-
+
test('unauthenticated', function() {
var req = request('_findPrincipal');
@@ -116,12 +116,28 @@ suite('caldav/request/propfind', function() {
}
}
};
-
req.respond(null, response);
- assert.equal(true, err instanceof Errors.UnauthenticatedError);
+ assert.instanceOf(err, Errors.Authentication);
+ });
+
+ test('without href', function() {
+ var req = request('_findPrincipal');
+ response[url] = {
+ 'principal-URL': {}
+ };
+
+ req.respond(null, response);
+ assert.instanceOf(err, Errors.InvalidEntrypoint);
+ });
+
+ test('without useful response', function() {
+ var req = request('_findPrincipal');
+ response[url] = {};
+ req.respond(null, response);
+
+ assert.instanceOf(err, Errors.InvalidEntrypoint);
});
-
});
suite('#_findCalendarHome', function() {
diff --git a/test/helper.js b/test/helper.js
index 5cf8d5f..92585f5 100644
--- a/test/helper.js
+++ b/test/helper.js
@@ -204,7 +204,10 @@
/* since we have global mocks easier to just include these globally */
requireRequest = function(callback) {
+ testSupport.helper('fake_xhr');
testSupport.lib('responder');
+ testSupport.lib('errors');
+ testSupport.lib('xhr');
testSupport.lib('oauth2');
testSupport.lib('http/basic_auth');
testSupport.lib('http/oauth2');
@@ -212,7 +215,6 @@
testSupport.lib('sax');
testSupport.lib('sax/base');
testSupport.lib('sax/dav_response');
- testSupport.lib('request/errors');
testSupport.lib('request/abstract');
testSupport.lib('template');
testSupport.lib('request/propfind');
diff --git a/test/support/fake_xhr.js b/test/support/fake_xhr.js
index 3f6cea0..59c6598 100644
--- a/test/support/fake_xhr.js
+++ b/test/support/fake_xhr.js
@@ -1,6 +1,4 @@
(function(module) {
- console.log('I HAZ LOADED');
-
function FakeXhr() {
this.openArgs = null;
this.sendArgs = null;
@@ -44,7 +42,6 @@
}
};
- console.log('EXPORTS ME', FakeXhr);
module.exports = FakeXhr;
}.apply(