From 22c8651aae631c729b8d684336b9f3533e6f7e1d Mon Sep 17 00:00:00 2001 From: Jason Dobry Date: Fri, 2 Sep 2016 11:55:00 -0700 Subject: [PATCH] Simplify PubSub samples. --- pubsub/README.md | 41 ++--- pubsub/iam.js | 124 ++++----------- pubsub/subscriptions.js | 190 +++++++++++------------ pubsub/system-test/iam.test.js | 13 +- pubsub/system-test/subscriptions.test.js | 100 ++++++++---- pubsub/system-test/topics.test.js | 21 ++- pubsub/test/iam.test.js | 74 ++------- pubsub/test/subscriptions.test.js | 159 ++++++++++--------- pubsub/test/topics.test.js | 84 ++++------ pubsub/topics.js | 131 ++++++---------- 10 files changed, 404 insertions(+), 533 deletions(-) diff --git a/pubsub/README.md b/pubsub/README.md index a4c6d6e925..d985c23d56 100644 --- a/pubsub/README.md +++ b/pubsub/README.md @@ -35,20 +35,19 @@ __Usage:__ `node topics --help` ``` Commands: - create Create a new topic. - list List topics. - publish Publish a message to the specified topic. - delete Delete the specified topic. + create Creates a new topic. + list Lists topics. + publish Publish a message to the specified topic. + delete Deletes the specified topic. Options: - --help Show help [boolean] + --help Show help [boolean] Examples: - node topics create my-topic Create a new topic named "my-topic". - node topics list List topics. - node topics publish my-topic Publish a message to "my-topic". - '{"data":"Hello world!"}' - node topics delete my-topic Delete a topic named "my-topic". + node topics create greetings Creates a new topic named "greetings". + node topics list Lists all topics. + node topics publish greetings '{"data":"Hello world!"}' Publishes a message to "greetings". + node topics delete greetings Deletes a topic named "greetings". For more information, see https://cloud.google.com/pubsub/docs ``` @@ -64,20 +63,22 @@ __Usage:__ `node subscriptions --help` ``` Commands: - create Create a new subscription. - list [topic] List subscriptions. - pull Pull messages from the specified subscription. - delete Delete the specified subscription. + create Creates a new subscription. + list [topicName] Lists subscriptions, optionally filtering by a topic. + get Gets the metadata the metadata for the specified subscription. + pull Pulls messages for the specified subscription. + delete Deletes the specified subscription. Options: - --help Show help [boolean] + --help Show help [boolean] Examples: - node subscriptions create my-topic my-subscription Create a new subscription. - node subscriptions delete my-subscription Delete a subscription. - node subscriptions pull my-subscription Pull messages from "my-subscription". - node subscriptions list List all subscriptions. - node subscriptions list my-topic List subscriptions to topic "my-topic". + node subscriptions create greetings greetings-worker-1 Creates a subscription named "greetings-worker-1" to a topic + named "greetings". + node subscriptions delete greetings-worker-1 Deletes a subscription named "greetings-worker-1". + node subscriptions pull greetings-worker-1 Pulls messages for a subscription named "greetings-worker-1". + node subscriptions list Lists all subscriptions. + node subscriptions list greetings Lists subscriptions for a topic named "greetings". For more information, see https://cloud.google.com/pubsub/docs ``` diff --git a/pubsub/iam.js b/pubsub/iam.js index 98966f6ac0..8abfd1e70f 100644 --- a/pubsub/iam.js +++ b/pubsub/iam.js @@ -13,84 +13,48 @@ 'use strict'; -// [START auth] +// [START setup] // By default, the client will authenticate using the service account file // specified by the GOOGLE_APPLICATION_CREDENTIALS environment variable and use // the project specified by the GCLOUD_PROJECT environment variable. See // https://googlecloudplatform.github.io/gcloud-node/#/docs/google-cloud/latest/guides/authentication var PubSub = require('@google-cloud/pubsub'); +// [END setup] -// Instantiate a pubsub client -var pubsub = PubSub(); -// [END auth] - -// [START get_topic_policy] -/** - * Retrieve a topic's IAM policy. - * - * @param {string} topicName The name of the topic. - * @param {function} callback The callback function. - */ function getTopicPolicy (topicName, callback) { - if (!topicName) { - return callback(new Error('"topicName" is required!')); - } - - // Grab a reference to an existing topic + var pubsub = PubSub(); var topic = pubsub.topic(topicName); // Retrieve the IAM policy for the topic - topic.iam.getPolicy(function (err, policy) { + // See https://googlecloudplatform.github.io/google-cloud-node/#/docs/pubsub/latest/pubsub/topic?method=iam.getPolicy + topic.iam.getPolicy(function (err, policy, apiResponse) { if (err) { return callback(err); } - console.log('Got topic policy:', policy); - return callback(null, policy); + console.log('Got policy for topic: %s', topicName); + return callback(null, policy, apiResponse); }); } -// [END get_topic_policy] -// [START get_subscription_policy] -/** - * Retrieve a subcription's IAM policy. - * - * @param {string} subscriptionName The name of the subscription. - * @param {function} callback The callback function. - */ function getSubscriptionPolicy (subscriptionName, callback) { - if (!subscriptionName) { - return callback(new Error('"subscriptionName" is required!')); - } - - // Grab a reference to an existing subscription + var pubsub = PubSub(); var subscription = pubsub.subscription(subscriptionName); // Retrieve the IAM policy for the subscription - subscription.iam.getPolicy(function (err, policy) { + // See https://googlecloudplatform.github.io/google-cloud-node/#/docs/pubsub/latest/pubsub/subscription?method=iam.getPolicy + subscription.iam.getPolicy(function (err, policy, apiResponse) { if (err) { return callback(err); } - console.log('Got subscription policy:', policy); - return callback(null, policy); + console.log('Got policy for subscription: %s', subscriptionName); + return callback(null, policy, apiResponse); }); } -// [END get_subscription_policy] -// [START set_topic_policy] -/** - * Set a topic's IAM policy. - * - * @param {string} topicName The name of the topic. - * @param {function} callback The callback function. - */ function setTopicPolicy (topicName, callback) { - if (!topicName) { - return callback(new Error('"topicName" is required!')); - } - - // Grab a reference to an existing topic + var pubsub = PubSub(); var topic = pubsub.topic(topicName); // Policy update @@ -104,29 +68,19 @@ function setTopicPolicy (topicName, callback) { }; // Set the IAM policy for the specified topic - topic.iam.setPolicy(newPolicy, function (err, policy) { + // See https://googlecloudplatform.github.io/google-cloud-node/#/docs/pubsub/latest/pubsub/topic?method=iam.setPolicy + topic.iam.setPolicy(newPolicy, function (err, updatedPolicy, apiResponse) { if (err) { return callback(err); } console.log('Updated policy for topic: %s', topicName); - return callback(null, policy); + return callback(null, updatedPolicy, apiResponse); }); } -// [END set_topic_policy] -// [START set_subscription_policy] -/** - * @param {string} subscriptionName Name of the subscription whose policy is to - * be updated. - * @param {function} callback The callback function. - */ function setSubscriptionPolicy (subscriptionName, callback) { - if (!subscriptionName) { - return callback(new Error('"subscriptionName" is required!')); - } - - // Grab a reference to an existing subscription + var pubsub = PubSub(); var subscription = pubsub.subscription(subscriptionName); // Policy update @@ -140,30 +94,19 @@ function setSubscriptionPolicy (subscriptionName, callback) { }; // Set the IAM policy for the specified subscription - subscription.iam.setPolicy(newPolicy, function (err, policy) { + // See https://googlecloudplatform.github.io/google-cloud-node/#/docs/pubsub/latest/pubsub/subscription?method=iam.setPolicy + subscription.iam.setPolicy(newPolicy, function (err, updatedPolicy, apiResponse) { if (err) { return callback(err); } console.log('Updated policy for subscription: %s', subscriptionName); - return callback(null, policy); + return callback(null, updatedPolicy, apiResponse); }); } -// [END set_subscription_policy] -// [START test_topic_permissions] -/** - * Test a topic's IAM permissions. - * - * @param {string} topicName The name of the topic. - * @param {function} callback The callback function. - */ function testTopicPermissions (topicName, callback) { - if (!topicName) { - return callback(new Error('"topicName" is required!')); - } - - // Grab a reference to an existing topic + var pubsub = PubSub(); var topic = pubsub.topic(topicName); var permissionsToTest = [ @@ -173,30 +116,19 @@ function testTopicPermissions (topicName, callback) { ]; // Test the IAM policy for the specified topic - topic.iam.testPermissions(permissionsToTest, function (err, permissions) { + // See https://googlecloudplatform.github.io/google-cloud-node/#/docs/pubsub/latest/pubsub/topic?method=iam.testPermissions + topic.iam.testPermissions(permissionsToTest, function (err, permissions, apiResponse) { if (err) { return callback(err); } console.log('Tested permissions for topic: %s', topicName); - return callback(null, permissions); + return callback(null, permissions, apiResponse); }); } -// [END test_topic_permissions] -// [START test_subscription_permissions] -/** - * Test a subcription's IAM permissions. - * - * @param {string} subscriptionName The name of the subscription. - * @param {function} callback The callback function. - */ function testSubscriptionPermissions (subscriptionName, callback) { - if (!subscriptionName) { - return callback(new Error('"subscriptionName" is required!')); - } - - // Grab a reference to an existing subscription + var pubsub = PubSub(); var subscription = pubsub.subscription(subscriptionName); var permissionsToTest = [ @@ -205,16 +137,16 @@ function testSubscriptionPermissions (subscriptionName, callback) { ]; // Test the IAM policy for the specified subscription - subscription.iam.testPermissions(permissionsToTest, function (err, permissions) { + // See https://googlecloudplatform.github.io/google-cloud-node/#/docs/pubsub/latest/pubsub/subscription?method=iam.testPermissions + subscription.iam.testPermissions(permissionsToTest, function (err, permissions, apiResponse) { if (err) { return callback(err); } console.log('Tested permissions for subscription: %s', subscriptionName); - return callback(null, permissions); + return callback(null, permissions, apiResponse); }); } -// [END test_subscription_permissions] // [START usage] function printUsage () { diff --git a/pubsub/subscriptions.js b/pubsub/subscriptions.js index 42c883d8d6..24aadc82cf 100644 --- a/pubsub/subscriptions.js +++ b/pubsub/subscriptions.js @@ -13,149 +13,128 @@ 'use strict'; -// [START auth] +// [START setup] // By default, the client will authenticate using the service account file // specified by the GOOGLE_APPLICATION_CREDENTIALS environment variable and use // the project specified by the GCLOUD_PROJECT environment variable. See // https://googlecloudplatform.github.io/gcloud-node/#/docs/google-cloud/latest/guides/authentication var PubSub = require('@google-cloud/pubsub'); +// [END setup] -// Instantiate a pubsub client -var pubsub = PubSub(); -// [END auth] - -// [START create_subscription] -/** - * Create a new subscription. - * - * @param {string} topicName Name of the topic for the new subscription. - * @param {string} subscriptionName Name for the new subscription. - * @param {Function} callback Callback function. - */ function createSubscription (topicName, subscriptionName, callback) { - if (!topicName) { - return callback(new Error('"topicName" is required!')); - } else if (!subscriptionName) { - return callback(new Error('"subscriptionName" is required!')); - } + var pubsub = PubSub(); + var topic = pubsub.topic(topicName); - var options = { - reuseExisting: true - }; - pubsub.subscribe(topicName, subscriptionName, options, function (err, subscription) { + // Get the subscription if it exists, otherwise create the subscription + // See https://googlecloudplatform.github.io/google-cloud-node/#/docs/pubsub/latest/pubsub/topic?method=subscribe + topic.subscribe(subscriptionName, function (err, subscription, apiResponse) { if (err) { return callback(err); } console.log('Created subscription %s to topic %s', subscriptionName, topicName); - return callback(null, subscription); + return callback(null, subscription, apiResponse); }); } -// [END create_subscription] - -// [START delete_subscription] -/** - * Delete a subscription. - * - * @param {string} subscriptionName Name of the subscription to delete. - * @param {Function} callback The callback function. - */ -function deleteSubscription (subscriptionName, callback) { - if (!subscriptionName) { - return callback(new Error('"subscriptionName" is required!')); - } +function deleteSubscription (subscriptionName, callback) { + var pubsub = PubSub(); var subscription = pubsub.subscription(subscriptionName); // Delete the subscription - subscription.delete(function (err) { + // See https://googlecloudplatform.github.io/google-cloud-node/#/docs/pubsub/latest/pubsub/subscription?method=delete + subscription.delete(function (err, apiResponse) { if (err) { return callback(err); } console.log('Deleted subscription: %s', subscriptionName); - return callback(null); + return callback(null, apiResponse); + }); +} + +function getSubscriptionMetadata (subscriptionName, callback) { + var pubsub = PubSub(); + var subscription = pubsub.subscription(subscriptionName); + + // Get the metadata for the specified subscription + // See https://googlecloudplatform.github.io/google-cloud-node/#/docs/pubsub/latest/pubsub/subscription?method=getMetadata + subscription.getMetadata(function (err, metadata) { + if (err) { + return callback(err); + } + + console.log('Got metadata for subscription: %s', subscriptionName); + return callback(null, metadata); }); } -// [END delete_subscription] - -// [START get_all_subscriptions] -/** - * List all subscriptions for the specified topic, or list all subcriptions for - * all topics. - * - * @param {string} [topicName] The name of the topic. If omitted, list all - * subscriptions. - * @param {Function} callback The callback function. - */ + function listSubscriptions (topicName, callback) { - var options = {}; - if (typeof topicName === 'string') { - // Optionally find subscriptions for a specific topic - options.topic = pubsub.topic(topicName); - } - pubsub.getSubscriptions(options, function (err, subscriptions) { + var pubsub = PubSub(); + var topic = pubsub.topic(topicName); + + // List all subscriptions for the specified topic + // See https://googlecloudplatform.github.io/google-cloud-node/#/docs/pubsub/latest/pubsub/topic?method=getSubscriptions + topic.getSubscriptions(function (err, subscriptions) { if (err) { return callback(err); } - console.log('Found %d subscriptions!', subscriptions.length); + console.log('Found %d subscription(s)!', subscriptions.length); + return callback(null, subscriptions); + }); +} + +function listAllSubscriptions (callback) { + var pubsub = PubSub(); + + // List all subscriptions + // See https://googlecloudplatform.github.io/google-cloud-node/#/docs/pubsub/latest/pubsub?method=getSubscriptions + pubsub.getSubscriptions(function (err, subscriptions) { + if (err) { + return callback(err); + } + + console.log('Found %d subscription(s)!', subscriptions.length); return callback(null, subscriptions); }); } -// [END get_all_subscriptions] -// [START handle_message] function handleMessage (message) { console.log('received message: ' + message.data); } -// [END handle_message] - -// [START pull_messages] -/** - * Pull messages from a topic's subscription. - * - * @param {string} subscriptionName The name of the subscription. - * @param {function} callback The callback function. - */ -function pullMessages (subscriptionName, callback) { - if (!subscriptionName) { - return callback(new Error('"subscriptionName" is required!')); - } +function pullMessages (subscriptionName, callback) { + var pubsub = PubSub(); var subscription = pubsub.subscription(subscriptionName); - var options = { - // Limit the amount of messages pulled. - maxResults: 100, - // If set, the system will respond immediately. Otherwise, wait until - // new messages are available. Returns if timeout is reached. - returnImmediately: false - }; + // Pull any messages on the subscription - subscription.pull(options, function (err, messages) { + // See https://googlecloudplatform.github.io/google-cloud-node/#/docs/pubsub/latest/pubsub/subscription?method=pull + subscription.pull(function (err, messages) { if (err) { return callback(err); } // Do something for each message messages.forEach(handleMessage); - console.log('Pulled %d messages!', messages.length); + console.log('Pulled %d message(s)!', messages.length); - // Acknowledge messages - var subscription = pubsub.subscription(subscriptionName); - subscription.ack(messages.map(function (message) { + var ackIds = messages.map(function (message) { return message.ackId; - }), function (err) { + }); + + // Acknowledge messages + // See https://googlecloudplatform.github.io/google-cloud-node/#/docs/pubsub/latest/pubsub/subscription?method=ack + subscription.ack(ackIds, function (err, apiResponse) { if (err) { return callback(err); } - console.log('Acked %d messages!', messages.length); - return callback(null, messages); + console.log('Acked %d message(s)!', messages.length); + return callback(null, messages, apiResponse); }); }); } -// [END pull_messages] // The command-line program var cli = require('yargs'); @@ -164,8 +143,10 @@ var makeHandler = require('../utils').makeHandler; var program = module.exports = { createSubscription: createSubscription, deleteSubscription: deleteSubscription, + getSubscriptionMetadata: getSubscriptionMetadata, pullMessages: pullMessages, listSubscriptions: listSubscriptions, + listAllSubscriptions: listAllSubscriptions, main: function (args) { // Run the command-line program cli.help().strict().parse(args).argv; @@ -174,24 +155,31 @@ var program = module.exports = { cli .demand(1) - .command('create ', 'Create a new subscription.', {}, function (options) { - program.createSubscription(options.topic, options.name, makeHandler(true, 'id')); + .command('create ', 'Creates a new subscription.', {}, function (options) { + program.createSubscription(options.topicName, options.subscriptionName, makeHandler(true, 'id')); + }) + .command('list [topicName]', 'Lists subscriptions, optionally filtering by a topic.', {}, function (options) { + if (options.topicName) { + program.listSubscriptions(options.topicName, makeHandler(true, 'id')); + } else { + program.listAllSubscriptions(makeHandler(true, 'id')); + } }) - .command('list [topic]', 'List subscriptions.', {}, function (options) { - program.listSubscriptions(options.topic, makeHandler(true, 'id')); + .command('get ', 'Gets the metadata the metadata for the specified subscription.', {}, function (options) { + program.getSubscriptionMetadata(options.subscriptionName, makeHandler()); }) - .command('pull ', 'Pull messages from the specified subscription.', {}, function (options) { - program.pullMessages(options.subscription, makeHandler(false)); + .command('pull ', 'Pulls messages for the specified subscription.', {}, function (options) { + program.pullMessages(options.subscriptionName, makeHandler(false)); }) - .command('delete ', 'Delete the specified subscription.', {}, function (options) { - program.deleteSubscription(options.subscription, makeHandler(false)); + .command('delete ', 'Deletes the specified subscription.', {}, function (options) { + program.deleteSubscription(options.subscriptionName, makeHandler(false)); }) - .example('node $0 create my-topic my-subscription', 'Create a new subscription.') - .example('node $0 delete my-subscription', 'Delete a subscription.') - .example('node $0 pull my-subscription', 'Pull messages from "my-subscription".') - .example('node $0 list', 'List all subscriptions.') - .example('node $0 list my-topic', 'List subscriptions to topic "my-topic".') - .wrap(100) + .example('node $0 create greetings greetings-worker-1', 'Creates a subscription named "greetings-worker-1" to a topic named "greetings".') + .example('node $0 delete greetings-worker-1', 'Deletes a subscription named "greetings-worker-1".') + .example('node $0 pull greetings-worker-1', 'Pulls messages for a subscription named "greetings-worker-1".') + .example('node $0 list', 'Lists all subscriptions.') + .example('node $0 list greetings', 'Lists subscriptions for a topic named "greetings".') + .wrap(120) .recommendCommands() .epilogue('For more information, see https://cloud.google.com/pubsub/docs'); diff --git a/pubsub/system-test/iam.test.js b/pubsub/system-test/iam.test.js index d052e21d9b..b95a6caedf 100644 --- a/pubsub/system-test/iam.test.js +++ b/pubsub/system-test/iam.test.js @@ -15,8 +15,9 @@ var uuid = require('node-uuid'); var PubSub = require('@google-cloud/pubsub'); -var pubsub = PubSub(); var program = require('../iam'); + +var pubsub = PubSub(); var topicName = 'nodejs-docs-samples-test-' + uuid.v4(); var subscriptionName = 'nodejs-docs-samples-test-sub-' + uuid.v4(); @@ -46,7 +47,7 @@ describe('pubsub:iam', function () { program.getTopicPolicy(topicName, function (err, policy) { assert.ifError(err); assert(policy); - assert(console.log.calledWith('Got topic policy:', policy)); + assert(console.log.calledWith('Got policy for topic: %s', topicName)); done(); }); }); @@ -57,7 +58,7 @@ describe('pubsub:iam', function () { program.getSubscriptionPolicy(subscriptionName, function (err, policy) { assert.ifError(err); assert(policy); - assert(console.log.calledWith('Got subscription policy:', policy)); + assert(console.log.calledWith('Got policy for subscription: %s', subscriptionName)); done(); }); }); @@ -65,10 +66,11 @@ describe('pubsub:iam', function () { describe('testTopicPermissions', function () { it('should test a topic\'s permissions', function (done) { - program.testTopicPermissions(topicName, function (err, permissions) { + program.testTopicPermissions(topicName, function (err, permissions, apiResponse) { assert.ifError(err); assert(permissions); assert(console.log.calledWith('Tested permissions for topic: %s', topicName)); + assert.notEqual(apiResponse, undefined); done(); }); }); @@ -76,10 +78,11 @@ describe('pubsub:iam', function () { describe('testSubscriptionPermissions', function () { it('should test a subscriptions\'s permissions', function (done) { - program.testSubscriptionPermissions(subscriptionName, function (err, permissions) { + program.testSubscriptionPermissions(subscriptionName, function (err, permissions, apiResponse) { assert.ifError(err); assert(permissions); assert(console.log.calledWith('Tested permissions for subscription: %s', subscriptionName)); + assert.notEqual(apiResponse, undefined); done(); }); }); diff --git a/pubsub/system-test/subscriptions.test.js b/pubsub/system-test/subscriptions.test.js index d19aceab75..ecc2187263 100644 --- a/pubsub/system-test/subscriptions.test.js +++ b/pubsub/system-test/subscriptions.test.js @@ -15,59 +15,95 @@ var uuid = require('node-uuid'); var PubSub = require('@google-cloud/pubsub'); -var pubsub = PubSub(); var program = require('../subscriptions'); -var topicName = 'nodejs-docs-samples-test-' + uuid.v4(); -var subscriptionName = 'nodejs-docs-samples-test-sub-' + uuid.v4(); + +var pubsub = PubSub(); +var topicNameOne = 'nodejs-docs-samples-test-' + uuid.v4(); +var topicNameTwo = 'nodejs-docs-samples-test-' + uuid.v4(); +var subscriptionNameOne = 'nodejs-docs-samples-test-sub-' + uuid.v4(); +var subscriptionNameTwo = 'nodejs-docs-samples-test-sub-' + uuid.v4(); var projectId = process.env.GCLOUD_PROJECT; -var name = 'projects/' + projectId + '/subscriptions/' + subscriptionName; +var fullSubscriptionNameOne = 'projects/' + projectId + '/subscriptions/' + subscriptionNameOne; +var fullSubscriptionNameTwo = 'projects/' + projectId + '/subscriptions/' + subscriptionNameTwo; describe('pubsub:subscriptions', function () { before(function (done) { - pubsub.topic(topicName).get({ + pubsub.topic(topicNameOne).get({ autoCreate: true - }, done); + }, function (err) { + assert.ifError(err, 'topic creation succeeded'); + + pubsub.topic(topicNameTwo).get({ + autoCreate: true + }, function (err, topic) { + assert.ifError(err, 'topic creation succeeded'); + + topic.subscribe(subscriptionNameTwo, function (err) { + assert.ifError(err, 'subscription creation succeeded'); + + done(); + }); + }); + }); }); after(function (done) { - pubsub.topic(topicName).delete(done); + pubsub.topic(topicNameOne).delete(done); }); describe('createSubscription', function () { it('should create a subscription', function (done) { - program.createSubscription(topicName, subscriptionName, function (err, subscription) { + program.createSubscription(topicNameOne, subscriptionNameOne, function (err, subscription, apiResponse) { assert.ifError(err); - assert.equal(subscription.name, name); - assert(console.log.calledWith('Created subscription %s to topic %s', subscriptionName, topicName)); - // The next test sometimes fails, so, slow this test down + assert.equal(subscription.name, fullSubscriptionNameOne); + assert(console.log.calledWith('Created subscription %s to topic %s', subscriptionNameOne, topicNameOne)); + assert.notEqual(apiResponse, undefined); + // Listing is eventually consistent, so give the index time to update setTimeout(done, 5000); }); }); }); + describe('getSubscriptionMetadata', function () { + it('should get metadata for a subscription', function (done) { + program.getSubscriptionMetadata(subscriptionNameOne, function (err, metadata) { + assert.ifError(err); + assert.equal(metadata.name, fullSubscriptionNameOne); + assert(console.log.calledWith('Got metadata for subscription: %s', subscriptionNameOne)); + done(); + }); + }); + }); + describe('listSubscriptions', function () { it('should list subscriptions', function (done) { - program.listSubscriptions(topicName, function (err, subscriptions) { + program.listSubscriptions(topicNameOne, function (err, subscriptions) { assert.ifError(err); assert(Array.isArray(subscriptions)); assert(subscriptions.length > 0); var recentlyCreatedSubscriptions = subscriptions.filter(function (subscription) { - return subscription.name === name; + return subscription.name === fullSubscriptionNameOne || subscription.name === fullSubscriptionNameTwo; }); - assert.equal(recentlyCreatedSubscriptions.length, 1, 'list has newly created subscription'); - assert(console.log.calledWith('Found %d subscriptions!', subscriptions.length)); - - program.listSubscriptions(undefined, function (err, allSubscriptions) { - assert.ifError(err); - assert(Array.isArray(allSubscriptions)); - assert(allSubscriptions.length > 0); - var recentlyCreatedAllSubscriptions = allSubscriptions.filter(function (subscription) { - return subscription.name === name; - }); - assert.equal(recentlyCreatedAllSubscriptions.length, 1, 'list has newly created subscription'); - assert(console.log.calledWith('Found %d subscriptions!', allSubscriptions.length)); - done(); + assert.equal(recentlyCreatedSubscriptions.length, 1, 'list only has one newly created subscription'); + assert.equal(recentlyCreatedSubscriptions[0].name, fullSubscriptionNameOne, 'list has correct newly created subscription'); + assert(console.log.calledWith('Found %d subscription(s)!', subscriptions.length)); + done(); + }); + }); + }); + + describe('listAllSubscriptions', function () { + it('should list all subscriptions', function (done) { + program.listAllSubscriptions(function (err, allSubscriptions) { + assert.ifError(err); + assert(Array.isArray(allSubscriptions)); + assert(allSubscriptions.length > 0); + var recentlyCreatedAllSubscriptions = allSubscriptions.filter(function (subscription) { + return subscription.name === fullSubscriptionNameOne || subscription.name === fullSubscriptionNameTwo; }); + assert.equal(recentlyCreatedAllSubscriptions.length, 2, 'list has both newly created subscriptions'); + assert(console.log.calledWith('Found %d subscription(s)!', allSubscriptions.length)); + done(); }); }); }); @@ -76,16 +112,16 @@ describe('pubsub:subscriptions', function () { var expected = 'Hello World!'; before(function (done) { - pubsub.topic(topicName).publish({ data: expected }, done); + pubsub.topic(topicNameOne).publish({ data: expected }, done); }); it('should pull messages', function (done) { - program.pullMessages(subscriptionName, function (err, messages) { + program.pullMessages(subscriptionNameOne, function (err, messages) { assert.ifError(err); assert(Array.isArray(messages)); assert(messages.length > 0); - assert(console.log.calledWith('Pulled %d messages!', messages.length)); - assert(console.log.calledWith('Acked %d messages!', messages.length)); + assert(console.log.calledWith('Pulled %d message(s)!', messages.length)); + assert(console.log.calledWith('Acked %d message(s)!', messages.length)); assert.equal(messages[0].data, expected); done(); }); @@ -94,9 +130,9 @@ describe('pubsub:subscriptions', function () { describe('deleteSubscription', function () { it('should delete a subscription', function (done) { - program.deleteSubscription(subscriptionName, function (err) { + program.deleteSubscription(subscriptionNameOne, function (err) { assert.ifError(err); - assert(console.log.calledWith('Deleted subscription: %s', subscriptionName)); + assert(console.log.calledWith('Deleted subscription: %s', subscriptionNameOne)); done(); }); }); diff --git a/pubsub/system-test/topics.test.js b/pubsub/system-test/topics.test.js index 62704a4440..353b5a7863 100644 --- a/pubsub/system-test/topics.test.js +++ b/pubsub/system-test/topics.test.js @@ -15,17 +15,21 @@ var uuid = require('node-uuid'); var program = require('../topics'); + var topicName = 'nodejs-docs-samples-test-' + uuid.v4(); var projectId = process.env.GCLOUD_PROJECT; -var name = 'projects/' + projectId + '/topics/' + topicName; +var fullTopicName = 'projects/' + projectId + '/topics/' + topicName; +var message = { data: 'Hello, world!' }; describe('pubsub:topics', function () { describe('createTopic', function () { it('should create a topic', function (done) { - program.createTopic(topicName, function (err, topic) { + program.createTopic(topicName, function (err, topic, apiResponse) { assert.ifError(err); - assert.equal(topic.name, name); + assert.equal(topic.name, fullTopicName); assert(console.log.calledWith('Created topic: %s', topicName)); + assert.notEqual(apiResponse, undefined); + // Listing is eventually consistent, so give the index time to update setTimeout(done, 5000); }); }); @@ -38,7 +42,7 @@ describe('pubsub:topics', function () { assert(Array.isArray(topics)); assert(topics.length > 0); var recentlyCreatedTopics = topics.filter(function (topic) { - return topic.name === name; + return topic.name === fullTopicName; }); assert.equal(recentlyCreatedTopics.length, 1, 'list has newly created topic'); assert(console.log.calledWith('Found %d topics!', topics.length)); @@ -49,12 +53,12 @@ describe('pubsub:topics', function () { describe('publishMessage', function () { it('should publish a message', function (done) { - var json = '{"data":"Hello World!"}'; - program.publishMessage(topicName, json, function (err, messageIds) { + program.publishMessage(topicName, message, function (err, messageIds, apiResponse) { assert.ifError(err); assert(Array.isArray(messageIds)); assert(messageIds.length > 0); - assert(console.log.calledWith('Published %d messages!', messageIds.length)); + assert(console.log.calledWith('Published %d message(s)!', messageIds.length)); + assert.notEqual(apiResponse, undefined); done(); }); }); @@ -62,9 +66,10 @@ describe('pubsub:topics', function () { describe('deleteTopic', function () { it('should delete a topic', function (done) { - program.deleteTopic(topicName, function (err) { + program.deleteTopic(topicName, function (err, apiResponse) { assert.ifError(err); assert(console.log.calledWith('Deleted topic: %s', topicName)); + assert.notEqual(apiResponse, undefined); done(); }); }); diff --git a/pubsub/test/iam.test.js b/pubsub/test/iam.test.js index 8c87510edc..9af08e11f2 100644 --- a/pubsub/test/iam.test.js +++ b/pubsub/test/iam.test.js @@ -20,18 +20,19 @@ var policyMock = 'policy'; var permissionsMock = 'permissions'; function getSample () { + var apiResponseMock = {}; var subscriptionMock = { iam: { getPolicy: sinon.stub().callsArgWith(0, null, policyMock), - setPolicy: sinon.stub().callsArgWith(1, null, policyMock), - testPermissions: sinon.stub().callsArgWith(1, null, permissionsMock) + setPolicy: sinon.stub().callsArgWith(1, null, policyMock, apiResponseMock), + testPermissions: sinon.stub().callsArgWith(1, null, permissionsMock, apiResponseMock) } }; var topicMock = { iam: { getPolicy: sinon.stub().callsArgWith(0, null, policyMock), - setPolicy: sinon.stub().callsArgWith(1, null, policyMock), - testPermissions: sinon.stub().callsArgWith(1, null, permissionsMock) + setPolicy: sinon.stub().callsArgWith(1, null, policyMock, apiResponseMock), + testPermissions: sinon.stub().callsArgWith(1, null, permissionsMock, apiResponseMock) } }; var pubsubMock = { @@ -47,7 +48,8 @@ function getSample () { PubSub: PubSubMock, pubsub: pubsubMock, topic: topicMock, - subscription: subscriptionMock + subscription: subscriptionMock, + apiResponse: apiResponseMock } }; } @@ -62,18 +64,9 @@ describe('pubsub:iam', function () { assert.ifError(callback.firstCall.args[0]); assert.equal(callback.firstCall.args[1], policyMock); - assert(console.log.calledWith('Got topic policy:', policyMock)); + assert(console.log.calledWith('Got policy for topic: %s', topicName)); }); - it('should require topicName', function () { - var sample = getSample(); - var callback = sinon.stub(); - - sample.program.getTopicPolicy(undefined, callback); - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message = '"topicName" is required!'); - assert.equal(callback.firstCall.args[1], undefined); - }); it('should handle error', function () { var sample = getSample(); var error = new Error('error'); @@ -96,18 +89,9 @@ describe('pubsub:iam', function () { assert.ifError(callback.firstCall.args[0]); assert.equal(callback.firstCall.args[1], policyMock); - assert(console.log.calledWith('Got subscription policy:', policyMock)); + assert(console.log.calledWith('Got policy for subscription: %s', subscriptionName)); }); - it('should require subscriptionName', function () { - var sample = getSample(); - var callback = sinon.stub(); - - sample.program.getSubscriptionPolicy(undefined, callback); - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message = '"subscriptionName" is required!'); - assert.equal(callback.firstCall.args[1], undefined); - }); it('should handle error', function () { var sample = getSample(); var error = new Error('error'); @@ -130,18 +114,10 @@ describe('pubsub:iam', function () { assert.ifError(callback.firstCall.args[0]); assert.equal(callback.firstCall.args[1], policyMock); + assert.strictEqual(callback.firstCall.args[2], sample.mocks.apiResponse); assert(console.log.calledWith('Updated policy for topic: %s', topicName)); }); - it('should require topicName', function () { - var sample = getSample(); - var callback = sinon.stub(); - sample.program.setTopicPolicy(undefined, callback); - - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message = '"topicName" is required!'); - assert.equal(callback.firstCall.args[1], undefined); - }); it('should handle error', function () { var sample = getSample(); var error = new Error('error'); @@ -164,18 +140,10 @@ describe('pubsub:iam', function () { assert.ifError(callback.firstCall.args[0]); assert.equal(callback.firstCall.args[1], policyMock); + assert.strictEqual(callback.firstCall.args[2], sample.mocks.apiResponse); assert(console.log.calledWith('Updated policy for subscription: %s', subscriptionName)); }); - it('should require subscriptionName', function () { - var sample = getSample(); - var callback = sinon.stub(); - - sample.program.setSubscriptionPolicy(undefined, callback); - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message = '"subscriptionName" is required!'); - assert.equal(callback.firstCall.args[1], undefined); - }); it('should handle error', function () { var sample = getSample(); var error = new Error('error'); @@ -198,18 +166,10 @@ describe('pubsub:iam', function () { assert.ifError(callback.firstCall.args[0]); assert.equal(callback.firstCall.args[1], permissionsMock); + assert.strictEqual(callback.firstCall.args[2], sample.mocks.apiResponse); assert(console.log.calledWith('Tested permissions for topic: %s', topicName)); }); - it('should require topicName', function () { - var sample = getSample(); - var callback = sinon.stub(); - - sample.program.testTopicPermissions(undefined, callback); - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message = '"topicName" is required!'); - assert.equal(callback.firstCall.args[1], undefined); - }); it('should handle error', function () { var sample = getSample(); var error = new Error('error'); @@ -233,18 +193,10 @@ describe('pubsub:iam', function () { assert.ifError(callback.firstCall.args[0]); assert.equal(callback.firstCall.args[1], permissionsMock); + assert.strictEqual(callback.firstCall.args[2], sample.mocks.apiResponse); assert(console.log.calledWith('Tested permissions for subscription: %s', subscriptionName)); }); - it('should require subscriptionName', function () { - var sample = getSample(); - var callback = sinon.stub(); - sample.program.testSubscriptionPermissions(undefined, callback); - - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message = '"subscriptionName" is required!'); - assert.equal(callback.firstCall.args[1], undefined); - }); it('should handle error', function () { var sample = getSample(); var error = new Error('error'); diff --git a/pubsub/test/subscriptions.test.js b/pubsub/test/subscriptions.test.js index a460a8e85e..edf0800684 100644 --- a/pubsub/test/subscriptions.test.js +++ b/pubsub/test/subscriptions.test.js @@ -18,34 +18,33 @@ var topicName = 'foo'; var subscriptionName = 'bar'; function getSample () { + var apiResponseMock = {}; var messagesMock = [ { data: 'Hello World!' } ]; - var subscriptionMock = { - get: sinon.stub(), - delete: sinon.stub().callsArgWith(0, null), - pull: sinon.stub().callsArgWith(1, null, messagesMock), - ack: sinon.stub().callsArgWith(1, null) - }; - subscriptionMock.get.callsArgWith(1, null, subscriptionMock); - var topicMock = { - get: sinon.stub(), - subscription: sinon.stub().returns(subscriptionMock) - }; - topicMock.get.callsArgWith(1, null, topicMock); var subscriptionsMock = [ { name: subscriptionName } ]; + var metadataMock = {}; + var subscriptionMock = { + delete: sinon.stub().callsArgWith(0, null, apiResponseMock), + pull: sinon.stub().callsArgWith(0, null, messagesMock), + ack: sinon.stub().callsArgWith(1, null, apiResponseMock), + getMetadata: sinon.stub().callsArgWith(0, null, metadataMock) + }; + var topicMock = { + subscribe: sinon.stub().callsArgWith(1, null, subscriptionMock, apiResponseMock), + getSubscriptions: sinon.stub().callsArgWith(0, null, subscriptionsMock) + }; var pubsubMock = { topic: sinon.stub().returns(topicMock), subscription: sinon.stub().returns(subscriptionMock), - subscribe: sinon.stub().callsArgWith(3, null, subscriptionMock), - getSubscriptions: sinon.stub().callsArgWith(1, null, subscriptionsMock) + getSubscriptions: sinon.stub().callsArgWith(0, null, subscriptionsMock) }; var PubSubMock = sinon.stub().returns(pubsubMock); return { @@ -58,13 +57,15 @@ function getSample () { topic: topicMock, subscription: subscriptionMock, subscriptions: subscriptionsMock, - messages: messagesMock + messages: messagesMock, + apiResponse: apiResponseMock, + metadata: metadataMock } }; } describe('pubsub:subscriptions', function () { - describe('create', function () { + describe('createSubscription', function () { it('should create a subscription', function () { var sample = getSample(); var callback = sinon.stub(); @@ -73,102 +74,118 @@ describe('pubsub:subscriptions', function () { assert.ifError(callback.firstCall.args[0]); assert.strictEqual(callback.firstCall.args[1], sample.mocks.subscription); + assert.strictEqual(callback.firstCall.args[2], sample.mocks.apiResponse); assert(console.log.calledWith('Created subscription %s to topic %s', subscriptionName, topicName)); }); - it('should require topicName', function () { + + it('should handle error', function () { var sample = getSample(); + var error = new Error('error'); var callback = sinon.stub(); + sample.mocks.topic.subscribe.callsArgWith(1, error); - sample.program.createSubscription(undefined, undefined, callback); + sample.program.createSubscription(topicName, subscriptionName, callback); assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message = '"topicName" is required!'); - assert.equal(callback.firstCall.args[1], undefined); + assert(callback.firstCall.args[0].message === 'error'); }); - it('should require subscriptionName', function () { + }); + + describe('deleteSubscription', function () { + it('should delete a subscription', function () { var sample = getSample(); var callback = sinon.stub(); - sample.program.createSubscription(topicName, undefined, callback); + sample.program.deleteSubscription(subscriptionName, callback); - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message = '"subscriptionName" is required!'); - assert.equal(callback.firstCall.args[1], undefined); + assert.ifError(callback.firstCall.args[0]); + assert.strictEqual(callback.firstCall.args[1], sample.mocks.apiResponse); + assert(console.log.calledWith('Deleted subscription: %s', subscriptionName)); }); + it('should handle error', function () { var sample = getSample(); var error = new Error('error'); var callback = sinon.stub(); - sample.mocks.pubsub.subscribe.callsArgWith(3, error); + sample.mocks.subscription.delete.callsArgWith(0, error); - sample.program.createSubscription(topicName, subscriptionName, callback); + sample.program.deleteSubscription(subscriptionName, callback); assert(callback.firstCall.args[0]); assert(callback.firstCall.args[0].message === 'error'); }); }); - describe('delete', function () { - it('should delete a subscription', function () { + describe('getSubscriptionMetadata', function () { + it('should get the metadata for a subscription', function () { var sample = getSample(); var callback = sinon.stub(); - sample.program.deleteSubscription(subscriptionName, callback); + sample.program.getSubscriptionMetadata(subscriptionName, callback); assert.ifError(callback.firstCall.args[0]); - assert(console.log.calledWith('Deleted subscription: %s', subscriptionName)); + assert.strictEqual(callback.firstCall.args[1], sample.mocks.metadata); + assert(console.log.calledWith('Got metadata for subscription: %s', subscriptionName)); }); - it('should require subscriptionName', function () { - var sample = getSample(); - var callback = sinon.stub(); - - sample.program.deleteSubscription(undefined, callback); - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message = '"subscriptionName" is required!'); - assert.equal(callback.firstCall.args[1], undefined); - }); it('should handle error', function () { var sample = getSample(); var error = new Error('error'); var callback = sinon.stub(); - sample.mocks.subscription.delete.callsArgWith(0, error); + sample.mocks.subscription.getMetadata.callsArgWith(0, error); - sample.program.deleteSubscription(subscriptionName, callback); + sample.program.getSubscriptionMetadata(subscriptionName, callback); assert(callback.firstCall.args[0]); assert(callback.firstCall.args[0].message === 'error'); }); }); - describe('list', function () { - it('should list all subscriptions', function () { + describe('listSubscriptions', function () { + it('should list all subscriptions of a topic', function () { var sample = getSample(); var callback = sinon.stub(); - sample.program.listSubscriptions(undefined, callback); + sample.program.listSubscriptions(topicName, callback); assert.ifError(callback.firstCall.args[0]); assert.strictEqual(callback.firstCall.args[1], sample.mocks.subscriptions); - assert(console.log.calledWith('Found %d subscriptions!', callback.firstCall.args[1].length)); + assert(console.log.calledWith('Found %d subscription(s)!', callback.firstCall.args[1].length)); }); - it('should list all subscriptions of a topic', function () { + + it('should handle error', function () { var sample = getSample(); + var error = new Error('error'); var callback = sinon.stub(); + sample.mocks.topic.getSubscriptions.callsArgWith(0, error); sample.program.listSubscriptions(topicName, callback); + assert(callback.firstCall.args[0]); + assert(callback.firstCall.args[0].message === 'error'); + assert.equal(callback.firstCall.args[1], undefined); + }); + }); + + describe('listAllSubscriptions', function () { + it('should list all subscriptions', function () { + var sample = getSample(); + var callback = sinon.stub(); + + sample.program.listAllSubscriptions(callback); + assert.ifError(callback.firstCall.args[0]); assert.strictEqual(callback.firstCall.args[1], sample.mocks.subscriptions); - assert(console.log.calledWith('Found %d subscriptions!', callback.firstCall.args[1].length)); + assert(console.log.calledWith('Found %d subscription(s)!', callback.firstCall.args[1].length)); }); + it('should handle error', function () { var sample = getSample(); var error = new Error('error'); var callback = sinon.stub(); - sample.mocks.pubsub.getSubscriptions.callsArgWith(1, error); + sample.mocks.pubsub.getSubscriptions.callsArgWith(0, error); - sample.program.listSubscriptions(undefined, callback); + sample.program.listAllSubscriptions(callback); assert(callback.firstCall.args[0]); assert(callback.firstCall.args[0].message === 'error'); @@ -176,7 +193,7 @@ describe('pubsub:subscriptions', function () { }); }); - describe('pull', function () { + describe('pullMessages', function () { it('should pull messages', function () { var sample = getSample(); var callback = sinon.stub(); @@ -185,24 +202,16 @@ describe('pubsub:subscriptions', function () { assert.ifError(callback.firstCall.args[0]); assert.strictEqual(callback.firstCall.args[1], sample.mocks.messages); - assert(console.log.calledWith('Pulled %d messages!', callback.firstCall.args[1].length)); - assert(console.log.calledWith('Acked %d messages!', callback.firstCall.args[1].length)); + assert.strictEqual(callback.firstCall.args[2], sample.mocks.apiResponse); + assert(console.log.calledWith('Pulled %d message(s)!', callback.firstCall.args[1].length)); + assert(console.log.calledWith('Acked %d message(s)!', callback.firstCall.args[1].length)); }); - it('should require subscriptionName', function () { - var sample = getSample(); - var callback = sinon.stub(); - - sample.program.pullMessages(undefined, callback); - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message = '"subscriptionName" is required!'); - assert.equal(callback.firstCall.args[1], undefined); - }); it('should handle pull error', function () { var sample = getSample(); var error = new Error('error'); var callback = sinon.stub(); - sample.mocks.subscription.pull.callsArgWith(1, error); + sample.mocks.subscription.pull.callsArgWith(0, error); sample.program.pullMessages(subscriptionName, callback); @@ -210,6 +219,7 @@ describe('pubsub:subscriptions', function () { assert(callback.firstCall.args[0].message === 'error'); assert.equal(callback.firstCall.args[1], undefined); }); + it('should handle ack error', function () { var sample = getSample(); var error = new Error('error'); @@ -246,18 +256,18 @@ describe('pubsub:subscriptions', function () { var program = getSample().program; sinon.stub(program, 'listSubscriptions'); - program.main(['list']); + program.main(['list', topicName]); assert.equal(program.listSubscriptions.calledOnce, true); - assert.deepEqual(program.listSubscriptions.firstCall.args.slice(0, -1), [undefined]); + assert.deepEqual(program.listSubscriptions.firstCall.args.slice(0, -1), [topicName]); }); - it('should call listSubscriptions and filter by topic', function () { + it('should call listAllSubscriptions', function () { var program = getSample().program; - sinon.stub(program, 'listSubscriptions'); + sinon.stub(program, 'listAllSubscriptions'); - program.main(['list', topicName]); - assert.equal(program.listSubscriptions.calledOnce, true); - assert.deepEqual(program.listSubscriptions.firstCall.args.slice(0, -1), [topicName]); + program.main(['list']); + assert.equal(program.listAllSubscriptions.calledOnce, true); + assert.deepEqual(program.listAllSubscriptions.firstCall.args.slice(0, -1), []); }); it('should call pullMessages', function () { @@ -268,5 +278,14 @@ describe('pubsub:subscriptions', function () { assert.equal(program.pullMessages.calledOnce, true); assert.deepEqual(program.pullMessages.firstCall.args.slice(0, -1), [subscriptionName]); }); + + it('should call getSubscriptionMetadata', function () { + var program = getSample().program; + + sinon.stub(program, 'getSubscriptionMetadata'); + program.main(['get', subscriptionName]); + assert.equal(program.getSubscriptionMetadata.calledOnce, true); + assert.deepEqual(program.getSubscriptionMetadata.firstCall.args.slice(0, -1), [subscriptionName]); + }); }); }); diff --git a/pubsub/test/topics.test.js b/pubsub/test/topics.test.js index ee58b78c4d..319a63aae6 100644 --- a/pubsub/test/topics.test.js +++ b/pubsub/test/topics.test.js @@ -15,14 +15,16 @@ var proxyquire = require('proxyquire').noCallThru(); var topicName = 'foo'; +var message = { data: 'Hello, world!' }; function getSample () { + var apiResponseMock = {}; var topicMock = { get: sinon.stub(), - publish: sinon.stub().callsArgWith(1, null, [1]), - delete: sinon.stub().callsArgWith(0, null) + publish: sinon.stub().callsArgWith(1, null, [1], apiResponseMock), + delete: sinon.stub().callsArgWith(0, null, apiResponseMock) }; - topicMock.get.callsArgWith(1, null, topicMock); + topicMock.get.callsArgWith(1, null, topicMock, apiResponseMock); var topicsMock = [ { name: topicName @@ -42,13 +44,14 @@ function getSample () { PubSub: PubSubMock, pubsub: pubsubMock, topics: topicsMock, - topic: topicMock + topic: topicMock, + apiResponse: apiResponseMock } }; } describe('pubsub:topics', function () { - describe('create', function () { + describe('createTopic', function () { it('should create a topic', function () { var sample = getSample(); var callback = sinon.stub(); @@ -57,18 +60,10 @@ describe('pubsub:topics', function () { assert.ifError(callback.firstCall.args[0]); assert.strictEqual(callback.firstCall.args[1], sample.mocks.topic); + assert.strictEqual(callback.firstCall.args[2], sample.mocks.apiResponse); assert(console.log.calledWith('Created topic: %s', topicName)); }); - it('should require name', function () { - var sample = getSample(); - var callback = sinon.stub(); - - sample.program.createTopic(undefined, callback); - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message = '"name" is required!'); - assert.equal(callback.firstCall.args[1], undefined); - }); it('should handle error', function () { var sample = getSample(); var error = new Error('error'); @@ -82,7 +77,7 @@ describe('pubsub:topics', function () { }); }); - describe('delete', function () { + describe('deleteTopic', function () { it('should delete a topic', function () { var sample = getSample(); var callback = sinon.stub(); @@ -90,18 +85,10 @@ describe('pubsub:topics', function () { sample.program.deleteTopic(topicName, callback); assert.ifError(callback.firstCall.args[0]); + assert.strictEqual(callback.firstCall.args[1], sample.mocks.apiResponse); assert(console.log.calledWith('Deleted topic: %s', topicName)); }); - it('should require name', function () { - var sample = getSample(); - var callback = sinon.stub(); - sample.program.deleteTopic(undefined, callback); - - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message = '"name" is required!'); - assert.equal(callback.firstCall.args[1], undefined); - }); it('should handle error', function () { var sample = getSample(); var error = new Error('error'); @@ -120,49 +107,21 @@ describe('pubsub:topics', function () { var sample = getSample(); var callback = sinon.stub(); - sample.program.publishMessage(topicName, '{"data":"hello world"}', callback); + sample.program.publishMessage(topicName, message, callback); assert.ifError(callback.firstCall.args[0]); assert.deepEqual(callback.firstCall.args[1], [1]); - assert(console.log.calledWith('Published %d messages!', callback.firstCall.args[1].length)); - }); - it('should require name', function () { - var sample = getSample(); - var callback = sinon.stub(); - - sample.program.publishMessage(undefined, undefined, callback); - - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message = '"name" is required!'); - assert.equal(callback.firstCall.args[1], undefined); + assert.strictEqual(callback.firstCall.args[2], sample.mocks.apiResponse); + assert(console.log.calledWith('Published %d message(s)!', callback.firstCall.args[1].length)); }); - it('should require message', function () { - var sample = getSample(); - var callback = sinon.stub(); - - sample.program.publishMessage(topicName, undefined, callback); - - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message = '"message" is required!'); - assert.equal(callback.firstCall.args[1], undefined); - }); - it('should require a valid JSON string', function () { - var sample = getSample(); - var callback = sinon.stub(); - - sample.program.publishMessage(topicName, 'asdf', callback); - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message = '"message" must be a valid JSON string!'); - assert.equal(callback.firstCall.args[1], undefined); - }); it('should handle error', function () { var sample = getSample(); var error = new Error('error'); var callback = sinon.stub(); sample.mocks.topic.publish.callsArgWith(1, error); - sample.program.publishMessage(topicName, '{"data":"hello world"}', callback); + sample.program.publishMessage(topicName, message, callback); assert(callback.firstCall.args[0]); assert(callback.firstCall.args[0].message === 'error'); @@ -181,6 +140,7 @@ describe('pubsub:topics', function () { assert.strictEqual(callback.firstCall.args[1], sample.mocks.topics); assert(console.log.calledWith('Found %d topics!', callback.firstCall.args[1].length)); }); + it('should handle error', function () { var sample = getSample(); var error = new Error('error'); @@ -229,7 +189,17 @@ describe('pubsub:topics', function () { sinon.stub(program, 'publishMessage'); program.main(['publish', topicName, '{}']); assert.equal(program.publishMessage.calledOnce, true); - assert.deepEqual(program.publishMessage.firstCall.args.slice(0, -1), [topicName, '{}']); + assert.deepEqual(program.publishMessage.firstCall.args.slice(0, -1), [topicName, {}]); + }); + + it('should call publishMessage and validate message', function () { + var program = getSample().program; + + sinon.stub(program, 'publishMessage'); + program.main(['publish', topicName, '{asdf}']); + assert.equal(program.publishMessage.calledOnce, false); + assert.equal(console.error.calledOnce, true); + assert.deepEqual(console.error.firstCall.args, ['"message" must be a valid JSON string!']); }); }); }); diff --git a/pubsub/topics.js b/pubsub/topics.js index b60e250c83..c51c2536f0 100644 --- a/pubsub/topics.js +++ b/pubsub/topics.js @@ -13,115 +13,77 @@ 'use strict'; -// [START auth] +// [START setup] // By default, the client will authenticate using the service account file // specified by the GOOGLE_APPLICATION_CREDENTIALS environment variable and use // the project specified by the GCLOUD_PROJECT environment variable. See // https://googlecloudplatform.github.io/gcloud-node/#/docs/google-cloud/latest/guides/authentication var PubSub = require('@google-cloud/pubsub'); +// [END setup] -// Instantiate a pubsub client -var pubsub = PubSub(); -// [END auth] - -// [START create_topic] -/** - * Create a new topic. - * - * @param {string} topicName Name for the new topic. - * @param {Function} callback The callback function. - */ function createTopic (topicName, callback) { - if (!topicName) { - return callback(new Error('"topicName" is required!')); - } - + var pubsub = PubSub(); var topic = pubsub.topic(topicName); - // Get the topic if it exists. Create it if it does not exist. + // Get the topic if it exists, otherwise create the topic + // See https://googlecloudplatform.github.io/google-cloud-node/#/docs/pubsub/latest/pubsub/topic?method=get topic.get({ autoCreate: true - }, function (err, topic) { + }, function (err, topic, apiResponse) { if (err) { return callback(err); } - // Created the topic console.log('Created topic: %s', topicName); - return callback(null, topic); + return callback(null, topic, apiResponse); }); } -// [END create_topic] - -// [START delete_topic] -/** - * Delete a topic. - * - * @param {string} topicName Name of the topic to delete. - * @param {Function} callback Callback function. - */ -function deleteTopic (topicName, callback) { - if (!topicName) { - return callback(new Error('"topicName" is required!')); - } - // Grab a reference to an existing topic +function deleteTopic (topicName, callback) { + var pubsub = PubSub(); var topic = pubsub.topic(topicName); // Delete the topic - topic.delete(function (err) { + // See https://googlecloudplatform.github.io/google-cloud-node/#/docs/pubsub/latest/pubsub/topic?method=delete + topic.delete(function (err, apiResponse) { if (err) { return callback(err); } // Deleted the topic console.log('Deleted topic: %s', topicName); - return callback(null); + return callback(null, apiResponse); }); } -// [END delete_topic] - -// [START publish] -/** - * Publish a message to a topic. - * - * @param {string} topicName Name of the topic to which to publish. - * @param {Function} callback Callback function. - */ -function publishMessage (topicName, message, callback) { - if (!topicName) { - return callback(new Error('"topicName" is required!')); - } else if (!message) { - return callback(new Error('"message" is required!')); - } - try { - message = JSON.parse(message); - } catch (err) { - return callback(new Error('"message" must be a valid JSON string!')); - } - // Grab a reference to an existing topic +function publishMessage (topicName, message, callback) { + var pubsub = PubSub(); var topic = pubsub.topic(topicName); - // Publish a message to the topic - topic.publish(message, function (err, messageIds) { + /** + * Publish a message to the topic, e.g. { "data": "Hello, world!" }. In + * Node.js, a PubSub message requires a "data" property, which can have a + * string or an object as its value. An optional "attributes" property can be + * an object of key/value pairs, where the keys and values are both strings. + * See https://cloud.google.com/pubsub/reference/rpc/google.pubsub.v1#google.pubsub.v1.PubsubMessage + * + * Topic#publish() takes either a single message object or an array of message + * objects. See https://googlecloudplatform.github.io/google-cloud-node/#/docs/pubsub/latest/pubsub/topic?method=publish + */ + topic.publish(message, function (err, messageIds, apiResponse) { if (err) { return callback(err); } - console.log('Published %d messages!', messageIds.length); - return callback(null, messageIds); + console.log('Published %d message(s)!', messageIds.length); + return callback(null, messageIds, apiResponse); }); } -// [END publish] - -// [START list_topics] -/** - * List all topics in the current project. - * - * @param {Function} callback The callback function. - */ + function listTopics (callback) { + var pubsub = PubSub(); + + // See https://googlecloudplatform.github.io/google-cloud-node/#/docs/pubsub/latest/pubsub?method=getTopics pubsub.getTopics(function (err, topics) { if (err) { return callback(err); @@ -131,8 +93,6 @@ function listTopics (callback) { return callback(null, topics); }); } -// [END list_topics] -// [END all] // The command-line program var cli = require('yargs'); @@ -151,23 +111,28 @@ var program = module.exports = { cli .demand(1) - .command('create ', 'Create a new topic.', {}, function (options) { - program.createTopic(options.name, makeHandler(true, 'id')); + .command('create ', 'Creates a new topic.', {}, function (options) { + program.createTopic(options.topicName, makeHandler(true, 'id')); }) - .command('list', 'List topics.', {}, function (options) { + .command('list', 'Lists topics.', {}, function (options) { program.listTopics(makeHandler(true, 'id')); }) - .command('publish ', 'Publish a message to the specified topic.', {}, function (options) { - program.publishMessage(options.topic, options.message, makeHandler()); + .command('publish ', 'Publish a message to the specified topic.', {}, function (options) { + try { + options.message = JSON.parse(options.message); + program.publishMessage(options.topicName, options.message, makeHandler()); + } catch (err) { + return console.error('"message" must be a valid JSON string!'); + } }) - .command('delete ', 'Delete the specified topic.', {}, function (options) { - program.deleteTopic(options.name, makeHandler(false)); + .command('delete ', 'Deletes the specified topic.', {}, function (options) { + program.deleteTopic(options.topicName, makeHandler(false)); }) - .example('node $0 create my-topic', 'Create a new topic named "my-topic".') - .example('node $0 list', 'List topics.') - .example('node $0 publish my-topic \'{"data":"Hello world!"}\'', 'Publish a message to "my-topic".') - .example('node $0 delete my-topic', 'Delete a topic named "my-topic".') - .wrap(80) + .example('node $0 create greetings', 'Creates a new topic named "greetings".') + .example('node $0 list', 'Lists all topics.') + .example('node $0 publish greetings \'{"data":"Hello world!"}\'', 'Publishes a message to "greetings".') + .example('node $0 delete greetings', 'Deletes a topic named "greetings".') + .wrap(120) .recommendCommands() .epilogue('For more information, see https://cloud.google.com/pubsub/docs');