1 | 'use strict';
|
2 |
|
3 | var test = require('tap').test
|
4 | , EventEmitter = require('events').EventEmitter
|
5 | , cls = require('../context.js')
|
6 | ;
|
7 |
|
8 | function fresh(name, context) {
|
9 | context.tearDown(function () {
|
10 | cls.destroyNamespace(name);
|
11 | });
|
12 | return cls.createNamespace(name);
|
13 | }
|
14 |
|
15 | test("event emitters bound to CLS context", function (t) {
|
16 | t.plan(12);
|
17 |
|
18 | t.test("handler registered in context", function (t) {
|
19 | t.plan(1);
|
20 |
|
21 | var n = fresh('in', this)
|
22 | , ee = new EventEmitter()
|
23 | ;
|
24 |
|
25 | n.run(function () {
|
26 | n.set('value', 'hello');
|
27 | n.bindEmitter(ee);
|
28 | ee.on('event', function () {
|
29 | t.equal(n.get('value'), 'hello', "value still set in EE.");
|
30 | });
|
31 | });
|
32 |
|
33 | ee.emit('event');
|
34 | });
|
35 |
|
36 | t.test("once handler registered in context", function (t) {
|
37 | t.plan(1);
|
38 |
|
39 | var n = fresh('inOnce', this)
|
40 | , ee = new EventEmitter()
|
41 | ;
|
42 |
|
43 | n.run(function () {
|
44 | n.set('value', 'hello');
|
45 | n.bindEmitter(ee);
|
46 | ee.once('event', function () {
|
47 | t.equal(n.get('value'), 'hello', "value still set in EE.");
|
48 | });
|
49 | });
|
50 |
|
51 | ee.emit('event');
|
52 | });
|
53 |
|
54 | t.test("handler registered out of context", function (t) {
|
55 | t.plan(1);
|
56 |
|
57 | var n = fresh('out', this)
|
58 | , ee = new EventEmitter()
|
59 | ;
|
60 |
|
61 | ee.on('event', function () {
|
62 | t.equal(n.get('value'), 'hello', "value still set in EE.");
|
63 | });
|
64 |
|
65 | n.run(function () {
|
66 | n.set('value', 'hello');
|
67 | n.bindEmitter(ee);
|
68 |
|
69 | ee.emit('event');
|
70 | });
|
71 | });
|
72 |
|
73 | t.test("once handler registered out of context", function (t) {
|
74 | t.plan(1);
|
75 |
|
76 | var n = fresh('outOnce', this)
|
77 | , ee = new EventEmitter()
|
78 | ;
|
79 |
|
80 | ee.once('event', function () {
|
81 | t.equal(n.get('value'), 'hello', "value still set in EE.");
|
82 | });
|
83 |
|
84 | n.run(function () {
|
85 | n.set('value', 'hello');
|
86 | n.bindEmitter(ee);
|
87 |
|
88 | ee.emit('event');
|
89 | });
|
90 | });
|
91 |
|
92 | t.test("once handler registered out of context on Readable", function (t) {
|
93 | var Readable = require('stream').Readable;
|
94 |
|
95 | if (Readable) {
|
96 | t.plan(12);
|
97 |
|
98 | var n = fresh('outOnceReadable', this)
|
99 | , re = new Readable()
|
100 | ;
|
101 |
|
102 | re._read = function () {};
|
103 |
|
104 | t.ok(n.name, "namespace has a name");
|
105 | t.equal(n.name, 'outOnceReadable', "namespace has a name");
|
106 |
|
107 | re.once('data', function (data) {
|
108 | t.equal(n.get('value'), 'hello', "value still set in EE");
|
109 | t.equal(data, 'blah', "emit still works");
|
110 | });
|
111 |
|
112 | n.run(function () {
|
113 | n.set('value', 'hello');
|
114 |
|
115 | t.notOk(re.emit.__wrapped, "emit is not wrapped");
|
116 | t.notOk(re.on.__wrapped, "on is not wrapped");
|
117 | t.notOk(re.addListener.__wrapped, "addListener is not wrapped");
|
118 |
|
119 | n.bindEmitter(re);
|
120 |
|
121 | t.ok(re.emit.__wrapped, "emit is wrapped");
|
122 | t.ok(re.on.__wrapped, "on is wrapped");
|
123 | t.ok(re.addListener.__wrapped, "addListener is wrapped");
|
124 |
|
125 | t.equal(typeof re._events.data, 'function', 'only the one data listener');
|
126 | t.notOk(re._events.data['context@outOnceReadable'], "context isn't on listener");
|
127 |
|
128 | re.emit('data', 'blah');
|
129 | });
|
130 | }
|
131 | else {
|
132 | t.comment("this test requires node 0.10+");
|
133 | t.end();
|
134 | }
|
135 | });
|
136 |
|
137 | t.test("emitter with newListener that removes handler", function (t) {
|
138 | t.plan(3);
|
139 |
|
140 | var n = fresh('newListener', this)
|
141 | , ee = new EventEmitter()
|
142 | ;
|
143 |
|
144 |
|
145 | n.bindEmitter(ee);
|
146 |
|
147 | function listen() {
|
148 | ee.on('data', function (chunk) {
|
149 | t.equal(chunk, 'chunk', 'listener still works');
|
150 | });
|
151 | }
|
152 |
|
153 | ee.on('newListener', function handler(event) {
|
154 | if (event !== 'data') return;
|
155 |
|
156 | this.removeListener('newListener', handler);
|
157 | t.notOk(this.listeners('newListener').length, 'newListener was removed');
|
158 | process.nextTick(listen);
|
159 | });
|
160 |
|
161 | ee.on('drain', function (chunk) {
|
162 | process.nextTick(function () {
|
163 | ee.emit('data', chunk);
|
164 | });
|
165 | });
|
166 |
|
167 | ee.on('data', function (chunk) {
|
168 | t.equal(chunk, 'chunk', 'got data event');
|
169 | });
|
170 |
|
171 | ee.emit('drain', 'chunk');
|
172 | });
|
173 |
|
174 | t.test("handler registered in context on Readable", function (t) {
|
175 | var Readable = require('stream').Readable;
|
176 |
|
177 | if (Readable) {
|
178 | t.plan(12);
|
179 |
|
180 | var n = fresh('outOnReadable', this)
|
181 | , re = new Readable()
|
182 | ;
|
183 |
|
184 | re._read = function () {};
|
185 |
|
186 | t.ok(n.name, "namespace has a name");
|
187 | t.equal(n.name, 'outOnReadable', "namespace has a name");
|
188 |
|
189 | n.run(function () {
|
190 | n.set('value', 'hello');
|
191 |
|
192 | n.bindEmitter(re);
|
193 |
|
194 | t.ok(re.emit.__wrapped, "emit is wrapped");
|
195 | t.ok(re.on.__wrapped, "on is wrapped");
|
196 | t.ok(re.addListener.__wrapped, "addListener is wrapped");
|
197 |
|
198 | re.on('data', function (data) {
|
199 | t.equal(n.get('value'), 'hello', "value still set in EE");
|
200 | t.equal(data, 'blah', "emit still works");
|
201 | });
|
202 | });
|
203 |
|
204 | t.ok(re.emit.__wrapped, "emit is still wrapped");
|
205 | t.ok(re.on.__wrapped, "on is still wrapped");
|
206 | t.ok(re.addListener.__wrapped, "addListener is still wrapped");
|
207 |
|
208 | t.equal(typeof re._events.data, 'function', 'only the one data listener');
|
209 | t.ok(re._events.data['cls@contexts']['context@outOnReadable'],
|
210 | "context is bound to listener");
|
211 |
|
212 | re.emit('data', 'blah');
|
213 | }
|
214 | else {
|
215 | t.comment("this test requires node 0.10+");
|
216 | t.end();
|
217 | }
|
218 | });
|
219 |
|
220 | t.test("handler added but used entirely out of context", function (t) {
|
221 | t.plan(2);
|
222 |
|
223 | var n = fresh('none', this)
|
224 | , ee = new EventEmitter()
|
225 | ;
|
226 |
|
227 | n.run(function () {
|
228 | n.set('value', 'hello');
|
229 | n.bindEmitter(ee);
|
230 | });
|
231 |
|
232 | ee.on('event', function () {
|
233 | t.ok(n, "n is set");
|
234 | t.notOk(n.get('value'), "value shouldn't be visible");
|
235 | });
|
236 |
|
237 | ee.emit('event');
|
238 | });
|
239 |
|
240 | t.test("handler added but no listeners registered", function (t) {
|
241 | t.plan(3);
|
242 |
|
243 | var http = require('http')
|
244 | , n = fresh('no_listener', this)
|
245 | ;
|
246 |
|
247 |
|
248 | var server = http.createServer(function (req, res) {
|
249 | n.bindEmitter(req);
|
250 |
|
251 | t.doesNotThrow(function () {
|
252 | req.emit('event');
|
253 | });
|
254 |
|
255 | res.writeHead(200, {"Content-Length" : 4});
|
256 | res.end('WORD');
|
257 | });
|
258 | server.listen(8080);
|
259 |
|
260 | http.get('http://localhost:8080/', function (res) {
|
261 | t.equal(res.statusCode, 200, "request came back OK");
|
262 |
|
263 | res.setEncoding('ascii');
|
264 | res.on('data', function (body) {
|
265 | t.equal(body, 'WORD');
|
266 |
|
267 | server.close();
|
268 | });
|
269 | });
|
270 | });
|
271 |
|
272 | t.test("listener with parameters added but not bound to context", function (t) {
|
273 | t.plan(2);
|
274 |
|
275 | var ee = new EventEmitter()
|
276 | , n = fresh('param_list', this)
|
277 | ;
|
278 |
|
279 | function sent(value) {
|
280 | t.equal(value, 3, "sent value is correct");
|
281 | }
|
282 |
|
283 | ee.on('send', sent);
|
284 | n.bindEmitter(ee);
|
285 | t.doesNotThrow(function () {
|
286 | ee.emit('send', 3);
|
287 | });
|
288 | });
|
289 |
|
290 | t.test("listener that throws doesn't leave removeListener wrapped", function (t) {
|
291 | t.plan(4);
|
292 |
|
293 | var ee = new EventEmitter()
|
294 | , n = fresh('kaboom', this)
|
295 | ;
|
296 |
|
297 | n.bindEmitter(ee);
|
298 |
|
299 | function kaboom() {
|
300 | throw new Error('whoops');
|
301 | }
|
302 |
|
303 | n.run(function () {
|
304 | ee.on('bad', kaboom);
|
305 |
|
306 | t.throws(function () { ee.emit('bad'); });
|
307 | t.equal(typeof ee.removeListener, 'function', 'removeListener is still there');
|
308 | t.notOk(ee.removeListener.__wrapped, "removeListener got unwrapped");
|
309 | t.equal(ee._events.bad, kaboom, "listener isn't still bound");
|
310 | });
|
311 | });
|
312 |
|
313 | t.test("emitter bound to multiple namespaces handles them correctly", function (t) {
|
314 | t.plan(8);
|
315 |
|
316 | var ee = new EventEmitter()
|
317 | , ns1 = cls.createNamespace('1')
|
318 | , ns2 = cls.createNamespace('2')
|
319 | ;
|
320 |
|
321 |
|
322 | setTimeout(function () {
|
323 | ee.emit('data', 'hi');
|
324 | }, 10);
|
325 |
|
326 | t.doesNotThrow(function () { ns1.bindEmitter(ee); });
|
327 | t.doesNotThrow(function () { ns2.bindEmitter(ee); });
|
328 |
|
329 | ns1.run(function () {
|
330 | ns2.run(function () {
|
331 | ns1.set('name', 'tom1');
|
332 | ns2.set('name', 'tom2');
|
333 |
|
334 | t.doesNotThrow(function () { ns1.bindEmitter(ee); });
|
335 | t.doesNotThrow(function () { ns2.bindEmitter(ee); });
|
336 |
|
337 | ns1.run(function () {
|
338 | process.nextTick(function () {
|
339 | t.equal(ns1.get('name'), 'tom1', "ns1 value correct");
|
340 | t.equal(ns2.get('name'), 'tom2', "ns2 value correct");
|
341 |
|
342 | ns1.set('name', 'bob');
|
343 | ns2.set('name', 'alice');
|
344 |
|
345 | ee.on('data', function () {
|
346 | t.equal(ns1.get('name'), 'bob', "ns1 value bound onto emitter");
|
347 | t.equal(ns2.get('name'), 'alice', "ns2 value bound onto emitter");
|
348 | });
|
349 | });
|
350 | });
|
351 | });
|
352 | });
|
353 | });
|
354 | });
|