DockerLockManagerTests.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /* eslint-disable
  2. no-return-assign,
  3. */
  4. // TODO: This file was created by bulk-decaffeinate.
  5. // Fix any style issues and re-enable lint.
  6. /*
  7. * decaffeinate suggestions:
  8. * DS101: Remove unnecessary use of Array.from
  9. * DS102: Remove unnecessary code created because of implicit returns
  10. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  11. */
  12. const SandboxedModule = require('sandboxed-module')
  13. const sinon = require('sinon')
  14. const modulePath = require('node:path').join(
  15. __dirname,
  16. '../../../app/js/DockerLockManager'
  17. )
  18. describe('DockerLockManager', function () {
  19. beforeEach(function () {
  20. return (this.LockManager = SandboxedModule.require(modulePath, {
  21. requires: {
  22. '@overleaf/settings': (this.Settings = { clsi: { docker: {} } }),
  23. },
  24. }))
  25. })
  26. return describe('runWithLock', function () {
  27. describe('with a single lock', function () {
  28. beforeEach(function (done) {
  29. this.callback = sinon.stub()
  30. return this.LockManager.runWithLock(
  31. 'lock-one',
  32. releaseLock =>
  33. setTimeout(() => releaseLock(null, 'hello', 'world'), 100),
  34. (err, ...args) => {
  35. this.callback(err, ...Array.from(args))
  36. return done()
  37. }
  38. )
  39. })
  40. return it('should call the callback', function () {
  41. return this.callback
  42. .calledWith(null, 'hello', 'world')
  43. .should.equal(true)
  44. })
  45. })
  46. describe('with two locks', function () {
  47. beforeEach(function (done) {
  48. this.callback1 = sinon.stub()
  49. this.callback2 = sinon.stub()
  50. this.LockManager.runWithLock(
  51. 'lock-one',
  52. releaseLock =>
  53. setTimeout(() => releaseLock(null, 'hello', 'world', 'one'), 100),
  54. (err, ...args) => {
  55. return this.callback1(err, ...Array.from(args))
  56. }
  57. )
  58. return this.LockManager.runWithLock(
  59. 'lock-two',
  60. releaseLock =>
  61. setTimeout(() => releaseLock(null, 'hello', 'world', 'two'), 200),
  62. (err, ...args) => {
  63. this.callback2(err, ...Array.from(args))
  64. return done()
  65. }
  66. )
  67. })
  68. it('should call the first callback', function () {
  69. return this.callback1
  70. .calledWith(null, 'hello', 'world', 'one')
  71. .should.equal(true)
  72. })
  73. return it('should call the second callback', function () {
  74. return this.callback2
  75. .calledWith(null, 'hello', 'world', 'two')
  76. .should.equal(true)
  77. })
  78. })
  79. return describe('with lock contention', function () {
  80. describe('where the first lock is released quickly', function () {
  81. beforeEach(function (done) {
  82. this.LockManager.MAX_LOCK_WAIT_TIME = 1000
  83. this.LockManager.LOCK_TEST_INTERVAL = 100
  84. this.callback1 = sinon.stub()
  85. this.callback2 = sinon.stub()
  86. this.LockManager.runWithLock(
  87. 'lock',
  88. releaseLock =>
  89. setTimeout(() => releaseLock(null, 'hello', 'world', 'one'), 100),
  90. (err, ...args) => {
  91. return this.callback1(err, ...Array.from(args))
  92. }
  93. )
  94. return this.LockManager.runWithLock(
  95. 'lock',
  96. releaseLock =>
  97. setTimeout(() => releaseLock(null, 'hello', 'world', 'two'), 200),
  98. (err, ...args) => {
  99. this.callback2(err, ...Array.from(args))
  100. return done()
  101. }
  102. )
  103. })
  104. it('should call the first callback', function () {
  105. return this.callback1
  106. .calledWith(null, 'hello', 'world', 'one')
  107. .should.equal(true)
  108. })
  109. return it('should call the second callback', function () {
  110. return this.callback2
  111. .calledWith(null, 'hello', 'world', 'two')
  112. .should.equal(true)
  113. })
  114. })
  115. describe('where the first lock is held longer than the waiting time', function () {
  116. beforeEach(function (done) {
  117. let doneTwo
  118. this.LockManager.MAX_LOCK_HOLD_TIME = 10000
  119. this.LockManager.MAX_LOCK_WAIT_TIME = 1000
  120. this.LockManager.LOCK_TEST_INTERVAL = 100
  121. this.callback1 = sinon.stub()
  122. this.callback2 = sinon.stub()
  123. let doneOne = (doneTwo = false)
  124. const finish = function (key) {
  125. if (key === 1) {
  126. doneOne = true
  127. }
  128. if (key === 2) {
  129. doneTwo = true
  130. }
  131. if (doneOne && doneTwo) {
  132. return done()
  133. }
  134. }
  135. this.LockManager.runWithLock(
  136. 'lock',
  137. releaseLock =>
  138. setTimeout(
  139. () => releaseLock(null, 'hello', 'world', 'one'),
  140. 1100
  141. ),
  142. (err, ...args) => {
  143. this.callback1(err, ...Array.from(args))
  144. return finish(1)
  145. }
  146. )
  147. return this.LockManager.runWithLock(
  148. 'lock',
  149. releaseLock =>
  150. setTimeout(() => releaseLock(null, 'hello', 'world', 'two'), 100),
  151. (err, ...args) => {
  152. this.callback2(err, ...Array.from(args))
  153. return finish(2)
  154. }
  155. )
  156. })
  157. it('should call the first callback', function () {
  158. return this.callback1
  159. .calledWith(null, 'hello', 'world', 'one')
  160. .should.equal(true)
  161. })
  162. return it('should call the second callback with an error', function () {
  163. const error = sinon.match.instanceOf(Error)
  164. return this.callback2.calledWith(error).should.equal(true)
  165. })
  166. })
  167. return describe('where the first lock is held longer than the max holding time', function () {
  168. beforeEach(function (done) {
  169. let doneTwo
  170. this.LockManager.MAX_LOCK_HOLD_TIME = 1000
  171. this.LockManager.MAX_LOCK_WAIT_TIME = 2000
  172. this.LockManager.LOCK_TEST_INTERVAL = 100
  173. this.callback1 = sinon.stub()
  174. this.callback2 = sinon.stub()
  175. let doneOne = (doneTwo = false)
  176. const finish = function (key) {
  177. if (key === 1) {
  178. doneOne = true
  179. }
  180. if (key === 2) {
  181. doneTwo = true
  182. }
  183. if (doneOne && doneTwo) {
  184. return done()
  185. }
  186. }
  187. this.LockManager.runWithLock(
  188. 'lock',
  189. releaseLock =>
  190. setTimeout(
  191. () => releaseLock(null, 'hello', 'world', 'one'),
  192. 1500
  193. ),
  194. (err, ...args) => {
  195. this.callback1(err, ...Array.from(args))
  196. return finish(1)
  197. }
  198. )
  199. return this.LockManager.runWithLock(
  200. 'lock',
  201. releaseLock =>
  202. setTimeout(() => releaseLock(null, 'hello', 'world', 'two'), 100),
  203. (err, ...args) => {
  204. this.callback2(err, ...Array.from(args))
  205. return finish(2)
  206. }
  207. )
  208. })
  209. it('should call the first callback', function () {
  210. return this.callback1
  211. .calledWith(null, 'hello', 'world', 'one')
  212. .should.equal(true)
  213. })
  214. return it('should call the second callback', function () {
  215. return this.callback2
  216. .calledWith(null, 'hello', 'world', 'two')
  217. .should.equal(true)
  218. })
  219. })
  220. })
  221. })
  222. })