diff --git a/README.md b/README.md index 75bf4a7057..5c2092c38a 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ on Google Cloud Platform. ### Prerequisites -1. Install [Node.js (and NPM)][node] +1. Install [Node.js v4.5.0 or greater][node] 1. Clone this repository: git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git diff --git a/bigquery/system-test/tables.test.js b/bigquery/system-test/tables.test.js index 607938f68e..a67bb37ad7 100644 --- a/bigquery/system-test/tables.test.js +++ b/bigquery/system-test/tables.test.js @@ -42,7 +42,7 @@ var srcTableId = options.tableId; var destDatasetId = generateUuid(); var destTableId = generateUuid(); -describe.only('bigquery:tables', function () { +describe('bigquery:tables', function () { before(function (done) { // Create bucket storage.createBucket(options.bucketName, function (err, bucket) { diff --git a/pubsub/README.md b/pubsub/README.md index d985c23d56..25584bf640 100644 --- a/pubsub/README.md +++ b/pubsub/README.md @@ -13,7 +13,6 @@ allows you to send and receive messages between independent applications. * [Samples](#samples) * [Topics](#topics) * [Subscriptions](#subscriptions) - * [IAM](#iam) ## Setup @@ -35,19 +34,26 @@ __Usage:__ `node topics --help` ``` Commands: + list Lists all topics in the current project. create Creates a new topic. - list Lists topics. - publish Publish a message to the specified topic. - delete Deletes the specified topic. + delete Deletes the a topic. + publish Publishes a message. + getPolicy Gets the IAM policy for a topic. + setPolicy Sets the IAM policy for a topic. + testPermissions Tests the permissions for a topic. Options: --help Show help [boolean] Examples: - 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". + node topics.js list Lists all topics in the current project. + node topics.js create greetings Creates a new topic named "greetings". + node topics.js delete greetings Deletes a topic named "greetings". + node topics.js publish greetings "Hello, world!" Publishes a simple message. + node topics.js publish greetings '{"data":"Hello, world!"}' Publishes a JSON message. + node topics.js getPolicy greetings Gets the IAM policy for a topic named "greetings". + node topics.js setPolicy greetings Sets the IAM policy for a topic named "greetings". + node topics.js testPermissions greetings Tests the permissions for a topic named "greetings". For more information, see https://cloud.google.com/pubsub/docs ``` @@ -63,58 +69,41 @@ __Usage:__ `node subscriptions --help` ``` Commands: - 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. + list [topicName] Lists all subscriptions in the current project, optionally filtering by a + topic. + create Creates a new subscription. + create-push Creates a new push subscription. + delete Deletes a subscription. + get Gets the metadata for a subscription. + pull Pulls messages for a subscription. + get-policy Gets the IAM policy for a subscription. + set-policy Sets the IAM policy for a subscription. + test-permissions Tests the permissions for a subscription. Options: --help Show help [boolean] Examples: - 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". + node subscriptions.js list Lists all subscriptions in the current project. + node subscriptions.js list greetings Lists all subscriptions for a topic named "greetings". + node subscriptions.js create greetings greetings-worker-1 Creates a subscription named "greetings-worker-1" to a + topic named "greetings". + node subscriptions.js create-push greetings Creates a push subscription named "greetings-worker-1" + greetings-worker-1 to a topic named "greetings". + node subscriptions.js get greetings-worker-1 Gets the metadata for a subscription named + "greetings-worker-1". + node subscriptions.js delete greetings-worker-1 Deletes a subscription named "greetings-worker-1". + node subscriptions.js pull greetings-worker-1 Pulls messages for a subscription named + "greetings-worker-1". + node subscriptions.js get-policy greetings-worker-1 Gets the IAM policy for a subscription named + "greetings-worker-1". + node subscriptions.js set-policy greetings-worker-1 Sets the IAM policy for a subscription named + "greetings-worker-1". + node subscriptions.js test-permissions greetings-worker-1 Tests the permissions for a subscription named + "greetings-worker-1". For more information, see https://cloud.google.com/pubsub/docs ``` [subscriptions_docs]: https://cloud.google.com/pubsub/subscriber [subscriptions_code]: subscriptions.js - -### IAM - -View the [documentation][iam_docs] or the [source code][iam_code]. - -__Usage:__ `node iam --help` - -``` -Usage: node iam RESOURCE COMMAND [ARGS...] - -Resources: - - topics - subscriptions - -Commands: - - get NAME - set NAME - test NAME - -Examples: - - node iam topics get my-topic - node iam topics set my-topic - node iam topics test my-topic - node iam subscriptions get my-subscription - node iam subscriptions set my-subscription - node iam subscriptions test my-subscription -``` - -[iam_docs]: https://cloud.google.com/pubsub/access_control -[iam_code]: iam.js diff --git a/pubsub/iam.js b/pubsub/iam.js deleted file mode 100644 index 8abfd1e70f..0000000000 --- a/pubsub/iam.js +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright 2016, Google, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -'use strict'; - -// [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] - -function getTopicPolicy (topicName, callback) { - var pubsub = PubSub(); - var topic = pubsub.topic(topicName); - - // Retrieve the IAM policy for the topic - // 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 policy for topic: %s', topicName); - return callback(null, policy, apiResponse); - }); -} - -function getSubscriptionPolicy (subscriptionName, callback) { - var pubsub = PubSub(); - var subscription = pubsub.subscription(subscriptionName); - - // Retrieve the IAM policy for the subscription - // 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 policy for subscription: %s', subscriptionName); - return callback(null, policy, apiResponse); - }); -} - -function setTopicPolicy (topicName, callback) { - var pubsub = PubSub(); - var topic = pubsub.topic(topicName); - - // Policy update - var newPolicy = { - bindings: [ - { - role: 'roles/pubsub.publisher', - members: ['serviceAccount:myotherproject@appspot.gserviceaccount.com'] - } - ] - }; - - // Set the IAM policy for the specified topic - // 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, updatedPolicy, apiResponse); - }); -} - -function setSubscriptionPolicy (subscriptionName, callback) { - var pubsub = PubSub(); - var subscription = pubsub.subscription(subscriptionName); - - // Policy update - var newPolicy = { - bindings: [ - { - role: 'roles/pubsub.subscriber', - members: ['serviceAccount:myotherproject@appspot.gserviceaccount.com'] - } - ] - }; - - // Set the IAM policy for the specified subscription - // 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, updatedPolicy, apiResponse); - }); -} - -function testTopicPermissions (topicName, callback) { - var pubsub = PubSub(); - var topic = pubsub.topic(topicName); - - var permissionsToTest = [ - 'pubsub.topics.attachSubscription', - 'pubsub.topics.publish', - 'pubsub.topics.update' - ]; - - // Test the IAM policy for the specified topic - // 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, apiResponse); - }); -} - -function testSubscriptionPermissions (subscriptionName, callback) { - var pubsub = PubSub(); - var subscription = pubsub.subscription(subscriptionName); - - var permissionsToTest = [ - 'pubsub.subscriptions.consume', - 'pubsub.subscriptions.update' - ]; - - // Test the IAM policy for the specified subscription - // 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, apiResponse); - }); -} - -// [START usage] -function printUsage () { - console.log('Usage: node iam RESOURCE COMMAND [ARGS...]'); - console.log('\nResources:\n'); - console.log('\ttopics'); - console.log('\tsubscriptions'); - console.log('\nCommands:\n'); - console.log('\tget NAME'); - console.log('\tset NAME'); - console.log('\ttest NAME'); - console.log('\nExamples:\n'); - console.log('\tnode iam topics get my-topic'); - console.log('\tnode iam topics set my-topic'); - console.log('\tnode iam topics test my-topic'); - console.log('\tnode iam subscriptions get my-subscription'); - console.log('\tnode iam subscriptions set my-subscription'); - console.log('\tnode iam subscriptions test my-subscription'); -} -// [END usage] - -// The command-line program -var program = { - getTopicPolicy: getTopicPolicy, - getSubscriptionPolicy: getSubscriptionPolicy, - setTopicPolicy: setTopicPolicy, - setSubscriptionPolicy: setSubscriptionPolicy, - testTopicPermissions: testTopicPermissions, - testSubscriptionPermissions: testSubscriptionPermissions, - printUsage: printUsage, - - // Executed when this program is run from the command-line - main: function (args, cb) { - var resource = args.shift(); - var command = args.shift(); - if (resource === 'topics') { - if (command === 'get') { - this.getTopicPolicy(args[0], cb); - } else if (command === 'set') { - this.setTopicPolicy(args[0], cb); - } else if (command === 'test') { - this.testTopicPermissions(args[0], cb); - } else { - this.printUsage(); - } - } else if (resource === 'subscriptions') { - if (command === 'get') { - this.getSubscriptionPolicy(args[0], cb); - } else if (command === 'set') { - this.setSubscriptionPolicy(args[0], cb); - } else if (command === 'test') { - this.testSubscriptionPermissions(args[0], cb); - } else { - this.printUsage(); - } - } else { - this.printUsage(); - } - } -}; - -if (module === require.main) { - program.main(process.argv.slice(2), console.log); -} - -module.exports = program; diff --git a/pubsub/package.json b/pubsub/package.json index 3c40d08300..da04a8f322 100644 --- a/pubsub/package.json +++ b/pubsub/package.json @@ -15,5 +15,8 @@ "devDependencies": { "mocha": "^3.0.2", "node-uuid": "^1.4.7" + }, + "engines": { + "node": "~4.5" } } diff --git a/pubsub/subscriptions.js b/pubsub/subscriptions.js index 24aadc82cf..915a5a9a95 100644 --- a/pubsub/subscriptions.js +++ b/pubsub/subscriptions.js @@ -1,153 +1,264 @@ -// Copyright 2016, Google, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/** + * Copyright 2016, Google, Inc. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ -'use strict'; +/** + * This application demonstrates how to perform basic operations on + * subscriptions with the Google Cloud Pub/Sub API. + * + * For more information, see the README.md under /pubsub and the documentation + * at https://cloud.google.com/pubsub/docs. + */ -// [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] +'use strict'; -function createSubscription (topicName, subscriptionName, callback) { - var pubsub = PubSub(); - var topic = pubsub.topic(topicName); +const pubsubClient = require(`@google-cloud/pubsub`)(); - // 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) { +// [START pubsub_list_subscriptions] +function listSubscriptions (callback) { + // Lists all subscriptions in the current project + pubsubClient.getSubscriptions((err, subscriptions) => { if (err) { - return callback(err); + callback(err); + return; } - console.log('Created subscription %s to topic %s', subscriptionName, topicName); - return callback(null, subscription, apiResponse); + console.log(`Subscriptions:`); + subscriptions.forEach((subscription) => console.log(subscription.name)); + callback(); }); } +// [END pubsub_list_subscriptions] -function deleteSubscription (subscriptionName, callback) { - var pubsub = PubSub(); - var subscription = pubsub.subscription(subscriptionName); +// [START pubsub_list_topic_subscriptions] +function listTopicSubscriptions (topicName, callback) { + // References an existing topic, e.g. "my-topic" + const topic = pubsubClient.topic(topicName); - // Delete the subscription - // See https://googlecloudplatform.github.io/google-cloud-node/#/docs/pubsub/latest/pubsub/subscription?method=delete - subscription.delete(function (err, apiResponse) { + // Lists all subscriptions for the topic + topic.getSubscriptions((err, subscriptions) => { if (err) { - return callback(err); + callback(err); + return; } - console.log('Deleted subscription: %s', subscriptionName); - return callback(null, apiResponse); + console.log(`Subscriptions for ${topicName}:`); + subscriptions.forEach((subscription) => console.log(subscription.name)); + callback(); }); } +// [END pubsub_list_topic_subscriptions] -function getSubscriptionMetadata (subscriptionName, callback) { - var pubsub = PubSub(); - var subscription = pubsub.subscription(subscriptionName); +// [START pubsub_create_subscription] +function createSubscription (topicName, subscriptionName, callback) { + // References an existing topic, e.g. "my-topic" + const topic = pubsubClient.topic(topicName); - // 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) { + // Creates a new subscription, e.g. "my-new-subscription" + topic.subscribe(subscriptionName, (err, subscription) => { if (err) { - return callback(err); + callback(err); + return; } - console.log('Got metadata for subscription: %s', subscriptionName); - return callback(null, metadata); + console.log(`Subscription ${subscription.name} created.`); + callback(); }); } +// [END pubsub_create_subscription] -function listSubscriptions (topicName, callback) { - var pubsub = PubSub(); - var topic = pubsub.topic(topicName); +// [START pubsub_create_push_subscription] +function createPushSubscription (topicName, subscriptionName, callback) { + // References an existing topic, e.g. "my-topic" + const topic = pubsubClient.topic(topicName); + const projectId = process.env.GCLOUD_PROJECT || 'YOU_PROJECT_ID'; - // 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) { + // Creates a new push subscription, e.g. "my-new-subscription" + topic.subscribe(subscriptionName, { + pushConfig: { + // Set to an HTTPS endpoint of your choice. If necessary, register + // (authorize) the domain on which the server is hosted. + pushEndpoint: `https://${projectId}.appspot.com/push` + } + }, (err, subscription) => { if (err) { - return callback(err); + callback(err); + return; } - console.log('Found %d subscription(s)!', subscriptions.length); - return callback(null, subscriptions); + console.log(`Subscription ${subscription.name} created.`); + callback(); }); } +// [END pubsub_create_push_subscription] -function listAllSubscriptions (callback) { - var pubsub = PubSub(); +// [START pubsub_delete_subscription] +function deleteSubscription (subscriptionName, callback) { + // References an existing subscription, e.g. "my-subscription" + const subscription = pubsubClient.subscription(subscriptionName); - // List all subscriptions - // See https://googlecloudplatform.github.io/google-cloud-node/#/docs/pubsub/latest/pubsub?method=getSubscriptions - pubsub.getSubscriptions(function (err, subscriptions) { + // Deletes the subscription + subscription.delete((err) => { if (err) { - return callback(err); + callback(err); + return; } - console.log('Found %d subscription(s)!', subscriptions.length); - return callback(null, subscriptions); + console.log(`Subscription ${subscription.name} deleted.`); + callback(); }); } +// [END pubsub_delete_subscription] + +// [START pubsub_get_subscription_metadata] +function getSubscriptionMetadata (subscriptionName, callback) { + // References an existing subscription, e.g. "my-subscription" + const subscription = pubsubClient.subscription(subscriptionName); + + // Gets the metadata for the subscription + subscription.getMetadata((err, metadata) => { + if (err) { + callback(err); + return; + } -function handleMessage (message) { - console.log('received message: ' + message.data); + console.log(`Subscription: ${metadata.name}`); + console.log(`Topic: ${metadata.topic}`); + console.log(`Push config: %s`, metadata.pushConfig.pushEndpoint); + console.log(`Ack deadline: ${metadata.ackDeadlineSeconds}s`); + callback(); + }); } +// [END pubsub_get_subscription_metadata] +// [START pubsub_pull_messages] function pullMessages (subscriptionName, callback) { - var pubsub = PubSub(); - var subscription = pubsub.subscription(subscriptionName); + // References an existing subscription, e.g. "my-subscription" + const subscription = pubsubClient.subscription(subscriptionName); - // Pull any messages on the subscription - // See https://googlecloudplatform.github.io/google-cloud-node/#/docs/pubsub/latest/pubsub/subscription?method=pull - subscription.pull(function (err, messages) { + // Pulls messages. Set returnImmediately to false to block until messages are + // received. + subscription.pull({ returnImmediately: true }, (err, messages) => { if (err) { - return callback(err); + callback(err); + return; } - // Do something for each message - messages.forEach(handleMessage); - console.log('Pulled %d message(s)!', messages.length); + console.log(`Received ${messages.length} messages.`); - var ackIds = messages.map(function (message) { - return message.ackId; + messages.forEach((message) => { + console.log(`* ${message.id} %j %j`, message.data, message.attributes); }); - // 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); + // Acknowledges received messages. If you do not acknowledge, Pub/Sub will + // redeliver the message. + subscription.ack(messages.map((message) => message.ackId), callback); + }); +} +// [END pubsub_pull_messages] + +// [START pubsub_get_subscription_policy] +function getSubscriptionPolicy (subscriptionName, callback) { + // References an existing subscription, e.g. "my-subscription" + const subscription = pubsubClient.subscription(subscriptionName); + + // Retrieves the IAM policy for the subscription + subscription.iam.getPolicy((err, policy) => { + if (err) { + callback(err); + return; + } + + console.log(`Policy for subscription: %j.`, policy.bindings); + callback(); + }); +} +// [END pubsub_get_subscription_policy] + +// [START pubsub_set_subscription_policy] +function setSubscriptionPolicy (subscriptionName, callback) { + // References an existing subscription, e.g. "my-subscription" + const subscription = pubsubClient.subscription(subscriptionName); + + // The new IAM policy + const newPolicy = { + bindings: [ + { + // Add a group as editors + role: `roles/pubsub.editor`, + members: [`group:cloud-logs@google.com`] + }, + { + // Add all users as viewers + role: `roles/pubsub.viewer`, + members: [`allUsers`] } + ] + }; - console.log('Acked %d message(s)!', messages.length); - return callback(null, messages, apiResponse); - }); + // Updates the IAM policy for the subscription + subscription.iam.setPolicy(newPolicy, (err, updatedPolicy) => { + if (err) { + callback(err); + return; + } + + console.log(`Updated policy for subscription: %j`, updatedPolicy.bindings); + callback(); }); } +// [END pubsub_set_subscription_policy] + +// [START pubsub_test_subscription_permissions] +function testSubscriptionPermissions (subscriptionName, callback) { + // References an existing subscription, e.g. "my-subscription" + const subscription = pubsubClient.subscription(subscriptionName); + + const permissionsToTest = [ + `pubsub.subscriptions.consume`, + `pubsub.subscriptions.update` + ]; + + // Tests the IAM policy for the specified subscription + subscription.iam.testPermissions(permissionsToTest, (err, permissions) => { + if (err) { + callback(err); + return; + } + + console.log(`Tested permissions for subscription: %j`, permissions); + callback(); + }); +} +// [END pubsub_test_subscription_permissions] // The command-line program -var cli = require('yargs'); -var makeHandler = require('../utils').makeHandler; +const cli = require(`yargs`); +const makeHandler = require(`../utils`).makeHandler; -var program = module.exports = { +const program = module.exports = { + listSubscriptions: listSubscriptions, + listTopicSubscriptions: listTopicSubscriptions, createSubscription: createSubscription, + createPushSubscription: createPushSubscription, deleteSubscription: deleteSubscription, getSubscriptionMetadata: getSubscriptionMetadata, pullMessages: pullMessages, - listSubscriptions: listSubscriptions, - listAllSubscriptions: listAllSubscriptions, - main: function (args) { + getSubscriptionPolicy: getSubscriptionPolicy, + setSubscriptionPolicy: setSubscriptionPolicy, + testSubscriptionPermissions: testSubscriptionPermissions, + main: (args) => { // Run the command-line program cli.help().strict().parse(args).argv; } @@ -155,33 +266,50 @@ var program = module.exports = { cli .demand(1) - .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) { + .command(`list [topicName]`, `Lists all subscriptions in the current project, optionally filtering by a topic.`, {}, (options) => { if (options.topicName) { - program.listSubscriptions(options.topicName, makeHandler(true, 'id')); + program.listTopicSubscriptions(options.topicName, makeHandler(false)); } else { - program.listAllSubscriptions(makeHandler(true, 'id')); + program.listSubscriptions(makeHandler(false)); } }) - .command('get ', 'Gets the metadata the metadata for the specified subscription.', {}, function (options) { - program.getSubscriptionMetadata(options.subscriptionName, makeHandler()); + .command(`create `, `Creates a new subscription.`, {}, (options) => { + program.createSubscription(options.topicName, options.subscriptionName, makeHandler(false)); }) - .command('pull ', 'Pulls messages for the specified subscription.', {}, function (options) { - program.pullMessages(options.subscriptionName, makeHandler(false)); + .command(`create-push `, `Creates a new push subscription.`, {}, (options) => { + program.createPushSubscription(options.topicName, options.subscriptionName, makeHandler(false)); }) - .command('delete ', 'Deletes the specified subscription.', {}, function (options) { + .command(`delete `, `Deletes a subscription.`, {}, (options) => { program.deleteSubscription(options.subscriptionName, makeHandler(false)); }) - .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".') + .command(`get `, `Gets the metadata for a subscription.`, {}, (options) => { + program.getSubscriptionMetadata(options.subscriptionName, makeHandler(false)); + }) + .command(`pull `, `Pulls messages for a subscription.`, {}, (options) => { + program.pullMessages(options.subscriptionName, makeHandler(false)); + }) + .command(`get-policy `, `Gets the IAM policy for a subscription.`, {}, (options) => { + program.getSubscriptionPolicy(options.subscriptionName, makeHandler(false)); + }) + .command(`set-policy `, `Sets the IAM policy for a subscription.`, {}, (options) => { + program.setSubscriptionPolicy(options.subscriptionName, makeHandler(false)); + }) + .command(`test-permissions `, `Tests the permissions for a subscription.`, {}, (options) => { + program.testSubscriptionPermissions(options.subscriptionName, makeHandler(false)); + }) + .example(`node $0 list`, `Lists all subscriptions in the current project.`) + .example(`node $0 list greetings`, `Lists all subscriptions for a topic named "greetings".`) + .example(`node $0 create greetings greetings-worker-1`, `Creates a subscription named "greetings-worker-1" to a topic named "greetings".`) + .example(`node $0 create-push greetings greetings-worker-1`, `Creates a push subscription named "greetings-worker-1" to a topic named "greetings".`) + .example(`node $0 get greetings-worker-1`, `Gets the metadata for a subscription named "greetings-worker-1".`) + .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 get-policy greetings-worker-1`, `Gets the IAM policy for a subscription named "greetings-worker-1".`) + .example(`node $0 set-policy greetings-worker-1`, `Sets the IAM policy for a subscription named "greetings-worker-1".`) + .example(`node $0 test-permissions greetings-worker-1`, `Tests the permissions for a subscription named "greetings-worker-1".`) .wrap(120) .recommendCommands() - .epilogue('For more information, see https://cloud.google.com/pubsub/docs'); + .epilogue(`For more information, see https://cloud.google.com/pubsub/docs`); if (module === require.main) { program.main(process.argv.slice(2)); diff --git a/pubsub/system-test/iam.test.js b/pubsub/system-test/iam.test.js deleted file mode 100644 index b95a6caedf..0000000000 --- a/pubsub/system-test/iam.test.js +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2015-2016, Google, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -'use strict'; - -var uuid = require('node-uuid'); -var PubSub = require('@google-cloud/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(); - -describe('pubsub:iam', function () { - before(function (done) { - pubsub.topic(topicName).get({ - autoCreate: true - }, function (err) { - if (err) { - return done(err); - } - var options = { - reuseExisting: true - }; - pubsub.subscribe(topicName, subscriptionName, options, done); - }); - }); - - after(function (done) { - pubsub.subscription(subscriptionName).delete(function () { - pubsub.topic(topicName).delete(done); - }); - }); - - describe('getTopicPolicy', function () { - it('should get a topic\'s policy', function (done) { - program.getTopicPolicy(topicName, function (err, policy) { - assert.ifError(err); - assert(policy); - assert(console.log.calledWith('Got policy for topic: %s', topicName)); - done(); - }); - }); - }); - - describe('getSubscriptionPolicy', function () { - it('should get a subscriptions\'s policy', function (done) { - program.getSubscriptionPolicy(subscriptionName, function (err, policy) { - assert.ifError(err); - assert(policy); - assert(console.log.calledWith('Got policy for subscription: %s', subscriptionName)); - done(); - }); - }); - }); - - describe('testTopicPermissions', function () { - it('should test a topic\'s permissions', function (done) { - 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(); - }); - }); - }); - - describe('testSubscriptionPermissions', function () { - it('should test a subscriptions\'s permissions', function (done) { - 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 ecc2187263..1574f2cca5 100644 --- a/pubsub/system-test/subscriptions.test.js +++ b/pubsub/system-test/subscriptions.test.js @@ -13,128 +13,139 @@ 'use strict'; -var uuid = require('node-uuid'); -var PubSub = require('@google-cloud/pubsub'); -var program = require('../subscriptions'); - -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 fullSubscriptionNameOne = 'projects/' + projectId + '/subscriptions/' + subscriptionNameOne; -var fullSubscriptionNameTwo = 'projects/' + projectId + '/subscriptions/' + subscriptionNameTwo; - -describe('pubsub:subscriptions', function () { - before(function (done) { - pubsub.topic(topicNameOne).get({ - autoCreate: true - }, 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'); +const pubsub = require(`@google-cloud/pubsub`)(); +const uuid = require(`node-uuid`); +const path = require(`path`); +const run = require(`../../utils`).run; + +const cwd = path.join(__dirname, `..`); +const topicName = `nodejs-docs-samples-test-${uuid.v4()}`; +const subscriptionNameOne = `nodejs-docs-samples-test-sub-${uuid.v4()}`; +const subscriptionNameTwo = `nodejs-docs-samples-test-sub-${uuid.v4()}`; +const projectId = process.env.GCLOUD_PROJECT; +const fullTopicName = `projects/${projectId}/topics/${topicName}`; +const fullSubscriptionNameOne = `projects/${projectId}/subscriptions/${subscriptionNameOne}`; +const fullSubscriptionNameTwo = `projects/${projectId}/subscriptions/${subscriptionNameTwo}`; +const cmd = `node subscriptions.js`; + +describe(`pubsub:subscriptions`, () => { + before((done) => { + pubsub.createTopic(topicName, (err) => { + assert.ifError(err); + done(); + }); + }); - done(); - }); + after((done) => { + pubsub.subscription(subscriptionNameOne).delete(() => { + // Ignore any error + pubsub.topic(topicName).delete(() => { + // Ignore any error + done(); }); }); }); - after(function (done) { - pubsub.topic(topicNameOne).delete(done); + it(`should create a subscription`, (done) => { + const output = run(`${cmd} create ${topicName} ${subscriptionNameOne}`, cwd); + assert.equal(output, `Subscription ${fullSubscriptionNameOne} created.`); + pubsub.subscription(subscriptionNameOne).exists((err, exists) => { + assert.ifError(err); + assert.equal(exists, true); + done(); + }); }); - describe('createSubscription', function () { - it('should create a subscription', function (done) { - program.createSubscription(topicNameOne, subscriptionNameOne, function (err, subscription, apiResponse) { - assert.ifError(err); - 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); - }); + it(`should create a push subscription`, (done) => { + const output = run(`${cmd} create-push ${topicName} ${subscriptionNameTwo}`, cwd); + assert.equal(output, `Subscription ${fullSubscriptionNameTwo} created.`); + pubsub.subscription(subscriptionNameTwo).exists((err, exists) => { + assert.ifError(err); + assert.equal(exists, true); + done(); }); }); - 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(); - }); - }); + it(`should get metadata for a subscription`, () => { + const output = run(`${cmd} get ${subscriptionNameOne}`, cwd); + const expected = `Subscription: ${fullSubscriptionNameOne}` + + `\nTopic: ${fullTopicName}` + + `\nPush config: ` + + `\nAck deadline: 10s`; + assert.equal(output, expected); }); - describe('listSubscriptions', function () { - it('should list subscriptions', function (done) { - 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 === fullSubscriptionNameOne || subscription.name === fullSubscriptionNameTwo; - }); - 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(); - }); - }); + it(`should list all subscriptions`, (done) => { + // Listing is eventually consistent. Give the indexes time to update. + setTimeout(() => { + const output = run(`${cmd} list`, cwd); + assert.notEqual(output.indexOf(`Subscriptions:`), -1); + assert.notEqual(output.indexOf(fullSubscriptionNameOne), -1); + done(); + }, 5000); + }); + + it(`should list subscriptions for a topic`, (done) => { + // Listing is eventually consistent. Give the indexes time to update. + const output = run(`${cmd} list ${topicName}`, cwd); + assert.notEqual(output.indexOf(`Subscriptions for ${topicName}:`), -1); + assert.notEqual(output.indexOf(fullSubscriptionNameOne), -1); + 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)); + it(`should pull messages`, (done) => { + const expected = `Hello, world!`; + pubsub.topic(topicName).publish({ data: expected }, (err, messageIds) => { + assert.ifError(err); + setTimeout(() => { + const output = run(`${cmd} pull ${subscriptionNameOne}`, cwd); + const expectedOutput = `Received ${messageIds.length} messages.\n` + + `* ${messageIds[0]} "${expected}" {}`; + assert.equal(output, expectedOutput); done(); - }); + }, 5000); }); }); - describe('pullMessages', function () { - var expected = 'Hello World!'; - - before(function (done) { - pubsub.topic(topicNameOne).publish({ data: expected }, done); + it(`should set the IAM policy for a subscription`, (done) => { + run(`${cmd} set-policy ${subscriptionNameOne}`, cwd); + pubsub.subscription(subscriptionNameOne).iam.getPolicy((err, policy) => { + assert.ifError(err); + assert.deepEqual(policy.bindings, [ + { + role: `roles/pubsub.editor`, + members: [`group:cloud-logs@google.com`] + }, + { + role: `roles/pubsub.viewer`, + members: [`allUsers`] + } + ]); + done(); }); + }); - it('should pull messages', function (done) { - program.pullMessages(subscriptionNameOne, function (err, messages) { - assert.ifError(err); - assert(Array.isArray(messages)); - assert(messages.length > 0); - 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(); - }); + it(`should get the IAM policy for a subscription`, (done) => { + pubsub.subscription(subscriptionNameOne).iam.getPolicy((err, policy) => { + assert.ifError(err); + const output = run(`${cmd} get-policy ${subscriptionNameOne}`, cwd); + assert.equal(output, `Policy for subscription: ${JSON.stringify(policy.bindings)}.`); + done(); }); }); - describe('deleteSubscription', function () { - it('should delete a subscription', function (done) { - program.deleteSubscription(subscriptionNameOne, function (err) { - assert.ifError(err); - assert(console.log.calledWith('Deleted subscription: %s', subscriptionNameOne)); - done(); - }); + it(`should test permissions for a subscription`, () => { + const output = run(`${cmd} test-permissions ${subscriptionNameOne}`, cwd); + assert.notEqual(output.indexOf(`Tested permissions for subscription`), -1); + }); + + it(`should delete a subscription`, (done) => { + const output = run(`${cmd} delete ${subscriptionNameOne}`, cwd); + assert.equal(output, `Subscription ${fullSubscriptionNameOne} deleted.`); + pubsub.subscription(subscriptionNameOne).exists((err, exists) => { + assert.ifError(err); + assert.equal(exists, false); + done(); }); }); }); diff --git a/pubsub/system-test/topics.test.js b/pubsub/system-test/topics.test.js index 353b5a7863..d84c701f60 100644 --- a/pubsub/system-test/topics.test.js +++ b/pubsub/system-test/topics.test.js @@ -13,65 +13,115 @@ 'use strict'; -var uuid = require('node-uuid'); -var program = require('../topics'); +const pubsub = require(`@google-cloud/pubsub`)(); +const uuid = require(`node-uuid`); +const path = require(`path`); +const run = require(`../../utils`).run; -var topicName = 'nodejs-docs-samples-test-' + uuid.v4(); -var projectId = process.env.GCLOUD_PROJECT; -var fullTopicName = 'projects/' + projectId + '/topics/' + topicName; -var message = { data: 'Hello, world!' }; +const cwd = path.join(__dirname, `..`); +const topicName = `nodejs-docs-samples-test-${uuid.v4()}`; +const subscriptionName = `nodejs-docs-samples-test-${uuid.v4()}`; +const projectId = process.env.GCLOUD_PROJECT; +const fullTopicName = `projects/${projectId}/topics/${topicName}`; +const message = { data: `Hello, world!` }; +const cmd = `node topics.js`; -describe('pubsub:topics', function () { - describe('createTopic', function () { - it('should create a topic', function (done) { - program.createTopic(topicName, function (err, topic, apiResponse) { - assert.ifError(err); - 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); +describe(`pubsub:topics`, () => { + after((done) => { + pubsub.subscription(subscriptionName).delete(() => { + // Ignore any error + pubsub.topic(topicName).delete(() => { + // Ignore any error + done(); }); }); }); - describe('listTopics', function () { - it('should list topics', function (done) { - program.listTopics(function (err, topics) { - assert.ifError(err); - assert(Array.isArray(topics)); - assert(topics.length > 0); - var recentlyCreatedTopics = topics.filter(function (topic) { - return topic.name === fullTopicName; - }); - assert.equal(recentlyCreatedTopics.length, 1, 'list has newly created topic'); - assert(console.log.calledWith('Found %d topics!', topics.length)); - done(); - }); + it(`should create a topic`, (done) => { + const output = run(`${cmd} create ${topicName}`, cwd); + assert.equal(output, `Topic ${fullTopicName} created.`); + pubsub.topic(topicName).exists((err, exists) => { + assert.ifError(err); + assert.equal(exists, true); + done(); }); }); - describe('publishMessage', function () { - it('should publish a message', function (done) { - program.publishMessage(topicName, message, function (err, messageIds, apiResponse) { + it(`should list topics`, (done) => { + // Listing is eventually consistent. Give the indexes time to update. + setTimeout(() => { + const output = run(`${cmd} list`, cwd); + assert.notEqual(output.indexOf(`Topics:`), -1); + assert.notEqual(output.indexOf(fullTopicName), -1); + done(); + }, 5000); + }); + + it(`should publish a simple message`, (done) => { + pubsub.topic(topicName).subscribe(subscriptionName, (err, subscription) => { + assert.ifError(err); + run(`${cmd} publish ${topicName} "${message.data}"`, cwd); + subscription.pull((err, messages) => { assert.ifError(err); - assert(Array.isArray(messageIds)); - assert(messageIds.length > 0); - assert(console.log.calledWith('Published %d message(s)!', messageIds.length)); - assert.notEqual(apiResponse, undefined); + console.log(JSON.stringify(messages, null, 2)); + assert.equal(messages[0].data, message.data); done(); }); }); }); - describe('deleteTopic', function () { - it('should delete a topic', function (done) { - program.deleteTopic(topicName, function (err, apiResponse) { + it(`should publish a JSON message`, (done) => { + pubsub.topic(topicName).subscribe(subscriptionName, { reuseExisting: true }, (err, subscription) => { + assert.ifError(err); + run(`${cmd} publish ${topicName} '${JSON.stringify(message)}'`, cwd); + subscription.pull((err, messages) => { assert.ifError(err); - assert(console.log.calledWith('Deleted topic: %s', topicName)); - assert.notEqual(apiResponse, undefined); + console.log(JSON.stringify(messages, null, 2)); + assert.deepEqual(messages[0].data, message); done(); }); }); }); + + it(`should set the IAM policy for a topic`, (done) => { + run(`${cmd} set-policy ${topicName}`, cwd); + pubsub.topic(topicName).iam.getPolicy((err, policy) => { + assert.ifError(err); + assert.deepEqual(policy.bindings, [ + { + role: `roles/pubsub.editor`, + members: [`group:cloud-logs@google.com`] + }, + { + role: `roles/pubsub.viewer`, + members: [`allUsers`] + } + ]); + done(); + }); + }); + + it(`should get the IAM policy for a topic`, (done) => { + pubsub.topic(topicName).iam.getPolicy((err, policy) => { + assert.ifError(err); + const output = run(`${cmd} get-policy ${topicName}`, cwd); + assert.equal(output, `Policy for topic: ${JSON.stringify(policy.bindings)}.`); + done(); + }); + }); + + it(`should test permissions for a topic`, () => { + const output = run(`${cmd} test-permissions ${topicName}`, cwd); + assert.notEqual(output.indexOf(`Tested permissions for topic`), -1); + }); + + it(`should delete a topic`, (done) => { + const output = run(`${cmd} delete ${topicName}`, cwd); + assert.equal(output, `Topic ${fullTopicName} deleted.`); + pubsub.topic(topicName).exists((err, exists) => { + assert.ifError(err); + assert.equal(exists, false); + done(); + }); + }); }); diff --git a/pubsub/test/iam.test.js b/pubsub/test/iam.test.js deleted file mode 100644 index 9af08e11f2..0000000000 --- a/pubsub/test/iam.test.js +++ /dev/null @@ -1,277 +0,0 @@ -// Copyright 2016, Google, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -'use strict'; - -var proxyquire = require('proxyquire').noCallThru(); -var topicName = 'foo'; -var subscriptionName = 'bar'; -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, 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, apiResponseMock), - testPermissions: sinon.stub().callsArgWith(1, null, permissionsMock, apiResponseMock) - } - }; - var pubsubMock = { - topic: sinon.stub().returns(topicMock), - subscription: sinon.stub().returns(subscriptionMock) - }; - var PubSubMock = sinon.stub().returns(pubsubMock); - return { - program: proxyquire('../iam', { - '@google-cloud/pubsub': PubSubMock - }), - mocks: { - PubSub: PubSubMock, - pubsub: pubsubMock, - topic: topicMock, - subscription: subscriptionMock, - apiResponse: apiResponseMock - } - }; -} - -describe('pubsub:iam', function () { - describe('getTopicPolicy', function () { - it('should get a topic\'s policy', function () { - var sample = getSample(); - var callback = sinon.stub(); - - sample.program.getTopicPolicy(topicName, callback); - - assert.ifError(callback.firstCall.args[0]); - assert.equal(callback.firstCall.args[1], policyMock); - assert(console.log.calledWith('Got policy for topic: %s', topicName)); - }); - - it('should handle error', function () { - var sample = getSample(); - var error = new Error('error'); - var callback = sinon.stub(); - sample.mocks.topic.iam.getPolicy.callsArgWith(0, error); - - sample.program.getTopicPolicy(topicName, callback); - - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message === 'error'); - }); - }); - - describe('getSubscriptionPolicy', function () { - it('should get a subscription\'s policy', function () { - var sample = getSample(); - var callback = sinon.stub(); - - sample.program.getSubscriptionPolicy(subscriptionName, callback); - - assert.ifError(callback.firstCall.args[0]); - assert.equal(callback.firstCall.args[1], policyMock); - assert(console.log.calledWith('Got policy for subscription: %s', subscriptionName)); - }); - - it('should handle error', function () { - var sample = getSample(); - var error = new Error('error'); - var callback = sinon.stub(); - sample.mocks.subscription.iam.getPolicy.callsArgWith(0, error); - - sample.program.getSubscriptionPolicy(subscriptionName, callback); - - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message === 'error'); - }); - }); - - describe('setTopicPolicy', function () { - it('should set a topic\'s policy', function () { - var sample = getSample(); - var callback = sinon.stub(); - - sample.program.setTopicPolicy(topicName, callback); - - 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 handle error', function () { - var sample = getSample(); - var error = new Error('error'); - var callback = sinon.stub(); - sample.mocks.topic.iam.setPolicy.callsArgWith(1, error); - - sample.program.setTopicPolicy(topicName, callback); - - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message === 'error'); - }); - }); - - describe('setSubscriptionPolicy', function () { - it('should set a subscription\'s policy', function () { - var sample = getSample(); - var callback = sinon.stub(); - - sample.program.setSubscriptionPolicy(subscriptionName, callback); - - 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 handle error', function () { - var sample = getSample(); - var error = new Error('error'); - var callback = sinon.stub(); - sample.mocks.subscription.iam.setPolicy.callsArgWith(1, error); - - sample.program.setSubscriptionPolicy(subscriptionName, callback); - - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message === 'error'); - }); - }); - - describe('testTopicPermissions', function () { - it('should test a topic\'s permissions', function () { - var sample = getSample(); - var callback = sinon.stub(); - - sample.program.testTopicPermissions(topicName, callback); - - 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 handle error', function () { - var sample = getSample(); - var error = new Error('error'); - var callback = sinon.stub(); - sample.mocks.topic.iam.testPermissions.callsArgWith(1, error); - - sample.program.testTopicPermissions(topicName, callback); - - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message === 'error'); - assert.equal(callback.firstCall.args[1], undefined); - }); - }); - - describe('testSubscriptionPermissions', function () { - it('should tests a subscription\'s permissions', function () { - var sample = getSample(); - var callback = sinon.stub(); - - sample.program.testSubscriptionPermissions(subscriptionName, callback); - - 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 handle error', function () { - var sample = getSample(); - var error = new Error('error'); - var callback = sinon.stub(); - sample.mocks.subscription.iam.testPermissions.callsArgWith(1, error); - - sample.program.testSubscriptionPermissions(subscriptionName, callback); - - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message === 'error'); - assert.equal(callback.firstCall.args[1], undefined); - }); - }); - - describe('printUsage', function () { - it('should print usage', function () { - var program = getSample().program; - - program.printUsage(); - - assert(console.log.calledWith('Usage: node iam RESOURCE COMMAND [ARGS...]')); - assert(console.log.calledWith('\nResources:\n')); - assert(console.log.calledWith('\ttopics')); - assert(console.log.calledWith('\tsubscriptions')); - assert(console.log.calledWith('\nCommands:\n')); - assert(console.log.calledWith('\tget NAME')); - assert(console.log.calledWith('\tset NAME')); - assert(console.log.calledWith('\ttest NAME')); - assert(console.log.calledWith('\nExamples:\n')); - assert(console.log.calledWith('\tnode iam topics get my-topic')); - assert(console.log.calledWith('\tnode iam topics set my-topic')); - assert(console.log.calledWith('\tnode iam topics test my-topic')); - assert(console.log.calledWith('\tnode iam subscriptions get my-subscription')); - assert(console.log.calledWith('\tnode iam subscriptions set my-subscription')); - assert(console.log.calledWith('\tnode iam subscriptions test my-subscription')); - }); - }); - - describe('main', function () { - it('should call the right commands', function () { - var program = getSample().program; - - sinon.stub(program, 'getTopicPolicy'); - program.main(['topics', 'get']); - assert(program.getTopicPolicy.calledOnce); - - sinon.stub(program, 'getSubscriptionPolicy'); - program.main(['subscriptions', 'get']); - assert(program.getSubscriptionPolicy.calledOnce); - - sinon.stub(program, 'setTopicPolicy'); - program.main(['topics', 'set']); - assert(program.setTopicPolicy.calledOnce); - - sinon.stub(program, 'setSubscriptionPolicy'); - program.main(['subscriptions', 'set']); - assert(program.setSubscriptionPolicy.calledOnce); - - sinon.stub(program, 'testTopicPermissions'); - program.main(['topics', 'test']); - assert(program.testTopicPermissions.calledOnce); - - sinon.stub(program, 'testSubscriptionPermissions'); - program.main(['subscriptions', 'test']); - assert(program.testSubscriptionPermissions.calledOnce); - - sinon.stub(program, 'printUsage'); - program.main(['--help']); - assert(program.printUsage.calledOnce); - - program.main(['topics', '--help']); - assert(program.printUsage.calledTwice); - - program.main(['subscriptions', '--help']); - assert(program.printUsage.calledThrice); - }); - }); -}); diff --git a/pubsub/test/subscriptions.test.js b/pubsub/test/subscriptions.test.js index edf0800684..982cd13d9b 100644 --- a/pubsub/test/subscriptions.test.js +++ b/pubsub/test/subscriptions.test.js @@ -13,279 +13,50 @@ 'use strict'; -var proxyquire = require('proxyquire').noCallThru(); -var topicName = 'foo'; -var subscriptionName = 'bar'; - -function getSample () { - var apiResponseMock = {}; - var messagesMock = [ - { - data: 'Hello World!' - } - ]; - 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), - getSubscriptions: sinon.stub().callsArgWith(0, null, subscriptionsMock) - }; - var PubSubMock = sinon.stub().returns(pubsubMock); - return { - program: proxyquire('../subscriptions', { +const proxyquire = require('proxyquire').noCallThru(); + +describe(`pubsub:subscriptions`, () => { + it(`should handle errors`, () => { + const topicName = `foo`; + const subscriptionName = `bar`; + const error = new Error(`error`); + const callback = sinon.spy(); + const subscriptionMock = { + delete: sinon.stub().yields(error), + getMetadata: sinon.stub().yields(error), + pull: sinon.stub().yields(error), + iam: { + getPolicy: sinon.stub().yields(error), + setPolicy: sinon.stub().yields(error), + testPermissions: sinon.stub().yields(error) + } + }; + const topicMock = { + subscribe: sinon.stub().yields(error), + getSubscriptions: sinon.stub().yields(error) + }; + const pubsubMock = { + topic: sinon.stub().returns(topicMock), + subscription: sinon.stub().returns(subscriptionMock), + getSubscriptions: sinon.stub().yields(error) + }; + const PubSubMock = sinon.stub().returns(pubsubMock); + const program = proxyquire(`../subscriptions`, { '@google-cloud/pubsub': PubSubMock - }), - mocks: { - PubSub: PubSubMock, - pubsub: pubsubMock, - topic: topicMock, - subscription: subscriptionMock, - subscriptions: subscriptionsMock, - messages: messagesMock, - apiResponse: apiResponseMock, - metadata: metadataMock - } - }; -} - -describe('pubsub:subscriptions', function () { - describe('createSubscription', function () { - it('should create a subscription', function () { - var sample = getSample(); - var callback = sinon.stub(); - - sample.program.createSubscription(topicName, subscriptionName, callback); - - 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 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(topicName, subscriptionName, callback); - - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message === 'error'); - }); - }); - - describe('deleteSubscription', function () { - it('should delete a subscription', function () { - var sample = getSample(); - var callback = sinon.stub(); - - sample.program.deleteSubscription(subscriptionName, callback); - - 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.subscription.delete.callsArgWith(0, error); - - sample.program.deleteSubscription(subscriptionName, callback); - - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message === 'error'); - }); - }); - - describe('getSubscriptionMetadata', function () { - it('should get the metadata for a subscription', function () { - var sample = getSample(); - var callback = sinon.stub(); - - sample.program.getSubscriptionMetadata(subscriptionName, callback); - - assert.ifError(callback.firstCall.args[0]); - assert.strictEqual(callback.firstCall.args[1], sample.mocks.metadata); - assert(console.log.calledWith('Got metadata for subscription: %s', subscriptionName)); - }); - - it('should handle error', function () { - var sample = getSample(); - var error = new Error('error'); - var callback = sinon.stub(); - sample.mocks.subscription.getMetadata.callsArgWith(0, error); - - sample.program.getSubscriptionMetadata(subscriptionName, callback); - - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message === 'error'); }); - }); - - describe('listSubscriptions', function () { - it('should list all subscriptions of a topic', function () { - var sample = getSample(); - var callback = sinon.stub(); - - 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 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.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); + program.createSubscription(topicName, subscriptionName, callback); + program.createPushSubscription(topicName, subscriptionName, callback); + program.deleteSubscription(subscriptionName, callback); + program.getSubscriptionMetadata(subscriptionName, callback); + program.listSubscriptions(callback); + program.listTopicSubscriptions(topicName, callback); + program.pullMessages(subscriptionName, callback); + program.getSubscriptionPolicy(subscriptionName, callback); + program.setSubscriptionPolicy(subscriptionName, callback); + program.testSubscriptionPermissions(subscriptionName, callback); - assert.ifError(callback.firstCall.args[0]); - assert.strictEqual(callback.firstCall.args[1], sample.mocks.subscriptions); - 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(0, error); - - sample.program.listAllSubscriptions(callback); - - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message === 'error'); - assert.equal(callback.firstCall.args[1], undefined); - }); - }); - - describe('pullMessages', function () { - it('should pull messages', function () { - var sample = getSample(); - var callback = sinon.stub(); - - sample.program.pullMessages(subscriptionName, callback); - - assert.ifError(callback.firstCall.args[0]); - assert.strictEqual(callback.firstCall.args[1], sample.mocks.messages); - 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 handle pull error', function () { - var sample = getSample(); - var error = new Error('error'); - var callback = sinon.stub(); - sample.mocks.subscription.pull.callsArgWith(0, error); - - sample.program.pullMessages(subscriptionName, callback); - - assert(callback.firstCall.args[0]); - 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'); - var callback = sinon.stub(); - sample.mocks.subscription.ack.callsArgWith(1, error); - - sample.program.pullMessages(subscriptionName, callback); - - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message === 'error'); - }); - }); - - describe('main', function () { - it('should call createSubscription', function () { - var program = getSample().program; - - sinon.stub(program, 'createSubscription'); - program.main(['create', topicName, subscriptionName]); - assert.equal(program.createSubscription.calledOnce, true); - assert.deepEqual(program.createSubscription.firstCall.args.slice(0, -1), [topicName, subscriptionName]); - }); - - it('should call deleteSubscription', function () { - var program = getSample().program; - - sinon.stub(program, 'deleteSubscription'); - program.main(['delete', subscriptionName]); - assert.equal(program.deleteSubscription.calledOnce, true); - assert.deepEqual(program.deleteSubscription.firstCall.args.slice(0, -1), [subscriptionName]); - }); - - it('should call listSubscriptions', function () { - var program = getSample().program; - sinon.stub(program, 'listSubscriptions'); - - program.main(['list', topicName]); - assert.equal(program.listSubscriptions.calledOnce, true); - assert.deepEqual(program.listSubscriptions.firstCall.args.slice(0, -1), [topicName]); - }); - - it('should call listAllSubscriptions', function () { - var program = getSample().program; - sinon.stub(program, 'listAllSubscriptions'); - - program.main(['list']); - assert.equal(program.listAllSubscriptions.calledOnce, true); - assert.deepEqual(program.listAllSubscriptions.firstCall.args.slice(0, -1), []); - }); - - it('should call pullMessages', function () { - var program = getSample().program; - - sinon.stub(program, 'pullMessages'); - program.main(['pull', subscriptionName]); - 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]); - }); + assert.equal(callback.callCount, 10); + assert.equal(callback.alwaysCalledWithExactly(error), true); }); }); diff --git a/pubsub/test/topics.test.js b/pubsub/test/topics.test.js index 319a63aae6..7e21d79dc5 100644 --- a/pubsub/test/topics.test.js +++ b/pubsub/test/topics.test.js @@ -13,193 +13,41 @@ 'use strict'; -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], apiResponseMock), - delete: sinon.stub().callsArgWith(0, null, apiResponseMock) - }; - topicMock.get.callsArgWith(1, null, topicMock, apiResponseMock); - var topicsMock = [ - { - name: topicName - } - ]; - - var pubsubMock = { - topic: sinon.stub().returns(topicMock), - getTopics: sinon.stub().callsArgWith(0, null, topicsMock) - }; - var PubSubMock = sinon.stub().returns(pubsubMock); - return { - program: proxyquire('../topics', { +const proxyquire = require(`proxyquire`).noCallThru(); + +describe(`pubsub:topics`, () => { + it(`should handle errors`, () => { + const topicName = `foo`; + const error = new Error(`error`); + const callback = sinon.spy(); + const topicMock = { + publish: sinon.stub().yields(error), + delete: sinon.stub().yields(error), + iam: { + getPolicy: sinon.stub().yields(error), + setPolicy: sinon.stub().yields(error), + testPermissions: sinon.stub().yields(error) + } + }; + const pubsubMock = { + topic: sinon.stub().returns(topicMock), + getTopics: sinon.stub().yields(error), + createTopic: sinon.stub().yields(error) + }; + const PubSubMock = sinon.stub().returns(pubsubMock); + const program = proxyquire(`../topics`, { '@google-cloud/pubsub': PubSubMock - }), - mocks: { - PubSub: PubSubMock, - pubsub: pubsubMock, - topics: topicsMock, - topic: topicMock, - apiResponse: apiResponseMock - } - }; -} - -describe('pubsub:topics', function () { - describe('createTopic', function () { - it('should create a topic', function () { - var sample = getSample(); - var callback = sinon.stub(); - - sample.program.createTopic(topicName, callback); - - 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 handle error', function () { - var sample = getSample(); - var error = new Error('error'); - var callback = sinon.stub(); - sample.mocks.topic.get.callsArgWith(1, error); - - sample.program.createTopic(topicName, callback); - - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message === 'error'); - }); - }); - - describe('deleteTopic', function () { - it('should delete a topic', function () { - var sample = getSample(); - var callback = sinon.stub(); - - 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 handle error', function () { - var sample = getSample(); - var error = new Error('error'); - var callback = sinon.stub(); - sample.mocks.topic.delete.callsArgWith(0, error); - - sample.program.deleteTopic(topicName, callback); - - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message === 'error'); - }); - }); - - describe('publish', function () { - it('should publish a message', function () { - var sample = getSample(); - var callback = sinon.stub(); - - sample.program.publishMessage(topicName, message, callback); - - assert.ifError(callback.firstCall.args[0]); - assert.deepEqual(callback.firstCall.args[1], [1]); - assert.strictEqual(callback.firstCall.args[2], sample.mocks.apiResponse); - assert(console.log.calledWith('Published %d message(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.topic.publish.callsArgWith(1, error); - - sample.program.publishMessage(topicName, message, callback); - - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message === 'error'); - assert.equal(callback.firstCall.args[1], undefined); - }); - }); - - describe('list', function () { - it('should list topics', function () { - var sample = getSample(); - var callback = sinon.stub(); - - sample.program.listTopics(callback); - - assert.ifError(callback.firstCall.args[0]); - 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'); - var callback = sinon.stub(); - sample.mocks.pubsub.getTopics.callsArgWith(0, error); + program.createTopic(topicName, callback); + program.deleteTopic(topicName, callback); + program.publishMessage(topicName, {}, callback); + program.listTopics(callback); + program.getTopicPolicy(topicName, callback); + program.setTopicPolicy(topicName, callback); + program.testTopicPermissions(topicName, callback); - sample.program.listTopics(callback); - - assert(callback.firstCall.args[0]); - assert(callback.firstCall.args[0].message === 'error'); - assert.equal(callback.firstCall.args[1], undefined); - }); - }); - - describe('main', function () { - it('should call createTopic', function () { - var program = getSample().program; - - sinon.stub(program, 'createTopic'); - program.main(['create', topicName]); - assert.equal(program.createTopic.calledOnce, true); - assert.deepEqual(program.createTopic.firstCall.args.slice(0, -1), [topicName]); - }); - - it('should call deleteTopic', function () { - var program = getSample().program; - - sinon.stub(program, 'deleteTopic'); - program.main(['delete', topicName]); - assert.equal(program.deleteTopic.calledOnce, true); - assert.deepEqual(program.deleteTopic.firstCall.args.slice(0, -1), [topicName]); - }); - - it('should call listTopics', function () { - var program = getSample().program; - - sinon.stub(program, 'listTopics'); - program.main(['list']); - assert.equal(program.listTopics.calledOnce, true); - assert.deepEqual(program.listTopics.firstCall.args.slice(0, -1), []); - }); - - it('should call publishMessage', function () { - var program = getSample().program; - - sinon.stub(program, 'publishMessage'); - program.main(['publish', topicName, '{}']); - assert.equal(program.publishMessage.calledOnce, true); - 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!']); - }); + assert.equal(callback.callCount, 7); + assert.equal(callback.alwaysCalledWithExactly(error), true); }); }); diff --git a/pubsub/topics.js b/pubsub/topics.js index c51c2536f0..6380ca7ccd 100644 --- a/pubsub/topics.js +++ b/pubsub/topics.js @@ -1,68 +1,86 @@ -// Copyright 2016, Google, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/** + * Copyright 2016, Google, Inc. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This application demonstrates how to perform basic operations on topics with + * the Google Cloud Pub/Sub API. + * + * For more information, see the README.md under /pubsub and the documentation + * at https://cloud.google.com/pubsub/docs. + */ 'use strict'; -// [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] +const pubsubClient = require(`@google-cloud/pubsub`)(); +// [START pubsub_list_topics] +function listTopics (callback) { + // Lists all topics in the current project + pubsubClient.getTopics((err, topics) => { + if (err) { + callback(err); + return; + } + + console.log(`Topics:`); + topics.forEach((topic) => console.log(topic.name)); + callback(); + }); +} +// [END pubsub_list_topics] + +// [START pubsub_create_topic] function createTopic (topicName, callback) { - var pubsub = PubSub(); - var topic = pubsub.topic(topicName); - - // 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, apiResponse) { + // Creates a new topic, e.g. "my-new-topic" + pubsubClient.createTopic(topicName, (err, topic) => { if (err) { - return callback(err); + callback(err); + return; } - console.log('Created topic: %s', topicName); - return callback(null, topic, apiResponse); + console.log(`Topic ${topic.name} created.`); + callback(); }); } +// [END pubsub_create_topic] +// [START pubsub_delete_topic] function deleteTopic (topicName, callback) { - var pubsub = PubSub(); - var topic = pubsub.topic(topicName); + // References an existing topic, e.g. "my-topic" + const topic = pubsubClient.topic(topicName); - // Delete the topic - // See https://googlecloudplatform.github.io/google-cloud-node/#/docs/pubsub/latest/pubsub/topic?method=delete - topic.delete(function (err, apiResponse) { + // Deletes the topic + topic.delete((err) => { if (err) { - return callback(err); + callback(err); + return; } - // Deleted the topic - console.log('Deleted topic: %s', topicName); - return callback(null, apiResponse); + console.log(`Topic ${topic.name} deleted.`); + callback(); }); } +// [END pubsub_delete_topic] -function publishMessage (topicName, message, callback) { - var pubsub = PubSub(); - var topic = pubsub.topic(topicName); +// [START pubsub_publish_message] +function publishMessage (topicName, data, callback) { + // References an existing topic, e.g. "my-topic" + const topic = pubsubClient.topic(topicName); /** - * 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 + * 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 @@ -70,40 +88,113 @@ function publishMessage (topicName, message, callback) { * 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) { + const message = { + data: data + }; + + // Publishes the message + topic.publish(message, (err, messageIds) => { if (err) { - return callback(err); + callback(err); + return; } - console.log('Published %d message(s)!', messageIds.length); - return callback(null, messageIds, apiResponse); + console.log(`Message ${messageIds[0]} published.`); + callback(); }); } +// [END pubsub_publish_message] -function listTopics (callback) { - var pubsub = PubSub(); +// [START pubsub_get_topic_policy] +function getTopicPolicy (topicName, callback) { + // References an existing topic, e.g. "my-topic" + const topic = pubsubClient.topic(topicName); + + // Retrieves the IAM policy for the topic + topic.iam.getPolicy((err, policy) => { + if (err) { + callback(err); + return; + } + + console.log(`Policy for topic: %j.`, policy.bindings); + callback(); + }); +} +// [END pubsub_get_topic_policy] + +// [START pubsub_set_topic_policy] +function setTopicPolicy (topicName, callback) { + // References an existing topic, e.g. "my-topic" + const topic = pubsubClient.topic(topicName); + + // The new IAM policy + const newPolicy = { + bindings: [ + { + // Add a group as editors + role: `roles/pubsub.editor`, + members: [`group:cloud-logs@google.com`] + }, + { + // Add all users as viewers + role: `roles/pubsub.viewer`, + members: [`allUsers`] + } + ] + }; + + // Updates the IAM policy for the topic + topic.iam.setPolicy(newPolicy, (err, updatedPolicy) => { + if (err) { + callback(err); + return; + } + + console.log(`Updated policy for topic: %j`, updatedPolicy.bindings); + callback(); + }); +} +// [END pubsub_set_topic_policy] + +// [START pubsub_test_topic_permissions] +function testTopicPermissions (topicName, callback) { + // References an existing topic, e.g. "my-topic" + const topic = pubsubClient.topic(topicName); - // See https://googlecloudplatform.github.io/google-cloud-node/#/docs/pubsub/latest/pubsub?method=getTopics - pubsub.getTopics(function (err, topics) { + const permissionsToTest = [ + `pubsub.topics.attachSubscription`, + `pubsub.topics.publish`, + `pubsub.topics.update` + ]; + + // Tests the IAM policy for the specified topic + topic.iam.testPermissions(permissionsToTest, (err, permissions) => { if (err) { - return callback(err); + callback(err); + return; } - console.log('Found %d topics!', topics.length); - return callback(null, topics); + console.log(`Tested permissions for topic: %j`, permissions); + + callback(); }); } +// [END pubsub_test_topic_permissions] // The command-line program -var cli = require('yargs'); -var makeHandler = require('../utils').makeHandler; +const cli = require(`yargs`); +const makeHandler = require(`../utils`).makeHandler; -var program = module.exports = { +const program = module.exports = { + listTopics: listTopics, createTopic: createTopic, deleteTopic: deleteTopic, publishMessage: publishMessage, - listTopics: listTopics, - main: function (args) { + getTopicPolicy: getTopicPolicy, + setTopicPolicy: setTopicPolicy, + testTopicPermissions: testTopicPermissions, + main: (args) => { // Run the command-line program cli.help().strict().parse(args).argv; } @@ -111,30 +202,43 @@ var program = module.exports = { cli .demand(1) - .command('create ', 'Creates a new topic.', {}, function (options) { - program.createTopic(options.topicName, makeHandler(true, 'id')); + .command(`list`, `Lists all topics in the current project.`, {}, (options) => { + program.listTopics(makeHandler(false)); }) - .command('list', 'Lists topics.', {}, function (options) { - program.listTopics(makeHandler(true, 'id')); + .command(`create `, `Creates a new topic.`, {}, (options) => { + program.createTopic(options.topicName, makeHandler(false)); + }) + .command(`delete `, `Deletes the a topic.`, {}, (options) => { + program.deleteTopic(options.topicName, makeHandler(false)); }) - .command('publish ', 'Publish a message to the specified topic.', {}, function (options) { + .command(`publish `, `Publishes a message.`, {}, (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!'); + // Ignore error } + program.publishMessage(options.topicName, options.message, makeHandler(false)); }) - .command('delete ', 'Deletes the specified topic.', {}, function (options) { - program.deleteTopic(options.topicName, makeHandler(false)); + .command(`get-policy `, `Gets the IAM policy for a topic.`, {}, (options) => { + program.getTopicPolicy(options.topicName, makeHandler(false)); + }) + .command(`set-policy `, `Sets the IAM policy for a topic.`, {}, (options) => { + program.setTopicPolicy(options.topicName, makeHandler(false)); + }) + .command(`test-permissions `, `Tests the permissions for a topic.`, {}, (options) => { + program.testTopicPermissions(options.topicName, makeHandler(false)); }) - .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".') + .example(`node $0 list`, `Lists all topics in the current project.`) + .example(`node $0 create greetings`, `Creates a new topic named "greetings".`) + .example(`node $0 delete greetings`, `Deletes a topic named "greetings".`) + .example(`node $0 publish greetings "Hello, world!"`, `Publishes a simple message.`) + .example(`node $0 publish greetings \`{"data":"Hello, world!"}\``, `Publishes a JSON message.`) + .example(`node $0 get-policy greetings`, `Gets the IAM policy for a topic named "greetings".`) + .example(`node $0 set-policy greetings`, `Sets the IAM policy for a topic named "greetings".`) + .example(`node $0 test-permissions greetings`, `Tests the permissions for a topic named "greetings".`) .wrap(120) .recommendCommands() - .epilogue('For more information, see https://cloud.google.com/pubsub/docs'); + .epilogue(`For more information, see https://cloud.google.com/pubsub/docs`); if (module === require.main) { program.main(process.argv.slice(2)); diff --git a/utils/index.js b/utils/index.js index 40abf17fc2..d272823de1 100644 --- a/utils/index.js +++ b/utils/index.js @@ -13,6 +13,12 @@ 'use strict'; +var execSync = require('child_process').execSync; + +exports.run = function (cmd, cwd) { + return execSync(cmd, { cwd: cwd }).toString().trim(); +}; + exports.pick = function (obj, field) { if (Array.isArray(field)) { var _obj = {};