PriorityQueue.test.js 5.0 KB

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