node-oauth/tests/oauthtests.js

1065 lines
51 KiB
JavaScript

var vows = require('vows'),
assert = require('assert'),
DummyResponse= require('./shared').DummyResponse,
DummyRequest= require('./shared').DummyRequest,
events = require('events'),
OAuth= require('../lib/oauth').OAuth,
OAuthEcho= require('../lib/oauth').OAuthEcho,
crypto = require('crypto');
//Valid RSA keypair used to test RSA-SHA1 signature method
var RsaPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\n" +
"MIICXQIBAAKBgQDizE4gQP5nPQhzof/Vp2U2DDY3UY/Gxha2CwKW0URe7McxtnmE\n" +
"CrZnT1n/YtfrrCNxY5KMP4o8hMrxsYEe05+1ZGFT68ztms3puUxilU5E3BQMhz1t\n" +
"JMJEGcTt8nZUlM4utli7fHgDtWbhvqvYjRMGn3AjyLOfY8XZvnFkGjipvQIDAQAB\n" +
"AoGAKgk6FcpWHOZ4EY6eL4iGPt1Gkzw/zNTcUsN5qGCDLqDuTq2Gmk2t/zn68VXt\n" +
"tVXDf/m3qN0CDzOBtghzaTZKLGhnSewQ98obMWgPcvAsb4adEEeW1/xigbMiaW2X\n" +
"cu6GhZxY16edbuQ40LRrPoVK94nXQpj8p7w4IQ301Sm8PSECQQD1ZlOj4ugvfhEt\n" +
"exi4WyAaM45fylmN290UXYqZ8SYPI/VliDytIlMfyq5Rv+l+dud1XDPrWOQ0ImgV\n" +
"HJn7uvoZAkEA7JhHNmHF9dbdF9Koj86K2Cl6c8KUu7U7d2BAuB6pPkt8+D8+y4St\n" +
"PaCmN4oP4X+sf5rqBYoXywHlqEei2BdpRQJBAMYgR4cZu7wcXGIL8HlnmROObHSK\n" +
"OqN9z5CRtUV0nPW8YnQG+nYOMG6KhRMbjri750OpnYF100kEPmRNI0VKQIECQE8R\n" +
"fQsRleTYz768ahTVQ9WF1ySErMwmfx8gDcD6jjkBZVxZVpURXAwyehopi7Eix/VF\n" +
"QlxjkBwKIEQi3Ks297kCQQCL9by1bueKDMJO2YX1Brm767pkDKkWtGfPS+d3xMtC\n" +
"KJHHCqrS1V+D5Q89x5wIRHKxE5UMTc0JNa554OxwFORX\n" +
"-----END RSA PRIVATE KEY-----";
var RsaPublicKey = "-----BEGIN PUBLIC KEY-----\n" +
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDizE4gQP5nPQhzof/Vp2U2DDY3\n" +
"UY/Gxha2CwKW0URe7McxtnmECrZnT1n/YtfrrCNxY5KMP4o8hMrxsYEe05+1ZGFT\n" +
"68ztms3puUxilU5E3BQMhz1tJMJEGcTt8nZUlM4utli7fHgDtWbhvqvYjRMGn3Aj\n" +
"yLOfY8XZvnFkGjipvQIDAQAB\n" +
"-----END PUBLIC KEY-----";
vows.describe('OAuth').addBatch({
'When newing OAuth': {
topic: new OAuth(null, null, null, null, null, null, "PLAINTEXT"),
'followRedirects is enabled by default': function (oa) {
assert.equal(oa._clientOptions.followRedirects, true)
}
},
'When generating the signature base string described in http://oauth.net/core/1.0/#sig_base_example': {
topic: new OAuth(null, null, null, null, null, null, "HMAC-SHA1"),
'we get the expected result string': function (oa) {
var result= oa._createSignatureBase("GET", "http://photos.example.net/photos",
"file=vacation.jpg&oauth_consumer_key=dpf43f3p2l4k3l03&oauth_nonce=kllo9940pd9333jh&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1191242096&oauth_token=nnch734d00sl2jdk&oauth_version=1.0&size=original")
assert.equal( result, "GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation.jpg%26oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dkllo9940pd9333jh%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1191242096%26oauth_token%3Dnnch734d00sl2jdk%26oauth_version%3D1.0%26size%3Doriginal");
}
},
'When generating the signature with RSA-SHA1': {
topic: new OAuth(null, null, null, RsaPrivateKey, null, null, "RSA-SHA1"),
'we get a valid oauth signature': function (oa) {
var signatureBase = "GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation.jpg%26oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dkllo9940pd9333jh%26oauth_signature_method%3DRSA-SHA1%26oauth_timestamp%3D1191242096%26oauth_token%3Dnnch734d00sl2jdk%26oauth_version%3D1.0%26size%3Doriginal";
var oauthSignature = oa._createSignature(signatureBase, "xyz4992k83j47x0b");
assert.equal( oauthSignature, "qS4rhWog7GPgo4ZCJvUdC/1ZAax/Q4Ab9yOBvgxSopvmKUKp5rso+Zda46GbyN2hnYDTiA/g3P/d/YiPWa454BEBb/KWFV83HpLDIoqUUhJnlXX9MqRQQac0oeope4fWbGlfTdL2PXjSFJmvfrzybERD/ZufsFtVrQKS3QBpYiw=");
//now check that given the public key we can verify this signature
var verifier = crypto.createVerify("RSA-SHA1").update(signatureBase);
var valid = verifier.verify(RsaPublicKey, oauthSignature, 'base64');
assert.ok( valid, "Signature could not be verified with RSA public key");
}
},
'When generating the signature base string with PLAINTEXT': {
topic: new OAuth(null, null, null, null, null, null, "PLAINTEXT"),
'we get the expected result string': function (oa) {
var result= oa._getSignature("GET", "http://photos.example.net/photos",
"file=vacation.jpg&oauth_consumer_key=dpf43f3p2l4k3l03&oauth_nonce=kllo9940pd9333jh&oauth_signature_method=PLAINTEXT&oauth_timestamp=1191242096&oauth_token=nnch734d00sl2jdk&oauth_version=1.0&size=original",
"test");
assert.equal( result, "&test");
}
},
'When normalising a url': {
topic: new OAuth(null, null, null, null, null, null, "HMAC-SHA1"),
'default ports should be stripped': function(oa) {
assert.equal( oa._normalizeUrl("https://somehost.com:443/foo/bar"), "https://somehost.com/foo/bar" );
},
'should leave in non-default ports from urls for use in signature generation': function(oa) {
assert.equal( oa._normalizeUrl("https://somehost.com:446/foo/bar"), "https://somehost.com:446/foo/bar" );
assert.equal( oa._normalizeUrl("http://somehost.com:81/foo/bar"), "http://somehost.com:81/foo/bar" );
},
'should add a trailing slash when no path at all is present': function(oa) {
assert.equal( oa._normalizeUrl("http://somehost.com"), "http://somehost.com/")
}
},
'When making an array out of the arguments hash' : {
topic: new OAuth(null, null, null, null, null, null, "HMAC-SHA1"),
'flatten out arguments that are arrays' : function(oa) {
var parameters= {"z": "a",
"a": ["1", "2"],
"1": "c" };
var parameterResults= oa._makeArrayOfArgumentsHash(parameters);
assert.equal(parameterResults.length, 4);
assert.equal(parameterResults[0][0], "1");
assert.equal(parameterResults[1][0], "z");
assert.equal(parameterResults[2][0], "a");
assert.equal(parameterResults[3][0], "a");
}
},
'When ordering the request parameters' : {
topic: new OAuth(null, null, null, null, null, null, "HMAC-SHA1"),
'Order them by name' : function(oa) {
var parameters= {"z": "a",
"a": "b",
"1": "c" };
var parameterResults= oa._sortRequestParams(oa._makeArrayOfArgumentsHash(parameters))
assert.equal(parameterResults[0][0], "1");
assert.equal(parameterResults[1][0], "a");
assert.equal(parameterResults[2][0], "z");
},
'If two parameter names are the same then order by the value': function(oa) {
var parameters= {"z": "a",
"a": ["z", "b", "b", "a", "y"],
"1": "c" };
var parameterResults= oa._sortRequestParams(oa._makeArrayOfArgumentsHash(parameters))
assert.equal(parameterResults[0][0], "1");
assert.equal(parameterResults[1][0], "a");
assert.equal(parameterResults[1][1], "a");
assert.equal(parameterResults[2][0], "a");
assert.equal(parameterResults[2][1], "b");
assert.equal(parameterResults[3][0], "a");
assert.equal(parameterResults[3][1], "b");
assert.equal(parameterResults[4][0], "a");
assert.equal(parameterResults[4][1], "y");
assert.equal(parameterResults[5][0], "a");
assert.equal(parameterResults[5][1], "z");
assert.equal(parameterResults[6][0], "z");
}
},
'When normalising the request parameters': {
topic: new OAuth(null, null, null, null, null, null, "HMAC-SHA1"),
'the resulting parameters should be encoded and ordered as per http://tools.ietf.org/html/rfc5849#section-3.1 (3.4.1.3.2)' : function(oa) {
var parameters= {"b5" : "=%3D",
"a3": ["a", "2 q"],
"c@": "",
"a2": "r b",
"oauth_consumer_key": "9djdj82h48djs9d2",
"oauth_token":"kkk9d7dh3k39sjv7",
"oauth_signature_method": "HMAC-SHA1",
"oauth_timestamp": "137131201",
"oauth_nonce": "7d8f3e4a",
"c2" : ""};
var normalisedParameterString= oa._normaliseRequestParams(parameters);
assert.equal(normalisedParameterString, "a2=r%20b&a3=2%20q&a3=a&b5=%3D%253D&c%40=&c2=&oauth_consumer_key=9djdj82h48djs9d2&oauth_nonce=7d8f3e4a&oauth_signature_method=HMAC-SHA1&oauth_timestamp=137131201&oauth_token=kkk9d7dh3k39sjv7");
}
},
'When preparing the parameters for use in signing': {
topic: new OAuth(null, null, null, null, null, null, "HMAC-SHA1"),
'We need to be wary of node\'s auto object creation from foo[bar] style url parameters' : function(oa) {
var result= oa._prepareParameters( "", "", "", "http://foo.com?foo[bar]=xxx&bar[foo]=yyy", {} );
assert.equal( result[0][0], "bar[foo]")
assert.equal( result[0][1], "yyy")
assert.equal( result[1][0], "foo[bar]")
assert.equal( result[1][1], "xxx")
}
},
'When signing a url': {
topic: function() {
var oa= new OAuth(null, null, "consumerkey", "consumersecret", "1.0", null, "HMAC-SHA1");
oa._getTimestamp= function(){ return "1272399856"; }
oa._getNonce= function(){ return "ybHPeOEkAUJ3k2wJT9Xb43MjtSgTvKqp"; }
return oa;
},
'Provide a valid signature when no token present': function(oa) {
assert.equal( oa.signUrl("http://somehost.com:3323/foo/poop?bar=foo"), "http://somehost.com:3323/foo/poop?bar=foo&oauth_consumer_key=consumerkey&oauth_nonce=ybHPeOEkAUJ3k2wJT9Xb43MjtSgTvKqp&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1272399856&oauth_version=1.0&oauth_signature=7ytO8vPSLut2GzHjU9pn1SV9xjc%3D");
},
'Provide a valid signature when a token is present': function(oa) {
assert.equal( oa.signUrl("http://somehost.com:3323/foo/poop?bar=foo", "token"), "http://somehost.com:3323/foo/poop?bar=foo&oauth_consumer_key=consumerkey&oauth_nonce=ybHPeOEkAUJ3k2wJT9Xb43MjtSgTvKqp&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1272399856&oauth_token=token&oauth_version=1.0&oauth_signature=9LwCuCWw5sURtpMroIolU3YwsdI%3D");
},
'Provide a valid signature when a token and a token secret is present': function(oa) {
assert.equal( oa.signUrl("http://somehost.com:3323/foo/poop?bar=foo", "token", "tokensecret"), "http://somehost.com:3323/foo/poop?bar=foo&oauth_consumer_key=consumerkey&oauth_nonce=ybHPeOEkAUJ3k2wJT9Xb43MjtSgTvKqp&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1272399856&oauth_token=token&oauth_version=1.0&oauth_signature=zeOR0Wsm6EG6XSg0Vw%2FsbpoSib8%3D");
}
},
'When getting a request token': {
topic: function() {
var oa= new OAuth(null, null, "consumerkey", "consumersecret", "1.0", null, "HMAC-SHA1");
oa._getTimestamp= function(){ return "1272399856"; }
oa._getNonce= function(){ return "ybHPeOEkAUJ3k2wJT9Xb43MjtSgTvKqp"; }
oa._performSecureRequest= function(){ return this.requestArguments = arguments; }
return oa;
},
'Use the HTTP method in the client options': function(oa) {
oa.setClientOptions({ requestTokenHttpMethod: "GET" });
oa.getOAuthRequestToken(function() {});
assert.equal(oa.requestArguments[2], "GET");
},
'Use a POST by default': function(oa) {
oa.setClientOptions({});
oa.getOAuthRequestToken(function() {});
assert.equal(oa.requestArguments[2], "POST");
}
},
'When getting an access token': {
topic: function() {
var oa= new OAuth(null, null, "consumerkey", "consumersecret", "1.0", null, "HMAC-SHA1");
oa._getTimestamp= function(){ return "1272399856"; }
oa._getNonce= function(){ return "ybHPeOEkAUJ3k2wJT9Xb43MjtSgTvKqp"; }
oa._performSecureRequest= function(){ return this.requestArguments = arguments; }
return oa;
},
'Use the HTTP method in the client options': function(oa) {
oa.setClientOptions({ accessTokenHttpMethod: "GET" });
oa.getOAuthAccessToken(function() {});
assert.equal(oa.requestArguments[2], "GET");
},
'Use a POST by default': function(oa) {
oa.setClientOptions({});
oa.getOAuthAccessToken(function() {});
assert.equal(oa.requestArguments[2], "POST");
}
},
'When get authorization header' : {
topic: function() {
var oa= new OAuth(null, null, "consumerkey", "consumersecret", "1.0", null, "HMAC-SHA1");
oa._getTimestamp= function(){ return "1272399856"; }
oa._getNonce= function(){ return "ybHPeOEkAUJ3k2wJT9Xb43MjtSgTvKqp"; }
return oa;
},
'Provide a valid signature when a token and a token secret is present': function(oa) {
assert.equal( oa.authHeader("http://somehost.com:3323/foo/poop?bar=foo", "token", "tokensecret"), 'OAuth oauth_consumer_key="consumerkey",oauth_nonce="ybHPeOEkAUJ3k2wJT9Xb43MjtSgTvKqp",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1272399856",oauth_token="token",oauth_version="1.0",oauth_signature="zeOR0Wsm6EG6XSg0Vw%2FsbpoSib8%3D"');
},
'Support variable whitespace separating the arguments': function(oa) {
oa._oauthParameterSeperator= ", ";
assert.equal( oa.authHeader("http://somehost.com:3323/foo/poop?bar=foo", "token", "tokensecret"), 'OAuth oauth_consumer_key="consumerkey", oauth_nonce="ybHPeOEkAUJ3k2wJT9Xb43MjtSgTvKqp", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1272399856", oauth_token="token", oauth_version="1.0", oauth_signature="zeOR0Wsm6EG6XSg0Vw%2FsbpoSib8%3D"');
}
},
'When get the OAuth Echo authorization header': {
topic: function () {
var realm = "http://foobar.com/";
var verifyCredentials = "http://api.foobar.com/verify.json";
var oa = new OAuthEcho(realm, verifyCredentials, "consumerkey", "consumersecret", "1.0A", "HMAC-SHA1");
oa._getTimestamp= function(){ return "1272399856"; }
oa._getNonce= function(){ return "ybHPeOEkAUJ3k2wJT9Xb43MjtSgTvKqp"; }
return oa;
},
'Provide a valid signature when a token and token secret is present': function (oa) {
assert.equal( oa.authHeader("http://somehost.com:3323/foo/poop?bar=foo", "token", "tokensecret"), 'OAuth realm="http://foobar.com/",oauth_consumer_key="consumerkey",oauth_nonce="ybHPeOEkAUJ3k2wJT9Xb43MjtSgTvKqp",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1272399856",oauth_token="token",oauth_version="1.0A",oauth_signature="0rr1LhSxACX2IEWRq3uCb4IwtOs%3D"');
}
},
'When non standard ports are used': {
topic: function() {
var oa= new OAuth(null, null, null, null, null, null, "HMAC-SHA1"),
mockProvider= {};
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
assert.equal(headers.Host, "somehost.com:8080");
assert.equal(hostname, "somehost.com");
assert.equal(port, "8080");
return {
on: function() {},
end: function() {}
};
}
return oa;
},
'getProtectedResource should correctly define the host headers': function(oa) {
oa.getProtectedResource("http://somehost.com:8080", "GET", "oauth_token", null, function(){})
}
},
'When building the OAuth Authorization header': {
topic: new OAuth(null, null, null, null, null, null, "HMAC-SHA1"),
'All provided oauth arguments should be concatentated correctly' : function(oa) {
var parameters= [
["oauth_timestamp", "1234567"],
["oauth_nonce", "ABCDEF"],
["oauth_version", "1.0"],
["oauth_signature_method", "HMAC-SHA1"],
["oauth_consumer_key", "asdasdnm2321b3"]];
assert.equal(oa._buildAuthorizationHeaders(parameters), 'OAuth oauth_timestamp="1234567",oauth_nonce="ABCDEF",oauth_version="1.0",oauth_signature_method="HMAC-SHA1",oauth_consumer_key="asdasdnm2321b3"');
},
'*Only* Oauth arguments should be concatentated, others should be disregarded' : function(oa) {
var parameters= [
["foo", "2343"],
["oauth_timestamp", "1234567"],
["oauth_nonce", "ABCDEF"],
["bar", "dfsdfd"],
["oauth_version", "1.0"],
["oauth_signature_method", "HMAC-SHA1"],
["oauth_consumer_key", "asdasdnm2321b3"],
["foobar", "asdasdnm2321b3"]];
assert.equal(oa._buildAuthorizationHeaders(parameters), 'OAuth oauth_timestamp="1234567",oauth_nonce="ABCDEF",oauth_version="1.0",oauth_signature_method="HMAC-SHA1",oauth_consumer_key="asdasdnm2321b3"');
},
'_buildAuthorizationHeaders should not depends on Array.prototype.toString' : function(oa) {
var _toString = Array.prototype.toString;
Array.prototype.toString = function(){ return '[Array] ' + this.length; }; // toString overwrite example used in jsdom.
var parameters= [
["foo", "2343"],
["oauth_timestamp", "1234567"],
["oauth_nonce", "ABCDEF"],
["bar", "dfsdfd"],
["oauth_version", "1.0"],
["oauth_signature_method", "HMAC-SHA1"],
["oauth_consumer_key", "asdasdnm2321b3"],
["foobar", "asdasdnm2321b3"]];
assert.equal(oa._buildAuthorizationHeaders(parameters), 'OAuth oauth_timestamp="1234567",oauth_nonce="ABCDEF",oauth_version="1.0",oauth_signature_method="HMAC-SHA1",oauth_consumer_key="asdasdnm2321b3"');
Array.prototype.toString = _toString;
}
},
'When performing the Secure Request' : {
topic: new OAuth("http://foo.com/RequestToken",
"http://foo.com/AccessToken",
"anonymous", "anonymous",
"1.0A", "http://foo.com/callback", "HMAC-SHA1"),
'using the POST method' : {
'Any passed extra_params should form part of the POST body': function(oa) {
var post_body_written= false;
var op= oa._createClient;
try {
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
return {
write: function(post_body){
post_body_written= true;
assert.equal(post_body,"scope=foobar%2C1%2C2");
}
};
}
oa._performSecureRequest("token", "token_secret", 'POST', 'http://foo.com/protected_resource', {"scope": "foobar,1,2"});
assert.equal(post_body_written, true);
}
finally {
oa._createClient= op;
}
}
}
},
'When performing a secure' : {
topic: new OAuth("http://foo.com/RequestToken",
"http://foo.com/AccessToken",
"anonymous", "anonymous",
"1.0A", "http://foo.com/callback", "HMAC-SHA1"),
'POST' : {
'if no callback is passed' : {
'it should return a request object': function(oa) {
var request= oa.post("http://foo.com/blah", "token", "token_secret", "BLAH", "text/plain")
assert.isObject(request);
assert.equal(request.method, "POST");
request.end();
}
},
'if a callback is passed' : {
"it should call the internal request's end method and return nothing": function(oa) {
var callbackCalled= false;
var op= oa._createClient;
try {
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
return {
write: function(){},
on: function() {},
end: function() {
callbackCalled= true;
}
};
}
var request= oa.post("http://foo.com/blah", "token", "token_secret", "BLAH", "text/plain", function(e,d){})
assert.equal(callbackCalled, true);
assert.isUndefined(request);
}
finally {
oa._createClient= op;
}
}
},
'if the post_body is a buffer' : {
"It should be passed through as is, and the original content-type (if specified) should be passed through": function(oa) {
var op= oa._createClient;
try {
var callbackCalled= false;
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
assert.equal(headers["Content-Type"], "image/jpeg")
return {
write: function(data){
callbackCalled= true;
assert.equal(data.length, 4);
},
on: function() {},
end: function() {
}
};
}
var request= oa.post("http://foo.com/blah", "token", "token_secret", new Buffer([10,20,30,40]), "image/jpeg")
assert.equal(callbackCalled, true);
}
finally {
oa._createClient= op;
}
},
"It should be passed through as is, and no content-type is specified.": function(oa) {
//Should probably actually set application/octet-stream, but to avoid a change in behaviour
// will just document (here) that the library will set it to application/x-www-form-urlencoded
var op= oa._createClient;
try {
var callbackCalled= false;
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
assert.equal(headers["Content-Type"], "application/x-www-form-urlencoded")
return {
write: function(data){
callbackCalled= true;
assert.equal(data.length, 4);
},
on: function() {},
end: function() {
}
};
}
var request= oa.post("http://foo.com/blah", "token", "token_secret", new Buffer([10,20,30,40]))
assert.equal(callbackCalled, true);
}
finally {
oa._createClient= op;
}
}
},
'if the post_body is not a string or a buffer' : {
"It should be url encoded and the content type set to be x-www-form-urlencoded" : function(oa) {
var op= oa._createClient;
try {
var callbackCalled= false;
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
assert.equal(headers["Content-Type"], "application/x-www-form-urlencoded")
return {
write: function(data){
callbackCalled= true;
assert.equal(data, "foo=1%2C2%2C3&bar=1%2B2");
},
on: function() {},
end: function() {
}
};
}
var request= oa.post("http://foo.com/blah", "token", "token_secret", {"foo":"1,2,3", "bar":"1+2"})
assert.equal(callbackCalled, true);
}
finally {
oa._createClient= op;
}
}
},
'if the post_body is a string' : {
"and it contains non ascii (7/8bit) characters" : {
"the content length should be the byte count, and not the string length" : function(oa) {
var testString= "Tôi yêu node";
var testStringLength= testString.length;
var testStringBytesLength= Buffer.byteLength(testString);
assert.notEqual(testStringLength, testStringBytesLength); // Make sure we're testing a string that differs between byte-length and char-length!
var op= oa._createClient;
try {
var callbackCalled= false;
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
assert.equal(headers["Content-length"], testStringBytesLength);
return {
write: function(data){
callbackCalled= true;
assert.equal(data, testString);
},
on: function() {},
end: function() {
}
};
}
var request= oa.post("http://foo.com/blah", "token", "token_secret", "Tôi yêu node")
assert.equal(callbackCalled, true);
}
finally {
oa._createClient= op;
}
}
},
"and no post_content_type is specified" : {
"It should be written as is, with a content length specified, and the encoding should be set to be x-www-form-urlencoded" : function(oa) {
var op= oa._createClient;
try {
var callbackCalled= false;
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
assert.equal(headers["Content-Type"], "application/x-www-form-urlencoded");
assert.equal(headers["Content-length"], 23);
return {
write: function(data){
callbackCalled= true;
assert.equal(data, "foo=1%2C2%2C3&bar=1%2B2");
},
on: function() {},
end: function() {
}
};
}
var request= oa.post("http://foo.com/blah", "token", "token_secret", "foo=1%2C2%2C3&bar=1%2B2")
assert.equal(callbackCalled, true);
}
finally {
oa._createClient= op;
}
}
},
"and a post_content_type is specified" : {
"It should be written as is, with a content length specified, and the encoding should be set to be as specified" : function(oa) {
var op= oa._createClient;
try {
var callbackCalled= false;
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
assert.equal(headers["Content-Type"], "unicorn/encoded");
assert.equal(headers["Content-length"], 23);
return {
write: function(data){
callbackCalled= true;
assert.equal(data, "foo=1%2C2%2C3&bar=1%2B2");
},
on: function() {},
end: function() {
}
};
}
var request= oa.post("http://foo.com/blah", "token", "token_secret", "foo=1%2C2%2C3&bar=1%2B2", "unicorn/encoded")
assert.equal(callbackCalled, true);
}
finally {
oa._createClient= op;
}
}
}
}
},
'GET' : {
'if no callback is passed' : {
'it should return a request object': function(oa) {
var request= oa.get("http://foo.com/blah", "token", "token_secret")
assert.isObject(request);
assert.equal(request.method, "GET");
request.end();
}
},
'if a callback is passed' : {
"it should call the internal request's end method and return nothing": function(oa) {
var callbackCalled= false;
var op= oa._createClient;
try {
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
return {
on: function() {},
end: function() {
callbackCalled= true;
}
};
}
var request= oa.get("http://foo.com/blah", "token", "token_secret", function(e,d) {})
assert.equal(callbackCalled, true);
assert.isUndefined(request);
}
finally {
oa._createClient= op;
}
}
},
},
'PUT' : {
'if no callback is passed' : {
'it should return a request object': function(oa) {
var request= oa.put("http://foo.com/blah", "token", "token_secret", "BLAH", "text/plain")
assert.isObject(request);
assert.equal(request.method, "PUT");
request.end();
}
},
'if a callback is passed' : {
"it should call the internal request's end method and return nothing": function(oa) {
var callbackCalled= 0;
var op= oa._createClient;
try {
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
return {
on: function() {},
write: function(data) {
callbackCalled++;
},
end: function() {
callbackCalled++;
}
};
}
var request= oa.put("http://foo.com/blah", "token", "token_secret", "BLAH", "text/plain", function(e,d){})
assert.equal(callbackCalled, 2);
assert.isUndefined(request);
}
finally {
oa._createClient= op;
}
}
},
'if the post_body is a buffer' : {
"It should be passed through as is, and the original content-type (if specified) should be passed through": function(oa) {
var op= oa._createClient;
try {
var callbackCalled= false;
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
assert.equal(headers["Content-Type"], "image/jpeg")
return {
write: function(data){
callbackCalled= true;
assert.equal(data.length, 4);
},
on: function() {},
end: function() {
}
};
}
var request= oa.put("http://foo.com/blah", "token", "token_secret", new Buffer([10,20,30,40]), "image/jpeg")
assert.equal(callbackCalled, true);
}
finally {
oa._createClient= op;
}
},
"It should be passed through as is, and no content-type is specified.": function(oa) {
//Should probably actually set application/octet-stream, but to avoid a change in behaviour
// will just document (here) that the library will set it to application/x-www-form-urlencoded
var op= oa._createClient;
try {
var callbackCalled= false;
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
assert.equal(headers["Content-Type"], "application/x-www-form-urlencoded")
return {
write: function(data){
callbackCalled= true;
assert.equal(data.length, 4);
},
on: function() {},
end: function() {
}
};
}
var request= oa.put("http://foo.com/blah", "token", "token_secret", new Buffer([10,20,30,40]))
assert.equal(callbackCalled, true);
}
finally {
oa._createClient= op;
}
}
},
'if the post_body is not a string' : {
"It should be url encoded and the content type set to be x-www-form-urlencoded" : function(oa) {
var op= oa._createClient;
try {
var callbackCalled= false;
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
assert.equal(headers["Content-Type"], "application/x-www-form-urlencoded")
return {
write: function(data) {
callbackCalled= true;
assert.equal(data, "foo=1%2C2%2C3&bar=1%2B2");
}
};
}
var request= oa.put("http://foo.com/blah", "token", "token_secret", {"foo":"1,2,3", "bar":"1+2"})
assert.equal(callbackCalled, true);
}
finally {
oa._createClient= op;
}
}
},
'if the post_body is a string' : {
"and no post_content_type is specified" : {
"It should be written as is, with a content length specified, and the encoding should be set to be x-www-form-urlencoded" : function(oa) {
var op= oa._createClient;
try {
var callbackCalled= false;
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
assert.equal(headers["Content-Type"], "application/x-www-form-urlencoded");
assert.equal(headers["Content-length"], 23);
return {
write: function(data) {
callbackCalled= true;
assert.equal(data, "foo=1%2C2%2C3&bar=1%2B2");
}
};
}
var request= oa.put("http://foo.com/blah", "token", "token_secret", "foo=1%2C2%2C3&bar=1%2B2")
assert.equal(callbackCalled, true);
}
finally {
oa._createClient= op;
}
}
},
"and a post_content_type is specified" : {
"It should be written as is, with a content length specified, and the encoding should be set to be as specified" : function(oa) {
var op= oa._createClient;
try {
var callbackCalled= false;
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
assert.equal(headers["Content-Type"], "unicorn/encoded");
assert.equal(headers["Content-length"], 23);
return {
write: function(data) {
callbackCalled= true;
assert.equal(data, "foo=1%2C2%2C3&bar=1%2B2");
}
};
}
var request= oa.put("http://foo.com/blah", "token", "token_secret", "foo=1%2C2%2C3&bar=1%2B2", "unicorn/encoded")
assert.equal(callbackCalled, true);
}
finally {
oa._createClient= op;
}
}
}
}
},
'DELETE' : {
'if no callback is passed' : {
'it should return a request object': function(oa) {
var request= oa.delete("http://foo.com/blah", "token", "token_secret")
assert.isObject(request);
assert.equal(request.method, "DELETE");
request.end();
}
},
'if a callback is passed' : {
"it should call the internal request's end method and return nothing": function(oa) {
var callbackCalled= false;
var op= oa._createClient;
try {
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
return {
on: function() {},
end: function() {
callbackCalled= true;
}
};
}
var request= oa.delete("http://foo.com/blah", "token", "token_secret", function(e,d) {})
assert.equal(callbackCalled, true);
assert.isUndefined(request);
}
finally {
oa._createClient= op;
}
}
}
},
'Request With a Callback' : {
'and a 200 response code is received' : {
'it should callback successfully' : function(oa) {
var op= oa._createClient;
var callbackCalled = false;
try {
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
return new DummyRequest( new DummyResponse(200) );
}
oa._performSecureRequest("token", "token_secret", 'POST', 'http://originalurl.com', {"scope": "foobar,1,2"}, null, null, function(error) {
// callback
callbackCalled= true;
assert.equal(error, undefined);
});
assert.equal(callbackCalled, true)
}
finally {
oa._createClient= op;
}
}
},
'and a 210 response code is received' : {
'it should callback successfully' : function(oa) {
var op= oa._createClient;
var callbackCalled = false;
try {
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
return new DummyRequest( new DummyResponse(210) );
}
oa._performSecureRequest("token", "token_secret", 'POST', 'http://originalurl.com', {"scope": "foobar,1,2"}, null, null, function(error) {
// callback
callbackCalled= true;
assert.equal(error, undefined);
});
assert.equal(callbackCalled, true)
}
finally {
oa._createClient= op;
}
}
},
'And A 301 redirect is received' : {
'and there is a location header' : {
'it should (re)perform the secure request but with the new location' : function(oa) {
var op= oa._createClient;
var psr= oa._performSecureRequest;
var responseCounter = 1;
var callbackCalled = false;
var DummyResponse =function() {
if( responseCounter == 1 ){
this.statusCode= 301;
this.headers= {location:"http://redirectto.com"};
responseCounter++;
}
else {
this.statusCode= 200;
}
}
DummyResponse.prototype= events.EventEmitter.prototype;
DummyResponse.prototype.setEncoding= function() {}
try {
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
return new DummyRequest( new DummyResponse() );
}
oa._performSecureRequest= function( oauth_token, oauth_token_secret, method, url, extra_params, post_body, post_content_type, callback ) {
if( responseCounter == 1 ) {
assert.equal(url, "http://originalurl.com");
}
else {
assert.equal(url, "http://redirectto.com");
}
return psr.call(oa, oauth_token, oauth_token_secret, method, url, extra_params, post_body, post_content_type, callback )
}
oa._performSecureRequest("token", "token_secret", 'POST', 'http://originalurl.com', {"scope": "foobar,1,2"}, null, null, function() {
// callback
assert.equal(responseCounter, 2);
callbackCalled= true;
});
assert.equal(callbackCalled, true)
}
finally {
oa._createClient= op;
oa._performSecureRequest= psr;
}
}
},
'but there is no location header' : {
'it should execute the callback, passing the HTTP Response code' : function(oa) {
var op= oa._createClient;
var callbackCalled = false;
try {
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
return new DummyRequest( new DummyResponse(301) );
}
oa._performSecureRequest("token", "token_secret", 'POST', 'http://originalurl.com', {"scope": "foobar,1,2"}, null, null, function(error) {
// callback
assert.equal(error.statusCode, 301);
callbackCalled= true;
});
assert.equal(callbackCalled, true)
}
finally {
oa._createClient= op;
}
}
},
'and followRedirect is true' : {
'it should (re)perform the secure request but with the new location' : function(oa) {
var op= oa._createClient;
var psr= oa._performSecureRequest;
var responseCounter = 1;
var callbackCalled = false;
var DummyResponse =function() {
if( responseCounter == 1 ){
this.statusCode= 301;
this.headers= {location:"http://redirectto.com"};
responseCounter++;
}
else {
this.statusCode= 200;
}
}
DummyResponse.prototype= events.EventEmitter.prototype;
DummyResponse.prototype.setEncoding= function() {}
try {
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
return new DummyRequest( new DummyResponse() );
}
oa._performSecureRequest= function( oauth_token, oauth_token_secret, method, url, extra_params, post_body, post_content_type, callback ) {
if( responseCounter == 1 ) {
assert.equal(url, "http://originalurl.com");
}
else {
assert.equal(url, "http://redirectto.com");
}
return psr.call(oa, oauth_token, oauth_token_secret, method, url, extra_params, post_body, post_content_type, callback )
}
oa._performSecureRequest("token", "token_secret", 'POST', 'http://originalurl.com', {"scope": "foobar,1,2"}, null, null, function() {
// callback
assert.equal(responseCounter, 2);
callbackCalled= true;
});
assert.equal(callbackCalled, true)
}
finally {
oa._createClient= op;
oa._performSecureRequest= psr;
}
}
},
'and followRedirect is false' : {
'it should not perform the secure request with the new location' : function(oa) {
var op= oa._createClient;
oa.setClientOptions({ followRedirects: false });
var DummyResponse =function() {
this.statusCode= 301;
this.headers= {location:"http://redirectto.com"};
}
DummyResponse.prototype= events.EventEmitter.prototype;
DummyResponse.prototype.setEncoding= function() {}
try {
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
return new DummyRequest( new DummyResponse() );
}
oa._performSecureRequest("token", "token_secret", 'POST', 'http://originalurl.com', {"scope": "foobar,1,2"}, null, null, function(res, data, response) {
// callback
assert.equal(res.statusCode, 301);
});
}
finally {
oa._createClient= op;
oa.setClientOptions({followRedirects:true});
}
}
}
},
'And A 302 redirect is received' : {
'and there is a location header' : {
'it should (re)perform the secure request but with the new location' : function(oa) {
var op= oa._createClient;
var psr= oa._performSecureRequest;
var responseCounter = 1;
var callbackCalled = false;
var DummyResponse =function() {
if( responseCounter == 1 ){
this.statusCode= 302;
this.headers= {location:"http://redirectto.com"};
responseCounter++;
}
else {
this.statusCode= 200;
}
}
DummyResponse.prototype= events.EventEmitter.prototype;
DummyResponse.prototype.setEncoding= function() {}
try {
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
return new DummyRequest( new DummyResponse() );
}
oa._performSecureRequest= function( oauth_token, oauth_token_secret, method, url, extra_params, post_body, post_content_type, callback ) {
if( responseCounter == 1 ) {
assert.equal(url, "http://originalurl.com");
}
else {
assert.equal(url, "http://redirectto.com");
}
return psr.call(oa, oauth_token, oauth_token_secret, method, url, extra_params, post_body, post_content_type, callback )
}
oa._performSecureRequest("token", "token_secret", 'POST', 'http://originalurl.com', {"scope": "foobar,1,2"}, null, null, function() {
// callback
assert.equal(responseCounter, 2);
callbackCalled= true;
});
assert.equal(callbackCalled, true)
}
finally {
oa._createClient= op;
oa._performSecureRequest= psr;
}
}
},
'but there is no location header' : {
'it should execute the callback, passing the HTTP Response code' : function(oa) {
var op= oa._createClient;
var callbackCalled = false;
try {
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
return new DummyRequest( new DummyResponse(302) );
}
oa._performSecureRequest("token", "token_secret", 'POST', 'http://originalurl.com', {"scope": "foobar,1,2"}, null, null, function(error) {
// callback
assert.equal(error.statusCode, 302);
callbackCalled= true;
});
assert.equal(callbackCalled, true)
}
finally {
oa._createClient= op;
}
}
},
'and followRedirect is true' : {
'it should (re)perform the secure request but with the new location' : function(oa) {
var op= oa._createClient;
var psr= oa._performSecureRequest;
var responseCounter = 1;
var callbackCalled = false;
var DummyResponse =function() {
if( responseCounter == 1 ){
this.statusCode= 302;
this.headers= {location:"http://redirectto.com"};
responseCounter++;
}
else {
this.statusCode= 200;
}
}
DummyResponse.prototype= events.EventEmitter.prototype;
DummyResponse.prototype.setEncoding= function() {}
try {
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
return new DummyRequest( new DummyResponse() );
}
oa._performSecureRequest= function( oauth_token, oauth_token_secret, method, url, extra_params, post_body, post_content_type, callback ) {
if( responseCounter == 1 ) {
assert.equal(url, "http://originalurl.com");
}
else {
assert.equal(url, "http://redirectto.com");
}
return psr.call(oa, oauth_token, oauth_token_secret, method, url, extra_params, post_body, post_content_type, callback )
}
oa._performSecureRequest("token", "token_secret", 'POST', 'http://originalurl.com', {"scope": "foobar,1,2"}, null, null, function() {
// callback
assert.equal(responseCounter, 2);
callbackCalled= true;
});
assert.equal(callbackCalled, true)
}
finally {
oa._createClient= op;
oa._performSecureRequest= psr;
}
}
},
'and followRedirect is false' : {
'it should not perform the secure request with the new location' : function(oa) {
var op= oa._createClient;
oa.setClientOptions({ followRedirects: false });
var DummyResponse =function() {
this.statusCode= 302;
this.headers= {location:"http://redirectto.com"};
}
DummyResponse.prototype= events.EventEmitter.prototype;
DummyResponse.prototype.setEncoding= function() {}
try {
oa._createClient= function( port, hostname, method, path, headers, sshEnabled ) {
return new DummyRequest( new DummyResponse() );
}
oa._performSecureRequest("token", "token_secret", 'POST', 'http://originalurl.com', {"scope": "foobar,1,2"}, null, null, function(res, data, response) {
// callback
assert.equal(res.statusCode, 302);
});
}
finally {
oa._createClient= op;
oa.setClientOptions({followRedirects:true});
}
}
}
}
}
}
}).export(module);