From 01d944230f556c6aa87494e81d717e6dc7371953 Mon Sep 17 00:00:00 2001 From: Ashley Date: Fri, 15 Jul 2016 08:56:55 -0400 Subject: [PATCH 1/5] compute: implement subnetworks --- lib/compute/index.js | 117 +++++++++++++++++++++ lib/compute/network.js | 137 ++++++++++++++++++++++++ lib/compute/region.js | 200 ++++++++++++++++++++++++++++++++++- lib/compute/subnetwork.js | 216 ++++++++++++++++++++++++++++++++++++++ system-test/compute.js | 60 +++++++++++ test/compute/index.js | 1 + 6 files changed, 730 insertions(+), 1 deletion(-) create mode 100644 lib/compute/subnetwork.js diff --git a/lib/compute/index.js b/lib/compute/index.js index eeeb890f3db..40970857831 100644 --- a/lib/compute/index.js +++ b/lib/compute/index.js @@ -1162,6 +1162,122 @@ Compute.prototype.getFirewalls = function(options, callback) { }); }; +/** + * Get a list of subnetworks in this project. + * + * @resource [Subnetworks Overview]{@link https://cloud.google.com/compute/docs/subnetworks} + * @resource [Subnetworks: list API Documentation]{@link https://cloud.google.com/compute/docs/reference/latest/subnetworks} + * + * @param {object=} options - Subnetwork search options. + * @param {boolean} options.autoPaginate - Have pagination handled + * automatically. Default: true. + * @param {string} options.filter - Search filter in the format of + * `{name} {comparison} {filterString}`. + * - **`name`**: the name of the field to compare + * - **`comparison`**: the comparison operator, `eq` (equal) or `ne` + * (not equal) + * - **`filterString`**: the string to filter to. For string fields, this + * can be a regular expression. + * @param {number} options.maxApiCalls - Maximum number of API calls to make. + * @param {number} options.maxResults - Maximum number of firewalls to return. + * @param {string} options.pageToken - A previously-returned page token + * representing part of the larger set of results to view. + * @param {function} callback - The callback function. + * @param {?error} callback.err - An error returned while making this request. + * @param {module:compute/subnetwork} callback.subnetworks - Subnetwork objects + * from your project. + * @param {?object} callback.nextQuery - If present, query with this object to + * check for more results. + * @param {object} callback.apiResponse - The full API response. + * + * @example + * gce.getSubnetworks(function(err, subnetworks) { + * // `subnetworks` is an array of `Subnetworks` objects. + * }); + * + * //- + * // To control how many API requests are made and page through the results + * // manually, set `autoPaginate` to `false`. + * //- + * function callback(err, subnetworks, nextQuery, apiResponse) { + * if (nextQuery) { + * // More results exist. + * gce.getSubnetworks(nextQuery, callback); + * } + * } + * + * gce.getSubnetworks({ + * autoPaginate: false + * }, callback); + * + * //- + * // Get the firewalls from your project as a readable object stream. + * //- + * gce.getSubnetworks() + * .on('error', console.error) + * .on('data', function(subnetwork) { + * // `subnetwork` is a `Subnetwork` object. + * }) + * .on('end', function() { + * // All subnetworks retrieved. + * }); + * + * //- + * // If you anticipate many results, you can end a stream early to prevent + * // unnecessary processing and API requests. + * //- + * gce.getSubnetworks() + * .on('data', function(subnetwork) { + * this.end(); + * }); + */ +Compute.prototype.getSubnetworks = function(options, callback) { + var self = this; + + if (is.fn(options)) { + callback = options; + options = {}; + } + + options = options || {}; + + this.request({ + uri: '/aggregated/subnetworks', + qs: options + }, function(err, resp) { + + if (err) { + callback(err, null, null, resp); + return; + } + + var nextQuery = null; + + if (resp.nextPageToken) { + nextQuery = extend({}, options, { + pageToken: resp.nextPageToken + }); + } + + var regions = resp.items || {}; + + var subnetworks = Object.keys(regions).reduce(function(acc, regionName) { + var region = self.region(regionName.replace('regions/', '')); + var subnetworks = regions[regionName].subnetworks || []; + + subnetworks.forEach(function(subnetwork) { + var subnetworkInstance = region.subnetwork(subnetwork.name); + subnetworkInstance.metadata = subnetwork; + acc.push(subnetworkInstance); + }); + + return acc; + }, []); + + callback(null, subnetworks, nextQuery, resp); + }); +}; + /** * Get a list of health checks. * @@ -2272,6 +2388,7 @@ streamRouter.extend(Compute, [ 'getRules', 'getServices', 'getSnapshots', + 'getSubnetworks', 'getVMs', 'getZones' ]); diff --git a/lib/compute/network.js b/lib/compute/network.js index 749847299a3..70bb5647d9c 100644 --- a/lib/compute/network.js +++ b/lib/compute/network.js @@ -37,6 +37,12 @@ var ServiceObject = require('../common/service-object.js'); */ var util = require('../common/util.js'); +/** + * @type {module:compute/region} + * @private + */ +var Region = require('./region.js'); + /*! Developer Documentation * * @param {module:compute} compute - The Compute module this network belongs to. @@ -214,6 +220,137 @@ Network.prototype.createFirewall = function(name, config, callback) { this.compute.createFirewall(name, config, callback); }; +/** + * Create a subnetwork in this network. + * + * @resource [Subnetwork Resource]{@link https://cloud.google.com/compute/docs/reference/v1/subnetworks#resource} + * @resource [Subnetwork: insert API Documentation]{@link https://cloud.google.com/compute/docs/reference/v1/subnetworks/insert} + * + * @param {string} name - Name of the subnetwork. + * @param {object} config - See a + * [Subnetwork resource](https://cloud.google.com/compute/docs/reference/v1/subnetworks#resource). + * @param {string=} config.description - An optional description of this + * resource. Provide this property when you create the resource. + * @param {string} config.ipCidrRange - The range of internal addresses that + * are owned by this subnetwork. Provide this property when you create the + * subnetwork. For example, 10.0.0.0/8 or 192.168.0.0/16. Ranges must be + * unique and non-overlapping within a network. + * @param {string} config.region - URL of the region where the Subnetwork + * resides. + * @param {function} callback - The callback function. + * @param {?error} callback.err - An error returned while making this request. + * @param {module:compute/rule} callback.rule - The created Rule object. + * @param {module:compute/operation} callback.operation - An operation object + * that can be used to check the status of the request. + * @param {object} callback.apiResponse - The full API response. + * + * @example + * var name = 'new-subnetwork-name'; + * + * var config = { + * region : 'regions/us-east1', + * ipCidrRange: '10.0.1.0/24' + * }; + * + * network.createSubnetwork(name, config, + * function (err, subnetwork, operation, apiResponse) { + * // `subnetwork` is a Subnetwork object. + * + * // `operation` is an Operation object that can be used to check the status + * // of the request. + * }); + */ +Network.prototype.createSubnetwork = function(name, config, callback) { + config = extend({}, config, { + network: this.formattedName + }); + + var region = new Region(this.compute, config.region); + delete config.region; + + return region.createSubnetwork(name, config, callback); +}; + +/** + * Get a list of subnetworks in this network. + * * @resource [Subnetworks Overview]{@link https://cloud.google.com/compute/docs/subnetworks} + * @resource [Subnetworks: list API Documentation]{@link https://cloud.google.com/compute/docs/reference/latest/subnetworks} + * + * @param {object=} options - Subnetwork search options. + * @param {boolean} options.autoPaginate - Have pagination handled + * automatically. Default: true. + * @param {string} options.filter - Search filter in the format of + * `{name} {comparison} {filterString}`. + * - **`name`**: the name of the field to compare + * - **`comparison`**: the comparison operator, `eq` (equal) or `ne` + * (not equal) + * - **`filterString`**: the string to filter to. For string fields, this + * can be a regular expression. + * @param {number} options.maxApiCalls - Maximum number of API calls to make. + * @param {number} options.maxResults - Maximum number of firewalls to return. + * @param {string} options.pageToken - A previously-returned page token + * representing part of the larger set of results to view. + * @param {function} callback - The callback function. + * @param {?error} callback.err - An error returned while making this request. + * @param {module:compute/firewall} callback.subnetworks - Subnetwork objects + * from your project. + * @param {?object} callback.nextQuery - If present, query with this object to + * check for more results. + * @param {object} callback.apiResponse - The full API response. + * + * @example + * gce.getSubnetworks(function(err, subnetworks) { + * // `subnetworks` is an array of `Subnetworks` objects. + * }); + * + * //- + * // To control how many API requests are made and page through the results + * // manually, set `autoPaginate` to `false`. + * //- + * function callback(err, subnetworks, nextQuery, apiResponse) { + * if (nextQuery) { + * // More results exist. + * gce.getSubnetworks(nextQuery, callback); + * } + * } + * + * gce.getSubnetworks({ + * autoPaginate: false + * }, callback); + * * //- + * // Get the firewalls from your project as a readable object stream. + * //- + * gce.getSubnetworks() + * .on('error', console.error) + * .on('data', function(subnetwork) { + * // `subnetwork` is a `Subnetwork` object. + * }) + * .on('end', function() { + * // All firewalls retrieved. + * }); + * + * //- + * // If you anticipate many results, you can end a stream early to prevent + * // unnecessary processing and API requests. + * //- + * gce.getSubnetworks() + * .on('data', function(subnetwork) { + * this.end(); + * }); + */ +Network.prototype.getSubnetworks = function(options, callback) { + if (is.fn(options)) { + callback = options; + options = {}; + } + + options = extend({}, options, { + filter: 'network eq .*' + this.formattedName + }); + + return this.compute.getSubnetworks(options, callback); +}; + /** * Delete the network. * diff --git a/lib/compute/region.js b/lib/compute/region.js index 6351aa9bd78..e3b5114e9b5 100644 --- a/lib/compute/region.js +++ b/lib/compute/region.js @@ -42,6 +42,12 @@ var Operation = require('./operation.js'); */ var Rule = require('./rule.js'); +/** + * @type {module:compute/subnetwork} + * @private + */ +var Subnetwork = require('./subnetwork.js'); + /** * @type {module:common/service-object} * @private @@ -214,6 +220,198 @@ Region.prototype.createAddress = function(name, options, callback) { }); }; +/** + * Get a list of subnetworks in this region. + * + * @resource [Subnetworks Overview]{@link https://cloud.google.com/compute/docs/subnetworks} + * @resource [Subnetworks: list API Documentation]{@link https://cloud.google.com/compute/docs/reference/latest/subnetworks} + * + * @param {object=} options - Subnetwork search options. + * @param {boolean} options.autoPaginate - Have pagination handled + * automatically. Default: true. + * @param {string} options.filter - Search filter in the format of + * `{name} {comparison} {filterString}`. + * - **`name`**: the name of the field to compare + * - **`comparison`**: the comparison operator, `eq` (equal) or `ne` + * (not equal) + * - **`filterString`**: the string to filter to. For string fields, this + * can be a regular expression. + * @param {number} options.maxApiCalls - Maximum number of API calls to make. + * @param {number} options.maxResults - Maximum number of firewalls to return. + * @param {string} options.pageToken - A previously-returned page token + * representing part of the larger set of results to view. + * @param {function} callback - The callback function. + * @param {?error} callback.err - An error returned while making this request. + * @param {module:compute/subnetworks} callback.subnetworks - Subnetwork objects + * from your project. + * @param {?object} callback.nextQuery - If present, query with this object to + * check for more results. + * @param {object} callback.apiResponse - The full API response. + * + * @example + * gce.getSubnetworks(function(err, subnetworks) { + * // `subnetworks` is an array of `Subnetworks` objects. + * }); + * + * //- + * // To control how many API requests are made and page through the results + * // manually, set `autoPaginate` to `false`. + * //- + * function callback(err, subnetworks, nextQuery, apiResponse) { + * if (nextQuery) { + * // More results exist. + * gce.getSubnetworks(nextQuery, callback); + * } + * } + * + * gce.getSubnetworks({ + * autoPaginate: false + * }, callback); + * + * //- + * // Get the firewalls from your project as a readable object stream. + * //- + * gce.getSubnetworks() + * .on('error', console.error) + * .on('data', function(subnetwork) { + * // `subnetwork` is a `Subnetwork` object. + * }) + * .on('end', function() { + * // All subnetworks retrieved. + * }); + * + * //- + * // If you anticipate many results, you can end a stream early to prevent + * // unnecessary processing and API requests. + * //- + * gce.getSubnetworks() + * .on('data', function(subnetwork) { + * this.end(); + * }); + */ +Region.prototype.getSubnetworks = function(options, callback) { + var self = this; + + if (is.fn(options)) { + callback = options; + options = {}; + } + + options = options || {}; + + this.request({ + uri: '/subnetworks', + qs: options + }, function(err, resp) { + if (err) { + callback(err, null, null, resp); + return; + } + + var nextQuery = null; + + if (resp.nextPageToken) { + nextQuery = extend({}, options, { + pageToken: resp.nextPageToken + }); + } + + var subnetworks = (resp.items || []).map(function(subnetwork) { + var subnetworkInstance = self.subnetwork(subnetwork.name); + subnetworkInstance.metadata = subnetwork; + return subnetworkInstance; + }); + + callback(null, subnetworks, nextQuery, resp); + }); +}; + +/** + * Get a reference to a Google Compute Engine address in this region. + * + * @resource [Instances and Networks]{@link https://cloud.google.com/compute/docs/instances-and-network} + * + * @param {string} name - Name of the subnetwork. + * @return {module:compute/subnetwork} + * + * @example + * var subnetwork = region.subnetwork('subnetwork-name'); + */ +Region.prototype.subnetwork = function(name) { + return new Subnetwork(this, name); +}; + +/** + * Create a subnetwork in this region. + * + * @resource [Subnetwork Resource]{@link https://cloud.google.com/compute/docs/reference/v1/subnetworks#resource} + * @resource [Subnetwork: insert API Documentation]{@link https://cloud.google.com/compute/docs/reference/v1/subnetworks/insert} + * + * @param {string} name - Name of the subnetwork. + * @param {object} config - See a + * [Subnetwork resource](https://cloud.google.com/compute/docs/reference/v1/subnetworks#resource). + * @param {string=} config.description - An optional description of this + * resource. Provide this property when you create the resource. + * @param {string} config.ipCidrRange - The range of internal addresses that + * are owned by this subnetwork. Provide this property when you create the + * subnetwork. For example, 10.0.0.0/8 or 192.168.0.0/16. Ranges must be + * unique and non-overlapping within a network. + * @param {string} config.network - The URL of the network to which this + * subnetwork belongs, provided by the client when initially creating + * the subnetwork. Only networks that are in the distributed mode can have + * subnetworks. + * @param {string=} config.region - URL of the region where the Subnetwork + * resides. + * @param {function} callback - The callback function. + * @param {?error} callback.err - An error returned while making this request. + * @param {module:compute/rule} callback.rule - The created Rule object. + * @param {module:compute/operation} callback.operation - An operation object + * that can be used to check the status of the request. + * @param {object} callback.apiResponse - The full API response. + * + * @example + * var name = 'new-subnetwork-name'; + * + * var config = { + * network : 'global/networks/network-name', + * ipCidrRange: '10.0.1.0/24' + * }; + * + * region.createSubnetwork(name, config, + * function (err, subnetwork, operation, apiResponse) { + * // `subnetwork` is a Subnetwork object. + * + * // `operation` is an Operation object that can be used to check the status + * // of the request. + * }); + */ +Region.prototype.createSubnetwork = function(name, config, callback) { + var self = this; + + var body = extend({}, config, { + name: name + }); + + this.request({ + method: 'POST', + uri: '/subnetworks', + json: body + }, function(err, resp) { + console.log(resp); + if (err) { + callback(err, null, null, resp); + return; + } + + var subnetwork = self.subnetwork(name); + + var operation = self.operation(resp.name); + operation.metadata = resp; + + callback(null, subnetwork, operation, resp); + }); +}; + /** * Create a forwarding rule in this region. * @@ -615,6 +813,6 @@ Region.prototype.rule = function(name) { * These methods can be used with either a callback or as a readable object * stream. `streamRouter` is used to add this dual behavior. */ -streamRouter.extend(Region, ['getAddresses', 'getOperations', 'getRules']); +streamRouter.extend(Region, ['getAddresses', 'getOperations', 'getRules', 'getSubnetworks']); module.exports = Region; diff --git a/lib/compute/subnetwork.js b/lib/compute/subnetwork.js new file mode 100644 index 00000000000..32e22593dc1 --- /dev/null +++ b/lib/compute/subnetwork.js @@ -0,0 +1,216 @@ +/*! + * Copyright 2015 Google Inc. All Rights Reserved. + * + * 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. + */ + +/*! + * @module compute/vm + */ + +'use strict'; + +var format = require('string-format-obj'); +var nodeutil = require('util'); + +/** + * @type {module:common/service-object} + * @private + */ +var ServiceObject = require('../common/service-object.js'); + +/** + * @type {module:common/util} + * @private + */ +var util = require('../common/util.js'); + + +/*! Developer Documentation + * + * @param {module:region} region - Region this address belongs to. + * @param {string} name - Name of the subnetwork. + */ +/** + * An Instance object allows you to interact with a Google Compute Engine + * subnetwork. + * + * @resource [Instances and Networks]{@link https://cloud.google.com/compute/docs/instances-and-network} + * @resource [Instance Resource]{@link https://cloud.google.com/compute/docs/reference/v1/subnetworks} + * + * @constructor + * @alias module:compute/subnetwork + * + * @example + * var gcloud = require('gcloud')({ + * keyFilename: '/path/to/keyfile.json', + * projectId: 'grape-spaceship-123' + * }); + * + * var gce = gcloud.compute(); + * + * var region = gce.region('region-name'); + * + * var subnetwork = region.subnetwork('subnetwork1'); + */ +function Subnetwork(region, name) { + this.name = name.replace(/.*\/([^/]+)$/, '$1'); // Just the instance name. + this.region = region; + + // this.url = format('{base}/{project}/regions/{regions}/subnetwork/{name}', { + // base: 'https://www.googleapis.com/compute/v1/projects', + // //project: region.projectId, + // zone: region.name, + // name: this.name + // }); + + var methods = { + /** + * Create a subnetwork. + * + * @param {object} config - See {module:compute/region#createSubnetwork}. + * + * @example + * var config = { + * // ... + * }; + * + * subnetwork.create(config, + * function(err, subnetwork, operation, apiResponse) { + * // `subnetwork` is a Subnetwork object. + * + * // `operation` is an Operation object that can be used to check the + * // status of the request. + * }); + */ + create: true, + + /** + * Check if the subnetwork exists. + * + * @param {function} callback - The callback function. + * @param {?error} callback.err - An error returned while making this + * request. + * @param {boolean} callback.exists - Whether the address exists or not. + * + * @example + * subnetwork.exists(function(err, exists) {}); + */ + exists: true, + + /** + * Get a subnetwork if it exists. + * + * You may optionally use this to "get or create" an object by providing an + * object with `autoCreate` set to `true`. Any extra configuration that is + * normally required for the `create` method must be contained within this + * object as well. + * + * @param {options=} options - Configuration object. + * @param {boolean} options.autoCreate - Automatically create the object if + * it does not exist. Default: `false` + * + * @example + * subnetwork.get(function(err, vm, apiResponse) { + * // `subnetwork` is a Subnetwork object. + * }); + */ + get: true, + + /** + * Get the metadata of this subnetwork. + * + * @resource [Address Resource]{@link https://cloud.google.com/compute/docs/reference/v1/subnetwork} + * @resource [Addresses: get API Documentation]{@link https://cloud.google.com/compute/docs/reference/v1/subnetwork/get} + * + * @param {function=} callback - The callback function. + * @param {?error} callback.err - An error returned while making this + * request. + * @param {object} callback.metadata - The address's metadata. + * @param {object} callback.apiResponse - The full API response. + * + * @example + * subnetwork.getMetadata(function(err, metadata, apiResponse) {}); + */ + getMetadata: true + + }; + + ServiceObject.call(this, { + parent: region, + baseUrl: '/subnetworks', + id: this.name, + createMethod: region.createSubnetwork.bind(region), + methods: methods + }); + + this.formattedName = Subnetwork.formatName_(region, name); +} + +nodeutil.inherits(Subnetwork, ServiceObject); + +/** + * Format a subnetwork's name how the API expects. + * + * @private + * + * @param {module:compute} compute - The Compute object this network belongs to. + * @param {string} name - The name of the network. + * @return {string} - The formatted name. + */ +Subnetwork.formatName_ = function(region, name) { + return format('regions/{region}/subnetworks/{name}', { + region: region.name, + name: name + }); +}; + +/** + * Delete the subnetwork. + * + * @resource [Subnetworks: delete API Documentation]{@link https://cloud.google.com/compute/docs/reference/latest/addresses/delete} + * + * @param {function=} callback - The callback function. + * @param {?error} callback.err - An error returned while making this request. + * @param {module:compute/operation} callback.operation - An operation object + * that can be used to check the status of the request. + * @param {object} callback.apiResponse - The full API response. + * + * @example + * subnetwork.delete(function(err, operation, apiResponse) { + * // `operation` is an Operation object that can be used to check the status + * // of the request. + * }); + */ +Subnetwork.prototype.delete = function(callback) { + callback = callback || util.noop; + + var region = this.region; + + this.request({ + method: 'DELETE', + uri: '' + }, function(err, resp) { + if (err) { + callback(err, null, resp); + return; + } + + var operation = region.operation(resp.name); + operation.metadata = resp; + + callback(null, operation, resp); + }); +}; + +module.exports = Subnetwork; diff --git a/system-test/compute.js b/system-test/compute.js index f0b554de9f3..99f6b174ddc 100644 --- a/system-test/compute.js +++ b/system-test/compute.js @@ -1129,6 +1129,65 @@ describe('Compute', function() { }); }); + describe('subnetworks', function() { + var SUBNETWORK_NAME = generateName('subnetwork'); + var subnetwork = region.subnetwork(SUBNETWORK_NAME); + + var NETWORK_NAME = generateName('network'); + var network = compute.network(NETWORK_NAME); + + var CONFIG = { + autoCreateSubnetworks: false + }; + + + var SUBNETWORK_CONFIG = { + network: 'global/networks/' + NETWORK_NAME, + ipCidrRange: '10.0.1.0/24' + }; + + before(function(done) { + async.series([ + create(network, CONFIG), + create(subnetwork, SUBNETWORK_CONFIG) + ], done); + }); + + it('should have created the subnetwork', function(done) { + subnetwork.getMetadata(function(err, metadata) { + assert.ifError(err); + assert.strictEqual(metadata.name, SUBNETWORK_NAME); + done(); + }); + }); + + it('should get a list of subnetworks', function(done) { + compute.getSubnetworks(function(err, subnetworks) { + assert.ifError(err); + assert(subnetworks.length > 0); + done(); + }); + }); + + it('should get a list of subnetworks in stream mode', function(done) { + var resultsMatched = 0; + + compute.getSubnetworks() + .on('error', done) + .on('data', function() { + resultsMatched++; + }) + .on('end', function() { + assert(resultsMatched > 0); + done(); + }); + }); + + it('should access a subnetwork through a Region', function(done) { + region.subnetwork(SUBNETWORK_NAME).getMetadata(done); + }); + }); + function generateName(customPrefix) { return TESTS_PREFIX + customPrefix + '-' + Date.now(); } @@ -1154,6 +1213,7 @@ describe('Compute', function() { 'getDisks', 'getInstanceGroups', 'getFirewalls', + 'getSubnetworks', 'getHealthChecks', 'getNetworks', 'getRules', diff --git a/test/compute/index.js b/test/compute/index.js index 1367b91560d..77f7c350baf 100644 --- a/test/compute/index.js +++ b/test/compute/index.js @@ -53,6 +53,7 @@ var fakeStreamRouter = { 'getRules', 'getServices', 'getSnapshots', + 'getSubnetworks', 'getVMs', 'getZones' ]); From c064a32434b4bc0b9b383320fa9d5b23c4d6fdd9 Mon Sep 17 00:00:00 2001 From: Ashley Date: Fri, 15 Jul 2016 18:11:49 -0400 Subject: [PATCH 2/5] adding unit tests --- lib/compute/region.js | 3 +- test/compute/index.js | 108 +++++++++++++++++++ test/compute/network.js | 66 ++++++++++++ test/compute/region.js | 213 ++++++++++++++++++++++++++++++++++++- test/compute/subnetwork.js | 186 ++++++++++++++++++++++++++++++++ 5 files changed, 574 insertions(+), 2 deletions(-) create mode 100644 test/compute/subnetwork.js diff --git a/lib/compute/region.js b/lib/compute/region.js index e3b5114e9b5..bc7da548884 100644 --- a/lib/compute/region.js +++ b/lib/compute/region.js @@ -813,6 +813,7 @@ Region.prototype.rule = function(name) { * These methods can be used with either a callback or as a readable object * stream. `streamRouter` is used to add this dual behavior. */ -streamRouter.extend(Region, ['getAddresses', 'getOperations', 'getRules', 'getSubnetworks']); +streamRouter.extend(Region, + ['getAddresses', 'getOperations', 'getRules', 'getSubnetworks']); module.exports = Region; diff --git a/test/compute/index.js b/test/compute/index.js index 77f7c350baf..f54e3cd3313 100644 --- a/test/compute/index.js +++ b/test/compute/index.js @@ -79,6 +79,7 @@ function FakeOperation() { function FakeRegion() { this.calledWith_ = slice.call(arguments); this.address = function() { return {}; }; + this.subnetwork = function() { return {}; }; } function FakeRule() { @@ -1140,6 +1141,113 @@ describe('Compute', function() { }); }); + describe('getSubnetworks', function() { + it('should accept only a callback', function(done) { + compute.request = function(reqOpts) { + assert.deepEqual(reqOpts.qs, {}); + done(); + }; + + compute.getSubnetworks(assert.ifError); + }); + + it('should make the correct API request', function(done) { + var options = {}; + + compute.request = function(reqOpts) { + assert.strictEqual(reqOpts.uri, '/aggregated/subnetworks'); + assert.strictEqual(reqOpts.qs, options); + done(); + }; + + compute.getSubnetworks(options, assert.ifError); + }); + + describe('error', function() { + var error = new Error('Error.'); + var apiResponse = { a: 'b', c: 'd' }; + + beforeEach(function() { + compute.request = function(reqOpts, callback) { + callback(error, apiResponse); + }; + }); + + it('should execute callback with error & API response', function(done) { + compute.getSubnetworks({}, function(err, subnetworks, nextQuery, resp) { + assert.strictEqual(err, error); + assert.strictEqual(subnetworks, null); + assert.strictEqual(nextQuery, null); + assert.strictEqual(resp, apiResponse); + + done(); + }); + }); + }); + + describe('success', function() { + var REGION_NAME = 'region-1'; + var FULL_REGION_NAME = 'regions/' + REGION_NAME; + + var subnetwork = { name: 'subnetwork-1' }; + var apiResponse = { + items: {} + }; + + apiResponse.items[FULL_REGION_NAME] = { + subnetworks: [subnetwork] + }; + + beforeEach(function() { + compute.request = function(reqOpts, callback) { + callback(null, apiResponse); + }; + }); + + it('should create Subnetwork objects from the response', function(done) { + var region = {}; + + compute.region = function(name) { + assert.strictEqual(name, REGION_NAME); + return region; + }; + + region.subnetwork = function(name) { + assert.strictEqual(name, subnetwork.name); + setImmediate(done); + return subnetwork; + }; + + compute.getSubnetworks({}, assert.ifError); + }); + + it('should build a nextQuery if necessary', function(done) { + var apiResponseWithNextPageToken = extend({}, apiResponse, { + nextPageToken: 'next-page-token' + }); + + var query = { a: 'b', c: 'd' }; + var originalQuery = extend({}, query); + + compute.request = function(reqOpts, callback) { + callback(null, apiResponseWithNextPageToken); + }; + + compute.getSubnetworks(query, function(err, subnetworks, nextQuery) { + assert.ifError(err); + + assert.deepEqual(query, originalQuery); + + assert.deepEqual(nextQuery, extend({}, query, { + pageToken: apiResponseWithNextPageToken.nextPageToken + })); + + done(); + }); + }); + }); + }); + describe('getFirewalls', function() { it('should accept only a callback', function(done) { compute.request = function(reqOpts) { diff --git a/test/compute/network.js b/test/compute/network.js index fcc40e55411..5d023ff8d70 100644 --- a/test/compute/network.js +++ b/test/compute/network.js @@ -146,6 +146,26 @@ describe('Network', function() { }); }); + describe('createSubnetwork', function() { + it('should make the correct call to Region', function(done) { + var name = 'subnetwork-name'; + var config = { a: 'b', c: 'd', region: 'region1'}; + var expectedConfig = extend({}, config, { + network: network.formattedName, + name: name + }); + delete expectedConfig.region; + + network.compute.request = function(config_) { + assert.strictEqual(config_.json.name, name); + assert.deepEqual(config_.json, expectedConfig); + done(); + }; + + network.createSubnetwork(name, config, done); + }); + }); + describe('delete', function() { it('should call ServiceObject.delete', function(done) { FakeServiceObject.prototype.delete = function() { @@ -235,6 +255,52 @@ describe('Network', function() { }); }); + describe('getSubnetworks', function() { + it('should make the correct call to Compute', function(done) { + var options = { a: 'b', c: 'd' }; + var expectedOptions = extend({}, options, { + filter: 'network eq .*' + network.formattedName + }); + + network.compute.getSubnetworks = function(options, callback) { + assert.deepEqual(options, expectedOptions); + callback(); + }; + + network.getSubnetworks(options, done); + }); + + it('should not require options', function(done) { + network.compute.getSubnetworks = function(options, callback) { + callback(); + }; + + network.getSubnetworks(done); + }); + + it('should not require any arguments', function(done) { + network.compute.getSubnetworks = function(options, callback) { + assert.deepEqual(options, { + filter: 'network eq .*' + network.formattedName + }); + assert.strictEqual(typeof callback, 'undefined'); + done(); + }; + + network.getSubnetworks(); + }); + + it('should return the result of calling Compute', function() { + var resultOfgetSubnetworks = {}; + + network.compute.getSubnetworks = function() { + return resultOfgetSubnetworks; + }; + + assert.strictEqual(network.getSubnetworks(), resultOfgetSubnetworks); + }); + }); + describe('getFirewalls', function() { it('should make the correct call to Compute', function(done) { var options = { a: 'b', c: 'd' }; diff --git a/test/compute/region.js b/test/compute/region.js index cb4730dd442..366122e4467 100644 --- a/test/compute/region.js +++ b/test/compute/region.js @@ -37,6 +37,10 @@ function FakeRule() { this.calledWith_ = [].slice.call(arguments); } +function FakeSubnetwork() { + this.calledWith_ = [].slice.call(arguments); +} + function FakeServiceObject() { this.calledWith_ = arguments; ServiceObject.apply(this, arguments); @@ -54,7 +58,8 @@ var fakeStreamRouter = { extended = true; methods = arrify(methods); assert.equal(Class.name, 'Region'); - assert.deepEqual(methods, ['getAddresses', 'getOperations', 'getRules']); + assert.deepEqual(methods, + ['getAddresses', 'getOperations', 'getRules', 'getSubnetworks']); } }; @@ -76,6 +81,7 @@ describe('Region', function() { mockery.registerMock('../../lib/compute/address.js', FakeAddress); mockery.registerMock('../../lib/compute/operation.js', FakeOperation); mockery.registerMock('../../lib/compute/rule.js', FakeRule); + mockery.registerMock('../../lib/compute/subnetwork.js', FakeSubnetwork); mockery.enable({ useCleanCache: true, @@ -264,6 +270,97 @@ describe('Region', function() { }); }); + describe('createSubnetwork', function() { + var NAME = 'subnetwork-name'; + var OPTIONS = { a: 'b', c: 'd' }; + var EXPECTED_BODY = extend({}, OPTIONS, { name: NAME }); + + it('should not require any options', function(done) { + var expectedBody = { name: NAME }; + + region.request = function(reqOpts) { + assert.deepEqual(reqOpts.json, expectedBody); + done(); + }; + + region.createSubnetwork(NAME, assert.ifError); + }); + + it('should make the correct API request', function(done) { + region.request = function(reqOpts) { + assert.strictEqual(reqOpts.method, 'POST'); + assert.strictEqual(reqOpts.uri, '/subnetworks'); + assert.deepEqual(reqOpts.json, EXPECTED_BODY); + + done(); + }; + + region.createSubnetwork(NAME, OPTIONS, assert.ifError); + }); + + describe('error', function() { + var error = new Error('Error.'); + var apiResponse = { a: 'b', c: 'd' }; + + beforeEach(function() { + region.request = function(reqOpts, callback) { + callback(error, apiResponse); + }; + }); + + it('should execute callback with error & API response', function(done) { + region.createSubnetwork(NAME, OPTIONS, + function(err, subnetwork_, op, resp) { + assert.strictEqual(err, error); + assert.strictEqual(subnetwork_, null); + assert.strictEqual(op, null); + assert.strictEqual(resp, apiResponse); + done(); + }); + }); + }); + + describe('success', function() { + var apiResponse = { name: 'operation-name' }; + + beforeEach(function() { + region.request = function(reqOpts, callback) { + callback(null, apiResponse); + }; + }); + + it('should exec callback with Subnetwork, Op & apiResponse', + function(done) { + var subnetwork = {}; + var operation = {}; + + region.subnetwork = function(name) { + assert.strictEqual(name, NAME); + return subnetwork; + }; + + region.operation = function(name) { + assert.strictEqual(name, apiResponse.name); + return operation; + }; + + region.createSubnetwork(NAME, OPTIONS, + function(err, subnetwork_, op, resp) { + assert.ifError(err); + + assert.strictEqual(subnetwork_, subnetwork); + + assert.strictEqual(op, operation); + assert.strictEqual(op.metadata, resp); + + assert.strictEqual(resp, apiResponse); + done(); + }); + }); + }); + }); + + describe('getAddresses', function() { it('should accept only a callback', function(done) { region.request = function(reqOpts) { @@ -365,6 +462,109 @@ describe('Region', function() { }); }); + describe('getSubnetworks', function() { + it('should accept only a callback', function(done) { + region.request = function(reqOpts) { + assert.deepEqual(reqOpts.qs, {}); + done(); + }; + + region.getSubnetworks(assert.ifError); + }); + + it('should make the correct API request', function(done) { + var query = { a: 'b', c: 'd' }; + + region.request = function(reqOpts) { + assert.strictEqual(reqOpts.uri, '/subnetworks'); + assert.strictEqual(reqOpts.qs, query); + + done(); + }; + + region.getSubnetworks(query, assert.ifError); + }); + + describe('error', function() { + var error = new Error('Error.'); + var apiResponse = { a: 'b', c: 'd' }; + + beforeEach(function() { + region.request = function(reqOpts, callback) { + callback(error, apiResponse); + }; + }); + + it('should execute callback with error & API response', function(done) { + region.getSubnetworks({}, + function(err, subnetworks, nextQuery, apiResp) { + assert.strictEqual(err, error); + assert.strictEqual(subnetworks, null); + assert.strictEqual(nextQuery, null); + assert.strictEqual(apiResp, apiResponse); + done(); + }); + }); + }); + + describe('success', function() { + var apiResponse = { + items: [ + { name: 'operation-name' } + ] + }; + + beforeEach(function() { + region.request = function(reqOpts, callback) { + callback(null, apiResponse); + }; + }); + + it('should build a nextQuery if necessary', function(done) { + var nextPageToken = 'next-page-token'; + var apiResponseWithNextPageToken = extend({}, apiResponse, { + nextPageToken: nextPageToken + }); + var expectedNextQuery = { + pageToken: nextPageToken + }; + + region.request = function(reqOpts, callback) { + callback(null, apiResponseWithNextPageToken); + }; + + region.getSubnetworks({}, function(err, subnetworks, nextQuery) { + assert.ifError(err); + + assert.deepEqual(nextQuery, expectedNextQuery); + + done(); + }); + }); + + it('should execute callback with Operations & API resp', function(done) { + var subnetwork = {}; + + region.subnetwork = function(name) { + assert.strictEqual(name, apiResponse.items[0].name); + return subnetwork; + }; + + region.getSubnetworks({}, + function(err, subnetworks, nextQuery, apiResp) { + assert.ifError(err); + + assert.strictEqual(subnetworks[0], subnetwork); + assert.strictEqual(subnetworks[0].metadata, apiResponse.items[0]); + + assert.strictEqual(apiResp, apiResponse); + + done(); + }); + }); + }); + }); + describe('getOperations', function() { it('should accept only a callback', function(done) { region.request = function(reqOpts) { @@ -567,6 +767,17 @@ describe('Region', function() { }); }); + describe('subnetwork', function() { + var NAME = 'subnetwork-name'; + + it('should return a Subnetwork object', function() { + var subnetwork = region.subnetwork(NAME); + assert(subnetwork instanceof FakeSubnetwork); + assert.strictEqual(subnetwork.calledWith_[0], region); + assert.strictEqual(subnetwork.calledWith_[1], NAME); + }); + }); + describe('operation', function() { var NAME = 'operation-name'; diff --git a/test/compute/subnetwork.js b/test/compute/subnetwork.js new file mode 100644 index 00000000000..6fc2df1dea5 --- /dev/null +++ b/test/compute/subnetwork.js @@ -0,0 +1,186 @@ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * 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 assert = require('assert'); +var extend = require('extend'); +var format = require('string-format-obj'); +var mockery = require('mockery-next'); +var nodeutil = require('util'); + +var ServiceObject = require('../../lib/common/service-object.js'); +var util = require('../../lib/common/util.js'); + +function FakeServiceObject() { + this.calledWith_ = arguments; + ServiceObject.apply(this, arguments); +} + +nodeutil.inherits(FakeServiceObject, ServiceObject); + +describe('Subnetwork', function() { + var Subnetwork; + var subnetwork; + + var SUBNETWORK_NAME = 'subnetwork_name'; + var REGION_NAME = 'region-1'; + var REGION = { + createSubnetwork: util.noop, + name: REGION_NAME + }; + var SUBNETWORK_FULL_NAME = format('regions/{region}/subnetworks/{name}', { + region: REGION_NAME, + name: SUBNETWORK_NAME + }); + + before(function() { + mockery.registerMock( + '../../lib/common/service-object.js', + FakeServiceObject + ); + mockery.enable({ + useCleanCache: true, + warnOnUnregistered: false + }); + + Subnetwork = require('../../lib/compute/subnetwork.js'); + }); + + after(function() { + mockery.deregisterAll(); + mockery.disable(); + }); + + beforeEach(function() { + subnetwork = new Subnetwork(REGION, SUBNETWORK_NAME); + }); + + describe('instantiation', function() { + it('should localize the region', function() { + assert.strictEqual(subnetwork.region, REGION); + }); + + it('should localize the name', function() { + assert.strictEqual(subnetwork.name, SUBNETWORK_NAME); + }); + + it('should inherit from ServiceObject', function(done) { + var regionInstance = extend({}, REGION, { + createSubnetwork: { + bind: function(context) { + assert.strictEqual(context, regionInstance); + done(); + } + } + }); + + var subnetwork = new Subnetwork(regionInstance, SUBNETWORK_NAME); + assert(subnetwork instanceof ServiceObject); + + var calledWith = subnetwork.calledWith_[0]; + + assert.strictEqual(calledWith.parent, regionInstance); + assert.strictEqual(calledWith.baseUrl, '/subnetworks'); + assert.strictEqual(calledWith.id, SUBNETWORK_NAME); + assert.deepEqual(calledWith.methods, { + create: true, + exists: true, + get: true, + getMetadata: true + }); + }); + }); + + describe('formatName_', function() { + it('should format the name', function() { + var formattedName_ = Subnetwork.formatName_(REGION, SUBNETWORK_NAME); + assert.strictEqual(formattedName_, SUBNETWORK_FULL_NAME); + }); + }); + + describe('delete', function() { + it('should make the correct API request', function(done) { + subnetwork.request = function(reqOpts) { + assert.strictEqual(reqOpts.method, 'DELETE'); + assert.strictEqual(reqOpts.uri, ''); + done(); + }; + + subnetwork.delete(assert.ifError); + }); + + describe('error', function() { + var error = new Error('Error.'); + var apiResponse = { a: 'b', c: 'd' }; + + beforeEach(function() { + subnetwork.request = function(reqOpts, callback) { + callback(error, apiResponse); + }; + }); + + it('should return an error if the request fails', function(done) { + subnetwork.delete(function(err, operation, apiResponse_) { + assert.strictEqual(err, error); + assert.strictEqual(operation, null); + assert.strictEqual(apiResponse_, apiResponse); + done(); + }); + }); + + it('should not require a callback', function() { + assert.doesNotThrow(function() { + subnetwork.delete(); + }); + }); + }); + + describe('success', function() { + var apiResponse = { + name: 'op-name' + }; + + beforeEach(function() { + subnetwork.request = function(reqOpts, callback) { + callback(null, apiResponse); + }; + }); + + it('should execute callback with Operation & Response', function(done) { + var operation = {}; + + subnetwork.region.operation = function(name) { + assert.strictEqual(name, apiResponse.name); + return operation; + }; + + subnetwork.delete(function(err, operation_, apiResponse_) { + assert.ifError(err); + assert.strictEqual(operation_, operation); + assert.strictEqual(apiResponse_, apiResponse); + done(); + }); + }); + + it('should not require a callback', function() { + assert.doesNotThrow(function() { + subnetwork.delete(); + }); + }); + }); + }); +}); From df4ac67609681cb665d7fb97bf00254c38fb99f3 Mon Sep 17 00:00:00 2001 From: Ashley Date: Tue, 19 Jul 2016 15:32:07 -0400 Subject: [PATCH 3/5] made changes --- lib/compute/index.js | 6 +-- lib/compute/network.js | 62 +++++++++++++++++------------- lib/compute/region.js | 79 +++++++++++++++++++++++---------------- lib/compute/subnetwork.js | 43 +++++++++------------ test/compute/network.js | 20 +++++++++- test/compute/region.js | 11 ------ 6 files changed, 121 insertions(+), 100 deletions(-) diff --git a/lib/compute/index.js b/lib/compute/index.js index 40970857831..f70c055b3ba 100644 --- a/lib/compute/index.js +++ b/lib/compute/index.js @@ -1166,7 +1166,7 @@ Compute.prototype.getFirewalls = function(options, callback) { * Get a list of subnetworks in this project. * * @resource [Subnetworks Overview]{@link https://cloud.google.com/compute/docs/subnetworks} - * @resource [Subnetworks: list API Documentation]{@link https://cloud.google.com/compute/docs/reference/latest/subnetworks} + * @resource [Subnetworks: list API Documentation]{@link https://cloud.google.com/compute/docs/reference/v1/subnetworks} * * @param {object=} options - Subnetwork search options. * @param {boolean} options.autoPaginate - Have pagination handled @@ -1179,7 +1179,7 @@ Compute.prototype.getFirewalls = function(options, callback) { * - **`filterString`**: the string to filter to. For string fields, this * can be a regular expression. * @param {number} options.maxApiCalls - Maximum number of API calls to make. - * @param {number} options.maxResults - Maximum number of firewalls to return. + * @param {number} options.maxResults - Maximum number of subnetworks to return. * @param {string} options.pageToken - A previously-returned page token * representing part of the larger set of results to view. * @param {function} callback - The callback function. @@ -1211,7 +1211,7 @@ Compute.prototype.getFirewalls = function(options, callback) { * }, callback); * * //- - * // Get the firewalls from your project as a readable object stream. + * // Get the subnetworks from your project as a readable object stream. * //- * gce.getSubnetworks() * .on('error', console.error) diff --git a/lib/compute/network.js b/lib/compute/network.js index 70bb5647d9c..f61fa54c392 100644 --- a/lib/compute/network.js +++ b/lib/compute/network.js @@ -229,17 +229,16 @@ Network.prototype.createFirewall = function(name, config, callback) { * @param {string} name - Name of the subnetwork. * @param {object} config - See a * [Subnetwork resource](https://cloud.google.com/compute/docs/reference/v1/subnetworks#resource). - * @param {string=} config.description - An optional description of this - * resource. Provide this property when you create the resource. - * @param {string} config.ipCidrRange - The range of internal addresses that - * are owned by this subnetwork. Provide this property when you create the - * subnetwork. For example, 10.0.0.0/8 or 192.168.0.0/16. Ranges must be - * unique and non-overlapping within a network. - * @param {string} config.region - URL of the region where the Subnetwork - * resides. + * @param {module:compute/region|string} config.region - The region where the + * Subnetwork resides. + * @param {string} config.range - The range of internal addresses that + * are owned by this subnetwork. [CIDR](http://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing) range + * of addresses that are legal on this network. (Alias for + * `config.ipCidrRange`) * @param {function} callback - The callback function. * @param {?error} callback.err - An error returned while making this request. - * @param {module:compute/rule} callback.rule - The created Rule object. + * @param {module:compute/subnetwork} callback.subnetwork - The created + * Subnetwork object. * @param {module:compute/operation} callback.operation - An operation object * that can be used to check the status of the request. * @param {object} callback.apiResponse - The full API response. @@ -248,24 +247,31 @@ Network.prototype.createFirewall = function(name, config, callback) { * var name = 'new-subnetwork-name'; * * var config = { - * region : 'regions/us-east1', - * ipCidrRange: '10.0.1.0/24' + * region : 'us-east1', + * range: '10.0.1.0/24' * }; * - * network.createSubnetwork(name, config, - * function (err, subnetwork, operation, apiResponse) { + * function callback(err, subnetwork, operation, apiResponse) { * // `subnetwork` is a Subnetwork object. * * // `operation` is an Operation object that can be used to check the status * // of the request. * }); + * + * network.createSubnetwork(name, config, callback); */ Network.prototype.createSubnetwork = function(name, config, callback) { config = extend({}, config, { network: this.formattedName }); - var region = new Region(this.compute, config.region); + var region; + + if (config.region instanceof Region) { + region = config.region; + } else { + region = this.compute.region(config.region); + } delete config.region; return region.createSubnetwork(name, config, callback); @@ -273,8 +279,9 @@ Network.prototype.createSubnetwork = function(name, config, callback) { /** * Get a list of subnetworks in this network. - * * @resource [Subnetworks Overview]{@link https://cloud.google.com/compute/docs/subnetworks} - * @resource [Subnetworks: list API Documentation]{@link https://cloud.google.com/compute/docs/reference/latest/subnetworks} + * + * @resource [Subnetworks Overview]{@link https://cloud.google.com/compute/docs/subnetworks} + * @resource [Subnetworks: list API Documentation]{@link https://cloud.google.com/compute/docs/reference/v1/subnetworks} * * @param {object=} options - Subnetwork search options. * @param {boolean} options.autoPaginate - Have pagination handled @@ -287,19 +294,19 @@ Network.prototype.createSubnetwork = function(name, config, callback) { * - **`filterString`**: the string to filter to. For string fields, this * can be a regular expression. * @param {number} options.maxApiCalls - Maximum number of API calls to make. - * @param {number} options.maxResults - Maximum number of firewalls to return. + * @param {number} options.maxResults - Maximum number of subnetworks to return. * @param {string} options.pageToken - A previously-returned page token * representing part of the larger set of results to view. * @param {function} callback - The callback function. * @param {?error} callback.err - An error returned while making this request. - * @param {module:compute/firewall} callback.subnetworks - Subnetwork objects - * from your project. + * @param {module:compute/subnetwork} callback.subnetworks - Subnetwork objects + * from this network. * @param {?object} callback.nextQuery - If present, query with this object to * check for more results. * @param {object} callback.apiResponse - The full API response. * * @example - * gce.getSubnetworks(function(err, subnetworks) { + * network.getSubnetworks(function(err, subnetworks) { * // `subnetworks` is an array of `Subnetworks` objects. * }); * @@ -310,30 +317,31 @@ Network.prototype.createSubnetwork = function(name, config, callback) { * function callback(err, subnetworks, nextQuery, apiResponse) { * if (nextQuery) { * // More results exist. - * gce.getSubnetworks(nextQuery, callback); + * network.getSubnetworks(nextQuery, callback); * } * } * - * gce.getSubnetworks({ + * network.getSubnetworks({ * autoPaginate: false * }, callback); - * * //- - * // Get the firewalls from your project as a readable object stream. + * * //- - * gce.getSubnetworks() + * // Get the subnetworks from this network as a readable object stream. + * //- + * network.getSubnetworks() * .on('error', console.error) * .on('data', function(subnetwork) { * // `subnetwork` is a `Subnetwork` object. * }) * .on('end', function() { - * // All firewalls retrieved. + * // All subnetworks retrieved. * }); * * //- * // If you anticipate many results, you can end a stream early to prevent * // unnecessary processing and API requests. * //- - * gce.getSubnetworks() + * network.getSubnetworks() * .on('data', function(subnetwork) { * this.end(); * }); diff --git a/lib/compute/region.js b/lib/compute/region.js index bc7da548884..2092c60a825 100644 --- a/lib/compute/region.js +++ b/lib/compute/region.js @@ -30,6 +30,12 @@ var nodeutil = require('util'); */ var Address = require('./address.js'); +/** + * @type {module:compute/network} + * @private + */ +var Network = require('./network.js'); + /** * @type {module:compute/operation} * @private @@ -224,7 +230,7 @@ Region.prototype.createAddress = function(name, options, callback) { * Get a list of subnetworks in this region. * * @resource [Subnetworks Overview]{@link https://cloud.google.com/compute/docs/subnetworks} - * @resource [Subnetworks: list API Documentation]{@link https://cloud.google.com/compute/docs/reference/latest/subnetworks} + * @resource [Subnetworks: list API Documentation]{@link https://cloud.google.com/compute/docs/reference/v1/subnetworks} * * @param {object=} options - Subnetwork search options. * @param {boolean} options.autoPaginate - Have pagination handled @@ -237,20 +243,20 @@ Region.prototype.createAddress = function(name, options, callback) { * - **`filterString`**: the string to filter to. For string fields, this * can be a regular expression. * @param {number} options.maxApiCalls - Maximum number of API calls to make. - * @param {number} options.maxResults - Maximum number of firewalls to return. + * @param {number} options.maxResults - Maximum number of subnetworks to return. * @param {string} options.pageToken - A previously-returned page token * representing part of the larger set of results to view. * @param {function} callback - The callback function. * @param {?error} callback.err - An error returned while making this request. * @param {module:compute/subnetworks} callback.subnetworks - Subnetwork objects - * from your project. + * from this region. * @param {?object} callback.nextQuery - If present, query with this object to * check for more results. * @param {object} callback.apiResponse - The full API response. * * @example - * gce.getSubnetworks(function(err, subnetworks) { - * // `subnetworks` is an array of `Subnetworks` objects. + * region.getSubnetworks(function(err, subnetworks) { + * // `subnetworks` is an array of `Subnetwork` objects. * }); * * //- @@ -260,18 +266,18 @@ Region.prototype.createAddress = function(name, options, callback) { * function callback(err, subnetworks, nextQuery, apiResponse) { * if (nextQuery) { * // More results exist. - * gce.getSubnetworks(nextQuery, callback); + * region.getSubnetworks(nextQuery, callback); * } * } * - * gce.getSubnetworks({ + * region.getSubnetworks({ * autoPaginate: false * }, callback); * * //- - * // Get the firewalls from your project as a readable object stream. + * // Get the subnetworks from this region as a readable object stream. * //- - * gce.getSubnetworks() + * region.getSubnetworks() * .on('error', console.error) * .on('data', function(subnetwork) { * // `subnetwork` is a `Subnetwork` object. @@ -284,7 +290,7 @@ Region.prototype.createAddress = function(name, options, callback) { * // If you anticipate many results, you can end a stream early to prevent * // unnecessary processing and API requests. * //- - * gce.getSubnetworks() + * region.getSubnetworks() * .on('data', function(subnetwork) { * this.end(); * }); @@ -327,9 +333,9 @@ Region.prototype.getSubnetworks = function(options, callback) { }; /** - * Get a reference to a Google Compute Engine address in this region. + * Get a reference to a Google Compute Engine subnetwork in this region. * - * @resource [Instances and Networks]{@link https://cloud.google.com/compute/docs/instances-and-network} + * @resource [Instances and Networks]{@link https://cloud.google.com/compute/docs/subnetworks} * * @param {string} name - Name of the subnetwork. * @return {module:compute/subnetwork} @@ -350,21 +356,17 @@ Region.prototype.subnetwork = function(name) { * @param {string} name - Name of the subnetwork. * @param {object} config - See a * [Subnetwork resource](https://cloud.google.com/compute/docs/reference/v1/subnetworks#resource). - * @param {string=} config.description - An optional description of this - * resource. Provide this property when you create the resource. - * @param {string} config.ipCidrRange - The range of internal addresses that - * are owned by this subnetwork. Provide this property when you create the - * subnetwork. For example, 10.0.0.0/8 or 192.168.0.0/16. Ranges must be - * unique and non-overlapping within a network. - * @param {string} config.network - The URL of the network to which this - * subnetwork belongs, provided by the client when initially creating - * the subnetwork. Only networks that are in the distributed mode can have - * subnetworks. - * @param {string=} config.region - URL of the region where the Subnetwork - * resides. + * @param {string} config.range - The range of internal addresses that + * are owned by this subnetwork. [CIDR](http://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing) range + * of addresses that are legal on this network. (Alias for + * `config.ipCidrRange`) + * @param {module:compute/network|string} config.network - The network to which + * this subnetwork belongs. **Only networks that are in the distributed mode + * can have subnetworks.** * @param {function} callback - The callback function. * @param {?error} callback.err - An error returned while making this request. - * @param {module:compute/rule} callback.rule - The created Rule object. + * @param {module:compute/subnetwork} callback.subnetwork - The created + * Subnetwork object. * @param {module:compute/operation} callback.operation - An operation object * that can be used to check the status of the request. * @param {object} callback.apiResponse - The full API response. @@ -374,16 +376,17 @@ Region.prototype.subnetwork = function(name) { * * var config = { * network : 'global/networks/network-name', - * ipCidrRange: '10.0.1.0/24' + * range: '10.0.1.0/24' * }; * - * region.createSubnetwork(name, config, - * function (err, subnetwork, operation, apiResponse) { + * function callback(err, subnetwork, operation, apiResponse) { * // `subnetwork` is a Subnetwork object. * * // `operation` is an Operation object that can be used to check the status * // of the request. - * }); + * } + * + * region.createSubnetwork(name, config, callback); */ Region.prototype.createSubnetwork = function(name, config, callback) { var self = this; @@ -392,12 +395,20 @@ Region.prototype.createSubnetwork = function(name, config, callback) { name: name }); + if (body.network instanceof Network) { + body.network = body.network.formattedName; + } + + if (body.range) { + body.ipCidrRange = body.range; + delete body.range; + } + this.request({ method: 'POST', uri: '/subnetworks', json: body }, function(err, resp) { - console.log(resp); if (err) { callback(err, null, null, resp); return; @@ -813,7 +824,11 @@ Region.prototype.rule = function(name) { * These methods can be used with either a callback or as a readable object * stream. `streamRouter` is used to add this dual behavior. */ -streamRouter.extend(Region, - ['getAddresses', 'getOperations', 'getRules', 'getSubnetworks']); +streamRouter.extend(Region, [ + 'getAddresses', + 'getOperations', + 'getRules', + 'getSubnetworks' +]); module.exports = Region; diff --git a/lib/compute/subnetwork.js b/lib/compute/subnetwork.js index 32e22593dc1..e8861bafd4a 100644 --- a/lib/compute/subnetwork.js +++ b/lib/compute/subnetwork.js @@ -1,5 +1,5 @@ /*! - * Copyright 2015 Google Inc. All Rights Reserved. + * Copyright 2016 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,7 @@ */ /*! - * @module compute/vm + * @module compute/subnetwork */ 'use strict'; @@ -38,15 +38,15 @@ var util = require('../common/util.js'); /*! Developer Documentation * - * @param {module:region} region - Region this address belongs to. + * @param {module:region} region - Region this subnetwork belongs to. * @param {string} name - Name of the subnetwork. */ /** - * An Instance object allows you to interact with a Google Compute Engine + * An Subnetwork object allows you to interact with a Google Compute Engine * subnetwork. * - * @resource [Instances and Networks]{@link https://cloud.google.com/compute/docs/instances-and-network} - * @resource [Instance Resource]{@link https://cloud.google.com/compute/docs/reference/v1/subnetworks} + * @resource [Subnetworks]{@link https://cloud.google.com/compute/docs/subnetworks} + * @resource [Subnetwork Resource]{@link https://cloud.google.com/compute/docs/reference/v1/subnetworks} * * @constructor * @alias module:compute/subnetwork @@ -64,16 +64,9 @@ var util = require('../common/util.js'); * var subnetwork = region.subnetwork('subnetwork1'); */ function Subnetwork(region, name) { - this.name = name.replace(/.*\/([^/]+)$/, '$1'); // Just the instance name. + this.name = name; this.region = region; - // this.url = format('{base}/{project}/regions/{regions}/subnetwork/{name}', { - // base: 'https://www.googleapis.com/compute/v1/projects', - // //project: region.projectId, - // zone: region.name, - // name: this.name - // }); - var methods = { /** * Create a subnetwork. @@ -85,13 +78,14 @@ function Subnetwork(region, name) { * // ... * }; * - * subnetwork.create(config, * function(err, subnetwork, operation, apiResponse) { * // `subnetwork` is a Subnetwork object. * * // `operation` is an Operation object that can be used to check the * // status of the request. - * }); + * } + * + * subnetwork.create(config, callback); */ create: true, @@ -101,7 +95,7 @@ function Subnetwork(region, name) { * @param {function} callback - The callback function. * @param {?error} callback.err - An error returned while making this * request. - * @param {boolean} callback.exists - Whether the address exists or not. + * @param {boolean} callback.exists - Whether the subnetwork exists or not. * * @example * subnetwork.exists(function(err, exists) {}); @@ -121,7 +115,7 @@ function Subnetwork(region, name) { * it does not exist. Default: `false` * * @example - * subnetwork.get(function(err, vm, apiResponse) { + * subnetwork.get(function(err, subnetwork, apiResponse) { * // `subnetwork` is a Subnetwork object. * }); */ @@ -130,20 +124,19 @@ function Subnetwork(region, name) { /** * Get the metadata of this subnetwork. * - * @resource [Address Resource]{@link https://cloud.google.com/compute/docs/reference/v1/subnetwork} - * @resource [Addresses: get API Documentation]{@link https://cloud.google.com/compute/docs/reference/v1/subnetwork/get} + * @resource [Subnetwork Resource]{@link https://cloud.google.com/compute/docs/reference/v1/subnetwork} + * @resource [Subnetwork: get API Documentation]{@link https://cloud.google.com/compute/docs/reference/v1/subnetwork/get} * * @param {function=} callback - The callback function. * @param {?error} callback.err - An error returned while making this * request. - * @param {object} callback.metadata - The address's metadata. + * @param {object} callback.metadata - The subnetwork's metadata. * @param {object} callback.apiResponse - The full API response. * * @example * subnetwork.getMetadata(function(err, metadata, apiResponse) {}); */ getMetadata: true - }; ServiceObject.call(this, { @@ -164,8 +157,8 @@ nodeutil.inherits(Subnetwork, ServiceObject); * * @private * - * @param {module:compute} compute - The Compute object this network belongs to. - * @param {string} name - The name of the network. + * @param {module:region} region - The Region object this subnetwork belongs to. + * @param {string} name - The name of the subnetwork. * @return {string} - The formatted name. */ Subnetwork.formatName_ = function(region, name) { @@ -178,7 +171,7 @@ Subnetwork.formatName_ = function(region, name) { /** * Delete the subnetwork. * - * @resource [Subnetworks: delete API Documentation]{@link https://cloud.google.com/compute/docs/reference/latest/addresses/delete} + * @resource [Subnetworks: delete API Documentation]{@link https://cloud.google.com/compute/docs/reference/v1/subnetworks/delete} * * @param {function=} callback - The callback function. * @param {?error} callback.err - An error returned while making this request. diff --git a/test/compute/network.js b/test/compute/network.js index 5d023ff8d70..cda603e0744 100644 --- a/test/compute/network.js +++ b/test/compute/network.js @@ -36,6 +36,9 @@ describe('Network', function() { var Network; var network; + var REGION; + var Region; + var COMPUTE = { projectId: 'project-id', createNetwork: util.noop @@ -45,6 +48,7 @@ describe('Network', function() { pId: COMPUTE.projectId, name: NETWORK_NAME }); + var REGION_NAME = 'region-name'; before(function() { mockery.registerMock( @@ -57,6 +61,7 @@ describe('Network', function() { }); Network = require('../../lib/compute/network.js'); + Region = require('../../lib/compute/region.js'); }); after(function() { @@ -66,6 +71,7 @@ describe('Network', function() { beforeEach(function() { network = new Network(COMPUTE, NETWORK_NAME); + REGION = new Region(COMPUTE, REGION_NAME); }); describe('instantiation', function() { @@ -147,15 +153,25 @@ describe('Network', function() { }); describe('createSubnetwork', function() { - it('should make the correct call to Region', function(done) { + it('should makes the correct call to Region', function(done) { var name = 'subnetwork-name'; - var config = { a: 'b', c: 'd', region: 'region1'}; + var region = {}; + var config = { a: 'b', c: 'd', region: REGION_NAME}; var expectedConfig = extend({}, config, { network: network.formattedName, name: name }); delete expectedConfig.region; + network.compute.region = function(name_) { + assert.strictEqual(name_, REGION_NAME); + return region; + }; + + region.createSubnetwork = function(name_, config_, callback){ + callback(); + }; + network.compute.request = function(config_) { assert.strictEqual(config_.json.name, name); assert.deepEqual(config_.json, expectedConfig); diff --git a/test/compute/region.js b/test/compute/region.js index 366122e4467..f1e40b73015 100644 --- a/test/compute/region.js +++ b/test/compute/region.js @@ -275,17 +275,6 @@ describe('Region', function() { var OPTIONS = { a: 'b', c: 'd' }; var EXPECTED_BODY = extend({}, OPTIONS, { name: NAME }); - it('should not require any options', function(done) { - var expectedBody = { name: NAME }; - - region.request = function(reqOpts) { - assert.deepEqual(reqOpts.json, expectedBody); - done(); - }; - - region.createSubnetwork(NAME, assert.ifError); - }); - it('should make the correct API request', function(done) { region.request = function(reqOpts) { assert.strictEqual(reqOpts.method, 'POST'); From 54de7d6b7dc584735be6549ab15c7795277a13bc Mon Sep 17 00:00:00 2001 From: Stephen Sawchuk Date: Wed, 20 Jul 2016 08:49:32 -0400 Subject: [PATCH 4/5] tests refactor --- docs/toc.json | 3 + lib/compute/index.js | 231 +++++++++++++++++----------------- lib/compute/network.js | 28 ++--- lib/compute/region.js | 250 ++++++++++++++++++------------------- lib/compute/subnetwork.js | 23 +--- system-test/compute.js | 35 ++++-- test/compute/index.js | 224 +++++++++++++++++---------------- test/compute/network.js | 73 +++++------ test/compute/region.js | 163 ++++++++++++------------ test/compute/subnetwork.js | 28 ++--- test/docs.js | 6 +- 11 files changed, 532 insertions(+), 532 deletions(-) diff --git a/docs/toc.json b/docs/toc.json index dcbdc7537fe..fbd147aaaca 100644 --- a/docs/toc.json +++ b/docs/toc.json @@ -101,6 +101,9 @@ }, { "title": "Snapshot", "type": "compute/snapshot" + }, { + "title": "Subnetwork", + "type": "compute/subnetwork" }, { "title": "VM", "type": "compute/vm" diff --git a/lib/compute/index.js b/lib/compute/index.js index f70c055b3ba..90faf1a42d5 100644 --- a/lib/compute/index.js +++ b/lib/compute/index.js @@ -1162,122 +1162,6 @@ Compute.prototype.getFirewalls = function(options, callback) { }); }; -/** - * Get a list of subnetworks in this project. - * - * @resource [Subnetworks Overview]{@link https://cloud.google.com/compute/docs/subnetworks} - * @resource [Subnetworks: list API Documentation]{@link https://cloud.google.com/compute/docs/reference/v1/subnetworks} - * - * @param {object=} options - Subnetwork search options. - * @param {boolean} options.autoPaginate - Have pagination handled - * automatically. Default: true. - * @param {string} options.filter - Search filter in the format of - * `{name} {comparison} {filterString}`. - * - **`name`**: the name of the field to compare - * - **`comparison`**: the comparison operator, `eq` (equal) or `ne` - * (not equal) - * - **`filterString`**: the string to filter to. For string fields, this - * can be a regular expression. - * @param {number} options.maxApiCalls - Maximum number of API calls to make. - * @param {number} options.maxResults - Maximum number of subnetworks to return. - * @param {string} options.pageToken - A previously-returned page token - * representing part of the larger set of results to view. - * @param {function} callback - The callback function. - * @param {?error} callback.err - An error returned while making this request. - * @param {module:compute/subnetwork} callback.subnetworks - Subnetwork objects - * from your project. - * @param {?object} callback.nextQuery - If present, query with this object to - * check for more results. - * @param {object} callback.apiResponse - The full API response. - * - * @example - * gce.getSubnetworks(function(err, subnetworks) { - * // `subnetworks` is an array of `Subnetworks` objects. - * }); - * - * //- - * // To control how many API requests are made and page through the results - * // manually, set `autoPaginate` to `false`. - * //- - * function callback(err, subnetworks, nextQuery, apiResponse) { - * if (nextQuery) { - * // More results exist. - * gce.getSubnetworks(nextQuery, callback); - * } - * } - * - * gce.getSubnetworks({ - * autoPaginate: false - * }, callback); - * - * //- - * // Get the subnetworks from your project as a readable object stream. - * //- - * gce.getSubnetworks() - * .on('error', console.error) - * .on('data', function(subnetwork) { - * // `subnetwork` is a `Subnetwork` object. - * }) - * .on('end', function() { - * // All subnetworks retrieved. - * }); - * - * //- - * // If you anticipate many results, you can end a stream early to prevent - * // unnecessary processing and API requests. - * //- - * gce.getSubnetworks() - * .on('data', function(subnetwork) { - * this.end(); - * }); - */ -Compute.prototype.getSubnetworks = function(options, callback) { - var self = this; - - if (is.fn(options)) { - callback = options; - options = {}; - } - - options = options || {}; - - this.request({ - uri: '/aggregated/subnetworks', - qs: options - }, function(err, resp) { - - if (err) { - callback(err, null, null, resp); - return; - } - - var nextQuery = null; - - if (resp.nextPageToken) { - nextQuery = extend({}, options, { - pageToken: resp.nextPageToken - }); - } - - var regions = resp.items || {}; - - var subnetworks = Object.keys(regions).reduce(function(acc, regionName) { - var region = self.region(regionName.replace('regions/', '')); - var subnetworks = regions[regionName].subnetworks || []; - - subnetworks.forEach(function(subnetwork) { - var subnetworkInstance = region.subnetwork(subnetwork.name); - subnetworkInstance.metadata = subnetwork; - acc.push(subnetworkInstance); - }); - - return acc; - }, []); - - callback(null, subnetworks, nextQuery, resp); - }); -}; - /** * Get a list of health checks. * @@ -2024,6 +1908,121 @@ Compute.prototype.getSnapshots = function(options, callback) { }); }; +/** + * Get a list of subnetworks in this project. + * + * @resource [Subnetworks Overview]{@link https://cloud.google.com/compute/docs/subnetworks} + * @resource [Subnetworks: list API Documentation]{@link https://cloud.google.com/compute/docs/reference/v1/subnetworks} + * + * @param {object=} options - Subnetwork search options. + * @param {boolean} options.autoPaginate - Have pagination handled + * automatically. Default: true. + * @param {string} options.filter - Search filter in the format of + * `{name} {comparison} {filterString}`. + * - **`name`**: the name of the field to compare + * - **`comparison`**: the comparison operator, `eq` (equal) or `ne` + * (not equal) + * - **`filterString`**: the string to filter to. For string fields, this + * can be a regular expression. + * @param {number} options.maxApiCalls - Maximum number of API calls to make. + * @param {number} options.maxResults - Maximum number of subnetworks to return. + * @param {string} options.pageToken - A previously-returned page token + * representing part of the larger set of results to view. + * @param {function} callback - The callback function. + * @param {?error} callback.err - An error returned while making this request. + * @param {module:compute/subnetwork} callback.subnetworks - Subnetwork objects + * from your project. + * @param {?object} callback.nextQuery - If present, query with this object to + * check for more results. + * @param {object} callback.apiResponse - The full API response. + * + * @example + * gce.getSubnetworks(function(err, subnetworks) { + * // `subnetworks` is an array of `Subnetworks` objects. + * }); + * + * //- + * // To control how many API requests are made and page through the results + * // manually, set `autoPaginate` to `false`. + * //- + * function callback(err, subnetworks, nextQuery, apiResponse) { + * if (nextQuery) { + * // More results exist. + * gce.getSubnetworks(nextQuery, callback); + * } + * } + * + * gce.getSubnetworks({ + * autoPaginate: false + * }, callback); + * + * //- + * // Get the subnetworks from your project as a readable object stream. + * //- + * gce.getSubnetworks() + * .on('error', console.error) + * .on('data', function(subnetwork) { + * // `subnetwork` is a `Subnetwork` object. + * }) + * .on('end', function() { + * // All subnetworks retrieved. + * }); + * + * //- + * // If you anticipate many results, you can end a stream early to prevent + * // unnecessary processing and API requests. + * //- + * gce.getSubnetworks() + * .on('data', function(subnetwork) { + * this.end(); + * }); + */ +Compute.prototype.getSubnetworks = function(options, callback) { + var self = this; + + if (is.fn(options)) { + callback = options; + options = {}; + } + + options = options || {}; + + this.request({ + uri: '/aggregated/subnetworks', + qs: options + }, function(err, resp) { + if (err) { + callback(err, null, null, resp); + return; + } + + var nextQuery = null; + + if (resp.nextPageToken) { + nextQuery = extend({}, options, { + pageToken: resp.nextPageToken + }); + } + + var regions = resp.items || {}; + + var subnetworks = Object.keys(regions).reduce(function(acc, regionName) { + var region = self.region(regionName.replace('regions/', '')); + var subnetworks = regions[regionName].subnetworks || []; + + subnetworks.forEach(function(subnetwork) { + var subnetworkInstance = region.subnetwork(subnetwork.name); + subnetworkInstance.metadata = subnetwork; + acc.push(subnetworkInstance); + }); + + return acc; + }, []); + + callback(null, subnetworks, nextQuery, resp); + }); +}; + /** * Get a list of virtual machine instances. * diff --git a/lib/compute/network.js b/lib/compute/network.js index f61fa54c392..e62b95dd4f7 100644 --- a/lib/compute/network.js +++ b/lib/compute/network.js @@ -37,12 +37,6 @@ var ServiceObject = require('../common/service-object.js'); */ var util = require('../common/util.js'); -/** - * @type {module:compute/region} - * @private - */ -var Region = require('./region.js'); - /*! Developer Documentation * * @param {module:compute} compute - The Compute module this network belongs to. @@ -232,7 +226,8 @@ Network.prototype.createFirewall = function(name, config, callback) { * @param {module:compute/region|string} config.region - The region where the * Subnetwork resides. * @param {string} config.range - The range of internal addresses that - * are owned by this subnetwork. [CIDR](http://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing) range + * are owned by this subnetwork. + * [CIDR](http://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing) range * of addresses that are legal on this network. (Alias for * `config.ipCidrRange`) * @param {function} callback - The callback function. @@ -244,10 +239,10 @@ Network.prototype.createFirewall = function(name, config, callback) { * @param {object} callback.apiResponse - The full API response. * * @example - * var name = 'new-subnetwork-name'; + * var region = gce.region('us-east1'); * * var config = { - * region : 'us-east1', + * region: region, * range: '10.0.1.0/24' * }; * @@ -256,25 +251,24 @@ Network.prototype.createFirewall = function(name, config, callback) { * * // `operation` is an Operation object that can be used to check the status * // of the request. - * }); + * } * - * network.createSubnetwork(name, config, callback); + * network.createSubnetwork('new-subnetwork-name', config, callback); */ Network.prototype.createSubnetwork = function(name, config, callback) { config = extend({}, config, { network: this.formattedName }); - var region; + var region = config.region; - if (config.region instanceof Region) { - region = config.region; - } else { - region = this.compute.region(config.region); + if (is.string(region)) { + region = this.compute.region(region); } + delete config.region; - return region.createSubnetwork(name, config, callback); + region.createSubnetwork(name, config, callback); }; /** diff --git a/lib/compute/region.js b/lib/compute/region.js index 2092c60a825..9a90416be7b 100644 --- a/lib/compute/region.js +++ b/lib/compute/region.js @@ -49,16 +49,16 @@ var Operation = require('./operation.js'); var Rule = require('./rule.js'); /** - * @type {module:compute/subnetwork} + * @type {module:common/service-object} * @private */ -var Subnetwork = require('./subnetwork.js'); +var ServiceObject = require('../common/service-object.js'); /** - * @type {module:common/service-object} + * @type {module:compute/subnetwork} * @private */ -var ServiceObject = require('../common/service-object.js'); +var Subnetwork = require('./subnetwork.js'); /** * @type {module:common/stream-router} @@ -226,127 +226,6 @@ Region.prototype.createAddress = function(name, options, callback) { }); }; -/** - * Get a list of subnetworks in this region. - * - * @resource [Subnetworks Overview]{@link https://cloud.google.com/compute/docs/subnetworks} - * @resource [Subnetworks: list API Documentation]{@link https://cloud.google.com/compute/docs/reference/v1/subnetworks} - * - * @param {object=} options - Subnetwork search options. - * @param {boolean} options.autoPaginate - Have pagination handled - * automatically. Default: true. - * @param {string} options.filter - Search filter in the format of - * `{name} {comparison} {filterString}`. - * - **`name`**: the name of the field to compare - * - **`comparison`**: the comparison operator, `eq` (equal) or `ne` - * (not equal) - * - **`filterString`**: the string to filter to. For string fields, this - * can be a regular expression. - * @param {number} options.maxApiCalls - Maximum number of API calls to make. - * @param {number} options.maxResults - Maximum number of subnetworks to return. - * @param {string} options.pageToken - A previously-returned page token - * representing part of the larger set of results to view. - * @param {function} callback - The callback function. - * @param {?error} callback.err - An error returned while making this request. - * @param {module:compute/subnetworks} callback.subnetworks - Subnetwork objects - * from this region. - * @param {?object} callback.nextQuery - If present, query with this object to - * check for more results. - * @param {object} callback.apiResponse - The full API response. - * - * @example - * region.getSubnetworks(function(err, subnetworks) { - * // `subnetworks` is an array of `Subnetwork` objects. - * }); - * - * //- - * // To control how many API requests are made and page through the results - * // manually, set `autoPaginate` to `false`. - * //- - * function callback(err, subnetworks, nextQuery, apiResponse) { - * if (nextQuery) { - * // More results exist. - * region.getSubnetworks(nextQuery, callback); - * } - * } - * - * region.getSubnetworks({ - * autoPaginate: false - * }, callback); - * - * //- - * // Get the subnetworks from this region as a readable object stream. - * //- - * region.getSubnetworks() - * .on('error', console.error) - * .on('data', function(subnetwork) { - * // `subnetwork` is a `Subnetwork` object. - * }) - * .on('end', function() { - * // All subnetworks retrieved. - * }); - * - * //- - * // If you anticipate many results, you can end a stream early to prevent - * // unnecessary processing and API requests. - * //- - * region.getSubnetworks() - * .on('data', function(subnetwork) { - * this.end(); - * }); - */ -Region.prototype.getSubnetworks = function(options, callback) { - var self = this; - - if (is.fn(options)) { - callback = options; - options = {}; - } - - options = options || {}; - - this.request({ - uri: '/subnetworks', - qs: options - }, function(err, resp) { - if (err) { - callback(err, null, null, resp); - return; - } - - var nextQuery = null; - - if (resp.nextPageToken) { - nextQuery = extend({}, options, { - pageToken: resp.nextPageToken - }); - } - - var subnetworks = (resp.items || []).map(function(subnetwork) { - var subnetworkInstance = self.subnetwork(subnetwork.name); - subnetworkInstance.metadata = subnetwork; - return subnetworkInstance; - }); - - callback(null, subnetworks, nextQuery, resp); - }); -}; - -/** - * Get a reference to a Google Compute Engine subnetwork in this region. - * - * @resource [Instances and Networks]{@link https://cloud.google.com/compute/docs/subnetworks} - * - * @param {string} name - Name of the subnetwork. - * @return {module:compute/subnetwork} - * - * @example - * var subnetwork = region.subnetwork('subnetwork-name'); - */ -Region.prototype.subnetwork = function(name) { - return new Subnetwork(this, name); -}; - /** * Create a subnetwork in this region. * @@ -791,6 +670,112 @@ Region.prototype.getRules = function(options, callback) { }); }; +/** + * Get a list of subnetworks in this region. + * + * @resource [Subnetworks Overview]{@link https://cloud.google.com/compute/docs/subnetworks} + * @resource [Subnetworks: list API Documentation]{@link https://cloud.google.com/compute/docs/reference/v1/subnetworks} + * + * @param {object=} options - Subnetwork search options. + * @param {boolean} options.autoPaginate - Have pagination handled + * automatically. Default: true. + * @param {string} options.filter - Search filter in the format of + * `{name} {comparison} {filterString}`. + * - **`name`**: the name of the field to compare + * - **`comparison`**: the comparison operator, `eq` (equal) or `ne` + * (not equal) + * - **`filterString`**: the string to filter to. For string fields, this + * can be a regular expression. + * @param {number} options.maxApiCalls - Maximum number of API calls to make. + * @param {number} options.maxResults - Maximum number of subnetworks to return. + * @param {string} options.pageToken - A previously-returned page token + * representing part of the larger set of results to view. + * @param {function} callback - The callback function. + * @param {?error} callback.err - An error returned while making this request. + * @param {module:compute/subnetworks} callback.subnetworks - Subnetwork objects + * from this region. + * @param {?object} callback.nextQuery - If present, query with this object to + * check for more results. + * @param {object} callback.apiResponse - The full API response. + * + * @example + * region.getSubnetworks(function(err, subnetworks) { + * // `subnetworks` is an array of `Subnetwork` objects. + * }); + * + * //- + * // To control how many API requests are made and page through the results + * // manually, set `autoPaginate` to `false`. + * //- + * function callback(err, subnetworks, nextQuery, apiResponse) { + * if (nextQuery) { + * // More results exist. + * region.getSubnetworks(nextQuery, callback); + * } + * } + * + * region.getSubnetworks({ + * autoPaginate: false + * }, callback); + * + * //- + * // Get the subnetworks from this region as a readable object stream. + * //- + * region.getSubnetworks() + * .on('error', console.error) + * .on('data', function(subnetwork) { + * // `subnetwork` is a `Subnetwork` object. + * }) + * .on('end', function() { + * // All subnetworks retrieved. + * }); + * + * //- + * // If you anticipate many results, you can end a stream early to prevent + * // unnecessary processing and API requests. + * //- + * region.getSubnetworks() + * .on('data', function(subnetwork) { + * this.end(); + * }); + */ +Region.prototype.getSubnetworks = function(options, callback) { + var self = this; + + if (is.fn(options)) { + callback = options; + options = {}; + } + + options = options || {}; + + this.request({ + uri: '/subnetworks', + qs: options + }, function(err, resp) { + if (err) { + callback(err, null, null, resp); + return; + } + + var nextQuery = null; + + if (resp.nextPageToken) { + nextQuery = extend({}, options, { + pageToken: resp.nextPageToken + }); + } + + var subnetworks = (resp.items || []).map(function(subnetwork) { + var subnetworkInstance = self.subnetwork(subnetwork.name); + subnetworkInstance.metadata = subnetwork; + return subnetworkInstance; + }); + + callback(null, subnetworks, nextQuery, resp); + }); +}; + /** * Get a reference to a Google Compute Engine region operation. * @@ -819,6 +804,21 @@ Region.prototype.rule = function(name) { return new Rule(this, name); }; +/** + * Get a reference to a Google Compute Engine subnetwork in this region. + * + * @resource [Subnetworks Overview]{@link https://cloud.google.com/compute/docs/subnetworks} + * + * @param {string} name - Name of the subnetwork. + * @return {module:compute/subnetwork} + * + * @example + * var subnetwork = region.subnetwork('subnetwork-name'); + */ +Region.prototype.subnetwork = function(name) { + return new Subnetwork(this, name); +}; + /*! Developer Documentation * * These methods can be used with either a callback or as a readable object diff --git a/lib/compute/subnetwork.js b/lib/compute/subnetwork.js index e8861bafd4a..350d91b9449 100644 --- a/lib/compute/subnetwork.js +++ b/lib/compute/subnetwork.js @@ -20,7 +20,6 @@ 'use strict'; -var format = require('string-format-obj'); var nodeutil = require('util'); /** @@ -45,7 +44,7 @@ var util = require('../common/util.js'); * An Subnetwork object allows you to interact with a Google Compute Engine * subnetwork. * - * @resource [Subnetworks]{@link https://cloud.google.com/compute/docs/subnetworks} + * @resource [Subnetworks Overview]{@link https://cloud.google.com/compute/docs/subnetworks} * @resource [Subnetwork Resource]{@link https://cloud.google.com/compute/docs/reference/v1/subnetworks} * * @constructor @@ -78,7 +77,7 @@ function Subnetwork(region, name) { * // ... * }; * - * function(err, subnetwork, operation, apiResponse) { + * function callback(err, subnetwork, operation, apiResponse) { * // `subnetwork` is a Subnetwork object. * * // `operation` is an Operation object that can be used to check the @@ -146,28 +145,10 @@ function Subnetwork(region, name) { createMethod: region.createSubnetwork.bind(region), methods: methods }); - - this.formattedName = Subnetwork.formatName_(region, name); } nodeutil.inherits(Subnetwork, ServiceObject); -/** - * Format a subnetwork's name how the API expects. - * - * @private - * - * @param {module:region} region - The Region object this subnetwork belongs to. - * @param {string} name - The name of the subnetwork. - * @return {string} - The formatted name. - */ -Subnetwork.formatName_ = function(region, name) { - return format('regions/{region}/subnetworks/{name}', { - region: region.name, - name: name - }); -}; - /** * Delete the subnetwork. * diff --git a/system-test/compute.js b/system-test/compute.js index 99f6b174ddc..2c2b80a68b8 100644 --- a/system-test/compute.js +++ b/system-test/compute.js @@ -1130,25 +1130,24 @@ describe('Compute', function() { }); describe('subnetworks', function() { - var SUBNETWORK_NAME = generateName('subnetwork'); - var subnetwork = region.subnetwork(SUBNETWORK_NAME); - var NETWORK_NAME = generateName('network'); var network = compute.network(NETWORK_NAME); - var CONFIG = { + var SUBNETWORK_NAME = generateName('subnetwork'); + var subnetwork = region.subnetwork(SUBNETWORK_NAME); + + var NETWORK_CONFIG = { autoCreateSubnetworks: false }; - var SUBNETWORK_CONFIG = { network: 'global/networks/' + NETWORK_NAME, - ipCidrRange: '10.0.1.0/24' + range: '10.0.1.0/24' }; before(function(done) { async.series([ - create(network, CONFIG), + create(network, NETWORK_CONFIG), create(subnetwork, SUBNETWORK_CONFIG) ], done); }); @@ -1183,6 +1182,28 @@ describe('Compute', function() { }); }); + it('should get a list of regional subnetworks', function(done) { + region.getSubnetworks(function(err, subnetworks) { + assert.ifError(err); + assert(subnetworks.length > 0); + done(); + }); + }); + + it('should get a list of regional subnetworks in stream', function(done) { + var resultsMatched = 0; + + region.getSubnetworks() + .on('error', done) + .on('data', function() { + resultsMatched++; + }) + .on('end', function() { + assert(resultsMatched > 0); + done(); + }); + }); + it('should access a subnetwork through a Region', function(done) { region.subnetwork(SUBNETWORK_NAME).getMetadata(done); }); diff --git a/test/compute/index.js b/test/compute/index.js index f54e3cd3313..017b412dd7d 100644 --- a/test/compute/index.js +++ b/test/compute/index.js @@ -1141,113 +1141,6 @@ describe('Compute', function() { }); }); - describe('getSubnetworks', function() { - it('should accept only a callback', function(done) { - compute.request = function(reqOpts) { - assert.deepEqual(reqOpts.qs, {}); - done(); - }; - - compute.getSubnetworks(assert.ifError); - }); - - it('should make the correct API request', function(done) { - var options = {}; - - compute.request = function(reqOpts) { - assert.strictEqual(reqOpts.uri, '/aggregated/subnetworks'); - assert.strictEqual(reqOpts.qs, options); - done(); - }; - - compute.getSubnetworks(options, assert.ifError); - }); - - describe('error', function() { - var error = new Error('Error.'); - var apiResponse = { a: 'b', c: 'd' }; - - beforeEach(function() { - compute.request = function(reqOpts, callback) { - callback(error, apiResponse); - }; - }); - - it('should execute callback with error & API response', function(done) { - compute.getSubnetworks({}, function(err, subnetworks, nextQuery, resp) { - assert.strictEqual(err, error); - assert.strictEqual(subnetworks, null); - assert.strictEqual(nextQuery, null); - assert.strictEqual(resp, apiResponse); - - done(); - }); - }); - }); - - describe('success', function() { - var REGION_NAME = 'region-1'; - var FULL_REGION_NAME = 'regions/' + REGION_NAME; - - var subnetwork = { name: 'subnetwork-1' }; - var apiResponse = { - items: {} - }; - - apiResponse.items[FULL_REGION_NAME] = { - subnetworks: [subnetwork] - }; - - beforeEach(function() { - compute.request = function(reqOpts, callback) { - callback(null, apiResponse); - }; - }); - - it('should create Subnetwork objects from the response', function(done) { - var region = {}; - - compute.region = function(name) { - assert.strictEqual(name, REGION_NAME); - return region; - }; - - region.subnetwork = function(name) { - assert.strictEqual(name, subnetwork.name); - setImmediate(done); - return subnetwork; - }; - - compute.getSubnetworks({}, assert.ifError); - }); - - it('should build a nextQuery if necessary', function(done) { - var apiResponseWithNextPageToken = extend({}, apiResponse, { - nextPageToken: 'next-page-token' - }); - - var query = { a: 'b', c: 'd' }; - var originalQuery = extend({}, query); - - compute.request = function(reqOpts, callback) { - callback(null, apiResponseWithNextPageToken); - }; - - compute.getSubnetworks(query, function(err, subnetworks, nextQuery) { - assert.ifError(err); - - assert.deepEqual(query, originalQuery); - - assert.deepEqual(nextQuery, extend({}, query, { - pageToken: apiResponseWithNextPageToken.nextPageToken - })); - - done(); - }); - }); - }); - }); - describe('getFirewalls', function() { it('should accept only a callback', function(done) { compute.request = function(reqOpts) { @@ -2140,6 +2033,123 @@ describe('Compute', function() { }); }); + describe('getSubnetworks', function() { + it('should accept only a callback', function(done) { + compute.request = function(reqOpts) { + assert.deepEqual(reqOpts.qs, {}); + done(); + }; + + compute.getSubnetworks(assert.ifError); + }); + + it('should make the correct API request', function(done) { + var options = {}; + + compute.request = function(reqOpts) { + assert.strictEqual(reqOpts.uri, '/aggregated/subnetworks'); + assert.strictEqual(reqOpts.qs, options); + done(); + }; + + compute.getSubnetworks(options, assert.ifError); + }); + + describe('error', function() { + var error = new Error('Error.'); + var apiResponse = { a: 'b', c: 'd' }; + + beforeEach(function() { + compute.request = function(reqOpts, callback) { + callback(error, apiResponse); + }; + }); + + it('should execute callback with error & API response', function(done) { + compute.getSubnetworks({}, function(err, subnetworks, nextQuery, resp) { + assert.strictEqual(err, error); + assert.strictEqual(subnetworks, null); + assert.strictEqual(nextQuery, null); + assert.strictEqual(resp, apiResponse); + + done(); + }); + }); + }); + + describe('success', function() { + var REGION_NAME = 'region-1'; + var FULL_REGION_NAME = 'regions/' + REGION_NAME; + + var subnetwork = { name: 'subnetwork-1' }; + var apiResponse = { + items: {} + }; + + apiResponse.items[FULL_REGION_NAME] = { + subnetworks: [subnetwork] + }; + + beforeEach(function() { + compute.request = function(reqOpts, callback) { + callback(null, apiResponse); + }; + }); + + it('should create Subnetwork objects from the response', function(done) { + var region = {}; + var fakeSubnetwork = {}; + + compute.region = function(name) { + assert.strictEqual(name, REGION_NAME); + return region; + }; + + region.subnetwork = function(name) { + assert.strictEqual(name, subnetwork.name); + return fakeSubnetwork; + }; + + compute.getSubnetworks({}, function(err, subnetworks, nextQuery, resp) { + assert.ifError(err); + + assert.strictEqual(subnetworks[0], fakeSubnetwork); + assert.strictEqual(subnetworks[0].metadata, subnetwork); + + assert.strictEqual(nextQuery, null); + assert.strictEqual(resp, apiResponse); + + done(); + }); + }); + + it('should build a nextQuery if necessary', function(done) { + var apiResponseWithNextPageToken = extend({}, apiResponse, { + nextPageToken: 'next-page-token' + }); + + var query = { a: 'b', c: 'd' }; + var originalQuery = extend({}, query); + + compute.request = function(reqOpts, callback) { + callback(null, apiResponseWithNextPageToken); + }; + + compute.getSubnetworks(query, function(err, subnetworks, nextQuery) { + assert.ifError(err); + + assert.deepEqual(query, originalQuery); + + assert.deepEqual(nextQuery, extend({}, query, { + pageToken: apiResponseWithNextPageToken.nextPageToken + })); + + done(); + }); + }); + }); + }); + describe('getVMs', function() { it('should work with only a callback', function(done) { compute.request = function(reqOpts) { diff --git a/test/compute/network.js b/test/compute/network.js index cda603e0744..a0fc4dc6790 100644 --- a/test/compute/network.js +++ b/test/compute/network.js @@ -153,29 +153,30 @@ describe('Network', function() { }); describe('createSubnetwork', function() { - it('should makes the correct call to Region', function(done) { + it('should call region.createSubnetwork correctly', function(done) { var name = 'subnetwork-name'; var region = {}; - var config = { a: 'b', c: 'd', region: REGION_NAME}; + var config = { + a: 'b', + c: 'd', + region: REGION_NAME + }; + var expectedConfig = extend({}, config, { - network: network.formattedName, - name: name + network: network.formattedName }); delete expectedConfig.region; - network.compute.region = function(name_) { - assert.strictEqual(name_, REGION_NAME); + network.compute.region = function(name) { + assert.strictEqual(name, REGION_NAME); return region; }; - region.createSubnetwork = function(name_, config_, callback){ - callback(); - }; + region.createSubnetwork = function(name_, config, callback) { + assert.strictEqual(name_, name); + assert.deepEqual(config, expectedConfig); - network.compute.request = function(config_) { - assert.strictEqual(config_.json.name, name); - assert.deepEqual(config_.json, expectedConfig); - done(); + callback(); // done(); }; network.createSubnetwork(name, config, done); @@ -271,31 +272,31 @@ describe('Network', function() { }); }); - describe('getSubnetworks', function() { + describe('getFirewalls', function() { it('should make the correct call to Compute', function(done) { var options = { a: 'b', c: 'd' }; var expectedOptions = extend({}, options, { filter: 'network eq .*' + network.formattedName }); - network.compute.getSubnetworks = function(options, callback) { + network.compute.getFirewalls = function(options, callback) { assert.deepEqual(options, expectedOptions); callback(); }; - network.getSubnetworks(options, done); + network.getFirewalls(options, done); }); it('should not require options', function(done) { - network.compute.getSubnetworks = function(options, callback) { + network.compute.getFirewalls = function(options, callback) { callback(); }; - network.getSubnetworks(done); + network.getFirewalls(done); }); it('should not require any arguments', function(done) { - network.compute.getSubnetworks = function(options, callback) { + network.compute.getFirewalls = function(options, callback) { assert.deepEqual(options, { filter: 'network eq .*' + network.formattedName }); @@ -303,45 +304,45 @@ describe('Network', function() { done(); }; - network.getSubnetworks(); + network.getFirewalls(); }); it('should return the result of calling Compute', function() { - var resultOfgetSubnetworks = {}; + var resultOfGetFirewalls = {}; - network.compute.getSubnetworks = function() { - return resultOfgetSubnetworks; + network.compute.getFirewalls = function() { + return resultOfGetFirewalls; }; - assert.strictEqual(network.getSubnetworks(), resultOfgetSubnetworks); + assert.strictEqual(network.getFirewalls(), resultOfGetFirewalls); }); }); - describe('getFirewalls', function() { - it('should make the correct call to Compute', function(done) { + describe('getSubnetworks', function() { + it('should call to compute.getSubnetworks correctly', function(done) { var options = { a: 'b', c: 'd' }; var expectedOptions = extend({}, options, { filter: 'network eq .*' + network.formattedName }); - network.compute.getFirewalls = function(options, callback) { + network.compute.getSubnetworks = function(options, callback) { assert.deepEqual(options, expectedOptions); callback(); }; - network.getFirewalls(options, done); + network.getSubnetworks(options, done); }); it('should not require options', function(done) { - network.compute.getFirewalls = function(options, callback) { + network.compute.getSubnetworks = function(options, callback) { callback(); }; - network.getFirewalls(done); + network.getSubnetworks(done); }); it('should not require any arguments', function(done) { - network.compute.getFirewalls = function(options, callback) { + network.compute.getSubnetworks = function(options, callback) { assert.deepEqual(options, { filter: 'network eq .*' + network.formattedName }); @@ -349,17 +350,17 @@ describe('Network', function() { done(); }; - network.getFirewalls(); + network.getSubnetworks(); }); it('should return the result of calling Compute', function() { - var resultOfGetFirewalls = {}; + var resultOfGetSubnetworks = {}; - network.compute.getFirewalls = function() { - return resultOfGetFirewalls; + network.compute.getSubnetworks = function() { + return resultOfGetSubnetworks; }; - assert.strictEqual(network.getFirewalls(), resultOfGetFirewalls); + assert.strictEqual(network.getSubnetworks(), resultOfGetSubnetworks); }); }); }); diff --git a/test/compute/region.js b/test/compute/region.js index f1e40b73015..f8c13a0ee92 100644 --- a/test/compute/region.js +++ b/test/compute/region.js @@ -58,8 +58,11 @@ var fakeStreamRouter = { extended = true; methods = arrify(methods); assert.equal(Class.name, 'Region'); - assert.deepEqual(methods, - ['getAddresses', 'getOperations', 'getRules', 'getSubnetworks']); + assert.deepEqual(methods, [ + 'getAddresses', + 'getOperations', + 'getRules', 'getSubnetworks' + ]); } }; @@ -320,36 +323,35 @@ describe('Region', function() { it('should exec callback with Subnetwork, Op & apiResponse', function(done) { - var subnetwork = {}; - var operation = {}; + var subnetwork = {}; + var operation = {}; - region.subnetwork = function(name) { - assert.strictEqual(name, NAME); - return subnetwork; - }; + region.subnetwork = function(name) { + assert.strictEqual(name, NAME); + return subnetwork; + }; - region.operation = function(name) { - assert.strictEqual(name, apiResponse.name); - return operation; - }; + region.operation = function(name) { + assert.strictEqual(name, apiResponse.name); + return operation; + }; - region.createSubnetwork(NAME, OPTIONS, - function(err, subnetwork_, op, resp) { - assert.ifError(err); + region.createSubnetwork(NAME, OPTIONS, + function(err, subnetwork_, op, resp) { + assert.ifError(err); - assert.strictEqual(subnetwork_, subnetwork); + assert.strictEqual(subnetwork_, subnetwork); - assert.strictEqual(op, operation); - assert.strictEqual(op.metadata, resp); + assert.strictEqual(op, operation); + assert.strictEqual(op.metadata, resp); - assert.strictEqual(resp, apiResponse); - done(); + assert.strictEqual(resp, apiResponse); + done(); + }); }); - }); }); }); - describe('getAddresses', function() { it('should accept only a callback', function(done) { region.request = function(reqOpts) { @@ -451,27 +453,27 @@ describe('Region', function() { }); }); - describe('getSubnetworks', function() { + describe('getOperations', function() { it('should accept only a callback', function(done) { region.request = function(reqOpts) { assert.deepEqual(reqOpts.qs, {}); done(); }; - region.getSubnetworks(assert.ifError); + region.getOperations(assert.ifError); }); it('should make the correct API request', function(done) { var query = { a: 'b', c: 'd' }; region.request = function(reqOpts) { - assert.strictEqual(reqOpts.uri, '/subnetworks'); + assert.strictEqual(reqOpts.uri, '/operations'); assert.strictEqual(reqOpts.qs, query); done(); }; - region.getSubnetworks(query, assert.ifError); + region.getOperations(query, assert.ifError); }); describe('error', function() { @@ -485,10 +487,9 @@ describe('Region', function() { }); it('should execute callback with error & API response', function(done) { - region.getSubnetworks({}, - function(err, subnetworks, nextQuery, apiResp) { + region.getOperations({}, function(err, operations, nextQuery, apiResp) { assert.strictEqual(err, error); - assert.strictEqual(subnetworks, null); + assert.strictEqual(operations, null); assert.strictEqual(nextQuery, null); assert.strictEqual(apiResp, apiResponse); done(); @@ -522,7 +523,7 @@ describe('Region', function() { callback(null, apiResponseWithNextPageToken); }; - region.getSubnetworks({}, function(err, subnetworks, nextQuery) { + region.getOperations({}, function(err, operations, nextQuery) { assert.ifError(err); assert.deepEqual(nextQuery, expectedNextQuery); @@ -532,49 +533,48 @@ describe('Region', function() { }); it('should execute callback with Operations & API resp', function(done) { - var subnetwork = {}; + var operation = {}; - region.subnetwork = function(name) { + region.operation = function(name) { assert.strictEqual(name, apiResponse.items[0].name); - return subnetwork; + return operation; }; - region.getSubnetworks({}, - function(err, subnetworks, nextQuery, apiResp) { - assert.ifError(err); + region.getOperations({}, function(err, operations, nextQuery, apiResp) { + assert.ifError(err); - assert.strictEqual(subnetworks[0], subnetwork); - assert.strictEqual(subnetworks[0].metadata, apiResponse.items[0]); + assert.strictEqual(operations[0], operation); + assert.strictEqual(operations[0].metadata, apiResponse.items[0]); - assert.strictEqual(apiResp, apiResponse); + assert.strictEqual(apiResp, apiResponse); - done(); - }); + done(); + }); }); }); }); - describe('getOperations', function() { + describe('getRules', function() { it('should accept only a callback', function(done) { region.request = function(reqOpts) { assert.deepEqual(reqOpts.qs, {}); done(); }; - region.getOperations(assert.ifError); + region.getRules(assert.ifError); }); it('should make the correct API request', function(done) { var query = { a: 'b', c: 'd' }; region.request = function(reqOpts) { - assert.strictEqual(reqOpts.uri, '/operations'); + assert.strictEqual(reqOpts.uri, '/forwardingRules'); assert.strictEqual(reqOpts.qs, query); done(); }; - region.getOperations(query, assert.ifError); + region.getRules(query, assert.ifError); }); describe('error', function() { @@ -588,9 +588,9 @@ describe('Region', function() { }); it('should execute callback with error & API response', function(done) { - region.getOperations({}, function(err, operations, nextQuery, apiResp) { + region.getRules({}, function(err, rules, nextQuery, apiResp) { assert.strictEqual(err, error); - assert.strictEqual(operations, null); + assert.strictEqual(rules, null); assert.strictEqual(nextQuery, null); assert.strictEqual(apiResp, apiResponse); done(); @@ -624,7 +624,7 @@ describe('Region', function() { callback(null, apiResponseWithNextPageToken); }; - region.getOperations({}, function(err, operations, nextQuery) { + region.getRules({}, function(err, rules, nextQuery) { assert.ifError(err); assert.deepEqual(nextQuery, expectedNextQuery); @@ -634,18 +634,18 @@ describe('Region', function() { }); it('should execute callback with Operations & API resp', function(done) { - var operation = {}; + var rule = {}; - region.operation = function(name) { + region.rule = function(name) { assert.strictEqual(name, apiResponse.items[0].name); - return operation; + return rule; }; - region.getOperations({}, function(err, operations, nextQuery, apiResp) { + region.getRules({}, function(err, rules, nextQuery, apiResp) { assert.ifError(err); - assert.strictEqual(operations[0], operation); - assert.strictEqual(operations[0].metadata, apiResponse.items[0]); + assert.strictEqual(rules[0], rule); + assert.strictEqual(rules[0].metadata, apiResponse.items[0]); assert.strictEqual(apiResp, apiResponse); @@ -655,27 +655,27 @@ describe('Region', function() { }); }); - describe('getRules', function() { + describe('getSubnetworks', function() { it('should accept only a callback', function(done) { region.request = function(reqOpts) { assert.deepEqual(reqOpts.qs, {}); done(); }; - region.getRules(assert.ifError); + region.getSubnetworks(assert.ifError); }); it('should make the correct API request', function(done) { var query = { a: 'b', c: 'd' }; region.request = function(reqOpts) { - assert.strictEqual(reqOpts.uri, '/forwardingRules'); + assert.strictEqual(reqOpts.uri, '/subnetworks'); assert.strictEqual(reqOpts.qs, query); done(); }; - region.getRules(query, assert.ifError); + region.getSubnetworks(query, assert.ifError); }); describe('error', function() { @@ -689,11 +689,11 @@ describe('Region', function() { }); it('should execute callback with error & API response', function(done) { - region.getRules({}, function(err, rules, nextQuery, apiResp) { + region.getSubnetworks({}, function(err, subnetworks, nextQuery, resp) { assert.strictEqual(err, error); - assert.strictEqual(rules, null); + assert.strictEqual(subnetworks, null); assert.strictEqual(nextQuery, null); - assert.strictEqual(apiResp, apiResponse); + assert.strictEqual(resp, apiResponse); done(); }); }); @@ -702,7 +702,7 @@ describe('Region', function() { describe('success', function() { var apiResponse = { items: [ - { name: 'operation-name' } + { name: 'subnetwork-name' } ] }; @@ -725,7 +725,7 @@ describe('Region', function() { callback(null, apiResponseWithNextPageToken); }; - region.getRules({}, function(err, rules, nextQuery) { + region.getSubnetworks({}, function(err, subnetworks, nextQuery) { assert.ifError(err); assert.deepEqual(nextQuery, expectedNextQuery); @@ -735,20 +735,20 @@ describe('Region', function() { }); it('should execute callback with Operations & API resp', function(done) { - var rule = {}; + var subnetwork = {}; - region.rule = function(name) { + region.subnetwork = function(name) { assert.strictEqual(name, apiResponse.items[0].name); - return rule; + return subnetwork; }; - region.getRules({}, function(err, rules, nextQuery, apiResp) { + region.getSubnetworks({}, function(err, subnetworks, nextQuery, resp) { assert.ifError(err); - assert.strictEqual(rules[0], rule); - assert.strictEqual(rules[0].metadata, apiResponse.items[0]); + assert.strictEqual(subnetworks[0], subnetwork); + assert.strictEqual(subnetworks[0].metadata, apiResponse.items[0]); - assert.strictEqual(apiResp, apiResponse); + assert.strictEqual(resp, apiResponse); done(); }); @@ -756,17 +756,6 @@ describe('Region', function() { }); }); - describe('subnetwork', function() { - var NAME = 'subnetwork-name'; - - it('should return a Subnetwork object', function() { - var subnetwork = region.subnetwork(NAME); - assert(subnetwork instanceof FakeSubnetwork); - assert.strictEqual(subnetwork.calledWith_[0], region); - assert.strictEqual(subnetwork.calledWith_[1], NAME); - }); - }); - describe('operation', function() { var NAME = 'operation-name'; @@ -788,4 +777,16 @@ describe('Region', function() { assert.strictEqual(rule.calledWith_[1], NAME); }); }); + + describe('subnetwork', function() { + var NAME = 'subnetwork-name'; + + it('should return a Subnetwork object', function() { + var subnetwork = region.subnetwork(NAME); + assert(subnetwork instanceof FakeSubnetwork); + assert.strictEqual(subnetwork.calledWith_[0], region); + assert.strictEqual(subnetwork.calledWith_[1], NAME); + }); + }); }); + diff --git a/test/compute/subnetwork.js b/test/compute/subnetwork.js index 6fc2df1dea5..eaaaf0c2a46 100644 --- a/test/compute/subnetwork.js +++ b/test/compute/subnetwork.js @@ -1,5 +1,5 @@ /** - * Copyright 2015 Google Inc. All Rights Reserved. + * Copyright 2016 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,6 @@ var assert = require('assert'); var extend = require('extend'); -var format = require('string-format-obj'); var mockery = require('mockery-next'); var nodeutil = require('util'); @@ -42,10 +41,6 @@ describe('Subnetwork', function() { createSubnetwork: util.noop, name: REGION_NAME }; - var SUBNETWORK_FULL_NAME = format('regions/{region}/subnetworks/{name}', { - region: REGION_NAME, - name: SUBNETWORK_NAME - }); before(function() { mockery.registerMock( @@ -70,20 +65,22 @@ describe('Subnetwork', function() { }); describe('instantiation', function() { + it('should localize the name', function() { + assert.strictEqual(subnetwork.name, SUBNETWORK_NAME); + }); + it('should localize the region', function() { assert.strictEqual(subnetwork.region, REGION); }); - it('should localize the name', function() { - assert.strictEqual(subnetwork.name, SUBNETWORK_NAME); - }); + it('should inherit from ServiceObject', function() { + var createSubnetworkBound = {}; - it('should inherit from ServiceObject', function(done) { var regionInstance = extend({}, REGION, { createSubnetwork: { bind: function(context) { assert.strictEqual(context, regionInstance); - done(); + return createSubnetworkBound; } } }); @@ -96,6 +93,7 @@ describe('Subnetwork', function() { assert.strictEqual(calledWith.parent, regionInstance); assert.strictEqual(calledWith.baseUrl, '/subnetworks'); assert.strictEqual(calledWith.id, SUBNETWORK_NAME); + assert.strictEqual(calledWith.createMethod, createSubnetworkBound); assert.deepEqual(calledWith.methods, { create: true, exists: true, @@ -105,13 +103,6 @@ describe('Subnetwork', function() { }); }); - describe('formatName_', function() { - it('should format the name', function() { - var formattedName_ = Subnetwork.formatName_(REGION, SUBNETWORK_NAME); - assert.strictEqual(formattedName_, SUBNETWORK_FULL_NAME); - }); - }); - describe('delete', function() { it('should make the correct API request', function(done) { subnetwork.request = function(reqOpts) { @@ -171,6 +162,7 @@ describe('Subnetwork', function() { subnetwork.delete(function(err, operation_, apiResponse_) { assert.ifError(err); assert.strictEqual(operation_, operation); + assert.strictEqual(operation_.metadata, apiResponse); assert.strictEqual(apiResponse_, apiResponse); done(); }); diff --git a/test/docs.js b/test/docs.js index e458b6750ae..ef0362036f3 100644 --- a/test/docs.js +++ b/test/docs.js @@ -16,7 +16,6 @@ 'use strict'; -var assert = require('assert'); var fs = require('fs'); var gcloud = require('../'); var glob = require('glob'); @@ -35,9 +34,8 @@ function runCodeInSandbox(code, sandbox) { }); } catch(err) { // rethrow the error with code for context and resolving issues faster. - var lineCol = err.stack.match('assert-code\.vm:(.+):(.+)'); + var lineCol = err.stack.match('assert-code\.vm:(.+)'); lineCol.line = lineCol[1]; - lineCol.col = lineCol[2]; var lines = code.split('\n') .filter(function(line, index) { @@ -133,7 +131,7 @@ describe('documentation', function() { displayName += '#' + method.id; it('should run ' + displayName + ' example without errors', function() { - assert.doesNotThrow(runCodeInSandbox.bind(null, code, sandbox)); + runCodeInSandbox(code, sandbox); }); }); }); From 61c207a2235775e9499d2cb0a1a89723caf2e7b0 Mon Sep 17 00:00:00 2001 From: Stephen Sawchuk Date: Wed, 20 Jul 2016 09:42:53 -0400 Subject: [PATCH 5/5] fix coverage --- lib/compute/region.js | 12 +++--- test/compute/region.js | 94 ++++++++++++++++++++++++++++++------------ 2 files changed, 72 insertions(+), 34 deletions(-) diff --git a/lib/compute/region.js b/lib/compute/region.js index 9a90416be7b..d0e13eac122 100644 --- a/lib/compute/region.js +++ b/lib/compute/region.js @@ -235,13 +235,13 @@ Region.prototype.createAddress = function(name, options, callback) { * @param {string} name - Name of the subnetwork. * @param {object} config - See a * [Subnetwork resource](https://cloud.google.com/compute/docs/reference/v1/subnetworks#resource). + * @param {module:compute/network|string} config.network - The network to which + * this subnetwork belongs. **Only networks that are in the distributed mode + * can have subnetworks.** * @param {string} config.range - The range of internal addresses that * are owned by this subnetwork. [CIDR](http://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing) range * of addresses that are legal on this network. (Alias for * `config.ipCidrRange`) - * @param {module:compute/network|string} config.network - The network to which - * this subnetwork belongs. **Only networks that are in the distributed mode - * can have subnetworks.** * @param {function} callback - The callback function. * @param {?error} callback.err - An error returned while making this request. * @param {module:compute/subnetwork} callback.subnetwork - The created @@ -251,10 +251,8 @@ Region.prototype.createAddress = function(name, options, callback) { * @param {object} callback.apiResponse - The full API response. * * @example - * var name = 'new-subnetwork-name'; - * * var config = { - * network : 'global/networks/network-name', + * network: 'network1', * range: '10.0.1.0/24' * }; * @@ -265,7 +263,7 @@ Region.prototype.createAddress = function(name, options, callback) { * // of the request. * } * - * region.createSubnetwork(name, config, callback); + * region.createSubnetwork('new-subnetwork-name', config, callback); */ Region.prototype.createSubnetwork = function(name, config, callback) { var self = this; diff --git a/test/compute/region.js b/test/compute/region.js index f8c13a0ee92..d6ed4c67095 100644 --- a/test/compute/region.js +++ b/test/compute/region.js @@ -37,6 +37,10 @@ function FakeRule() { this.calledWith_ = [].slice.call(arguments); } +function FakeNetwork() { + this.calledWith_ = [].slice.call(arguments); +} + function FakeSubnetwork() { this.calledWith_ = [].slice.call(arguments); } @@ -82,6 +86,7 @@ describe('Region', function() { ); mockery.registerMock('../../lib/common/stream-router.js', fakeStreamRouter); mockery.registerMock('../../lib/compute/address.js', FakeAddress); + mockery.registerMock('../../lib/compute/network.js', FakeNetwork); mockery.registerMock('../../lib/compute/operation.js', FakeOperation); mockery.registerMock('../../lib/compute/rule.js', FakeRule); mockery.registerMock('../../lib/compute/subnetwork.js', FakeSubnetwork); @@ -275,8 +280,12 @@ describe('Region', function() { describe('createSubnetwork', function() { var NAME = 'subnetwork-name'; - var OPTIONS = { a: 'b', c: 'd' }; - var EXPECTED_BODY = extend({}, OPTIONS, { name: NAME }); + var CONFIG = { + a: 'b', + c: 'd', + network: 'network-name' + }; + var EXPECTED_BODY = extend({}, CONFIG, { name: NAME }); it('should make the correct API request', function(done) { region.request = function(reqOpts) { @@ -287,7 +296,41 @@ describe('Region', function() { done(); }; - region.createSubnetwork(NAME, OPTIONS, assert.ifError); + region.createSubnetwork(NAME, CONFIG, assert.ifError); + }); + + describe('config.network', function() { + it('should accept a Network object', function(done) { + var network = new FakeNetwork(); + network.formattedName = 'formatted-name'; + + var config = extend({}, CONFIG, { + network: network + }); + + region.request = function(reqOpts) { + assert.strictEqual(reqOpts.json.network, network.formattedName); + done(); + }; + + region.createSubnetwork(NAME, config, assert.ifError); + }); + }); + + describe('config.range', function() { + it('should accept and delete a range property', function(done) { + var config = extend({}, CONFIG, { + range: '...' + }); + + region.request = function(reqOpts) { + assert.strictEqual(reqOpts.json.ipCidrRange, config.range); + assert.strictEqual(reqOpts.json.range, undefined); + done(); + }; + + region.createSubnetwork(NAME, config, assert.ifError); + }); }); describe('error', function() { @@ -301,10 +344,9 @@ describe('Region', function() { }); it('should execute callback with error & API response', function(done) { - region.createSubnetwork(NAME, OPTIONS, - function(err, subnetwork_, op, resp) { + region.createSubnetwork(NAME, CONFIG, function(err, sub, op, resp) { assert.strictEqual(err, error); - assert.strictEqual(subnetwork_, null); + assert.strictEqual(sub, null); assert.strictEqual(op, null); assert.strictEqual(resp, apiResponse); done(); @@ -321,34 +363,32 @@ describe('Region', function() { }; }); - it('should exec callback with Subnetwork, Op & apiResponse', - function(done) { - var subnetwork = {}; - var operation = {}; + it('should exec cb with Subnetwork, Op & apiResponse', function(done) { + var subnetwork = {}; + var operation = {}; - region.subnetwork = function(name) { - assert.strictEqual(name, NAME); - return subnetwork; - }; + region.subnetwork = function(name) { + assert.strictEqual(name, NAME); + return subnetwork; + }; - region.operation = function(name) { - assert.strictEqual(name, apiResponse.name); - return operation; - }; + region.operation = function(name) { + assert.strictEqual(name, apiResponse.name); + return operation; + }; - region.createSubnetwork(NAME, OPTIONS, - function(err, subnetwork_, op, resp) { - assert.ifError(err); + region.createSubnetwork(NAME, CONFIG, function(err, sub, op, resp) { + assert.ifError(err); - assert.strictEqual(subnetwork_, subnetwork); + assert.strictEqual(sub, subnetwork); - assert.strictEqual(op, operation); - assert.strictEqual(op.metadata, resp); + assert.strictEqual(op, operation); + assert.strictEqual(op.metadata, resp); - assert.strictEqual(resp, apiResponse); - done(); - }); + assert.strictEqual(resp, apiResponse); + done(); }); + }); }); });