From b5f6fde179040f90dbbcbf9fa3216d07e1d358e8 Mon Sep 17 00:00:00 2001 From: Jason Dobry Date: Fri, 19 Aug 2016 15:19:33 -0700 Subject: [PATCH] Bring Logging samples up to standard. --- logging/README.md | 74 +++++-- logging/export.js | 127 ----------- logging/list.js | 57 ----- logging/logs.js | 180 +++++++++++++++ logging/package.json | 8 +- logging/sinks.js | 216 ++++++++++++++++++ logging/system-test/export.test.js | 27 --- logging/system-test/list.test.js | 29 --- logging/system-test/logs.test.js | 69 ++++++ logging/system-test/sinks.test.js | 130 +++++++++++ logging/system-test/write.test.js | 29 --- logging/test/export.test.js | 18 -- logging/test/list.test.js | 18 -- logging/test/logs.test.js | 189 ++++++++++++++++ logging/test/sinks.test.js | 345 +++++++++++++++++++++++++++++ logging/test/write.test.js | 18 -- logging/write.js | 113 ---------- 17 files changed, 1187 insertions(+), 460 deletions(-) delete mode 100644 logging/export.js delete mode 100644 logging/list.js create mode 100644 logging/logs.js create mode 100644 logging/sinks.js delete mode 100644 logging/system-test/export.test.js delete mode 100644 logging/system-test/list.test.js create mode 100644 logging/system-test/logs.test.js create mode 100644 logging/system-test/sinks.test.js delete mode 100644 logging/system-test/write.test.js delete mode 100644 logging/test/export.test.js delete mode 100644 logging/test/list.test.js create mode 100644 logging/test/logs.test.js create mode 100644 logging/test/sinks.test.js delete mode 100644 logging/test/write.test.js delete mode 100644 logging/write.js diff --git a/logging/README.md b/logging/README.md index e924318f12..249281de6d 100644 --- a/logging/README.md +++ b/logging/README.md @@ -12,9 +12,8 @@ Web Services. * [Setup](#setup) * [Samples](#samples) - * [Reading logs](#reading-logs) - * [Writing logs](#writing-logs) - * [Exporting logs](#exporting-logs) + * [Logs](#logs) + * [Sinks](#sinks) * [Error Reporting on Compute Engine](#error-reporting-on-compute-engine) * [Logging to Google Cloud with Winston](https://github.com/GoogleCloudPlatform/winston-gae) @@ -30,38 +29,71 @@ Web Services. ## Samples -### Reading logs +### Logs -View the [documentation][read_docs] or the [source code][read_code]. +View the [documentation][logs_docs] or the [source code][logs_code]. -__Run the sample:__ +__Usage:__ `node logs --help` - node list +``` +Commands: + list List log entries in the authenticated project. + write Write a log entry. + delete Delete a Log. -[read_docs]: https://cloud.google.com/logging/docs/api/tasks/authorization -[read_code]: list.js +Options: + --help Show help [boolean] -### Writing logs +Examples: + node logs list List all log entires. + node logs list -f "severity = ERROR" -s List up to 2 error entries, sorted by + "timestamp" -l 2 timestamp ascending. + node logs write my-log Write a log entry. + '{"type":"gae_app","labels":{"module_id":"default" + }}' '{"message":"Hello World!"}' + node logs delete my-log Delete "my-log". -View the [documentation][write_docs] or the [source code][write_code]. +For more information, see https://cloud.google.com/logging/docs +``` -__Run the sample:__ +[logs_docs]: https://cloud.google.com/logging/docs +[logs_code]: logs.js - node write +### Sinks -[write_docs]: https://cloud.google.com/logging/docs/api/tasks/creating-logs -[write_code]: write.js +View the [documentation][sinks_docs] or the [source code][sinks_code]. -### Exporting logs +__Usage:__ `node sinks --help` -View the [documentation][export_docs] or the [source code][export_code]. +``` +Commands: + create Create a new sink with the given name and destination. + get Get the metadata for the specified sink. + list List all sinks in the authenticated project. + update Update the metadata for the specified sink. + delete Delete the specified sink. -__Run the sample:__ +Options: + --help Show help [boolean] - node export +Examples: + node sinks create my-sink my-bucket --type bucket Create a new sink named "my-sink" that exports + logs to a Cloud Storage bucket. + node sinks create my-sink my-dataset --type Create a new sink named "my-sink" that exports + dataset logs to a BigQuery dataset. + node sinks create my-sink my-topic --type topic Create a new sink named "my-sink" that exports + logs to a Cloud Pub/Sub topic. + node sinks get my-sink Get the metadata for "my-sink". + node sinks list List all sinks in the authenticated project. + node sinks update my-sink '{"filter":"severity > Update the specified sink. + ALERT"}' + node sinks delete my-sink Delete "my-sink". -[export_docs]: https://cloud.google.com/logging/docs/api/tasks/exporting-logs -[export_code]: export.js +For more information, see https://cloud.google.com/logging/docs +``` + +[sinks_docs]: https://cloud.google.com/logging/docs +[sinks_code]: sinks.js ### Error Reporting on Compute Engine diff --git a/logging/export.js b/logging/export.js deleted file mode 100644 index e323aa6169..0000000000 --- a/logging/export.js +++ /dev/null @@ -1,127 +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'; - -// [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 Logging = require('@google-cloud/logging'); - -// Instantiate a logging client -var logging = Logging(); -// [END setup] - -// [START listSinks] -/** - * @param {Function} callback Callback function. - */ -function listSinksExample (callback) { - // list all sinks in the authenticated project - logging.getSinks(function (err, sinks) { - if (err) { - return callback(err); - } - - // Should have received all sinks - console.log('Found ' + sinks.length + ' sinks'); - callback(null, sinks); - }); -} -// [END listSinks] - -// [START createSink] -/** - * @param {string} sinkName Name of the new sink. - * @param {Object} config Configuration options for the new sink. - * @param {Function} callback Callback function. - */ -function createSinkExample (sinkName, config, callback) { - // create a new sink in the authenticated project - // - // This method only works if you are authenticated as yourself, e.g. using the - // gcloud SDK. - logging.createSink(sinkName, config, function (err, sink, apiResponse) { - if (err) { - return callback(err); - } - - // Should have received newly created sink - console.log('Created ' + sinkName, sink); - callback(null, sink, apiResponse); - }); -} -// [END createSink] - -// [START updateSink] -/** - * @param {string} sinkName Name of the sink to update. - * @param {Object} config New configuration options for the sink. - * @param {Function} callback Callback function. - */ -function updateSinkExample (sinkName, config, callback) { - // Get a reference to an existing sink - var sink = logging.sink(sinkName); - - // update a sink - // - // This method only works if you are authenticated as yourself, e.g. using the - // gcloud SDK. - sink.setMetadata(config, function (err, apiResponse) { - if (err) { - return callback(err); - } - - console.log('Updated ' + sinkName); - callback(null, apiResponse); - }); -} -// [END updateSink] - -// [START deleteSink] -/** - * @param {string} sinkName Name of the sink to delete. - * @param {Function} callback Callback function. - */ -function deleteSinkExample (sinkName, callback) { - // Get a reference to an existing sink - var sink = logging.sink(sinkName); - - // delete a sink - // - // This method only works if you are authenticated as yourself, e.g. using the - // gcloud SDK. - sink.delete(function (err, apiResponse) { - if (err) { - return callback(err); - } - - console.log('Deleted ' + sinkName); - callback(null, apiResponse); - }); -} -// [END deleteSink] - -// Run the examples -exports.main = function (cb) { - listSinksExample(cb || console.log); -}; -exports.createSinkExample = createSinkExample; -exports.updateSinkExample = updateSinkExample; -exports.deleteSinkExample = deleteSinkExample; - -if (module === require.main) { - exports.main(); -} diff --git a/logging/list.js b/logging/list.js deleted file mode 100644 index 28252e56ef..0000000000 --- a/logging/list.js +++ /dev/null @@ -1,57 +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'; - -// [START list] -// [START auth] -// 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 Logging = require('@google-cloud/logging'); - -// Instantiate a logging client -var logging = Logging(); -// [END auth] - -/** - * @param {Object} [options] Configuration options for the request. - * @param {Function} callback Callback function. - */ -function listExample (options, callback) { - if (typeof options === 'function') { - callback = options; - } - - // Retrieve the latest some log entries from the authenticated project. - logging.getEntries(options, function (err, entries, nextQuery, apiResponse) { - if (err) { - return callback(err); - } - - // Should have received some log entries - console.log('Found ' + entries.length + ' entries'); - callback(null, entries, nextQuery, apiResponse); - }); -} -// [END list] - -// Run the examples -exports.main = function (options, cb) { - listExample(options || { pageSize: 1 }, cb || console.log); -}; - -if (module === require.main) { - exports.main(); -} diff --git a/logging/logs.js b/logging/logs.js new file mode 100644 index 0000000000..2629071056 --- /dev/null +++ b/logging/logs.js @@ -0,0 +1,180 @@ +// 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'; + +// [START all] +// [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 Logging = require('@google-cloud/logging'); + +// Instantiate a logging client +var logging = Logging(); +// [END setup] + +// [START list_log_entries] +/** + * List log entires in the authenticated project. + * + * @param {object} [options] Optional. Configuration options. + * @param {string} [options.filter] Optional. An advanced logs filter. An empty filter matches all log entries. + * @param {number} [options.limit] Optional. Maximum number of logs to return. + * @param {string} [options.sort] Optional. Default: "timestamp desc". + * @param {function} callback The callback function. + */ +function listLogEntries (options, callback) { + // Configuration to pass to Logging#getEntries + var config = {}; + + if (options.filter) { + config.filter = options.filter; + } + if (options.limit) { + config.pageSize = options.limit; + } + if (options.sort) { + config.orderBy = options.sort; + } + + // See https://googlecloudplatform.github.io/gcloud-node/#/docs/logging/latest/logging + logging.getEntries(config, function (err, entries) { + if (err) { + return callback(err); + } + + console.log('Found %d entries!', entries.length); + return callback(null, entries); + }); +} +// [END list_log_entries] + +// [START write_log_entry] +/** + * Write a log entry. + * + * @param {object} options Configuration options. + * @param {string} options.name The name of the log to write to. + * @param {object} options.resource The resource to associate with the log entry. + * @param {string|object} options.entry The body of the log entry. + * @param {function} callback The callback function. + */ +function writeLogEntry (options, callback) { + // Get a reference to an existing log + var log = logging.log(options.name); + + // Prepare the entry + var entry = log.entry(options.resource, options.entry); + + // See https://googlecloudplatform.github.io/gcloud-node/#/docs/logging/latest/logging/log + log.write(entry, function (err) { + if (err) { + return callback(err); + } + + console.log('Wrote entry to log: %s', options.name); + callback(null); + }); +} +// [END write_log_entry] + +// [START delete_log] +/** + * Delete a log. + * + * @param {string} name The name of the log to delete. + * @param {function} callback The callback function. + */ +function deleteLog (name, callback) { + // Get a reference to the Log to be deleted + var log = logging.log(name); + + // Delete the log + log.delete(function (err) { + if (err) { + return callback(err); + } + + console.log('Deleted log: %s', name); + callback(null); + }); +} +// [END delete_log] +// [END all] + +// The command-line program +var cli = require('yargs'); + +var program = module.exports = { + listLogEntries: listLogEntries, + writeLogEntry: writeLogEntry, + deleteLog: deleteLog, + main: function (args) { + // Run the command-line program + cli.help().strict().parse(args).argv; + } +}; + +cli + .demand(1) + .command('list', 'List log entries in the authenticated project.', { + filter: { + alias: 'f', + type: 'string', + requiresArg: true, + description: 'Only log entries matching the filter are written.' + }, + limit: { + alias: 'l', + type: 'number', + requiresArg: true, + description: 'Maximum number of results to return.' + }, + sort: { + alias: 's', + type: 'string', + requiresArg: true, + description: 'Sort results.' + } + }, function (options) { + program.listLogEntries(options, console.log); + }) + .command('write ', 'Write a log entry.', {}, function (options) { + try { + options.resource = JSON.parse(options.resource); + } catch (err) { + console.error('"resource" must be a valid JSON string!'); + } + try { + options.entry = JSON.parse(options.entry); + } catch (err) { + return console.error('"entry" must be a valid JSON string!'); + } + program.writeLogEntry(options, console.log); + }) + .command('delete ', 'Delete a Log.', {}, function (options) { + program.deleteLog(options.name, console.log); + }) + .example('node $0 list', 'List all log entires.') + .example('node $0 list -f "severity = ERROR" -s "timestamp" -l 2', 'List up to 2 error entries, sorted by timestamp ascending.') + .example('node $0 write my-log \'{"type":"gae_app","labels":{"module_id":"default"}}\' \'{"message":"Hello World!"}\'', 'Write a log entry.') + .example('node $0 delete my-log', 'Delete "my-log".') + .wrap(100) + .recommendCommands() + .epilogue('For more information, see https://cloud.google.com/logging/docs'); + +if (module === require.main) { + program.main(process.argv.slice(2)); +} diff --git a/logging/package.json b/logging/package.json index c01b689958..38484835f3 100644 --- a/logging/package.json +++ b/logging/package.json @@ -10,11 +10,13 @@ }, "dependencies": { "@google-cloud/logging": "^0.1.1", - "async": "^2.0.1", "express": "^4.13.4", - "fluent-logger": "^2.0.1" + "fluent-logger": "^2.0.1", + "google-cloud": "^0.38.3", + "yargs": "^5.0.0" }, "devDependencies": { - "mocha": "^3.0.2" + "mocha": "^3.0.2", + "node-uuid": "^1.4.7" } } diff --git a/logging/sinks.js b/logging/sinks.js new file mode 100644 index 0000000000..a6f3540d4e --- /dev/null +++ b/logging/sinks.js @@ -0,0 +1,216 @@ +// 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'; + +// [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 gcloud = require('google-cloud'); + +// Instantiate the logging client +var logging = gcloud.logging(); +// [END setup] + +// [START create_sink] +/** + * Create a new sink. + * + * @param {objects} options Configuration options. + * @param {string} options.name The name for new sink. + * @param {string} options.destination Destination for the new sink. + * @param {string} options.type The type of destination. Choices are: + * "bucket", "dataset", or "topic". + * @param {function} callback The callback function. + */ +function createSink (options, callback) { + var sink = logging.sink(options.name); + var config = {}; + + // Based on the type of destination, prepare the appropriate object + if (options.type === 'bucket') { + config.destination = gcloud.storage().bucket(options.destination); + } else if (options.type === 'dataset') { + config.destination = gcloud.bigquery().dataset(options.destination); + } else if (options.type === 'topic') { + config.destination = gcloud.pubsub().topic(options.destination); + } + + // See https://googlecloudplatform.github.io/gcloud-node/#/docs/logging/latest/logging/sink + sink.create(config, function (err, sink) { + if (err) { + return callback(err); + } + + console.log('Created sink: %s', options.name); + return callback(null, sink); + }); +} +// [END create_sink] + +// [START get_sink_metadata] +/** + * Get the metatdata for the specified sink. + * + * @param {string} name The name of the sink to get. + * @param {function} callback The callback function. + */ +function getSinkMetadata (name, callback) { + var sink = logging.sink(name); + + // See https://googlecloudplatform.github.io/gcloud-node/#/docs/logging/latest/logging/sink + sink.getMetadata(function (err, metadata) { + if (err) { + return callback(err); + } + + console.log('Got metadata for sink: %s', name); + return callback(null, metadata); + }); +} +// [END get_sink_metadata] + +// [START list_sinks] +/** + * List sinks in the authenticated project. + * + * @param {function} callback The callback function. + */ +function listSinks (callback) { + // See https://googlecloudplatform.github.io/gcloud-node/#/docs/logging/latest/logging + logging.getSinks(function (err, sinks) { + if (err) { + return callback(err); + } + + console.log('Found %d sink(s)!', sinks.length); + return callback(null, sinks); + }); +} +// [END list_sinks] + +// [START update_sink] +/** + * Update the metdata for a sink. + * + * @param {object} options Configuration options. + * @param {string} name The name of the sink to update. + * @param {object} metadata The new metadata for the sink. + * @param {function} callback The callback function. + */ +function updateSink (options, callback) { + var sink = logging.sink(options.name); + + // See https://googlecloudplatform.github.io/gcloud-node/#/docs/logging/latest/logging/sink + sink.setMetadata(options.metadata, function (err) { + if (err) { + return callback(err); + } + + console.log('Updated sink: %s', options.name); + return callback(null); + }); +} +// [END update_sink] + +// [START delete_sink] +/** + * Delete a sink. + * + * @param {string} name The name of the sink to delete. + * @param {function} callback The callback function. + */ +function deleteSink (name, callback) { + var sink = logging.sink(name); + + // See https://googlecloudplatform.github.io/gcloud-node/#/docs/logging/latest/logging/sink + sink.delete(function (err) { + if (err) { + return callback(err); + } + + console.log('Deleted sink: %s', name); + callback(null); + }); +} +// [END delete_sink] +// [END all] + +// The command-line program +var cli = require('yargs'); + +var program = module.exports = { + createSink: createSink, + getSinkMetadata: getSinkMetadata, + listSinks: listSinks, + updateSink: updateSink, + deleteSink: deleteSink, + main: function (args) { + // Run the command-line program + cli.help().strict().parse(args).argv; + } +}; + +cli + .demand(1) + .command('create ', 'Create a new sink with the given name and destination.', { + filter: { + alias: 'f', + type: 'string', + requiresArg: true, + description: 'Optional. Only log entries matching the filter are written.' + }, + type: { + alias: 't', + demand: true, + type: 'string', + choices: ['bucket', 'dataset', 'topic'], + requiresArg: true, + description: 'The type of destination.' + } + }, function (options) { + program.createSink(options, console.log); + }) + .command('get ', 'Get the metadata for the specified sink.', {}, function (options) { + program.getSinkMetadata(options.name, console.log); + }) + .command('list', 'List all sinks in the authenticated project.', {}, function () { + program.listSinks(console.log); + }) + .command('update ', 'Update the metadata for the specified sink.', {}, function (options) { + try { + options.metadata = JSON.parse(options.metadata); + } catch (err) { + return console.error('"metadata" must be a valid JSON string!'); + } + program.updateSink(options, console.log); + }) + .command('delete ', 'Delete the specified sink.', {}, function (options) { + program.deleteSink(options.name, console.log); + }) + .example('node $0 create my-sink my-bucket --type bucket', 'Create a new sink named "my-sink" that exports logs to a Cloud Storage bucket.') + .example('node $0 create my-sink my-dataset --type dataset', 'Create a new sink named "my-sink" that exports logs to a BigQuery dataset.') + .example('node $0 create my-sink my-topic --type topic', 'Create a new sink named "my-sink" that exports logs to a Cloud Pub/Sub topic.') + .example('node $0 get my-sink', 'Get the metadata for "my-sink".') + .example('node $0 list', 'List all sinks in the authenticated project.') + .example('node $0 update my-sink \'{"filter":"severity > ALERT"}\'', 'Update the specified sink.') + .example('node $0 delete my-sink', 'Delete "my-sink".') + .wrap(100) + .recommendCommands() + .epilogue('For more information, see https://cloud.google.com/logging/docs'); + +if (module === require.main) { + program.main(process.argv.slice(2)); +} diff --git a/logging/system-test/export.test.js b/logging/system-test/export.test.js deleted file mode 100644 index 3d6b65d7bc..0000000000 --- a/logging/system-test/export.test.js +++ /dev/null @@ -1,27 +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 exportExample = require('../export'); - -describe('logging:export', function () { - it('should list sinks', function (done) { - exportExample.main(function (err, sinks) { - assert.ifError(err); - assert(sinks, 'should have received sinks'); - assert(Array.isArray(sinks), 'sinks should be an array'); - done(); - }); - }); -}); diff --git a/logging/system-test/list.test.js b/logging/system-test/list.test.js deleted file mode 100644 index 907f020318..0000000000 --- a/logging/system-test/list.test.js +++ /dev/null @@ -1,29 +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 listExample = require('../list'); - -describe('logging:list', function () { - it('should list entries', function (done) { - listExample.main(undefined, function (err, entries, nextQuery, apiResponse) { - assert.ifError(err); - assert(entries, 'should have received entries'); - assert(Array.isArray(entries), 'entries should be an array'); - assert(nextQuery, 'should have received nextQuery'); - assert(apiResponse, 'should have received apiResponse'); - done(); - }); - }); -}); diff --git a/logging/system-test/logs.test.js b/logging/system-test/logs.test.js new file mode 100644 index 0000000000..a40133bda0 --- /dev/null +++ b/logging/system-test/logs.test.js @@ -0,0 +1,69 @@ +// 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 program = require('../logs'); + +var logName = 'nodejs-docs-samples-test-' + uuid.v4(); +var projectId = process.env.GCLOUD_PROJECT; +var filter = 'resource.type="global" AND logName="projects/' + projectId + '/logs/' + logName + '"'; +var message = 'Hello world!'; + +describe('logging:logs', function () { + it('should write a log entry', function (done) { + var options = { + name: logName, + resource: { + type: 'global' + }, + entry: { + message: message + } + }; + + program.writeLogEntry(options, function (err) { + assert.ifError(err); + // Logs are eventually consistent + setTimeout(done, 5000); + }); + }); + + it('should list log entries', function (done) { + var listOptions = { + filter: filter, + pageSize: 5 + }; + + program.listLogEntries(listOptions, function (err, entries) { + assert.ifError(err); + assert(Array.isArray(entries), '"entries" should be an array.'); + var matchingEntries = entries.filter(function (entry) { + return entry.data && entry.data.message === message; + }); + assert.equal(matchingEntries.length, 1, 'Newly written entry should be in list.'); + done(); + }); + }); + + it('should delete a log', function (done) { + program.deleteLog(logName, function (err) { + // Ignore "Not Found" error + if (err && err.code !== 404) { + assert.ifError(err); + } + done(); + }); + }); +}); diff --git a/logging/system-test/sinks.test.js b/logging/system-test/sinks.test.js new file mode 100644 index 0000000000..13c3c4e67a --- /dev/null +++ b/logging/system-test/sinks.test.js @@ -0,0 +1,130 @@ +// 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 gcloud = require('google-cloud'); +var uuid = require('node-uuid'); +var program = require('../sinks'); + +var logging = gcloud.logging(); +var storage = gcloud.storage(); + +var bucketName = 'nodejs-docs-samples-test-' + uuid.v4(); +var sinkName = 'nodejs-docs-samples-test-' + uuid.v4(); + +describe('logging:sinks', function () { + before(function (done) { + storage.createBucket(bucketName, done); + }); + + after(function (done) { + logging.sink(sinkName).delete(function () { + // Don't check for error, the sink might already have been deleted + storage.bucket(bucketName).delete(function () { + // Don't check for error, the bucket might already have been deleted + done(); + }); + }); + }); + + describe('createSink', function () { + it('should create a new sink', function (done) { + var options = { + name: sinkName, + destination: bucketName, + type: 'bucket' + }; + + program.createSink(options, function (err, sink) { + assert.ifError(err); + assert(sink, 'sink should be defined'); + assert.equal(sink.name, sinkName, 'should have received the new sink'); + done(); + }); + }); + }); + + describe('getSink', function () { + it('should get the metadata for a sink', function (done) { + var expected = { + name: sinkName, + destination: 'storage.googleapis.com/' + bucketName, + filter: '', + outputVersionFormat: 'V2' + }; + + program.getSinkMetadata(sinkName, function (err, metadata) { + assert.ifError(err); + assert.deepEqual(metadata, expected, 'should have received sink metadata'); + done(); + }); + }); + }); + + describe('listSinks', function () { + it('should list sinks', function (done) { + program.listSinks(function (err, sinks) { + assert.ifError(err); + assert(Array.isArray(sinks), '"sinks" should be an array.'); + var matchingSinks = sinks.map(function (sink) { + return sink.name === sinkName; + }); + assert.equal(matchingSinks.length, 1, 'Newly created sink should be in list.'); + done(); + }); + }); + }); + + describe('updateSink', function () { + it('should update metdata for a sink', function (done) { + var filter = 'severity > ALERT'; + var expected = { + name: sinkName, + destination: 'storage.googleapis.com/' + bucketName, + filter: filter, + outputVersionFormat: 'V2' + }; + var options = { + name: sinkName, + metadata: { + filter: filter + } + }; + + program.updateSink(options, function (err) { + assert.ifError(err); + + program.getSinkMetadata(options.name, function (err, metadata) { + assert.ifError(err); + assert.deepEqual(metadata, expected, 'Sink should have new metadata.'); + done(); + }); + }); + }); + }); + + describe('deleteSink', function () { + it('should delete a sink', function (done) { + program.deleteSink(sinkName, function (err) { + assert.ifError(err); + + program.getSinkMetadata(sinkName, function (err) { + assert(err, 'Should be an error.'); + assert.equal(err.code, 404, 'Should be a "not found" error.'); + done(); + }); + }); + }); + }); +}); diff --git a/logging/system-test/write.test.js b/logging/system-test/write.test.js deleted file mode 100644 index 519cde8bac..0000000000 --- a/logging/system-test/write.test.js +++ /dev/null @@ -1,29 +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 writeExample = require('../write'); - -describe('logging:write', function () { - it('should write entries', function (done) { - writeExample.main(function (err, results) { - if (err && err.code === 404) { - return done(); - } - assert.ifError(err); - assert(results.length === 2, 'should have two results'); - done(); - }); - }); -}); diff --git a/logging/test/export.test.js b/logging/test/export.test.js deleted file mode 100644 index 6fa813ad2c..0000000000 --- a/logging/test/export.test.js +++ /dev/null @@ -1,18 +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'; - -describe('logging:export', function () { - it('should be tested'); -}); diff --git a/logging/test/list.test.js b/logging/test/list.test.js deleted file mode 100644 index 2304b976e2..0000000000 --- a/logging/test/list.test.js +++ /dev/null @@ -1,18 +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'; - -describe('logging:list', function () { - it('should be tested'); -}); diff --git a/logging/test/logs.test.js b/logging/test/logs.test.js new file mode 100644 index 0000000000..2d7ceffa7d --- /dev/null +++ b/logging/test/logs.test.js @@ -0,0 +1,189 @@ +// 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 proxyquire = require('proxyquire').noCallThru(); +var filter = 'severity > ALERT'; +var logName = 'bar'; + +function getSample () { + var entriesMock = [{}]; + var entryMock = {}; + var logMock = { + entry: sinon.stub().returns(entryMock), + write: sinon.stub().callsArgWith(1, null), + delete: sinon.stub().callsArgWith(0, null) + }; + var loggingMock = { + log: sinon.stub().returns(logMock), + getEntries: sinon.stub().callsArgWith(1, null, entriesMock) + }; + var LoggingMock = sinon.stub().returns(loggingMock); + + return { + program: proxyquire('../logs', { + '@google-cloud/logging': LoggingMock, + yargs: proxyquire('yargs', {}) + }), + mocks: { + Logging: LoggingMock, + logging: loggingMock, + log: logMock, + entries: entriesMock, + entry: entryMock + } + }; +} + +describe('logging:entries', function () { + describe('listLogEntries', function () { + it('should list log entries', function () { + var sample = getSample(); + var callback = sinon.stub(); + var options = { + filter: filter, + limit: 1, + sort: 'field' + }; + + sample.program.listLogEntries(options, callback); + + assert(sample.mocks.logging.getEntries.calledOnce, 'method called once'); + assert.equal(sample.mocks.logging.getEntries.firstCall.args.length, 2, 'method received 2 arguments'); + assert.deepEqual(sample.mocks.logging.getEntries.firstCall.args[0], { + pageSize: options.limit, + filter: options.filter, + orderBy: options.sort + }, 'method received options'); + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 2, 'callback received 2 arguments'); + assert.ifError(callback.firstCall.args[0], 'callback did not receive error'); + assert.strictEqual(callback.firstCall.args[1], sample.mocks.entries, 'callback received result'); + assert(console.log.calledWith('Found %d entries!', sample.mocks.entries.length)); + }); + + it('should handle error', function () { + var error = 'error'; + var sample = getSample(); + var callback = sinon.stub(); + sample.mocks.logging.getEntries = sinon.stub().callsArgWith(1, error); + + sample.program.listLogEntries({}, callback); + + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 1, 'callback received 1 argument'); + assert(callback.firstCall.args[0], 'callback received error'); + assert.equal(callback.firstCall.args[0].message, error.message, 'error has correct message'); + }); + }); + + describe('writeLogEntry', function () { + it('should write a log entry', function () { + var sample = getSample(); + var callback = sinon.stub(); + + sample.program.writeLogEntry({ + name: logName + }, callback); + + assert(sample.mocks.log.write.calledOnce, 'method called once'); + assert.equal(sample.mocks.log.write.firstCall.args.length, 2, 'method received 2 arguments'); + assert.strictEqual(sample.mocks.log.write.firstCall.args[0], sample.mocks.entry, 'method received options'); + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 1, 'callback received 1 argument'); + assert.ifError(callback.firstCall.args[0], 'callback did not receive error'); + assert(console.log.calledWith('Wrote entry to log: %s', logName)); + }); + + it('should handle error', function () { + var error = 'error'; + var sample = getSample(); + var callback = sinon.stub(); + sample.mocks.log.write = sinon.stub().callsArgWith(1, error); + + sample.program.writeLogEntry({}, callback); + + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 1, 'callback received 1 argument'); + assert(callback.firstCall.args[0], 'callback received error'); + assert.equal(callback.firstCall.args[0].message, error.message, 'error has correct message'); + }); + }); + + describe('deleteLog', function () { + it('should delete a log', function () { + var sample = getSample(); + var callback = sinon.stub(); + + sample.program.deleteLog(logName, callback); + + assert(sample.mocks.log.delete.calledOnce, 'method called once'); + assert.equal(sample.mocks.log.delete.firstCall.args.length, 1, 'method received 1 argument'); + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 1, 'callback received 1 argument'); + assert.ifError(callback.firstCall.args[0], 'callback did not receive error'); + assert(console.log.calledWith('Deleted log: %s', logName)); + }); + + it('should handle error', function () { + var error = 'error'; + var sample = getSample(); + var callback = sinon.stub(); + sample.mocks.log.delete = sinon.stub().callsArgWith(0, error); + + sample.program.deleteLog(logName, callback); + + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 1, 'callback received 1 argument'); + assert(callback.firstCall.args[0], 'callback received error'); + assert.equal(callback.firstCall.args[0].message, error.message, 'error has correct message'); + }); + }); + + describe('main', function () { + it('should call listLogEntries', function () { + var program = getSample().program; + + sinon.stub(program, 'listLogEntries'); + program.main(['list', '-f', '"' + filter + '"', '-l', 1, '-s', 'field']); + assert(program.listLogEntries.calledOnce); + }); + + it('should call writeLogEntry', function () { + var program = getSample().program; + + sinon.stub(program, 'writeLogEntry'); + program.main(['write', logName, '{}', '{}']); + assert.equal(program.writeLogEntry.callCount, 1); + }); + + it('should validate args and call writeLogEntry', function () { + var program = getSample().program; + + sinon.stub(program, 'writeLogEntry'); + program.main(['write', logName, '"{"invalid', '"{"invalid']); + assert.equal(program.writeLogEntry.called, false, 'writeLogEntry should not have been called'); + assert(console.error.calledWith('"resource" must be a valid JSON string!')); + assert(console.error.calledWith('"entry" must be a valid JSON string!')); + }); + + it('should call deleteLog', function () { + var program = getSample().program; + + sinon.stub(program, 'deleteLog'); + program.main(['delete', logName]); + assert(program.deleteLog.calledOnce); + }); + }); +}); diff --git a/logging/test/sinks.test.js b/logging/test/sinks.test.js new file mode 100644 index 0000000000..6c5cec954c --- /dev/null +++ b/logging/test/sinks.test.js @@ -0,0 +1,345 @@ +// 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 proxyquire = require('proxyquire').noCallThru(); +var bucketName = 'foo'; +var datasetName = 'other-foo'; +var filter = 'severity > ALERT'; +var sinkName = 'bar'; +var topicName = 'other-bar'; + +function getSample () { + var bucketMock = {}; + var datasetMock = {}; + var metadataMock = {}; + var sinksMock = [ + { + name: sinkName + } + ]; + var sinkMock = { + create: sinon.stub().callsArgWith(1, null, sinksMock[0]), + delete: sinon.stub().callsArgWith(0, null), + getMetadata: sinon.stub().callsArgWith(0, null, metadataMock), + setMetadata: sinon.stub().callsArgWith(1, null) + }; + var topicMock = {}; + var bigqueryMock = { + dataset: sinon.stub().returns(datasetMock) + }; + var loggingMock = { + sink: sinon.stub().returns(sinkMock), + getSinks: sinon.stub().callsArgWith(0, null, sinksMock) + }; + var pubsubMock = { + topic: sinon.stub().returns(topicMock) + }; + var storageMock = { + bucket: sinon.stub().returns(bucketMock) + }; + var GcloudMock = { + bigquery: sinon.stub().returns(bigqueryMock), + logging: sinon.stub().returns(loggingMock), + pubsub: sinon.stub().returns(pubsubMock), + storage: sinon.stub().returns(storageMock) + }; + + return { + program: proxyquire('../sinks', { + 'google-cloud': GcloudMock, + yargs: proxyquire('yargs', {}) + }), + mocks: { + gcloud: GcloudMock, + bigquery: bigqueryMock, + logging: loggingMock, + storage: storageMock, + pubsub: pubsubMock, + bucket: bucketMock, + dataset: datasetMock, + metadata: metadataMock, + sink: sinkMock, + sinks: sinksMock, + topic: topicMock + } + }; +} + +describe('logging:sinks', function () { + describe('createSink', function () { + it('should create a new sink to a bucket', function () { + var sample = getSample(); + var callback = sinon.stub(); + var options = { + name: sinkName, + destination: bucketName, + type: 'bucket' + }; + + sample.program.createSink(options, callback); + + assert(sample.mocks.sink.create.calledOnce, 'method called once'); + assert.equal(sample.mocks.sink.create.firstCall.args.length, 2, 'method received 2 arguments'); + assert.deepEqual(sample.mocks.sink.create.firstCall.args[0], { + destination: sample.mocks.bucket + }, 'method received options'); + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 2, 'callback received 2 arguments'); + assert.ifError(callback.firstCall.args[0], 'callback did not receive error'); + assert.strictEqual(callback.firstCall.args[1], sample.mocks.sinks[0], 'callback received result'); + assert(console.log.calledWith('Created sink: %s', sinkName)); + }); + + it('should create a new sink to a dataset', function () { + var sample = getSample(); + var callback = sinon.stub(); + var options = { + name: sinkName, + destination: datasetName, + type: 'dataset' + }; + + sample.program.createSink(options, callback); + + assert(sample.mocks.sink.create.calledOnce, 'method called once'); + assert.equal(sample.mocks.sink.create.firstCall.args.length, 2, 'method received 2 arguments'); + assert.deepEqual(sample.mocks.sink.create.firstCall.args[0], { + destination: sample.mocks.dataset + }, 'method received options'); + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 2, 'callback received 2 arguments'); + assert.ifError(callback.firstCall.args[0], 'callback did not receive error'); + assert.strictEqual(callback.firstCall.args[1], sample.mocks.sinks[0], 'callback received result'); + assert(console.log.calledWith('Created sink: %s', sinkName)); + }); + + it('should create a new sink to a topic', function () { + var sample = getSample(); + var callback = sinon.stub(); + var options = { + name: sinkName, + destination: topicName, + type: 'topic' + }; + + sample.program.createSink(options, callback); + + assert(sample.mocks.sink.create.calledOnce, 'method called once'); + assert.equal(sample.mocks.sink.create.firstCall.args.length, 2, 'method received 2 arguments'); + assert.deepEqual(sample.mocks.sink.create.firstCall.args[0], { + destination: sample.mocks.topic + }, 'method received options'); + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 2, 'callback received 2 arguments'); + assert.ifError(callback.firstCall.args[0], 'callback did not receive error'); + assert.strictEqual(callback.firstCall.args[1], sample.mocks.sinks[0], 'callback received result'); + assert(console.log.calledWith('Created sink: %s', sinkName)); + }); + + it('should handle error', function () { + var error = 'error'; + var sample = getSample(); + var callback = sinon.stub(); + sample.mocks.sink.create = sinon.stub().callsArgWith(1, error); + + sample.program.createSink({}, callback); + + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 1, 'callback received 1 argument'); + assert(callback.firstCall.args[0], 'callback received error'); + assert.equal(callback.firstCall.args[0].message, error.message, 'error has correct message'); + }); + }); + + describe('getSinkMetadata', function () { + it('should get metadata for a sink', function () { + var sample = getSample(); + var callback = sinon.stub(); + + sample.program.getSinkMetadata(sinkName, callback); + + assert(sample.mocks.sink.getMetadata.calledOnce, 'method called once'); + assert.equal(sample.mocks.sink.getMetadata.firstCall.args.length, 1, 'method received 1 argument'); + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 2, 'callback received 2 arguments'); + assert.ifError(callback.firstCall.args[0], 'callback did not receive error'); + assert.strictEqual(callback.firstCall.args[1], sample.mocks.metadata, 'callback received result'); + assert(console.log.calledWith('Got metadata for sink: %s', sinkName)); + }); + + it('should handle error', function () { + var error = 'error'; + var sample = getSample(); + var callback = sinon.stub(); + sample.mocks.sink.getMetadata = sinon.stub().callsArgWith(0, error); + + sample.program.getSinkMetadata(sinkName, callback); + + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 1, 'callback received 1 argument'); + assert(callback.firstCall.args[0], 'callback received error'); + assert.equal(callback.firstCall.args[0].message, error.message, 'error has correct message'); + }); + }); + + describe('listSinks', function () { + it('should list sinks', function () { + var sample = getSample(); + var callback = sinon.stub(); + + sample.program.listSinks(callback); + + assert(sample.mocks.logging.getSinks.calledOnce, 'method called once'); + assert.equal(sample.mocks.logging.getSinks.firstCall.args.length, 1, 'method received 1 argument'); + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 2, 'callback received 2 arguments'); + assert.ifError(callback.firstCall.args[0], 'callback did not receive error'); + assert.strictEqual(callback.firstCall.args[1], sample.mocks.sinks, 'callback received result'); + assert(console.log.calledWith('Found %d sink(s)!', sample.mocks.sinks.length)); + }); + + it('should handle error', function () { + var error = 'error'; + var sample = getSample(); + var callback = sinon.stub(); + sample.mocks.logging.getSinks = sinon.stub().callsArgWith(0, error); + + sample.program.listSinks(callback); + + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 1, 'callback received 1 argument'); + assert(callback.firstCall.args[0], 'callback received error'); + assert.equal(callback.firstCall.args[0].message, error.message, 'error has correct message'); + }); + }); + + describe('updateSink', function () { + it('should update metadata for a sink', function () { + var sample = getSample(); + var callback = sinon.stub(); + var options = { + name: sinkName, + metadata: { + filter: filter + } + }; + + sample.program.updateSink(options, callback); + + assert(sample.mocks.sink.setMetadata.calledOnce, 'method called once'); + assert.equal(sample.mocks.sink.setMetadata.firstCall.args.length, 2, 'method received 2 arguments'); + assert.deepEqual(sample.mocks.sink.setMetadata.firstCall.args[0], options.metadata, 'method received options'); + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 1, 'callback received 1 argument'); + assert.ifError(callback.firstCall.args[0], 'callback did not receive error'); + assert(console.log.calledWith('Updated sink: %s', sinkName)); + }); + + it('should handle error', function () { + var error = 'error'; + var sample = getSample(); + var callback = sinon.stub(); + sample.mocks.sink.setMetadata = sinon.stub().callsArgWith(1, error); + + sample.program.updateSink({}, callback); + + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 1, 'callback received 1 argument'); + assert(callback.firstCall.args[0], 'callback received error'); + assert.equal(callback.firstCall.args[0].message, error.message, 'error has correct message'); + }); + }); + + describe('deleteSink', function () { + it('should get metadata for a sink', function () { + var sample = getSample(); + var callback = sinon.stub(); + + sample.program.deleteSink(sinkName, callback); + + assert(sample.mocks.sink.delete.calledOnce, 'method called once'); + assert.equal(sample.mocks.sink.delete.firstCall.args.length, 1, 'method received 1 argument'); + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 1, 'callback received 1 argument'); + assert.ifError(callback.firstCall.args[0], 'callback did not receive error'); + assert(console.log.calledWith('Deleted sink: %s', sinkName)); + }); + + it('should handle error', function () { + var error = 'error'; + var sample = getSample(); + var callback = sinon.stub(); + sample.mocks.sink.delete = sinon.stub().callsArgWith(0, error); + + sample.program.deleteSink(sinkName, callback); + + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 1, 'callback received 1 argument'); + assert(callback.firstCall.args[0], 'callback received error'); + assert.equal(callback.firstCall.args[0].message, error.message, 'error has correct message'); + }); + }); + + describe('main', function () { + it('should call createSink', function () { + var program = getSample().program; + + sinon.stub(program, 'createSink'); + program.main(['create', sinkName, bucketName, '-t', 'bucket']); + assert(program.createSink.calledOnce); + }); + + it('should call getSinkMetadata', function () { + var program = getSample().program; + + sinon.stub(program, 'getSinkMetadata'); + program.main(['get', sinkName]); + assert(program.getSinkMetadata.calledOnce); + }); + + it('should call listSinks', function () { + var program = getSample().program; + + sinon.stub(program, 'listSinks'); + program.main(['list']); + assert(program.listSinks.calledOnce); + }); + + it('should call updateSink', function () { + var program = getSample().program; + + sinon.stub(program, 'updateSink'); + program.main(['update', sinkName, '"{}"']); + assert(program.updateSink.calledOnce); + }); + + it('should validate metadata and call updateSink', function () { + var program = getSample().program; + + sinon.stub(program, 'updateSink'); + program.main(['update', sinkName, '"{"invalid']); + assert.equal(program.updateSink.called, false, 'updateSink should not have been called'); + assert(console.error.calledWith('"metadata" must be a valid JSON string!')); + }); + + it('should call deleteSink', function () { + var program = getSample().program; + + sinon.stub(program, 'deleteSink'); + program.main(['delete', sinkName]); + assert(program.deleteSink.calledOnce); + }); + }); +}); diff --git a/logging/test/write.test.js b/logging/test/write.test.js deleted file mode 100644 index 03c1e6c2ae..0000000000 --- a/logging/test/write.test.js +++ /dev/null @@ -1,18 +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'; - -describe('logging:write', function () { - it('should be tested'); -}); diff --git a/logging/write.js b/logging/write.js deleted file mode 100644 index d021087c33..0000000000 --- a/logging/write.js +++ /dev/null @@ -1,113 +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. - -/* jshint camelcase:false */ -'use strict'; - -var async = require('async'); - -// [START write] -// [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 Logging = require('@google-cloud/logging'); - -// Instantiate a logging client -var logging = Logging(); -// [END setup] - -/** - * @param {string} logName Name of the log to write to. - * @param {Function} callback Callback function. - */ -function writeExample (logName, callback) { - // Get a reference to an existing log - var log = logging.log(logName); - - // Modify this resource type to match a resource in your project - // See https://cloud.google.com/logging/docs/api/ref_v2beta1/rest \ - // /v2beta1/monitoredResourceDescriptors/list - var resource = { - type: 'gae_app', - // This example targets a "App Engine" resource in the default module with - // a version_id of "express" - labels: { - module_id: 'default', - version_id: 'express' - } - }; - - // Create a log entry attached to the specified resource - var entry = log.entry(resource, { - foo: 'bar' - }); - - // Create a second log entry attached to the specified resource - var secondEntry = log.entry(resource, { - beep: 'boop' - }); - - // Save the two log entries. You can log multiple entries one at a a time, but - // it is best to write multiple entires together in a batch. - log.write([ - entry, - secondEntry - ], function (err, apiResponse) { - if (err) { - return callback(err); - } - - console.log('Wrote to ' + logName); - callback(null, apiResponse); - }); -} -// [END write] - -// [START deleteLog] -/** - * @param {string} logName Name of the log to delete. - * @param {Function} callback Callback function. - */ -function deleteLogExample (logName, callback) { - // Get a reference to an existing log - var log = logging.log(logName); - - // Delete the log - log.delete(function (err, apiResponse) { - if (err) { - return callback(err); - } - - console.log('Deleted ' + logName); - callback(null, apiResponse); - }); -} -// [END deleteLog] - -// Run the examples -exports.main = function (cb) { - async.series([ - function (cb) { - writeExample('myLog', cb); - }, - function (cb) { - deleteLogExample('myLog', cb); - } - ], cb || console.log); -}; - -if (module === require.main) { - exports.main(); -}