RateLimterTests.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /* eslint-disable
  2. handle-callback-err,
  3. max-len,
  4. no-return-assign,
  5. no-unused-vars,
  6. */
  7. // TODO: This file was created by bulk-decaffeinate.
  8. // Fix any style issues and re-enable lint.
  9. /*
  10. * decaffeinate suggestions:
  11. * DS102: Remove unnecessary code created because of implicit returns
  12. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  13. */
  14. const { assert } = require('chai')
  15. const sinon = require('sinon')
  16. const chai = require('chai')
  17. const should = chai.should()
  18. const { expect } = chai
  19. const modulePath = '../../../../app/src/infrastructure/RateLimiter.js'
  20. const SandboxedModule = require('sandboxed-module')
  21. describe('RateLimiter', function() {
  22. beforeEach(function() {
  23. this.settings = {
  24. redis: {
  25. web: {
  26. port: '1234',
  27. host: 'somewhere',
  28. password: 'password'
  29. }
  30. }
  31. }
  32. this.rclient = {
  33. incr: sinon.stub(),
  34. get: sinon.stub(),
  35. expire: sinon.stub(),
  36. exec: sinon.stub()
  37. }
  38. this.rclient.multi = sinon.stub().returns(this.rclient)
  39. this.RedisWrapper = { client: sinon.stub().returns(this.rclient) }
  40. this.endpointName = 'compiles'
  41. this.subject = 'some-project-id'
  42. this.timeInterval = 20
  43. this.throttleLimit = 5
  44. this.requires = {
  45. 'settings-sharelatex': this.settings,
  46. 'logger-sharelatex': (this.logger = {
  47. log: sinon.stub(),
  48. err: sinon.stub()
  49. }),
  50. 'metrics-sharelatex': (this.Metrics = { inc: sinon.stub() }),
  51. './RedisWrapper': this.RedisWrapper
  52. }
  53. this.details = {
  54. endpointName: this.endpointName,
  55. subjectName: this.subject,
  56. throttle: this.throttleLimit,
  57. timeInterval: this.timeInterval
  58. }
  59. return (this.key = `RateLimiter:${this.endpointName}:{${this.subject}}`)
  60. })
  61. describe('when action is permitted', function() {
  62. beforeEach(function() {
  63. this.requires['rolling-rate-limiter'] = opts => {
  64. return sinon.stub().callsArgWith(1, null, 0, 22)
  65. }
  66. return (this.limiter = SandboxedModule.require(modulePath, {
  67. globals: {
  68. console: console
  69. },
  70. requires: this.requires
  71. }))
  72. })
  73. it('should not produce and error', function(done) {
  74. return this.limiter.addCount({}, function(err, should) {
  75. expect(err).to.equal(null)
  76. return done()
  77. })
  78. })
  79. it('should callback with true', function(done) {
  80. return this.limiter.addCount({}, function(err, should) {
  81. expect(should).to.equal(true)
  82. return done()
  83. })
  84. })
  85. it('should not increment the metric', function(done) {
  86. return this.limiter.addCount(
  87. { endpointName: this.endpointName },
  88. (err, should) => {
  89. sinon.assert.notCalled(this.Metrics.inc)
  90. return done()
  91. }
  92. )
  93. })
  94. })
  95. describe('when action is not permitted', function() {
  96. beforeEach(function() {
  97. this.requires['rolling-rate-limiter'] = opts => {
  98. return sinon.stub().callsArgWith(1, null, 4000, 0)
  99. }
  100. return (this.limiter = SandboxedModule.require(modulePath, {
  101. globals: {
  102. console: console
  103. },
  104. requires: this.requires
  105. }))
  106. })
  107. it('should not produce and error', function(done) {
  108. return this.limiter.addCount({}, function(err, should) {
  109. expect(err).to.equal(null)
  110. return done()
  111. })
  112. })
  113. it('should callback with false', function(done) {
  114. return this.limiter.addCount({}, function(err, should) {
  115. expect(should).to.equal(false)
  116. return done()
  117. })
  118. })
  119. it('should increment the metric', function(done) {
  120. return this.limiter.addCount(
  121. { endpointName: this.endpointName },
  122. (err, should) => {
  123. sinon.assert.calledWith(
  124. this.Metrics.inc,
  125. `rate-limit-hit.${this.endpointName}`,
  126. 1,
  127. { path: this.endpointName }
  128. )
  129. return done()
  130. }
  131. )
  132. })
  133. })
  134. describe('when limiter produces an error', function() {
  135. beforeEach(function() {
  136. this.requires['rolling-rate-limiter'] = opts => {
  137. return sinon.stub().callsArgWith(1, new Error('woops'))
  138. }
  139. return (this.limiter = SandboxedModule.require(modulePath, {
  140. globals: {
  141. console: console
  142. },
  143. requires: this.requires
  144. }))
  145. })
  146. it('should produce and error', function(done) {
  147. return this.limiter.addCount({}, function(err, should) {
  148. expect(err).to.not.equal(null)
  149. expect(err).to.be.instanceof(Error)
  150. return done()
  151. })
  152. })
  153. })
  154. })