diff --git a/src/index.ts b/src/index.ts index 929ba8e54..fa96ce218 100644 --- a/src/index.ts +++ b/src/index.ts @@ -125,10 +125,6 @@ function initConfig(userConfig: Forceable): TopLevelConfig { }, writerConfig: { [FORCE_NEW]: forceNew, - projectId: lastOf( - mergedConfig.projectId, - process.env.GCLOUD_PROJECT - ), onUncaughtException: mergedConfig.onUncaughtException, bufferSize: mergedConfig.bufferSize, flushDelaySeconds: mergedConfig.flushDelaySeconds, @@ -153,6 +149,18 @@ function initConfig(userConfig: Forceable): TopLevelConfig { process.env.GAE_MINOR_VERSION ), }, + /** + * Our TypeScript interface suggests that only credentials, keyFilename, + * and projectId are accepted, but by passing the entire object to the + * Trace Writer, we can allow users to supply other fields that are + * publicly supported by the Google Auth Library. + */ + authOptions: Object.assign({}, mergedConfig, { + projectId: lastOf( + mergedConfig.projectId, + process.env.GCLOUD_PROJECT + ), + }), }, pluginLoaderConfig: { [FORCE_NEW]: forceNew, diff --git a/src/trace-writer.ts b/src/trace-writer.ts index c1ca80162..bad828d92 100644 --- a/src/trace-writer.ts +++ b/src/trace-writer.ts @@ -40,8 +40,8 @@ const SCOPES: string[] = ['https://www.googleapis.com/auth/trace.append']; /* The API endpoint of the Stackdriver Trace service */ const TRACE_API_ENDPOINT = 'cloudtrace.googleapis.com'; -export interface TraceWriterConfig extends common.GoogleAuthOptions { - projectId?: string; +export interface TraceWriterConfig { + authOptions: common.GoogleAuthOptions; onUncaughtException: string; bufferSize: number; flushDelaySeconds: number; @@ -124,7 +124,7 @@ export class TraceWriter extends common.Service { baseUrl: `https://${TRACE_API_ENDPOINT}/v1`, scopes: SCOPES, }, - config + config.authOptions ); this.logger = logger; diff --git a/src/tracing.ts b/src/tracing.ts index 4abf6070c..dae7a5396 100644 --- a/src/tracing.ts +++ b/src/tracing.ts @@ -154,8 +154,8 @@ export class Tracing implements Component { .activate(); if ( - typeof this.config.writerConfig.projectId !== 'string' && - typeof this.config.writerConfig.projectId !== 'undefined' + typeof this.config.writerConfig.authOptions.projectId !== 'string' && + typeof this.config.writerConfig.authOptions.projectId !== 'undefined' ) { this.logger.error( 'StackdriverTracer#start: config.projectId, if provided, must be a string.', diff --git a/test/test-config-priority.ts b/test/test-config-priority.ts index c38c2d959..dbcab6695 100644 --- a/test/test-config-priority.ts +++ b/test/test-config-priority.ts @@ -105,13 +105,13 @@ describe('should respect config load order', () => { it('should respect GCLOUD_PROJECT', () => { traceTestModule.start(); const config = getCapturedConfig(); - assert.strictEqual(config.writerConfig.projectId, '1729'); + assert.strictEqual(config.writerConfig.authOptions.projectId, '1729'); }); it('should prefer env to config', () => { traceTestModule.start({ projectId: '1927' }); const config = getCapturedConfig(); - assert.strictEqual(config.writerConfig.projectId, '1729'); + assert.strictEqual(config.writerConfig.authOptions.projectId, '1729'); }); }); }); diff --git a/test/test-config.ts b/test/test-config.ts index 5af8efedf..709160483 100644 --- a/test/test-config.ts +++ b/test/test-config.ts @@ -24,6 +24,7 @@ import * as testTraceModule from './trace'; import { TopLevelConfig } from '../src/tracing'; import { StackdriverTracer } from '../src/trace-api'; import {Logger} from '../src/logger'; +import { TraceWriterConfig } from '../src/trace-writer'; describe('Behavior set by config for CLS', () => { const useAH = semver.satisfies(process.version, '>=8'); @@ -164,3 +165,38 @@ describe('Behavior set by config for TracePolicy', () => { }); }); +describe('Behavior set by config for TraceWriter', () => { + let capturedConfig: TraceWriterConfig|null; + + class CaptureConfigTestWriter extends testTraceModule.TestTraceWriter { + constructor(config: TraceWriterConfig, logger: Logger) { + super(config, logger); + // Capture the config object passed into this constructor. + capturedConfig = config; + } + } + + beforeEach(() => { + capturedConfig = null; + }); + + before(() => { + testTraceModule.setTraceWriterForTest(CaptureConfigTestWriter); + }); + + after(() => { + testTraceModule.setTraceWriterForTest(testTraceModule.TestTraceWriter); + }); + + it('should set auth variables passed to TraceWriter as authOptions', () => { + const credentials = { private_key: 'abc' }; + testTraceModule.start({ + keyFilename: 'a', + credentials + }); + assert.ok(capturedConfig); + assert.strictEqual(capturedConfig!.authOptions.keyFilename, 'a'); + assert.deepStrictEqual(capturedConfig!.authOptions.credentials, credentials); + }); +}); + diff --git a/test/test-trace-api.ts b/test/test-trace-api.ts index 12a920f4a..1526702d5 100644 --- a/test/test-trace-api.ts +++ b/test/test-trace-api.ts @@ -68,7 +68,7 @@ describe('Trace Interface', () => { return traceWriter .create( Object.assign( - { [FORCE_NEW]: true, projectId: 'project-1' }, + { [FORCE_NEW]: true, authOptions: { projectId: 'project-1' } }, defaultConfig ), logger diff --git a/test/test-trace-writer.ts b/test/test-trace-writer.ts index 610bf61a5..601d2c5c6 100644 --- a/test/test-trace-writer.ts +++ b/test/test-trace-writer.ts @@ -87,6 +87,7 @@ function createDummyTrace(numSpans: number): Trace { describe('Trace Writer', () => { const pjson = require('../../package.json'); const DEFAULT_CONFIG: TraceWriterConfig = { + authOptions: {}, onUncaughtException: 'ignore', bufferSize: Infinity, flushDelaySeconds: 3600, @@ -174,8 +175,10 @@ describe('Trace Writer', () => { it('should use the keyFilename field of the config object', async () => { const expectedCredentials: TestCredentials = require('./fixtures/gcloud-credentials.json'); const actualCredentials = await captureCredentialsForConfig({ - projectId: 'my-project', - keyFilename: path.join('test', 'fixtures', 'gcloud-credentials.json'), + authOptions: { + projectId: 'my-project', + keyFilename: path.join('test', 'fixtures', 'gcloud-credentials.json'), + }, }); assert.deepStrictEqual(actualCredentials, expectedCredentials); }); @@ -183,8 +186,10 @@ describe('Trace Writer', () => { it('should use the credentials field of the config object', async () => { const expectedCredentials: TestCredentials = require('./fixtures/gcloud-credentials.json'); const actualCredentials = await captureCredentialsForConfig({ - projectId: 'my-project', - credentials: expectedCredentials, + authOptions: { + projectId: 'my-project', + credentials: expectedCredentials, + }, }); assert.deepStrictEqual(actualCredentials, expectedCredentials); }); @@ -197,9 +202,11 @@ describe('Trace Writer', () => { type: 'authorized_user', }; const actualCredentials = await captureCredentialsForConfig({ - projectId: 'my-project', - keyFilename: path.join('test', 'fixtures', 'gcloud-credentials.json'), - credentials: expectedCredentials, + authOptions: { + projectId: 'my-project', + keyFilename: path.join('test', 'fixtures', 'gcloud-credentials.json'), + credentials: expectedCredentials, + }, }); assert.deepStrictEqual(actualCredentials, expectedCredentials); }); @@ -216,7 +223,9 @@ describe('Trace Writer', () => { it(`doesn't call Service#getProjectId if project ID is passed`, async () => { const writer = new TraceWriter( - Object.assign({ projectId: 'my-project' }, DEFAULT_CONFIG), + Object.assign({}, DEFAULT_CONFIG, { + authOptions: { projectId: 'my-project' }, + }), logger ); getProjectIdOverride = () => Promise.resolve('my-different-project'); diff --git a/test/trace.ts b/test/trace.ts index 95fb32d00..003d403e1 100644 --- a/test/trace.ts +++ b/test/trace.ts @@ -75,7 +75,7 @@ export class TestLogger extends testLogger.TestLogger { export class TestTraceWriter extends TraceWriter { constructor(config: TraceWriterConfig, logger: logger.Logger) { super(config, logger); - this.getConfig().projectId = '0'; + this.getConfig().authOptions.projectId = '0'; } async initialize(): Promise {}