This commit is contained in:
2022-09-30 05:39:11 +00:00
parent 41ee9463ae
commit 4687fa49bc
11418 changed files with 1312504 additions and 0 deletions

36
buildfiles/app/node_modules/lastfm/tests/TestData.js generated vendored Normal file
View File

@ -0,0 +1,36 @@
var FakeData = exports.FakeData = Object.create;
FakeData.SingleRecentTrack = '{\"recenttracks\":{\"track\":42}}';
FakeData.UnknownObject = '{\"recentevents\":{\"event\":{}}}';
FakeData.MultipleRecentsTracks = '{\"recenttracks\":{\"track\":[\"first\", \"second\"]}}';
FakeData.Garbage = 'fi30i\ 32';
var FakeTracks = exports.FakeTracks = Object.create;
FakeTracks.LambAndTheLion = { name: 'Lamb and the Lion'};
FakeTracks.RunToYourGrave_NP = {"artist":{"#text":"The Mae Shi","mbid":"8eb5c47c-4847-4c4b-a041-879d8fc5fbf3"},"name":"Run To Your Grave","streamable":"1","mbid":"","album":{"#text":"HILLYH","mbid":""},"url":"http:\/\/www.last.fm\/music\/The+Mae+Shi\/_\/Run+To+Your+Grave","image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/4656031.jpg","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/4656031.jpg","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/4656031.jpg","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/4656031.jpg","size":"extralarge"}],"@attr":{"nowplaying":"true"}};
FakeTracks.RunToYourGrave = {"artist":{"#text":"The Mae Shi","mbid":"8eb5c47c-4847-4c4b-a041-879d8fc5fbf3"},"name":"Run To Your Grave","streamable":"1","mbid":"fakembid","album":{"#text":"HILLYH","mbid":""},"url":"http:\/\/www.last.fm\/music\/The+Mae+Shi\/_\/Run+To+Your+Grave","image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/4656031.jpg","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/4656031.jpg","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/4656031.jpg","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/4656031.jpg","size":"extralarge"}]};
FakeTracks.NowPlayingAndScrobbled = [{"artist":{"#text":"Super Tennis","mbid":""},"name":"Theme Song","streamable":"1","mbid":"","album":{"#text":"The Quiet Finale","mbid":""},"url":"http:\/\/www.last.fm\/music\/Super+Tennis\/_\/Theme+Song","image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/41788301.jpg","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/41788301.jpg","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/41788301.jpg","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/41788301.jpg","size":"extralarge"}],"@attr":{"nowplaying":"true"}},{"artist":{"#text":"Colour","mbid":""},"name":"Over The Moon","streamable":"1","mbid":"","album":{"#text":"The 6 Machine","mbid":""},"url":"http:\/\/www.last.fm\/music\/Colour\/_\/Over+The+Moon","image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/32970217.jpg","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/32970217.jpg","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/32970217.jpg","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/32970217.jpg","size":"extralarge"}]}];
FakeData.AuthorisationError = "{ \"error\" : 13, \"message\" : \"Signature is invalid\" }";
FakeData.SuccessfulAuthorisation = "{ \"session\": { \"name\": \"username\", \"key\": \"sessionkey\", \"subscriber\": \"0\"} }";
FakeData.UpdateError = "{ \"error\" : 13, \"message\" : \"Invalid method signature supplied\" }";
FakeData.UpdateNowPlayingSuccess = "{\"nowplaying\":{\"track\":{\"#text\":\"Run To Your Grave\",\"corrected\":\"0\"},\"artist\":{\"#text\":\"The Mai Shi\",\"corrected\":\"0\"},\"album\":{\"#text\":\"\",\"corrected\":\"0\"},\"albumArtist\":{\"#text\":\"\",\"corrected\":\"0\"},\"ignoredMessage\":{\"#text\":\"\",\"code\":\"0\"}}}";
FakeData.ScrobbleSuccess= "{\"scrobbles\":{\"scrobble\":{\"track\":{\"#text\":\"Run To Your Grave\",\"corrected\":\"0\"},\"artist\":{\"#text\":\"The Mai Shi\",\"corrected\":\"0\"},\"album\":{\"#text\":\"\",\"corrected\":\"0\"},\"albumArtist\":{\"#text\":\"\",\"corrected\":\"0\"},\"timestamp\":\"1287180538\",\"ignoredMessage\":{\"#text\":\"\",\"code\":\"0\"}},\"@attr\":{\"accepted\":\"1\",\"ignored\":\"0\"}}}";
FakeData.UserInfo = "{\"user\":{\"name\":\"jammus\",\"realname\":\"James\",\"image\":[{\"#text\":\"http:\/\/userserve-ak.last.fm\/serve\/34\/5208646.jpg\",\"size\":\"small\"},{\"#text\":\"http:\/\/userserve-ak.last.fm\/serve\/64\/5208646.jpg\",\"size\":\"medium\"},{\"#text\":\"http:\/\/userserve-ak.last.fm\/serve\/126\/5208646.jpg\",\"size\":\"large\"},{\"#text\":\"http:\/\/userserve-ak.last.fm\/serve\/252\/5208646.jpg\",\"size\":\"extralarge\"}],\"url\":\"http:\/\/www.last.fm\/user\/jammus\",\"id\":\"9421325\",\"country\":\"UK\",\"age\":\"29\",\"gender\":\"m\",\"subscriber\":\"0\",\"playcount\":\"4049\",\"playlists\":\"2\",\"bootstrap\":\"0\",\"registered\":{\"#text\":\"2008-02-14 14:14\",\"unixtime\":\"1202998466\"}}}";
FakeData.UnknownUser = "{\"error\":6,\"message\":\"No user with that name was found\"}";
FakeData.Error = "{\"error\":1,\"message\":\"Error received\"}";
FakeData.NotEnoughTrackInfo = "{\"error\":6,\"message\":\"You must supply either a track & artist name or a track mbid.\"}";
FakeData.RunToYourGraveTrackInfo = "{\"track\":{\"id\":\"87962768\",\"name\":\"Run To Your Grave\",\"mbid\":\"\",\"url\":\"http:\/\/www.last.fm\/music\/The+Mae+Shi\/_\/Run+To+Your+Grave\",\"duration\":\"232000\",\"streamable\":{\"#text\":\"1\",\"fulltrack\":\"0\"},\"listeners\":\"38019\",\"playcount\":\"164628\",\"artist\":{\"name\":\"The Mae Shi\",\"mbid\":\"8eb5c47c-4847-4c4b-a041-879d8fc5fbf3\",\"url\":\"http:\/\/www.last.fm\/music\/The+Mae+Shi\"},\"album\":{\"artist\":\"The Mae Shi\",\"title\":\"HILLYH\",\"mbid\":\"\",\"url\":\"http:\/\/www.last.fm\/music\/The+Mae+Shi\/HILLYH\",\"image\":[{\"#text\":\"http:\/\/userserve-ak.last.fm\/serve\/64s\/4656031.jpg\",\"size\":\"small\"},{\"#text\":\"http:\/\/userserve-ak.last.fm\/serve\/126\/4656031.jpg\",\"size\":\"medium\"},{\"#text\":\"http:\/\/userserve-ak.last.fm\/serve\/174s\/4656031.jpg\",\"size\":\"large\"},{\"#text\":\"http:\/\/userserve-ak.last.fm\/serve\/300x300\/4656031.jpg\",\"size\":\"extralarge\"}],\"@attr\":{\"position\":\"7\"}},\"toptags\":{\"tag\":[{\"name\":\"experimental\",\"url\":\"http:\/\/www.last.fm\/tag\/experimental\"},{\"name\":\"00s\",\"url\":\"http:\/\/www.last.fm\/tag\/00s\"},{\"name\":\"fuck yeah\",\"url\":\"http:\/\/www.last.fm\/tag\/fuck%20yeah\"},{\"name\":\"pop\",\"url\":\"http:\/\/www.last.fm\/tag\/pop\"},{\"name\":\"sing-a-long\",\"url\":\"http:\/\/www.last.fm\/tag\/sing-a-long\"}]}}}";
FakeData.UnexpectedRecentTracks = "{\"recenttracks\":\"somthing\"}";

16
buildfiles/app/node_modules/lastfm/tests/common.js generated vendored Normal file
View File

@ -0,0 +1,16 @@
var path = require("path");
global.Gently = require("gently");
global.GENTLY_HIJACK = new Gently();
global.assert = require("assert");
global.ntest = require('ntest');
global.it = ntest.it;
global.describe = ntest.describe;
global.before = ntest.before;
global.after = ntest.after;
global.LastFmNode = require("../lib/lastfm").LastFmNode;
global.FakeData = require("./TestData.js").FakeData;
global.FakeTracks = require("./TestData.js").FakeTracks;
if (process.setMaxListeners) {
process.setMaxListeners(900);
}
global.emptyFn = function() { };

39
buildfiles/app/node_modules/lastfm/tests/fakes.js generated vendored Normal file
View File

@ -0,0 +1,39 @@
var EventEmitter = require('events').EventEmitter;
var Client = exports.Client = function(port, host) {
EventEmitter.call(this);
this.port = port;
this.host = host;
};
Client.prototype = Object.create(EventEmitter.prototype);
Client.prototype.request = function() {
return new ClientRequest();
};
var ClientRequest = exports.ClientRequest = function() {
EventEmitter.call(this);
};
ClientRequest.prototype = Object.create(EventEmitter.prototype);
ClientRequest.prototype.write = function() {
};
ClientRequest.prototype.end = function() {
};
var ClientResponse = exports.ClientResponse = function() {
EventEmitter.call(this);
};
ClientResponse.prototype = Object.create(EventEmitter.prototype);
var LastFmRequest = exports.LastFmRequest = function(connection, url) {
EventEmitter.call(this);
this.connection = connection;
this.url = url;
};
LastFmRequest.prototype = Object.create(EventEmitter.prototype);

9
buildfiles/app/node_modules/lastfm/tests/index.js generated vendored Normal file
View File

@ -0,0 +1,9 @@
require("./lastfm-node-test.js");
require("./lastfm-recenttracks-stream-test.js");
require("./lastfm-session-test.js");
require("./lastfm-info-test.js");
require("./lastfm-read-test.js");
require("./lastfm-info-track-test.js");
require("./lastfm-update-test.js");
require("./lastfm-request-test.js");
require("./lastfm-base-test.js");

View File

@ -0,0 +1,78 @@
require('./common');
var LastFmBase = require("../lib/lastfm/lastfm-base");
(function() {
describe("LastFmBase");
it("is an event emitter", function() {
var events = { expected: function(){} };
var gently = new Gently();
var lastfmBase = new LastFmBase();
gently.expect(events, "expected");
lastfmBase.on("test", function() {
events.expected();
});
lastfmBase.emit("test");
});
})();
(function() {
describe("LastFmBase.registerHandlers");
it("attaches events specified in handelers parameter", function() {
var handlers = {
error: function() { },
success: function() { },
anything: function() { }
};
var gently = new Gently();
gently.expect(handlers, "error");
gently.expect(handlers, "success");
gently.expect(handlers, "anything");
var lastfmBase = new LastFmBase();
lastfmBase.registerHandlers(handlers);
lastfmBase.emit("error");
lastfmBase.emit("success");
lastfmBase.emit("anything");
});
})();
(function() {
var lastfmBase, original;
describe("LastFmBase.filterParameters");
before(function() {
lastfmBase = new LastFmBase();
original = { one: 1, two: 2, three: 3 };
});
it("unfiltered object matches original object", function() {
var copy = lastfmBase.filterParameters(original);
assert.deepEqual(copy, original);
});
it("returns copy of original object", function() {
var copy = lastfmBase.filterParameters(original);
copy.four = 4;
assert.notDeepEqual(copy, original);
});
it("filteres out blacklisted parameters", function() {
var copy = lastfmBase.filterParameters(original, ["one", "three"]);
assert.equal(typeof copy.one, "undefined");
assert.equal(typeof copy.three, "undefined");
assert.equal(copy.two, 2);
});
it("automatically removed error, success, handler parameters", function() {
var copy = lastfmBase.filterParameters({
error: emptyFn,
success: emptyFn,
handlers: { }
});
assert.equal(typeof copy.error, "undefined");
assert.equal(typeof copy.success, "undefined");
assert.equal(typeof copy.handlers, "undefined");
});
})();

View File

@ -0,0 +1,118 @@
require("./common.js");
var LastFmInfo = require("../lib/lastfm/lastfm-info");
var LastFmRequest = require("../lib/lastfm/lastfm-request");
var fakes = require("./fakes");
(function() {
describe("a new info instance")
var lastfm, gently;
before(function() {
lastfm = new LastFmNode();
gently = new Gently();
});
it("accepts listeners in handler options", function() {
var handlers = { error: function() {}, success: function() {} };
var options = { handlers: handlers };
gently.expect(handlers, "error");
gently.expect(handlers, "success");
var info = new LastFmInfo(lastfm, "", options);
info.emit("success");
});
it("emits error if type not specified", function() {
var handlers = { error: function() {}};
gently.expect(handlers, "error", function(error) {
assert.equal("Item type not specified", error.message);
});
var info = new LastFmInfo(lastfm, "", { handlers: handlers });
});
it("allows requests for user info", function() {
gently.expect(lastfm, "request", function() {
return new fakes.LastFmRequest();
});
var info = new LastFmInfo(lastfm, "user");
});
it("allows requests for track info", function() {
gently.expect(lastfm, "request", function() {
return new fakes.LastFmRequest();
});
var info = new LastFmInfo(lastfm, "track");
});
it("allows all [itemtype].getinfo calls", function() {
gently.expect(lastfm, "request", function(method, params) {
assert.equal("event.getinfo", method);
return new fakes.LastFmRequest();
});
new LastFmInfo(lastfm, "event");
});
it("passes through parameters", function() {
gently.expect(lastfm, "request", function(method, params) {
assert.equal("username", params.user);
assert.equal("anything", params.arbitrary);
return new fakes.LastFmRequest();
});
new LastFmInfo(lastfm, "user", { user: "username", arbitrary: "anything" });
});
it("doesnt pass through callback parameters", function() {
gently.expect(lastfm, "request", function(method, params) {
assert.ok(!params.error);
assert.ok(!params.success);
assert.ok(!params.handlers);
return new fakes.LastFmRequest();
});
new LastFmInfo(lastfm, "user", { handlers: { error: function() {}, success: function() {} } });
});
})();
(function() {
describe("when receiving data")
var gently, lastfm, request;
before(function() {
gently = new Gently();
lastfm = new LastFmNode();
request = new fakes.LastFmRequest();
});
it("emits error when receiving unexpected data", function() {
gently.expect(lastfm, "request", function() {
return request;
});
new LastFmInfo(lastfm, "track", { handlers: {
error: gently.expect(function errorHandler(error) {
assert.equal("Unexpected error", error.message);
})
}});
request.emit("success", JSON.parse(FakeData.SuccessfulAuthorisation));
});
it("emits success with received data when matches expected type", function() {
gently.expect(lastfm, "request", function() {
return request;
});
new LastFmInfo(lastfm, "track", { handlers: {
success: gently.expect(function success(track) {
assert.equal("Run To Your Grave", track.name);
assert.equal("232000", track.duration);
})
}});
request.emit("success", JSON.parse(FakeData.RunToYourGraveTrackInfo));
});
it("bubbles up errors", function() {
gently.expect(lastfm, "request", function() {
return request;
});
var info = new LastFmInfo(lastfm, "track");
gently.expect(info, "emit", function(event, error) {
assert.equal("error", event);
assert.equal("Bubbled error", error.message);
});
request.emit("error", new Error("Bubbled error"));
});
})();

View File

@ -0,0 +1,35 @@
require("./common.js");
var LastFmInfo = require("../lib/lastfm/lastfm-info")
, fakes = require("./fakes");
(function() {
describe("a track info request");
before(function() {
this.gently = new Gently();
this.lastfm = new LastFmNode();
});
it("calls method track.getInfo", function() {
this.gently.expect(this.lastfm, "request", function(method, params) {
assert.equal("track.getinfo", method);
return new fakes.LastFmRequest();
});
new LastFmInfo(this.lastfm, "track", { mbid: "mbid" });
});
it("can accept artist, track name and mbid", function() {
this.gently.expect(this.lastfm, "request", function(method, params) {
assert.equal("The Mae Shi", params.artist);
assert.equal("Run To Your Grave", params.track);
assert.equal("1234567890", params.mbid);
return new fakes.LastFmRequest();
});
new LastFmInfo(this.lastfm, "track", {
artist: "The Mae Shi",
track: "Run To Your Grave",
mbid: "1234567890"
});
});
})();

View File

@ -0,0 +1,38 @@
require("./common.js");
var querystring = require("querystring");
(function() {
var lastfm;
describe("default LastFmNode instance")
before(function() {
lastfm = new LastFmNode();
})
it("has default host", function() {
assert.equal("ws.audioscrobbler.com", lastfm.host);
});
})();
(function() {
var lastfm;
describe("LastFmNode options")
before(function() {
lastfm = new LastFmNode({
api_key: "abcdef12345",
secret: "ghijk67890"
});
})
it("configures api key", function() {
assert.equal("abcdef12345", lastfm.api_key);
});
it("configures secret", function() {
assert.equal("ghijk67890", lastfm.secret);
});
})();

View File

@ -0,0 +1,382 @@
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: "Tonys 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();
});
});
})();

View File

@ -0,0 +1,324 @@
require("./common.js");
var _ = require("underscore")
, RecentTracksStream = require("../lib/lastfm/recenttracks-stream")
, LastFmRequest = require("../lib/lastfm/lastfm-request")
, fakes = require("./fakes");
(function() {
var gently, lastfm, trackStream;
describe("a new stream instance");
before(function() {
gently = new Gently();
lastfm = new LastFmNode();
trackStream = new RecentTracksStream(lastfm, "username");
});
it("accepts listeners", function() {
trackStream.addListener("event", function() {});
});
it("is not streaming", function() {
assert.ok(!trackStream.isStreaming());
});
it("event handlers can be specified in options", function() {
var handlers = {};
gently.expect(handlers, "error");
gently.expect(handlers, "lastPlayed");
gently.expect(handlers, "nowPlaying");
gently.expect(handlers, "stoppedPlaying");
gently.expect(handlers, "scrobbled");
var trackStream = new RecentTracksStream(lastfm, "username", {
handlers: {
error: handlers.error,
lastPlayed: handlers.lastPlayed,
nowPlaying: handlers.nowPlaying,
stoppedPlaying: handlers.stoppedPlaying,
scrobbled: handlers.scrobbled
}
});
trackStream.emit("error");
trackStream.emit("lastPlayed");
trackStream.emit("nowPlaying");
trackStream.emit("stoppedPlaying");
trackStream.emit("scrobbled");
});
})();
(function() {
var requestEmits = [],
previousEmits = [];
function ifRequestHasPreviouslyEmit(emits) {
previousEmits = emits;
}
function whenRequestEmits(count, event, object) {
if (typeof count !== "number") {
object = event;
event = count;
count = 1;
}
if (typeof event !== "string") {
object = event;
event = "success";
}
requestEmits = [event, object, count];
}
function expectStreamToEmit(count, expectation) {
if (typeof count === "function") {
expectation = count;
count = 1;
}
var lastfm = new LastFmNode(),
connection = new fakes.Client(80, lastfm.host),
request = new fakes.LastFmRequest(),
gently = new Gently();
gently.expect(lastfm, "request", function() {
return request;
});
var trackStream = new RecentTracksStream(lastfm, "username");
trackStream.start();
trackStream.stop();
for(var index = 0; index < previousEmits.length; index++) {
request.emit("success", previousEmits[index]);
}
gently.expect(trackStream, "emit", count, expectation);
for(var times = 0; times < requestEmits[2]; times++) {
request.emit(requestEmits[0], requestEmits[1]);
}
}
describe("An active stream");
before(function() {
previousEmits = [];
requestEmits = [];
});
it("bubbles errors", function() {
whenRequestEmits("error", { error: 1, message: "An error" });
expectStreamToEmit(function(event, error) {
assert.equal("error", event);
assert.equal("An error", error.message);
});
});
it("emits last played when track received", function() {
whenRequestEmits({ recenttracks: { track:
FakeTracks.LambAndTheLion
} });
expectStreamToEmit(function(event, track) {
assert.equal("lastPlayed", event);
assert.equal("Lamb and the Lion", track.name);
});
});
it("emits now playing if track flagged now playing", function() {
whenRequestEmits({
recenttracks: { track: FakeTracks.RunToYourGrave_NP }
});
expectStreamToEmit(function(event, track) {
assert.equal("nowPlaying", event);
assert.equal("Run To Your Grave", track.name);
});
});
it("emits now playing and last played if both received", function() {
var count = 0;
whenRequestEmits({
recenttracks: { track: FakeTracks.NowPlayingAndScrobbled }
});
expectStreamToEmit(2, function(event, track) {
if (count == 0) {
assert.equal("nowPlaying", event);
assert.equal("Theme Song", track.name);
}
else {
assert.equal("lastPlayed", event);
assert.equal("Over The Moon", track.name);
}
count++;
});
});
it("does not re-emit lastPlayed on receipt of same track", function() {
whenRequestEmits(2, {
recenttracks: { track: FakeTracks.LambAndTheLion }
});
expectStreamToEmit(1, function(event, track) {
assert.equal("lastPlayed", event);
assert.equal("Lamb and the Lion", track.name);
});
});
it("does not re-emit nowPlaying on receipt of same track", function() {
whenRequestEmits(2, {
recenttracks: { track: FakeTracks.RunToYourGrave_NP }
});
expectStreamToEmit(1, function(event, track) {
assert.equal("nowPlaying", event);
assert.equal("Run To Your Grave", track.name);
});
});
it("emits stoppedPlaying track when now playing stops", function() {
ifRequestHasPreviouslyEmit([
{ recenttracks: { track: FakeTracks.RunToYourGrave } },
{ recenttracks: { track: FakeTracks.RunToYourGrave_NP } }
]);
whenRequestEmits({
recenttracks: { track: FakeTracks.RunToYourGrave }
});
expectStreamToEmit(function(event, track) {
assert.equal("stoppedPlaying", event);
assert.equal("Run To Your Grave", track.name);
});
});
it("emits scrobbled when last play changes", function() {
ifRequestHasPreviouslyEmit([
{ recenttracks: { track: FakeTracks.LambAndTheLion } },
{ recenttracks: { track: FakeTracks.RunToYourGrave_NP } }
]);
whenRequestEmits({
recenttracks: { track: FakeTracks.RunToYourGrave }
});
expectStreamToEmit(function(event, track) {
assert.equal("scrobbled", event);
assert.equal("Run To Your Grave", track.name);
});
});
it("emits nowPlaying when track same as lastPlayed", function() {
ifRequestHasPreviouslyEmit([
{ recenttracks: { track: FakeTracks.RunToYourGrave } }
]);
whenRequestEmits({
recenttracks: { track: FakeTracks.RunToYourGrave_NP }
});
expectStreamToEmit(function(event, track) {
assert.equal("nowPlaying", event);
assert.equal("Run To Your Grave", track.name);
});
});
it("emits error when unexpected item is received", function() {
whenRequestEmits({
something: "we've never seen before"
});
expectStreamToEmit(function(event, error) {
assert.equal("error", event);
assert.equal("Unexpected response", error.message);
});
});
})();
(function() {
var lastfm, gently, request;
describe("Streaming")
before(function() {
lastfm = new LastFmNode();
gently = new Gently();
request = new fakes.LastFmRequest();
});
it("starts and stops streaming when requested", function() {
gently.expect(lastfm, "request", 1, function(method, params) {
return request;
});
var trackStream = new RecentTracksStream(lastfm);
trackStream.start();
trackStream.stop();
assert.ok(!trackStream.isStreaming());
});
it("starts automatically when autostart set to true", function() {
gently.expect(lastfm, "request", function() {
return request;
});
var trackStream = new RecentTracksStream(lastfm, "username", { autostart: true} );
assert.ok(trackStream.isStreaming());
trackStream.stop();
});
it("calls user.getrecenttracks method for user", function() {
gently.expect(lastfm, "request", function(method, params) {
assert.equal("user.getrecenttracks", method);
assert.equal("username", params.user);
return request;
});
var trackStream = new RecentTracksStream(lastfm, "username", { autostart: true} );
trackStream.stop();
});
it("only fetches most recent track", function() {
gently.expect(lastfm, "request", function(method, params) {
assert.equal(1, params.limit);
return request;
});
var trackStream = new RecentTracksStream(lastfm, "username", { autostart: true} );
trackStream.stop();
});
it("bubbles up errors", function() {
var errorMessage = "Bubbled error";
gently.expect(lastfm, "request", function() {
return request;
});
var trackStream = new RecentTracksStream(lastfm, "username", { autostart:true });
gently.expect(trackStream, "emit", function(event, error) {
assert.equal(errorMessage, error.message);
});
request.emit("error", new Error(errorMessage));
trackStream.stop();
});
})();
(function() {
var lastfm, gently;
describe("Streaming")
var tmpScheduleFn;
before(function() {
tmpScheduleFn = RecentTracksStream.prototype.scheduleCallback;
lastfm = new LastFmNode();
gently = new Gently();
});
after(function() {
RecentTracksStream.prototype.scheduleCallback = tmpScheduleFn;
});
it("queries API every 10 seconds", function() {
var trackStream = new RecentTracksStream(lastfm, "username");
var count = 0;
RecentTracksStream.prototype.scheduleCallback = function(callback, delay) {
count++;
if (count === 10) {
trackStream.stop();
}
assert.ok(delay, 10000);
gently.expect(lastfm, "request", function(method, params) {
return new fakes.LastFmRequest();
});
callback();
};
gently.expect(lastfm, "request", function(method, params) {
return new fakes.LastFmRequest();
});
trackStream.start();
});
})();

View File

@ -0,0 +1,186 @@
require("./common");
var _ = require("underscore"),
LastFmRequest = require("../lib/lastfm/lastfm-request"),
fakes = require("./fakes");
(function() {
describe("a LastFm request")
var lastfm, connection, url, gently, request;
before(function() {
lastfm = new LastFmNode();
connection = new fakes.Client(80, lastfm.host);
request = new fakes.ClientRequest();
gently = new Gently();
});
it("creates a get request", function() {
gently.expect(GENTLY_HIJACK.hijacked.http, "request", function(options, cb) {
assert.equal("GET", options.method);
assert.equal(lastfm.host, options.host);
return request;
});
var lastfmRequest = new LastFmRequest(lastfm, "any.method");
});
it("ends the request", function() {
gently.expect(GENTLY_HIJACK.hijacked.http, "request", function() {
return request;
});
gently.expect(request, "end");
var lastfmRequest = new LastFmRequest(lastfm);
});
it("defaults user agent to lastfm-node", function() {
gently.expect(GENTLY_HIJACK.hijacked.http, "request", function(options, cb) {
assert.equal("lastfm-node", options.headers["User-Agent"]);
return request;
});
var lastFmRequest = new LastFmRequest(lastfm, "any.method");
});
it("can specify user agent in lastfm options", function() {
var useragent = "custom-user-agent";
gently.expect(GENTLY_HIJACK.hijacked.http, "request", function(options, cb) {
assert.equal(useragent, options.headers["User-Agent"]);
return request;
});
var lastfm = new LastFmNode({ useragent: useragent });
var lastFmRequest = new LastFmRequest(lastfm, "any.method");
});
it("bubbles up connection errors", function() {
var message = "Bubbled error";
gently.expect(GENTLY_HIJACK.hijacked.http, "request", function(options, cb) {
return request;
});
var lastfmRequest = new LastFmRequest(lastfm, "any.method");
gently.expect(lastfmRequest, "emit", function(event, error) {
assert.equal("error", event);
assert.equal(message, error.message);
});
request.emit("error", new Error(message));
});
})();
(function() {
describe("a LastFm request with a body")
var lastfm, connection, url, gently, request, params;
before(function() {
lastfm = new LastFmNode();
connection = new fakes.Client(80, lastfm.host);
request = new fakes.ClientRequest();
gently = new Gently();
params = { foo:"bar" };
});
it("write parameter forces a post request", function() {
gently.expect(GENTLY_HIJACK.hijacked.http, "request", function(options, cb) {
assert.equal("POST", options.method);
assert.equal(lastfm.url, options.path);
assert.equal(lastfm.host, options.host);
return request;
});
params.write = true;
var lastFmRequest = new LastFmRequest(lastfm, "any.method", params);
});
it("post requests includes additional headers", function() {
gently.expect(GENTLY_HIJACK.hijacked.http, "request", function(options, cb) {
assert.ok(options.headers["Content-Length"]);
assert.equal("application/x-www-form-urlencoded", options.headers["Content-Type"]);
return request;
});
params.write = true;
var lastFmRequest = new LastFmRequest(lastfm, "any.method", params);
});
it("writes body to request", function() {
gently.expect(GENTLY_HIJACK.hijacked.http, "request", function() {
return request;
});
gently.expect(request, "write", function(data) {
assert.ok(data);
});
params.write = true;
var lastFmRequest = new LastFmRequest(lastfm, "any.method", params);
});
})();
(function() {
var lastfm, connection, url, gently, request, receivedData;
describe("A Lastfm request which returns data")
before(function() {
lastfm = new LastFmNode();
connection = new fakes.Client(80, lastfm.host);
request = new fakes.ClientRequest();
gently = new Gently();
});
it("emits data as json", function() {
whenReceiving("{\"testdata\":\"received\"}");
expectRequestToEmit(function(event, data) {
assert.equal("success", event);
assert.equal("received", data.testdata);
});
});
it("emits error if received data cannot be parsed to json", function() {
whenReceiving("{\"testdata\"");
expectRequestToEmit(function(event, error) {
assert.equal("error", event);
assert.ok(error);
});
});
it("emits error if json response contains a lastfm error", function() {
whenReceiving("{\"error\": 2, \"message\": \"service does not exist\"}");
expectRequestToEmit(function(event, error) {
assert.equal("error", event);
assert.equal("service does not exist", error.message);
});
});
it("accepts data in chunks", function() {
whenReceiving(["{\"testda", "ta\":\"recei", "ved\"}"]);
expectRequestToEmit(function(event, data) {
assert.equal("success", event);
assert.equal("received", data.testdata);
});
});
it("does not covert to json if requested is different format", function() {
var xml = "<somexml />";
lastfm.format = "xml";
whenReceiving(xml);
expectRequestToEmit(function(event, data) {
assert.equal(xml, data);
});
});
function whenReceiving(data) {
if (data.constructor.name !== 'Array') {
data = [data];
}
receivedData = data;
}
function expectRequestToEmit(expectation) {
var response = new fakes.ClientResponse();
gently.expect(GENTLY_HIJACK.hijacked.http, "request", function(options, cb) {
cb(response);
return request;
});
var lastfmRequest = new LastFmRequest(lastfm);
gently.expect(lastfmRequest, "emit", expectation);
_(receivedData).each(function(data) {
response.emit("data", data);
});
response.emit("end");
}
})();

View File

@ -0,0 +1,176 @@
require('./common.js');
var LastFmSession = require('../lib/lastfm/lastfm-session');
var fakes = require("./fakes");
(function() {
describe("a new LastFmSession");
var session;
before(function() {
session = new LastFmSession(new LastFmNode());
});
it("has no session key", function() {
assert.ok(!session.key);
});
it("has no user", function() {
assert.ok(!session.user);
});
it("is not authorised", function() {
assert.ok(!session.isAuthorised());
});
it("can configure key and user", function() {
var session = new LastFmSession(new LastFmNode(), "user", "sessionkey");
assert.equal("user", session.user);
assert.equal("sessionkey", session.key);
});
it("is authorised when it has a key", function() {
var session = new LastFmSession(new LastFmNode(), "user", "sessionkey");
assert.ok(session.isAuthorised());
});
})();
(function() {
var readError, token, returndata, options, request, lastfm, session, gently;
function setupFixture() {
readError = "";
token = "";
returndata = null;
options = null;
request = new fakes.LastFmRequest();
lastfm = new LastFmNode();
session = new LastFmSession(lastfm);
gently = new Gently();
}
function expectError(expectedError) {
gently.expect(session, "emit", function(event, error) {
assert.equal("error", event);
assert.equal(expectedError, error.message);
});
session.authorise(token, options);
if (readError) {
request.emit("error", new Error(readError));
}
else {
request.emit("success", returndata);
}
}
function expectAuthorisation(assertions) {
gently.expect(session, "emit", function(event, emittedSession) {
assert.equal("authorised", event);
if (assertions) {
assertions(emittedSession);
}
});
session.authorise(token, options);
request.emit("success", returndata);
}
function whenReadRequestReturns(data) {
returndata = JSON.parse(data);
gently.expect(lastfm, "request", function() {
return request;
});
}
function whenReadRequestThrowsError(message) {
readError = message;
gently.expect(lastfm, "request", function() {
return request;
});
}
function andTokenIs(setToken) {
token = setToken;
}
function andOptionsAre(setOptions) {
options = setOptions;
}
describe("a LastFmSession authorisation request")
before(function() {
setupFixture();
});
it("emits error when no token supplied", function() {
expectError("No token supplied");
});
it("contains supplied token", function() {
gently.expect(lastfm, "request", function(method, params) {
assert.equal("token", params.token);
return request;
});
session.authorise("token");
});
it("uses getSession method", function() {
gently.expect(lastfm, "request", function(method, params) {
assert.equal("auth.getsession", method);
return request;
});
session.authorise("token");
});
describe("a completed LastFmSession authorisation request")
before(function() {
setupFixture();
});
it("emits error when receiving unexpected return data", function() {
whenReadRequestReturns(FakeData.SingleRecentTrack);
andTokenIs("token");
expectError("Unexpected error");
});
it("emits authorised when successful", function() {
whenReadRequestReturns(FakeData.SuccessfulAuthorisation);
andTokenIs("token");
expectAuthorisation();
});
it("can have error handler specified with authorise call", function() {
var handler = { error: function(error) { } };
gently.expect(handler, "error", function(error) {
assert.equal("No token supplied", error.message);
});
session.authorise("", { handlers: {
error: handler.error
}});
});
it("updates session key and user when successful", function() {
whenReadRequestReturns(FakeData.SuccessfulAuthorisation);
andTokenIs("token");
expectAuthorisation(function(session) {
assert.equal("username", session.user);
assert.equal("sessionkey", session.key);
assert.ok(session.isAuthorised());
});
});
it("can have authorised handler specified with authorise call", function() {
var handler = { authorised: function(session) { } };
whenReadRequestReturns(FakeData.SuccessfulAuthorisation);
gently.expect(handler, "authorised");
session.authorise("token", { handlers: {
authorised: handler.authorised
}});
request.emit("success", returndata);
});
it("bubbles up errors", function() {
var errorMessage = "Bubbled error";
whenReadRequestThrowsError(errorMessage);
andTokenIs("token");
expectError(errorMessage);
});
})();

View File

@ -0,0 +1,485 @@
require('./common.js');
var LastFmSession = require('../lib/lastfm/lastfm-session');
var LastFmUpdate = require('../lib/lastfm/lastfm-update');
var fakes = require("./fakes");
(function() {
describe("new LastFmUpdate")
it("can have success and error handlers specified in option at creation", function() {
var gently = new Gently();
var lastfm = new LastFmNode();
var update = new LastFmUpdate(lastfm, "method", new LastFmSession(lastfm, "user", "key"), { handlers: {
error: gently.expect(function error() {}),
success: gently.expect(function success() {})
}});
update.emit("error");
update.emit("success");
});
})();
(function() {
var request, returndata, options, session, method, gently, lastfm, authorisedSession, errorCode, errorMessage, update;
function setupFixture() {
request = new fakes.LastFmRequest();
returndata;
options = {};
session = null;
method = "";
gently = new Gently();
lastfm = new LastFmNode();
authorisedSession = new LastFmSession(lastfm, "user", "key");
errorCode = -1;
errorMessage = null;
update = undefined;
}
function whenRequestReturns(data) {
errorCode = -1;
errorMessage = null;
returndata = JSON.parse(data);
request = new fakes.LastFmRequest();
gently.expect(lastfm, "request", function() {
return request;
});
}
function whenRequestThrowsError(code, message) {
errorCode = code;
errorMessage = message;
request = new fakes.LastFmRequest();
gently.expect(lastfm, "request", function() {
return request;
});
}
function andOptionsAre(setOptions) {
options = setOptions;
}
function andMethodIs(setMethod) {
method = setMethod;
}
function andSessionIs(setSession) {
session = setSession;
}
function expectSuccess(assertions) {
var checkSuccess = function(track) {
if (assertions) {
assertions(track);
}
};
if (update) {
update.on("success", checkSuccess);
}
else {
options.handlers = options.handlers || {};
options.handlers.success = checkSuccess;
}
doUpdate();
}
function expectError(errorCode, expectedError) {
var checkError = function(error) {
if (errorCode || expectedError) {
assert.equal(expectedError, error.message);
assert.equal(errorCode, error.error);
}
};
if (update) {
update.on("error", checkError);
}
else {
options.handlers = options.handlers || {};
options.handlers.error = gently.expect(checkError);
}
doUpdate();
}
function doNotExpectError() {
options.handlers = options.handlers || {};
options.handlers.error = function checkNoErrorThrown(error) {
assert.ok(false);
};
doUpdate();
}
function expectRetry(callback) {
callback = callback || function() { };
if (update) {
gently.expect(update, "emit", function(event, retry) {
assert.equal(event, "retrying");
callback(retry);
});
}
else {
options.handlers = options.handlers || { };
options.handlers.retrying = gently.expect(callback);
}
doUpdate();
}
function doUpdate() {
update = update || new LastFmUpdate(lastfm, method, session, options);
if (errorMessage) {
request.emit("error", { error: errorCode, message: errorMessage });
}
else {
request.emit("success", returndata);
}
}
describe("update requests")
before(function() {
setupFixture();
});
it("fail when the session is not authorised", function() {
var session = new LastFmSession()
, update = new LastFmUpdate(lastfm, "method", session, {
handlers: {
error: gently.expect(function(error) {
assert.equal(error.error, 4);
assert.equal(error.message, "Authentication failed");
})
}
});
});
describe("nowPlaying updates")
before(function() {
setupFixture();
});
it("uses updateNowPlaying method", function() {
gently.expect(lastfm, "request", function(method, params) {
assert.equal("track.updateNowPlaying", method);
return request;
});
new LastFmUpdate(lastfm, "nowplaying", authorisedSession, {
track: FakeTracks.RunToYourGrave
});
});
it("sends required parameters", function() {
gently.expect(lastfm, "request", function(method, params) {
assert.equal(FakeTracks.RunToYourGrave, params.track);
assert.equal("key", params.sk);
return request;
});
new LastFmUpdate(lastfm, "nowplaying", authorisedSession, {
track: FakeTracks.RunToYourGrave
});
});
it("emits success when updated", function() {
whenRequestReturns(FakeData.UpdateNowPlayingSuccess);
andMethodIs("nowplaying");
andSessionIs(authorisedSession);
andOptionsAre({
track: FakeTracks.RunToYourGrave
});
expectSuccess(function(track) {
assert.equal("Run To Your Grave", track.name);
});
});
it("sends duration when supplied", function() {
gently.expect(lastfm, "request", function(method, params) {
assert.equal(232000, params.duration);
return request;
});
new LastFmUpdate(lastfm, "nowplaying", authorisedSession, {
track: FakeTracks.RunToYourGrave,
duration: 232000
});
});
it("can have artist and track string parameters supplied", function() {
gently.expect(lastfm, "request", function(method, params) {
assert.equal("The Mae Shi", params.artist);
assert.equal("Run To Your Grave", params.track);
assert.equal("key", params.sk);
return request;
});
new LastFmUpdate(lastfm, "nowplaying", authorisedSession, {
track: "Run To Your Grave",
artist: "The Mae Shi"
});
});
it("bubbles up errors", function() {
var errorMessage = "Bubbled error";
whenRequestThrowsError(100, errorMessage);
andMethodIs("nowplaying");
andSessionIs(authorisedSession);
andOptionsAre({
track: FakeTracks.RunToYourGrave,
timestamp: 12345678
});
expectError(100, errorMessage);
});
describe("a scrobble request")
before(function() {
setupFixture();
});
it("emits error when no timestamp supplied", function() {
new LastFmUpdate(lastfm, "scrobble", authorisedSession, {
track: FakeTracks.RunToYourGrave,
handlers: {
error: gently.expect(function error(error) {
assert.equal(6, error.error);
assert.equal("Invalid parameters - Timestamp is required for scrobbling", error.message);
})
}
});
});
it("uses scrobble method", function() {
gently.expect(lastfm, "request", function(method, params) {
assert.equal("track.scrobble", method);
return request;
});
new LastFmUpdate(lastfm, "scrobble", authorisedSession, {
track: FakeTracks.RunToYourGrave,
timestamp: 12345678
});
});
it("sends required parameters", function() {
gently.expect(lastfm, "request", function(method, params) {
assert.equal(FakeTracks.RunToYourGrave, params.track);
assert.equal("key", params.sk);
assert.equal(12345678, params.timestamp);
return request;
});
new LastFmUpdate(lastfm, "scrobble", authorisedSession, {
track: FakeTracks.RunToYourGrave,
timestamp: 12345678
});
});
it("emits success when updated", function() {
whenRequestReturns(FakeData.ScrobbleSuccess);
andMethodIs("scrobble");
andSessionIs(authorisedSession);
andOptionsAre({
track: FakeTracks.RunToYourGrave,
timestamp: 12345678
});
expectSuccess(function(track) {
assert.equal("Run To Your Grave", track.name);
});
});
it("bubbles up errors", function() {
var errorMessage = "Bubbled error";
whenRequestThrowsError(100, errorMessage);
andMethodIs("scrobble");
andSessionIs(authorisedSession);
andOptionsAre({
track: FakeTracks.RunToYourGrave,
timestamp: 12345678
});
expectError(100, errorMessage);
});
it("can have artist and track string parameters supplied", function() {
gently.expect(lastfm, "request", function(method, params) {
assert.equal("The Mae Shi", params.artist);
assert.equal("Run To Your Grave", params.track);
assert.equal("key", params.sk);
return request;
});
new LastFmUpdate(lastfm, "scrobble", authorisedSession, {
track: "Run To Your Grave",
artist: "The Mae Shi",
timestamp: 12345678
});
});
it("can have arbitrary parameters supplied", function() {
gently.expect(lastfm, "request", function(method, params) {
assert.equal("somevalue", params.arbitrary);
return request;
});
new LastFmUpdate(lastfm, "scrobble", authorisedSession, {
track: "Run To Your Grave",
artist: "The Mae Shi",
timestamp: 12345678,
arbitrary: "somevalue"
});
});
it("does not include handler parameters", function() {
gently.expect(lastfm, "request", function(method, params) {
assert.equal(undefined, params.handlers);
assert.equal(undefined, params.error);
assert.equal(undefined, params.success);
return request;
});
new LastFmUpdate(lastfm, "scrobble", authorisedSession, {
track: "Run To Your Grave",
artist: "The Mae Shi",
timestamp: 12345678,
handlers: { success: function() { } },
success: function() { },
error: function() { }
});
});
var tmpFn;
describe("update retries")
before(function() {
tmpFn = LastFmUpdate.prototype.scheduleCallback;
LastFmUpdate.prototype.scheduleCallback = function(callback, delay) { };
setupFixture();
andMethodIs("scrobble");
andSessionIs(authorisedSession);
andOptionsAre({
track: FakeTracks.RunToYourGrave,
timestamp: 12345678
});
});
after(function() {
LastFmUpdate.prototype.scheduleCallback = tmpFn;
});
it("a error which should trigger a retry does not bubble errors", function() {
whenRequestThrowsError(11, "Service Offline");
doNotExpectError();
});
it("service offline triggers a retry", function() {
whenRequestThrowsError(11, "Service Offline");
expectRetry();
});
it("rate limit exceeded triggers a retry", function() {
whenRequestThrowsError(29, "Rate limit exceeded");
expectRetry();
});
it("temporarily unavailable triggers a retry", function() {
whenRequestThrowsError(16, "Temporarily unavailable");
expectRetry();
});
it("nowplaying update never trigger retries", function() {
whenRequestThrowsError(16, "Temporarily unavailable");
andMethodIs("nowplaying");
expectError();
});
it("first retry schedules a request after a 10 second delay", function() {
whenRequestThrowsError(16, "Temporarily unavailable");
LastFmUpdate.prototype.scheduleCallback = gently.expect(function testSchedule(callback, delay) {
assert.equal(delay, 10000);
});
doUpdate();
});
function onNextRequests(callback, count) {
count = count || 1;
var gently = new Gently();
LastFmUpdate.prototype.scheduleCallback = gently.expect(count, callback);
doUpdate();
}
function lastRequest() {
LastFmUpdate.prototype.scheduleCallback = function() { };
}
function whenNextRequestThrowsError(request, code, message) {
whenRequestThrowsError(code, message);
request();
}
function whenNextRequestReturns(request, data) {
whenRequestReturns(data);
request();
}
it("retry triggers another request", function() {
whenRequestThrowsError(16, "Temporarily unavailable");
onNextRequests(function(nextRequest) {
lastRequest();
whenNextRequestThrowsError(nextRequest, 16, "Temporarily unavailable");
expectRetry();
});
});
it("emits succes if retry is successful", function() {
whenRequestThrowsError(16, "Temporarily unavailable");
onNextRequests(function(nextRequest) {
whenNextRequestReturns(nextRequest, FakeData.ScrobbleSuccess);
expectSuccess(function(track) {
assert.equal("Run To Your Grave", track.name);
});
});
});
it("emits succes if retry is non-retry error", function() {
whenRequestThrowsError(16, "Temporarily unavailable");
onNextRequests(function(nextRequest) {
whenNextRequestThrowsError(nextRequest, 6, "Invalid parameter");
expectError(6, "Invalid parameter");
});
});
it("retrying events include error received and delay details", function() {
whenRequestThrowsError(16, "Temporarily unavailable");
expectRetry(function(retry) {
assert.equal(retry.delay, 10000);
assert.equal(retry.error, 16);
assert.equal(retry.message, "Temporarily unavailable");
});
});
var retrySchedule = [
10 * 1000,
30 * 1000,
60 * 1000,
5 * 60 * 1000,
15 * 60 * 1000,
30 * 60 * 1000,
30 * 60 * 1000,
30 * 60 * 1000
];
it("follows a retry schedule on subsequent failures", function() {
var count = 0;
whenRequestThrowsError(16, "Temporarily unavailable");
onNextRequests(function(nextRequest, delay) {
var expectedDelay = retrySchedule[count++];
assert.equal(delay, expectedDelay);
if (count >= retrySchedule.length) {
lastRequest();
}
whenNextRequestThrowsError(nextRequest, 16, "Temporarily unavailable");
expectRetry();
}, retrySchedule.length);
});
it("includes delay in subsequent retry events", function() {
var count = 0;
whenRequestThrowsError(16, "Temporarily unavailable");
onNextRequests(function(nextRequest, delay) {
count++;
if (count >= retrySchedule.length) {
lastRequest();
}
var expectedDelay = retrySchedule[Math.min(count, retrySchedule.length - 1)];
whenNextRequestThrowsError(nextRequest, 16, "Temporarily unavailable");
expectRetry(function(retry) {
assert.equal(retry.delay, expectedDelay);
});
}, retrySchedule.length);
});
})();

16
buildfiles/app/node_modules/lastfm/tests/tests.sh generated vendored Executable file
View File

@ -0,0 +1,16 @@
#!/bin/bash
. ~/.nvm/nvm.sh
nvm use v0.2.6
node ./index.js
nvm use v0.3.3
node ./index.js
nvm use v0.4.0
node ./index.js
nvm use v0.4.3
node ./index.js
nvm use v0.4.7
node ./index.js
nvm use v0.4.8
node ./index.js
nvm use v0.6.2
node ./index.js