timeAsyncMethodTests.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /*
  2. * decaffeinate suggestions:
  3. * DS102: Remove unnecessary code created because of implicit returns
  4. * DS207: Consider shorter variations of null checks
  5. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  6. */
  7. const chai = require('chai');
  8. const should = chai.should();
  9. const {
  10. expect
  11. } = chai;
  12. const path = require('path');
  13. const modulePath = path.join(__dirname, '../../../timeAsyncMethod.js');
  14. const SandboxedModule = require('sandboxed-module');
  15. const sinon = require("sinon");
  16. describe('timeAsyncMethod', function() {
  17. beforeEach(function() {
  18. this.Timer = {done: sinon.stub()};
  19. this.TimerConstructor = sinon.stub().returns(this.Timer);
  20. this.metrics = {
  21. Timer: this.TimerConstructor,
  22. inc: sinon.stub()
  23. };
  24. this.timeAsyncMethod = SandboxedModule.require(modulePath, { requires: {
  25. './index': this.metrics
  26. }
  27. }
  28. );
  29. return this.testObject = {
  30. nextNumber(n, callback) {
  31. if (callback == null) { callback = function(err, result){}; }
  32. return setTimeout(
  33. () => callback(null, n+1)
  34. , 100
  35. );
  36. }
  37. };});
  38. it('should have the testObject behave correctly before wrapping', function(done) {
  39. return this.testObject.nextNumber(2, function(err, result) {
  40. expect(err).to.not.exist;
  41. expect(result).to.equal(3);
  42. return done();
  43. });
  44. });
  45. it('should wrap method without error', function(done) {
  46. this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject');
  47. return done();
  48. });
  49. it('should transparently wrap method invocation in timer', function(done) {
  50. this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject');
  51. return this.testObject.nextNumber(2, (err, result) => {
  52. expect(err).to.not.exist;
  53. expect(result).to.equal(3);
  54. expect(this.TimerConstructor.callCount).to.equal(1);
  55. expect(this.Timer.done.callCount).to.equal(1);
  56. return done();
  57. });
  58. });
  59. it('should increment success count', function(done) {
  60. this.metrics.inc = sinon.stub();
  61. this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject');
  62. return this.testObject.nextNumber(2, (err, result) => {
  63. expect(this.metrics.inc.callCount).to.equal(1);
  64. expect(this.metrics.inc.calledWith('someContext_result', 1, { method: 'TestObject_nextNumber', status: 'success'})).to.equal(true);
  65. return done();
  66. });
  67. });
  68. describe('when base method produces an error', function() {
  69. beforeEach(function() {
  70. this.metrics.inc = sinon.stub();
  71. return this.testObject.nextNumber = function(n, callback) {
  72. if (callback == null) { callback = function(err, result){}; }
  73. return setTimeout(
  74. () => callback(new Error('woops'))
  75. , 100
  76. );
  77. };
  78. });
  79. it('should propagate the error transparently', function(done) {
  80. this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject');
  81. return this.testObject.nextNumber(2, (err, result) => {
  82. expect(err).to.exist;
  83. expect(err).to.be.instanceof(Error);
  84. expect(result).to.not.exist;
  85. return done();
  86. });
  87. });
  88. return it('should increment failure count', function(done) {
  89. this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject');
  90. return this.testObject.nextNumber(2, (err, result) => {
  91. expect(this.metrics.inc.callCount).to.equal(1);
  92. expect(this.metrics.inc.calledWith('someContext_result', 1, { method: 'TestObject_nextNumber', status: 'failed'})).to.equal(true);
  93. return done();
  94. });
  95. });
  96. });
  97. describe('when a logger is supplied', function() {
  98. beforeEach(function() {
  99. return this.logger = {log: sinon.stub()};});
  100. return it('should also call logger.log', function(done) {
  101. this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject', this.logger);
  102. return this.testObject.nextNumber(2, (err, result) => {
  103. expect(err).to.not.exist;
  104. expect(result).to.equal(3);
  105. expect(this.TimerConstructor.callCount).to.equal(1);
  106. expect(this.Timer.done.callCount).to.equal(1);
  107. expect(this.logger.log.callCount).to.equal(1);
  108. return done();
  109. });
  110. });
  111. });
  112. describe('when the wrapper cannot be applied', function() {
  113. beforeEach(function() {});
  114. return it('should raise an error', function() {
  115. const badWrap = () => {
  116. return this.timeAsyncMethod(this.testObject, 'DEFINITELY_NOT_A_REAL_METHOD', 'someContext.TestObject');
  117. };
  118. return expect(badWrap).to.throw(
  119. /^.*expected object property 'DEFINITELY_NOT_A_REAL_METHOD' to be a function.*$/
  120. );
  121. });
  122. });
  123. return describe('when the wrapped function is not using a callback', function() {
  124. beforeEach(function() {
  125. this.realMethod = sinon.stub().returns(42);
  126. return this.testObject.nextNumber = this.realMethod;
  127. });
  128. it('should not throw an error', function() {
  129. this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject');
  130. const badCall = () => {
  131. return this.testObject.nextNumber(2);
  132. };
  133. return expect(badCall).to.not.throw(Error);
  134. });
  135. return it('should call the underlying method', function() {
  136. this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject');
  137. const result = this.testObject.nextNumber(12);
  138. expect(this.realMethod.callCount).to.equal(1);
  139. expect(this.realMethod.calledWith(12)).to.equal(true);
  140. return expect(result).to.equal(42);
  141. });
  142. });
  143. });