UNPKG

10.9 kBJavaScriptView Raw
1require('./common');
2var crypto = require("crypto");
3var _ = require("underscore");
4var querystring = require("querystring");
5var fakes = require("./fakes");
6var LastFmRequest = fakes.LastFmRequest;
7
8(function() {
9 var gently, lastfm;
10 var options, expectations;
11 var notExpected;
12
13 describe("a lastfm request");
14
15 before(function() {
16 gently = new Gently();
17 options = {};
18 expectations = {
19 pairs:[],
20 handlers:[]
21 };
22 notExpected = {
23 keys:[]
24 }
25 lastfm = new LastFmNode({
26 api_key: "key",
27 secret: "secret"
28 });
29 gently.expect(GENTLY_HIJACK.hijacked.http, "request", function(options, cb) {
30 verifyCreateClient(options.port, options.host);
31 var request = new fakes.ClientRequest();
32 if (options.method == "POST") {
33 gently.expect(request, "write", function(data) {
34 verifyRequest(options.method, options.path, options.headers, data);
35 });
36 } else {
37 verifyRequest(options.method, options.path, options.headers);
38 }
39 return request;
40 });
41 });
42
43 after(function() {
44 var request = doRequest();
45 verifyHandlers(request);
46 });
47
48 function verifyCreateClient(port, host) {
49 if (expectations.port) {
50 assert.equal(expectations.port, port);
51 }
52 if (expectations.host) {
53 assert.equal(expectations.host, host);
54 }
55 }
56
57 function verifyRequest(method, url, header, data) {
58 if (expectations.url) {
59 assert.equal(expectations.url, url);
60 }
61 var pairs = querystring.parse(data || url.substr("/2.0?".length));
62 _(Object.keys(expectations.pairs)).each(function(key) {
63 assert.equal(expectations.pairs[key], pairs[key]);
64 });
65 if (expectations.signed || expectations.signatureHash) {
66 assert.ok(pairs.api_sig);
67 }
68 else if (expectations.signed === false) {
69 assert.ok(!pairs.api_sig);
70 }
71 if (expectations.signatureHash) {
72 assert.equal(expectations.signatureHash, pairs.api_sig);
73 }
74 if (expectations.method) {
75 assert.equal(expectations.method, method);
76 }
77 _(notExpected.keys).each(function(key) {
78 assert.ok(!pairs[key]);
79 });
80 if (expectations.requestData) {
81 assert.ok(data);
82 }
83 }
84
85 function whenMethodIs(method) {
86 options.method = method;
87 }
88
89 function andParamsAre(params) {
90 options.params = params;
91 }
92
93 function expectHttpMethod(method) {
94 expectations.method = method;
95 }
96
97 function expectDataPair(key, value) {
98 expectations.pairs[key] = value;
99 }
100
101 function expectSignature() {
102 expectations.signed = true;
103 }
104
105 function expectUrl(url) {
106 expectations.url = url;
107 }
108
109 function expectSignatureHashOf(unhashed) {
110 var expectedHash = crypto.createHash("md5").update(unhashed, "utf8").digest("hex");
111 expectSignatureHashToBe(expectedHash);
112 };
113
114 this.expectSignatureHashToBe = function(hash) {
115 expectations.signatureHash = hash;
116 }
117
118 function expectRequestOnPort(port) {
119 expectations.port = port;
120 }
121
122 function expectRequestToHost(host) {
123 expectations.host = host;
124 }
125
126 function expectHandlerFor(event) {
127 expectations.handlers.push(event);
128 }
129
130 function expectRequestData() {
131 expectations.requestData = true;
132 }
133
134 function doNotExpectDataKey(key) {
135 notExpected.keys.push(key);
136 }
137
138 function doRequest() {
139 return lastfm.request(options.method, options.params);
140 }
141
142 function verifyHandlers(request) {
143 _(expectations.handlers).each(function(event) {
144 var listeners = request.listeners(event);
145 assert.equal(1, listeners.length, "No handler for event: " + event);
146 });
147 }
148
149 it("default to port 80", function() {
150 whenMethodIs("any.method");
151 expectRequestOnPort(80);
152 });
153
154 it("makes request to audioscrobbler", function() {
155 whenMethodIs("any.method");
156 expectRequestToHost("ws.audioscrobbler.com");
157 });
158
159 it("always requests as json", function() {
160 whenMethodIs("any.method");
161 expectDataPair("format", "json");
162 });
163
164 it("always passes api_key", function() {
165 whenMethodIs("any.method");
166 expectDataPair("api_key", "key");
167 });
168
169 it("defaults to get request", function() {
170 whenMethodIs("any.method");
171 expectHttpMethod("GET");
172 });
173
174 it("calls the method specified", function() {
175 whenMethodIs("user.getinfo");
176 expectDataPair("method", "user.getinfo");
177 });
178
179 it("passes through parameters", function() {
180 whenMethodIs("user.getinfo");
181 andParamsAre({ user: "jammus" });
182 expectDataPair("user", "jammus");
183 });
184
185 it("converts track object to separate parameters", function() {
186 whenMethodIs("any.method");
187 andParamsAre({
188 track: {
189 artist: { "#text": "The Mae Shi" },
190 name: "Run To Your Grave",
191 mbid: "1234567890"
192 }
193 });
194 expectDataPair("artist", "The Mae Shi");
195 expectDataPair("track", "Run To Your Grave");
196 expectDataPair("mbid", "1234567890");
197 });
198
199 it("converts track object album details to separate parameters", function() {
200 whenMethodIs("any.method");
201 andParamsAre({
202 track: {
203 artist: { "#text": "The Mae Shi" },
204 name: "Run To Your Grave",
205 album: { "#text": "HLLLYH" }
206 }
207 });
208 expectDataPair("album", "HLLLYH");
209 });
210
211 it("does not overwrite explicitly set album parameters", function() {
212 whenMethodIs("any.method");
213 andParamsAre({
214 track: {
215 artist: { "#text": "The Mae Shi" },
216 name: "Run To Your Grave",
217 album: { "#text": "HLLLYH" }
218 },
219 album: "Run To Your Grave"
220 });
221 expectDataPair("album", "Run To Your Grave");
222 });
223
224 it("doesn't include mbid if one isn't supplied", function() {
225 whenMethodIs("any.method");
226 andParamsAre({
227 track: {
228 artist: { "#text": "The Mae Shi" },
229 name: "Run To Your Grave"
230 }
231 });
232 expectDataPair("artist", "The Mae Shi");
233 expectDataPair("track", "Run To Your Grave");
234 doNotExpectDataKey("mbid");
235 });
236
237 it("does not pass through event handler parameters", function() {
238 whenMethodIs("any.method");
239 andParamsAre({ handlers: "handlers", error: "error", success: "success" });
240 doNotExpectDataKey("handlers");
241 doNotExpectDataKey("error");
242 doNotExpectDataKey("success");
243 });
244
245 it("auth.getsession has signature", function() {
246 whenMethodIs("auth.getsession");
247 expectSignature();
248 });
249
250 it("attaches handlers to returned request", function() {
251 whenMethodIs("any.method");
252 andParamsAre({ handlers: {
253 error: function() {console.log("errrors");},
254 success: function() {},
255 arbitrary: function() {},
256 }});
257 expectHandlerFor("error");
258 expectHandlerFor("success");
259 expectHandlerFor("arbitrary");
260 });
261
262 it("uses signed param to force signature", function() {
263 whenMethodIs("any.method");
264 andParamsAre({
265 signed: true
266 });
267 expectSignature();
268 });
269
270 it("signature hashes api_key, method and secret", function() {
271 whenMethodIs("auth.getsession");
272 expectSignatureHashOf("api_keykeymethodauth.getsessionsecret");
273 });
274
275 it("signature includes other parameters", function() {
276 whenMethodIs("auth.getsession");
277 andParamsAre({ foo: "bar" });
278 expectSignatureHashOf("api_keykeyfoobarmethodauth.getsessionsecret");
279 });
280
281 it("signature hashes all params alphabetically", function() {
282 whenMethodIs("auth.getsession");
283 andParamsAre({ foo : "bar", baz: "bash", flip : "flop" });
284 expectSignatureHashOf("api_keykeybazbashflipflopfoobarmethodauth.getsessionsecret");
285 });
286
287 it("signature hash ignores format parameter", function() {
288 whenMethodIs("auth.getsession");
289 andParamsAre({ format: "json" });
290 expectSignatureHashOf("api_keykeymethodauth.getsessionsecret");
291 });
292
293 it("signature hash ignores handlers parameter", function() {
294 whenMethodIs("auth.getsession");
295 andParamsAre({ handlers: "handlers" });
296 expectSignatureHashOf("api_keykeymethodauth.getsessionsecret");
297 });
298
299 it("signature hash ignores write parameter", function() {
300 whenMethodIs("auth.getsession");
301 andParamsAre({ write: true });
302 expectSignatureHashOf("api_keykeymethodauth.getsessionsecret");
303 });
304
305 it("signature hash ignores signed parameter", function() {
306 whenMethodIs("any.method");
307 andParamsAre({ signed: true });
308 expectSignatureHashOf("api_keykeymethodany.methodsecret");
309 });
310
311 it("signature hash handles high characters as expected by last.fm (utf8)", function() {
312 whenMethodIs("auth.getsession");
313 andParamsAre({ track: "Tony’s Theme (Remastered)" });
314 expectSignatureHashToBe("15f5159046bf1e76774b9dd46a4ed993");
315 });
316
317 it("signature hash treats undefined values as blank", function() {
318 whenMethodIs("any.method");
319 andParamsAre({ signed: true, track: 'Replicating Networks', artist: 'Rabbit Milk', albumArtist: undefined });
320 expectSignatureHashOf("albumArtistapi_keykeyartistRabbit Milkmethodany.methodtrackReplicating Networkssecret");
321 });
322
323 it("signature hash treats null values as blank", function() {
324 whenMethodIs("any.method");
325 andParamsAre({ signed: true, track: 'Replicating Networks', artist: 'Rabbit Milk', albumArtist: null });
326 expectSignatureHashOf("albumArtistapi_keykeyartistRabbit Milkmethodany.methodtrackReplicating Networkssecret");
327 });
328
329 it("write requests use post", function() {
330 whenMethodIs("any.method");
331 andParamsAre({ write: true });
332 expectHttpMethod("POST");
333 });
334
335 it("write requests don't use get parameters", function() {
336 whenMethodIs("any.method");
337 andParamsAre({ write: true });
338 expectUrl("/2.0");
339 });
340
341 it("write requests send data in request", function() {
342 whenMethodIs("any.method");
343 andParamsAre({
344 write: true,
345 foo: "bar"
346 });
347 expectRequestData();
348 expectDataPair("foo", "bar");
349 });
350
351 it("write requests are always signed", function() {
352 whenMethodIs("album.removeTag");
353 andParamsAre({
354 write: true
355 });
356 expectSignature();
357 });
358
359 _(["album.addTags", "album.removeTag", "album.share",
360 "artist.addTags", "artist.removeTag", "artist.share", "artist.shout",
361 "event.attend", "event.share", "event.shout",
362 "library.addAlbum", "library.addArtist", "library.addTrack",
363 "playlist.addTrack", "playlist.create",
364 "radio.tune",
365 "track.addTags", "track.ban", "track.love", "track.removeTag",
366 "track.scrobble", "track.share", "track.unban", "track.unlove",
367 "track.updateNowPlaying",
368 "user.shout"]).each(function(method) {
369 it(method + " is a write (post) request", function() {
370 whenMethodIs(method);
371 expectHttpMethod("POST");
372 });
373 });
374
375 _(["auth.getMobileSession", "auth.getSession", "auth.getToken",
376 "radio.getPlaylist"]).each(function(method) {
377 it(method + " is signed", function() {
378 whenMethodIs(method);
379 expectSignature();
380 });
381 });
382})();