From 7b9e48fbf0e0a7153f2bf5f55ef8ca8488f5c794 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Tue, 5 Jun 2018 11:18:28 -0700 Subject: [PATCH] test: modernize test-trace-api (#767) PR-URL: #767 --- test/test-trace-api.ts | 383 +++++++++++++++++------------------------ tsconfig.json | 1 + 2 files changed, 156 insertions(+), 228 deletions(-) diff --git a/test/test-trace-api.ts b/test/test-trace-api.ts index c7042789b..cfbf8c618 100644 --- a/test/test-trace-api.ts +++ b/test/test-trace-api.ts @@ -14,284 +14,213 @@ * limitations under the License. */ -'use strict'; - -import './override-gcp-metadata'; -import { cls, TraceCLSMechanism } from '../src/cls'; -import { defaultConfig } from '../src/config'; -import { TraceAgent } from '../src/trace-api'; -import { traceWriter } from '../src/trace-writer'; -import * as TracingPolicy from '../src/tracing-policy'; -import { FORCE_NEW } from '../src/util'; -import { asRootSpanData, asChildSpanData } from './utils'; -import { SpanType } from '../src/constants'; - -var assert = require('assert'); -var common = require('./plugins/common'/*.js*/); -var EventEmitter = require('events'); -var nock = require('nock'); -var request = require('request'); - -var logger = require('@google-cloud/common').logger(); - -nock.disableNetConnect(); - -function createTraceAgent(policy?, config?) { - var result = new TraceAgent('test'); - result.enable(config || { - enhancedDatabaseReporting: false, - ignoreContextHeader: false - }, logger); - result.policy = policy || new TracingPolicy.TraceAllPolicy(); - return result; -} - -function assertAPISurface(traceAPI) { - assert.strictEqual(typeof traceAPI.enhancedDatabaseReportingEnabled(), 'boolean'); - traceAPI.runInRootSpan({ name: 'root' }, function(root) { - assert.strictEqual(typeof root.addLabel, 'function'); - assert.strictEqual(typeof root.endSpan, 'function'); - assert.strictEqual(typeof root.getTraceContext(), 'string'); - var child = traceAPI.createChildSpan({ name: 'child' }); - assert.strictEqual(typeof child.addLabel, 'function'); - assert.strictEqual(typeof child.endSpan, 'function'); - assert.strictEqual(typeof child.getTraceContext(), 'string'); +import * as assert from 'assert'; + +import {cls, TraceCLS, TraceCLSMechanism} from '../src/cls'; +import {defaultConfig} from '../src/config'; +import {SpanType} from '../src/constants'; +import {TraceAgent, TraceAgentConfig} from '../src/trace-api'; +import {traceWriter} from '../src/trace-writer'; +import {FilterPolicy, TraceAllPolicy, TraceNonePolicy, TracePolicy} from '../src/tracing-policy'; +import {FORCE_NEW} from '../src/util'; + +import {TestLogger} from './logger'; +import * as testTraceModule from './trace'; +import {asChildSpanData, asRootSpanData} from './utils'; + +describe('Trace Interface', () => { + const logger = new TestLogger(); + function createTraceAgent( + policy?: TracePolicy|null, + config?: Partial): TraceAgent { + const result = new TraceAgent('test'); + result.enable( + Object.assign( + { + enhancedDatabaseReporting: false, + ignoreContextHeader: false, + samplingRate: 0 + }, + config), + logger); + result.policy = policy || new TraceAllPolicy(); + return result; + } + + before((done) => { + testTraceModule.setCLSForTest(TraceCLS); + cls.create({mechanism: TraceCLSMechanism.ASYNC_LISTENER}, logger).enable(); + traceWriter + .create(Object.assign({[FORCE_NEW]: true}, defaultConfig), logger) + .initialize(done); }); - assert.strictEqual(typeof traceAPI.getCurrentContextId, 'function'); - assert.strictEqual(typeof traceAPI.getWriterProjectId, 'function'); - assert.strictEqual(typeof traceAPI.wrap(function() {}), 'function'); - assert.strictEqual(typeof traceAPI.wrapEmitter(new EventEmitter()), 'undefined'); - assert.strictEqual(typeof traceAPI.constants, 'object'); - assert.strictEqual(typeof traceAPI.labels, 'object'); -} -describe('Trace Interface', function() { - before(function(done) { - cls.create({ mechanism: TraceCLSMechanism.ASYNC_LISTENER }, logger).enable(); - traceWriter.create( - Object.assign(defaultConfig, { - projectId: '0', - [FORCE_NEW]: false - }), logger).initialize(function(err) { - assert.ok(!err); - done(); - }); + after(() => { + testTraceModule.setCLSForTest(testTraceModule.TestCLS); }); - it('should correctly manage internal state', function() { - var traceAPI = createTraceAgent(); - assert.ok(traceAPI.isActive(), - 'Newly created instances are active'); + it('should correctly manage internal state', () => { + const traceAPI = createTraceAgent(); + assert.ok(traceAPI.isActive()); traceAPI.disable(); - assert.ok(!traceAPI.isActive(), - 'Being disabled sets isActive to false'); + assert.ok(!traceAPI.isActive(), 'Being disabled sets isActive to false'); }); - it('should expose the same interface regardless of state', function() { - var traceAPI = createTraceAgent(); - assertAPISurface(traceAPI); - traceAPI.disable(); - assertAPISurface(traceAPI); - }); - - describe('constants', function() { - it('have correct values', function() { - var traceAPI = createTraceAgent(); - assert.equal(traceAPI.constants.TRACE_CONTEXT_HEADER_NAME, - 'x-cloud-trace-context'); - assert.equal(traceAPI.constants.TRACE_AGENT_REQUEST_HEADER, - 'x-cloud-trace-agent-request'); + describe('behavior when initialized', () => { + afterEach(() => { + testTraceModule.clearTraceData(); }); - }); - describe('behavior when initialized', function() { - before(function() { - traceWriter.get().request = request; - common.avoidTraceWriterAuth(); - }); - - afterEach(function() { - common.cleanTraces(); - }); - - it('should produce real child spans with createChildSpan', function() { - var traceAPI = createTraceAgent(); - traceAPI.runInRootSpan({name: 'root'}, function(root_) { - var root = asRootSpanData(root_); - var child = asChildSpanData(traceAPI.createChildSpan({name: 'sub'})); - assert.strictEqual(child.span.parentSpanId, root.span.spanId); - child.addLabel('key', 'val'); - child.endSpan(); - root.endSpan(); - var spanPredicate = function(span) { - return span.name === 'sub'; - }; - var matchingSpan = common.getMatchingSpan(spanPredicate); - assert.equal(matchingSpan.labels.key, 'val'); + it('should produce real child spans with createChildSpan', () => { + const traceAPI = createTraceAgent(); + traceAPI.runInRootSpan({name: 'root'}, (rootSpan) => { + const childSpan = traceAPI.createChildSpan({name: 'sub'}); + childSpan.addLabel('key', 'val'); + childSpan.endSpan(); + rootSpan.endSpan(); }); + const rootSpanData = + testTraceModule.getOneSpan(span => span.name === 'root'); + const childSpanData = + testTraceModule.getOneSpan(span => span.name === 'sub'); + assert.strictEqual(childSpanData.parentSpanId, rootSpanData.spanId); + assert.strictEqual(childSpanData.labels.key, 'val'); }); - it('should produce real child spans with thru root span API', function() { - var traceAPI = createTraceAgent(); - traceAPI.runInRootSpan({name: 'root'}, function(root_) { - var root = asRootSpanData(root_); - var child = asChildSpanData(root.createChildSpan({name: 'sub'})); - child.endSpan(); - root.endSpan(); - assert.strictEqual(child.span.parentSpanId, root.span.spanId); - var spanPredicate = function(span) { - return span.name === 'sub'; - }; - common.getMatchingSpan(spanPredicate); // use assertion in gMS - + it('should produce real child spans through root span API', () => { + const traceAPI = createTraceAgent(); + traceAPI.runInRootSpan({name: 'root'}, (rootSpan) => { + const childSpan = rootSpan.createChildSpan({name: 'sub'}); + childSpan.addLabel('key', 'val'); + childSpan.endSpan(); + rootSpan.endSpan(); }); + // getOneSpan asserts that only one such span exists. + const rootSpanData = + testTraceModule.getOneSpan(span => span.name === 'root'); + const childSpanData = + testTraceModule.getOneSpan(span => span.name === 'sub'); + assert.strictEqual(childSpanData.parentSpanId, rootSpanData.spanId); + assert.strictEqual(childSpanData.labels.key, 'val'); }); - it('should produce real root spans runInRootSpan', function() { - var traceAPI = createTraceAgent(); - traceAPI.runInRootSpan({name: 'root', url: 'root'}, function(rootSpan_) { - var rootSpan = asRootSpanData(rootSpan_); + it('should produce real root spans with runInRootSpan', () => { + const traceAPI = createTraceAgent(); + const result = traceAPI.runInRootSpan({name: 'root'}, (rootSpan) => { rootSpan.addLabel('key', 'val'); - var childSpan = asChildSpanData(traceAPI.createChildSpan({name: 'sub'})); - childSpan.endSpan(); rootSpan.endSpan(); - var spanPredicate = function(span) { - return span.name === 'root'; - }; - var matchingSpan = common.getMatchingSpan(spanPredicate); - assert.equal(matchingSpan.labels.key, 'val'); + return 'result'; }); + assert.strictEqual(result, 'result'); + // getOneSpan asserts that only one such span exists. + const rootSpanData = + testTraceModule.getOneSpan(span => span.name === 'root'); + assert.strictEqual(rootSpanData.labels.key, 'val'); }); - it('should allow sequential root spans', function() { - var traceAPI = createTraceAgent(); - traceAPI.runInRootSpan({name: 'root', url: 'root'}, function(rootSpan1_) { - var rootSpan1 = asRootSpanData(rootSpan1_); - rootSpan1.endSpan(); + it('should allow sequential root spans', () => { + const traceAPI = createTraceAgent(); + traceAPI.runInRootSpan({name: 'root1'}, (rootSpan) => { + rootSpan.endSpan(); }); - traceAPI.runInRootSpan({name: 'root2', url: 'root2'}, function(rootSpan2) { - rootSpan2.endSpan(); - var spans = common.getMatchingSpans(function() { return true; }); - assert.equal(spans.length, 2); - assert.ok(spans.find(span => span.name === 'root')); - assert.ok(spans.find(span => span.name === 'root2')); + traceAPI.runInRootSpan({name: 'root2'}, (rootSpan) => { + rootSpan.endSpan(); }); + assert.strictEqual(testTraceModule.getTraces().length, 2); }); - it('should not allow nested root spans', function() { - var traceAPI = createTraceAgent(); - traceAPI.runInRootSpan({name: 'root', url: 'root'}, function(rootSpan1_) { - var rootSpan1 = asRootSpanData(rootSpan1_); - traceAPI.runInRootSpan({name: 'root2', url: 'root2'}, function(rootSpan2) { - assert.strictEqual(rootSpan2.type, SpanType.UNCORRELATED); - const childSpan = rootSpan2.createChildSpan({ name: 'child' }); - assert.strictEqual(childSpan.type, SpanType.UNCORRELATED); + it('should not allow nested root spans', () => { + const traceAPI = createTraceAgent(); + traceAPI.runInRootSpan({name: 'root1'}, (rootSpan) => { + traceAPI.runInRootSpan({name: 'root2'}, (notRootSpan) => { + assert.strictEqual(notRootSpan.type, SpanType.UNCORRELATED); + notRootSpan.endSpan(); }); - rootSpan1.endSpan(); - var span = common.getMatchingSpan(function() { return true; }); - assert.equal(span.name, 'root'); + rootSpan.endSpan(); }); + assert.strictEqual(testTraceModule.getTraces().length, 1); }); - it('should return null context id when one does not exist', function() { - var traceAPI = createTraceAgent(); + it('should return null context id when one does not exist', () => { + const traceAPI = createTraceAgent(); assert.strictEqual(traceAPI.getCurrentContextId(), null); }); - it('should return the appropriate trace id', function() { - var traceAPI = createTraceAgent(); - traceAPI.runInRootSpan({name: 'root', url: 'root'}, function(rootSpan_) { - var rootSpan = asRootSpanData(rootSpan_); - var id = traceAPI.getCurrentContextId(); - assert.strictEqual(id, rootSpan.trace.traceId); + it('should return the appropriate trace id', () => { + const traceAPI = createTraceAgent(); + traceAPI.runInRootSpan({name: 'root'}, (rootSpan) => { + const id = traceAPI.getCurrentContextId(); + rootSpan.endSpan(); + // getOneTrace asserts that there is exactly one trace. + testTraceModule.getOneTrace(trace => trace.traceId === id); }); }); - it('should return get the project ID if set in config', function() { - var config = {projectId: 'project-1'}; - var traceApi = createTraceAgent(null /* policy */, config); + it('should return get the project ID if set in config', () => { + const config = {projectId: 'project-1'}; + const traceApi = createTraceAgent(null /* policy */, config); assert.equal(traceApi.getWriterProjectId(), 'project-1'); }); - it('should add labels to spans', function() { - var traceAPI = createTraceAgent(); - traceAPI.runInRootSpan({name: 'root', url: 'root'}, function(root_) { - var root = asRootSpanData(root_); - var child = asChildSpanData(traceAPI.createChildSpan({name: 'sub'})); - child.addLabel('test1', 'value'); - child.endSpan(); - assert.equal(child.span.name, 'sub'); - assert.ok(child.span.labels); - assert.equal(child.span.labels.test1, 'value'); - root.endSpan(); - }); - }); - - it('should respect trace policy', function(done) { - var traceAPI = createTraceAgent(new TracingPolicy.TraceNonePolicy()); - traceAPI.runInRootSpan({name: 'root', url: 'root'}, function(rootSpan) { + it('should respect trace policy', (done) => { + const traceAPI = createTraceAgent(new TraceNonePolicy()); + traceAPI.runInRootSpan({name: 'root', url: 'root'}, (rootSpan) => { assert.strictEqual(rootSpan.type, SpanType.UNTRACED); - const childSpan = rootSpan.createChildSpan({ name: 'child' }); + const childSpan = rootSpan.createChildSpan({name: 'child'}); assert.strictEqual(childSpan.type, SpanType.UNTRACED); done(); }); }); - it('should respect filter urls', function() { - var url = 'rootUrl'; - var traceAPI = createTraceAgent(new TracingPolicy.FilterPolicy( - new TracingPolicy.TraceAllPolicy(), - [url])); - traceAPI.runInRootSpan({name: 'root1', url: url}, function(rootSpan) { + it('should respect filter urls', () => { + const url = 'rootUrl'; + const traceAPI = + createTraceAgent(new FilterPolicy(new TraceAllPolicy(), [url])); + traceAPI.runInRootSpan({name: 'root', url}, (rootSpan) => { assert.strictEqual(rootSpan.type, SpanType.UNTRACED); }); - traceAPI.runInRootSpan({name: 'root2', url: 'alternativeUrl'}, function(rootSpan_) { - var rootSpan = asRootSpanData(rootSpan_); - assert.strictEqual(rootSpan.span.name, 'root2'); - }); + traceAPI.runInRootSpan( + {name: 'root', url: 'alternativeUrl'}, (rootSpan) => { + assert.strictEqual(rootSpan.type, SpanType.ROOT); + }); }); - it('should respect enhancedDatabaseReporting options field', function() { - [true, false].forEach(function(enhancedDatabaseReporting) { - var traceAPI = createTraceAgent(null, { - enhancedDatabaseReporting: enhancedDatabaseReporting, - ignoreContextHeader: false - }); - assert.strictEqual(traceAPI.enhancedDatabaseReportingEnabled(), - enhancedDatabaseReporting); + it('should respect enhancedDatabaseReporting options field', () => { + [true, false].forEach((enhancedDatabaseReporting) => { + const traceAPI = createTraceAgent( + null, {enhancedDatabaseReporting, ignoreContextHeader: false}); + assert.strictEqual( + traceAPI.enhancedDatabaseReportingEnabled(), + enhancedDatabaseReporting); }); }); - it('should respect ignoreContextHeader options field', function() { - var traceAPI; + it('should respect ignoreContextHeader options field', () => { // ignoreContextHeader: true - traceAPI = createTraceAgent(null, { - enhancedDatabaseReporting: false, - ignoreContextHeader: true - }); - traceAPI.runInRootSpan({ - name: 'root', - traceContext: '123456/667;o=1' - }, function(rootSpan) { - assert.ok(rootSpan); - assert.strictEqual(rootSpan.span.name, 'root'); - assert.notEqual(rootSpan.trace.traceId, '123456'); - assert.notEqual(rootSpan.span.parentSpanId, '667'); - }); + createTraceAgent( + null, {enhancedDatabaseReporting: false, ignoreContextHeader: true}) + .runInRootSpan( + {name: 'root1', traceContext: '123456/667;o=1'}, (rootSpan) => { + rootSpan.endSpan(); + }); + // The trace ID will not randomly be 123456 + let foundTrace = + testTraceModule.getOneTrace(trace => trace.traceId !== '123456'); + assert.strictEqual(foundTrace.spans.length, 1); + assert.strictEqual(foundTrace.spans[0].name, 'root1'); + assert.notStrictEqual(foundTrace.spans[0].parentSpanId, '667'); // ignoreContextHeader: false - traceAPI = createTraceAgent(null, { - enhancedDatabaseReporting: false, - ignoreContextHeader: false - }); - traceAPI.runInRootSpan({ - name: 'root', - traceContext: '123456/667;o=1' - }, function(rootSpan) { - assert.ok(rootSpan); - assert.strictEqual(rootSpan.span.name, 'root'); - assert.strictEqual(rootSpan.trace.traceId, '123456'); - assert.strictEqual(rootSpan.span.parentSpanId, '667'); - }); + createTraceAgent( + null, {enhancedDatabaseReporting: false, ignoreContextHeader: false}) + .runInRootSpan( + {name: 'root2', traceContext: '123456/667;o=1'}, (rootSpan) => { + rootSpan.endSpan(); + }); + foundTrace = + testTraceModule.getOneTrace(trace => trace.traceId === '123456'); + assert.strictEqual(foundTrace.spans.length, 1); + assert.strictEqual(foundTrace.spans[0].name, 'root2'); + assert.strictEqual(foundTrace.spans[0].parentSpanId, '667'); }); describe('getting response trace context', () => { @@ -323,5 +252,3 @@ describe('Trace Interface', function() { }); }); }); - -export default {}; diff --git a/tsconfig.json b/tsconfig.json index d8b7c2cc5..d96026903 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -31,6 +31,7 @@ "test/test-modules-loaded-before-agent.ts", "test/test-plugin-loader.ts", "test/test-span-data.ts", + "test/test-trace-api.ts", "test/test-trace-api-none-cls.ts", "test/test-trace-cluster.ts", "test/test-trace-web-frameworks.ts",