PriorityQueue.test.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. import { PriorityQueue } from '../src/utilities/PriorityQueue.js';
  2. const nextFrame = () => new Promise( resolve => requestAnimationFrame( resolve ) );
  3. const nextTick = () => new Promise( resolve => process.nextTick( resolve ) );
  4. describe( 'PriorityQueue', () => {
  5. it( 'should run jobs automatically in the correct order.', async () => {
  6. const queue = new PriorityQueue();
  7. queue.maxJobs = 6;
  8. queue.priorityCallback = item => item.priority;
  9. queue.add( { priority: 6 }, () => new Promise( () => {} ) );
  10. queue.add( { priority: 3 }, () => new Promise( () => {} ) );
  11. queue.add( { priority: 4 }, () => new Promise( () => {} ) );
  12. queue.add( { priority: 0 }, () => new Promise( () => {} ) );
  13. queue.add( { priority: 8 }, () => new Promise( () => {} ) );
  14. queue.add( { priority: 2 }, () => new Promise( () => {} ) );
  15. queue.add( { priority: 1 }, () => new Promise( () => {} ) );
  16. await nextFrame();
  17. expect( queue.items.map( item => item.priority ) ).toEqual( [ 0 ] );
  18. expect( queue.currJobs ).toEqual( 6 );
  19. } );
  20. it( 'should run jobs in the correct order.', async () => {
  21. const result = [];
  22. const cb = item => new Promise( resolve => {
  23. result.push( item.priority );
  24. resolve();
  25. } );
  26. const queue = new PriorityQueue();
  27. queue.maxJobs = 1;
  28. queue.priorityCallback = item => item.priority;
  29. queue.add( { priority: 6 }, cb );
  30. queue.add( { priority: 3 }, cb );
  31. queue.add( { priority: 4 }, cb );
  32. queue.add( { priority: 0 }, cb );
  33. queue.add( { priority: 8 }, cb );
  34. queue.add( { priority: 2 }, cb );
  35. queue.add( { priority: 1 }, cb );
  36. expect( queue.items.length ).toEqual( queue.callbacks.size );
  37. // We require a new frame to trigger each subsequent task
  38. for ( let i = 0; i < 7; i ++ ) {
  39. await nextFrame();
  40. }
  41. expect( result ).toEqual( [ 8, 6, 4, 3, 2, 1, 0 ] );
  42. expect( queue.items.length ).toEqual( queue.callbacks.size );
  43. } );
  44. it( 'should remove an item from the queue correctly.', () => {
  45. const A = { priority: 0 };
  46. const B = { priority: 1 };
  47. const C = { priority: 2 };
  48. const D = { priority: 3 };
  49. const queue = new PriorityQueue();
  50. queue.priorityCallback = item => item.priority;
  51. queue.add( A, () => new Promise( () => {} ) );
  52. queue.add( B, () => new Promise( () => {} ) );
  53. queue.add( C, () => new Promise( () => {} ) );
  54. queue.add( D, () => new Promise( () => {} ) );
  55. queue.sort();
  56. expect( queue.items ).toEqual( [ A, B, C, D ] );
  57. queue.remove( C );
  58. expect( queue.items ).toEqual( [ A, B, D ] );
  59. queue.remove( A );
  60. expect( queue.items ).toEqual( [ B, D ] );
  61. queue.remove( B );
  62. expect( queue.items ).toEqual( [ D ] );
  63. queue.remove( D );
  64. expect( queue.items ).toEqual( [] );
  65. expect( queue.items.length ).toEqual( queue.callbacks.size );
  66. } );
  67. it( 'should automatically run new jobs when one is finished.', async () => {
  68. let called = 0;
  69. let resolveFunc = null;
  70. const queue = new PriorityQueue();
  71. queue.maxJobs = 1;
  72. queue.priorityCallback = item => item.priority;
  73. queue.add( { priority: 1 }, () => new Promise( resolve => {
  74. resolveFunc = resolve;
  75. called ++;
  76. } ) );
  77. queue.add( { priority: 0 }, () => new Promise( () => {
  78. called ++;
  79. } ) );
  80. expect( queue.currJobs ).toEqual( 0 );
  81. await nextFrame();
  82. expect( queue.currJobs ).toEqual( 1 );
  83. expect( resolveFunc ).not.toEqual( null );
  84. expect( called ).toEqual( 1 );
  85. resolveFunc();
  86. // one frame for resolving the promise, one frame schedule new
  87. // tasks, and one frame to complete the last one.
  88. await nextFrame();
  89. await nextFrame();
  90. expect( queue.currJobs ).toEqual( 1 );
  91. expect( called ).toEqual( 2 );
  92. } );
  93. it( 'should fire the callback with the item and priority.', async () => {
  94. const A = { priority: 100 };
  95. const queue = new PriorityQueue();
  96. queue.priorityCallback = item => item.priority;
  97. queue.add( A, item => new Promise( () => {
  98. expect( item ).toEqual( A );
  99. } ) );
  100. await nextFrame();
  101. } );
  102. it( 'should return a promise that resolves from the add function.', async () => {
  103. const queue = new PriorityQueue();
  104. queue.priorityCallback = item => item.priority;
  105. let result = null;
  106. queue.add( { priority: 0 }, item => Promise.resolve( 1000 ) ).then( res => result = res );
  107. expect( result ).toEqual( null );
  108. await nextFrame();
  109. expect( result ).toEqual( 1000 );
  110. } );
  111. it( 'should not automatically run if autoUpdate is false.', async () => {
  112. const queue = new PriorityQueue();
  113. queue.priorityCallback = () => 0;
  114. queue.autoUpdate = false;
  115. queue.maxJobs = 1;
  116. queue.add( {}, async () => {} );
  117. queue.add( {}, async () => {} );
  118. expect( queue.items ).toHaveLength( 2 );
  119. await nextFrame();
  120. expect( queue.items ).toHaveLength( 2 );
  121. queue.scheduleJobRun();
  122. await nextFrame();
  123. expect( queue.items ).toHaveLength( 1 );
  124. await nextFrame();
  125. expect( queue.items ).toHaveLength( 1 );
  126. queue.scheduleJobRun();
  127. await nextFrame();
  128. expect( queue.items ).toHaveLength( 0 );
  129. } );
  130. } );