From b312004693643e0088f39db24433f33892bbed5c Mon Sep 17 00:00:00 2001 From: Jeffrey Rennie Date: Thu, 20 May 2021 17:39:45 -0700 Subject: [PATCH 1/3] chore: migrate to owl bot (#958) * chore: migrate to owl bot * chore: copy files from googleapis-gen 397c0bfd367a2427104f988d5329bc117caafd95 * chore: run the post processor * lint Co-authored-by: Justin Beckwith --- .github/.OwlBot.lock.yaml | 4 + .github/.OwlBot.yaml | 19 +++ .github/generated-files-bot.yml | 16 +++ synth.py => owlbot.py | 14 +- src/agent/controller.ts | 4 +- src/agent/debuglet.ts | 34 ++--- src/agent/io/sourcemapper.ts | 11 +- src/agent/state/inspector-state.ts | 2 +- src/agent/state/legacy-state.ts | 4 +- src/agent/util/debug-assert.ts | 2 +- src/agent/v8/inspector-debugapi.ts | 11 +- src/agent/v8/legacy-debugapi.ts | 13 +- synth.metadata | 18 --- system-test/test-install.ts | 2 +- test/test-controller.ts | 6 +- test/test-debug-assert.ts | 2 +- test/test-debuglet.ts | 41 +++--- test/test-max-data-size.ts | 4 +- test/test-options-credentials.ts | 6 +- test/test-v8debugapi.ts | 221 ++++++++++++++--------------- 20 files changed, 224 insertions(+), 210 deletions(-) create mode 100644 .github/.OwlBot.lock.yaml create mode 100644 .github/.OwlBot.yaml create mode 100644 .github/generated-files-bot.yml rename synth.py => owlbot.py (64%) delete mode 100644 synth.metadata diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml new file mode 100644 index 00000000..6e5f21ef --- /dev/null +++ b/.github/.OwlBot.lock.yaml @@ -0,0 +1,4 @@ +docker: + digest: sha256:f556e6e7be625deb1b2429fe608df27be57185c3e6b7d39ee0059f1609f17530 + image: gcr.io/repo-automation-bots/owlbot-nodejs:latest + diff --git a/.github/.OwlBot.yaml b/.github/.OwlBot.yaml new file mode 100644 index 00000000..3a281cc9 --- /dev/null +++ b/.github/.OwlBot.yaml @@ -0,0 +1,19 @@ +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +docker: + image: gcr.io/repo-automation-bots/owlbot-nodejs:latest + + +begin-after-commit-hash: 397c0bfd367a2427104f988d5329bc117caafd95 + diff --git a/.github/generated-files-bot.yml b/.github/generated-files-bot.yml new file mode 100644 index 00000000..6b04910c --- /dev/null +++ b/.github/generated-files-bot.yml @@ -0,0 +1,16 @@ +generatedFiles: +- path: '.kokoro/**' + message: '`.kokoro` files are templated and should be updated in [`synthtool`](https://github.com/googleapis/synthtool)' +- path: '.github/CODEOWNERS' + message: 'CODEOWNERS should instead be modified via the `codeowner_team` property in .repo-metadata.json' +- path: '.github/workflows/**' + message: '`.github/workflows` (GitHub Actions) should be updated in [`synthtool`](https://github.com/googleapis/synthtool)' +- path: '.github/generated-files-bot.+(yml|yaml)' + message: '`.github/generated-files-bot.(yml|yaml)` should be updated in [`synthtool`](https://github.com/googleapis/synthtool)' +- path: 'README.md' + message: '`README.md` is managed by [`synthtool`](https://github.com/googleapis/synthtool). However, a partials file can be used to update the README, e.g.: https://github.com/googleapis/nodejs-storage/blob/master/.readme-partials.yaml' +- path: 'samples/README.md' + message: '`samples/README.md` is managed by [`synthtool`](https://github.com/googleapis/synthtool). However, a partials file can be used to update the README, e.g.: https://github.com/googleapis/nodejs-storage/blob/master/.readme-partials.yaml' +ignoreAuthors: +- 'gcf-owl-bot[bot]' +- 'yoshi-automation' diff --git a/synth.py b/owlbot.py similarity index 64% rename from synth.py rename to owlbot.py index dcb46941..a7f40972 100644 --- a/synth.py +++ b/owlbot.py @@ -12,18 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import synthtool as s -import synthtool.gcp as gcp import synthtool.languages.node as node -import logging -logging.basicConfig(level=logging.DEBUG) - -AUTOSYNTH_MULTIPLE_COMMITS = True - -common_templates = gcp.CommonTemplates() -templates = common_templates.node_library() -s.copy(templates, excludes=['.eslintignore', '.mocharc.js', '.github/workflows/ci.yaml']) - -node.install() -node.fix() +node.owlbot_main(templates_excludes=['.eslintignore', '.mocharc.js', '.github/workflows/ci.yaml']) \ No newline at end of file diff --git a/src/agent/controller.ts b/src/agent/controller.ts index 45a43d21..1687beb0 100644 --- a/src/agent/controller.ts +++ b/src/agent/controller.ts @@ -134,7 +134,7 @@ export class Controller extends ServiceObject { } else if (response.statusCode === 404) { // The v2 API returns 404 (google.rpc.Code.NOT_FOUND) when the agent // registration expires. We should re-register. - callback(null, (response as {}) as t.Response); + callback(null, response as {} as t.Response); return; } else if (response.statusCode !== 200) { callback( @@ -146,7 +146,7 @@ export class Controller extends ServiceObject { } else { body = body || {}; that.nextWaitToken = body.nextWaitToken; - callback(null, (response as {}) as t.Response, body); + callback(null, response as {} as t.Response, body); } } ); diff --git a/src/agent/debuglet.ts b/src/agent/debuglet.ts index ff4718b9..691b58fe 100644 --- a/src/agent/debuglet.ts +++ b/src/agent/debuglet.ts @@ -457,7 +457,7 @@ export class Debuglet extends EventEmitter { let sourceContext; try { sourceContext = - ((that.config.sourceContext as {}) as SourceContext) || + (that.config.sourceContext as {} as SourceContext) || (await Debuglet.getSourceContextFromFile()); } catch (err5) { that.logger.warn('Unable to discover source context', err5); @@ -741,9 +741,11 @@ export class Debuglet extends EventEmitter { ); // TODO: Handle the case when `that.debuggee` is null. // TODO: Handle the case when `result` is undefined. - (that.debuggee as Debuggee).id = (result as { - debuggee: Debuggee; - }).debuggee.id; + (that.debuggee as Debuggee).id = ( + result as { + debuggee: Debuggee; + } + ).debuggee.id; // TODO: Handle the case when `result` is undefined. that.emit('registered', (result as {debuggee: Debuggee}).debuggee.id); that.debuggeeRegistered.resolve(); @@ -926,9 +928,7 @@ export class Debuglet extends EventEmitter { // field. It is possible that breakpoint.id is always // undefined! // TODO: Make sure the use of `that` here is correct. - delete that.completedBreakpointMap[ - ((breakpoint as {}) as {id: number}).id - ]; + delete that.completedBreakpointMap[(breakpoint as {} as {id: number}).id]; }); // Remove active breakpoints that the server no longer care about. @@ -946,9 +946,9 @@ export class Debuglet extends EventEmitter { * @return {Object.} A map of breakpoint IDs to breakpoints. * @private */ - convertBreakpointListToMap_( - breakpointList: stackdriver.Breakpoint[] - ): {[key: string]: stackdriver.Breakpoint} { + convertBreakpointListToMap_(breakpointList: stackdriver.Breakpoint[]): { + [key: string]: stackdriver.Breakpoint; + } { const map: {[id: string]: stackdriver.Breakpoint} = {}; breakpointList.forEach(breakpoint => { // TODO: Address the case when `breakpoint.id` is `undefined`. @@ -1098,13 +1098,15 @@ export class Debuglet extends EventEmitter { const that = this; // TODO: Address the case when `that.debuggee` is `null`. - that.controller.updateBreakpoint(that.debuggee as Debuggee, breakpoint, ( - err /*, body*/ - ) => { - if (err) { - that.logger.error('Unable to complete breakpoint on server', err); + that.controller.updateBreakpoint( + that.debuggee as Debuggee, + breakpoint, + (err /*, body*/) => { + if (err) { + that.logger.error('Unable to complete breakpoint on server', err); + } } - }); + ); } /** diff --git a/src/agent/io/sourcemapper.ts b/src/agent/io/sourcemapper.ts index 509321fb..84e8787e 100644 --- a/src/agent/io/sourcemapper.ts +++ b/src/agent/io/sourcemapper.ts @@ -74,9 +74,9 @@ async function processSourcemap( // TODO: Resolve the cast of `contents as any` (This is needed because the // type is expected to be of `RawSourceMap` but the existing // working code uses a string.) - consumer = (new sourceMap.SourceMapConsumer( - (contents as {}) as sourceMap.RawSourceMap - ) as {}) as sourceMap.RawSourceMap; + consumer = new sourceMap.SourceMapConsumer( + contents as {} as sourceMap.RawSourceMap + ) as {} as sourceMap.RawSourceMap; } catch (e) { throw new Error( 'An error occurred while reading the ' + @@ -246,7 +246,8 @@ export class SourceMapper { }; // TODO: Determine how to remove the explicit cast here. - const consumer: sourceMap.SourceMapConsumer = (entry.mapConsumer as {}) as sourceMap.SourceMapConsumer; + const consumer: sourceMap.SourceMapConsumer = + entry.mapConsumer as {} as sourceMap.SourceMapConsumer; const allPos = consumer.allGeneratedPositionsFor(sourcePos); /* * Based on testing, it appears that the following code is needed to @@ -270,7 +271,7 @@ export class SourceMapper { // TODO: The `sourceMap.Position` type definition has a `column` // attribute and not a `col` attribute. Determine if the type // definition or this code is correct. - column: ((mappedPos as {}) as {col: number}).col, // SourceMapConsumer uses + column: (mappedPos as {} as {col: number}).col, // SourceMapConsumer uses // zero-based column // numbers which is the // same as the expected diff --git a/src/agent/state/inspector-state.ts b/src/agent/state/inspector-state.ts index 9e8845e0..f0268e67 100644 --- a/src/agent/state/inspector-state.ts +++ b/src/agent/state/inspector-state.ts @@ -151,7 +151,7 @@ class StateResolver { }; // TODO: Determine why _extend is used here - this.resolvedVariableTable = ((util as {}) as {_extend: Function})._extend( + this.resolvedVariableTable = (util as {} as {_extend: Function})._extend( [], this.messageTable ); diff --git a/src/agent/state/legacy-state.ts b/src/agent/state/legacy-state.ts index 1f26e0fd..4e112092 100644 --- a/src/agent/state/legacy-state.ts +++ b/src/agent/state/legacy-state.ts @@ -138,7 +138,7 @@ class StateResolver { }; // TODO: Determine why _extend is used here - this.resolvedVariableTable = ((util as {}) as {_extend: Function})._extend( + this.resolvedVariableTable = (util as {} as {_extend: Function})._extend( [], this.messageTable ); @@ -148,7 +148,7 @@ class StateResolver { // This constructor is only used in situations where the legacy vm // interface is used that has the `runInDebugContext` method. - this.scopeType = ((vm as {}) as LegacyVm).runInDebugContext('ScopeType'); + this.scopeType = (vm as {} as LegacyVm).runInDebugContext('ScopeType'); } /** diff --git a/src/agent/util/debug-assert.ts b/src/agent/util/debug-assert.ts index 56f7b30b..4bc58e35 100644 --- a/src/agent/util/debug-assert.ts +++ b/src/agent/util/debug-assert.ts @@ -62,5 +62,5 @@ const fakeAssert: FakeAssert = { export function debugAssert(enableAssertions: boolean): FakeAssert { // The typecast is needed since the @types/node doesn't cover Node 10 yet - return enableAssertions ? ((realAssert as {}) as FakeAssert) : fakeAssert; + return enableAssertions ? (realAssert as {} as FakeAssert) : fakeAssert; } diff --git a/src/agent/v8/inspector-debugapi.ts b/src/agent/v8/inspector-debugapi.ts index 487bd849..60dd2910 100644 --- a/src/agent/v8/inspector-debugapi.ts +++ b/src/agent/v8/inspector-debugapi.ts @@ -559,9 +559,11 @@ export class InspectorDebugApi implements debugapi.DebugApi { // TODO: Address the case where `breakpoint.id` is `null`. breakpoint.expressions[i] = // TODO: Address the case where `compile` is `null`. - (this.breakpoints[breakpoint.id].compile as ( - text: string - ) => string)(breakpoint.expressions[i]); + ( + this.breakpoints[breakpoint.id].compile as ( + text: string + ) => string + )(breakpoint.expressions[i]); } catch (e) { this.logger.info( 'Unable to compile watch expression >> ' + @@ -617,7 +619,8 @@ export class InspectorDebugApi implements debugapi.DebugApi { breakpoint.stackFrames = captured.stackFrames; // TODO: This suggests the Status type and Variable type are the same. // Determine if that is the case. - breakpoint.variableTable = captured.variableTable as stackdriver.Variable[]; + breakpoint.variableTable = + captured.variableTable as stackdriver.Variable[]; breakpoint.evaluatedExpressions = expressionErrors.concat( captured.evaluatedExpressions ); diff --git a/src/agent/v8/legacy-debugapi.ts b/src/agent/v8/legacy-debugapi.ts index bd0b87e0..8d5b107e 100644 --- a/src/agent/v8/legacy-debugapi.ts +++ b/src/agent/v8/legacy-debugapi.ts @@ -73,7 +73,7 @@ export class V8DebugApi implements debugapi.DebugApi { this.sourcemapper = sourcemapper; // This constructor is only used in situations where the legacy vm // interface is used that has the `runInDebugContext` method. - this.v8 = ((vm as {}) as LegacyVm).runInDebugContext('Debug'); + this.v8 = (vm as {} as LegacyVm).runInDebugContext('Debug'); this.config = config; this.fileStats = jsFiles; this.v8Version = /(\d+\.\d+\.\d+)\.\d+/.exec(process.versions.v8); @@ -522,9 +522,11 @@ export class V8DebugApi implements debugapi.DebugApi { try { breakpoint.expressions[i] = // TODO: Address the case where `compile` is `null`. - (this.breakpoints[breakpoint.id].compile as ( - text: string - ) => string)(breakpoint.expressions[i]); + ( + this.breakpoints[breakpoint.id].compile as ( + text: string + ) => string + )(breakpoint.expressions[i]); } catch (e) { this.logger.info( 'Unable to compile watch expression >> ' + @@ -579,7 +581,8 @@ export class V8DebugApi implements debugapi.DebugApi { breakpoint.stackFrames = captured.stackFrames; // TODO: This suggests the Status type and Variable type are the same. // Determine if that is the case. - breakpoint.variableTable = captured.variableTable as stackdriver.Variable[]; + breakpoint.variableTable = + captured.variableTable as stackdriver.Variable[]; breakpoint.evaluatedExpressions = expressionErrors.concat( captured.evaluatedExpressions ); diff --git a/synth.metadata b/synth.metadata deleted file mode 100644 index 2efd88bb..00000000 --- a/synth.metadata +++ /dev/null @@ -1,18 +0,0 @@ -{ - "sources": [ - { - "git": { - "name": ".", - "remote": "https://github.com/googleapis/cloud-debug-nodejs.git", - "sha": "72b5d590450e53d9a3276fe88371a4577a0d6341" - } - }, - { - "git": { - "name": "synthtool", - "remote": "https://github.com/googleapis/synthtool.git", - "sha": "b33b0e2056a85fc2264b294f2cf47dcd45e95186" - } - } - ] -} \ No newline at end of file diff --git a/system-test/test-install.ts b/system-test/test-install.ts index c1a612ca..ac0d3e16 100644 --- a/system-test/test-install.ts +++ b/system-test/test-install.ts @@ -18,7 +18,7 @@ import {ncp} from 'ncp'; import * as tmp from 'tmp-promise'; import {promisify} from 'util'; -const mvp = (promisify(mv) as {}) as (...args: string[]) => Promise; +const mvp = promisify(mv) as {} as (...args: string[]) => Promise; const ncpp = promisify(ncp); const stagingDir = tmp.dirSync({keep: false, unsafeCleanup: true}); const stagingPath = stagingDir.name; diff --git a/test/test-controller.ts b/test/test-controller.ts index 20d43a78..0f825168 100644 --- a/test/test-controller.ts +++ b/test/test-controller.ts @@ -28,14 +28,14 @@ delete process.env.GCLOUD_PROJECT; import {Controller} from '../src/agent/controller'; // TODO: Fix fakeDebug to actually implement Debug. -const fakeDebug = ({ +const fakeDebug = { apiEndpoint: 'clouddebugger.googleapis.com', request: (options: t.Options, cb: t.RequestCallback) => { teenyRequest(options, (err, r) => { cb(err, r ? r.body : undefined, r); }); }, -} as {}) as Debug; +} as {} as Debug; const agentVersion = 'SomeName/client/SomeVersion'; const url = 'https://clouddebugger.googleapis.com'; @@ -226,7 +226,7 @@ describe('Controller API', () => { // TODO: Fix this error that states `body` is not a property // of `ServerResponse`. assert( - ((response as {}) as {body: {waitExpired: {}}}).body.waitExpired, + (response as {} as {body: {waitExpired: {}}}).body.waitExpired, 'should have expired set' ); scope.done(); diff --git a/test/test-debug-assert.ts b/test/test-debug-assert.ts index 793b13bd..0e0414fb 100644 --- a/test/test-debug-assert.ts +++ b/test/test-debug-assert.ts @@ -34,7 +34,7 @@ describe('debug-assert', () => { it.skip('should cover the full assert API', () => { Object.keys(realAssert).forEach(key => { realAssert.strictEqual( - typeof ((assert as {}) as {[key: string]: Function})[key], + typeof (assert as {} as {[key: string]: Function})[key], 'function', `${key} does not exist on the debug assert library` ); diff --git a/test/test-debuglet.ts b/test/test-debuglet.ts index 4439861f..82369828 100644 --- a/test/test-debuglet.ts +++ b/test/test-debuglet.ts @@ -39,7 +39,8 @@ import {Debug} from '../src/client/stackdriver/debug'; const DEBUGGEE_ID = 'bar'; const REGISTER_PATH = '/v2/controller/debuggees/register'; const BPS_PATH = '/v2/controller/debuggees/' + DEBUGGEE_ID + '/breakpoints'; -const EXPRESSIONS_REGEX = /Expressions and conditions are not allowed.*https:\/\/goo\.gl\/ShSm6r/; +const EXPRESSIONS_REGEX = + /Expressions and conditions are not allowed.*https:\/\/goo\.gl\/ShSm6r/; // eslint-disable-next-line @typescript-eslint/no-var-requires const fakeCredentials = require('./fixtures/gcloud-credentials.json'); @@ -64,11 +65,11 @@ const bp: stackdriver.Breakpoint = { location: {path: 'build/test/fixtures/foo.js', line: 2}, } as stackdriver.Breakpoint; // TODO: Have this actually implement Breakpoint. -const errorBp: stackdriver.Breakpoint = ({ +const errorBp: stackdriver.Breakpoint = { id: 'testLog', action: 'FOO', location: {path: 'build/test/fixtures/foo.js', line: 2}, -} as {}) as stackdriver.Breakpoint; +} as {} as stackdriver.Breakpoint; function verifyBreakpointRejection( re: RegExp, @@ -594,9 +595,11 @@ describe('Debuglet', () => { // Resolve this. assert.strictEqual( undefined, - (debuglet.config.serviceContext as { - minorVersion: {}; - }).minorVersion + ( + debuglet.config.serviceContext as { + minorVersion: {}; + } + ).minorVersion ); }); @@ -972,7 +975,7 @@ describe('Debuglet', () => { ); const old = Debuglet.getSourceContextFromFile; Debuglet.getSourceContextFromFile = async () => { - return {a: (5 as {}) as string}; + return {a: 5 as {} as string}; }; const config = debugletConfig(); @@ -1007,7 +1010,7 @@ describe('Debuglet', () => { const old = Debuglet.getSourceContextFromFile; Debuglet.getSourceContextFromFile = async () => { - return {a: (5 as {}) as string}; + return {a: 5 as {} as string}; }; const config = debugletConfig({ @@ -1471,43 +1474,43 @@ describe('Debuglet', () => { // TODO: Determine if Debuglet.format() should allow a number[] // or if only string[] should be allowed. assert.deepStrictEqual( - Debuglet.format('hi', ([5] as {}) as string[]), + Debuglet.format('hi', [5] as {} as string[]), 'hi' ); assert.deepStrictEqual( - Debuglet.format('hi $0', ([5] as {}) as string[]), + Debuglet.format('hi $0', [5] as {} as string[]), 'hi 5' ); assert.deepStrictEqual( - Debuglet.format('hi $0 $1', ([5, 'there'] as {}) as string[]), + Debuglet.format('hi $0 $1', [5, 'there'] as {} as string[]), 'hi 5 there' ); assert.deepStrictEqual( - Debuglet.format('hi $0 $1', ([5] as {}) as string[]), + Debuglet.format('hi $0 $1', [5] as {} as string[]), 'hi 5 $1' ); assert.deepStrictEqual( - Debuglet.format('hi $0 $1 $0', ([5] as {}) as string[]), + Debuglet.format('hi $0 $1 $0', [5] as {} as string[]), 'hi 5 $1 5' ); assert.deepStrictEqual( - Debuglet.format('hi $$', ([5] as {}) as string[]), + Debuglet.format('hi $$', [5] as {} as string[]), 'hi $' ); assert.deepStrictEqual( - Debuglet.format('hi $$0', ([5] as {}) as string[]), + Debuglet.format('hi $$0', [5] as {} as string[]), 'hi $0' ); assert.deepStrictEqual( - Debuglet.format('hi $00', ([5] as {}) as string[]), + Debuglet.format('hi $00', [5] as {} as string[]), 'hi 50' ); assert.deepStrictEqual( - Debuglet.format('hi $0', (['$1', 5] as {}) as string[]), + Debuglet.format('hi $0', ['$1', 5] as {} as string[]), 'hi $1' ); assert.deepStrictEqual( - Debuglet.format('hi $11', ([ + Debuglet.format('hi $11', [ 0, 1, 2, @@ -1522,7 +1525,7 @@ describe('Debuglet', () => { 'b', 'c', 'd', - ] as {}) as string[]), + ] as {} as string[]), 'hi b' ); }); diff --git a/test/test-max-data-size.ts b/test/test-max-data-size.ts index 4379c3d7..2d105ba1 100644 --- a/test/test-max-data-size.ts +++ b/test/test-max-data-size.ts @@ -117,9 +117,9 @@ describe('maxDataSize', () => { ) => { return ( acc && - (((!elem!.status || + ((!elem!.status || elem!.status!.description.format !== - 'Max data size reached') as {}) as stackdriver.Variable) + 'Max data size reached') as {} as stackdriver.Variable) ); } ) diff --git a/test/test-options-credentials.ts b/test/test-options-credentials.ts index 2f551b40..e2d75d23 100644 --- a/test/test-options-credentials.ts +++ b/test/test-options-credentials.ts @@ -77,7 +77,7 @@ describe('test-options-credentials', () => { }); nocks.projectId('project-via-metadata'); // TODO: Determine how to remove this cast. - debuglet = new Debuglet(debug, (config as {}) as DebugAgentConfig); + debuglet = new Debuglet(debug, config as {} as DebugAgentConfig); debuglet.start(); }); @@ -104,7 +104,7 @@ describe('test-options-credentials', () => { }); nocks.projectId('project-via-metadata'); // TODO: Determine how to remove this cast. - debuglet = new Debuglet(debug, (config as {}) as DebugAgentConfig); + debuglet = new Debuglet(debug, config as {} as DebugAgentConfig); debuglet.start(); }); @@ -145,7 +145,7 @@ describe('test-options-credentials', () => { assert.notStrictEqual(options.credentials[field], fileCredentials[field]); }); // TODO: Determine how to remove this cast. - debuglet = new Debuglet(debug, (config as {}) as DebugAgentConfig); + debuglet = new Debuglet(debug, config as {} as DebugAgentConfig); debuglet.start(); }); }); diff --git a/test/test-v8debugapi.ts b/test/test-v8debugapi.ts index 47a82c4c..741948bc 100644 --- a/test/test-v8debugapi.ts +++ b/test/test-v8debugapi.ts @@ -301,10 +301,10 @@ describe('v8debugapi', () => { it('should accept breakpoint with ids 0 as a valid breakpoint', done => { // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: 0, location: breakpointInFoo.location, - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; api.set(bp, err1 => { assert.ifError(err1); api.clear(bp, err2 => { @@ -316,10 +316,10 @@ describe('v8debugapi', () => { it('should permit breakpoints on js files with non-standard extensions', done => { require('./fixtures/hello.jsz'); - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: 0, location: {line: 1, path: path.join('fixtures', 'hello.jsz')}, - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; api.set(bp, err1 => { assert.ifError(err1); api.clear(bp, err2 => { @@ -332,10 +332,10 @@ describe('v8debugapi', () => { it('should set error for breakpoint in non-js files', done => { require('./fixtures/key-bad.json'); // TODO(dominickramer): Have this actually implement Breakpoint - const bp = ({ + const bp = { id: 0, location: {line: 1, path: path.join('fixtures', 'key-bad.json')}, - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; api.set(bp, err => { assert.ok(err, 'should return an error'); assert.ok(bp.status); @@ -349,10 +349,10 @@ describe('v8debugapi', () => { it('should disambiguate incorrect path if filename is unique', done => { require('./fixtures/foo.js'); // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: 0, location: {line: 1, path: path.join(path.sep, 'test', 'foo.js')}, - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; api.set(bp, err1 => { assert.ifError(err1); api.clear(bp, err2 => { @@ -366,10 +366,10 @@ describe('v8debugapi', () => { require('./fixtures/foo.js'); // hello.js is not unique but a/hello.js is. // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: 0, location: {line: 1, path: path.join(path.sep, 'Server', 'a', 'hello.js')}, - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; api.set(bp, err1 => { assert.ifError(err1); api.clear(bp, err2 => { @@ -382,21 +382,21 @@ describe('v8debugapi', () => { describe('invalid breakpoints', () => { // TODO(dominickramer): Have this actually be a list of Breakpoints const badBreakpoints: stackdriver.Breakpoint[] = [ - ({} as {}) as stackdriver.Breakpoint, - ({id: 'with no location'} as {}) as stackdriver.Breakpoint, - ({id: 'with bad location', location: {}} as {}) as stackdriver.Breakpoint, - ({ + {} as {} as stackdriver.Breakpoint, + {id: 'with no location'} as {} as stackdriver.Breakpoint, + {id: 'with bad location', location: {}} as {} as stackdriver.Breakpoint, + { id: 'with no path', location: {line: 4}, - } as {}) as stackdriver.Breakpoint, - ({ + } as {} as stackdriver.Breakpoint, + { id: 'with no line', location: {path: 'foo.js'}, - } as {}) as stackdriver.Breakpoint, - ({ + } as {} as stackdriver.Breakpoint, + { id: 'with incomplete path', location: {path: 'st-v8debugapi.js', line: 4}, - } as {}) as stackdriver.Breakpoint, + } as {} as stackdriver.Breakpoint, ]; badBreakpoints.forEach((bp: stackdriver.Breakpoint) => { @@ -415,10 +415,10 @@ describe('v8debugapi', () => { require('./fixtures/a/hello.js'); require('./fixtures/b/hello.js'); // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: 'ambiguous', location: {line: 1, path: 'hello.js'}, - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; api.set(bp, err => { assert.ok(err); assert.ok(bp.status); @@ -460,10 +460,10 @@ describe('v8debugapi', () => { it('should reject breakpoint on non-existent line', done => { require('./fixtures/foo.js'); // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: 'non-existent line', location: {path: path.join('fixtures', 'foo.js'), line: 500}, - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; api.set(bp, err => { assert.ok(err); assert.ok(bp.status); @@ -489,11 +489,11 @@ describe('v8debugapi', () => { it('should validate breakpoint with condition "' + expr + '"', done => { // make a clean copy of breakpointInFoo // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: breakpointInFoo.id, location: breakpointInFoo.location, condition: expr, - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; api.set(bp, err1 => { test(err1); api.clear(bp, err2 => { @@ -595,18 +595,18 @@ describe('v8debugapi', () => { describe('path normalization', () => { // TODO(dominickramer): Have this actually be a list of Breakpoints const breakpoints = [ - ({ + { id: 'path0', location: { line: 5, path: path.join(path.sep, 'test', 'test-v8debugapi-code.js'), }, - } as {}) as stackdriver.Breakpoint, - ({ + } as {} as stackdriver.Breakpoint, + { id: 'path1', location: {line: 5, path: path.join('test', 'test-v8debugapi-code.js')}, - } as {}) as stackdriver.Breakpoint, - ({ + } as {} as stackdriver.Breakpoint, + { id: 'path2', location: { line: 5, @@ -618,32 +618,32 @@ describe('v8debugapi', () => { .concat('test-v8debugapi-code.js') .join(path.sep), }, - } as {}) as stackdriver.Breakpoint, - ({ + } as {} as stackdriver.Breakpoint, + { id: 'with . in path', location: { path: path.join('test', '.', 'test-v8debugapi-code.js'), line: 5, }, - } as {}) as stackdriver.Breakpoint, - ({ + } as {} as stackdriver.Breakpoint, + { id: 'with . in path', location: {path: path.join('.', 'test-v8debugapi-code.js'), line: 5}, - } as {}) as stackdriver.Breakpoint, - ({ + } as {} as stackdriver.Breakpoint, + { id: 'with .. in path', location: { path: path.join('test', '..', 'test-v8debugapi-code.js'), line: 5, }, - } as {}) as stackdriver.Breakpoint, - ({ + } as {} as stackdriver.Breakpoint, + { id: 'with .. in path', location: { path: path.join('..', 'test', 'test-v8debugapi-code.js'), line: 5, }, - } as {}) as stackdriver.Breakpoint, + } as {} as stackdriver.Breakpoint, ]; breakpoints.forEach((bp: stackdriver.Breakpoint) => { @@ -685,12 +685,12 @@ describe('v8debugapi', () => { it('should throttle correctly', done => { let completed = false; // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: breakpointInFoo.id, location: breakpointInFoo.location, action: 'LOG', logMessageFormat: 'cat', - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; api.set(bp, err1 => { let transcript = ''; let runCount = 0; @@ -726,10 +726,10 @@ describe('v8debugapi', () => { it('should be possible to wait on a breakpoint', done => { // clone a clean breakpointInFoo // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: breakpointInFoo.id, location: breakpointInFoo.location, - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; api.set(bp, err1 => { assert.ifError(err1); api.wait(bp, err2 => { @@ -746,10 +746,10 @@ describe('v8debugapi', () => { }); it('should resolve actual line number hit rather than originally set for js files', done => { - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: 'fake-id-124', location: {path: 'build/test/test-v8debugapi-code.js', line: 4}, - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; api.set(bp, err1 => { assert.ifError(err1); api.wait(bp, err2 => { @@ -842,10 +842,10 @@ describe('v8debugapi', () => { }; // clone a clean breakpointInFoo // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: breakpointInFoo.id, location: breakpointInFoo.location, - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; api.set(bp, err1 => { assert.ifError(err1); api.wait(bp, err2 => { @@ -870,12 +870,12 @@ describe('v8debugapi', () => { it('should be possible to wait on a logpoint without expressions', done => { // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: breakpointInFoo.id, action: 'LOG', logMessageFormat: 'Hello World', location: breakpointInFoo.location, - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; api.set(bp, err1 => { assert.ifError(err1); api.wait(bp, err2 => { @@ -894,10 +894,10 @@ describe('v8debugapi', () => { it('should capture state', done => { // clone a clean breakpointInFoo // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: breakpointInFoo.id, location: breakpointInFoo.location, - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; api.set(bp, err1 => { assert.ifError(err1); api.wait(bp, err2 => { @@ -926,10 +926,10 @@ describe('v8debugapi', () => { it('should resolve correct frame count', done => { // clone a clean breakpointInFoo // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: breakpointInFoo.id, location: breakpointInFoo.location, - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; const oldCount = config.capture.maxExpandFrames; config.capture.maxExpandFrames = 0; api.set(bp, err1 => { @@ -980,10 +980,10 @@ describe('v8debugapi', () => { it('should capture correct frame count', done => { // clone a clean breakpointInFoo // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: breakpointInFoo.id, location: breakpointInFoo.location, - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; const oldMax = config.capture.maxFrames; config.capture.maxFrames = 1; api.set(bp, err1 => { @@ -1012,11 +1012,11 @@ describe('v8debugapi', () => { it('should capture state with watch expressions', done => { // clone a clean breakpointInFoo // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: breakpointInFoo.id, location: breakpointInFoo.location, expressions: ['process'], - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; const oldMaxProps = config.capture.maxProperties; const oldMaxData = config.capture.maxDataSize; config.capture.maxProperties = 0; @@ -1067,14 +1067,14 @@ describe('v8debugapi', () => { it('should report error for native prop or getter', done => { // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: 'fake-id-124', // TODO(dominickramer): This path can be lest strict when this file has // been // converted to Typescript. location: {path: 'build/test/test-v8debugapi-code.js', line: 10}, expressions: ['process.env', 'hasGetter'], - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; const oldMaxData = config.capture.maxDataSize; config.capture.maxDataSize = 20000; api.set(bp, err1 => { @@ -1118,14 +1118,14 @@ describe('v8debugapi', () => { it('should work with array length despite being native', done => { // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: breakpointInFoo.id, // TODO(dominickramer): This path can be lest strict when this file has // been // converted to Typescript. location: {path: 'build/test/test-v8debugapi-code.js', line: 6}, expressions: ['A'], - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; api.set(bp, err1 => { assert.ifError(err1); api.wait(bp, err2 => { @@ -1157,13 +1157,13 @@ describe('v8debugapi', () => { it('should limit string length', done => { // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: 'fake-id-124', // TODO(dominickramer): This path can be lest strict when this file has // been // converted to Typescript. location: {path: 'build/test/test-v8debugapi-code.js', line: 10}, - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; const oldMaxLength = config.capture.maxStringLength; const oldMaxData = config.capture.maxDataSize; config.capture.maxStringLength = 3; @@ -1202,13 +1202,13 @@ describe('v8debugapi', () => { it('should limit array length', done => { // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: 'fake-id-124', // TODO(dominickramer): This path can be lest strict when this file has // been // converted to Typescript. location: {path: 'build/test/test-v8debugapi-code.js', line: 6}, - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; const oldMax = config.capture.maxProperties; config.capture.maxProperties = 1; api.set(bp, err1 => { @@ -1241,13 +1241,13 @@ describe('v8debugapi', () => { it('should limit object length', done => { // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: 'fake-id-124', // TODO(dominickramer): This path can be lest strict when this file has // been // converted to Typescript. location: {path: 'build/test/test-v8debugapi-code.js', line: 6}, - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; const oldMax = config.capture.maxProperties; config.capture.maxProperties = 1; api.set(bp, err1 => { @@ -1280,14 +1280,14 @@ describe('v8debugapi', () => { it('should not limit the length of an evaluated string based on maxStringLength', done => { // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: 'fake-id-124', // TODO(dominickramer): This path can be lest strict when this file // has been // converted to Typescript. location: {path: 'build/test/test-v8debugapi-code.js', line: 10}, expressions: ['hasGetter'], - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; const oldMaxLength = config.capture.maxStringLength; const oldMaxData = config.capture.maxDataSize; config.capture.maxStringLength = 3; @@ -1320,14 +1320,14 @@ describe('v8debugapi', () => { it('should not limit the length of an evaluated array based on maxProperties', done => { // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: 'fake-id-124', // TODO(dominickramer): This path can be lest strict when this file // has been // converted to Typescript. location: {path: 'build/test/test-v8debugapi-code.js', line: 6}, expressions: ['A'], - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; const oldMaxProps = config.capture.maxProperties; const oldMaxData = config.capture.maxDataSize; config.capture.maxProperties = 1; @@ -1357,14 +1357,14 @@ describe('v8debugapi', () => { it('should not limit the length of an evaluated object based on maxProperties', done => { // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: 'fake-id-124', // TODO(dominickramer): This path can be lest strict when this file // has been // converted to Typescript. location: {path: 'build/test/test-v8debugapi-code.js', line: 6}, expressions: ['B'], - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; const oldMaxProps = config.capture.maxProperties; const oldMaxData = config.capture.maxDataSize; config.capture.maxProperties = 1; @@ -1393,14 +1393,14 @@ describe('v8debugapi', () => { it('should display an error for an evaluated array beyond maxDataSize', done => { // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: 'fake-id-124', // TODO(dominickramer): This path can be lest strict when this file // has been // converted to Typescript. location: {path: 'build/test/test-v8debugapi-code.js', line: 6}, expressions: ['A'], - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; const oldMaxProps = config.capture.maxProperties; const oldMaxData = config.capture.maxDataSize; config.capture.maxProperties = 5; @@ -1431,14 +1431,14 @@ describe('v8debugapi', () => { it('should display an error for an evaluated object beyond maxDataSize', done => { // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: 'fake-id-124', // TODO(dominickramer): This path can be lest strict when this file // has been // converted to Typescript. location: {path: 'build/test/test-v8debugapi-code.js', line: 6}, expressions: ['B'], - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; const oldMaxProps = config.capture.maxProperties; const oldMaxData = config.capture.maxDataSize; config.capture.maxProperties = 5; @@ -1469,14 +1469,14 @@ describe('v8debugapi', () => { it('should set the correct status messages if maxDataSize is reached', done => { // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: 'fake-id-124', // TODO(dominickramer): This path can be lest strict when this file // has been // converted to Typescript. location: {path: 'build/test/test-v8debugapi-code.js', line: 6}, expressions: ['A'], - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; const oldMaxProps = config.capture.maxProperties; const oldMaxData = config.capture.maxDataSize; config.capture.maxProperties = 1; @@ -1515,7 +1515,7 @@ describe('v8debugapi', () => { it('should capture without values for invalid watch expressions', done => { // clone a clean breakpointInFoo // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: breakpointInFoo.id, location: breakpointInFoo.location, expressions: [ @@ -1525,7 +1525,7 @@ describe('v8debugapi', () => { 'i', 'process._not._def', ], - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; api.set(bp, err1 => { assert.ifError(err1); api.wait(bp, err2 => { @@ -1555,11 +1555,11 @@ describe('v8debugapi', () => { it('should be possible to set conditional breakpoints', done => { // clone a clean breakpointInFoo // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: breakpointInFoo.id, location: breakpointInFoo.location, condition: 'n===5', - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; api.set(bp, err1 => { assert.ifError(err1); api.wait(bp, err2 => { @@ -1583,7 +1583,7 @@ describe('v8debugapi', () => { it('should be possible to set conditional breakpoints in coffeescript', done => { // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: 'coffee-id-1729', // TODO(dominickramer): Determine if this path should contain 'build' location: { @@ -1598,7 +1598,7 @@ describe('v8debugapi', () => { line: 3, }, condition: 'if n == 3 then true else false', - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; // eslint-disable-next-line @typescript-eslint/no-var-requires const tt = require('./fixtures/coffee/transpile'); api.set(bp, err1 => { @@ -1625,7 +1625,7 @@ describe('v8debugapi', () => { it('should show error for invalid conditions in coffeescript', done => { // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: 'coffee-id-1729', location: { path: path.join( @@ -1638,7 +1638,7 @@ describe('v8debugapi', () => { line: 3, }, condition: 'process=false', - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; api.set(bp, err => { assert(err); assert.strictEqual(err!.message, 'Error compiling condition.'); @@ -1648,7 +1648,7 @@ describe('v8debugapi', () => { it('should be possible to set conditional breakpoints with babel', done => { // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: 'babel-id-1729', // TODO(dominickramer): Determine if this path should contain 'build' location: { @@ -1663,7 +1663,7 @@ describe('v8debugapi', () => { line: 2, }, condition: 'i + j === 3', - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; // eslint-disable-next-line @typescript-eslint/no-var-requires const tt = require('./fixtures/es6/transpile'); api.set(bp, err1 => { @@ -1690,7 +1690,7 @@ describe('v8debugapi', () => { it('should be possible to view watch expressions in coffeescript', done => { // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: 'coffee-id-1729', // TODO(dominickramer): Determine if this path should contain 'build' location: { @@ -1705,7 +1705,7 @@ describe('v8debugapi', () => { line: 3, }, expressions: ['if n == 3 then Math.PI * n else n'], - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; // eslint-disable-next-line @typescript-eslint/no-var-requires const tt = require('./fixtures/coffee/transpile'); api.set(bp, err1 => { @@ -1736,7 +1736,7 @@ describe('v8debugapi', () => { it('should capture without values for invalid watch expressions in coffeescript', done => { // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: 'coffee-id-1729', // TODO(dominickramer): Determine if this path should contain 'build' location: { @@ -1757,7 +1757,7 @@ describe('v8debugapi', () => { '((x) -> x x) n', 'return', ], - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; // eslint-disable-next-line @typescript-eslint/no-var-requires const tt = require('./fixtures/coffee/transpile'); api.set(bp, err => { @@ -1805,11 +1805,11 @@ describe('v8debugapi', () => { it('should remove listener when breakpoint is cleared before hitting', done => { // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: breakpointInFoo.id, location: breakpointInFoo.location, condition: 'n===447', - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; api.set(bp, err1 => { assert.ifError(err1); api.wait(bp, () => { @@ -1830,15 +1830,15 @@ describe('v8debugapi', () => { it('should be possible to set multiple breakpoints at once', done => { // TODO(dominickramer): Have this actually implement Breakpoint - const bp1: stackdriver.Breakpoint = ({ + const bp1: stackdriver.Breakpoint = { id: 'bp1', location: {path: __filename, line: 5}, - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; // TODO(dominickramer): Have this actually implement Breakpoint - const bp2: stackdriver.Breakpoint = ({ + const bp2: stackdriver.Breakpoint = { id: 'bp2', location: {path: __filename, line: 6}, - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; api.set(bp1, err1 => { assert.ifError(err1); api.set(bp2, err2 => { @@ -1861,10 +1861,10 @@ describe('v8debugapi', () => { // eslint-disable-next-line @typescript-eslint/no-var-requires const foo = require('./fixtures/foo.js'); // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: 'bp-line-1', location: {path: 'foo.js', line: 1, column: 45}, - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; api.set(bp, err1 => { assert.ifError(err1); api.wait(bp, err2 => { @@ -1899,10 +1899,10 @@ describe('v8debugapi', () => { // clone a clean breakpointInFoo // TODO(dominickramer): Have this actually implement Breakpoint - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: breakpointInFoo.id, location: breakpointInFoo.location, - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; api.set(bp, err1 => { assert.ifError(err1); // TODO(dominickramer): Determine if the err parameter should be used. @@ -1919,13 +1919,13 @@ describe('v8debugapi', () => { }); it('should capture state in transpiled TS async functions', done => { - const bp: stackdriver.Breakpoint = ({ + const bp: stackdriver.Breakpoint = { id: 'async-id-1', location: { path: path.join('.', 'test', 'fixtures', 'ts', 'async.js'), line: 71, }, - } as {}) as stackdriver.Breakpoint; + } as {} as stackdriver.Breakpoint; // eslint-disable-next-line @typescript-eslint/no-var-requires const run = require('./fixtures/ts/async.js'); @@ -1970,15 +1970,8 @@ describe('v8debugapi.findScripts', () => { 'a', 'hello.js' )]: {hash: 'fake', lines: 5}, - [path.join( - 'my', - 'project', - 'root', - 'test', - 'fixtures', - 'a', - 'hello.js' - )]: {hash: 'fake', lines: 50}, + [path.join('my', 'project', 'root', 'test', 'fixtures', 'a', 'hello.js')]: + {hash: 'fake', lines: 50}, }; const scriptPath = path.join( 'my', From 7735425ee8999c6ab1c30706ddf014315309705c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Louis=20Ye=20=E5=8F=B6=E7=BB=BF=E5=AE=87?= Date: Mon, 31 May 2021 13:25:37 -0400 Subject: [PATCH 2/3] fix: periodically reset v8 session to prevent memory leak (#957) * fix: periodically reset v8 session to prevent memory leak This patch makes the cloud debugger reset the v8 debugger session to prevent the memory leak caused by v8 breakpoint hits whenenever the number of breakpoint hits reach the threshold. The threshold can be set through environment variable. Fixes #811 * fix: lint issue, remove reading from env about reset threshold * fix: run lint on all the files * fix: update comments for default value Co-authored-by: Benjamin E. Coe --- src/agent/config.ts | 9 +++ src/agent/v8/inspector-debugapi.ts | 103 +++++++++++++++++++++++------ test/test-debuglet.ts | 14 ++++ test/test-v8debugapi.ts | 71 ++++++++++++++++++++ 4 files changed, 176 insertions(+), 21 deletions(-) diff --git a/src/agent/config.ts b/src/agent/config.ts index e72e7117..45ef4f36 100644 --- a/src/agent/config.ts +++ b/src/agent/config.ts @@ -357,6 +357,14 @@ export interface ResolvedDebugAgentConfig extends GoogleAuthOptions { * used to set a default api url */ apiUrl?: string; + + /** + * Number of times of the V8 breakpoint hits events before resetting the + * breakpoints. This is to release the memory usage held by V8 engine for each + * breakpoint hit to prevent the memory leak. The default value is specified + * in defaultConfig. + */ + resetV8DebuggerThreshold: number; } export interface StackdriverConfig extends GoogleAuthOptions { @@ -406,4 +414,5 @@ export const defaultConfig: ResolvedDebugAgentConfig = { forceNewAgent_: false, testMode_: false, + resetV8DebuggerThreshold: 30, }; diff --git a/src/agent/v8/inspector-debugapi.ts b/src/agent/v8/inspector-debugapi.ts index 60dd2910..b71815ee 100644 --- a/src/agent/v8/inspector-debugapi.ts +++ b/src/agent/v8/inspector-debugapi.ts @@ -41,6 +41,21 @@ interface InspectorOptions { useWellFormattedUrl: boolean; } +/** Data related to the v8 inspector. */ +interface V8Data { + session: inspector.Session; + // Options for behavior when interfacing with the Inspector API. + inspectorOptions: InspectorOptions; + inspector: V8Inspector; + // Store the v8 setBreakpoint parameters for each v8 breakpoint so that later + // the recorded parameters can be used to reset the breakpoints. + setBreakpointsParams: { + [ + v8BreakpointId: string + ]: inspector.Debugger.SetBreakpointByUrlParameterType; + }; +} + /** * In older versions of Node, the script source as seen by the Inspector * backend is wrapped in `require('module').wrapper`, and in new versions @@ -68,7 +83,6 @@ export class InspectorDebugApi implements debugapi.DebugApi { fileStats: ScanStats; breakpoints: {[id: string]: BreakpointData} = {}; sourcemapper: SourceMapper; - session: inspector.Session; // TODO: listeners, scrpitmapper, location mapper and breakpointmapper can use // Map in the future after resolving Map.prototype.get(key) returns V or // undefined. @@ -81,9 +95,9 @@ export class InspectorDebugApi implements debugapi.DebugApi { // stackdriver breakpoint id. breakpointMapper: {[id: string]: stackdriver.BreakpointId[]} = {}; numBreakpoints = 0; - // Options for behavior when interfacing with the Inspector API. - private inspectorOptions: InspectorOptions; - v8Inspector: V8Inspector; + numBreakpointHitsBeforeReset = 0; + v8: V8Data; + constructor( logger: consoleLogLevel.Logger, config: ResolvedDebugAgentConfig, @@ -94,25 +108,36 @@ export class InspectorDebugApi implements debugapi.DebugApi { this.config = config; this.fileStats = jsFiles; this.sourcemapper = sourcemapper; - this.session = new inspector.Session(); - this.session.connect(); - this.session.on('Debugger.scriptParsed', script => { + this.scriptMapper = {}; + this.v8 = this.createV8Data(); + } + + /** Creates a new V8 Debugging session and the related data. */ + private createV8Data(): V8Data { + const session = new inspector.Session(); + session.connect(); + session.on('Debugger.scriptParsed', script => { this.scriptMapper[script.params.scriptId] = script.params; }); - this.session.post('Debugger.enable'); - this.session.post('Debugger.setBreakpointsActive', {active: true}); - this.session.on('Debugger.paused', message => { + session.post('Debugger.enable'); + session.post('Debugger.setBreakpointsActive', {active: true}); + session.on('Debugger.paused', message => { try { this.handleDebugPausedEvent(message.params); } catch (error) { this.logger.error(error); } }); - this.inspectorOptions = { - // Well-Formatted URL is required in Node 10.11.1+. - useWellFormattedUrl: utils.satisfies(process.version, '>10.11.0'), + + return { + session, + inspectorOptions: { + // Well-Formatted URL is required in Node 10.11.1+. + useWellFormattedUrl: utils.satisfies(process.version, '>10.11.0'), + }, + inspector: new V8Inspector(session), + setBreakpointsParams: {}, }; - this.v8Inspector = new V8Inspector(this.session); } set( @@ -219,7 +244,8 @@ export class InspectorDebugApi implements debugapi.DebugApi { if (!this.breakpointMapper[breakpointData.id]) { // When breakpointmapper does not countain current v8/inspector breakpoint // id, we should remove this breakpoint from v8. - result = this.v8Inspector.removeBreakpoint(breakpointData.id); + result = this.v8.inspector.removeBreakpoint(breakpointData.id); + delete this.v8.setBreakpointsParams[breakpointData.id]; } delete this.breakpoints[breakpoint.id]; delete this.listeners[breakpoint.id]; @@ -297,7 +323,7 @@ export class InspectorDebugApi implements debugapi.DebugApi { } disconnect(): void { - this.session.disconnect(); + this.v8.session.disconnect(); } numBreakpoints_(): number { @@ -487,7 +513,7 @@ export class InspectorDebugApi implements debugapi.DebugApi { let v8BreakpointId; // v8/inspector breakpoint id if (!this.locationMapper[locationStr]) { // The first time when a breakpoint was set to this location. - const rawUrl = this.inspectorOptions.useWellFormattedUrl + const rawUrl = this.v8.inspectorOptions.useWellFormattedUrl ? `file://${matchingScript}` : matchingScript; // on windows on Node 11+, the url must start with file:/// @@ -496,17 +522,20 @@ export class InspectorDebugApi implements debugapi.DebugApi { process.platform === 'win32' && utils.satisfies(process.version, '>=11') ? rawUrl.replace(/^file:\/\//, 'file:///').replace(/\\/g, '/') : rawUrl; - const res = this.v8Inspector.setBreakpointByUrl({ + const params = { lineNumber: line - 1, url, columnNumber: column - 1, condition: breakpoint.condition || undefined, - }); + }; + const res = this.v8.inspector.setBreakpointByUrl(params); if (res.error || !res.response) { // Error case. return null; } v8BreakpointId = res.response.breakpointId; + this.v8.setBreakpointsParams[v8BreakpointId] = params; + this.locationMapper[locationStr] = []; this.breakpointMapper[v8BreakpointId] = []; } else { @@ -593,7 +622,7 @@ export class InspectorDebugApi implements debugapi.DebugApi { const evaluatedExpressions = breakpoint.expressions.map(exp => { // returnByValue is set to true here so that the JSON string of the // value will be returned to log. - const result = state.evaluate(exp, frame, that.v8Inspector, true); + const result = state.evaluate(exp, frame, that.v8.inspector, true); if (result.error) { return result.error; } else { @@ -608,7 +637,7 @@ export class InspectorDebugApi implements debugapi.DebugApi { breakpoint, this.config, this.scriptMapper, - this.v8Inspector + this.v8.inspector ); if ( breakpoint.location && @@ -642,5 +671,37 @@ export class InspectorDebugApi implements debugapi.DebugApi { } catch (e) { this.logger.warn('Internal V8 error on breakpoint event: ' + e); } + + this.tryResetV8Debugger(); + } + + /** + * Periodically resets breakpoints to prevent memory leaks in V8 (for holding + * contexts of previous breakpoint hits). + */ + private tryResetV8Debugger() { + this.numBreakpointHitsBeforeReset += 1; + if ( + this.numBreakpointHitsBeforeReset < this.config.resetV8DebuggerThreshold + ) { + return; + } + this.numBreakpointHitsBeforeReset = 0; + + const storedParams = this.v8.setBreakpointsParams; + + // Re-connect the session to clean the memory usage. + this.disconnect(); + this.scriptMapper = {}; + this.v8 = this.createV8Data(); + this.v8.setBreakpointsParams = storedParams; + + // Setting the v8 breakpoints again according to the stored parameters. + for (const params of Object.values(storedParams)) { + const res = this.v8.inspector.setBreakpointByUrl(params); + if (res.error || !res.response) { + this.logger.error('Error upon re-setting breakpoint: ' + res); + } + } } } diff --git a/test/test-debuglet.ts b/test/test-debuglet.ts index 82369828..6c923236 100644 --- a/test/test-debuglet.ts +++ b/test/test-debuglet.ts @@ -286,6 +286,20 @@ describe('Debuglet', () => { debuglet.start(); }); + it('should have default resetV8DebuggerThreshold value', done => { + const debuglet = new Debuglet(new Debug({}, packageInfo), {}); + assert.strictEqual(debuglet.config.resetV8DebuggerThreshold, 30); + done(); + }); + + it('should overwrite resetV8DebuggerThreshold when available', done => { + const debuglet = new Debuglet(new Debug({}, packageInfo), { + resetV8DebuggerThreshold: 123, + }); + assert.strictEqual(debuglet.config.resetV8DebuggerThreshold, 123); + done(); + }); + it('should not fail if files cannot be read', done => { const MOCKED_DIRECTORY = process.cwd(); const errors: Array<{filename: string; error: string}> = []; diff --git a/test/test-v8debugapi.ts b/test/test-v8debugapi.ts index 741948bc..a27b7b02 100644 --- a/test/test-v8debugapi.ts +++ b/test/test-v8debugapi.ts @@ -35,6 +35,7 @@ import * as extend from 'extend'; import * as debugapi from '../src/agent/v8/debugapi'; import {defaultConfig} from '../src/agent/config'; import {StatusMessage} from '../src/client/stackdriver/status-message'; +import {InspectorDebugApi} from '../src/agent/v8/inspector-debugapi'; import * as scanner from '../src/agent/io/scanner'; import * as SourceMapper from '../src/agent/io/sourcemapper'; import * as path from 'path'; @@ -722,6 +723,76 @@ describe('v8debugapi', () => { }); }); + describe('InspectorDebugApi', () => { + let oldLPS: number; + let oldDS: number; + + before(() => { + oldLPS = config.log.maxLogsPerSecond; + oldDS = config.log.logDelaySeconds; + config.log.maxLogsPerSecond = config.resetV8DebuggerThreshold * 3; + config.log.logDelaySeconds = 1; + }); + + after(() => { + config.log.maxLogsPerSecond = oldLPS; + config.log.logDelaySeconds = oldDS; + assert(stateIsClean(api)); + }); + + it('should perform v8 breakpoints reset when meeting threshold', done => { + // The test is only eligible for the InspectorDebugApi test target. + if (!(api instanceof InspectorDebugApi)) { + done(); + return; + } + + const bp: stackdriver.Breakpoint = { + id: breakpointInFoo.id, + location: breakpointInFoo.location, + action: 'LOG', + logMessageFormat: 'cat', + } as {} as stackdriver.Breakpoint; + api.set(bp, err1 => { + let logpointEvaluatedTimes = 0; + + assert.ifError(err1); + api.log( + bp, + () => { + logpointEvaluatedTimes += 1; + }, + () => false + ); + + const inspectorDebugApi = api as InspectorDebugApi; + const v8BeforeReset = inspectorDebugApi.v8; + + // The loop should trigger the breakpoints reset. + for (let i = 0; i < config.resetV8DebuggerThreshold; i++) { + code.foo(1); + } + + // Expect the current v8 data is no longer the previous one. + assert.notStrictEqual(inspectorDebugApi.v8, v8BeforeReset); + + // Make sure the logpoint is still triggered correctly after the second reset. + for (let i = 0; i < config.resetV8DebuggerThreshold + 1; i++) { + code.foo(1); + } + assert.strictEqual( + logpointEvaluatedTimes, + config.resetV8DebuggerThreshold * 2 + 1 + ); + + api.clear(bp, err2 => { + assert.ifError(err2); + done(); + }); + }); + }); + }); + describe('set and wait', () => { it('should be possible to wait on a breakpoint', done => { // clone a clean breakpointInFoo From a0df5b708f67da52df34b11fd3b10bbfca89bfc3 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Wed, 2 Jun 2021 12:31:34 -0400 Subject: [PATCH 3/3] chore: release 5.2.1 (#960) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- CHANGELOG.md | 7 +++++++ package.json | 2 +- samples/package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db526a06..b1d49fbc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Node.js Agent for Google Cloud Debug ChangeLog +### [5.2.1](https://www.github.com/googleapis/cloud-debug-nodejs/compare/v5.2.0...v5.2.1) (2021-05-31) + + +### Bug Fixes + +* periodically reset v8 session to prevent memory leak ([#957](https://www.github.com/googleapis/cloud-debug-nodejs/issues/957)) ([7735425](https://www.github.com/googleapis/cloud-debug-nodejs/commit/7735425ee8999c6ab1c30706ddf014315309705c)) + ## [5.2.0](https://www.github.com/googleapis/cloud-debug-nodejs/compare/v5.1.3...v5.2.0) (2021-05-04) diff --git a/package.json b/package.json index 46157e0e..300c4bdf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@google-cloud/debug-agent", - "version": "5.2.0", + "version": "5.2.1", "author": "Google Inc.", "description": "Stackdriver Debug Agent for Node.js", "main": "./build/src/index", diff --git a/samples/package.json b/samples/package.json index 9d49ce9e..c100321e 100644 --- a/samples/package.json +++ b/samples/package.json @@ -17,7 +17,7 @@ "test": "mocha" }, "dependencies": { - "@google-cloud/debug-agent": "^5.2.0", + "@google-cloud/debug-agent": "^5.2.1", "express": "4.17.1" }, "devDependencies": {