UNPKG

9.35 kBJavaScriptView Raw
1'use strict';
2
3var EventEmitter = require('events').EventEmitter
4 , assert = require('assert')
5 , test = require('tap').test
6 , cls = require('../context.js')
7 ;
8
9var nextID = 1;
10function fresh(name, test) {
11 assert.ok(!cls.getNamespace(name), "namespace " + name + " already exists");
12
13 // set it up for demolition immediately
14 test.tearDown(function () {
15 cls.destroyNamespace(name);
16 assert.ok(!cls.getNamespace(name), "namespace " + name + " should no longer exist");
17 });
18 return cls.createNamespace(name);
19}
20
21function runInTransaction(name, fn) {
22 var namespace = cls.getNamespace(name);
23 assert(namespace, "namespaces " + name + " doesn't exist");
24
25 var context = namespace.createContext();
26 context.transaction = ++nextID;
27 process.nextTick(namespace.bind(fn, context));
28}
29
30test("asynchronous state propagation", function (t) {
31 t.plan(12);
32
33 t.test("a. async transaction with setTimeout", function (t) {
34 t.plan(2);
35
36 var namespace = fresh('a', this);
37
38 function handler() {
39 t.ok(namespace.get('transaction'), "transaction should be visible");
40 }
41
42 t.notOk(namespace.get('transaction'), "transaction should not yet be visible");
43 runInTransaction('a', function () { setTimeout(handler, 100); });
44 });
45
46 t.test("b. async transaction with setInterval", function (t) {
47 t.plan(4);
48
49 var namespace = fresh('b', this)
50 , count = 0
51 , handle
52 ;
53
54 function handler() {
55 count += 1;
56 if (count > 2) clearInterval(handle);
57 t.ok(namespace.get('transaction'), "transaction should be visible");
58 }
59
60 t.notOk(namespace.get('transaction'), "transaction should not yet be visible");
61 runInTransaction('b', function () { handle = setInterval(handler, 50); });
62 });
63
64 t.test("c. async transaction with process.nextTick", function (t) {
65 t.plan(2);
66
67 var namespace = fresh('c', this);
68
69 function handler() {
70 t.ok(namespace.get('transaction'), "transaction should be visible");
71 }
72
73 t.notOk(namespace.get('transaction'), "transaction should not yet be visible");
74 runInTransaction('c', function () { process.nextTick(handler); });
75 });
76
77 t.test("d. async transaction with EventEmitter.emit", function (t) {
78 t.plan(2);
79
80 var namespace = fresh('d', this)
81 , ee = new EventEmitter()
82 ;
83
84 function handler() {
85 t.ok(namespace.get('transaction'), "transaction should be visible");
86 }
87
88 t.notOk(namespace.get('transaction'), "transaction should not yet be visible");
89 runInTransaction('d', function () {
90 ee.on('transaction', handler);
91 ee.emit('transaction');
92 });
93 });
94
95 t.test("e. two overlapping async transactions with setTimeout", function (t) {
96 t.plan(6);
97
98 var namespace = fresh('e', this)
99 , first
100 , second
101 ;
102
103 function handler(id) {
104 t.ok(namespace.get('transaction'), "transaction should be visible");
105 t.equal(namespace.get('transaction'), id, "transaction matches");
106 }
107
108 t.notOk(namespace.get('transaction'), "transaction should not yet be visible");
109 runInTransaction('e', function () {
110 first = namespace.get('transaction');
111 setTimeout(handler.bind(null, first), 100);
112 });
113
114 setTimeout(function () {
115 runInTransaction('e', function () {
116 second = namespace.get('transaction');
117 t.notEqual(first, second, "different transaction IDs");
118 setTimeout(handler.bind(null, second), 100);
119 });
120 }, 25);
121 });
122
123 t.test("f. two overlapping async transactions with setInterval", function (t) {
124 t.plan(15);
125
126 var namespace = fresh('f', this);
127
128 function runInterval() {
129 var count = 0
130 , handle
131 , id
132 ;
133
134 function handler() {
135 count += 1;
136 if (count > 2) clearInterval(handle);
137 t.ok(namespace.get('transaction'), "transaction should be visible");
138 t.equal(id, namespace.get('transaction'), "transaction ID should be immutable");
139 }
140
141 function run() {
142 t.ok(namespace.get('transaction'), "transaction should have been created");
143 id = namespace.get('transaction');
144 handle = setInterval(handler, 50);
145 }
146
147 runInTransaction('f', run);
148 }
149
150 t.notOk(namespace.get('transaction'), "transaction should not yet be visible");
151 runInterval(); runInterval();
152 });
153
154 t.test("g. two overlapping async transactions with process.nextTick", function (t) {
155 t.plan(6);
156
157 var namespace = fresh('g', this)
158 , first
159 , second
160 ;
161
162 function handler(id) {
163 var transaction = namespace.get('transaction');
164 t.ok(transaction, "transaction should be visible");
165 t.equal(transaction, id, "transaction matches");
166 }
167
168 t.notOk(namespace.get('transaction'), "transaction should not yet be visible");
169 runInTransaction('g', function () {
170 first = namespace.get('transaction');
171 process.nextTick(handler.bind(null, first));
172 });
173
174 process.nextTick(function () {
175 runInTransaction('g', function () {
176 second = namespace.get('transaction');
177 t.notEqual(first, second, "different transaction IDs");
178 process.nextTick(handler.bind(null, second));
179 });
180 });
181 });
182
183 t.test("h. two overlapping async runs with EventEmitter.prototype.emit", function (t) {
184 t.plan(3);
185
186 var namespace = fresh('h', this)
187 , ee = new EventEmitter()
188 ;
189
190 function handler() {
191 t.ok(namespace.get('transaction'), "transaction should be visible");
192 }
193
194 function lifecycle() {
195 ee.once('transaction', process.nextTick.bind(process, handler));
196 ee.emit('transaction');
197 }
198
199 t.notOk(namespace.get('transaction'), "transaction should not yet be visible");
200 runInTransaction('h', lifecycle);
201 runInTransaction('h', lifecycle);
202 });
203
204 t.test("i. async transaction with an async sub-call with setTimeout", function (t) {
205 t.plan(5);
206
207 var namespace = fresh('i', this);
208
209 function inner(callback) {
210 setTimeout(function () {
211 t.ok(namespace.get('transaction'), "transaction should (yep) still be visible");
212 callback();
213 }, 50);
214 }
215
216 function outer() {
217 t.ok(namespace.get('transaction'), "transaction should be visible");
218 setTimeout(function () {
219 t.ok(namespace.get('transaction'), "transaction should still be visible");
220 inner(function () {
221 t.ok(namespace.get('transaction'), "transaction should even still be visible");
222 });
223 }, 50);
224 }
225
226 t.notOk(namespace.get('transaction'), "transaction should not yet be visible");
227 runInTransaction('i', setTimeout.bind(null, outer, 50));
228 });
229
230 t.test("j. async transaction with an async sub-call with setInterval", function (t) {
231 t.plan(5);
232
233 var namespace = fresh('j', this)
234 , outerHandle
235 , innerHandle
236 ;
237
238 function inner(callback) {
239 innerHandle = setInterval(function () {
240 clearInterval(innerHandle);
241 t.ok(namespace.get('transaction'), "transaction should (yep) still be visible");
242 callback();
243 }, 50);
244 }
245
246 function outer() {
247 t.ok(namespace.get('transaction'), "transaction should be visible");
248 outerHandle = setInterval(function () {
249 clearInterval(outerHandle);
250 t.ok(namespace.get('transaction'), "transaction should still be visible");
251 inner(function () {
252 t.ok(namespace.get('transaction'), "transaction should even still be visible");
253 });
254 }, 50);
255 }
256
257 t.notOk(namespace.get('transaction'), "transaction should not yet be visible");
258 runInTransaction('j', outer);
259 });
260
261 t.test("k. async transaction with an async call with process.nextTick", function (t) {
262 t.plan(5);
263
264 var namespace = fresh('k', this);
265
266 function inner(callback) {
267 process.nextTick(function () {
268 t.ok(namespace.get('transaction'), "transaction should (yep) still be visible");
269 callback();
270 });
271 }
272
273 function outer() {
274 t.ok(namespace.get('transaction'), "transaction should be visible");
275 process.nextTick(function () {
276 t.ok(namespace.get('transaction'), "transaction should still be visible");
277 inner(function () {
278 t.ok(namespace.get('transaction'), "transaction should even still be visible");
279 });
280 });
281 }
282
283 t.notOk(namespace.get('transaction'), "transaction should not yet be visible");
284 runInTransaction('k', function () { process.nextTick(outer); });
285 });
286
287 t.test("l. async transaction with an async call with EventEmitter.emit", function (t) {
288 t.plan(4);
289
290 var namespace = fresh('l', this)
291 , outer = new EventEmitter()
292 , inner = new EventEmitter()
293 ;
294
295 inner.on('pong', function (callback) {
296 t.ok(namespace.get('transaction'), "transaction should still be visible");
297 callback();
298 });
299
300 function outerCallback() {
301 t.ok(namespace.get('transaction'), "transaction should even still be visible");
302 }
303
304 outer.on('ping', function () {
305 t.ok(namespace.get('transaction'), "transaction should be visible");
306 inner.emit('pong', outerCallback);
307 });
308
309 t.notOk(namespace.get('transaction'), "transaction should not yet be visible");
310 runInTransaction('l', outer.emit.bind(outer, 'ping'));
311 });
312});