Brian Gough 6 tahun lalu
induk
melakukan
a0f856cff2

+ 0 - 1
libraries/metrics/.gitignore

@@ -1,2 +1 @@
 node_modules
-test/unit/js/*

File diff ditekan karena terlalu besar
+ 511 - 497
libraries/metrics/package-lock.json


+ 7 - 10
libraries/metrics/package.json

@@ -10,21 +10,18 @@
     "@google-cloud/debug-agent": "^3.0.0",
     "@google-cloud/profiler": "^0.2.3",
     "@google-cloud/trace-agent": "^3.2.0",
-    "coffee-script": "1.6.0",
     "prom-client": "^11.1.3",
     "underscore": "~1.6.0",
     "yn": "^3.1.1"
   },
   "devDependencies": {
     "bunyan": "^1.0.0",
-    "chai": "",
-    "grunt": "^0.4.5",
-    "grunt-bunyan": "^0.5.0",
-    "grunt-contrib-clean": "^0.6.0",
-    "grunt-contrib-coffee": "^0.11.0",
-    "grunt-execute": "^0.2.2",
-    "grunt-mocha-test": "^0.11.0",
-    "sandboxed-module": "",
-    "sinon": ""
+    "chai": "^4.2.0",
+    "mocha": "^8.0.1",
+    "sandboxed-module": "^2.0.4",
+    "sinon": "^9.0.2"
+  },
+  "scripts": {
+    "test": "mocha --reporter spec --recursive --exit --grep=$MOCHA_GREP test/unit"
   }
 }

+ 47 - 0
libraries/metrics/test/unit/js/event_loop.js

@@ -0,0 +1,47 @@
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const chai = require('chai');
+const should = chai.should();
+const {
+    expect
+} = chai;
+const path = require('path');
+const modulePath = path.join(__dirname, '../../../event_loop.js');
+const SandboxedModule = require('sandboxed-module');
+const sinon = require("sinon");
+
+describe('event_loop', function() {
+
+	before(function() {
+		this.metrics = {
+			timing: sinon.stub(),
+			registerDestructor: sinon.stub()
+		};
+		this.logger = {
+			warn: sinon.stub()
+		};
+		return this.event_loop = SandboxedModule.require(modulePath, { requires: {
+			'./metrics': this.metrics
+		}
+	}
+		);
+	});
+
+	describe('with a logger provided', function() {
+		before(function() {
+			return this.event_loop.monitor(this.logger);
+		});
+
+		return it('should register a destructor with metrics', function() {
+			return this.metrics.registerDestructor.called.should.equal(true);
+		});
+	});
+
+	return describe('without a logger provided', () => it('should throw an exception', function() {
+        return expect(this.event_loop.monitor).to.throw('logger is undefined');
+    }));
+});
+

+ 163 - 0
libraries/metrics/test/unit/js/timeAsyncMethodTests.js

@@ -0,0 +1,163 @@
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * DS207: Consider shorter variations of null checks
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const chai = require('chai');
+const should = chai.should();
+const {
+    expect
+} = chai;
+const path = require('path');
+const modulePath = path.join(__dirname, '../../../timeAsyncMethod.js');
+const SandboxedModule = require('sandboxed-module');
+const sinon = require("sinon");
+
+
+describe('timeAsyncMethod', function() {
+
+	beforeEach(function() {
+		this.Timer = {done: sinon.stub()};
+		this.TimerConstructor = sinon.stub().returns(this.Timer);
+		this.metrics = {
+			Timer: this.TimerConstructor,
+			inc: sinon.stub()
+		};
+		this.timeAsyncMethod = SandboxedModule.require(modulePath, { requires: {
+			'./metrics': this.metrics
+		}
+	}
+		);
+
+		return this.testObject = {
+			nextNumber(n, callback) {
+				if (callback == null) { callback = function(err, result){}; }
+				return setTimeout(
+					() => callback(null, n+1)
+					, 100
+				);
+			}
+		};});
+
+	it('should have the testObject behave correctly before wrapping', function(done) {
+		return this.testObject.nextNumber(2, function(err, result) {
+			expect(err).to.not.exist;
+			expect(result).to.equal(3);
+			return done();
+		});
+	});
+
+	it('should wrap method without error', function(done) {
+		this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject');
+		return done();
+	});
+
+	it('should transparently wrap method invocation in timer', function(done) {
+		this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject');
+		return this.testObject.nextNumber(2, (err, result) => {
+			expect(err).to.not.exist;
+			expect(result).to.equal(3);
+			expect(this.TimerConstructor.callCount).to.equal(1);
+			expect(this.Timer.done.callCount).to.equal(1);
+			return done();
+		});
+	});
+
+	it('should increment success count', function(done) {
+		this.metrics.inc = sinon.stub();
+		this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject');
+		return this.testObject.nextNumber(2, (err, result) => {
+			expect(this.metrics.inc.callCount).to.equal(1);
+			expect(this.metrics.inc.calledWith('someContext_result', 1, { method: 'TestObject_nextNumber', status: 'success'})).to.equal(true);
+			return done();
+		});
+	});
+
+	describe('when base method produces an error', function() {
+		beforeEach(function() {
+			this.metrics.inc = sinon.stub();
+			return this.testObject.nextNumber = function(n, callback) {
+				if (callback == null) { callback = function(err, result){}; }
+				return setTimeout(
+					() => callback(new Error('woops'))
+					, 100
+				);
+			};
+		});
+
+		it('should propagate the error transparently', function(done) {
+			this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject');
+			return this.testObject.nextNumber(2, (err, result) => {
+				expect(err).to.exist;
+				expect(err).to.be.instanceof(Error);
+				expect(result).to.not.exist;
+				return done();
+			});
+		});
+
+		return it('should increment failure count', function(done) {
+			this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject');
+			return this.testObject.nextNumber(2, (err, result) => {
+				expect(this.metrics.inc.callCount).to.equal(1);
+				expect(this.metrics.inc.calledWith('someContext_result', 1, { method: 'TestObject_nextNumber', status: 'failed'})).to.equal(true);
+				return done();
+			});
+		});
+	});
+
+	describe('when a logger is supplied', function() {
+		beforeEach(function() {
+			return this.logger = {log: sinon.stub()};});
+
+		return it('should also call logger.log', function(done) {
+			this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject', this.logger);
+			return this.testObject.nextNumber(2, (err, result) => {
+				expect(err).to.not.exist;
+				expect(result).to.equal(3);
+				expect(this.TimerConstructor.callCount).to.equal(1);
+				expect(this.Timer.done.callCount).to.equal(1);
+				expect(this.logger.log.callCount).to.equal(1);
+				return done();
+			});
+		});
+	});
+
+	describe('when the wrapper cannot be applied', function() {
+		beforeEach(function() {});
+
+		return it('should raise an error', function() {
+			const badWrap = () => {
+				return this.timeAsyncMethod(this.testObject, 'DEFINITELY_NOT_A_REAL_METHOD', 'someContext.TestObject');
+			};
+			return expect(badWrap).to.throw(
+				/^.*expected object property 'DEFINITELY_NOT_A_REAL_METHOD' to be a function.*$/
+			);
+		});
+	});
+
+	return describe('when the wrapped function is not using a callback', function() {
+		beforeEach(function() {
+			this.realMethod =  sinon.stub().returns(42);
+			return this.testObject.nextNumber = this.realMethod;
+		});
+
+		it('should not throw an error', function() {
+			this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject');
+			const badCall = () => {
+				return this.testObject.nextNumber(2);
+			};
+			return expect(badCall).to.not.throw(Error);
+		});
+
+		return it('should call the underlying method', function() {
+			this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject');
+			const result = this.testObject.nextNumber(12);
+			expect(this.realMethod.callCount).to.equal(1);
+			expect(this.realMethod.calledWith(12)).to.equal(true);
+			return expect(result).to.equal(42);
+		});
+	});
+});
+
+

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini