]> git.proxmox.com Git - extjs.git/blame - extjs/packages/core/test/specs/util/Scheduler.js
add extjs 6.0.1 sources
[extjs.git] / extjs / packages / core / test / specs / util / Scheduler.js
CommitLineData
6527f429
DM
1describe('Ext.util.Scheduler', function () {\r
2 var scheduler,\r
3 Item,\r
4 log;\r
5 var busy, idle;\r
6 var sorts = 0;\r
7\r
8 function setup () {\r
9 setup = Ext.emptyFn;\r
10\r
11 Item = Ext.define(null, {\r
12 extend: Ext.util.Schedulable,\r
13\r
14 constructor: function (name) {\r
15 this.name = name;\r
16 this.scheduler = scheduler;\r
17\r
18 this.callParent();\r
19 },\r
20\r
21 react: function () {\r
22 log.push(this.name);\r
23 },\r
24\r
25 privates: {\r
26 sort: function () {\r
27 this.scheduler.sortItems(this.depends);\r
28 }\r
29 }\r
30 });\r
31 }\r
32\r
33 beforeEach(function () {\r
34 setup();\r
35\r
36 scheduler = new Ext.util.Scheduler({\r
37 listeners: {\r
38 busy: function () {\r
39 ++busy;\r
40 },\r
41 idle: function () {\r
42 ++idle;\r
43 }\r
44 }\r
45 });\r
46\r
47 busy = idle = 0;\r
48\r
49 var sort = scheduler.sort;\r
50\r
51 scheduler.sort = function () {\r
52 ++sorts;\r
53 return sort.apply(this, arguments);\r
54 };\r
55\r
56 log = [];\r
57 sorts = 0;\r
58 });\r
59\r
60 afterEach(function () {\r
61 if (scheduler) {\r
62 scheduler.destroy();\r
63 scheduler = null;\r
64 }\r
65 expect(Ext.util.Scheduler.instances.length).toBe(0);\r
66 });\r
67\r
68 describe("notify", function() {\r
69 it("should suspend/resume on notify", function() {\r
70 var suspend = spyOn(Ext, 'suspendLayouts').andCallThrough(),\r
71 resume = spyOn(Ext, 'resumeLayouts').andCallThrough();\r
72\r
73 scheduler.notify();\r
74 expect(suspend.callCount).toBe(1);\r
75 expect(resume.callCount).toBe(1);\r
76\r
77 });\r
78 });\r
79\r
80 describe('ordering', function () {\r
81 it('should order items only on first notification', function () {\r
82 expect(sorts).toBe(0);\r
83\r
84 var item1 = new Item('item1');\r
85 var item2 = new Item('item2');\r
86\r
87 item2.depends = [item1];\r
88 scheduler.add(item2); // we add item2 then rely on its depends to get item1\r
89\r
90 item1.schedule();\r
91 item2.schedule();\r
92\r
93 expect(sorts).toBe(0);\r
94 scheduler.notify();\r
95\r
96 expect(sorts).toBe(1);\r
97 expect(log.join('/')).toBe('item1/item2');\r
98\r
99 item1.schedule();\r
100 scheduler.notify(); // no change to items so no sort\r
101\r
102 expect(sorts).toBe(1);\r
103 expect(log.join('/')).toBe('item1/item2/item1');\r
104 });\r
105\r
106 it('should react to only what was scheduled', function () {\r
107 var item1 = new Item('item1');\r
108 var item2 = new Item('item2');\r
109\r
110 item2.depends = [item1];\r
111 scheduler.add(item2); // we add item2 then rely on its depends to get item1\r
112\r
113 item1.schedule();\r
114\r
115 scheduler.notify();\r
116\r
117 expect(log.join('/')).toBe('item1');\r
118\r
119 item2.schedule();\r
120 scheduler.notify(); // no change to items so no sort\r
121\r
122 expect(sorts).toBe(1);\r
123 expect(log.join('/')).toBe('item1/item2');\r
124 });\r
125\r
126 it('should reorder items if new items are added', function () {\r
127 expect(sorts).toBe(0);\r
128\r
129 var item1 = new Item('item1');\r
130 var item2 = new Item('item2');\r
131\r
132 item2.depends = [item1];\r
133 scheduler.add(item2); // we add item2 then rely on its depends to get item1\r
134\r
135 item1.schedule();\r
136 item2.schedule();\r
137\r
138 expect(sorts).toBe(0);\r
139 scheduler.notify();\r
140\r
141 expect(sorts).toBe(1);\r
142 expect(log.join('/')).toBe('item1/item2');\r
143\r
144 var item3 = new Item('item3');\r
145\r
146 item1.depends = [item3];\r
147 log.length = 0;\r
148\r
149 item1.schedule();\r
150 item2.schedule();\r
151 item3.schedule();\r
152\r
153 expect(sorts).toBe(1);\r
154\r
155 scheduler.notify(); // no change and no sort\r
156\r
157 expect(sorts).toBe(2);\r
158 expect(log.join('/')).toBe('item3/item1/item2');\r
159 });\r
160\r
161 it('should detect dependency cycles', function () {\r
162 var item1 = new Item('item1');\r
163 var item2 = new Item('item2');\r
164\r
165 item2.depends = [item1];\r
166 item1.depends = [item2];\r
167\r
168 scheduler.add(item2);\r
169\r
170 item2.schedule();\r
171\r
172 expect(function () {\r
173 scheduler.notify();\r
174 }).toThrow();\r
175 // Scheduler calls suspendLayouts\r
176 Ext.Component.layoutSuspendCount = 0;\r
177 });\r
178 });\r
179\r
180 describe('multiple pass notifications', function () {\r
181 it('should trigger dependent items in single pass', function () {\r
182 var item1 = new Item('item1');\r
183 var item2 = new Item('item2');\r
184\r
185 item2.depends = [item1];\r
186 scheduler.add(item2); // we add item2 then rely on its depends to get item1\r
187\r
188 item1.schedule();\r
189 Ext.override(item1, {\r
190 react: function () {\r
191 item2.schedule();\r
192 return this.callParent();\r
193 }\r
194 });\r
195\r
196 expect(scheduler.passes).toBe(0);\r
197 expect(sorts).toBe(0);\r
198 scheduler.notify();\r
199\r
200 expect(scheduler.passes).toBe(1);\r
201 expect(sorts).toBe(1);\r
202 expect(log.join('/')).toBe('item1/item2');\r
203\r
204 // No changes...\r
205 scheduler.notify();\r
206\r
207 expect(scheduler.passes).toBe(1);\r
208 expect(sorts).toBe(1);\r
209 expect(log.join('/')).toBe('item1/item2');\r
210 });\r
211\r
212 it('should trigger anti-dependent items in two passes', function () {\r
213 var item1 = new Item('item1');\r
214 var item2 = new Item('item2');\r
215\r
216 item2.depends = [item1];\r
217 scheduler.add(item2); // we add item2 then rely on its depends to get item1\r
218\r
219 item2.schedule();\r
220 Ext.override(item2, {\r
221 react: function () {\r
222 item1.schedule();\r
223 return this.callParent();\r
224 }\r
225 });\r
226\r
227 expect(scheduler.passes).toBe(0);\r
228 expect(sorts).toBe(0);\r
229 scheduler.notify();\r
230\r
231 expect(scheduler.passes).toBe(2);\r
232 expect(sorts).toBe(1);\r
233 expect(log.join('/')).toBe('item2/item1');\r
234\r
235 // No changes...\r
236 scheduler.notify();\r
237\r
238 expect(scheduler.passes).toBe(2);\r
239 expect(sorts).toBe(1);\r
240 expect(log.join('/')).toBe('item2/item1');\r
241 });\r
242\r
243 it('should trigger self in two passes', function () {\r
244 var item1 = new Item('item1');\r
245 var item2 = new Item('item2');\r
246\r
247 item2.depends = [item1];\r
248 scheduler.add(item2); // we add item2 then rely on its depends to get item1\r
249\r
250 item2.schedule();\r
251 Ext.override(item2, {\r
252 react: function () {\r
253 delete this.react;\r
254 item2.schedule();\r
255 return this.callParent();\r
256 }\r
257 });\r
258\r
259 expect(scheduler.passes).toBe(0);\r
260 expect(sorts).toBe(0);\r
261 scheduler.notify();\r
262\r
263 expect(scheduler.passes).toBe(2);\r
264 expect(sorts).toBe(1);\r
265 expect(log.join('/')).toBe('item2/item2');\r
266\r
267 // No changes...\r
268 scheduler.notify();\r
269\r
270 expect(scheduler.passes).toBe(2);\r
271 expect(sorts).toBe(1);\r
272 expect(log.join('/')).toBe('item2/item2');\r
273 });\r
274\r
275 it('should limit number of cycles', function () {\r
276 var item1 = new Item('A');\r
277 var item2 = new Item('B');\r
278 var limit = 100;\r
279\r
280 item2.depends = [item1];\r
281 scheduler.add(item2); // we add item2 then rely on its depends to get item1\r
282 scheduler.setCycleLimit(4);\r
283\r
284 item2.schedule();\r
285 Ext.override(item2, {\r
286 react: function () {\r
287 if (limit-- < 0) {\r
288 return;\r
289 }\r
290 item1.schedule();\r
291 return this.callParent();\r
292 }\r
293 });\r
294 Ext.override(item1, {\r
295 react: function () {\r
296 if (limit-- < 0) {\r
297 return;\r
298 }\r
299 item2.schedule();\r
300 return this.callParent();\r
301 }\r
302 });\r
303\r
304 expect(scheduler.passes).toBe(0);\r
305 expect(sorts).toBe(0);\r
306\r
307 var exceeded;\r
308 scheduler.onCycleLimitExceeded = function () {\r
309 exceeded = true;\r
310 };\r
311\r
312 scheduler.notify();\r
313 expect(exceeded).toBe(true);\r
314\r
315 expect(scheduler.passes).toBe(4);\r
316 expect(sorts).toBe(1);\r
317 expect(log.join('')).toBe('BABABAB');\r
318\r
319 // No changes... but will aborted early so we think there is work to do\r
320 exceeded = false;\r
321 scheduler.notify();\r
322 expect(exceeded).toBe(true);\r
323\r
324 expect(scheduler.passes).toBe(8);\r
325 expect(sorts).toBe(1);\r
326 expect(log.join('')).toBe('BABABABABABABAB');\r
327 });\r
328 });\r
329\r
330 describe('busy / idle', function () {\r
331 it('should fire nothing initially', function () {\r
332 expect(busy).toBe(0);\r
333 expect(idle).toBe(0);\r
334 expect(scheduler.isBusy()).toBe(false);\r
335 expect(scheduler.isIdle()).toBe(true);\r
336\r
337 scheduler.notify();\r
338\r
339 expect(busy).toBe(0);\r
340 expect(idle).toBe(0);\r
341 expect(scheduler.isBusy()).toBe(false);\r
342 expect(scheduler.isIdle()).toBe(true);\r
343 });\r
344\r
345 it('should fire busy event', function () {\r
346 expect(busy).toBe(0);\r
347 expect(idle).toBe(0);\r
348\r
349 scheduler.adjustBusy(1);\r
350\r
351 expect(busy).toBe(1);\r
352 expect(idle).toBe(0);\r
353 expect(scheduler.isBusy()).toBe(true);\r
354 expect(scheduler.isIdle()).toBe(false);\r
355 });\r
356\r
357 it('should not fire the idle event when busy', function () {\r
358 expect(busy).toBe(0);\r
359 expect(idle).toBe(0);\r
360\r
361 scheduler.adjustBusy(1);\r
362\r
363 expect(busy).toBe(1);\r
364 expect(idle).toBe(0);\r
365\r
366 scheduler.notify();\r
367\r
368 expect(busy).toBe(1); // not twice\r
369 expect(idle).toBe(0); // still busy\r
370 expect(scheduler.isBusy()).toBe(true);\r
371 expect(scheduler.isIdle()).toBe(false);\r
372\r
373 scheduler.notify();\r
374\r
375 expect(busy).toBe(1); // not twice\r
376 expect(idle).toBe(0); // still busy\r
377 expect(scheduler.isBusy()).toBe(true);\r
378 expect(scheduler.isIdle()).toBe(false);\r
379 });\r
380\r
381 it('should fire idle event', function () {\r
382 expect(busy).toBe(0);\r
383 expect(idle).toBe(0);\r
384\r
385 scheduler.adjustBusy(1);\r
386\r
387 expect(busy).toBe(1);\r
388 expect(idle).toBe(0);\r
389\r
390 scheduler.adjustBusy(-1);\r
391\r
392 expect(busy).toBe(1); // not twice\r
393 expect(idle).toBe(0); // not yet\r
394\r
395 for (var i = 0; i < 2; ++i) {\r
396 scheduler.notify();\r
397\r
398 expect(busy).toBe(1);\r
399 expect(idle).toBe(1); // just once please\r
400 expect(scheduler.isBusy()).toBe(false);\r
401 expect(scheduler.isIdle()).toBe(true);\r
402 }\r
403 });\r
404\r
405 it('should wait to fire the idle event', function () {\r
406 expect(busy).toBe(0);\r
407 expect(idle).toBe(0);\r
408\r
409 var item1 = new Item('A');\r
410\r
411 Ext.override(item1, {\r
412 react: function () {\r
413 scheduler.adjustBusy(1);\r
414 return this.callParent();\r
415 }\r
416 });\r
417\r
418 item1.schedule();\r
419 scheduler.notify();\r
420\r
421 expect(busy).toBe(1);\r
422 expect(idle).toBe(0);\r
423 expect(scheduler.isBusy()).toBe(true);\r
424 expect(scheduler.isIdle()).toBe(false);\r
425\r
426 for (var i = 0; i < 2; ++i) {\r
427 scheduler.adjustBusy(-1); // would go idle\r
428 item1.schedule();\r
429 scheduler.notify(); // except item1 bounces back to 1\r
430\r
431 expect(busy).toBe(1);\r
432 expect(idle).toBe(0);\r
433 expect(scheduler.isBusy()).toBe(true);\r
434 expect(scheduler.isIdle()).toBe(false);\r
435\r
436 scheduler.notify(); // no change\r
437\r
438 expect(busy).toBe(1);\r
439 expect(idle).toBe(0);\r
440 expect(scheduler.isBusy()).toBe(true);\r
441 expect(scheduler.isIdle()).toBe(false);\r
442 }\r
443\r
444 scheduler.adjustBusy(-1);\r
445 scheduler.notify();\r
446\r
447 expect(busy).toBe(1);\r
448 expect(idle).toBe(1); // now\r
449 expect(scheduler.isBusy()).toBe(false);\r
450 expect(scheduler.isIdle()).toBe(true);\r
451 });\r
452 });\r
453});\r