From c3c4717edd0e02b40a17839b7dd76764be4396f7 Mon Sep 17 00:00:00 2001 From: Dave Gramlich Date: Mon, 17 Oct 2016 17:14:40 -0400 Subject: [PATCH] pubsub: add promise support --- packages/pubsub/README.md | 10 ++ packages/pubsub/package.json | 2 +- packages/pubsub/src/iam.js | 31 ++++++ packages/pubsub/src/index.js | 133 ++++++++++++++++++-------- packages/pubsub/src/subscription.js | 79 ++++++++++++++- packages/pubsub/src/topic.js | 113 ++++++++++++++++++++-- packages/pubsub/system-test/pubsub.js | 6 +- packages/pubsub/test/iam.js | 17 +++- packages/pubsub/test/index.js | 30 +++++- packages/pubsub/test/subscription.js | 16 +++- packages/pubsub/test/topic.js | 44 ++++++++- 11 files changed, 420 insertions(+), 61 deletions(-) diff --git a/packages/pubsub/README.md b/packages/pubsub/README.md index 648dd668b8b..b8d8ca252ec 100644 --- a/packages/pubsub/README.md +++ b/packages/pubsub/README.md @@ -38,6 +38,16 @@ topic.subscribe('subscription-name', options, function(err, subscription) { subscription.removeListener('message', onMessage); subscription.removeListener('error', onError); }); + +// Promises are also supported by omitting callbacks. +topic.publish('New message!').then(function(data) { + var messageIds = data[0]; +}); + +// It's also possible to integrate with third-party Promise libraries. +var pubsub = require('@google-cloud/pubsub')({ + promise: require('bluebird') +}); ``` diff --git a/packages/pubsub/package.json b/packages/pubsub/package.json index 55438b3aa8d..520eb93f7fb 100644 --- a/packages/pubsub/package.json +++ b/packages/pubsub/package.json @@ -50,7 +50,7 @@ "pubsub" ], "dependencies": { - "@google-cloud/common": "^0.6.0", + "@google-cloud/common": "^0.7.0", "arrify": "^1.0.0", "extend": "^3.0.0", "google-gax": "^0.7.0", diff --git a/packages/pubsub/src/iam.js b/packages/pubsub/src/iam.js index 30501f8471d..1f953bfdc9e 100644 --- a/packages/pubsub/src/iam.js +++ b/packages/pubsub/src/iam.js @@ -99,6 +99,14 @@ util.inherits(IAM, common.GrpcService); * topic.iam.getPolicy(function(err, policy, apiResponse) {}); * * subscription.iam.getPolicy(function(err, policy, apiResponse) {}); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * topic.iam.getPolicy().then(function(data) { + * var policy = data[0]; + * var apiResponse = data[1]; + * }); */ IAM.prototype.getPolicy = function(callback) { var protoOpts = { @@ -144,6 +152,14 @@ IAM.prototype.getPolicy = function(callback) { * topic.iam.setPolicy(myPolicy, function(err, policy, apiResponse) {}); * * subscription.iam.setPolicy(myPolicy, function(err, policy, apiResponse) {}); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * topic.iam.setPolicy(myPolicy).then(function(data) { + * var policy = data[0]; + * var apiResponse = data[1]; + * }); */ IAM.prototype.setPolicy = function(policy, callback) { if (!is.object(policy)) { @@ -209,6 +225,14 @@ IAM.prototype.setPolicy = function(policy, callback) { * // "pubsub.subscriptions.update": false * // } * }); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * topic.iam.testPermissions(test).then(function(data) { + * var permissions = data[0]; + * var apiResponse = data[1]; + * }); */ IAM.prototype.testPermissions = function(permissions, callback) { if (!is.array(permissions) && !is.string(permissions)) { @@ -244,4 +268,11 @@ IAM.prototype.testPermissions = function(permissions, callback) { }); }; +/*! Developer Documentation + * + * All async methods (except for streams) will return a Promise in the event + * that a callback is omitted. + */ +common.util.promisifyAll(IAM); + module.exports = IAM; diff --git a/packages/pubsub/src/index.js b/packages/pubsub/src/index.js index d76f4968a95..3d104d0f240 100644 --- a/packages/pubsub/src/index.js +++ b/packages/pubsub/src/index.js @@ -99,6 +99,14 @@ util.inherits(PubSub, common.GrpcService); * // The topic was created successfully. * } * }); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * pubsub.createTopic('my-new-topic').then(function(data) { + * var topic = data[0]; + * var apiResponse = data[1]; + * }); */ PubSub.prototype.createTopic = function(name, callback) { var self = this; @@ -178,25 +186,11 @@ PubSub.prototype.createTopic = function(name, callback) { * }, callback); * * //- - * // Get the subscriptions as a readable object stream. - * //- - * pubsub.getSubscriptions() - * .on('error', console.error) - * .on('data', function(subscription) { - * // subscription is a Subscription object. - * }) - * .on('end', function() { - * // All subscriptions retrieved. - * }); - * - * //- - * // If you anticipate many results, you can end a stream early to prevent - * // unnecessary processing and API requests. + * // If the callback is omitted, we'll return a Promise. * //- - * pubsub.getSubscriptions() - * .on('data', function(topic) { - * this.end(); - * }); + * pubsub.getSubscriptions().then(function(data) { + * var subscriptions = data[0]; + * }); */ PubSub.prototype.getSubscriptions = function(options, callback) { var self = this; @@ -259,6 +253,36 @@ PubSub.prototype.getSubscriptions = function(options, callback) { }); }; +/** + * Get a list of the {module:pubsub/subscription} objects registered to all of + * your project's topics as a readable object stream. + * + * @param {object=} options - Configuration object. See + * {module:pubsub#getSubscriptions} for a complete list of options. + * @return {stream} + * + * @example + * pubsub.getSubscriptionsStream() + * .on('error', console.error) + * .on('data', function(subscription) { + * // subscription is a Subscription object. + * }) + * .on('end', function() { + * // All subscriptions retrieved. + * }); + * + * //- + * // If you anticipate many results, you can end a stream early to prevent + * // unnecessary processing and API requests. + * //- + * pubsub.getSubscriptionsStream() + * .on('data', function(topic) { + * this.end(); + * }); + */ +PubSub.prototype.getSubscriptionsStream = + common.paginator.streamify('getSubscriptions'); + /** * Get a list of the topics registered to your project. You may optionally * provide a query object as the first argument to customize the response. @@ -308,25 +332,11 @@ PubSub.prototype.getSubscriptions = function(options, callback) { * }, callback); * * //- - * // Get the topics as a readable object stream. - * //- - * pubsub.getTopics() - * .on('error', console.error) - * .on('data', function(topic) { - * // topic is a Topic object. - * }) - * .on('end', function() { - * // All topics retrieved. - * }); - * - * //- - * // If you anticipate many results, you can end a stream early to prevent - * // unnecessary processing and API requests. + * // If the callback is omitted, we'll return a Promise. * //- - * pubsub.getTopics() - * .on('data', function(topic) { - * this.end(); - * }); + * pubsub.getTopics().then(function(data) { + * var topics = data[0]; + * }); */ PubSub.prototype.getTopics = function(query, callback) { var self = this; @@ -367,6 +377,35 @@ PubSub.prototype.getTopics = function(query, callback) { }); }; +/** + * Get a list of the {module:pubsub/topic} objects registered to your project as + * a readable object stream. + * + * @param {object=} query - Configuration object. See + * {module:pubsub#getTopics} for a complete list of options. + * @return {stream} + * + * @example + * pubsub.getTopicsStream() + * .on('error', console.error) + * .on('data', function(topic) { + * // topic is a Topic object. + * }) + * .on('end', function() { + * // All topics retrieved. + * }); + * + * //- + * // If you anticipate many results, you can end a stream early to prevent + * // unnecessary processing and API requests. + * //- + * pubsub.getTopicsStream() + * .on('data', function(topic) { + * this.end(); + * }); + */ +PubSub.prototype.getTopicsStream = common.paginator.streamify('getTopics'); + /** * Create a subscription to a topic. You may optionally provide an object to * customize the subscription. @@ -423,6 +462,14 @@ PubSub.prototype.getTopics = function(query, callback) { * autoAck: true, * interval: 30 * }, function(err, subscription, apiResponse) {}); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * pubsub.subscribe(topic, name).then(function(data) { + * var subscription = data[0]; + * var apiResponse = data[1]; + * }); */ PubSub.prototype.subscribe = function(topic, subName, options, callback) { if (!is.string(topic) && !(topic instanceof Topic)) { @@ -564,10 +611,18 @@ PubSub.prototype.determineBaseUrl_ = function() { /*! Developer Documentation * - * These methods can be used with either a callback or as a readable object - * stream. `streamRouter` is used to add this dual behavior. + * These methods can be auto-paginated. + */ +common.paginator.extend(PubSub, ['getSubscriptions', 'getTopics']); + +/*! Developer Documentation + * + * All async methods (except for streams) will return a Promise in the event + * that a callback is omitted. */ -common.streamRouter.extend(PubSub, ['getSubscriptions', 'getTopics']); +common.util.promisifyAll(PubSub, { + exclude: ['subscription', 'topic'] +}); PubSub.Subscription = Subscription; PubSub.Topic = Topic; diff --git a/packages/pubsub/src/subscription.js b/packages/pubsub/src/subscription.js index d716c820e07..c0ca4912148 100644 --- a/packages/pubsub/src/subscription.js +++ b/packages/pubsub/src/subscription.js @@ -154,6 +154,13 @@ function Subscription(pubsub, options) { * * @example * subscription.exists(function(err, exists) {}); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * subscription.exists().then(function(data) { + * var exists = data[0]; + * }); */ exists: true, @@ -176,6 +183,14 @@ function Subscription(pubsub, options) { * subscription.get(function(err, subscription, apiResponse) { * // `subscription.metadata` has been populated. * }); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * subscription.get().then(function(data) { + * var subscription = data[0]; + * var apiResponse = data[1]; + * }); */ get: true, @@ -193,6 +208,14 @@ function Subscription(pubsub, options) { * * @example * subscription.getMetadata(function(err, metadata, apiResponse) {}); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * subscription.getMetadata().then(function(data) { + * var metadata = data[0]; + * var apiResponse = data[1]; + * }); */ getMetadata: { protoOpts: { @@ -230,6 +253,14 @@ function Subscription(pubsub, options) { * // The subscription was created successfully. * } * }); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * subscription.create().then(function(data) { + * var subscription = data[0]; + * var apiResponse = data[1]; + * }); */ config.methods.create = true; } @@ -281,6 +312,14 @@ function Subscription(pubsub, options) { * subscription.iam.getPolicy(function(err, policy) { * console.log(policy); * }); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * subscription.iam.getPolicy().then(function(data) { + * var policy = data[0]; + * var apiResponse = data[1]; + * }); */ this.iam = new IAM(pubsub, this.name); @@ -347,7 +386,16 @@ Subscription.formatName_ = function(projectId, name) { * @param {function=} callback - The callback function. * * @example - * subscription.ack('ePHEESyhuE8e...', function(err, apiResponse) {}); + * var ackId = 'ePHEESyhuE8e...'; + * + * subscription.ack(ackId, function(err, apiResponse) {}); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * subscription.ack(ackId).then(function(data) { + * var apiResponse = data[0]; + * }); */ Subscription.prototype.ack = function(ackIds, callback) { var self = this; @@ -428,6 +476,13 @@ Subscription.prototype.decorateMessage_ = function(message) { * * @example * subscription.delete(function(err, apiResponse) {}); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * subscription.delete().then(function(data) { + * var apiResponse = data[0]; + * }); */ Subscription.prototype.delete = function(callback) { var self = this; @@ -504,6 +559,14 @@ Subscription.prototype.delete = function(callback) { * }; * * subscription.pull(opts, function(err, messages, apiResponse) {}); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * subscription.pull(opts).then(function(data) { + * var messages = data[0]; + * var apiResponse = data[1]; + * }); */ Subscription.prototype.pull = function(options, callback) { var self = this; @@ -586,6 +649,13 @@ Subscription.prototype.pull = function(options, callback) { * }; * * subscription.setAckDeadline(options, function(err, apiResponse) {}); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * subscription.setAckDeadline(options).then(function(data) { + * var apiResponse = data[0]; + * }); */ Subscription.prototype.setAckDeadline = function(options, callback) { callback = callback || common.util.noop; @@ -713,4 +783,11 @@ Subscription.prototype.startPulling_ = function() { }); }; +/*! Developer Documentation + * + * All async methods (except for streams) will return a Promise in the event + * that a callback is omitted. + */ +common.util.promisifyAll(Subscription); + module.exports = Subscription; diff --git a/packages/pubsub/src/topic.js b/packages/pubsub/src/topic.js index 051ea58285d..6c31502108b 100644 --- a/packages/pubsub/src/topic.js +++ b/packages/pubsub/src/topic.js @@ -62,6 +62,14 @@ function Topic(pubsub, name) { * // The topic was created successfully. * } * }); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * topic.create().then(function(data) { + * var topic = data[0]; + * var apiResponse = data[1]; + * }); */ create: true, @@ -74,6 +82,13 @@ function Topic(pubsub, name) { * * @example * topic.delete(function(err, apiResponse) {}); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * topic.delete().then(function(data) { + * var apiResponse = data[0]; + * }); */ delete: { protoOpts: { @@ -95,6 +110,13 @@ function Topic(pubsub, name) { * * @example * topic.exists(function(err, exists) {}); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * topic.exists().then(function(data) { + * var exists = data[0]; + * }); */ exists: true, @@ -114,6 +136,14 @@ function Topic(pubsub, name) { * topic.get(function(err, topic, apiResponse) { * // `topic.metadata` has been populated. * }); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * topic.get().then(function(data) { + * var topic = data[0]; + * var apiResponse = data[1]; + * }); */ get: true, @@ -127,6 +157,17 @@ function Topic(pubsub, name) { * request. * @param {object} callback.metadata - The metadata of the Topic. * @param {object} callback.apiResponse - The full API response. + * + * @example + * topic.getMetadata(function(err, metadata, apiResponse) {}); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * topic.getMetadata().then(function(data) { + * var metadata = data[0]; + * var apiResponse = data[1]; + * }); */ getMetadata: { protoOpts: { @@ -171,6 +212,14 @@ function Topic(pubsub, name) { * topic.iam.getPolicy(function(err, policy) { * console.log(policy); * }); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * topic.iam.getPolicy().then(function(data) { + * var policy = data[0]; + * var apiResponse = data[1]; + * }); */ this.iam = new IAM(pubsub, this.name); } @@ -243,9 +292,34 @@ Topic.formatName_ = function(projectId, name) { * }, callback); * * //- - * // Get the subscriptions for this topic as a readable object stream. + * // If the callback is omitted, we'll return a Promise. * //- - * topic.getSubscriptions() + * topic.getSubscriptions().then(function(data) { + * var subscriptions = data[0]; + * }); + */ +Topic.prototype.getSubscriptions = function(options, callback) { + if (is.fn(options)) { + callback = options; + options = {}; + } + + options = options || {}; + options.topic = this; + + return this.pubsub.getSubscriptions(options, callback); +}; + +/** + * Get a list of the {module:pubsub/subscription} objects registered to this + * topic as a readable object stream. + * + * @param {object=} query - Configuration object. See + * {module:pubsub/topic#getSubscriptions} for a complete list of options. + * @return {stream} + * + * @example + * topic.getSubscriptionsStream() * .on('error', console.error) * .on('data', function(subscription) { * // subscription is a Subscription object. @@ -258,21 +332,16 @@ Topic.formatName_ = function(projectId, name) { * // If you anticipate many results, you can end a stream early to prevent * // unnecessary processing and API requests. * //- - * topic.getSubscriptions() + * topic.getSubscriptionsStream() * .on('data', function(subscription) { * this.end(); * }); */ -Topic.prototype.getSubscriptions = function(options, callback) { - if (is.fn(options)) { - callback = options; - options = {}; - } - +Topic.prototype.getSubscriptionsStream = function(options) { options = options || {}; options.topic = this; - return this.pubsub.getSubscriptions(options, callback); + return this.pubsub.getSubscriptionsStream(options); }; /** @@ -343,6 +412,13 @@ Topic.prototype.getSubscriptions = function(options, callback) { * }; * * topic.publish(message, options, function(err, messageIds, apiResponse) {}); + * + * // If the callback is omitted, we'll return a Promise. + * //- + * topic.publish(message).then(function(data) { + * var messageIds = data[0]; + * var apiResponse = data[1]; + * }); */ Topic.prototype.publish = function(messages, options, callback) { messages = arrify(messages); @@ -426,6 +502,14 @@ Topic.prototype.publish = function(messages, options, callback) { * autoAck: true, * interval: 30 * }, function(err, subscription, apiResponse) {}); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * topic.subscribe('newMessages').then(function(data) { + * var subscription = data[0]; + * var apiResponse = data[1]; + * }); */ Topic.prototype.subscribe = function(subName, options, callback) { this.pubsub.subscribe(this, subName, options, callback); @@ -462,4 +546,13 @@ Topic.prototype.subscription = function(name, options) { return this.pubsub.subscription(name, options); }; +/*! Developer Documentation + * + * All async methods (except for streams) will return a Promise in the event + * that a callback is omitted. + */ +common.util.promisifyAll(Topic, { + exclude: ['subscription'] +}); + module.exports = Topic; diff --git a/packages/pubsub/system-test/pubsub.js b/packages/pubsub/system-test/pubsub.js index 2549ab686b7..2679591acff 100644 --- a/packages/pubsub/system-test/pubsub.js +++ b/packages/pubsub/system-test/pubsub.js @@ -122,7 +122,7 @@ describe('pubsub', function() { it('should list topics in a stream', function(done) { var topicsEmitted = []; - pubsub.getTopics() + pubsub.getTopicsStream() .on('error', done) .on('data', function(topic) { topicsEmitted.push(topic); @@ -260,7 +260,7 @@ describe('pubsub', function() { it('should list all topic subscriptions as a stream', function(done) { var subscriptionsEmitted = []; - topic.getSubscriptions() + topic.getSubscriptionsStream() .on('error', done) .on('data', function(subscription) { subscriptionsEmitted.push(subscription); @@ -282,7 +282,7 @@ describe('pubsub', function() { it('should list all subscriptions as a stream', function(done) { var subscriptionEmitted = false; - pubsub.getSubscriptions() + pubsub.getSubscriptionsStream() .on('error', done) .on('data', function(subscription) { subscriptionEmitted = subscription instanceof Subscription; diff --git a/packages/pubsub/test/iam.js b/packages/pubsub/test/iam.js index d13eda5c7d3..21cfa8a3f1b 100644 --- a/packages/pubsub/test/iam.js +++ b/packages/pubsub/test/iam.js @@ -17,11 +17,21 @@ 'use strict'; var assert = require('assert'); +var extend = require('extend'); var GrpcService = require('@google-cloud/common').GrpcService; var nodeutil = require('util'); var proxyquire = require('proxyquire'); var util = require('@google-cloud/common').util; +var promisified = false; +var fakeUtil = extend({}, util, { + promisifyAll: function(Class) { + if (Class.name === 'IAM') { + promisified = true; + } + } +}); + function FakeGrpcService() { this.calledWith_ = arguments; GrpcService.apply(this, arguments); @@ -42,7 +52,8 @@ describe('IAM', function() { before(function() { IAM = proxyquire('../src/iam.js', { '@google-cloud/common': { - GrpcService: FakeGrpcService + GrpcService: FakeGrpcService, + util: fakeUtil } }); }); @@ -70,6 +81,10 @@ describe('IAM', function() { assert.strictEqual(options, PUBSUB.options); }); + it('should promisify all the things', function() { + assert(promisified); + }); + it('should localize the ID', function() { assert.strictEqual(iam.id, ID); }); diff --git a/packages/pubsub/test/index.js b/packages/pubsub/test/index.js index 111e31f098e..ddf07c84f21 100644 --- a/packages/pubsub/test/index.js +++ b/packages/pubsub/test/index.js @@ -32,14 +32,24 @@ function Subscription(a, b) { return new OverrideFn(a, b); } -var fakeUtil = extend({}, util); +var promisified = false; +var fakeUtil = extend({}, util, { + promisifyAll: function(Class, options) { + if (Class.name !== 'PubSub') { + return; + } + + promisified = true; + assert.deepEqual(options.exclude, ['subscription', 'topic']); + } +}); function FakeGrpcService() { this.calledWith_ = arguments; } var extended = false; -var fakeStreamRouter = { +var fakePaginator = { extend: function(Class, methods) { if (Class.name !== 'PubSub') { return; @@ -49,6 +59,9 @@ var fakeStreamRouter = { assert.equal(Class.name, 'PubSub'); assert.deepEqual(methods, ['getSubscriptions', 'getTopics']); extended = true; + }, + streamify: function(methodName) { + return methodName; } }; @@ -65,7 +78,7 @@ describe('PubSub', function() { PubSub = proxyquire('../', { '@google-cloud/common': { GrpcService: FakeGrpcService, - streamRouter: fakeStreamRouter, + paginator: fakePaginator, util: fakeUtil }, './subscription.js': Subscription, @@ -87,7 +100,16 @@ describe('PubSub', function() { describe('instantiation', function() { it('should extend the correct methods', function() { - assert(extended); // See `fakeStreamRouter.extend` + assert(extended); // See `fakePaginator.extend` + }); + + it('should streamify the correct methods', function() { + assert.strictEqual(pubsub.getSubscriptionsStream, 'getSubscriptions'); + assert.strictEqual(pubsub.getTopicsStream, 'getTopics'); + }); + + it('should promisify all the things', function() { + assert(promisified); }); it('should normalize the arguments', function() { diff --git a/packages/pubsub/test/subscription.js b/packages/pubsub/test/subscription.js index e7dbc5d2dcd..81fcc475dcc 100644 --- a/packages/pubsub/test/subscription.js +++ b/packages/pubsub/test/subscription.js @@ -23,6 +23,15 @@ var nodeutil = require('util'); var proxyquire = require('proxyquire'); var util = require('@google-cloud/common').util; +var promisified = false; +var fakeUtil = extend({}, util, { + promisifyAll: function(Class) { + if (Class.name === 'Subscription') { + promisified = true; + } + } +}); + function FakeGrpcServiceObject() { this.calledWith_ = arguments; GrpcServiceObject.apply(this, arguments); @@ -72,7 +81,8 @@ describe('Subscription', function() { before(function() { Subscription = proxyquire('../src/subscription.js', { '@google-cloud/common': { - GrpcServiceObject: FakeGrpcServiceObject + GrpcServiceObject: FakeGrpcServiceObject, + util: fakeUtil }, './iam.js': FakeIAM }); @@ -92,6 +102,10 @@ describe('Subscription', function() { }); describe('initialization', function() { + it('should promisify all the things', function() { + assert(promisified); + }); + it('should format name', function(done) { var formatName_ = Subscription.formatName_; Subscription.formatName_ = function() { diff --git a/packages/pubsub/test/topic.js b/packages/pubsub/test/topic.js index 96bedd9fe80..30180f77dee 100644 --- a/packages/pubsub/test/topic.js +++ b/packages/pubsub/test/topic.js @@ -23,6 +23,18 @@ var nodeutil = require('util'); var proxyquire = require('proxyquire'); var util = require('@google-cloud/common').util; +var promisified = false; +var fakeUtil = extend({}, util, { + promisifyAll: function(Class, options) { + if (Class.name !== 'Topic') { + return; + } + + promisified = true; + assert.deepEqual(options.exclude, ['subscription']); + } +}); + function FakeGrpcServiceObject() { this.calledWith_ = arguments; GrpcServiceObject.apply(this, arguments); @@ -50,7 +62,8 @@ describe('Topic', function() { Topic = proxyquire('../src/topic.js', { './iam.js': FakeIAM, '@google-cloud/common': { - GrpcServiceObject: FakeGrpcServiceObject + GrpcServiceObject: FakeGrpcServiceObject, + util: fakeUtil } }); }); @@ -178,6 +191,35 @@ describe('Topic', function() { }); }); + describe('getSubscriptionsStream', function() { + it('should return a stream', function(done) { + var fakeStream = {}; + + topic.pubsub.getSubscriptions = function(options) { + assert.deepEqual(options, { topic: topic }); + setImmediate(done); + return fakeStream; + }; + + var stream = topic.getSubscriptions(); + assert.strictEqual(stream, fakeStream); + }); + + it('should pass correct args to getSubscriptionsStream', function(done) { + var opts = { a: 'b', c: 'd' }; + + topic.pubsub = { + getSubscriptions: function(options) { + assert.deepEqual(options, opts); + assert.deepEqual(options.topic, topic); + done(); + } + }; + + topic.getSubscriptions(opts); + }); + }); + describe('publish', function() { var message = 'howdy'; var attributes = {