diff --git a/package.json b/package.json index 9e003f0f8..6f6033294 100644 --- a/package.json +++ b/package.json @@ -33,10 +33,8 @@ "scripts": { "presystem-test": "npm run compile", "system-test": "mocha build/system-test --timeout 600000", - "cover": "nyc --reporter=lcov mocha build/test && nyc report", "samples-test": "cd samples/ && npm link ../ && npm test && cd ../", - "test-no-cover": "mocha build/test", - "test": "npm run cover", + "test": "nyc mocha build/test", "lint": "eslint '**/*.js' && gts check", "docs": "jsdoc -c .jsdoc.js", "fix": "eslint --fix '**/*.js' && gts fix", diff --git a/samples/.eslintrc.yml b/samples/.eslintrc.yml index bb975e012..0aa37ac63 100644 --- a/samples/.eslintrc.yml +++ b/samples/.eslintrc.yml @@ -1,6 +1,4 @@ --- -env: - mocha: true rules: no-console: off node/no-missing-require: off diff --git a/samples/package.json b/samples/package.json index 7e02b58b6..0ee386321 100644 --- a/samples/package.json +++ b/samples/package.json @@ -1,31 +1,26 @@ { "name": "nodejs-docs-samples-pubsub", - "version": "0.0.1", + "files": [ + "*.js" + ], "private": true, "license": "Apache-2.0", "author": "Google Inc.", - "repository": { - "type": "git", - "url": "https://github.com/googleapis/nodejs-pubsub.git" - }, + "repository": "googleapis/nodejs-pubsub", "engines": { "node": ">=8" }, "scripts": { - "mocha": "mocha system-test/*.js --timeout 600000", - "cover": "nyc --reporter=lcov --cache mocha system-test/*.test.js --timeout 600000 && nyc report", - "test": "npm run cover" + "test": "mocha system-test --timeout 600000" }, "dependencies": { "@google-cloud/pubsub": "^0.22.2", "yargs": "^12.0.0" }, "devDependencies": { + "chai": "^4.2.0", + "execa": "^1.0.0", "mocha": "^5.2.0", - "@google-cloud/nodejs-repo-tools": "^3.0.0", - "nyc": "^13.0.0", - "proxyquire": "^2.0.0", - "sinon": "^7.0.0", "uuid": "^3.1.0" } } diff --git a/samples/quickstart.js b/samples/quickstart.js old mode 100755 new mode 100644 index 160a003c7..9d23d61b0 --- a/samples/quickstart.js +++ b/samples/quickstart.js @@ -19,21 +19,18 @@ // Imports the Google Cloud client library const {PubSub} = require('@google-cloud/pubsub'); -async function quickstart() { - // Your Google Cloud Platform project ID - const projectId = process.env.GCLOUD_PROJECT || 'YOUR_PROJECT_ID'; - +async function quickstart( + projectId = 'your-project-id', // Your Google Cloud Platform project ID + topicName = 'my-topic' // Name for the new topic to create +) { // Instantiates a client - const pubsubClient = new PubSub({ - projectId: projectId, - }); - - // The name for the new topic - const topicName = 'my-topic'; + const pubsub = new PubSub({projectId}); // Creates the new topic - const [topic] = await pubsubClient.createTopic(topicName); + const [topic] = await pubsub.createTopic(topicName); console.log(`Topic ${topic.name} created.`); } -quickstart().catch(console.error); // [END pubsub_quickstart_create_topic] + +const args = process.argv.slice(2); +quickstart(...args).catch(console.error); diff --git a/samples/subscriptions.js b/samples/subscriptions.js old mode 100755 new mode 100644 diff --git a/samples/system-test/.eslintrc.yml b/samples/system-test/.eslintrc.yml index 08f62dcff..6db2a46c5 100644 --- a/samples/system-test/.eslintrc.yml +++ b/samples/system-test/.eslintrc.yml @@ -1,8 +1,3 @@ --- env: mocha: true -rules: - node/no-unpublished-require: off - node/no-unsupported-features: off - no-empty: off - no-unused-vars: error diff --git a/samples/system-test/quickstart.test.js b/samples/system-test/quickstart.test.js index 11bd1539c..e446036f8 100644 --- a/samples/system-test/quickstart.test.js +++ b/samples/system-test/quickstart.test.js @@ -15,51 +15,24 @@ 'use strict'; -const proxyquire = require('proxyquire').noPreserveCache(); -const {PubSub} = proxyquire('@google-cloud/pubsub', {}); -const sinon = require('sinon'); -const assert = require('assert'); -const tools = require('@google-cloud/nodejs-repo-tools'); +const {PubSub} = require('@google-cloud/pubsub'); +const {assert} = require('chai'); +const execa = require('execa'); const uuid = require('uuid'); -const projectId = process.env.GCLOUD_PROJECT; -const pubsub = new PubSub({projectId}); +describe('quickstart', () => { + const projectId = process.env.GCLOUD_PROJECT; + const pubsub = new PubSub({projectId}); + const topicName = `nodejs-docs-samples-test-${uuid.v4()}`; -const topicName = `nodejs-docs-samples-test-${uuid.v4()}`; -const fullTopicName = `projects/${projectId}/topics/${topicName}`; - -before(tools.stubConsole); -after(async () => { - tools.restoreConsole(); - return await pubsub - .topic(topicName) - .delete() - .catch(() => {}); -}); - -it(`should create a topic`, async () => { - const expectedTopicName = `my-topic`; - const pubsubMock = { - createTopic: _topicName => { - assert.strictEqual(_topicName, expectedTopicName); - return pubsub.createTopic(topicName).then(([topic]) => { - assert.strictEqual(topic.name, fullTopicName); - setTimeout(() => { - try { - assert.strictEqual(console.log.callCount, 1); - assert.deepStrictEqual(console.log.getCall(0).args, [ - `Topic ${topic.name} created.`, - ]); - } catch (err) {} - }, 200); - return [topic]; - }); - }, - }; + after(async () => { + await pubsub.topic(topicName).delete(); + }); - proxyquire(`../quickstart`, { - '@google-cloud/pubsub': { - PubSub: sinon.stub().returns(pubsubMock), - }, + it('should run the quickstart', async () => { + const {stdout} = await execa.shell( + `node quickstart ${projectId} ${topicName}` + ); + assert.match(stdout, /^Topic .* created.$/); }); }); diff --git a/samples/system-test/subscriptions.test.js b/samples/system-test/subscriptions.test.js index 873322b2b..40c486924 100644 --- a/samples/system-test/subscriptions.test.js +++ b/samples/system-test/subscriptions.test.js @@ -15,289 +15,238 @@ 'use strict'; -const path = require(`path`); const {PubSub} = require('@google-cloud/pubsub'); -const assert = require(`assert`); -const tools = require(`@google-cloud/nodejs-repo-tools`); -const uuid = require(`uuid`); - -const projectId = process.env.GCLOUD_PROJECT; -const pubsub = new PubSub({projectId}); - -const cwd = path.join(__dirname, `..`); -const topicNameOne = `nodejs-docs-samples-test-${uuid.v4()}`; -const topicNameTwo = `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 subscriptionNameThree = `nodejs-docs-samples-test-sub-${uuid.v4()}`; -const subscriptionNameFour = `nodejs-docs-samples-test-sub-${uuid.v4()}`; -const fullTopicNameOne = `projects/${projectId}/topics/${topicNameOne}`; -const fullSubscriptionNameOne = `projects/${projectId}/subscriptions/${subscriptionNameOne}`; -const fullSubscriptionNameTwo = `projects/${projectId}/subscriptions/${subscriptionNameTwo}`; -const fullSubscriptionNameFour = `projects/${projectId}/subscriptions/${subscriptionNameFour}`; -const cmd = `node subscriptions.js`; - -before(tools.checkCredentials); -before(async () => { - await Promise.all([ - pubsub.createTopic(topicNameOne), - pubsub.createTopic(topicNameTwo), - ]); -}); - -after(async () => { - try { - await pubsub.subscription(subscriptionNameOne).delete(); - } catch (err) {} // ignore error - try { - await pubsub.subscription(subscriptionNameTwo).delete(); - } catch (err) {} // ignore error - try { - await pubsub.subscription(subscriptionNameThree).delete(); - } catch (err) {} // ignore error - try { - await pubsub.topic(topicNameOne).delete(); - } catch (err) {} // ignore error - try { - await pubsub.topic(topicNameTwo).delete(); - } catch (err) {} // ignore error -}); - -beforeEach(tools.stubConsole); -afterEach(tools.restoreConsole); +const {assert} = require('chai'); +const execa = require('execa'); +const uuid = require('uuid'); + +const exec = async cmd => (await execa.shell(cmd)).stdout; + +describe('subscriptions', () => { + const projectId = process.env.GCLOUD_PROJECT; + const pubsub = new PubSub({projectId}); + + const topicNameOne = `nodejs-docs-samples-test-${uuid.v4()}`; + const topicNameTwo = `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 subscriptionNameThree = `nodejs-docs-samples-test-sub-${uuid.v4()}`; + const subscriptionNameFour = `nodejs-docs-samples-test-sub-${uuid.v4()}`; + const fullTopicNameOne = `projects/${projectId}/topics/${topicNameOne}`; + const fullSubscriptionNameOne = `projects/${projectId}/subscriptions/${subscriptionNameOne}`; + const fullSubscriptionNameTwo = `projects/${projectId}/subscriptions/${subscriptionNameTwo}`; + const fullSubscriptionNameFour = `projects/${projectId}/subscriptions/${subscriptionNameFour}`; + const cmd = `node subscriptions.js`; + + before(async () => { + await Promise.all([ + pubsub.createTopic(topicNameOne), + pubsub.createTopic(topicNameTwo), + ]); + }); -it(`should create a subscription`, async () => { - const output = await tools.runAsync( - `${cmd} create ${topicNameOne} ${subscriptionNameOne}`, - cwd - ); - assert.strictEqual(output, `Subscription ${subscriptionNameOne} created.`); - await tools - .tryTest(async assert => { - const [subscriptions] = await pubsub - .topic(topicNameOne) - .getSubscriptions(); - assert.strictEqual(subscriptions[0].name, fullSubscriptionNameOne); - }) - .start(); -}); + after(async () => { + const rm = obj => obj.delete().catch(console.error); + await rm(pubsub.subscription(subscriptionNameOne)); + await rm(pubsub.subscription(subscriptionNameTwo)); + await rm(pubsub.subscription(subscriptionNameThree)); + await rm(pubsub.topic(topicNameOne)); + await rm(pubsub.topic(topicNameTwo)); + }); -it(`should create a push subscription`, async () => { - const output = await tools.runAsync( - `${cmd} create-push ${topicNameOne} ${subscriptionNameTwo}`, - cwd - ); - assert.strictEqual(output, `Subscription ${subscriptionNameTwo} created.`); - await tools - .tryTest(async assert => { - const [subscriptions] = await pubsub - .topic(topicNameOne) - .getSubscriptions(); - assert(subscriptions.some(s => s.name === fullSubscriptionNameTwo)); - }) - .start(); -}); + it('should create a subscription', async () => { + const output = await exec( + `${cmd} create ${topicNameOne} ${subscriptionNameOne}` + ); + assert.strictEqual(output, `Subscription ${subscriptionNameOne} created.`); + const [subscriptions] = await pubsub.topic(topicNameOne).getSubscriptions(); + assert.strictEqual(subscriptions[0].name, fullSubscriptionNameOne); + }); -it(`should modify the config of an existing push subscription`, async () => { - const output = await tools.runAsync( - `${cmd} modify-config ${topicNameTwo} ${subscriptionNameTwo}`, - cwd - ); - assert.strictEqual( - output, - `Modified push config for subscription ${subscriptionNameTwo}.` - ); -}); + it('should create a push subscription', async () => { + const output = await exec( + `${cmd} create-push ${topicNameOne} ${subscriptionNameTwo}` + ); + assert.strictEqual(output, `Subscription ${subscriptionNameTwo} created.`); + const [subscriptions] = await pubsub.topic(topicNameOne).getSubscriptions(); + assert(subscriptions.some(s => s.name === fullSubscriptionNameTwo)); + }); -it(`should get metadata for a subscription`, async () => { - const output = await tools.runAsync(`${cmd} get ${subscriptionNameOne}`, cwd); - const expected = - `Subscription: ${fullSubscriptionNameOne}` + - `\nTopic: ${fullTopicNameOne}` + - `\nPush config: ` + - `\nAck deadline: 10s`; - assert.strictEqual(output, expected); -}); + it('should modify the config of an existing push subscription', async () => { + const output = await exec( + `${cmd} modify-config ${topicNameTwo} ${subscriptionNameTwo}` + ); + assert.strictEqual( + output, + `Modified push config for subscription ${subscriptionNameTwo}.` + ); + }); -it(`should list all subscriptions`, async () => { - await tools - .tryTest(async assert => { - const output = await tools.runAsync(`${cmd} list`, cwd); - assert(output.includes(`Subscriptions:`)); - assert(output.includes(fullSubscriptionNameOne)); - assert(output.includes(fullSubscriptionNameTwo)); - }) - .start(); -}); + it('should get metadata for a subscription', async () => { + const output = await exec(`${cmd} get ${subscriptionNameOne}`); + const expected = + `Subscription: ${fullSubscriptionNameOne}` + + `\nTopic: ${fullTopicNameOne}` + + `\nPush config: ` + + `\nAck deadline: 10s`; + assert.strictEqual(output, expected); + }); -it(`should list subscriptions for a topic`, async () => { - await tools - .tryTest(async assert => { - const output = await tools.runAsync(`${cmd} list ${topicNameOne}`, cwd); - assert(output.includes(`Subscriptions for ${topicNameOne}:`)); - assert(output.includes(fullSubscriptionNameOne)); - assert(output.includes(fullSubscriptionNameTwo)); - }) - .start(); -}); + it('should list all subscriptions', async () => { + const output = await exec(`${cmd} list`); + assert.match(output, /Subscriptions:/); + assert.match(output, new RegExp(fullSubscriptionNameOne)); + assert.match(output, new RegExp(fullSubscriptionNameTwo)); + }); -it(`should listen for messages`, async () => { - const messageIds = await pubsub - .topic(topicNameOne) - .publisher() - .publish(Buffer.from(`Hello, world!`)); - const output = await tools.runAsync( - `${cmd} listen-messages ${subscriptionNameOne}`, - cwd - ); - assert.strictEqual(output.includes(`Received message ${messageIds}:`), true); -}); + it('should list subscriptions for a topic', async () => { + const output = await exec(`${cmd} list ${topicNameOne}`); + assert.match(output, new RegExp(`Subscriptions for ${topicNameOne}:`)); + assert.match(output, new RegExp(fullSubscriptionNameOne)); + assert.match(output, new RegExp(fullSubscriptionNameTwo)); + }); -it(`should listen for messages synchronously`, async () => { - pubsub - .topic(topicNameOne) - .publisher() - .publish(Buffer.from(`Hello, world!`)); - const output = await tools.runAsync( - `${cmd} sync-pull ${projectId} ${subscriptionNameOne}`, - cwd - ); - assert.strictEqual(output.includes(`Done.`), true); -}); + it('should listen for messages', async () => { + const messageIds = await pubsub + .topic(topicNameOne) + .publisher() + .publish(Buffer.from(`Hello, world!`)); + const output = await exec(`${cmd} listen-messages ${subscriptionNameOne}`); + assert.match(output, new RegExp(`Received message ${messageIds}:`)); + }); -it(`should listen for ordered messages`, async () => { - const timeout = 5; - const subscriptions = require('../subscriptions'); - const expected = `Hello, world!`; - const expectedBuffer = Buffer.from(expected); - const publishedMessageIds = []; - const publisherTwo = pubsub.topic(topicNameTwo).publisher(); + it('should listen for messages synchronously', async () => { + pubsub + .topic(topicNameOne) + .publisher() + .publish(Buffer.from(`Hello, world!`)); + const output = await exec( + `${cmd} sync-pull ${projectId} ${subscriptionNameOne}` + ); + assert.match(output, /Done./); + }); - await pubsub - .topic(topicNameTwo) - .subscription(subscriptionNameThree) - .get({autoCreate: true}); - let [result] = await publisherTwo.publish(expectedBuffer, {counterId: '3'}); - publishedMessageIds.push(result); - await subscriptions.listenForOrderedMessages(subscriptionNameThree, timeout); - assert.strictEqual(console.log.callCount, 0); + it('should listen for ordered messages', async () => { + const timeout = 5; + const subscriptions = require('../subscriptions'); + const spy = {calls: []}; + const log = console.log; + console.log = (...args) => { + spy.calls.push(args); + log(...args); + }; + const expected = `Hello, world!`; + const expectedBuffer = Buffer.from(expected); + const publishedMessageIds = []; + const publisherTwo = pubsub.topic(topicNameTwo).publisher(); + + await pubsub + .topic(topicNameTwo) + .subscription(subscriptionNameThree) + .get({autoCreate: true}); + let result = await publisherTwo.publish(expectedBuffer, {counterId: '3'}); + publishedMessageIds.push(result); + await subscriptions.listenForOrderedMessages( + subscriptionNameThree, + timeout + ); + assert.strictEqual(spy.calls.length, 0); - result = await publisherTwo.publish(expectedBuffer, {counterId: '1'}); - publishedMessageIds.push(result); - await subscriptions.listenForOrderedMessages(subscriptionNameThree, timeout); - assert.strictEqual(console.log.callCount, 1); - assert.deepStrictEqual(console.log.firstCall.args, [ - `* %d %j %j`, - publishedMessageIds[1], - expected, - {counterId: '1'}, - ]); + result = await publisherTwo.publish(expectedBuffer, {counterId: '1'}); + publishedMessageIds.push(result); + await subscriptions.listenForOrderedMessages( + subscriptionNameThree, + timeout + ); + assert.strictEqual(spy.calls.length, 1); + assert.deepStrictEqual(spy.calls[0], [ + `* %d %j %j`, + publishedMessageIds[1], + expected, + {counterId: '1'}, + ]); - [result] = await publisherTwo.publish(expectedBuffer, {counterId: '1'}); - [result] = await publisherTwo.publish(expectedBuffer, {counterId: '2'}); - publishedMessageIds.push(result); - await tools.tryTest(async assert => { + result = await publisherTwo.publish(expectedBuffer, {counterId: '1'}); + result = await publisherTwo.publish(expectedBuffer, {counterId: '2'}); + publishedMessageIds.push(result); await subscriptions.listenForOrderedMessages( subscriptionNameThree, timeout ); - assert.strictEqual(console.log.callCount, 3); - assert.deepStrictEqual(console.log.secondCall.args, [ + assert.strictEqual(spy.calls.length, 3); + assert.deepStrictEqual(spy.calls[1], [ `* %d %j %j`, publishedMessageIds[2], expected, {counterId: '2'}, ]); - assert.deepStrictEqual(console.log.thirdCall.args, [ + assert.deepStrictEqual(spy.calls[2], [ `* %d %j %j`, publishedMessageIds[0], expected, {counterId: '3'}, ]); + console.log = log; }); -}); -it(`should listen for error messages`, async () => { - const output = await tools.runAsyncWithIO( - `${cmd} listen-errors nonexistent-subscription`, - cwd - ); - assert.strictEqual(output.stderr.includes(`Resource not found`), true); -}); + it('should listen for error messages', async () => { + const {stderr} = await execa.shell( + `${cmd} listen-errors nonexistent-subscription` + ); + assert.match(stderr, /Resource not found/); + }); -it(`should set the IAM policy for a subscription`, async () => { - await tools.runAsync(`${cmd} set-policy ${subscriptionNameOne}`, cwd); - const results = await pubsub - .subscription(subscriptionNameOne) - .iam.getPolicy(); - const policy = results[0]; - assert.deepStrictEqual(policy.bindings, [ - { - role: `roles/pubsub.editor`, - members: [`group:cloud-logs@google.com`], - }, - { - role: `roles/pubsub.viewer`, - members: [`allUsers`], - }, - ]); -}); + it('should set the IAM policy for a subscription', async () => { + await exec(`${cmd} set-policy ${subscriptionNameOne}`); + const results = await pubsub + .subscription(subscriptionNameOne) + .iam.getPolicy(); + const policy = results[0]; + assert.deepStrictEqual(policy.bindings, [ + { + role: `roles/pubsub.editor`, + members: [`group:cloud-logs@google.com`], + }, + { + role: `roles/pubsub.viewer`, + members: [`allUsers`], + }, + ]); + }); -it(`should get the IAM policy for a subscription`, async () => { - const results = await pubsub - .subscription(subscriptionNameOne) - .iam.getPolicy(); - const output = await tools.runAsync( - `${cmd} get-policy ${subscriptionNameOne}`, - cwd - ); - assert.strictEqual( - output, - `Policy for subscription: ${JSON.stringify(results[0].bindings)}.` - ); -}); + it('should get the IAM policy for a subscription', async () => { + const results = await pubsub + .subscription(subscriptionNameOne) + .iam.getPolicy(); + const output = await exec(`${cmd} get-policy ${subscriptionNameOne}`); + assert.strictEqual( + output, + `Policy for subscription: ${JSON.stringify(results[0].bindings)}.` + ); + }); -it(`should test permissions for a subscription`, async () => { - const output = await tools.runAsync( - `${cmd} test-permissions ${subscriptionNameOne}`, - cwd - ); - assert.strictEqual( - output.includes(`Tested permissions for subscription`), - true - ); -}); + it('should test permissions for a subscription', async () => { + const output = await exec(`${cmd} test-permissions ${subscriptionNameOne}`); + assert.match(output, /Tested permissions for subscription/); + }); -it(`should delete a subscription`, async () => { - const output = await tools.runAsync( - `${cmd} delete ${subscriptionNameOne}`, - cwd - ); - assert.strictEqual(output, `Subscription ${subscriptionNameOne} deleted.`); - await tools - .tryTest(async assert => { - const [subscriptions] = await pubsub.getSubscriptions(); - assert.ok(subscriptions); - assert(subscriptions.every(s => s.name !== fullSubscriptionNameOne)); - }) - .start(); -}); + it('should delete a subscription', async () => { + const output = await exec(`${cmd} delete ${subscriptionNameOne}`); + assert.strictEqual(output, `Subscription ${subscriptionNameOne} deleted.`); + const [subscriptions] = await pubsub.getSubscriptions(); + assert.ok(subscriptions); + assert(subscriptions.every(s => s.name !== fullSubscriptionNameOne)); + }); -it(`should create a subscription with flow control`, async () => { - const output = await tools.runAsync( - `${cmd} create-flow ${topicNameTwo} ${subscriptionNameFour} -m 5 -b 1024`, - cwd - ); - assert.strictEqual( - output, - `Subscription ${fullSubscriptionNameFour} created with a maximum of 5 unprocessed messages.` - ); - await tools - .tryTest(async assert => { - const [subscriptions] = await pubsub - .topic(topicNameTwo) - .getSubscriptions(); - assert(subscriptions.some(s => s.name === fullSubscriptionNameFour)); - }) - .start(); + it('should create a subscription with flow control', async () => { + const output = await exec( + `${cmd} create-flow ${topicNameTwo} ${subscriptionNameFour} -m 5 -b 1024` + ); + assert.strictEqual( + output, + `Subscription ${fullSubscriptionNameFour} created with a maximum of 5 unprocessed messages.` + ); + const [subscriptions] = await pubsub.topic(topicNameTwo).getSubscriptions(); + assert(subscriptions.some(s => s.name === fullSubscriptionNameFour)); + }); }); diff --git a/samples/system-test/topics.test.js b/samples/system-test/topics.test.js index 8649659f9..32549c63b 100644 --- a/samples/system-test/topics.test.js +++ b/samples/system-test/topics.test.js @@ -15,246 +15,211 @@ 'use strict'; -const path = require(`path`); const {PubSub} = require('@google-cloud/pubsub'); -const assert = require(`assert`); -const tools = require(`@google-cloud/nodejs-repo-tools`); -const uuid = require(`uuid`); - -const projectId = process.env.GCLOUD_PROJECT; -const pubsub = new PubSub({projectId}); - -const cwd = path.join(__dirname, `..`); -const topicNameOne = `nodejs-docs-samples-test-${uuid.v4()}`; -const topicNameTwo = `nodejs-docs-samples-test-${uuid.v4()}`; -const subscriptionNameOne = `nodejs-docs-samples-test-${uuid.v4()}`; -const subscriptionNameTwo = `nodejs-docs-samples-test-${uuid.v4()}`; -const subscriptionNameThree = `nodejs-docs-samples-test-${uuid.v4()}`; -const subscriptionNameFour = `nodejs-docs-samples-test-${uuid.v4()}`; -const fullTopicNameOne = `projects/${projectId}/topics/${topicNameOne}`; -const expectedMessage = {data: `Hello, world!`}; -const cmd = `node topics.js`; - -before(tools.checkCredentials); -before(async () => { - try { - await pubsub.createTopic(topicNameTwo); - } catch (err) {} // ignore error -}); - -after(async () => { - try { - await pubsub.subscription(subscriptionNameOne).delete(); - } catch (err) {} // ignore error - try { - await pubsub.topic(topicNameOne).delete(); - } catch (err) {} // ignore error - try { - await pubsub.subscription(subscriptionNameTwo).delete(); - } catch (err) {} // ignore error - try { - await pubsub.subscription(subscriptionNameThree).delete(); - } catch (err) {} // ignore error - try { - await pubsub.subscription(subscriptionNameFour).delete(); - } catch (err) {} // ignore error - try { - await pubsub.topic(topicNameTwo).delete(); - } catch (err) {} // ignore error -}); - -// Helper function to pull one message -const _pullOneMessage = (subscriptionObj, timeout) => { - timeout = timeout || 10000; // 10 second timeout by default - - let message; - return new Promise((resolve, reject) => { - // First message received; ack it + resolve promise - const messageHandler = received => { - received.ack(); - message = received; - return resolve(messageHandler); - }; - - // Listen for new messages - subscriptionObj.on(`message`, messageHandler); - - // Timeout appropriately - setTimeout(() => { - return reject(new Error(`_pullOneMessage timed out`)); - }, timeout); - }).then(messageHandler => { - subscriptionObj.removeListener('message', messageHandler); - return Promise.resolve(message); +const {assert} = require('chai'); +const execa = require('execa'); +const uuid = require('uuid'); + +describe('topics', () => { + const exec = async cmd => (await execa.shell(cmd)).stdout; + const projectId = process.env.GCLOUD_PROJECT; + const pubsub = new PubSub({projectId}); + const topicNameOne = `nodejs-docs-samples-test-${uuid.v4()}`; + const topicNameTwo = `nodejs-docs-samples-test-${uuid.v4()}`; + const subscriptionNameOne = `nodejs-docs-samples-test-${uuid.v4()}`; + const subscriptionNameTwo = `nodejs-docs-samples-test-${uuid.v4()}`; + const subscriptionNameThree = `nodejs-docs-samples-test-${uuid.v4()}`; + const subscriptionNameFour = `nodejs-docs-samples-test-${uuid.v4()}`; + const fullTopicNameOne = `projects/${projectId}/topics/${topicNameOne}`; + const expectedMessage = {data: 'Hello, world!'}; + const cmd = 'node topics.js'; + + before(async () => { + await pubsub.createTopic(topicNameTwo).catch(console.error); }); -}; -it(`should create a topic`, async () => { - const output = await tools.runAsync(`${cmd} create ${topicNameOne}`, cwd); - assert.strictEqual(output, `Topic ${topicNameOne} created.`); - await tools - .tryTest(async assert => { - const [topics] = await pubsub.getTopics(); - assert(topics.some(t => t.name === fullTopicNameOne)); - }) - .start(); -}); - -it(`should list topics`, async () => { - await tools - .tryTest(async () => { - const output = await tools.runAsync(`${cmd} list`, cwd); - assert.strictEqual(output.includes(`Topics:`), true); - assert.strictEqual(output.includes(fullTopicNameOne), true); - }) - .start(); -}); + after(async () => { + const rm = obj => obj.delete().catch(console.error); + await rm(pubsub.subscription(subscriptionNameOne)); + await rm(pubsub.topic(topicNameOne)); + await rm(pubsub.subscription(subscriptionNameTwo)); + await rm(pubsub.subscription(subscriptionNameThree)); + await rm(pubsub.subscription(subscriptionNameFour)); + await rm(pubsub.topic(topicNameTwo)); + }); -it(`should publish a simple message`, async () => { - const [subscription] = await pubsub - .topic(topicNameOne) - .subscription(subscriptionNameOne) - .get({autoCreate: true}); - await tools.runAsync( - `${cmd} publish ${topicNameOne} "${expectedMessage.data}"`, - cwd - ); - const receivedMessage = await _pullOneMessage(subscription); - assert.strictEqual(receivedMessage.data.toString(), expectedMessage.data); -}); + // Helper function to pull one message + const _pullOneMessage = (subscriptionObj, timeout) => { + timeout = timeout || 10000; // 10 second timeout by default + + let message; + return new Promise((resolve, reject) => { + // First message received; ack it + resolve promise + const messageHandler = received => { + received.ack(); + message = received; + return resolve(messageHandler); + }; + + // Listen for new messages + subscriptionObj.on(`message`, messageHandler); + + // Timeout appropriately + setTimeout(() => { + return reject(new Error(`_pullOneMessage timed out`)); + }, timeout); + }).then(messageHandler => { + subscriptionObj.removeListener('message', messageHandler); + return Promise.resolve(message); + }); + }; + + it('should create a topic', async () => { + const output = await exec(`${cmd} create ${topicNameOne}`); + assert.strictEqual(output, `Topic ${topicNameOne} created.`); + const [topics] = await pubsub.getTopics(); + assert(topics.some(t => t.name === fullTopicNameOne)); + }); -it(`should publish a JSON message`, async () => { - const [subscription] = await pubsub - .topic(topicNameOne) - .subscription(subscriptionNameOne) - .get({autoCreate: true}); - await tools.runAsync( - `${cmd} publish ${topicNameOne} "${expectedMessage.data}"`, - cwd - ); - const receivedMessage = await _pullOneMessage(subscription); - assert.deepStrictEqual(receivedMessage.data.toString(), expectedMessage.data); -}); + it('should list topics', async () => { + const output = await exec(`${cmd} list`); + assert.match(output, /Topics:/); + assert.match(output, new RegExp(fullTopicNameOne)); + }); -it(`should publish a message with custom attributes`, async () => { - const [subscription] = await pubsub - .topic(topicNameOne) - .subscription(subscriptionNameOne) - .get({autoCreate: true}); - await tools.runAsync( - `${cmd} publish-attributes ${topicNameOne} "${expectedMessage.data}"`, - cwd - ); - const receivedMessage = await _pullOneMessage(subscription); - assert.strictEqual(receivedMessage.data.toString(), expectedMessage.data); - assert.deepStrictEqual(receivedMessage.attributes, { - origin: 'nodejs-sample', - username: 'gcp', + it('should publish a simple message', async () => { + const [subscription] = await pubsub + .topic(topicNameOne) + .subscription(subscriptionNameOne) + .get({autoCreate: true}); + await exec(`${cmd} publish ${topicNameOne} "${expectedMessage.data}"`); + const receivedMessage = await _pullOneMessage(subscription); + assert.strictEqual(receivedMessage.data.toString(), expectedMessage.data); }); -}); -it(`should publish ordered messages`, async () => { - const topics = require(`../topics`); + it('should publish a JSON message', async () => { + const [subscription] = await pubsub + .topic(topicNameOne) + .subscription(subscriptionNameOne) + .get({autoCreate: true}); + await exec(`${cmd} publish ${topicNameOne} "${expectedMessage.data}"`); + const receivedMessage = await _pullOneMessage(subscription); + assert.deepStrictEqual( + receivedMessage.data.toString(), + expectedMessage.data + ); + }); - const [subscription] = await pubsub - .topic(topicNameTwo) - .subscription(subscriptionNameTwo) - .get({autoCreate: true}); + it('should publish a message with custom attributes', async () => { + const [subscription] = await pubsub + .topic(topicNameOne) + .subscription(subscriptionNameOne) + .get({autoCreate: true}); + await exec( + `${cmd} publish-attributes ${topicNameOne} "${expectedMessage.data}"` + ); + const receivedMessage = await _pullOneMessage(subscription); + assert.strictEqual(receivedMessage.data.toString(), expectedMessage.data); + assert.deepStrictEqual(receivedMessage.attributes, { + origin: 'nodejs-sample', + username: 'gcp', + }); + }); - let messageId = await topics.publishOrderedMessage( - topicNameTwo, - expectedMessage.data - ); - let message = await _pullOneMessage(subscription); - assert.strictEqual(message.id, messageId); - assert.strictEqual(message.data.toString(), expectedMessage.data); - assert.strictEqual(message.attributes.counterId, '1'); + it('should publish ordered messages', async () => { + const topics = require(`../topics`); - messageId = await topics.publishOrderedMessage( - topicNameTwo, - expectedMessage.data - ); - message = await _pullOneMessage(subscription); - assert.strictEqual(message.id, messageId); - assert.strictEqual(message.data.toString(), expectedMessage.data); - assert.strictEqual(message.attributes.counterId, '2'); - await topics.publishOrderedMessage(topicNameTwo, expectedMessage.data); -}); + const [subscription] = await pubsub + .topic(topicNameTwo) + .subscription(subscriptionNameTwo) + .get({autoCreate: true}); -it(`should publish with specific batch settings`, async () => { - const expectedWait = 1000; - const [subscription] = await pubsub - .topic(topicNameOne) - .subscription(subscriptionNameThree) - .get({autoCreate: true}); - const startTime = Date.now(); - await tools.runAsync( - `${cmd} publish-batch ${topicNameOne} "${ + let messageId = await topics.publishOrderedMessage( + topicNameTwo, expectedMessage.data - }" -w ${expectedWait}`, - cwd - ); - const receivedMessage = await _pullOneMessage(subscription); - const publishTime = Date.parse(receivedMessage.publishTime); - assert.strictEqual(receivedMessage.data.toString(), expectedMessage.data); - assert.strictEqual(publishTime - startTime > expectedWait, true); -}); - -it(`should publish with retry settings`, async () => { - const [subscription] = await pubsub - .topic(topicNameOne) - .subscription(subscriptionNameFour) - .get({autoCreate: true}); - await tools.runAsync( - `${cmd} publish-retry ${projectId} ${topicNameOne} "${ + ); + let message = await _pullOneMessage(subscription); + assert.strictEqual(message.id, messageId); + assert.strictEqual(message.data.toString(), expectedMessage.data); + assert.strictEqual(message.attributes.counterId, '1'); + + messageId = await topics.publishOrderedMessage( + topicNameTwo, expectedMessage.data - }"`, - cwd - ); - const receivedMessage = await _pullOneMessage(subscription); - assert.strictEqual(receivedMessage.data.toString(), expectedMessage.data); -}); + ); + message = await _pullOneMessage(subscription); + assert.strictEqual(message.id, messageId); + assert.strictEqual(message.data.toString(), expectedMessage.data); + assert.strictEqual(message.attributes.counterId, '2'); + await topics.publishOrderedMessage(topicNameTwo, expectedMessage.data); + }); -it(`should set the IAM policy for a topic`, async () => { - await tools.runAsync(`${cmd} set-policy ${topicNameOne}`, cwd); - const results = await pubsub.topic(topicNameOne).iam.getPolicy(); - const [policy] = results; - assert.deepStrictEqual(policy.bindings, [ - { - role: `roles/pubsub.editor`, - members: [`group:cloud-logs@google.com`], - }, - { - role: `roles/pubsub.viewer`, - members: [`allUsers`], - }, - ]); -}); + it('should publish with specific batch settings', async () => { + const expectedWait = 1000; + const [subscription] = await pubsub + .topic(topicNameOne) + .subscription(subscriptionNameThree) + .get({autoCreate: true}); + const startTime = Date.now(); + await exec( + `${cmd} publish-batch ${topicNameOne} "${ + expectedMessage.data + }" -w ${expectedWait}` + ); + const receivedMessage = await _pullOneMessage(subscription); + const publishTime = Date.parse(receivedMessage.publishTime); + assert.strictEqual(receivedMessage.data.toString(), expectedMessage.data); + assert.strictEqual(publishTime - startTime > expectedWait, true); + }); -it(`should get the IAM policy for a topic`, async () => { - const [policy] = await pubsub.topic(topicNameOne).iam.getPolicy(); - const output = await tools.runAsync(`${cmd} get-policy ${topicNameOne}`, cwd); - assert.strictEqual( - output, - `Policy for topic: ${JSON.stringify(policy.bindings)}.` - ); -}); + it('should publish with retry settings', async () => { + const [subscription] = await pubsub + .topic(topicNameOne) + .subscription(subscriptionNameFour) + .get({autoCreate: true}); + await exec( + `${cmd} publish-retry ${projectId} ${topicNameOne} "${ + expectedMessage.data + }"` + ); + const receivedMessage = await _pullOneMessage(subscription); + assert.strictEqual(receivedMessage.data.toString(), expectedMessage.data); + }); -it(`should test permissions for a topic`, async () => { - const output = await tools.runAsync( - `${cmd} test-permissions ${topicNameOne}`, - cwd - ); - assert.strictEqual(output.includes(`Tested permissions for topic`), true); -}); + it('should set the IAM policy for a topic', async () => { + await exec(`${cmd} set-policy ${topicNameOne}`); + const results = await pubsub.topic(topicNameOne).iam.getPolicy(); + const [policy] = results; + assert.deepStrictEqual(policy.bindings, [ + { + role: `roles/pubsub.editor`, + members: [`group:cloud-logs@google.com`], + }, + { + role: `roles/pubsub.viewer`, + members: [`allUsers`], + }, + ]); + }); -it(`should delete a topic`, async () => { - const output = await tools.runAsync(`${cmd} delete ${topicNameOne}`, cwd); - assert.strictEqual(output, `Topic ${topicNameOne} deleted.`); - await tools - .tryTest(async assert => { - const [topics] = await pubsub.getTopics(); - assert(topics.every(s => s.name !== fullTopicNameOne)); - }) - .start(); + it('should get the IAM policy for a topic', async () => { + const [policy] = await pubsub.topic(topicNameOne).iam.getPolicy(); + const output = await exec(`${cmd} get-policy ${topicNameOne}`); + assert.strictEqual( + output, + `Policy for topic: ${JSON.stringify(policy.bindings)}.` + ); + }); + + it('should test permissions for a topic', async () => { + const output = await exec(`${cmd} test-permissions ${topicNameOne}`); + assert.match(output, /Tested permissions for topic/); + }); + + it('should delete a topic', async () => { + const output = await exec(`${cmd} delete ${topicNameOne}`); + assert.strictEqual(output, `Topic ${topicNameOne} deleted.`); + const [topics] = await pubsub.getTopics(); + assert(topics.every(s => s.name !== fullTopicNameOne)); + }); }); diff --git a/samples/topics.js b/samples/topics.js old mode 100755 new mode 100644