|
@@ -0,0 +1,90 @@
|
|
|
|
|
+sinon = require('sinon')
|
|
|
|
|
+chai = require('chai')
|
|
|
|
|
+should = chai.should()
|
|
|
|
|
+expect = chai.expect
|
|
|
|
|
+modulePath = "../../../../app/js/RateLimitManager.js"
|
|
|
|
|
+SandboxedModule = require('sandboxed-module')
|
|
|
|
|
+
|
|
|
|
|
+describe "RateLimitManager", ->
|
|
|
|
|
+ beforeEach ->
|
|
|
|
|
+ @RateLimitManager = SandboxedModule.require modulePath, requires:
|
|
|
|
|
+ "logger-sharelatex": @logger = { log: sinon.stub() }
|
|
|
|
|
+ "settings-sharelatex": @settings =
|
|
|
|
|
+ redis:
|
|
|
|
|
+ realtime: {}
|
|
|
|
|
+ "./Metrics": @Metrics =
|
|
|
|
|
+ Timer: class Timer
|
|
|
|
|
+ done: sinon.stub()
|
|
|
|
|
+ gauge: sinon.stub()
|
|
|
|
|
+ @callback = sinon.stub()
|
|
|
|
|
+ @RateLimiter = new @RateLimitManager(1)
|
|
|
|
|
+
|
|
|
|
|
+ describe "for a single task", ->
|
|
|
|
|
+ beforeEach ->
|
|
|
|
|
+ @task = sinon.stub()
|
|
|
|
|
+ @RateLimiter.run @task, @callback
|
|
|
|
|
+
|
|
|
|
|
+ it "should execute the task in the background", ->
|
|
|
|
|
+ @task.called.should.equal true
|
|
|
|
|
+
|
|
|
|
|
+ it "should call the callback", ->
|
|
|
|
|
+ @callback.called.should.equal true
|
|
|
|
|
+
|
|
|
|
|
+ it "should finish with a worker count of one", ->
|
|
|
|
|
+ # because it's in the background
|
|
|
|
|
+ expect(@RateLimiter.ActiveWorkerCount).to.equal 1
|
|
|
|
|
+
|
|
|
|
|
+ describe "for multiple tasks", ->
|
|
|
|
|
+ beforeEach (done) ->
|
|
|
|
|
+ @task = sinon.stub()
|
|
|
|
|
+ @finalTask = sinon.stub()
|
|
|
|
|
+ task = (cb) =>
|
|
|
|
|
+ @task()
|
|
|
|
|
+ setTimeout cb, 100
|
|
|
|
|
+ finalTask = (cb) =>
|
|
|
|
|
+ @finalTask()
|
|
|
|
|
+ setTimeout cb, 100
|
|
|
|
|
+ @RateLimiter.run task, @callback
|
|
|
|
|
+ @RateLimiter.run task, @callback
|
|
|
|
|
+ @RateLimiter.run task, @callback
|
|
|
|
|
+ @RateLimiter.run finalTask, (err) =>
|
|
|
|
|
+ @callback(err)
|
|
|
|
|
+ done()
|
|
|
|
|
+
|
|
|
|
|
+ it "should execute the first three tasks", ->
|
|
|
|
|
+ @task.calledThrice.should.equal true
|
|
|
|
|
+
|
|
|
|
|
+ it "should execute the final task", ->
|
|
|
|
|
+ @finalTask.called.should.equal true
|
|
|
|
|
+
|
|
|
|
|
+ it "should call the callback", ->
|
|
|
|
|
+ @callback.called.should.equal true
|
|
|
|
|
+
|
|
|
|
|
+ it "should finish with worker count of zero", ->
|
|
|
|
|
+ expect(@RateLimiter.ActiveWorkerCount).to.equal 0
|
|
|
|
|
+
|
|
|
|
|
+ describe "for a mixture of long-running tasks", ->
|
|
|
|
|
+ beforeEach (done) ->
|
|
|
|
|
+ @task = sinon.stub()
|
|
|
|
|
+ @finalTask = sinon.stub()
|
|
|
|
|
+ finalTask = (cb) =>
|
|
|
|
|
+ @finalTask()
|
|
|
|
|
+ setTimeout cb, 100
|
|
|
|
|
+ @RateLimiter.run @task, @callback
|
|
|
|
|
+ @RateLimiter.run @task, @callback
|
|
|
|
|
+ @RateLimiter.run @task, @callback
|
|
|
|
|
+ @RateLimiter.run finalTask, (err) =>
|
|
|
|
|
+ @callback(err)
|
|
|
|
|
+ done()
|
|
|
|
|
+
|
|
|
|
|
+ it "should execute the first three tasks", ->
|
|
|
|
|
+ @task.calledThrice.should.equal true
|
|
|
|
|
+
|
|
|
|
|
+ it "should execute the final task", ->
|
|
|
|
|
+ @finalTask.called.should.equal true
|
|
|
|
|
+
|
|
|
|
|
+ it "should call the callback", ->
|
|
|
|
|
+ @callback.called.should.equal true
|
|
|
|
|
+
|
|
|
|
|
+ it "should finish with worker count of three", ->
|
|
|
|
|
+ expect(@RateLimiter.ActiveWorkerCount).to.equal 3
|