Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 2 additions & 8 deletions core/packages/gax/src/apitypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,7 @@ export interface GRPCCallResult {
// when it might be useful for users.
export interface RequestType {
[index: string]:
| string
| number
| RequestType
| Array<string | number | RequestType>;
string | number | RequestType | Array<string | number | RequestType>;
}
export type ResponseType = {} | null;
export type NextPageRequestType = {
Expand Down Expand Up @@ -85,10 +82,7 @@ export type BiDiStreamingCall = (
options: {},
) => Duplex & GRPCCallResult;
export type GRPCCall =
| UnaryCall
| ServerStreamingCall
| ClientStreamingCall
| BiDiStreamingCall;
UnaryCall | ServerStreamingCall | ClientStreamingCall | BiDiStreamingCall;

// GAX wraps gRPC calls so that the wrapper functions return either a
// cancellable promise, or a stream (also cancellable!)
Expand Down
7 changes: 4 additions & 3 deletions core/packages/gax/src/fallbackServiceStub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
* limitations under the License.
*/

import type {Response as NodeFetchResponse} from 'node-fetch' with {'resolution-mode': 'import'};
import type {Response as NodeFetchResponse} from 'node-fetch' with {
'resolution-mode': 'import',
};

import {AuthClient, GoogleAuth, gaxios} from 'google-auth-library';
import * as serializer from 'proto3-json-serializer';
Expand All @@ -33,8 +35,7 @@
// - https://github.com/node-fetch/node-fetch#custom-agent
// - https://github.com/googleapis/gax-nodejs/pull/1534
let agentOption:
| ((parsedUrl: {protocol: string}) => HttpAgent | HttpsAgent)
| null = null;
((parsedUrl: {protocol: string}) => HttpAgent | HttpsAgent) | null = null;
if (isNodeJS()) {
const http = require('http');
const https = require('https');
Expand Down Expand Up @@ -198,7 +199,7 @@
(err instanceof Error && err.name !== 'AbortError'))
) {
if (callback) {
callback(err);

Check warning on line 202 in core/packages/gax/src/fallbackServiceStub.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid calling back inside of a promise

Check warning on line 202 in core/packages/gax/src/fallbackServiceStub.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid calling back inside of a promise
}
streamArrayParser.emit('error', err);
}
Expand All @@ -210,15 +211,15 @@
Promise.resolve(response.ok),
response.arrayBuffer(),
])
.then(([ok, buffer]: [boolean, Buffer | ArrayBuffer]) => {

Check failure on line 214 in core/packages/gax/src/fallbackServiceStub.ts

View workflow job for this annotation

GitHub Actions / lint

Each then() should return a value or throw

Check warning on line 214 in core/packages/gax/src/fallbackServiceStub.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid nesting promises

Check failure on line 214 in core/packages/gax/src/fallbackServiceStub.ts

View workflow job for this annotation

GitHub Actions / lint

Each then() should return a value or throw

Check warning on line 214 in core/packages/gax/src/fallbackServiceStub.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid nesting promises
const response = responseDecoder(rpc, ok, buffer);
callback!(null, response);
})
.catch((err: Error) => {

Check warning on line 218 in core/packages/gax/src/fallbackServiceStub.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid nesting promises

Check warning on line 218 in core/packages/gax/src/fallbackServiceStub.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid nesting promises
if (!cancelRequested || err.name !== 'AbortError') {
if (rpc.responseStream) {
if (callback) {
callback(err);

Check warning on line 222 in core/packages/gax/src/fallbackServiceStub.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid calling back inside of a promise

Check warning on line 222 in core/packages/gax/src/fallbackServiceStub.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid calling back inside of a promise
}
streamArrayParser.emit('error', err);
} else {
Expand Down Expand Up @@ -247,11 +248,11 @@
.catch((err: unknown) => {
if (rpc.responseStream) {
if (callback) {
callback(err);

Check warning on line 251 in core/packages/gax/src/fallbackServiceStub.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid calling back inside of a promise

Check warning on line 251 in core/packages/gax/src/fallbackServiceStub.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid calling back inside of a promise
}
streamArrayParser.emit('error', err);
} else if (callback) {
callback(err);

Check warning on line 255 in core/packages/gax/src/fallbackServiceStub.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid calling back inside of a promise

Check warning on line 255 in core/packages/gax/src/fallbackServiceStub.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid calling back inside of a promise
} else {
throw err;
}
Expand Down
2 changes: 1 addition & 1 deletion core/packages/gax/src/paginationCalls/pagedApiCaller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
SimpleCallbackFunction,
UnaryCall,
RequestType,
APICallback,
} from '../apitypes';
import {APICallback} from '../apitypes';
import {OngoingCall, OngoingCallPromise} from '../call';
import {CallOptions} from '../gax';
import {GoogleError} from '../googleError';
Expand Down Expand Up @@ -164,7 +164,7 @@
const maxResults = settings.maxResults || -1;

const resourceCollector = new ResourceCollector(apiCall, maxResults);
resourceCollector.processAllPages(request).then(

Check failure on line 167 in core/packages/gax/src/paginationCalls/pagedApiCaller.ts

View workflow job for this annotation

GitHub Actions / lint

Expected catch() or return

Check failure on line 167 in core/packages/gax/src/paginationCalls/pagedApiCaller.ts

View workflow job for this annotation

GitHub Actions / lint

Expected catch() or return
resources => ongoingCall.callback(null, resources),
err => ongoingCall.callback(err),
);
Expand Down
12 changes: 9 additions & 3 deletions core/packages/gax/src/streamingCalls/streaming.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,22 @@

/* This file describes the gRPC-streaming. */

import {Duplex, DuplexOptions, Readable, Stream, Writable} from 'stream';
import {
Duplex,
DuplexOptions,
Readable,
Stream,
Writable,
PassThrough,
} from 'stream';

import {
APICallback,
CancellableStream,
GRPCCallResult,
RequestType,
SimpleCallbackFunction,
ResponseType,
} from '../apitypes';
import {
RetryOptions,
Expand All @@ -32,8 +40,6 @@ import {
} from '../gax';
import {GoogleError} from '../googleError';
import {Status} from '../status';
import {PassThrough} from 'stream';
import {ResponseType} from '../apitypes';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const duplexify: DuplexifyConstructor = require('duplexify');
// eslint-disable-next-line @typescript-eslint/no-var-requires
Expand Down
10 changes: 7 additions & 3 deletions core/packages/gax/src/transcoding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,9 @@ function validateUriPath(propertyName: string, value: string): void {
// valid domain-scoped resource segments (e.g. projects/example.com:project-id).
const segments = value.split('/');
if (segments.some(segment => segment === '.' || segment === '..')) {
throw new Error(`Value for ${propertyName} must not contain segments that are exactly . or ..`);
throw new Error(
`Value for ${propertyName} must not contain segments that are exactly . or ..`,
);
}
}
}
Expand All @@ -164,7 +166,9 @@ export function buildQueryStringComponents(
} else {
resultList.push(
`${prefix}${encodeWithoutSlashes(key)}=${encodeWithoutSlashes(
requestValue === null || requestValue === undefined ? 'null' : requestValue.toString(),
requestValue === null || requestValue === undefined
? 'null'
: requestValue.toString(),
)}`,
);
}
Expand All @@ -187,7 +191,7 @@ export function buildQueryStringComponents(
export function encodeWithSlashes(str: string): string {
return encodeURIComponent(str).replace(
/[!'()*]/g, // Characters preserved by encodeURIComponent
character => '%' + character.charCodeAt(0).toString(16).toUpperCase()
character => '%' + character.charCodeAt(0).toString(16).toUpperCase(),
);
}

Expand Down
145 changes: 67 additions & 78 deletions core/packages/gax/test/unit/apiCallable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1106,8 +1106,8 @@ describe('createApiCall', () => {
});

describe('Promise', () => {
it('calls api call', done => {
let deadlineArg: string;
it('calls api call', async () => {
let deadlineArg: string | undefined = undefined;
function func(
argument: {},
metadata: {},
Expand All @@ -1119,14 +1119,10 @@ describe('Promise', () => {
}
const apiCall = createApiCall(func);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(apiCall as any)(null)
.then((response: number[]) => {
assert.ok(Array.isArray(response));
assert.strictEqual(response[0], 42);
assert.ok(deadlineArg);
return done();
})
.catch(done);
const response = (await (apiCall as any)(null)) as number[];
assert.ok(Array.isArray(response));
assert.strictEqual(response[0], 42);
assert.ok(deadlineArg);
});

it('emits error on rejected promise', async () => {
Expand All @@ -1143,28 +1139,30 @@ describe('Promise', () => {
await assert.rejects(apiCall({}, undefined));
});

it('has cancel method', done => {
it('has cancel method', async () => {
function func(argument: {}, metadata: {}, options: {}, callback: Function) {
setTimeout(() => {
callback(null, 42);
}, 0);
}
const apiCall = createApiCall(func, {cancel: done});
const apiCall = createApiCall(func);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const promise = (apiCall as any)(null);
promise
.then(() => {
return done(new Error('should not reach'));
})
.catch((err: {code: number}) => {
assert.strictEqual(typeof promise.cancel, 'function');
promise.cancel();
await assert.rejects(
async () => {
await promise;
},
(err: GoogleError) => {
assert(err instanceof GoogleError);
assert.strictEqual(err.code, status.CANCELLED);
done();
});
promise.cancel();
return true;
},
);
});

it('cancels retrying call', done => {
it('cancels retrying call', async () => {
const retryOptions = utils.createRetryOptions(0, 0, 0, 0, 0, 0, 100);

let callCount = 0;
Expand Down Expand Up @@ -1192,18 +1190,13 @@ describe('Promise', () => {
});
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const promise = (apiCall as any)(null);
promise
.then(() => {
return done(new Error('should not reach'));
})
.catch(() => {
assert(callCount < 4);
done();
})
.catch(done);
setTimeout(() => {
promise.cancel();
}, 15);
await assert.rejects(async () => {
await promise;
});
assert(callCount < 4);
});

it('does not return promise when callback is supplied', done => {
Expand Down Expand Up @@ -1259,9 +1252,9 @@ describe('retryable', () => {
});
});

it('retries the API call with promise', done => {
it('retries the API call with promise', async () => {
let toAttempt = 3;
let deadlineArg: string;
let deadlineArg: string | undefined = undefined;
function func(
argument: {},
metadata: {},
Expand All @@ -1277,18 +1270,14 @@ describe('retryable', () => {
callback(null, 1729);
}
const apiCall = createApiCall(func, settings);
apiCall({}, undefined)
.then(resp => {
assert.ok(Array.isArray(resp));
assert.strictEqual(resp[0], 1729);
assert.strictEqual(toAttempt, 0);
assert.ok(deadlineArg);
return done();
})
.catch(done);
const resp = (await apiCall({}, undefined)) as [number, unknown, unknown];
assert.ok(Array.isArray(resp));
assert.strictEqual(resp[0], 1729);
assert.strictEqual(toAttempt, 0);
assert.ok(deadlineArg);
});

it('cancels in the middle of retries', done => {
it('cancels in the middle of retries', async () => {
let callCount = 0;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function func(argument: {}, metadata: {}, options: {}, callback: Function) {
Expand All @@ -1306,14 +1295,15 @@ describe('retryable', () => {
}
const apiCall = createApiCall(func, settings);
const promise = apiCall({}, undefined);
promise
.then(() => {
return done(new Error('should not reach'));
})
.catch((err: Error) => {
await assert.rejects(
async () => {
await promise;
},
(err: Error) => {
assert(err instanceof Error);
done();
});
return true;
},
);
});

it("doesn't retry if no codes", done => {
Expand Down Expand Up @@ -1499,7 +1489,7 @@ describe('retryable', () => {
});
});

it.skip('retries with exponential backoff', done => {
it.skip('retries with exponential backoff', async () => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

When skipping a test, please ensure there is an accompanying comment or TODO that references the correct tracking issue and accurately describes the failure reason.

References
  1. When skipping a test, ensure the accompanying comment or TODO references the correct tracking issue and accurately describes the failure reason.

const startTime = new Date();
const spy = sinon.spy(fail);

Expand All @@ -1509,23 +1499,28 @@ describe('retryable', () => {
settings: {timeout: 0, retry: retryOptions},
});

void apiCall({}, undefined, err => {
assert(err instanceof Error);
assert.strictEqual(err!.code, FAKE_STATUS_CODE_1);
assert(err!.note);
const now = new Date();
assert(
now.getTime() - startTime.getTime() >= backoff.totalTimeoutMillis!,
);
const callsLowerBound =
backoff.totalTimeoutMillis! /
(backoff.maxRetryDelayMillis + backoff.maxRpcTimeoutMillis!);
const callsUpperBound =
backoff.totalTimeoutMillis! / backoff.initialRetryDelayMillis;
assert(spy.callCount > callsLowerBound);
assert(spy.callCount < callsUpperBound);
done();
}).catch(done);
await assert.rejects(
async () => {
await apiCall({}, undefined);
},
(err: GoogleError) => {
assert(err instanceof Error);
assert.strictEqual(err!.code, FAKE_STATUS_CODE_1);
assert(err!.note);
const now = new Date();
assert(
now.getTime() - startTime.getTime() >= backoff.totalTimeoutMillis!,
);
const callsLowerBound =
backoff.totalTimeoutMillis! /
(backoff.maxRetryDelayMillis + backoff.maxRpcTimeoutMillis!);
const callsUpperBound =
backoff.totalTimeoutMillis! / backoff.initialRetryDelayMillis;
assert(spy.callCount > callsLowerBound);
assert(spy.callCount < callsUpperBound);
return true;
},
);
});

it.skip('reports A/B testing', () => {
Expand Down Expand Up @@ -1573,12 +1568,12 @@ describe('retryable', () => {
});
});

it('forwards metadata to builder', done => {
it('forwards metadata to builder', async () => {
function func(argument: {}, metadata: {}, options: {}, callback: Function) {
callback(null, {});
}

let gotHeaders: {h1?: string; h2?: string};
let gotHeaders: {h1?: string; h2?: string} = {};
const mockBuilder = (abTest: {}, headers: {}) => {
gotHeaders = headers;
};
Expand All @@ -1592,14 +1587,8 @@ describe('retryable', () => {
h1: 'val1',
h2: 'val2',
};
void apiCall({}, {otherArgs: {headers}}).then(() => {
try {
assert.strictEqual(gotHeaders.h1, 'val1');
assert.strictEqual(gotHeaders.h2, 'val2');
return done();
} catch (err) {
return done(err);
}
});
await apiCall({}, {otherArgs: {headers}});
assert.strictEqual(gotHeaders.h1, 'val1');
assert.strictEqual(gotHeaders.h2, 'val2');
});
});
3 changes: 1 addition & 2 deletions core/packages/gax/test/unit/pagedIteration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,13 @@
import assert from 'assert';
import * as pumpify from 'pumpify';
import * as sinon from 'sinon';
import {PassThrough} from 'stream';
import {PassThrough, Stream} from 'stream';
import streamEvents from 'stream-events';
import {PageDescriptor} from '../../src/paginationCalls/pageDescriptor';
import {APICallback, GaxCall, RequestType} from '../../src/apitypes';
import {describe, it, beforeEach} from 'mocha';

import * as util from './utils';
import {Stream} from 'stream';
import * as gax from '../../src/gax';
import * as warnings from '../../src/warnings';

Expand Down Expand Up @@ -68,7 +67,7 @@
expected.push(i);
}
apiCall({pageSize: pageSize}, undefined)
.then(results => {

Check failure on line 70 in core/packages/gax/test/unit/pagedIteration.ts

View workflow job for this annotation

GitHub Actions / lint

Each then() should return a value or throw

Check failure on line 70 in core/packages/gax/test/unit/pagedIteration.ts

View workflow job for this annotation

GitHub Actions / lint

Each then() should return a value or throw
assert.ok(Array.isArray(results));
assert.deepStrictEqual(results[0], expected);
assert.strictEqual(warnStub.callCount, 1);
Expand All @@ -80,9 +79,9 @@
),
);
warnStub.restore();
done();

Check warning on line 82 in core/packages/gax/test/unit/pagedIteration.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid calling back inside of a promise

Check warning on line 82 in core/packages/gax/test/unit/pagedIteration.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid calling back inside of a promise
})
.catch(done);

Check warning on line 84 in core/packages/gax/test/unit/pagedIteration.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid calling back inside of a promise

Check warning on line 84 in core/packages/gax/test/unit/pagedIteration.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid calling back inside of a promise
});
it('returns an Array of results', done => {
const apiCall = util.createApiCall(func, createOptions);
Expand All @@ -91,12 +90,12 @@
expected.push(i);
}
apiCall({}, undefined)
.then(results => {

Check failure on line 93 in core/packages/gax/test/unit/pagedIteration.ts

View workflow job for this annotation

GitHub Actions / lint

Each then() should return a value or throw

Check failure on line 93 in core/packages/gax/test/unit/pagedIteration.ts

View workflow job for this annotation

GitHub Actions / lint

Each then() should return a value or throw
assert.ok(Array.isArray(results));
assert.deepStrictEqual(results[0], expected);
done();

Check warning on line 96 in core/packages/gax/test/unit/pagedIteration.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid calling back inside of a promise

Check warning on line 96 in core/packages/gax/test/unit/pagedIteration.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid calling back inside of a promise
})
.catch(done);

Check warning on line 98 in core/packages/gax/test/unit/pagedIteration.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid calling back inside of a promise

Check warning on line 98 in core/packages/gax/test/unit/pagedIteration.ts

View workflow job for this annotation

GitHub Actions / lint

Avoid calling back inside of a promise
});

it('calls callback with an Array', done => {
Expand Down Expand Up @@ -142,7 +141,7 @@
assert.ok(Array.isArray(response));
assert(Array.isArray(response[0]));
assert.strictEqual((response[0] as Array<{}>).length, pageSize);
for (let i = 0; i < pageSize; ++i) {

Check failure on line 144 in core/packages/gax/test/unit/pagedIteration.ts

View workflow job for this annotation

GitHub Actions / lint

Each then() should return a value or throw

Check failure on line 144 in core/packages/gax/test/unit/pagedIteration.ts

View workflow job for this annotation

GitHub Actions / lint

Each then() should return a value or throw
assert.strictEqual((response[0] as Array<{}>)[i], expected);
expected++;
}
Expand Down Expand Up @@ -205,7 +204,7 @@
}
const apiCall = util.createApiCall(failingFunc, createOptions);
apiCall({}, undefined)
.then(resources => {

Check failure on line 207 in core/packages/gax/test/unit/pagedIteration.ts

View workflow job for this annotation

GitHub Actions / lint

Each then() should return a value or throw

Check failure on line 207 in core/packages/gax/test/unit/pagedIteration.ts

View workflow job for this annotation

GitHub Actions / lint

Each then() should return a value or throw
assert(Array.isArray(resources));
// @ts-ignore response type
assert.strictEqual(resources[0].length, pageSize * pagesToStream);
Expand All @@ -224,7 +223,7 @@
assert.strictEqual(response[0].length, pageSize * 2 + 2);
let expected = 0;
// @ts-ignore response type
for (let i = 0; i < response[0].length; ++i) {

Check failure on line 226 in core/packages/gax/test/unit/pagedIteration.ts

View workflow job for this annotation

GitHub Actions / lint

Each then() should return a value or throw

Check failure on line 226 in core/packages/gax/test/unit/pagedIteration.ts

View workflow job for this annotation

GitHub Actions / lint

Each then() should return a value or throw
// @ts-ignore response type
assert.strictEqual(response[0][i], expected);
expected++;
Expand Down
3 changes: 1 addition & 2 deletions core/packages/gax/test/unit/streamArrayParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@
import assert from 'assert';
import {StreamArrayParser} from '../../src/streamArrayParser';
import {before, describe, it} from 'mocha';
import {pipeline} from 'stream';
import {pipeline, PassThrough} from 'stream';
import path = require('path');
import protobuf = require('protobufjs');
import {PassThrough} from 'stream';
import {toProtobufJSON} from './utils';

interface User {
Expand Down
Loading
Loading