From 7045fdbd381f3ca6ee9281c91242c050a9c78acc Mon Sep 17 00:00:00 2001 From: Amar Zavery Date: Mon, 11 Jul 2016 12:35:30 -0700 Subject: [PATCH] node clientruntime updates (#1244) * remove stale token from tokencache for sp auth as adal does not remove it. * more improvements * jshint fixes * application token creds update * update version * auth updates to node azure clientruntime * fix to make nodejs tests work for 6.x as well as 4.x --- .../applicationTokenCredentials.js | 13 +- .../lib/credentials/deviceTokenCredentials.js | 19 +- .../lib/credentials/userTokenCredentials.js | 24 +- src/client/NodeJS/ms-rest-azure/lib/login.js | 40 +- src/client/NodeJS/ms-rest-azure/package.json | 4 +- src/client/NodeJS/ms-rest/package.json | 6 +- src/dev/TestServer/server/routes/complex.js | 875 +++++++++--------- src/dev/TestServer/server/routes/header.js | 2 +- .../AcceptanceTests/lro.js | 8 +- .../AutoRest.NodeJS.Azure.Tests/package.json | 2 +- .../AzureNodeJSCodeGenerator.cs | 2 +- .../AutoRest.NodeJS.Tests/package.json | 2 +- .../AutoRest.NodeJS/NodeJSCodeGenerator.cs | 2 +- 13 files changed, 533 insertions(+), 466 deletions(-) diff --git a/src/client/NodeJS/ms-rest-azure/lib/credentials/applicationTokenCredentials.js b/src/client/NodeJS/ms-rest-azure/lib/credentials/applicationTokenCredentials.js index 8afc2f3f3a..2b7cc8ec7b 100644 --- a/src/client/NodeJS/ms-rest-azure/lib/credentials/applicationTokenCredentials.js +++ b/src/client/NodeJS/ms-rest-azure/lib/credentials/applicationTokenCredentials.js @@ -50,6 +50,11 @@ function ApplicationTokenCredentials(clientId, domain, secret, options) { options.tokenCache = new adal.MemoryCache(); } + if (options.tokenAudience && options.tokenAudience.toLowerCase() !== 'graph') { + throw new Error('Valid value for \'tokenAudience\' is \'graph\'.'); + } + + this.tokenAudience = options.tokenAudience; this.environment = options.environment; this.authorizationScheme = options.authorizationScheme; this.tokenCache = options.tokenCache; @@ -76,7 +81,9 @@ function _retrieveTokenFromCache(callback) { //For service principal userId and clientId are the same thing. Since the token has _clientId property we shall //retrieve token using it. var self = this; - self.context.acquireToken(self.environment.activeDirectoryResourceId, null, self.clientId, function (err, result) { + var resource = self.environment.activeDirectoryResourceId; + if (self.tokenAudience && self.tokenAudience.toLowerCase() === 'graph') resource = self.environment.activeDirectoryGraphResourceId; + self.context.acquireToken(resource, null, self.clientId, function (err, result) { if (err) { //make sure to remove the stale token from the tokencache. ADAL gives the same error message "Entry not found in cache." //for entry not being present in the cache and for accessToken being expired in the cache. We do not want the token cache @@ -109,7 +116,9 @@ ApplicationTokenCredentials.prototype.getToken = function (callback) { return callback(err); } else { //Some error occured in retrieving the token from cache. May be the cache was empty or the access token expired. Let's try again. - self.context.acquireTokenWithClientCredentials(self.environment.activeDirectoryResourceId, self.clientId, self.secret, function (err, tokenResponse) { + var resource = self.environment.activeDirectoryResourceId; + if (self.tokenAudience && self.tokenAudience.toLowerCase() === 'graph') resource = self.environment.activeDirectoryGraphResourceId; + self.context.acquireTokenWithClientCredentials(resource, self.clientId, self.secret, function (err, tokenResponse) { if (err) { return callback(new Error('Failed to acquire token for application with the provided secret. \n' + err)); } diff --git a/src/client/NodeJS/ms-rest-azure/lib/credentials/deviceTokenCredentials.js b/src/client/NodeJS/ms-rest-azure/lib/credentials/deviceTokenCredentials.js index 48cb16802a..da0e280571 100644 --- a/src/client/NodeJS/ms-rest-azure/lib/credentials/deviceTokenCredentials.js +++ b/src/client/NodeJS/ms-rest-azure/lib/credentials/deviceTokenCredentials.js @@ -21,6 +21,8 @@ var AzureEnvironment = require('../azureEnvironment'); * @param {string} [options.username] The user name for account in the form: 'user@example.com'. * @param {AzureEnvironment} [options.environment] The azure environment to authenticate with. Default environment is "Azure" popularly known as "Public Azure Cloud". * @param {string} [options.domain] The domain or tenant id containing this application. Default value is 'common' +* @param {string} [options.tokenAudience] The audience for which the token is requested. Valid value is 'graph'. If tokenAudience is provided +* then domain should also be provided and its value should not be the default 'common' tenant. It must be a string (preferrably in a guid format). * @param {string} [options.clientId] The active directory application client id. * See {@link https://azure.microsoft.com/en-us/documentation/articles/active-directory-devquickstarts-dotnet/ Active Directory Quickstart for .Net} * for an example. @@ -55,7 +57,18 @@ function DeviceTokenCredentials(options) { if (!options.tokenCache) { options.tokenCache = new adal.MemoryCache(); } - + + if (options.tokenAudience) { + if (options.tokenAudience.toLowerCase() !== 'graph') { + throw new Error('Valid value for \'tokenAudience\' is \'graph\'.'); + } + if (options.domain.toLowerCase() === 'common') { + throw new Error('If the tokenAudience is specified as \'graph\' then \'domain\' cannot be the default \'commmon\' tenant. ' + + 'It must be the actual tenant (preferrably a string in a guid format).'); + } + } + + this.tokenAudience = options.tokenAudience; this.username = options.username; this.environment = options.environment; this.domain = options.domain; @@ -68,7 +81,9 @@ function DeviceTokenCredentials(options) { DeviceTokenCredentials.prototype.retrieveTokenFromCache = function (callback) { var self = this; - self.context.acquireToken(self.environment.activeDirectoryResourceId, self.username, self.clientId, function (err, result) { + var resource = self.environment.activeDirectoryResourceId; + if (self.tokenAudience && self.tokenAudience.toLowerCase() === 'graph') resource = self.environment.activeDirectoryGraphResourceId; + self.context.acquireToken(resource, self.username, self.clientId, function (err, result) { if (err) return callback(err); return callback(null, result.tokenType, result.accessToken); }); diff --git a/src/client/NodeJS/ms-rest-azure/lib/credentials/userTokenCredentials.js b/src/client/NodeJS/ms-rest-azure/lib/credentials/userTokenCredentials.js index 12908b0edb..d9ffce6a2f 100644 --- a/src/client/NodeJS/ms-rest-azure/lib/credentials/userTokenCredentials.js +++ b/src/client/NodeJS/ms-rest-azure/lib/credentials/userTokenCredentials.js @@ -19,6 +19,8 @@ var AzureEnvironment = require('../azureEnvironment'); * @param {string} username The user name for the Organization Id account. * @param {string} password The password for the Organization Id account. * @param {object} [options] Object representing optional parameters. +* @param {string} [options.tokenAudience] The audience for which the token is requested. Valid value is 'graph'. If tokenAudience is provided +* then domain should also be provided its value should not be the default 'common' tenant. It must be a string (preferrably in a guid format). * @param {AzureEnvironment} [options.environment] The azure environment to authenticate with. * @param {string} [options.authorizationScheme] The authorization scheme. Default value is 'bearer'. * @param {object} [options.tokenCache] The token cache. Default value is the MemoryCache object from adal. @@ -55,7 +57,18 @@ function UserTokenCredentials(clientId, domain, username, password, options) { if (!options.tokenCache) { options.tokenCache = new adal.MemoryCache(); } - + + if (options.tokenAudience) { + if (options.tokenAudience.toLowerCase() !== 'graph') { + throw new Error('Valid value for \'tokenAudience\' is \'graph\'.'); + } + if (domain.toLowerCase() === 'common') { + throw new Error('If the tokenAudience is specified as \'graph\' then \'domain\' cannot be the default \'commmon\' tenant. ' + + 'It must be the actual tenant (preferrably a string in a guid format).'); + } + } + + this.tokenAudience = options.tokenAudience; this.environment = options.environment; this.authorizationScheme = options.authorizationScheme; this.tokenCache = options.tokenCache; @@ -68,7 +81,9 @@ function UserTokenCredentials(clientId, domain, username, password, options) { } function _retrieveTokenFromCache(callback) { - this.context.acquireToken(this.environment.activeDirectoryResourceId, this.username, this.clientId, function (err, result) { + var resource = this.environment.activeDirectoryResourceId; + if (this.tokenAudience && this.tokenAudience.toLowerCase() === 'graph') resource = this.environment.activeDirectoryGraphResourceId; + this.context.acquireToken(resource, this.username, this.clientId, function (err, result) { if (err) return callback(err); return callback(null, result); }); @@ -86,8 +101,9 @@ UserTokenCredentials.prototype.getToken = function (callback) { _retrieveTokenFromCache.call(this, function (err, result) { if (err) { //Some error occured in retrieving the token from cache. May be the cache was empty. Let's try again. - self.context.acquireTokenWithUsernamePassword(self.environment.activeDirectoryResourceId, self.username, - self.password, self.clientId, function (err, tokenResponse) { + var resource = self.environment.activeDirectoryResourceId; + if (self.tokenAudience && self.tokenAudience.toLowerCase() === 'graph') resource = self.environment.activeDirectoryGraphResourceId; + self.context.acquireTokenWithUsernamePassword(resource, self.username, self.password, self.clientId, function (err, tokenResponse) { if (err) { return callback(new Error('Failed to acquire token for the user. \n' + err)); } diff --git a/src/client/NodeJS/ms-rest-azure/lib/login.js b/src/client/NodeJS/ms-rest-azure/lib/login.js index f1dc5ee5ca..f461202ee5 100644 --- a/src/client/NodeJS/ms-rest-azure/lib/login.js +++ b/src/client/NodeJS/ms-rest-azure/lib/login.js @@ -20,6 +20,7 @@ function _createCredentials(parameters) { options.tokenCache = this.tokenCache; options.username = this.username; options.authorizationScheme = this.authorizationScheme; + options.tokenAudience = this.tokenAudience; if (parameters) { if (parameters.domain) { options.domain = parameters.domain; @@ -33,6 +34,9 @@ function _createCredentials(parameters) { if (parameters.tokenCache) { options.tokenCache = parameters.tokenCache; } + if (parameters.tokenAudience) { + options.tokenAudience = parameters.tokenAudience; + } } var credentials; if (UserTokenCredentials.prototype.isPrototypeOf(this)) { @@ -135,7 +139,10 @@ function _crossCheckUserNameWithToken(usernameFromMethodCall, userIdFromToken) { * See {@link https://azure.microsoft.com/en-us/documentation/articles/active-directory-devquickstarts-dotnet/ Active Directory Quickstart for .Net} * for an example. * - * @param {string} [options.domain] The domain or tenant id containing this application. Default value is 'common' + * @param {string} [options.tokenAudience] The audience for which the token is requested. Valid value is 'graph'.If tokenAudience is provided + * then domain should also be provided its value should not be the default 'common' tenant. It must be a string (preferrably in a guid format). + * + * @param {string} [options.domain] The domain or tenant id containing this application. Default value is 'common'. * * @param {AzureEnvironment} [options.environment] The azure environment to authenticate with. Default environment is "Public Azure". * @@ -177,6 +184,7 @@ exports.interactive = function interactive(options, callback) { options.language = azureConstants.DEFAULT_LANGUAGE; } + this.tokenAudience = options.tokenAudience; this.environment = options.environment; this.domain = options.domain; this.clientId = options.clientId; @@ -213,7 +221,12 @@ exports.interactive = function interactive(options, callback) { //to build the list of subscriptions across all tenants. So let's build both at the same time :). function (tenants, callback) { tenantList = tenants; - getSubscriptionsFromTenants.call(self, tenants, callback); + if (self.tokenAudience && self.tokenAudience.toLowerCase() === 'graph') { + // we dont need to get the subscriptionList if the tokenAudience is graph as graph clients are tenant based. + return callback(null, []); + } else { + return getSubscriptionsFromTenants.call(self, tenants, callback); + } } ], function(err, subscriptions) { if (err) return callback(err); @@ -231,6 +244,8 @@ exports.interactive = function interactive(options, callback) { * @param {string} [options.clientId] The active directory application client id. * See {@link https://azure.microsoft.com/en-us/documentation/articles/active-directory-devquickstarts-dotnet/ Active Directory Quickstart for .Net} * for an example. + * @param {string} [options.tokenAudience] The audience for which the token is requested. Valid value is 'graph'. If tokenAudience is provided + * then domain should also be provided and its value should not be the default 'common' tenant. It must be a string (preferrably in a guid format). * @param {string} [options.domain] The domain or tenant id containing this application. Default value 'common'. * @param {AzureEnvironment} [options.environment] The azure environment to authenticate with. * @param {string} [options.authorizationScheme] The authorization scheme. Default value is 'bearer'. @@ -272,7 +287,12 @@ exports.withUsernamePassword = function withUsernamePassword(username, password, }, function (tenants, callback) { tenantList = tenants; - getSubscriptionsFromTenants.call(creds, tenants, callback); + if (options.tokenAudience && options.tokenAudience.toLowerCase() === 'graph') { + // we dont need to get the subscriptionList if the tokenAudience is graph as graph clients are tenant based. + return callback(null, []); + } else { + return getSubscriptionsFromTenants.call(options, tenants, callback); + } }, ], function (err, subscriptions) { return callback(null, creds, subscriptions); @@ -289,6 +309,7 @@ exports.withUsernamePassword = function withUsernamePassword(username, password, * @param {string} secret The application secret for the service principal. * @param {string} domain The domain or tenant id containing this application. * @param {object} [options] Object representing optional parameters. + * @param {string} [options.tokenAudience] The audience for which the token is requested. Valid value is 'graph'. * @param {AzureEnvironment} [options.environment] The azure environment to authenticate with. * @param {string} [options.authorizationScheme] The authorization scheme. Default value is 'bearer'. * @param {object} [options.tokenCache] The token cache. Default value is the MemoryCache object from adal. @@ -313,10 +334,15 @@ exports.withServicePrincipalSecret = function withServicePrincipalSecret(clientI } creds.getToken(function (err) { if (err) return callback(err); - getSubscriptionsFromTenants.call(creds, [domain], function (err, subscriptions) { - if (err) return callback(err); - return callback(null, creds, subscriptions); - }); + if (options.tokenAudience && options.tokenAudience.toLowerCase() === 'graph') { + // we dont need to get the subscriptionList if the tokenAudience is graph as graph clients are tenant based. + return callback(null, creds, []); + } else { + getSubscriptionsFromTenants.call(creds, [domain], function (err, subscriptions) { + if (err) return callback(err); + return callback(null, creds, subscriptions); + }); + } }); }; diff --git a/src/client/NodeJS/ms-rest-azure/package.json b/src/client/NodeJS/ms-rest-azure/package.json index 8357ebf50e..32d50339e7 100644 --- a/src/client/NodeJS/ms-rest-azure/package.json +++ b/src/client/NodeJS/ms-rest-azure/package.json @@ -5,7 +5,7 @@ "email": "azsdkteam@microsoft.com", "url": "https://github.com/Azure/AutoRest" }, - "version": "1.14.4", + "version": "1.14.5", "description": "Client Runtime for Node.js Azure client libraries generated using AutoRest", "tags": [ "node", "microsoft", "autorest", "azure", "clientruntime" ], "keywords": [ "node", "microsoft", "autorest", "azure", "clientruntime" ], @@ -15,7 +15,7 @@ "async": "0.2.7", "uuid": "2.0.1", "adal-node": "^0.1.17", - "ms-rest": "^1.14.3", + "ms-rest": "^1.14.4", "moment": "^2.6.0", "azure-arm-resource": "^1.4.4-preview" }, diff --git a/src/client/NodeJS/ms-rest/package.json b/src/client/NodeJS/ms-rest/package.json index 0ba36267e6..c1ac1813c5 100644 --- a/src/client/NodeJS/ms-rest/package.json +++ b/src/client/NodeJS/ms-rest/package.json @@ -5,7 +5,7 @@ "email": "azsdkteam@microsoft.com", "url": "https://github.com/Azure/AutoRest" }, - "version": "1.14.3", + "version": "1.14.4", "description": "Client Runtime for Node.js client libraries generated using AutoRest", "tags": ["node", "microsoft", "autorest", "clientruntime"], "keywords": ["node", "microsoft", "autorest", "clientruntime"], @@ -15,10 +15,10 @@ "dependencies": { "underscore": "^1.4.0", "tunnel": "~0.0.2", - "request": "2.69.0", + "request": "2.72.0", "duplexer": "~0.1.1", "through": "~2.3.4", - "moment": "^2.9.0" + "moment": "^2.14.1" }, "devDependencies": { "jshint": "2.6.3", diff --git a/src/dev/TestServer/server/routes/complex.js b/src/dev/TestServer/server/routes/complex.js index 815c8257e8..f3ccda6174 100644 --- a/src/dev/TestServer/server/routes/complex.js +++ b/src/dev/TestServer/server/routes/complex.js @@ -4,473 +4,474 @@ var util = require('util'); var _ = require('underscore'); var utils = require('../util/utils') -var complex = function(coverage) { - /** +var complex = function (coverage) { + /** * Put and get for basic complex classes. */ - router.put('/basic/:scenario', function(req, res, next) { - if (req.params.scenario === 'valid') { - if (_.isEqual(req.body, {"id":2,"name":"abc", "color": "Magenta" })) { - coverage['putComplexBasicValid']++; - res.status(200).end(); - } else { - utils.send400(res, next, "Did not like valid req " + util.inspect(req.body)); - } - } else { - utils.send400(res, next, 'Must specify scenario either "valid" or "empty"'); - } - }); - - router.get('/basic/:scenario', function(req, res, next) { - if (req.params.scenario === 'valid') { - coverage['getComplexBasicValid']++; - res.status(200).end('{ "id": 2, "name": "abc", "color": "YELLOW" }'); - } else if (req.params.scenario === 'empty') { - coverage['getComplexBasicEmpty']++; - res.status(200).end('{ }'); - } else if (req.params.scenario === 'notprovided') { - coverage['getComplexBasicNotProvided']++; - res.status(200).end(); - } else if (req.params.scenario === 'null') { - coverage['getComplexBasicNull']++; - res.status(200).end('{ "id": null, "name": null }'); - } else if (req.params.scenario === 'invalid') { - coverage['getComplexBasicInvalid']++; - res.status(200).end('{ "id": "a", "name": "abc" }'); - } else { - res.status(400).send('Request scenario must be valid, empty, null, notprovided, or invalid.'); - } - }); - - /** + router.put('/basic/:scenario', function (req, res, next) { + if (req.params.scenario === 'valid') { + if (_.isEqual(req.body, { "id": 2, "name": "abc", "color": "Magenta" })) { + coverage['putComplexBasicValid']++; + res.status(200).end(); + } else { + utils.send400(res, next, "Did not like valid req " + util.inspect(req.body)); + } + } else { + utils.send400(res, next, 'Must specify scenario either "valid" or "empty"'); + } + }); + + router.get('/basic/:scenario', function (req, res, next) { + if (req.params.scenario === 'valid') { + coverage['getComplexBasicValid']++; + res.status(200).end('{ "id": 2, "name": "abc", "color": "YELLOW" }'); + } else if (req.params.scenario === 'empty') { + coverage['getComplexBasicEmpty']++; + res.status(200).end('{ }'); + } else if (req.params.scenario === 'notprovided') { + coverage['getComplexBasicNotProvided']++; + res.status(200).end(); + } else if (req.params.scenario === 'null') { + coverage['getComplexBasicNull']++; + res.status(200).end('{ "id": null, "name": null }'); + } else if (req.params.scenario === 'invalid') { + coverage['getComplexBasicInvalid']++; + res.status(200).end('{ "id": "a", "name": "abc" }'); + } else { + res.status(400).send('Request scenario must be valid, empty, null, notprovided, or invalid.'); + } + }); + + /** * Put and get for primitive */ - var intBody = {"field1":-1,"field2":2}; - var longBody = {"field1":1099511627775,"field2":-999511627788}; - var floatBody = {"field1":1.05,"field2":-0.003}; - var doubleBody = {"field1":3e-100,"field_56_zeros_after_the_dot_and_negative_zero_before_dot_and_this_is_a_long_field_name_on_purpose":-0.000000000000000000000000000000000000000000000000000000005}; - var doubleBodyInbound = {"field1":3e-100,"field_56_zeros_after_the_dot_and_negative_zero_before_dot_and_this_is_a_long_field_name_on_purpose":-5e-57}; - var boolBody = {"field_true":true,"field_false":false}; - var stringBody = {"field":"goodrequest","empty":"","null":null}; - var stringBodyInbound = {"field":"goodrequest","empty":""}; - var dateBody = {"field":"0001-01-01","leap":"2016-02-29"}; - var datetimeBody = {"field":"0001-01-01T00:00:00Z","now":"2015-05-18T18:38:00Z"}; - var datetimeRfc1123Body = {"field":"Mon, 01 Jan 0001 00:00:00 GMT","now":"Mon, 18 May 2015 11:38:00 GMT"}; - var datetimeRfc1123BodyAlternate = {"field":"Mon, 01 Jan 1 00:00:00 GMT","now":"Mon, 18 May 2015 11:38:00 GMT"}; - var durationBody = {"field":"P123DT22H14M12.011S"}; - var durationBodyAlternate = {"field":"P123DT22H14M12.010999999998603S"}; - var datetimeBodyExact = {"field":"0001-01-01T00:00:00.000Z","now":"2015-05-18T18:38:00.000Z"}; - var byteString = new Buffer([255, 254, 253, 252, 0, 250, 249, 248, 247, 246]).toString('base64'); - var byteBody = '{"field":"' + byteString + '"}'; - router.put('/primitive/:scenario', function(req, res, next) { - if (req.params.scenario === 'integer') { - if (_.isEqual(req.body, intBody)) { - coverage['putComplexPrimitiveInteger']++; - res.status(200).end(); - } else { - utils.send400(res, next, "Did not like integer req " + util.inspect(req.body)); - } - } else if (req.params.scenario === 'long') { - if (_.isEqual(req.body, longBody)) { - coverage['putComplexPrimitiveLong']++; - res.status(200).end(); - } else { - utils.send400(res, next, "Did not like long req " + util.inspect(req.body)); - } - } else if (req.params.scenario === 'float') { - if (_.isEqual(req.body, floatBody)) { - coverage['putComplexPrimitiveFloat']++; - res.status(200).end(); - } else { - utils.send400(res, next, "Did not like float req " + util.inspect(req.body)); - } - } else if (req.params.scenario === 'double') { - if (_.isEqual(req.body, doubleBodyInbound)) { - coverage['putComplexPrimitiveDouble']++; - res.status(200).end(); - } else { - utils.send400(res, next, "Did not like double req " + util.inspect(req.body)); - } - } else if (req.params.scenario === 'bool') { - if (_.isEqual(req.body, boolBody)) { - coverage['putComplexPrimitiveBool']++; - res.status(200).end(); - } else { - utils.send400(res, next, "Did not like bool req " + util.inspect(req.body)); - } - } else if (req.params.scenario === 'string') { - console.log(JSON.stringify(req.body)); - if (_.isEqual(req.body, stringBody) || _.isEqual(req.body, stringBodyInbound)) { - coverage['putComplexPrimitiveString']++; - res.status(200).end(); - } else { - utils.send400(res, next, "Did not like string req " + util.inspect(req.body)); - } - } else if (req.params.scenario === 'date') { - if (_.isEqual(req.body, dateBody)) { - coverage['putComplexPrimitiveDate']++; - res.status(200).end(); - } else { - utils.send400(res, next, "Did not like date req " + util.inspect(req.body)); - } - } else if (req.params.scenario === 'datetime') { - if (_.isEqual(req.body, datetimeBody) || _.isEqual(req.body, datetimeBodyExact)) { - coverage['putComplexPrimitiveDateTime']++; - res.status(200).end(); - } else { - utils.send400(res, next, "Did not like datetime req " + util.inspect(req.body)); - } - } else if (req.params.scenario === 'datetimerfc1123') { - if (_.isEqual(req.body, datetimeRfc1123Body) || _.isEqual(req.body, datetimeRfc1123BodyAlternate)) { - coverage['putComplexPrimitiveDateTimeRfc1123']++; - res.status(200).end(); - } else { - utils.send400(res, next, "Did not like datetimerfc1123 req " + util.inspect(req.body)); - } - } else if (req.params.scenario === 'duration') { - if (_.isEqual(req.body, durationBody) || _.isEqual(req.body, durationBodyAlternate)) { - coverage['putComplexPrimitiveDuration']++; - res.status(200).end(); - } else { - utils.send400(res, next, "Did not like duration req " + util.inspect(req.body)); - } - } else if (req.params.scenario === 'byte') { - if (JSON.stringify(req.body) === byteBody) { - coverage['putComplexPrimitiveByte']++; - res.status(200).end(); - } else { - utils.send400(res, next, "Did not like byte req " + util.inspect(req.body)); - } - } else { - utils.send400(res, next, 'Must provide a valid primitive type.'); - } - }); - - router.get('/primitive/:scenario', function(req, res, next) { - if (req.params.scenario === 'integer') { - coverage['getComplexPrimitiveInteger']++; - res.status(200).end(JSON.stringify(intBody)); - } else if (req.params.scenario === 'long') { - coverage['getComplexPrimitiveLong']++; - res.status(200).end(JSON.stringify(longBody)); - } else if (req.params.scenario === 'float') { - coverage['getComplexPrimitiveFloat']++; - res.status(200).end(JSON.stringify(floatBody)); - } else if (req.params.scenario === 'double') { - coverage['getComplexPrimitiveDouble']++; - res.status(200).end(JSON.stringify(doubleBody)); - } else if (req.params.scenario === 'bool') { - coverage['getComplexPrimitiveBool']++; - res.status(200).end(JSON.stringify(boolBody)); - } else if (req.params.scenario === 'string') { - coverage['getComplexPrimitiveString']++; - res.status(200).end(JSON.stringify(stringBody)); - } else if (req.params.scenario === 'date') { - coverage['getComplexPrimitiveDate']++; - res.status(200).end(JSON.stringify(dateBody)); - } else if (req.params.scenario === 'datetime') { - coverage['getComplexPrimitiveDateTime']++; - res.status(200).end(JSON.stringify(datetimeBody)); - } else if (req.params.scenario === 'datetimerfc1123') { - coverage['getComplexPrimitiveDateTimeRfc1123']++; - res.status(200).end(JSON.stringify(datetimeRfc1123Body)); - } else if (req.params.scenario === 'duration') { - coverage['getComplexPrimitiveDuration']++; - res.status(200).end(JSON.stringify(durationBody)); - } else if (req.params.scenario === 'byte') { - coverage['getComplexPrimitiveByte']++; - res.status(200).end(byteBody); - } else { - utils.send400(res, next, 'Must provide a valid primitive type scenario.'); - } - }); - - /** + var intBody = { "field1": -1, "field2": 2 }; + var longBody = { "field1": 1099511627775, "field2": -999511627788 }; + var floatBody = { "field1": 1.05, "field2": -0.003 }; + var doubleBody = { "field1": 3e-100, "field_56_zeros_after_the_dot_and_negative_zero_before_dot_and_this_is_a_long_field_name_on_purpose": -0.000000000000000000000000000000000000000000000000000000005 }; + var doubleBodyInbound = { "field1": 3e-100, "field_56_zeros_after_the_dot_and_negative_zero_before_dot_and_this_is_a_long_field_name_on_purpose": -5e-57 }; + var boolBody = { "field_true": true, "field_false": false }; + var stringBody = { "field": "goodrequest", "empty": "", "null": null }; + var stringBodyInbound = { "field": "goodrequest", "empty": "" }; + var dateBody = { "field": "0001-01-01", "leap": "2016-02-29" }; + var datetimeBody = { "field": "0001-01-01T00:00:00Z", "now": "2015-05-18T18:38:00Z" }; + var datetimeRfc1123Body = { "field": "Mon, 01 Jan 0001 00:00:00 GMT", "now": "Mon, 18 May 2015 11:38:00 GMT" }; + var datetimeRfc1123BodyAlternate = { "field": "Mon, 01 Jan 1 00:00:00 GMT", "now": "Mon, 18 May 2015 11:38:00 GMT" }; + var datetimeRfc1123BodyAlternateWithSpaces = { "field": "Mon, 01 Jan 1 00:00:00 GMT", "now": "Mon, 18 May 2015 11:38:00 GMT" }; + var durationBody = { "field": "P123DT22H14M12.011S" }; + var durationBodyAlternate = { "field": "P123DT22H14M12.010999999998603S" }; + var datetimeBodyExact = { "field": "0001-01-01T00:00:00.000Z", "now": "2015-05-18T18:38:00.000Z" }; + var byteString = new Buffer([255, 254, 253, 252, 0, 250, 249, 248, 247, 246]).toString('base64'); + var byteBody = '{"field":"' + byteString + '"}'; + router.put('/primitive/:scenario', function (req, res, next) { + if (req.params.scenario === 'integer') { + if (_.isEqual(req.body, intBody)) { + coverage['putComplexPrimitiveInteger']++; + res.status(200).end(); + } else { + utils.send400(res, next, "Did not like integer req " + util.inspect(req.body)); + } + } else if (req.params.scenario === 'long') { + if (_.isEqual(req.body, longBody)) { + coverage['putComplexPrimitiveLong']++; + res.status(200).end(); + } else { + utils.send400(res, next, "Did not like long req " + util.inspect(req.body)); + } + } else if (req.params.scenario === 'float') { + if (_.isEqual(req.body, floatBody)) { + coverage['putComplexPrimitiveFloat']++; + res.status(200).end(); + } else { + utils.send400(res, next, "Did not like float req " + util.inspect(req.body)); + } + } else if (req.params.scenario === 'double') { + if (_.isEqual(req.body, doubleBodyInbound)) { + coverage['putComplexPrimitiveDouble']++; + res.status(200).end(); + } else { + utils.send400(res, next, "Did not like double req " + util.inspect(req.body)); + } + } else if (req.params.scenario === 'bool') { + if (_.isEqual(req.body, boolBody)) { + coverage['putComplexPrimitiveBool']++; + res.status(200).end(); + } else { + utils.send400(res, next, "Did not like bool req " + util.inspect(req.body)); + } + } else if (req.params.scenario === 'string') { + console.log(JSON.stringify(req.body)); + if (_.isEqual(req.body, stringBody) || _.isEqual(req.body, stringBodyInbound)) { + coverage['putComplexPrimitiveString']++; + res.status(200).end(); + } else { + utils.send400(res, next, "Did not like string req " + util.inspect(req.body)); + } + } else if (req.params.scenario === 'date') { + if (_.isEqual(req.body, dateBody)) { + coverage['putComplexPrimitiveDate']++; + res.status(200).end(); + } else { + utils.send400(res, next, "Did not like date req " + util.inspect(req.body)); + } + } else if (req.params.scenario === 'datetime') { + if (_.isEqual(req.body, datetimeBody) || _.isEqual(req.body, datetimeBodyExact)) { + coverage['putComplexPrimitiveDateTime']++; + res.status(200).end(); + } else { + utils.send400(res, next, "Did not like datetime req " + util.inspect(req.body)); + } + } else if (req.params.scenario === 'datetimerfc1123') { + if (_.isEqual(req.body, datetimeRfc1123Body) || _.isEqual(req.body, datetimeRfc1123BodyAlternate) || _.isEqual(req.body, datetimeRfc1123BodyAlternateWithSpaces)) { + coverage['putComplexPrimitiveDateTimeRfc1123']++; + res.status(200).end(); + } else { + utils.send400(res, next, "Did not like datetimerfc1123 req " + util.inspect(req.body)); + } + } else if (req.params.scenario === 'duration') { + if (_.isEqual(req.body, durationBody) || _.isEqual(req.body, durationBodyAlternate)) { + coverage['putComplexPrimitiveDuration']++; + res.status(200).end(); + } else { + utils.send400(res, next, "Did not like duration req " + util.inspect(req.body)); + } + } else if (req.params.scenario === 'byte') { + if (JSON.stringify(req.body) === byteBody) { + coverage['putComplexPrimitiveByte']++; + res.status(200).end(); + } else { + utils.send400(res, next, "Did not like byte req " + util.inspect(req.body)); + } + } else { + utils.send400(res, next, 'Must provide a valid primitive type.'); + } + }); + + router.get('/primitive/:scenario', function (req, res, next) { + if (req.params.scenario === 'integer') { + coverage['getComplexPrimitiveInteger']++; + res.status(200).end(JSON.stringify(intBody)); + } else if (req.params.scenario === 'long') { + coverage['getComplexPrimitiveLong']++; + res.status(200).end(JSON.stringify(longBody)); + } else if (req.params.scenario === 'float') { + coverage['getComplexPrimitiveFloat']++; + res.status(200).end(JSON.stringify(floatBody)); + } else if (req.params.scenario === 'double') { + coverage['getComplexPrimitiveDouble']++; + res.status(200).end(JSON.stringify(doubleBody)); + } else if (req.params.scenario === 'bool') { + coverage['getComplexPrimitiveBool']++; + res.status(200).end(JSON.stringify(boolBody)); + } else if (req.params.scenario === 'string') { + coverage['getComplexPrimitiveString']++; + res.status(200).end(JSON.stringify(stringBody)); + } else if (req.params.scenario === 'date') { + coverage['getComplexPrimitiveDate']++; + res.status(200).end(JSON.stringify(dateBody)); + } else if (req.params.scenario === 'datetime') { + coverage['getComplexPrimitiveDateTime']++; + res.status(200).end(JSON.stringify(datetimeBody)); + } else if (req.params.scenario === 'datetimerfc1123') { + coverage['getComplexPrimitiveDateTimeRfc1123']++; + res.status(200).end(JSON.stringify(datetimeRfc1123Body)); + } else if (req.params.scenario === 'duration') { + coverage['getComplexPrimitiveDuration']++; + res.status(200).end(JSON.stringify(durationBody)); + } else if (req.params.scenario === 'byte') { + coverage['getComplexPrimitiveByte']++; + res.status(200).end(byteBody); + } else { + utils.send400(res, next, 'Must provide a valid primitive type scenario.'); + } + }); + + /** * Put and get for array properties. */ var arrayValidBody = '{"array":["1, 2, 3, 4","",null,"&S#$(*Y","The quick brown fox jumps over the lazy dog"]}'; - router.put('/array/:scenario', function(req, res, next) { - if (req.params.scenario === 'valid') { - if (JSON.stringify(req.body) === arrayValidBody) { - coverage['putComplexArrayValid']++; - res.status(200).end(); - } else { - utils.send400(res, next, "Did not like complex array req " + util.inspect(req.body)); - } - } else if (req.params.scenario === 'empty') { - if (JSON.stringify(req.body) === '{"array":[]}') { - coverage['putComplexArrayEmpty']++; - res.status(200).end(); - } else { - utils.send400(res, next, "Did not like complex array req " + util.inspect(req.body)); - } - } else { - utils.send400(res, next, 'Must provide a valid scenario.'); - } - }); - - router.get('/array/:scenario', function(req, res, next) { - if (req.params.scenario === 'valid') { - coverage['getComplexArrayValid']++; - res.status(200).end(arrayValidBody); - } else if (req.params.scenario === 'empty') { - coverage['getComplexArrayEmpty']++; - res.status(200).end('{"array":[]}'); - } else if (req.params.scenario === 'notprovided') { - coverage['getComplexArrayNotProvided']++; - res.status(200).end('{}'); - } else { - utils.send400(res, next, 'Must provide a valid scenario.'); - } - }); - - /** + router.put('/array/:scenario', function (req, res, next) { + if (req.params.scenario === 'valid') { + if (JSON.stringify(req.body) === arrayValidBody) { + coverage['putComplexArrayValid']++; + res.status(200).end(); + } else { + utils.send400(res, next, "Did not like complex array req " + util.inspect(req.body)); + } + } else if (req.params.scenario === 'empty') { + if (JSON.stringify(req.body) === '{"array":[]}') { + coverage['putComplexArrayEmpty']++; + res.status(200).end(); + } else { + utils.send400(res, next, "Did not like complex array req " + util.inspect(req.body)); + } + } else { + utils.send400(res, next, 'Must provide a valid scenario.'); + } + }); + + router.get('/array/:scenario', function (req, res, next) { + if (req.params.scenario === 'valid') { + coverage['getComplexArrayValid']++; + res.status(200).end(arrayValidBody); + } else if (req.params.scenario === 'empty') { + coverage['getComplexArrayEmpty']++; + res.status(200).end('{"array":[]}'); + } else if (req.params.scenario === 'notprovided') { + coverage['getComplexArrayNotProvided']++; + res.status(200).end('{}'); + } else { + utils.send400(res, next, 'Must provide a valid scenario.'); + } + }); + + /** * Put and get for typed dictionary properties. */ var dictionaryValidBody = '{"defaultProgram":{"txt":"notepad","bmp":"mspaint","xls":"excel","exe":"","":null}}'; - router.put('/dictionary/typed/:scenario', function(req, res, next) { - if (req.params.scenario === 'valid') { - if (_.isEqual(req.body, JSON.parse(dictionaryValidBody))) { - coverage['putComplexDictionaryValid']++; - res.status(200).end(); - } else { - utils.send400(res, next, "Did not like complex dictionary req " + util.inspect(req.body)); - } - } else if (req.params.scenario === 'empty') { - if (JSON.stringify(req.body) === '{"defaultProgram":{}}') { - coverage['putComplexDictionaryEmpty']++; - res.status(200).end(); - } else { - utils.send400(res, next, "Did not like complex array req " + util.inspect(req.body)); - } - } else { - utils.send400(res, next, 'Must provide a valid scenario.'); - } - }); - - router.get('/dictionary/typed/:scenario', function(req, res, next) { - if (req.params.scenario === 'valid') { - coverage['getComplexDictionaryValid']++; - res.status(200).end(dictionaryValidBody); - } else if (req.params.scenario === 'empty') { - coverage['getComplexDictionaryEmpty']++; - res.status(200).end('{"defaultProgram":{}}'); - } else if (req.params.scenario === 'null') { - coverage['getComplexDictionaryNull']++; - res.status(200).end('{"defaultProgram":null}'); - } else if (req.params.scenario === 'notprovided') { - coverage['getComplexDictionaryNotProvided']++; - res.status(200).end('{}'); - } else { - utils.send400(res, next, 'Must provide a valid scenario.'); - } - }); - - /** + router.put('/dictionary/typed/:scenario', function (req, res, next) { + if (req.params.scenario === 'valid') { + if (_.isEqual(req.body, JSON.parse(dictionaryValidBody))) { + coverage['putComplexDictionaryValid']++; + res.status(200).end(); + } else { + utils.send400(res, next, "Did not like complex dictionary req " + util.inspect(req.body)); + } + } else if (req.params.scenario === 'empty') { + if (JSON.stringify(req.body) === '{"defaultProgram":{}}') { + coverage['putComplexDictionaryEmpty']++; + res.status(200).end(); + } else { + utils.send400(res, next, "Did not like complex array req " + util.inspect(req.body)); + } + } else { + utils.send400(res, next, 'Must provide a valid scenario.'); + } + }); + + router.get('/dictionary/typed/:scenario', function (req, res, next) { + if (req.params.scenario === 'valid') { + coverage['getComplexDictionaryValid']++; + res.status(200).end(dictionaryValidBody); + } else if (req.params.scenario === 'empty') { + coverage['getComplexDictionaryEmpty']++; + res.status(200).end('{"defaultProgram":{}}'); + } else if (req.params.scenario === 'null') { + coverage['getComplexDictionaryNull']++; + res.status(200).end('{"defaultProgram":null}'); + } else if (req.params.scenario === 'notprovided') { + coverage['getComplexDictionaryNotProvided']++; + res.status(200).end('{}'); + } else { + utils.send400(res, next, 'Must provide a valid scenario.'); + } + }); + + /** * Put and get for untyped dictionary properties. */ - router.put('/dictionary/untyped/:scenario', function(req, res, next) { - res.status(501).end("Untyped dictionaries are not supported for now."); - }); - - router.get('/dictionary/untyped/:scenario', function(req, res, next) { - res.status(501).end("Untyped dictionaries are not supported for now."); - }); - - /** + router.put('/dictionary/untyped/:scenario', function (req, res, next) { + res.status(501).end("Untyped dictionaries are not supported for now."); + }); + + router.get('/dictionary/untyped/:scenario', function (req, res, next) { + res.status(501).end("Untyped dictionaries are not supported for now."); + }); + + /** * Put and get for inhertiance. */ var siamese = '{"breed":"persian","color":"green","hates":[{"food":"tomato","id":1,"name":"Potato"},{"food":"french fries","id":-1,"name":"Tomato"}],"id":2,"name":"Siameeee"}'; - - router.put('/inheritance/:scenario', function(req, res, next) { - if (req.params.scenario === 'valid') { - if (_.isEqual(req.body, JSON.parse(siamese))) { - coverage['putComplexInheritanceValid']++; - res.status(200).end(); - } else { - utils.send400(res, next, "Did not like complex inheritance req " + util.inspect(req.body)); - } - } else { - utils.send400(res, next, 'Must provide a valid scenario.'); - } - }); - - router.get('/inheritance/:scenario', function(req, res, next) { - if (req.params.scenario === 'valid') { - coverage['getComplexInheritanceValid']++; - res.status(200).end(siamese); - } else { - utils.send400(res, next, 'Must provide a valid scenario.'); - } - }); - - /** + + router.put('/inheritance/:scenario', function (req, res, next) { + if (req.params.scenario === 'valid') { + if (_.isEqual(req.body, JSON.parse(siamese))) { + coverage['putComplexInheritanceValid']++; + res.status(200).end(); + } else { + utils.send400(res, next, "Did not like complex inheritance req " + util.inspect(req.body)); + } + } else { + utils.send400(res, next, 'Must provide a valid scenario.'); + } + }); + + router.get('/inheritance/:scenario', function (req, res, next) { + if (req.params.scenario === 'valid') { + coverage['getComplexInheritanceValid']++; + res.status(200).end(siamese); + } else { + utils.send400(res, next, 'Must provide a valid scenario.'); + } + }); + + /** * Put and get for polymorphism. */ var rawFish = + { + 'fishtype': 'salmon', + 'location': 'alaska', + 'iswild': true, + 'species': 'king', + 'length': 1.0, + 'siblings': [ { - 'fishtype':'salmon', - 'location':'alaska', - 'iswild':true, - 'species':'king', - 'length':1.0, - 'siblings':[ - { - 'fishtype':'shark', - 'age':6, - 'birthday': '2012-01-05T01:00:00Z', - 'length':20.0, - 'species':'predator', - }, - { - 'fishtype':'sawshark', - 'age':105, - 'birthday': '1900-01-05T01:00:00Z', - 'length':10.0, - 'picture': new Buffer([255, 255, 255, 255, 254]).toString('base64'), - 'species':'dangerous', - }, - { - 'fishtype': 'goblin', - 'age': 1, - 'birthday': '2015-08-08T00:00:00Z', - 'length': 30.0, - 'species': 'scary', - 'jawsize': 5 - } - ] - }; - - router.put('/polymorphism/:scenario', function(req, res, next) { - if (req.params.scenario === 'valid') { - console.log(JSON.stringify(req.body, null, 4)); - console.log(JSON.stringify(rawFish, null, 4)); - if (_.isEqual(utils.coerceDate(req.body), rawFish) ) { - coverage['putComplexPolymorphismValid']++; - res.status(200).end(); - } else { - utils.send400(res, next, "Did not like complex polymorphism req " + util.inspect(req.body)); - } - } else { - utils.send400(res, next, 'Must provide a valid scenario.'); - } - }); - - router.get('/polymorphism/:scenario', function(req, res, next) { - if (req.params.scenario === 'valid') { - coverage['getComplexPolymorphismValid']++; - res.status(200).end(JSON.stringify(rawFish)); - } else { - utils.send400(res, next, 'Must provide a valid scenario.'); - } - }); - - router.put('/polymorphism/missingrequired/invalid', function(req, res, next) { - utils.send400(res, next, 'Reached server in scenario: /complex/polymorphism/missingrequired/invalid, and should not have - since required fields are missing from the request, the client should not be able to send it.') - }) - - /** + 'fishtype': 'shark', + 'age': 6, + 'birthday': '2012-01-05T01:00:00Z', + 'length': 20.0, + 'species': 'predator', + }, + { + 'fishtype': 'sawshark', + 'age': 105, + 'birthday': '1900-01-05T01:00:00Z', + 'length': 10.0, + 'picture': new Buffer([255, 255, 255, 255, 254]).toString('base64'), + 'species': 'dangerous', + }, + { + 'fishtype': 'goblin', + 'age': 1, + 'birthday': '2015-08-08T00:00:00Z', + 'length': 30.0, + 'species': 'scary', + 'jawsize': 5 + } + ] + }; + + router.put('/polymorphism/:scenario', function (req, res, next) { + if (req.params.scenario === 'valid') { + console.log(JSON.stringify(req.body, null, 4)); + console.log(JSON.stringify(rawFish, null, 4)); + if (_.isEqual(utils.coerceDate(req.body), rawFish)) { + coverage['putComplexPolymorphismValid']++; + res.status(200).end(); + } else { + utils.send400(res, next, "Did not like complex polymorphism req " + util.inspect(req.body)); + } + } else { + utils.send400(res, next, 'Must provide a valid scenario.'); + } + }); + + router.get('/polymorphism/:scenario', function (req, res, next) { + if (req.params.scenario === 'valid') { + coverage['getComplexPolymorphismValid']++; + res.status(200).end(JSON.stringify(rawFish)); + } else { + utils.send400(res, next, 'Must provide a valid scenario.'); + } + }); + + router.put('/polymorphism/missingrequired/invalid', function (req, res, next) { + utils.send400(res, next, 'Reached server in scenario: /complex/polymorphism/missingrequired/invalid, and should not have - since required fields are missing from the request, the client should not be able to send it.') + }) + + /** * Put and get for recursive reference. */ var bigfishRaw = { - "fishtype":"salmon", - "location":"alaska", - "iswild":true, - "species":"king", - "length":1, - "siblings":[ + "fishtype": "salmon", + "location": "alaska", + "iswild": true, + "species": "king", + "length": 1, + "siblings": [ + { + "fishtype": "shark", + "age": 6, + 'birthday': '2012-01-05T01:00:00Z', + "species": "predator", + "length": 20, + "siblings": [ { - "fishtype":"shark", - "age":6, - 'birthday': '2012-01-05T01:00:00Z', - "species":"predator", - "length":20, - "siblings":[ - { - "fishtype":"salmon", - "location":"atlantic", - "iswild":true, - "species":"coho", - "length":2, - "siblings":[ - { - "fishtype":"shark", - "age":6, - 'birthday': '2012-01-05T01:00:00Z', - "species":"predator", - "length":20 - }, - { - "fishtype":"sawshark", - "age":105, - 'birthday': '1900-01-05T01:00:00Z', - 'picture': new Buffer([255, 255, 255, 255, 254]).toString('base64'), - "species":"dangerous", - "length":10 - } - ] - }, - { - "fishtype":"sawshark", - "age":105, - 'birthday': '1900-01-05T01:00:00Z', - 'picture': new Buffer([255, 255, 255, 255, 254]).toString('base64'), - "species":"dangerous", - "length":10, - "siblings":[] - } + "fishtype": "salmon", + "location": "atlantic", + "iswild": true, + "species": "coho", + "length": 2, + "siblings": [ + { + "fishtype": "shark", + "age": 6, + 'birthday': '2012-01-05T01:00:00Z', + "species": "predator", + "length": 20 + }, + { + "fishtype": "sawshark", + "age": 105, + 'birthday': '1900-01-05T01:00:00Z', + 'picture': new Buffer([255, 255, 255, 255, 254]).toString('base64'), + "species": "dangerous", + "length": 10 + } ] }, { - "fishtype":"sawshark", - "age":105, + "fishtype": "sawshark", + "age": 105, 'birthday': '1900-01-05T01:00:00Z', 'picture': new Buffer([255, 255, 255, 255, 254]).toString('base64'), - "species":"dangerous", - "length":10,"siblings":[] + "species": "dangerous", + "length": 10, + "siblings": [] } ] - }; - - - router.put('/polymorphicrecursive/:scenario', function(req, res, next) { - if (req.params.scenario === 'valid') { - console.log(JSON.stringify(req.body, null, 4)); - console.log(JSON.stringify(bigfishRaw, null, 4)); - if (_.isEqual(utils.coerceDate(req.body), bigfishRaw) ) { - coverage['putComplexPolymorphicRecursiveValid']++; - res.status(200).end(); - } else { - utils.send400(res, next, "Did not like complex polymorphic recursive req " + util.inspect(req.body)); - } - } else { - utils.send400(res, next, 'Must provide a valid scenario.'); - } - }); - - router.get('/polymorphicrecursive/:scenario', function(req, res, next) { - if (req.params.scenario === 'valid') { - coverage['getComplexPolymorphicRecursiveValid']++; - res.status(200).end(JSON.stringify(bigfishRaw)); - } else { - utils.send400(res, next, 'Must provide a valid scenario.'); - } - }); - - router.get('/readonlyproperty/valid', function(req, res, next) { - res.status(200).end(JSON.stringify({"id": "1234", "size": 2})); - }); - - router.put('/readonlyproperty/valid', function(req, res, next) { - if (req.body) { - if (typeof req.body.id == "undefined") { - coverage["putComplexReadOnlyPropertyValid"]++; - res.status(200).end(); - } else { - utils.send400(res, next, 'id is readonly'); - } - } - }); + }, + { + "fishtype": "sawshark", + "age": 105, + 'birthday': '1900-01-05T01:00:00Z', + 'picture': new Buffer([255, 255, 255, 255, 254]).toString('base64'), + "species": "dangerous", + "length": 10, "siblings": [] + } + ] + }; + + + router.put('/polymorphicrecursive/:scenario', function (req, res, next) { + if (req.params.scenario === 'valid') { + console.log(JSON.stringify(req.body, null, 4)); + console.log(JSON.stringify(bigfishRaw, null, 4)); + if (_.isEqual(utils.coerceDate(req.body), bigfishRaw)) { + coverage['putComplexPolymorphicRecursiveValid']++; + res.status(200).end(); + } else { + utils.send400(res, next, "Did not like complex polymorphic recursive req " + util.inspect(req.body)); + } + } else { + utils.send400(res, next, 'Must provide a valid scenario.'); + } + }); + + router.get('/polymorphicrecursive/:scenario', function (req, res, next) { + if (req.params.scenario === 'valid') { + coverage['getComplexPolymorphicRecursiveValid']++; + res.status(200).end(JSON.stringify(bigfishRaw)); + } else { + utils.send400(res, next, 'Must provide a valid scenario.'); + } + }); + + router.get('/readonlyproperty/valid', function (req, res, next) { + res.status(200).end(JSON.stringify({ "id": "1234", "size": 2 })); + }); + + router.put('/readonlyproperty/valid', function (req, res, next) { + if (req.body) { + if (typeof req.body.id == "undefined") { + coverage["putComplexReadOnlyPropertyValid"]++; + res.status(200).end(); + } else { + utils.send400(res, next, 'id is readonly'); + } + } + }); }; complex.prototype.router = router; diff --git a/src/dev/TestServer/server/routes/header.js b/src/dev/TestServer/server/routes/header.js index c1cf54d648..087b29b6b2 100644 --- a/src/dev/TestServer/server/routes/header.js +++ b/src/dev/TestServer/server/routes/header.js @@ -201,7 +201,7 @@ var header = function (coverage, optionalCoverage) { break; } } else if (scenario === "min") { - if (value === "Mon, 01 Jan 0001 00:00:00 GMT" || value == "Mon, 01 Jan 1 00:00:00 GMT") { + if (value === "Mon, 01 Jan 0001 00:00:00 GMT" || value == "Mon, 01 Jan 1 00:00:00 GMT" || value == "Mon, 01 Jan 1 00:00:00 GMT") { coverage['HeaderParameterDateTimeRfc1123Min']++; res.status(200).end(); break; diff --git a/src/generator/AutoRest.NodeJS.Azure.Tests/AcceptanceTests/lro.js b/src/generator/AutoRest.NodeJS.Azure.Tests/AcceptanceTests/lro.js index 1f31c354a1..fc5b71efd1 100644 --- a/src/generator/AutoRest.NodeJS.Azure.Tests/AcceptanceTests/lro.js +++ b/src/generator/AutoRest.NodeJS.Azure.Tests/AcceptanceTests/lro.js @@ -532,7 +532,7 @@ describe('nodejs', function () { it('should throw on Put200InvalidJson', function (done) { testClient.lROSADs.put200InvalidJson(product, function (error, result) { should.exist(error); - error.message.should.containEql('SyntaxError: Unexpected end of input'); + error.message.should.match(/.*SyntaxError: Unexpected end of (json\s)?input.*/ig); done(); }); }); @@ -548,7 +548,7 @@ describe('nodejs', function () { it('should throw on PutAsyncRelativeRetryInvalidJsonPolling', function (done) { testClient.lROSADs.putAsyncRelativeRetryInvalidJsonPolling(product, function (error, result) { should.exist(error); - error.message.should.match(/.*SyntaxError: Unexpected end of input.*/ig); + error.message.should.match(/.*SyntaxError: Unexpected end of (json\s)?input.*/ig); done(); }); }); @@ -572,7 +572,7 @@ describe('nodejs', function () { it('should throw on DeleteAsyncRelativeRetryInvalidJsonPolling', function (done) { testClient.lROSADs.deleteAsyncRelativeRetryInvalidJsonPolling(function (error, result) { should.exist(error); - error.message.should.match(/.*SyntaxError: Unexpected end of input.*/ig); + error.message.should.match(/.*SyntaxError: Unexpected end of (json\s)?input.*/ig); done(); }); }); @@ -596,7 +596,7 @@ describe('nodejs', function () { it('should throw on PostAsyncRelativeRetryInvalidJsonPolling', function (done) { testClient.lROSADs.postAsyncRelativeRetryInvalidJsonPolling(product, function (error, result) { should.exist(error); - error.message.should.match(/.*SyntaxError: Unexpected end of input.*/ig); + error.message.should.match(/.*SyntaxError: Unexpected end of (json\s)?input.*/ig); done(); }); }); diff --git a/src/generator/AutoRest.NodeJS.Azure.Tests/package.json b/src/generator/AutoRest.NodeJS.Azure.Tests/package.json index 6e55f6da42..80683f7003 100644 --- a/src/generator/AutoRest.NodeJS.Azure.Tests/package.json +++ b/src/generator/AutoRest.NodeJS.Azure.Tests/package.json @@ -21,7 +21,7 @@ "ms-rest": "file:../../client/NodeJS/ms-rest", "ms-rest-azure": "file:../../client/NodeJS/ms-rest-azure", "jshint": "2.8.0", - "moment": "*", + "moment": "^2.14.1", "xunit-file": "0.0.5", "mocha": "2.2.5", "should": "5.2.0", diff --git a/src/generator/AutoRest.NodeJS.Azure/AzureNodeJSCodeGenerator.cs b/src/generator/AutoRest.NodeJS.Azure/AzureNodeJSCodeGenerator.cs index d945914b70..84ec4a2577 100644 --- a/src/generator/AutoRest.NodeJS.Azure/AzureNodeJSCodeGenerator.cs +++ b/src/generator/AutoRest.NodeJS.Azure/AzureNodeJSCodeGenerator.cs @@ -20,7 +20,7 @@ namespace AutoRest.NodeJS.Azure { public class AzureNodeJSCodeGenerator : NodeJSCodeGenerator { - private const string ClientRuntimePackage = "ms-rest-azure version 1.14.2"; + private const string ClientRuntimePackage = "ms-rest-azure version 1.14.5"; // List of models with paging extensions. private IList pageModels; diff --git a/src/generator/AutoRest.NodeJS.Tests/package.json b/src/generator/AutoRest.NodeJS.Tests/package.json index 55766a985b..f293658f02 100644 --- a/src/generator/AutoRest.NodeJS.Tests/package.json +++ b/src/generator/AutoRest.NodeJS.Tests/package.json @@ -22,7 +22,7 @@ "jshint": "2.8.0", "xunit-file": "0.0.5", "mocha": "2.2.5", - "moment": "2.10.6", + "moment": "^2.14.1", "should": "5.2.0", "underscore": "*" }, diff --git a/src/generator/AutoRest.NodeJS/NodeJSCodeGenerator.cs b/src/generator/AutoRest.NodeJS/NodeJSCodeGenerator.cs index 48aee00e06..77d135f205 100644 --- a/src/generator/AutoRest.NodeJS/NodeJSCodeGenerator.cs +++ b/src/generator/AutoRest.NodeJS/NodeJSCodeGenerator.cs @@ -17,7 +17,7 @@ namespace AutoRest.NodeJS { public class NodeJSCodeGenerator : CodeGenerator { - private const string ClientRuntimePackage = "ms-rest version 1.14.2"; + private const string ClientRuntimePackage = "ms-rest version 1.14.4"; public NodeJsCodeNamer Namer { get; private set; }