DockerLockManagerTests.js 7.6 KB

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