diff --git a/src/index.ts b/src/index.ts index c427d329a..e9aebf2d5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -33,19 +33,22 @@ const PKG = require('../../package.json'); const v1 = require('./v1'); import {Snapshot} from './snapshot'; -import {Subscription, SubscriptionMetadata, SubscriptionMetadataRaw} from './subscription'; +import {Subscription, SubscriptionMetadataRaw} from './subscription'; import {Topic, PublishOptions} from './topic'; import {CallOptions} from 'google-gax'; import {Readable} from 'stream'; import {google} from '../proto/pubsub'; import {ServiceError} from 'grpc'; +import {FlowControlOptions} from './lease-manager'; +import {BatchPublishOptions} from './publisher'; const opts = {} as gax.GrpcClientOptions; const {grpc} = new gax.GrpcClient(opts); +export type SeekCallback = RequestCallback; export interface GetSubscriptionMetadataCallback { - (err: ServiceError|null, res?: google.pubsub.v1.Subscription|null): void; + (err: ServiceError|null, res?: google.pubsub.v1.ISubscription|null): void; } export interface ExistsCallback { @@ -56,28 +59,22 @@ export interface GetCallOptions extends CallOptions { autoCreate?: boolean; } -export interface PushConfig { - pushEndpoint: string; - attibutes?: Map; +export interface Attributes { + [key: string]: string; } export interface SubscriptionCallOptions { - flowControl?: - {maxBytes?: number, maxMessages?: number, allowExcessMessages: boolean;}; + flowControl?: FlowControlOptions; maxConnections?: number; topic?: Topic; ackDeadline?: number; autoPaginate?: boolean; gaxOpts?: CallOptions; - batching?: - {maxBytes?: number, maxMessages?: number, maxMilliseconds?: number}; + batching?: BatchPublishOptions; } -export interface PublisherCallOptions { - batching?: - {maxBytes?: number, maxMessages?: number, maxMilliseconds?: number}; -} + /** * @callback CreateTopicCallback @@ -87,7 +84,7 @@ export interface PublisherCallOptions { */ export interface CreateSnapshotCallback { (err: Error|null, snapshot?: Snapshot|null, - apiResponse?: google.pubsub.v1.Snapshot): void; + apiResponse?: google.pubsub.v1.ISnapshot): void; } /** @@ -95,7 +92,7 @@ export interface CreateSnapshotCallback { * @property {Snapshot}. * @property {object} 1 The full API response. */ -export type CreateSnapshotResponse = [Snapshot, google.pubsub.v1.Snapshot]; +export type CreateSnapshotResponse = [Snapshot, google.pubsub.v1.ISnapshot]; /** * Project ID placeholder. @@ -112,7 +109,7 @@ export type Metadata = any; * @property {Topic} 0 The new {@link Topic}. * @property {object} 1 The full API response. */ -export type CreateTopicResponse = [Topic, google.pubsub.v1.Topic]; +export type CreateTopicResponse = [Topic, google.pubsub.v1.ITopic]; /** * @callback CreateTopicCallback @@ -122,7 +119,7 @@ export type CreateTopicResponse = [Topic, google.pubsub.v1.Topic]; */ export interface CreateTopicCallback { (err?: Error|null, topic?: Topic|null, - apiResponse?: google.pubsub.v1.Topic): void; + apiResponse?: google.pubsub.v1.ITopic): void; } /** @@ -133,7 +130,7 @@ export interface CreateTopicCallback { */ export interface CreateSubscriptionCallback { (err?: Error|null, subscription?: Subscription|null, - apiResponse?: google.pubsub.v1.Subscription): void; + apiResponse?: google.pubsub.v1.ISubscription): void; } export type Client = 'PublisherClient'|'SubscriberClient'; @@ -160,11 +157,11 @@ export interface RequestCallback { * @property {object} 1 The full API response. */ export type CreateSubscriptionResponse = - [Subscription, google.pubsub.v1.Subscription]; + [Subscription, google.pubsub.v1.ISubscription]; export interface CreateSubscriptionOptions { - flowControl?: {maxBytes?: number; maxMessages?: number;}; + flowControl?: FlowControlOptions; gaxOpts?: CallOptions; /** * Duration in seconds. @@ -406,7 +403,7 @@ export class PubSub { name: subscription.name, }); - this.request( + this.request( { client: 'SubscriberClient', method: 'createSubscription', diff --git a/src/publisher.ts b/src/publisher.ts index ba62612fd..a738268e7 100644 --- a/src/publisher.ts +++ b/src/publisher.ts @@ -17,21 +17,26 @@ import {promisifyAll} from '@google-cloud/promisify'; import * as arrify from 'arrify'; import {CallOptions} from 'google-gax'; -import {ServiceError} from 'grpc'; +import {google} from '../proto/pubsub'; const each = require('async-each'); import * as extend from 'extend'; import * as is from 'is'; import {Topic} from './topic'; +import {Attributes} from '.'; +import {ServiceError} from 'grpc'; -export interface PublishCallback { - (err: null|ServiceError, messageId: string): void; +interface Inventory { + callbacks: PublishCallback[]; + queued: google.pubsub.v1.IPubsubMessage[]; + bytes: number; } -interface PublishApiResponse { - messageIds: string[]; +export interface PublishCallback { + (err?: ServiceError|null, messageId?: string|null): void; } + /** * @typedef BatchPublishOptions * @property {number} [maxBytes=1024^2 * 5] The maximum number of bytes to @@ -41,7 +46,7 @@ interface PublishApiResponse { * @property {number} [maxMilliseconds=100] The maximum duration to wait before * sending a payload. */ -interface BatchPublishOptions { +export interface BatchPublishOptions { maxBytes?: number; maxMessages?: number; maxMilliseconds?: number; @@ -80,7 +85,7 @@ export class Publisher { // tslint:disable-next-line variable-name Promise?: PromiseConstructor; topic: Topic; - inventory_; + inventory_: Inventory; settings!: PublishOptions; timeoutHandle_?: NodeJS.Timer; constructor(topic: Topic, options?: PublishOptions) { @@ -157,17 +162,22 @@ export class Publisher { * //- * publisher.publish(data).then((messageId) => {}); */ - publish(data: Buffer, attributes?: object): Promise; + publish(data: Buffer, attributes?: Attributes): Promise; publish(data: Buffer, callback: PublishCallback): void; - publish(data: Buffer, attributes: object, callback: PublishCallback): void; - publish(data: Buffer, attributes?, callback?): Promise|void { + publish(data: Buffer, attributes: Attributes, callback: PublishCallback): + void; + publish( + data: Buffer, attributesOrCallback?: Attributes|PublishCallback, + callback?: PublishCallback): Promise|void { if (!(data instanceof Buffer)) { throw new TypeError('Data must be in the form of a Buffer.'); } - if (is.fn(attributes)) { - callback = attributes; - attributes = {}; - } + + const attributes = + typeof attributesOrCallback === 'object' ? attributesOrCallback : {}; + callback = typeof attributesOrCallback === 'function' ? + attributesOrCallback : + callback; // Ensure the `attributes` object only has string values for (const key of Object.keys(attributes)) { const value = attributes[key]; @@ -185,10 +195,10 @@ export class Publisher { this.publish_(); } // add it to the queue! - this.queue_(data, attributes, callback); + this.queue_(data, attributes, callback!); // next lets check if this message brings us to the message cap or if we // hit the max byte limit - const hasMaxMessages = this.inventory_.queued.length === opts.maxMessages!; + const hasMaxMessages = this.inventory_.queued.length === opts.maxMessages; if (this.inventory_.bytes >= opts.maxBytes! || hasMaxMessages) { this.publish_(); return; @@ -247,7 +257,7 @@ export class Publisher { topic: this.topic.name, messages, }; - this.topic.request( + this.topic.request( { client: 'PublisherClient', method: 'publish', @@ -256,7 +266,7 @@ export class Publisher { }, (err, resp) => { const messageIds = arrify(resp && resp.messageIds); - each(callbacks, (callback, next) => { + each(callbacks, (callback: PublishCallback, next: Function) => { const messageId = messageIds[callbacks.indexOf(callback)]; callback(err, messageId); next(); @@ -272,13 +282,16 @@ export class Publisher { * @param {object} attributes The message attributes. * @param {function} callback The callback function. */ - queue_(data, attrs, callback) { + queue_(data: Buffer, attrs: Attributes): Promise; + queue_(data: Buffer, attrs: Attributes, callback: PublishCallback): void; + queue_(data: Buffer, attrs: Attributes, callback?: PublishCallback): + void|Promise { this.inventory_.queued.push({ data, attributes: attrs, }); this.inventory_.bytes += data.length; - this.inventory_.callbacks.push(callback); + this.inventory_.callbacks.push(callback!); } } diff --git a/src/snapshot.ts b/src/snapshot.ts index 58150c9ca..b5940397c 100644 --- a/src/snapshot.ts +++ b/src/snapshot.ts @@ -15,9 +15,12 @@ */ import {promisifyAll} from '@google-cloud/promisify'; -import * as is from 'is'; +import {CallOptions} from 'google-gax'; -import {PubSub} from '.'; +import {google} from '../proto/pubsub'; + +import {CreateSnapshotCallback, CreateSnapshotResponse, RequestCallback, SeekCallback, Subscription} from '.'; +import {PubSub} from './index'; import * as util from './util'; /** @@ -85,85 +88,17 @@ import * as util from './util'; * }); */ export class Snapshot { - parent; + parent: Subscription|PubSub; name: string; // tslint:disable-next-line variable-name Promise?: PromiseConstructor; - create; - seek; - metadata; - constructor(parent, name: string) { - if (parent.Promise) { + metadata!: google.pubsub.v1.ISnapshot; + constructor(parent: Subscription|PubSub, name: string) { + if (parent instanceof PubSub) { this.Promise = parent.Promise; } this.parent = parent; this.name = Snapshot.formatName_(parent.projectId, name); - if (is.fn(parent.createSnapshot)) { - /** - * Create a snapshot with the given name. - * - * **This is only available if you accessed this object through - * {@link Subscription#snapshot}.** - * - * @method Snapshot#create - * @param {string} name Name of the snapshot. - * @param {function} [callback] The callback function. - * @param {?error} callback.err An error from the API call, may be null. - * @param {Snapshot} callback.snapshot The newly created - * snapshot. - * @param {object} callback.apiResponse The full API response from the - * service. - * - * @example - * const subscription = pubsub.subscription('my-subscription'); - * const snapshot = subscription.snapshot('my-snapshot'); - * - * const callback = (err, snapshot, apiResponse) => { - * if (!err) { - * // The snapshot was created successfully. - * } - * }; - * - * snapshot.create('my-snapshot', callback); - * - * //- - * // If the callback is omitted, we'll return a Promise. - * //- - * snapshot.create('my-snapshot').then((data) => { - * const snapshot = data[0]; - * const apiResponse = data[1]; - * }); - */ - this.create = parent.createSnapshot.bind(parent, name); - } - if (is.fn(parent.seek)) { - /** - * Seeks an existing subscription to the snapshot. - * - * **This is only available if you accessed this object through - * {@link Subscription#snapshot}.** - * - * @method Snapshot#seek - * @param {function} callback The callback function. - * @param {?error} callback.err An error from the API call, may be null. - * @param {object} callback.apiResponse The full API response from the - * service. - * - * @example - * const subscription = pubsub.subscription('my-subscription'); - * const snapshot = subscription.snapshot('my-snapshot'); - * - * snapshot.seek((err, apiResponse) => {}); - * - * //- - * // If the callback is omitted, we'll return a Promise. - * //- - * snapshot.seek().then((data) => { - * const apiResponse = data[0]; - * }); - */ - this.seek = parent.seek.bind(parent, name); - } } /** @@ -185,12 +120,15 @@ export class Snapshot { * const apiResponse = data[0]; * }); */ - delete(callback) { + delete(): Promise; + delete(callback: RequestCallback): void; + delete(callback?: RequestCallback): + void|Promise { const reqOpts = { snapshot: this.name, }; callback = callback || util.noop; - this.parent.request( + this.parent.request( { client: 'SubscriberClient', method: 'deleteSnapshot', @@ -207,8 +145,97 @@ export class Snapshot { static formatName_(projectId: string, name: string) { return 'projects/' + projectId + '/snapshots/' + name.split('/').pop(); } + + /** + * Create a snapshot with the given name. + * + * **This is only available if you accessed this object through + * {@link Subscription#snapshot}.** + * + * @method Snapshot#create + * @param {string} name Name of the snapshot. + * @param {function} [callback] The callback function. + * @param {?error} callback.err An error from the API call, may be null. + * @param {Snapshot} callback.snapshot The newly created + * snapshot. + * @param {object} callback.apiResponse The full API response from the + * service. + * + * @example + * const subscription = pubsub.subscription('my-subscription'); + * const snapshot = subscription.snapshot('my-snapshot'); + * + * const callback = (err, snapshot, apiResponse) => { + * if (!err) { + * // The snapshot was created successfully. + * } + * }; + * + * snapshot.create('my-snapshot', callback); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * snapshot.create('my-snapshot').then((data) => { + * const snapshot = data[0]; + * const apiResponse = data[1]; + * }); + */ + create(gaxOpts?: CallOptions): Promise; + create(callback: CreateSnapshotCallback): void; + create(gaxOpts: CallOptions, callback: CreateSnapshotCallback): void; + create( + gaxOpts?: CallOptions|CreateSnapshotCallback, + callback?: CreateSnapshotCallback): void|Promise { + if (!(this.parent instanceof Subscription)) { + throw new Error( + `This is only available if you accessed this object through Subscription#snapshot`); + } + return (this.parent as Subscription) + .createSnapshot(this.name, gaxOpts! as CallOptions, callback!); + } + + /** + * Seeks an existing subscription to the snapshot. + * + * **This is only available if you accessed this object through + * {@link Subscription#snapshot}.** + * + * @method Snapshot#seek + * @param {function} callback The callback function. + * @param {?error} callback.err An error from the API call, may be null. + * @param {object} callback.apiResponse The full API response from the + * service. + * + * @example + * const subscription = pubsub.subscription('my-subscription'); + * const snapshot = subscription.snapshot('my-snapshot'); + * + * snapshot.seek((err, apiResponse) => {}); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * snapshot.seek().then((data) => { + * const apiResponse = data[0]; + * }); + */ + seek(gaxOpts?: CallOptions): Promise; + seek(callback: SeekCallback): void; + seek(gaxOpts: CallOptions, callback: SeekCallback): void; + seek(gaxOpts?: CallOptions|SeekCallback, callback?: SeekCallback): + void|Promise { + if (!(this.parent instanceof Subscription)) { + throw new Error( + `This is only available if you accessed this object through Subscription#snapshot`); + } + return (this.parent as Subscription) + .seek(this.name, gaxOpts! as CallOptions, callback!); + } } + + /*! Developer Documentation * * All async methods (except for streams) will return a Promise in the event diff --git a/src/subscription.ts b/src/subscription.ts index 75333c42b..43317028d 100644 --- a/src/subscription.ts +++ b/src/subscription.ts @@ -23,7 +23,7 @@ import * as snakeCase from 'lodash.snakecase'; import {google} from '../proto/pubsub'; -import {CreateSnapshotCallback, CreateSnapshotResponse, CreateSubscriptionCallback, CreateSubscriptionResponse, ExistsCallback, GetCallOptions, GetSubscriptionMetadataCallback, Metadata, PubSub, PushConfig, RequestCallback, SubscriptionCallOptions} from '.'; +import {CreateSnapshotCallback, CreateSnapshotResponse, CreateSubscriptionCallback, CreateSubscriptionResponse, ExistsCallback, GetCallOptions, GetSubscriptionMetadataCallback, Metadata, PubSub, RequestCallback, SeekCallback, SubscriptionCallOptions} from '.'; import {IAM} from './iam'; import {Snapshot} from './snapshot'; import {Subscriber, SubscriberOptions} from './subscriber'; @@ -203,17 +203,16 @@ export class Subscription extends EventEmitter { name: string; metadata: Metadata; - request: Function; + request: typeof PubSub.prototype.request; private _subscriber: Subscriber; constructor(pubsub: PubSub, name: string, options?: SubscriptionCallOptions) { super(); - - options = options || {}; this.pubsub = pubsub; - this.request = pubsub.request.bind(pubsub); + // tslint:disable-next-line no-any + this.request = pubsub.request.bind(pubsub) as any; this.name = Subscription.formatName_(this.projectId, name); if (options.topic) { @@ -298,6 +297,7 @@ export class Subscription extends EventEmitter { * // If the callback is omitted a Promise will be returned. * subscription.close().then(() => {}); */ + close(): Promise; close(callback: RequestCallback): void; close(callback?: RequestCallback): void|Promise { @@ -368,20 +368,20 @@ export class Subscription extends EventEmitter { name: snapshot.name, subscription: this.name, }; - this.request( + this.request( { client: 'SubscriberClient', method: 'createSnapshot', reqOpts, gaxOpts, }, - (err: Error, resp: google.pubsub.v1.Snapshot) => { + (err, resp) => { if (err) { - callback!(err, null, resp); + callback!(err, null, resp!); return; } - snapshot.metadata = resp; - callback!(null, snapshot, resp); + snapshot.metadata = resp!; + callback!(null, snapshot, resp!); }); } /** @@ -429,6 +429,7 @@ export class Subscription extends EventEmitter { callback = typeof gaxOptsOrCallback === 'function' ? gaxOptsOrCallback : callback; + callback = callback || noop; const reqOpts = { subscription: this.name, @@ -597,14 +598,14 @@ export class Subscription extends EventEmitter { * const apiResponse = data[0]; * }); */ - getMetadata(gaxOpts?: CallOptions): Promise; + getMetadata(gaxOpts?: CallOptions): Promise; getMetadata(callback: GetSubscriptionMetadataCallback): void; getMetadata(gaxOpts: CallOptions, callback: GetSubscriptionMetadataCallback): void; getMetadata( gaxOptsOrCallback?: CallOptions|GetSubscriptionMetadataCallback, callback?: GetSubscriptionMetadataCallback): - void|Promise { + void|Promise { const gaxOpts = typeof gaxOptsOrCallback === 'object' ? gaxOptsOrCallback : {}; callback = @@ -612,18 +613,18 @@ export class Subscription extends EventEmitter { const reqOpts = { subscription: this.name, }; - this.request( + this.request( { client: 'SubscriberClient', method: 'getSubscription', reqOpts, gaxOpts, }, - (err: Error, apiResponse: google.pubsub.v1.Subscription) => { + (err, apiResponse) => { if (!err) { this.metadata = apiResponse; } - callback!(err, apiResponse); + callback!(err!, apiResponse); }); } /** @@ -702,7 +703,7 @@ export class Subscription extends EventEmitter { reqOpts, gaxOpts, }, - callback); + callback!); } /** * Opens the Subscription to receive messages. In general this method @@ -769,15 +770,12 @@ export class Subscription extends EventEmitter { */ seek(snapshot: string|Date, gaxOpts?: CallOptions): Promise; - seek(snapshot: string|Date, callback: google.pubsub.v1.ISeekResponse): void; - seek( - snapshot: string|Date, gaxOpts: CallOptions, - callback: google.pubsub.v1.ISeekResponse): void; + seek(snapshot: string|Date, callback: SeekCallback): void; + seek(snapshot: string|Date, gaxOpts: CallOptions, callback: SeekCallback): + void; seek( - snapshot: string|Date, - gaxOptsOrCallback: CallOptions|google.pubsub.v1.ISeekResponse, - callback?: google.pubsub.v1.ISeekResponse): - void|Promise { + snapshot: string|Date, gaxOptsOrCallback?: CallOptions|SeekCallback, + callback?: SeekCallback): void|Promise { const gaxOpts = typeof gaxOptsOrCallback === 'object' ? gaxOptsOrCallback : {}; callback = @@ -796,6 +794,7 @@ export class Subscription extends EventEmitter { reqOpts.snapshot = Snapshot.formatName_(this.pubsub.projectId, snapshot); + } else if (is.date(snapshot)) { reqOpts.time = snapshot as Date; } else { @@ -808,7 +807,7 @@ export class Subscription extends EventEmitter { reqOpts, gaxOpts, }, - callback); + callback!); } /** * @typedef {array} SetSubscriptionMetadataResponse @@ -847,19 +846,19 @@ export class Subscription extends EventEmitter { * }); */ setMetadata(metadata: Metadata, gaxOpts?: CallOptions): - Promise; + Promise; setMetadata( metadata: Metadata, - callback: RequestCallback): void; + callback: RequestCallback): void; setMetadata( metadata: Metadata, gaxOpts: CallOptions, - callback: RequestCallback): void; + callback: RequestCallback): void; setMetadata( metadata: Metadata, gaxOptsOrCallback?: CallOptions| - RequestCallback, - callback?: RequestCallback): - void|Promise { + RequestCallback, + callback?: RequestCallback): + void|Promise { const gaxOpts = typeof gaxOptsOrCallback === 'object' ? gaxOptsOrCallback : {}; callback = @@ -881,7 +880,7 @@ export class Subscription extends EventEmitter { reqOpts, gaxOpts, }, - callback); + callback!); } /** * Sets the Subscription options. @@ -903,7 +902,7 @@ export class Subscription extends EventEmitter { * @example * const snapshot = subscription.snapshot('my-snapshot'); */ - snapshot(name: string) { + snapshot(name: string): Snapshot { return this.pubsub.snapshot.call(this, name); } /** diff --git a/src/topic.ts b/src/topic.ts index 4f9575999..7eda9d188 100644 --- a/src/topic.ts +++ b/src/topic.ts @@ -22,7 +22,7 @@ import {Readable} from 'stream'; import {google} from '../proto/pubsub'; -import {CreateSubscriptionCallback, CreateSubscriptionOptions, CreateSubscriptionResponse, CreateTopicCallback, CreateTopicResponse, ExistsCallback, GetCallOptions, Metadata, PublisherCallOptions, PubSub, RequestCallback, SubscriptionCallOptions} from '.'; +import {CreateSubscriptionCallback, CreateSubscriptionOptions, CreateSubscriptionResponse, CreateTopicCallback, CreateTopicResponse, ExistsCallback, GetCallOptions, Metadata, PubSub, RequestCallback, SubscriptionCallOptions} from '.'; import {IAM} from './iam'; import {PublishCallback, Publisher, PublishOptions} from './publisher'; import {Subscription} from './subscription'; @@ -361,9 +361,9 @@ export class Topic { * }); */ get(callback: CreateTopicCallback): void; - get(gaxOpts?: CallOptions&GetCallOptions): Promise; - get(gaxOpts: CallOptions&GetCallOptions, callback: CreateTopicCallback): void; - get(gaxOptsOrCallback?: CallOptions&GetCallOptions|CreateTopicCallback, + get(gaxOpts?: GetCallOptions): Promise; + get(gaxOpts: GetCallOptions, callback: CreateTopicCallback): void; + get(gaxOptsOrCallback?: GetCallOptions|CreateTopicCallback, callback?: CreateTopicCallback): void|Promise { const gaxOpts = typeof gaxOptsOrCallback === 'object' ? gaxOptsOrCallback : {}; @@ -423,15 +423,15 @@ export class Topic { * const apiResponse = data[0]; * }); */ - getMetadata(callback: RequestCallback): void; + getMetadata(callback: RequestCallback): void; getMetadata( gaxOpts: CallOptions, - callback: RequestCallback): void; - getMetadata(gaxOpts?: CallOptions): Promise; + callback: RequestCallback): void; + getMetadata(gaxOpts?: CallOptions): Promise; getMetadata( - gaxOptsOrCallback?: CallOptions|RequestCallback, - callback?: RequestCallback): - void|Promise { + gaxOptsOrCallback?: CallOptions|RequestCallback, + callback?: RequestCallback): + void|Promise { const gaxOpts = typeof gaxOptsOrCallback === 'object' ? gaxOptsOrCallback : {}; callback = @@ -439,7 +439,7 @@ export class Topic { const reqOpts = { topic: this.name, }; - this.request( + this.request( { client: 'PublisherClient', method: 'getTopic', diff --git a/test/snapshot.ts b/test/snapshot.ts index 619fe7831..edc63a530 100644 --- a/test/snapshot.ts +++ b/test/snapshot.ts @@ -19,12 +19,14 @@ import * as assert from 'assert'; import * as proxyquire from 'proxyquire'; import * as sinon from 'sinon'; +import {PubSub, Subscription} from '../src'; +import {Snapshot} from '../src/snapshot'; import * as util from '../src/util'; let promisified = false; const fakePromisify = Object.assign({}, pfy, { // tslint:disable-next-line variable-name - promisifyAll(Class) { + promisifyAll(Class: Snapshot) { if (Class.name === 'Snapshot') { promisified = true; } @@ -43,9 +45,7 @@ describe('Snapshot', () => { projectId: PROJECT_ID, }; - // tslint:disable-next-line no-any - const SUBSCRIPTION: any = { - Promise: {}, + const SUBSCRIPTION = { projectId: PROJECT_ID, pubsub: PUBSUB, api: {}, @@ -53,6 +53,7 @@ describe('Snapshot', () => { seek() {}, }; + before(() => { Snapshot = proxyquire('../src/snapshot', { '@google-cloud/promisify': fakePromisify, @@ -85,7 +86,9 @@ describe('Snapshot', () => { }); it('should localize parent.Promise', () => { - assert.strictEqual(snapshot.Promise, SUBSCRIPTION.Promise); + const pubsub = new PubSub(); + snapshot = new Snapshot(pubsub, SNAPSHOT_NAME); + assert.strictEqual(snapshot.Promise, pubsub.Promise); }); it('should localize the parent', () => { @@ -117,24 +120,30 @@ describe('Snapshot', () => { }); describe('with Subscription parent', () => { + let pubsub: PubSub; + let subscription: Subscription; + before(() => { + pubsub = new PubSub(PUBSUB); + subscription = pubsub.subscription('test'); + }); it('should include the create method', done => { - SUBSCRIPTION.createSnapshot = (name, callback) => { - assert.strictEqual(name, SNAPSHOT_NAME); - callback(); // The done function - }; - - const snapshot = new Snapshot(SUBSCRIPTION, SNAPSHOT_NAME); - snapshot.create(done); + sandbox.stub(subscription, 'createSnapshot') + .callsFake((name: string) => { + assert.strictEqual(name, FULL_SNAPSHOT_NAME); + done(); + }); + + const snapshot = new Snapshot(subscription, SNAPSHOT_NAME); + snapshot.create(assert.ifError); }); - it('should create a seek method', done => { - SUBSCRIPTION.seek = (name, callback) => { - assert.strictEqual(name, SNAPSHOT_NAME); - callback(); // The done function - }; - - const snapshot = new Snapshot(SUBSCRIPTION, SNAPSHOT_NAME); - snapshot.seek(done); + it('should call the seek method', done => { + sandbox.stub(subscription, 'seek').callsFake((snapshot) => { + assert.strictEqual(snapshot, FULL_SNAPSHOT_NAME); + done(); + }); + const snapshot = new Snapshot(subscription, SNAPSHOT_NAME); + snapshot.seek(assert.ifError); }); }); @@ -145,12 +154,16 @@ describe('Snapshot', () => { snapshot = new Snapshot(PUBSUB, SNAPSHOT_NAME); }); - it('should not include the create method', () => { - assert.strictEqual(snapshot.create, undefined); + it('should throw on create method', () => { + assert.throws( + () => snapshot.create(), + /This is only available if you accessed this object through Subscription#snapshot/); }); - it('should not include a seek method', () => { - assert.strictEqual(snapshot.seek, undefined); + it('should throw on seek method', () => { + assert.throws( + () => snapshot.seek(), + /This is only available if you accessed this object through Subscription#snapshot/); }); }); });