383 lines
11 KiB
JavaScript
383 lines
11 KiB
JavaScript
require('./common');
|
||
var crypto = require("crypto");
|
||
var _ = require("underscore");
|
||
var querystring = require("querystring");
|
||
var fakes = require("./fakes");
|
||
var LastFmRequest = fakes.LastFmRequest;
|
||
|
||
(function() {
|
||
var gently, lastfm;
|
||
var options, expectations;
|
||
var notExpected;
|
||
|
||
describe("a lastfm request");
|
||
|
||
before(function() {
|
||
gently = new Gently();
|
||
options = {};
|
||
expectations = {
|
||
pairs:[],
|
||
handlers:[]
|
||
};
|
||
notExpected = {
|
||
keys:[]
|
||
}
|
||
lastfm = new LastFmNode({
|
||
api_key: "key",
|
||
secret: "secret"
|
||
});
|
||
gently.expect(GENTLY_HIJACK.hijacked.http, "request", function(options, cb) {
|
||
verifyCreateClient(options.port, options.host);
|
||
var request = new fakes.ClientRequest();
|
||
if (options.method == "POST") {
|
||
gently.expect(request, "write", function(data) {
|
||
verifyRequest(options.method, options.path, options.headers, data);
|
||
});
|
||
} else {
|
||
verifyRequest(options.method, options.path, options.headers);
|
||
}
|
||
return request;
|
||
});
|
||
});
|
||
|
||
after(function() {
|
||
var request = doRequest();
|
||
verifyHandlers(request);
|
||
});
|
||
|
||
function verifyCreateClient(port, host) {
|
||
if (expectations.port) {
|
||
assert.equal(expectations.port, port);
|
||
}
|
||
if (expectations.host) {
|
||
assert.equal(expectations.host, host);
|
||
}
|
||
}
|
||
|
||
function verifyRequest(method, url, header, data) {
|
||
if (expectations.url) {
|
||
assert.equal(expectations.url, url);
|
||
}
|
||
var pairs = querystring.parse(data || url.substr("/2.0?".length));
|
||
_(Object.keys(expectations.pairs)).each(function(key) {
|
||
assert.equal(expectations.pairs[key], pairs[key]);
|
||
});
|
||
if (expectations.signed || expectations.signatureHash) {
|
||
assert.ok(pairs.api_sig);
|
||
}
|
||
else if (expectations.signed === false) {
|
||
assert.ok(!pairs.api_sig);
|
||
}
|
||
if (expectations.signatureHash) {
|
||
assert.equal(expectations.signatureHash, pairs.api_sig);
|
||
}
|
||
if (expectations.method) {
|
||
assert.equal(expectations.method, method);
|
||
}
|
||
_(notExpected.keys).each(function(key) {
|
||
assert.ok(!pairs[key]);
|
||
});
|
||
if (expectations.requestData) {
|
||
assert.ok(data);
|
||
}
|
||
}
|
||
|
||
function whenMethodIs(method) {
|
||
options.method = method;
|
||
}
|
||
|
||
function andParamsAre(params) {
|
||
options.params = params;
|
||
}
|
||
|
||
function expectHttpMethod(method) {
|
||
expectations.method = method;
|
||
}
|
||
|
||
function expectDataPair(key, value) {
|
||
expectations.pairs[key] = value;
|
||
}
|
||
|
||
function expectSignature() {
|
||
expectations.signed = true;
|
||
}
|
||
|
||
function expectUrl(url) {
|
||
expectations.url = url;
|
||
}
|
||
|
||
function expectSignatureHashOf(unhashed) {
|
||
var expectedHash = crypto.createHash("md5").update(unhashed, "utf8").digest("hex");
|
||
expectSignatureHashToBe(expectedHash);
|
||
};
|
||
|
||
this.expectSignatureHashToBe = function(hash) {
|
||
expectations.signatureHash = hash;
|
||
}
|
||
|
||
function expectRequestOnPort(port) {
|
||
expectations.port = port;
|
||
}
|
||
|
||
function expectRequestToHost(host) {
|
||
expectations.host = host;
|
||
}
|
||
|
||
function expectHandlerFor(event) {
|
||
expectations.handlers.push(event);
|
||
}
|
||
|
||
function expectRequestData() {
|
||
expectations.requestData = true;
|
||
}
|
||
|
||
function doNotExpectDataKey(key) {
|
||
notExpected.keys.push(key);
|
||
}
|
||
|
||
function doRequest() {
|
||
return lastfm.request(options.method, options.params);
|
||
}
|
||
|
||
function verifyHandlers(request) {
|
||
_(expectations.handlers).each(function(event) {
|
||
var listeners = request.listeners(event);
|
||
assert.equal(1, listeners.length, "No handler for event: " + event);
|
||
});
|
||
}
|
||
|
||
it("default to port 80", function() {
|
||
whenMethodIs("any.method");
|
||
expectRequestOnPort(80);
|
||
});
|
||
|
||
it("makes request to audioscrobbler", function() {
|
||
whenMethodIs("any.method");
|
||
expectRequestToHost("ws.audioscrobbler.com");
|
||
});
|
||
|
||
it("always requests as json", function() {
|
||
whenMethodIs("any.method");
|
||
expectDataPair("format", "json");
|
||
});
|
||
|
||
it("always passes api_key", function() {
|
||
whenMethodIs("any.method");
|
||
expectDataPair("api_key", "key");
|
||
});
|
||
|
||
it("defaults to get request", function() {
|
||
whenMethodIs("any.method");
|
||
expectHttpMethod("GET");
|
||
});
|
||
|
||
it("calls the method specified", function() {
|
||
whenMethodIs("user.getinfo");
|
||
expectDataPair("method", "user.getinfo");
|
||
});
|
||
|
||
it("passes through parameters", function() {
|
||
whenMethodIs("user.getinfo");
|
||
andParamsAre({ user: "jammus" });
|
||
expectDataPair("user", "jammus");
|
||
});
|
||
|
||
it("converts track object to separate parameters", function() {
|
||
whenMethodIs("any.method");
|
||
andParamsAre({
|
||
track: {
|
||
artist: { "#text": "The Mae Shi" },
|
||
name: "Run To Your Grave",
|
||
mbid: "1234567890"
|
||
}
|
||
});
|
||
expectDataPair("artist", "The Mae Shi");
|
||
expectDataPair("track", "Run To Your Grave");
|
||
expectDataPair("mbid", "1234567890");
|
||
});
|
||
|
||
it("converts track object album details to separate parameters", function() {
|
||
whenMethodIs("any.method");
|
||
andParamsAre({
|
||
track: {
|
||
artist: { "#text": "The Mae Shi" },
|
||
name: "Run To Your Grave",
|
||
album: { "#text": "HLLLYH" }
|
||
}
|
||
});
|
||
expectDataPair("album", "HLLLYH");
|
||
});
|
||
|
||
it("does not overwrite explicitly set album parameters", function() {
|
||
whenMethodIs("any.method");
|
||
andParamsAre({
|
||
track: {
|
||
artist: { "#text": "The Mae Shi" },
|
||
name: "Run To Your Grave",
|
||
album: { "#text": "HLLLYH" }
|
||
},
|
||
album: "Run To Your Grave"
|
||
});
|
||
expectDataPair("album", "Run To Your Grave");
|
||
});
|
||
|
||
it("doesn't include mbid if one isn't supplied", function() {
|
||
whenMethodIs("any.method");
|
||
andParamsAre({
|
||
track: {
|
||
artist: { "#text": "The Mae Shi" },
|
||
name: "Run To Your Grave"
|
||
}
|
||
});
|
||
expectDataPair("artist", "The Mae Shi");
|
||
expectDataPair("track", "Run To Your Grave");
|
||
doNotExpectDataKey("mbid");
|
||
});
|
||
|
||
it("does not pass through event handler parameters", function() {
|
||
whenMethodIs("any.method");
|
||
andParamsAre({ handlers: "handlers", error: "error", success: "success" });
|
||
doNotExpectDataKey("handlers");
|
||
doNotExpectDataKey("error");
|
||
doNotExpectDataKey("success");
|
||
});
|
||
|
||
it("auth.getsession has signature", function() {
|
||
whenMethodIs("auth.getsession");
|
||
expectSignature();
|
||
});
|
||
|
||
it("attaches handlers to returned request", function() {
|
||
whenMethodIs("any.method");
|
||
andParamsAre({ handlers: {
|
||
error: function() {console.log("errrors");},
|
||
success: function() {},
|
||
arbitrary: function() {},
|
||
}});
|
||
expectHandlerFor("error");
|
||
expectHandlerFor("success");
|
||
expectHandlerFor("arbitrary");
|
||
});
|
||
|
||
it("uses signed param to force signature", function() {
|
||
whenMethodIs("any.method");
|
||
andParamsAre({
|
||
signed: true
|
||
});
|
||
expectSignature();
|
||
});
|
||
|
||
it("signature hashes api_key, method and secret", function() {
|
||
whenMethodIs("auth.getsession");
|
||
expectSignatureHashOf("api_keykeymethodauth.getsessionsecret");
|
||
});
|
||
|
||
it("signature includes other parameters", function() {
|
||
whenMethodIs("auth.getsession");
|
||
andParamsAre({ foo: "bar" });
|
||
expectSignatureHashOf("api_keykeyfoobarmethodauth.getsessionsecret");
|
||
});
|
||
|
||
it("signature hashes all params alphabetically", function() {
|
||
whenMethodIs("auth.getsession");
|
||
andParamsAre({ foo : "bar", baz: "bash", flip : "flop" });
|
||
expectSignatureHashOf("api_keykeybazbashflipflopfoobarmethodauth.getsessionsecret");
|
||
});
|
||
|
||
it("signature hash ignores format parameter", function() {
|
||
whenMethodIs("auth.getsession");
|
||
andParamsAre({ format: "json" });
|
||
expectSignatureHashOf("api_keykeymethodauth.getsessionsecret");
|
||
});
|
||
|
||
it("signature hash ignores handlers parameter", function() {
|
||
whenMethodIs("auth.getsession");
|
||
andParamsAre({ handlers: "handlers" });
|
||
expectSignatureHashOf("api_keykeymethodauth.getsessionsecret");
|
||
});
|
||
|
||
it("signature hash ignores write parameter", function() {
|
||
whenMethodIs("auth.getsession");
|
||
andParamsAre({ write: true });
|
||
expectSignatureHashOf("api_keykeymethodauth.getsessionsecret");
|
||
});
|
||
|
||
it("signature hash ignores signed parameter", function() {
|
||
whenMethodIs("any.method");
|
||
andParamsAre({ signed: true });
|
||
expectSignatureHashOf("api_keykeymethodany.methodsecret");
|
||
});
|
||
|
||
it("signature hash handles high characters as expected by last.fm (utf8)", function() {
|
||
whenMethodIs("auth.getsession");
|
||
andParamsAre({ track: "Tony’s Theme (Remastered)" });
|
||
expectSignatureHashToBe("15f5159046bf1e76774b9dd46a4ed993");
|
||
});
|
||
|
||
it("signature hash treats undefined values as blank", function() {
|
||
whenMethodIs("any.method");
|
||
andParamsAre({ signed: true, track: 'Replicating Networks', artist: 'Rabbit Milk', albumArtist: undefined });
|
||
expectSignatureHashOf("albumArtistapi_keykeyartistRabbit Milkmethodany.methodtrackReplicating Networkssecret");
|
||
});
|
||
|
||
it("signature hash treats null values as blank", function() {
|
||
whenMethodIs("any.method");
|
||
andParamsAre({ signed: true, track: 'Replicating Networks', artist: 'Rabbit Milk', albumArtist: null });
|
||
expectSignatureHashOf("albumArtistapi_keykeyartistRabbit Milkmethodany.methodtrackReplicating Networkssecret");
|
||
});
|
||
|
||
it("write requests use post", function() {
|
||
whenMethodIs("any.method");
|
||
andParamsAre({ write: true });
|
||
expectHttpMethod("POST");
|
||
});
|
||
|
||
it("write requests don't use get parameters", function() {
|
||
whenMethodIs("any.method");
|
||
andParamsAre({ write: true });
|
||
expectUrl("/2.0");
|
||
});
|
||
|
||
it("write requests send data in request", function() {
|
||
whenMethodIs("any.method");
|
||
andParamsAre({
|
||
write: true,
|
||
foo: "bar"
|
||
});
|
||
expectRequestData();
|
||
expectDataPair("foo", "bar");
|
||
});
|
||
|
||
it("write requests are always signed", function() {
|
||
whenMethodIs("album.removeTag");
|
||
andParamsAre({
|
||
write: true
|
||
});
|
||
expectSignature();
|
||
});
|
||
|
||
_(["album.addTags", "album.removeTag", "album.share",
|
||
"artist.addTags", "artist.removeTag", "artist.share", "artist.shout",
|
||
"event.attend", "event.share", "event.shout",
|
||
"library.addAlbum", "library.addArtist", "library.addTrack",
|
||
"playlist.addTrack", "playlist.create",
|
||
"radio.tune",
|
||
"track.addTags", "track.ban", "track.love", "track.removeTag",
|
||
"track.scrobble", "track.share", "track.unban", "track.unlove",
|
||
"track.updateNowPlaying",
|
||
"user.shout"]).each(function(method) {
|
||
it(method + " is a write (post) request", function() {
|
||
whenMethodIs(method);
|
||
expectHttpMethod("POST");
|
||
});
|
||
});
|
||
|
||
_(["auth.getMobileSession", "auth.getSession", "auth.getToken",
|
||
"radio.getPlaylist"]).each(function(method) {
|
||
it(method + " is signed", function() {
|
||
whenMethodIs(method);
|
||
expectSignature();
|
||
});
|
||
});
|
||
})();
|