diff --git a/AutoRest/AutoRest/AutoRest.csproj b/AutoRest/AutoRest/AutoRest.csproj index 8bd5ec84e97dd..7c578e0980acb 100644 --- a/AutoRest/AutoRest/AutoRest.csproj +++ b/AutoRest/AutoRest/AutoRest.csproj @@ -31,6 +31,7 @@ Properties\AssemblyVersionInfo.cs + @@ -70,4 +71,4 @@ - + \ No newline at end of file diff --git a/AutoRest/AutoRest/ExitCode.cs b/AutoRest/AutoRest/ExitCode.cs new file mode 100644 index 0000000000000..fe09a82b44c21 --- /dev/null +++ b/AutoRest/AutoRest/ExitCode.cs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +namespace Microsoft.Rest.Generator.Cli +{ + /// + /// Available exit codes. + /// + public enum ExitCode : int + { + Success = 0, + Error = 1 + } +} diff --git a/AutoRest/AutoRest/Program.cs b/AutoRest/AutoRest/Program.cs index b0c4aa7abea2b..f7bdf406b1066 100644 --- a/AutoRest/AutoRest/Program.cs +++ b/AutoRest/AutoRest/Program.cs @@ -12,8 +12,10 @@ namespace Microsoft.Rest.Generator.Cli { internal class Program { - private static void Main(string[] args) + private static int Main(string[] args) { + int exitCode = (int)ExitCode.Error; + try { Settings settings = null; @@ -69,6 +71,7 @@ private static void Main(string[] args) { Console.WriteLine(Resources.GenerationComplete, settings.CodeGenerator, settings.Input); + exitCode = (int)ExitCode.Success; } } @@ -91,6 +94,7 @@ private static void Main(string[] args) Console.Error.WriteLine(Resources.ConsoleErrorMessage, exception.Message); Console.Error.WriteLine(Resources.ConsoleErrorStackTrace, exception.StackTrace); } + return exitCode; } /// diff --git a/AutoRest/Generators/AzureResourceSchema/AzureResourceSchema/AutoRest.Generator.AzureResourceSchema.csproj b/AutoRest/Generators/AzureResourceSchema/AzureResourceSchema/AutoRest.Generator.AzureResourceSchema.csproj index d5fb8d215a8db..efd0dc9af685d 100644 --- a/AutoRest/Generators/AzureResourceSchema/AzureResourceSchema/AutoRest.Generator.AzureResourceSchema.csproj +++ b/AutoRest/Generators/AzureResourceSchema/AzureResourceSchema/AutoRest.Generator.AzureResourceSchema.csproj @@ -32,6 +32,7 @@ + diff --git a/AutoRest/Generators/AzureResourceSchema/AzureResourceSchema/ResourceProperty.cs b/AutoRest/Generators/AzureResourceSchema/AzureResourceSchema/ResourceProperty.cs new file mode 100644 index 0000000000000..7212e90200bc7 --- /dev/null +++ b/AutoRest/Generators/AzureResourceSchema/AzureResourceSchema/ResourceProperty.cs @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System.Collections.Generic; + +namespace Microsoft.Rest.Generator.AzureResourceSchema +{ + public class ResourceProperty + { + private readonly string name; + private readonly bool isRequired; + private readonly string propertyType; + private readonly IEnumerable allowedValues; + private readonly string description; + + public ResourceProperty(string name, bool isRequired, string propertyType, IEnumerable allowedValues, string description) + { + this.name = name; + this.isRequired = isRequired; + this.propertyType = propertyType; + this.allowedValues = allowedValues; + this.description = description; + } + + public string Name + { + get { return name; } + } + + public bool IsRequired + { + get { return isRequired; } + } + + public string PropertyType + { + get { return propertyType; } + } + + public IEnumerable AllowedValues + { + get { return allowedValues; } + } + + public string Description + { + get { return description; } + } + } +} diff --git a/AutoRest/Generators/CSharp/Azure.CSharp.Tests/AcceptanceTests.cs b/AutoRest/Generators/CSharp/Azure.CSharp.Tests/AcceptanceTests.cs index d04c712fd1c96..6c254399697c3 100644 --- a/AutoRest/Generators/CSharp/Azure.CSharp.Tests/AcceptanceTests.cs +++ b/AutoRest/Generators/CSharp/Azure.CSharp.Tests/AcceptanceTests.cs @@ -274,6 +274,10 @@ public void LroSadPathTests() Assert.Equal("Error from the server", exception.Body.Message); Assert.NotNull(exception.Request); Assert.NotNull(exception.Response); + exception = + Assert.Throws(() => client.LROSADs.PutNonRetry201Creating400InvalidJson(new Product { Location = "West US" })); + Assert.Null(exception.Body); + Assert.Equal("Long running operation failed with status 'BadRequest'.", exception.Message); exception = Assert.Throws( () => client.LROSADs.PutAsyncRelativeRetry400(new Product {Location = "West US"})); @@ -527,8 +531,7 @@ public void AzureODataTests() Top = 10, OrderBy = "id" }; - var filterString = Uri.EscapeDataString("id gt 5 and name eq 'foo'"); - Assert.Equal(string.Format("$filter={0}&$orderby=id&$top=10", filterString), filter.ToString()); + Assert.Equal("$filter=id gt 5 and name eq 'foo'&$orderby=id&$top=10", filter.ToString()); client.Odata.GetWithFilter(filter); } } diff --git a/AutoRest/Generators/CSharp/Azure.CSharp.Tests/Expected/AcceptanceTests/Lro/ILROSADsOperations.cs b/AutoRest/Generators/CSharp/Azure.CSharp.Tests/Expected/AcceptanceTests/Lro/ILROSADsOperations.cs index 60ac71a045d3e..5717f7f8f64e8 100644 --- a/AutoRest/Generators/CSharp/Azure.CSharp.Tests/Expected/AcceptanceTests/Lro/ILROSADsOperations.cs +++ b/AutoRest/Generators/CSharp/Azure.CSharp.Tests/Expected/AcceptanceTests/Lro/ILROSADsOperations.cs @@ -79,6 +79,34 @@ public partial interface ILROSADsOperations /// Task> BeginPutNonRetry201Creating400WithHttpMessagesAsync(Product product = default(Product), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); /// + /// Long running put request, service returns a Product with + /// 'ProvisioningState' = 'Creating' and 201 response code + /// + /// + /// Product to put + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + Task> PutNonRetry201Creating400InvalidJsonWithHttpMessagesAsync(Product product = default(Product), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// Long running put request, service returns a Product with + /// 'ProvisioningState' = 'Creating' and 201 response code + /// + /// + /// Product to put + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + Task> BeginPutNonRetry201Creating400InvalidJsonWithHttpMessagesAsync(Product product = default(Product), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// /// Long running put request, service returns a 200 with /// ProvisioningState=’Creating’. Poll the endpoint indicated in the /// Azure-AsyncOperation header for operation status diff --git a/AutoRest/Generators/CSharp/Azure.CSharp.Tests/Expected/AcceptanceTests/Lro/LROSADsOperations.cs b/AutoRest/Generators/CSharp/Azure.CSharp.Tests/Expected/AcceptanceTests/Lro/LROSADsOperations.cs index 7b0662de0c29e..cbd54f78112ae 100644 --- a/AutoRest/Generators/CSharp/Azure.CSharp.Tests/Expected/AcceptanceTests/Lro/LROSADsOperations.cs +++ b/AutoRest/Generators/CSharp/Azure.CSharp.Tests/Expected/AcceptanceTests/Lro/LROSADsOperations.cs @@ -453,6 +453,209 @@ public async Task> BeginPutNonRetry201Creating40 return _result; } + /// + /// Long running put request, service returns a Product with + /// 'ProvisioningState' = 'Creating' and 201 response code + /// + /// + /// Product to put + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + public async Task> PutNonRetry201Creating400InvalidJsonWithHttpMessagesAsync(Product product = default(Product), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Send Request + AzureOperationResponse _response = await BeginPutNonRetry201Creating400InvalidJsonWithHttpMessagesAsync( + product, customHeaders, cancellationToken); + return await this.Client.GetPutOrPatchOperationResultAsync(_response, + customHeaders, + cancellationToken); + } + + /// + /// Long running put request, service returns a Product with + /// 'ProvisioningState' = 'Creating' and 201 response code + /// + /// + /// Product to put + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> BeginPutNonRetry201Creating400InvalidJsonWithHttpMessagesAsync(Product product = default(Product), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("product", product); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "BeginPutNonRetry201Creating400InvalidJson", tracingParameters); + } + // Construct URL + var _baseUrl = this.Client.BaseUri.AbsoluteUri; + var _url = new Uri(new Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "lro/nonretryerror/put/201/creating/400/invalidjson").ToString(); + List _queryParameters = new List(); + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + HttpRequestMessage _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("PUT"); + _httpRequest.RequestUri = new Uri(_url); + // Set Headers + if (this.Client.GenerateClientRequestId != null && this.Client.GenerateClientRequestId.Value) + { + _httpRequest.Headers.TryAddWithoutValidation("x-ms-client-request-id", Guid.NewGuid().ToString()); + } + if (this.Client.AcceptLanguage != null) + { + if (_httpRequest.Headers.Contains("accept-language")) + { + _httpRequest.Headers.Remove("accept-language"); + } + _httpRequest.Headers.TryAddWithoutValidation("accept-language", this.Client.AcceptLanguage); + } + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(product != null) + { + _requestContent = SafeJsonConvert.SerializeObject(product, this.Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, Encoding.UTF8); + _httpRequest.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Set Credentials + if (this.Client.Credentials != null) + { + cancellationToken.ThrowIfCancellationRequested(); + await this.Client.Credentials.ProcessHttpRequestAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await this.Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if ((int)_statusCode != 200 && (int)_statusCode != 201) + { + var ex = new CloudException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + CloudError _errorBody = SafeJsonConvert.DeserializeObject(_responseContent, this.Client.DeserializationSettings); + if (_errorBody != null) + { + ex = new CloudException(_errorBody.Message); + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_httpResponse.Headers.Contains("x-ms-request-id")) + { + ex.RequestId = _httpResponse.Headers.GetValues("x-ms-request-id").FirstOrDefault(); + } + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new AzureOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + if (_httpResponse.Headers.Contains("x-ms-request-id")) + { + _result.RequestId = _httpResponse.Headers.GetValues("x-ms-request-id").FirstOrDefault(); + } + // Deserialize Response + if ((int)_statusCode == 200) + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = SafeJsonConvert.DeserializeObject(_responseContent, this.Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _responseContent, ex); + } + } + // Deserialize Response + if ((int)_statusCode == 201) + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = SafeJsonConvert.DeserializeObject(_responseContent, this.Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _responseContent, ex); + } + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + /// /// Long running put request, service returns a 200 with /// ProvisioningState=’Creating’. Poll the endpoint indicated in the diff --git a/AutoRest/Generators/CSharp/Azure.CSharp.Tests/Expected/AcceptanceTests/Lro/LROSADsOperationsExtensions.cs b/AutoRest/Generators/CSharp/Azure.CSharp.Tests/Expected/AcceptanceTests/Lro/LROSADsOperationsExtensions.cs index 86b6c1b083fc9..dc7d177cbe402 100644 --- a/AutoRest/Generators/CSharp/Azure.CSharp.Tests/Expected/AcceptanceTests/Lro/LROSADsOperationsExtensions.cs +++ b/AutoRest/Generators/CSharp/Azure.CSharp.Tests/Expected/AcceptanceTests/Lro/LROSADsOperationsExtensions.cs @@ -162,6 +162,78 @@ public static async Task BeginPutNonRetry201Creating400Async(this ILROS } } + /// + /// Long running put request, service returns a Product with + /// 'ProvisioningState' = 'Creating' and 201 response code + /// + /// + /// The operations group for this extension method. + /// + /// + /// Product to put + /// + public static Product PutNonRetry201Creating400InvalidJson(this ILROSADsOperations operations, Product product = default(Product)) + { + return Task.Factory.StartNew(s => ((ILROSADsOperations)s).PutNonRetry201Creating400InvalidJsonAsync(product), operations, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap().GetAwaiter().GetResult(); + } + + /// + /// Long running put request, service returns a Product with + /// 'ProvisioningState' = 'Creating' and 201 response code + /// + /// + /// The operations group for this extension method. + /// + /// + /// Product to put + /// + /// + /// The cancellation token. + /// + public static async Task PutNonRetry201Creating400InvalidJsonAsync(this ILROSADsOperations operations, Product product = default(Product), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.PutNonRetry201Creating400InvalidJsonWithHttpMessagesAsync(product, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// Long running put request, service returns a Product with + /// 'ProvisioningState' = 'Creating' and 201 response code + /// + /// + /// The operations group for this extension method. + /// + /// + /// Product to put + /// + public static Product BeginPutNonRetry201Creating400InvalidJson(this ILROSADsOperations operations, Product product = default(Product)) + { + return Task.Factory.StartNew(s => ((ILROSADsOperations)s).BeginPutNonRetry201Creating400InvalidJsonAsync(product), operations, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap().GetAwaiter().GetResult(); + } + + /// + /// Long running put request, service returns a Product with + /// 'ProvisioningState' = 'Creating' and 201 response code + /// + /// + /// The operations group for this extension method. + /// + /// + /// Product to put + /// + /// + /// The cancellation token. + /// + public static async Task BeginPutNonRetry201Creating400InvalidJsonAsync(this ILROSADsOperations operations, Product product = default(Product), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.BeginPutNonRetry201Creating400InvalidJsonWithHttpMessagesAsync(product, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + /// /// Long running put request, service returns a 200 with /// ProvisioningState=’Creating’. Poll the endpoint indicated in the diff --git a/AutoRest/Generators/CSharp/CSharp.Tests/AcceptanceTests.cs b/AutoRest/Generators/CSharp/CSharp.Tests/AcceptanceTests.cs index 804db915e6111..bdd10a6f30136 100644 --- a/AutoRest/Generators/CSharp/CSharp.Tests/AcceptanceTests.cs +++ b/AutoRest/Generators/CSharp/CSharp.Tests/AcceptanceTests.cs @@ -1366,6 +1366,9 @@ public void HeaderTests() SwaggerPath("header.json"), ExpectedPath("Header")); using (var client = new AutoRestSwaggerBATHeaderService(Fixture.Uri)) { + // Check the UserAgent ProductInfoHeaderValue + Assert.Equal("1.5.0.1", client.UserAgent.Select(c => c.Product.Version.ToString()).FirstOrDefault()); + // POST param/prim/integer client.Header.ParamInteger("positive", 1); client.Header.ParamInteger("negative", -2); diff --git a/AutoRest/Generators/CSharp/CSharp.Tests/Properties/AssemblyInfo.cs b/AutoRest/Generators/CSharp/CSharp.Tests/Properties/AssemblyInfo.cs index 68d34505c6d76..61dbf33914dc9 100644 --- a/AutoRest/Generators/CSharp/CSharp.Tests/Properties/AssemblyInfo.cs +++ b/AutoRest/Generators/CSharp/CSharp.Tests/Properties/AssemblyInfo.cs @@ -17,3 +17,4 @@ [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.5.0.0")] +[assembly: AssemblyInformationalVersion("1.5.0.1")] diff --git a/AutoRest/Generators/Java/Azure.Java.Tests/src/main/java/fixtures/lro/LROSADsOperations.java b/AutoRest/Generators/Java/Azure.Java.Tests/src/main/java/fixtures/lro/LROSADsOperations.java index 67695190d0b37..7fdc2cc170dd2 100644 --- a/AutoRest/Generators/Java/Azure.Java.Tests/src/main/java/fixtures/lro/LROSADsOperations.java +++ b/AutoRest/Generators/Java/Azure.Java.Tests/src/main/java/fixtures/lro/LROSADsOperations.java @@ -195,6 +195,82 @@ public interface LROSADsOperations { */ ServiceCall beginPutNonRetry201Creating400Async(Product product, final ServiceCallback serviceCallback) throws IllegalArgumentException; + /** + * Long running put request, service returns a Product with 'ProvisioningState' = 'Creating' and 201 response code. + * + * @throws CloudException exception thrown from REST call + * @throws IOException exception thrown from serialization/deserialization + * @throws InterruptedException exception thrown when long running operation is interrupted + * @return the Product object wrapped in {@link ServiceResponse} if successful. + */ + ServiceResponse putNonRetry201Creating400InvalidJson() throws CloudException, IOException, InterruptedException; + + /** + * Long running put request, service returns a Product with 'ProvisioningState' = 'Creating' and 201 response code. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if callback is null + * @return the {@link ServiceCall} object + */ + ServiceCall putNonRetry201Creating400InvalidJsonAsync(final ServiceCallback serviceCallback) throws IllegalArgumentException; + /** + * Long running put request, service returns a Product with 'ProvisioningState' = 'Creating' and 201 response code. + * + * @param product Product to put + * @throws CloudException exception thrown from REST call + * @throws IOException exception thrown from serialization/deserialization + * @throws InterruptedException exception thrown when long running operation is interrupted + * @return the Product object wrapped in {@link ServiceResponse} if successful. + */ + ServiceResponse putNonRetry201Creating400InvalidJson(Product product) throws CloudException, IOException, InterruptedException; + + /** + * Long running put request, service returns a Product with 'ProvisioningState' = 'Creating' and 201 response code. + * + * @param product Product to put + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if callback is null + * @return the {@link ServiceCall} object + */ + ServiceCall putNonRetry201Creating400InvalidJsonAsync(Product product, final ServiceCallback serviceCallback) throws IllegalArgumentException; + + /** + * Long running put request, service returns a Product with 'ProvisioningState' = 'Creating' and 201 response code. + * + * @throws CloudException exception thrown from REST call + * @throws IOException exception thrown from serialization/deserialization + * @return the Product object wrapped in {@link ServiceResponse} if successful. + */ + ServiceResponse beginPutNonRetry201Creating400InvalidJson() throws CloudException, IOException; + + /** + * Long running put request, service returns a Product with 'ProvisioningState' = 'Creating' and 201 response code. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if callback is null + * @return the {@link ServiceCall} object + */ + ServiceCall beginPutNonRetry201Creating400InvalidJsonAsync(final ServiceCallback serviceCallback) throws IllegalArgumentException; + /** + * Long running put request, service returns a Product with 'ProvisioningState' = 'Creating' and 201 response code. + * + * @param product Product to put + * @throws CloudException exception thrown from REST call + * @throws IOException exception thrown from serialization/deserialization + * @return the Product object wrapped in {@link ServiceResponse} if successful. + */ + ServiceResponse beginPutNonRetry201Creating400InvalidJson(Product product) throws CloudException, IOException; + + /** + * Long running put request, service returns a Product with 'ProvisioningState' = 'Creating' and 201 response code. + * + * @param product Product to put + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if callback is null + * @return the {@link ServiceCall} object + */ + ServiceCall beginPutNonRetry201Creating400InvalidJsonAsync(Product product, final ServiceCallback serviceCallback) throws IllegalArgumentException; + /** * Long running put request, service returns a 200 with ProvisioningState=’Creating’. Poll the endpoint indicated in the Azure-AsyncOperation header for operation status. * diff --git a/AutoRest/Generators/Java/Azure.Java.Tests/src/main/java/fixtures/lro/LROSADsOperationsImpl.java b/AutoRest/Generators/Java/Azure.Java.Tests/src/main/java/fixtures/lro/LROSADsOperationsImpl.java index a00b4293ab132..2f3623d834f8d 100644 --- a/AutoRest/Generators/Java/Azure.Java.Tests/src/main/java/fixtures/lro/LROSADsOperationsImpl.java +++ b/AutoRest/Generators/Java/Azure.Java.Tests/src/main/java/fixtures/lro/LROSADsOperationsImpl.java @@ -95,6 +95,14 @@ interface LROSADsService { @PUT("lro/nonretryerror/put/201/creating/400") Call beginPutNonRetry201Creating400(@Body Product product, @Header("accept-language") String acceptLanguage); + @Headers("Content-Type: application/json; charset=utf-8") + @PUT("lro/nonretryerror/put/201/creating/400/invalidjson") + Call putNonRetry201Creating400InvalidJson(@Body Product product, @Header("accept-language") String acceptLanguage); + + @Headers("Content-Type: application/json; charset=utf-8") + @PUT("lro/nonretryerror/put/201/creating/400/invalidjson") + Call beginPutNonRetry201Creating400InvalidJson(@Body Product product, @Header("accept-language") String acceptLanguage); + @Headers("Content-Type: application/json; charset=utf-8") @PUT("lro/nonretryerror/putasync/retry/400") Call putAsyncRelativeRetry400(@Body Product product, @Header("accept-language") String acceptLanguage); @@ -627,6 +635,179 @@ private ServiceResponse beginPutNonRetry201Creating400Delegate(Response .build(response); } + /** + * Long running put request, service returns a Product with 'ProvisioningState' = 'Creating' and 201 response code. + * + * @throws CloudException exception thrown from REST call + * @throws IOException exception thrown from serialization/deserialization + * @throws InterruptedException exception thrown when long running operation is interrupted + * @return the Product object wrapped in ServiceResponse if successful. + */ + public ServiceResponse putNonRetry201Creating400InvalidJson() throws CloudException, IOException, InterruptedException { + final Product product = null; + Response result = service.putNonRetry201Creating400InvalidJson(product, this.client.getAcceptLanguage()).execute(); + return client.getAzureClient().getPutOrPatchResult(result, new TypeToken() { }.getType()); + } + + /** + * Long running put request, service returns a Product with 'ProvisioningState' = 'Creating' and 201 response code. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if callback is null + * @return the {@link ServiceCall} object + */ + public ServiceCall putNonRetry201Creating400InvalidJsonAsync(final ServiceCallback serviceCallback) throws IllegalArgumentException { + if (serviceCallback == null) { + throw new IllegalArgumentException("ServiceCallback is required for async calls."); + } + final Product product = null; + Call call = service.putNonRetry201Creating400InvalidJson(product, this.client.getAcceptLanguage()); + final ServiceCall serviceCall = new ServiceCall(call); + call.enqueue(new Callback() { + @Override + public void onFailure(Call call, Throwable t) { + serviceCallback.failure(t); + } + @Override + public void onResponse(Call call, Response response) { + client.getAzureClient().getPutOrPatchResultAsync(response, new TypeToken() { }.getType(), serviceCall, serviceCallback); + } + }); + return serviceCall; + } + /** + * Long running put request, service returns a Product with 'ProvisioningState' = 'Creating' and 201 response code. + * + * @param product Product to put + * @throws CloudException exception thrown from REST call + * @throws IOException exception thrown from serialization/deserialization + * @throws InterruptedException exception thrown when long running operation is interrupted + * @return the Product object wrapped in ServiceResponse if successful. + */ + public ServiceResponse putNonRetry201Creating400InvalidJson(Product product) throws CloudException, IOException, InterruptedException { + Validator.validate(product); + Response result = service.putNonRetry201Creating400InvalidJson(product, this.client.getAcceptLanguage()).execute(); + return client.getAzureClient().getPutOrPatchResult(result, new TypeToken() { }.getType()); + } + + /** + * Long running put request, service returns a Product with 'ProvisioningState' = 'Creating' and 201 response code. + * + * @param product Product to put + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if callback is null + * @return the {@link ServiceCall} object + */ + public ServiceCall putNonRetry201Creating400InvalidJsonAsync(Product product, final ServiceCallback serviceCallback) throws IllegalArgumentException { + if (serviceCallback == null) { + throw new IllegalArgumentException("ServiceCallback is required for async calls."); + } + Validator.validate(product, serviceCallback); + Call call = service.putNonRetry201Creating400InvalidJson(product, this.client.getAcceptLanguage()); + final ServiceCall serviceCall = new ServiceCall(call); + call.enqueue(new Callback() { + @Override + public void onFailure(Call call, Throwable t) { + serviceCallback.failure(t); + } + @Override + public void onResponse(Call call, Response response) { + client.getAzureClient().getPutOrPatchResultAsync(response, new TypeToken() { }.getType(), serviceCall, serviceCallback); + } + }); + return serviceCall; + } + + /** + * Long running put request, service returns a Product with 'ProvisioningState' = 'Creating' and 201 response code. + * + * @throws CloudException exception thrown from REST call + * @throws IOException exception thrown from serialization/deserialization + * @return the Product object wrapped in {@link ServiceResponse} if successful. + */ + public ServiceResponse beginPutNonRetry201Creating400InvalidJson() throws CloudException, IOException { + final Product product = null; + Call call = service.beginPutNonRetry201Creating400InvalidJson(product, this.client.getAcceptLanguage()); + return beginPutNonRetry201Creating400InvalidJsonDelegate(call.execute()); + } + + /** + * Long running put request, service returns a Product with 'ProvisioningState' = 'Creating' and 201 response code. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if callback is null + * @return the {@link Call} object + */ + public ServiceCall beginPutNonRetry201Creating400InvalidJsonAsync(final ServiceCallback serviceCallback) throws IllegalArgumentException { + if (serviceCallback == null) { + throw new IllegalArgumentException("ServiceCallback is required for async calls."); + } + final Product product = null; + Call call = service.beginPutNonRetry201Creating400InvalidJson(product, this.client.getAcceptLanguage()); + final ServiceCall serviceCall = new ServiceCall(call); + call.enqueue(new ServiceResponseCallback(serviceCallback) { + @Override + public void onResponse(Call call, Response response) { + try { + serviceCallback.success(beginPutNonRetry201Creating400InvalidJsonDelegate(response)); + } catch (CloudException | IOException exception) { + serviceCallback.failure(exception); + } + } + }); + return serviceCall; + } + + /** + * Long running put request, service returns a Product with 'ProvisioningState' = 'Creating' and 201 response code. + * + * @param product Product to put + * @throws CloudException exception thrown from REST call + * @throws IOException exception thrown from serialization/deserialization + * @return the Product object wrapped in {@link ServiceResponse} if successful. + */ + public ServiceResponse beginPutNonRetry201Creating400InvalidJson(Product product) throws CloudException, IOException { + Validator.validate(product); + Call call = service.beginPutNonRetry201Creating400InvalidJson(product, this.client.getAcceptLanguage()); + return beginPutNonRetry201Creating400InvalidJsonDelegate(call.execute()); + } + + /** + * Long running put request, service returns a Product with 'ProvisioningState' = 'Creating' and 201 response code. + * + * @param product Product to put + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if callback is null + * @return the {@link Call} object + */ + public ServiceCall beginPutNonRetry201Creating400InvalidJsonAsync(Product product, final ServiceCallback serviceCallback) throws IllegalArgumentException { + if (serviceCallback == null) { + throw new IllegalArgumentException("ServiceCallback is required for async calls."); + } + Validator.validate(product, serviceCallback); + Call call = service.beginPutNonRetry201Creating400InvalidJson(product, this.client.getAcceptLanguage()); + final ServiceCall serviceCall = new ServiceCall(call); + call.enqueue(new ServiceResponseCallback(serviceCallback) { + @Override + public void onResponse(Call call, Response response) { + try { + serviceCallback.success(beginPutNonRetry201Creating400InvalidJsonDelegate(response)); + } catch (CloudException | IOException exception) { + serviceCallback.failure(exception); + } + } + }); + return serviceCall; + } + + private ServiceResponse beginPutNonRetry201Creating400InvalidJsonDelegate(Response response) throws CloudException, IOException { + return new AzureServiceResponseBuilder(this.client.getMapperAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(201, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + /** * Long running put request, service returns a 200 with ProvisioningState=’Creating’. Poll the endpoint indicated in the Azure-AsyncOperation header for operation status. * diff --git a/AutoRest/Generators/Java/Java.Tests/src/main/java/fixtures/bodyinteger/IntOperations.java b/AutoRest/Generators/Java/Java.Tests/src/main/java/fixtures/bodyinteger/IntOperations.java index 2f705c55d8129..9710c80eabe31 100644 --- a/AutoRest/Generators/Java/Java.Tests/src/main/java/fixtures/bodyinteger/IntOperations.java +++ b/AutoRest/Generators/Java/Java.Tests/src/main/java/fixtures/bodyinteger/IntOperations.java @@ -209,4 +209,78 @@ public interface IntOperations { */ ServiceCall putMin64Async(long intBody, final ServiceCallback serviceCallback) throws IllegalArgumentException; + /** + * Get datetime encoded as Unix time value. + * + * @throws ErrorException exception thrown from REST call + * @throws IOException exception thrown from serialization/deserialization + * @return the long object wrapped in {@link ServiceResponse} if successful. + */ + ServiceResponse getUnixTime() throws ErrorException, IOException; + + /** + * Get datetime encoded as Unix time value. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if callback is null + * @return the {@link ServiceCall} object + */ + ServiceCall getUnixTimeAsync(final ServiceCallback serviceCallback) throws IllegalArgumentException; + + /** + * Put datetime encoded as Unix time. + * + * @param intBody the long value + * @throws ErrorException exception thrown from REST call + * @throws IOException exception thrown from serialization/deserialization + * @return the {@link ServiceResponse} object if successful. + */ + ServiceResponse putUnixTimeDate(long intBody) throws ErrorException, IOException; + + /** + * Put datetime encoded as Unix time. + * + * @param intBody the long value + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if callback is null + * @return the {@link ServiceCall} object + */ + ServiceCall putUnixTimeDateAsync(long intBody, final ServiceCallback serviceCallback) throws IllegalArgumentException; + + /** + * Get invalid Unix time value. + * + * @throws ErrorException exception thrown from REST call + * @throws IOException exception thrown from serialization/deserialization + * @return the long object wrapped in {@link ServiceResponse} if successful. + */ + ServiceResponse getInvalidUnixTime() throws ErrorException, IOException; + + /** + * Get invalid Unix time value. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if callback is null + * @return the {@link ServiceCall} object + */ + ServiceCall getInvalidUnixTimeAsync(final ServiceCallback serviceCallback) throws IllegalArgumentException; + + /** + * Get null Unix time value. + * + * @throws ErrorException exception thrown from REST call + * @throws IOException exception thrown from serialization/deserialization + * @return the long object wrapped in {@link ServiceResponse} if successful. + */ + ServiceResponse getNullUnixTime() throws ErrorException, IOException; + + /** + * Get null Unix time value. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if callback is null + * @return the {@link ServiceCall} object + */ + ServiceCall getNullUnixTimeAsync(final ServiceCallback serviceCallback) throws IllegalArgumentException; + } diff --git a/AutoRest/Generators/Java/Java.Tests/src/main/java/fixtures/bodyinteger/IntOperationsImpl.java b/AutoRest/Generators/Java/Java.Tests/src/main/java/fixtures/bodyinteger/IntOperationsImpl.java index 8e9325c0caf42..134ce02e57ae8 100644 --- a/AutoRest/Generators/Java/Java.Tests/src/main/java/fixtures/bodyinteger/IntOperationsImpl.java +++ b/AutoRest/Generators/Java/Java.Tests/src/main/java/fixtures/bodyinteger/IntOperationsImpl.java @@ -93,6 +93,22 @@ interface IntService { @PUT("int/min/64") Call putMin64(@Body long intBody); + @Headers("Content-Type: application/json; charset=utf-8") + @GET("int/unixtime") + Call getUnixTime(); + + @Headers("Content-Type: application/json; charset=utf-8") + @PUT("int/unixtime") + Call putUnixTimeDate(@Body long intBody); + + @Headers("Content-Type: application/json; charset=utf-8") + @GET("int/invalidunixtime") + Call getInvalidUnixTime(); + + @Headers("Content-Type: application/json; charset=utf-8") + @GET("int/nullunixtime") + Call getNullUnixTime(); + } /** @@ -553,4 +569,186 @@ private ServiceResponse putMin64Delegate(Response response) .build(response); } + /** + * Get datetime encoded as Unix time value. + * + * @throws ErrorException exception thrown from REST call + * @throws IOException exception thrown from serialization/deserialization + * @return the long object wrapped in {@link ServiceResponse} if successful. + */ + public ServiceResponse getUnixTime() throws ErrorException, IOException { + Call call = service.getUnixTime(); + return getUnixTimeDelegate(call.execute()); + } + + /** + * Get datetime encoded as Unix time value. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if callback is null + * @return the {@link Call} object + */ + public ServiceCall getUnixTimeAsync(final ServiceCallback serviceCallback) throws IllegalArgumentException { + if (serviceCallback == null) { + throw new IllegalArgumentException("ServiceCallback is required for async calls."); + } + Call call = service.getUnixTime(); + final ServiceCall serviceCall = new ServiceCall(call); + call.enqueue(new ServiceResponseCallback(serviceCallback) { + @Override + public void onResponse(Call call, Response response) { + try { + serviceCallback.success(getUnixTimeDelegate(response)); + } catch (ErrorException | IOException exception) { + serviceCallback.failure(exception); + } + } + }); + return serviceCall; + } + + private ServiceResponse getUnixTimeDelegate(Response response) throws ErrorException, IOException { + return new ServiceResponseBuilder(this.client.getMapperAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(ErrorException.class) + .build(response); + } + + /** + * Put datetime encoded as Unix time. + * + * @param intBody the long value + * @throws ErrorException exception thrown from REST call + * @throws IOException exception thrown from serialization/deserialization + * @return the {@link ServiceResponse} object if successful. + */ + public ServiceResponse putUnixTimeDate(long intBody) throws ErrorException, IOException { + Call call = service.putUnixTimeDate(intBody); + return putUnixTimeDateDelegate(call.execute()); + } + + /** + * Put datetime encoded as Unix time. + * + * @param intBody the long value + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if callback is null + * @return the {@link Call} object + */ + public ServiceCall putUnixTimeDateAsync(long intBody, final ServiceCallback serviceCallback) throws IllegalArgumentException { + if (serviceCallback == null) { + throw new IllegalArgumentException("ServiceCallback is required for async calls."); + } + Call call = service.putUnixTimeDate(intBody); + final ServiceCall serviceCall = new ServiceCall(call); + call.enqueue(new ServiceResponseCallback(serviceCallback) { + @Override + public void onResponse(Call call, Response response) { + try { + serviceCallback.success(putUnixTimeDateDelegate(response)); + } catch (ErrorException | IOException exception) { + serviceCallback.failure(exception); + } + } + }); + return serviceCall; + } + + private ServiceResponse putUnixTimeDateDelegate(Response response) throws ErrorException, IOException { + return new ServiceResponseBuilder(this.client.getMapperAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(ErrorException.class) + .build(response); + } + + /** + * Get invalid Unix time value. + * + * @throws ErrorException exception thrown from REST call + * @throws IOException exception thrown from serialization/deserialization + * @return the long object wrapped in {@link ServiceResponse} if successful. + */ + public ServiceResponse getInvalidUnixTime() throws ErrorException, IOException { + Call call = service.getInvalidUnixTime(); + return getInvalidUnixTimeDelegate(call.execute()); + } + + /** + * Get invalid Unix time value. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if callback is null + * @return the {@link Call} object + */ + public ServiceCall getInvalidUnixTimeAsync(final ServiceCallback serviceCallback) throws IllegalArgumentException { + if (serviceCallback == null) { + throw new IllegalArgumentException("ServiceCallback is required for async calls."); + } + Call call = service.getInvalidUnixTime(); + final ServiceCall serviceCall = new ServiceCall(call); + call.enqueue(new ServiceResponseCallback(serviceCallback) { + @Override + public void onResponse(Call call, Response response) { + try { + serviceCallback.success(getInvalidUnixTimeDelegate(response)); + } catch (ErrorException | IOException exception) { + serviceCallback.failure(exception); + } + } + }); + return serviceCall; + } + + private ServiceResponse getInvalidUnixTimeDelegate(Response response) throws ErrorException, IOException { + return new ServiceResponseBuilder(this.client.getMapperAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(ErrorException.class) + .build(response); + } + + /** + * Get null Unix time value. + * + * @throws ErrorException exception thrown from REST call + * @throws IOException exception thrown from serialization/deserialization + * @return the long object wrapped in {@link ServiceResponse} if successful. + */ + public ServiceResponse getNullUnixTime() throws ErrorException, IOException { + Call call = service.getNullUnixTime(); + return getNullUnixTimeDelegate(call.execute()); + } + + /** + * Get null Unix time value. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if callback is null + * @return the {@link Call} object + */ + public ServiceCall getNullUnixTimeAsync(final ServiceCallback serviceCallback) throws IllegalArgumentException { + if (serviceCallback == null) { + throw new IllegalArgumentException("ServiceCallback is required for async calls."); + } + Call call = service.getNullUnixTime(); + final ServiceCall serviceCall = new ServiceCall(call); + call.enqueue(new ServiceResponseCallback(serviceCallback) { + @Override + public void onResponse(Call call, Response response) { + try { + serviceCallback.success(getNullUnixTimeDelegate(response)); + } catch (ErrorException | IOException exception) { + serviceCallback.failure(exception); + } + } + }); + return serviceCall; + } + + private ServiceResponse getNullUnixTimeDelegate(Response response) throws ErrorException, IOException { + return new ServiceResponseBuilder(this.client.getMapperAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(ErrorException.class) + .build(response); + } + } diff --git a/AutoRest/Generators/Java/Java.Tests/src/main/java/fixtures/url/PathsOperations.java b/AutoRest/Generators/Java/Java.Tests/src/main/java/fixtures/url/PathsOperations.java index f7676a65a59a3..1ccd08f952b57 100644 --- a/AutoRest/Generators/Java/Java.Tests/src/main/java/fixtures/url/PathsOperations.java +++ b/AutoRest/Generators/Java/Java.Tests/src/main/java/fixtures/url/PathsOperations.java @@ -502,4 +502,24 @@ public interface PathsOperations { */ ServiceCall arrayCsvInPathAsync(List arrayPath, final ServiceCallback serviceCallback) throws IllegalArgumentException; + /** + * Get the date 2016-04-13 encoded value as '1460505600' (Unix time). + * + * @param unixTimeUrlPath Unix time encoded value + * @throws ErrorException exception thrown from REST call + * @throws IOException exception thrown from serialization/deserialization + * @return the {@link ServiceResponse} object if successful. + */ + ServiceResponse unixTimeUrl(long unixTimeUrlPath) throws ErrorException, IOException; + + /** + * Get the date 2016-04-13 encoded value as '1460505600' (Unix time). + * + * @param unixTimeUrlPath Unix time encoded value + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if callback is null + * @return the {@link ServiceCall} object + */ + ServiceCall unixTimeUrlAsync(long unixTimeUrlPath, final ServiceCallback serviceCallback) throws IllegalArgumentException; + } diff --git a/AutoRest/Generators/Java/Java.Tests/src/main/java/fixtures/url/PathsOperationsImpl.java b/AutoRest/Generators/Java/Java.Tests/src/main/java/fixtures/url/PathsOperationsImpl.java index b32c2fcbd2471..31942e3ce28cb 100644 --- a/AutoRest/Generators/Java/Java.Tests/src/main/java/fixtures/url/PathsOperationsImpl.java +++ b/AutoRest/Generators/Java/Java.Tests/src/main/java/fixtures/url/PathsOperationsImpl.java @@ -159,6 +159,10 @@ interface PathsService { @GET("paths/array/ArrayPath1%2cbegin%21%2A%27%28%29%3B%3A%40%20%26%3D%2B%24%2C%2F%3F%23%5B%5Dend%2c%2c/{arrayPath:commaSeparated}") Call arrayCsvInPath(@Path("arrayPath") String arrayPath); + @Headers("Content-Type: application/json; charset=utf-8") + @GET("paths/int/1460505600/{unixTimeUrlPath}") + Call unixTimeUrl(@Path("unixTimeUrlPath") long unixTimeUrlPath); + } /** @@ -1418,4 +1422,51 @@ private ServiceResponse arrayCsvInPathDelegate(Response resp .build(response); } + /** + * Get the date 2016-04-13 encoded value as '1460505600' (Unix time). + * + * @param unixTimeUrlPath Unix time encoded value + * @throws ErrorException exception thrown from REST call + * @throws IOException exception thrown from serialization/deserialization + * @return the {@link ServiceResponse} object if successful. + */ + public ServiceResponse unixTimeUrl(long unixTimeUrlPath) throws ErrorException, IOException { + Call call = service.unixTimeUrl(unixTimeUrlPath); + return unixTimeUrlDelegate(call.execute()); + } + + /** + * Get the date 2016-04-13 encoded value as '1460505600' (Unix time). + * + * @param unixTimeUrlPath Unix time encoded value + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if callback is null + * @return the {@link Call} object + */ + public ServiceCall unixTimeUrlAsync(long unixTimeUrlPath, final ServiceCallback serviceCallback) throws IllegalArgumentException { + if (serviceCallback == null) { + throw new IllegalArgumentException("ServiceCallback is required for async calls."); + } + Call call = service.unixTimeUrl(unixTimeUrlPath); + final ServiceCall serviceCall = new ServiceCall(call); + call.enqueue(new ServiceResponseCallback(serviceCallback) { + @Override + public void onResponse(Call call, Response response) { + try { + serviceCallback.success(unixTimeUrlDelegate(response)); + } catch (ErrorException | IOException exception) { + serviceCallback.failure(exception); + } + } + }); + return serviceCall; + } + + private ServiceResponse unixTimeUrlDelegate(Response response) throws ErrorException, IOException { + return new ServiceResponseBuilder(this.client.getMapperAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(ErrorException.class) + .build(response); + } + } diff --git a/AutoRest/Generators/Java/Java/TemplateModels/MethodTemplateModel.cs b/AutoRest/Generators/Java/Java/TemplateModels/MethodTemplateModel.cs index c9f8bc6faf9fa..7b9afbb821d68 100644 --- a/AutoRest/Generators/Java/Java/TemplateModels/MethodTemplateModel.cs +++ b/AutoRest/Generators/Java/Java/TemplateModels/MethodTemplateModel.cs @@ -363,6 +363,7 @@ public IEnumerable RequiredNullableParameters !param.Type.IsPrimaryType(KnownPrimaryType.Double) && !param.Type.IsPrimaryType(KnownPrimaryType.Boolean) && !param.Type.IsPrimaryType(KnownPrimaryType.Long) && + !param.Type.IsPrimaryType(KnownPrimaryType.UnixTime) && !param.IsConstant && param.IsRequired) { yield return param; diff --git a/AutoRest/Generators/NodeJS/Azure.NodeJS.Tests/Expected/AcceptanceTests/Lro/operations/index.d.ts b/AutoRest/Generators/NodeJS/Azure.NodeJS.Tests/Expected/AcceptanceTests/Lro/operations/index.d.ts index ec051455be3e0..01c453943187e 100644 --- a/AutoRest/Generators/NodeJS/Azure.NodeJS.Tests/Expected/AcceptanceTests/Lro/operations/index.d.ts +++ b/AutoRest/Generators/NodeJS/Azure.NodeJS.Tests/Expected/AcceptanceTests/Lro/operations/index.d.ts @@ -1908,6 +1908,52 @@ export interface LROSADs { beginPutNonRetry201Creating400(options: { product? : models.Product, customHeaders? : { [headerName: string]: string; } }, callback: ServiceCallback): void; beginPutNonRetry201Creating400(callback: ServiceCallback): void; + /** + * Long running put request, service returns a Product with + * 'ProvisioningState' = 'Creating' and 201 response code + * + * @param {object} [options] Optional Parameters. + * + * @param {object} [options.product] Product to put + * + * @param {string} [options.product.provisioningState] + * + * @param {object} [options.product.tags] + * + * @param {string} [options.product.location] Resource Location + * + * @param {object} [options.customHeaders] Headers that will be added to the + * request + * + * @param {ServiceCallback} [callback] callback function; see ServiceCallback + * doc in ms-rest index.d.ts for details + */ + putNonRetry201Creating400InvalidJson(options: { product? : models.Product, customHeaders? : { [headerName: string]: string; } }, callback: ServiceCallback): void; + putNonRetry201Creating400InvalidJson(callback: ServiceCallback): void; + + /** + * Long running put request, service returns a Product with + * 'ProvisioningState' = 'Creating' and 201 response code + * + * @param {object} [options] Optional Parameters. + * + * @param {object} [options.product] Product to put + * + * @param {string} [options.product.provisioningState] + * + * @param {object} [options.product.tags] + * + * @param {string} [options.product.location] Resource Location + * + * @param {object} [options.customHeaders] Headers that will be added to the + * request + * + * @param {ServiceCallback} [callback] callback function; see ServiceCallback + * doc in ms-rest index.d.ts for details + */ + beginPutNonRetry201Creating400InvalidJson(options: { product? : models.Product, customHeaders? : { [headerName: string]: string; } }, callback: ServiceCallback): void; + beginPutNonRetry201Creating400InvalidJson(callback: ServiceCallback): void; + /** * Long running put request, service returns a 200 with * ProvisioningState=’Creating’. Poll the endpoint indicated in the diff --git a/AutoRest/Generators/NodeJS/Azure.NodeJS.Tests/Expected/AcceptanceTests/Lro/operations/lRORetrys.js b/AutoRest/Generators/NodeJS/Azure.NodeJS.Tests/Expected/AcceptanceTests/Lro/operations/lRORetrys.js index f3cb1fecfb34b..91416004b938f 100644 --- a/AutoRest/Generators/NodeJS/Azure.NodeJS.Tests/Expected/AcceptanceTests/Lro/operations/lRORetrys.js +++ b/AutoRest/Generators/NodeJS/Azure.NodeJS.Tests/Expected/AcceptanceTests/Lro/operations/lRORetrys.js @@ -1485,4 +1485,4 @@ LRORetrys.prototype.beginPostAsyncRelativeRetrySucceeded = function (options, ca }; -module.exports = LRORetrys; +module.exports = LRORetrys; \ No newline at end of file diff --git a/AutoRest/Generators/NodeJS/Azure.NodeJS.Tests/Expected/AcceptanceTests/Lro/operations/lROSADs.js b/AutoRest/Generators/NodeJS/Azure.NodeJS.Tests/Expected/AcceptanceTests/Lro/operations/lROSADs.js index 33fff6078369c..b82dd78f09140 100644 --- a/AutoRest/Generators/NodeJS/Azure.NodeJS.Tests/Expected/AcceptanceTests/Lro/operations/lROSADs.js +++ b/AutoRest/Generators/NodeJS/Azure.NodeJS.Tests/Expected/AcceptanceTests/Lro/operations/lROSADs.js @@ -525,6 +525,255 @@ LROSADs.prototype.beginPutNonRetry201Creating400 = function (options, callback) }); }; +/** + * + * Long running put request, service returns a Product with + * 'ProvisioningState' = 'Creating' and 201 response code + * + * @param {object} [options] Optional Parameters. + * + * @param {object} [options.product] Product to put + * + * @param {string} [options.product.provisioningState] + * + * @param {object} [options.product.tags] + * + * @param {string} [options.product.location] Resource Location + * + * @param {object} [options.customHeaders] Headers that will be added to the + * request + * + * @param {function} callback + * + * @returns {function} callback(err, result, request, response) + * + * {Error} err - The Error object if an error occurred, null otherwise. + * + * {object} [result] - The deserialized result object. + * See {@link Product} for more information. + * + * {object} [request] - The HTTP Request object if an error did not occur. + * + * {stream} [response] - The HTTP Response stream if an error did not occur. + */ +LROSADs.prototype.putNonRetry201Creating400InvalidJson = function (options, callback) { + var client = this.client; + if(!callback && typeof options === 'function') { + callback = options; + options = null; + } + + if (!callback) { + throw new Error('callback cannot be null.'); + } + + // Send request + this.beginPutNonRetry201Creating400InvalidJson(options, function (err, parsedResult, httpRequest, response){ + if (err) return callback(err); + + var initialResult = new msRest.HttpOperationResponse(); + initialResult.request = httpRequest; + initialResult.response = response; + initialResult.body = response.body; + client.getPutOrPatchOperationResult(initialResult, options, function (err, pollingResult) { + if (err) return callback(err); + + // Create Result + var result = null; + httpRequest = pollingResult.request; + response = pollingResult.response; + var responseBody = pollingResult.body; + if (responseBody === '') responseBody = null; + + // Deserialize Response + var parsedResponse = null; + try { + parsedResponse = JSON.parse(responseBody); + result = JSON.parse(responseBody); + if (parsedResponse !== null && parsedResponse !== undefined) { + var resultMapper = new client.models['Product']().mapper(); + result = client.deserialize(resultMapper, parsedResponse, 'result'); + } + } catch (error) { + var deserializationError = new Error(util.format('Error "%s" occurred in deserializing the responseBody - "%s"', error, responseBody)); + deserializationError.request = msRest.stripRequest(httpRequest); + deserializationError.response = msRest.stripResponse(response); + return callback(deserializationError); + } + + return callback(null, result, httpRequest, response); + }); + }); +}; + +/** + * Long running put request, service returns a Product with + * 'ProvisioningState' = 'Creating' and 201 response code + * + * @param {object} [options] Optional Parameters. + * + * @param {object} [options.product] Product to put + * + * @param {string} [options.product.provisioningState] + * + * @param {object} [options.product.tags] + * + * @param {string} [options.product.location] Resource Location + * + * @param {object} [options.customHeaders] Headers that will be added to the + * request + * + * @param {function} callback + * + * @returns {function} callback(err, result, request, response) + * + * {Error} err - The Error object if an error occurred, null otherwise. + * + * {object} [result] - The deserialized result object. + * See {@link Product} for more information. + * + * {object} [request] - The HTTP Request object if an error did not occur. + * + * {stream} [response] - The HTTP Response stream if an error did not occur. + */ +LROSADs.prototype.beginPutNonRetry201Creating400InvalidJson = function (options, callback) { + var client = this.client; + if(!callback && typeof options === 'function') { + callback = options; + options = null; + } + if (!callback) { + throw new Error('callback cannot be null.'); + } + var product = (options && options.product !== undefined) ? options.product : undefined; + // Validate + try { + if (this.client.acceptLanguage !== null && this.client.acceptLanguage !== undefined && typeof this.client.acceptLanguage.valueOf() !== 'string') { + throw new Error('this.client.acceptLanguage must be of type string.'); + } + } catch (error) { + return callback(error); + } + + // Construct URL + var requestUrl = this.client.baseUri + + '//lro/nonretryerror/put/201/creating/400/invalidjson'; + var queryParameters = []; + if (queryParameters.length > 0) { + requestUrl += '?' + queryParameters.join('&'); + } + // trim all duplicate forward slashes in the url + var regex = /([^:]\/)\/+/gi; + requestUrl = requestUrl.replace(regex, '$1'); + + // Create HTTP transport objects + var httpRequest = new WebResource(); + httpRequest.method = 'PUT'; + httpRequest.headers = {}; + httpRequest.url = requestUrl; + // Set Headers + if (this.client.generateClientRequestId) { + httpRequest.headers['x-ms-client-request-id'] = msRestAzure.generateUuid(); + } + if (this.client.acceptLanguage !== undefined && this.client.acceptLanguage !== null) { + httpRequest.headers['accept-language'] = this.client.acceptLanguage; + } + if(options) { + for(var headerName in options['customHeaders']) { + if (options['customHeaders'].hasOwnProperty(headerName)) { + httpRequest.headers[headerName] = options['customHeaders'][headerName]; + } + } + } + httpRequest.headers['Content-Type'] = 'application/json; charset=utf-8'; + // Serialize Request + var requestContent = null; + var requestModel = null; + try { + if (product !== null && product !== undefined) { + var requestModelMapper = new client.models['Product']().mapper(); + requestModel = client.serialize(requestModelMapper, product, 'product'); + requestContent = JSON.stringify(requestModel); + } + } catch (error) { + var serializationError = new Error(util.format('Error "%s" occurred in serializing the ' + + 'payload - "%s"', error.message, util.inspect(product, {depth: null}))); + return callback(serializationError); + } + httpRequest.body = requestContent; + // Send Request + return client.pipeline(httpRequest, function (err, response, responseBody) { + if (err) { + return callback(err); + } + var statusCode = response.statusCode; + if (statusCode !== 200 && statusCode !== 201) { + var error = new Error(responseBody); + error.statusCode = response.statusCode; + error.request = msRest.stripRequest(httpRequest); + error.response = msRest.stripResponse(response); + if (responseBody === '') responseBody = null; + var parsedErrorResponse; + try { + parsedErrorResponse = JSON.parse(responseBody); + if (parsedErrorResponse) { + if (parsedErrorResponse.error) parsedErrorResponse = parsedErrorResponse.error; + if (parsedErrorResponse.code) error.code = parsedErrorResponse.code; + if (parsedErrorResponse.message) error.message = parsedErrorResponse.message; + } + if (parsedErrorResponse !== null && parsedErrorResponse !== undefined) { + var resultMapper = new client.models['CloudError']().mapper(); + error.body = client.deserialize(resultMapper, parsedErrorResponse, 'error.body'); + } + } catch (defaultError) { + error.message = util.format('Error "%s" occurred in deserializing the responseBody ' + + '- "%s" for the default response.', defaultError.message, responseBody); + return callback(error); + } + return callback(error); + } + // Create Result + var result = null; + if (responseBody === '') responseBody = null; + // Deserialize Response + if (statusCode === 200) { + var parsedResponse = null; + try { + parsedResponse = JSON.parse(responseBody); + result = JSON.parse(responseBody); + if (parsedResponse !== null && parsedResponse !== undefined) { + var resultMapper = new client.models['Product']().mapper(); + result = client.deserialize(resultMapper, parsedResponse, 'result'); + } + } catch (error) { + var deserializationError = new Error(util.format('Error "%s" occurred in deserializing the responseBody - "%s"', error, responseBody)); + deserializationError.request = msRest.stripRequest(httpRequest); + deserializationError.response = msRest.stripResponse(response); + return callback(deserializationError); + } + } + // Deserialize Response + if (statusCode === 201) { + var parsedResponse = null; + try { + parsedResponse = JSON.parse(responseBody); + result = JSON.parse(responseBody); + if (parsedResponse !== null && parsedResponse !== undefined) { + var resultMapper = new client.models['Product']().mapper(); + result = client.deserialize(resultMapper, parsedResponse, 'result'); + } + } catch (error) { + var deserializationError1 = new Error(util.format('Error "%s" occurred in deserializing the responseBody - "%s"', error, responseBody)); + deserializationError1.request = msRest.stripRequest(httpRequest); + deserializationError1.response = msRest.stripResponse(response); + return callback(deserializationError1); + } + } + + return callback(null, result, httpRequest, response); + }); +}; + /** * * Long running put request, service returns a 200 with diff --git a/AutoRest/Generators/NodeJS/Azure.NodeJS.Tests/Expected/AcceptanceTests/Lro/operations/lROs.js b/AutoRest/Generators/NodeJS/Azure.NodeJS.Tests/Expected/AcceptanceTests/Lro/operations/lROs.js index b0cc6a272fd58..7655fc4191aa2 100644 --- a/AutoRest/Generators/NodeJS/Azure.NodeJS.Tests/Expected/AcceptanceTests/Lro/operations/lROs.js +++ b/AutoRest/Generators/NodeJS/Azure.NodeJS.Tests/Expected/AcceptanceTests/Lro/operations/lROs.js @@ -7787,4 +7787,4 @@ LROs.prototype.beginPostAsyncRetrycanceled = function (options, callback) { }; -module.exports = LROs; +module.exports = LROs; \ No newline at end of file diff --git a/AutoRest/Generators/NodeJS/Azure.NodeJS.Tests/Expected/AcceptanceTests/Lro/operations/lROsCustomHeader.js b/AutoRest/Generators/NodeJS/Azure.NodeJS.Tests/Expected/AcceptanceTests/Lro/operations/lROsCustomHeader.js index 9dc6656111ba1..0c25e2df3bb0c 100644 --- a/AutoRest/Generators/NodeJS/Azure.NodeJS.Tests/Expected/AcceptanceTests/Lro/operations/lROsCustomHeader.js +++ b/AutoRest/Generators/NodeJS/Azure.NodeJS.Tests/Expected/AcceptanceTests/Lro/operations/lROsCustomHeader.js @@ -931,4 +931,4 @@ LROsCustomHeader.prototype.beginPostAsyncRetrySucceeded = function (options, cal }; -module.exports = LROsCustomHeader; +module.exports = LROsCustomHeader; \ No newline at end of file diff --git a/AutoRest/Generators/NodeJS/Azure.NodeJS/TemplateModels/AzureMethodTemplateModel.cs b/AutoRest/Generators/NodeJS/Azure.NodeJS/TemplateModels/AzureMethodTemplateModel.cs index 95a519d366c9d..a6fbcc9e356e9 100644 --- a/AutoRest/Generators/NodeJS/Azure.NodeJS/TemplateModels/AzureMethodTemplateModel.cs +++ b/AutoRest/Generators/NodeJS/Azure.NodeJS/TemplateModels/AzureMethodTemplateModel.cs @@ -86,14 +86,7 @@ public string LongRunningOperationMethodNameInRuntime string result = null; if (this.IsLongRunningOperation) { - if (HttpMethod == HttpMethod.Post || HttpMethod == HttpMethod.Delete) - { - result = "getPostOrDeleteOperationResult"; - } - else if (HttpMethod == HttpMethod.Put || HttpMethod == HttpMethod.Patch) - { - result = "getPutOrPatchOperationResult"; - } + result = "getLongRunningOperationResult"; } return result; } diff --git a/AutoRest/Generators/NodeJS/NodeJS.Tests/AcceptanceTests/acceptanceTests.ts b/AutoRest/Generators/NodeJS/NodeJS.Tests/AcceptanceTests/acceptanceTests.ts index 0a81b3420068b..db5042f716ed3 100644 --- a/AutoRest/Generators/NodeJS/NodeJS.Tests/AcceptanceTests/acceptanceTests.ts +++ b/AutoRest/Generators/NodeJS/NodeJS.Tests/AcceptanceTests/acceptanceTests.ts @@ -199,6 +199,29 @@ describe('nodejs', function () { }); }); }); + + it('should put and get UnixTime date correctly', function (done) { + var d = new Date('2016-04-13T00:00:00.000Z'); + testClient.intModel.putUnixTimeDate(d, function (error, result) { + should.not.exist(error); + testClient.intModel.getUnixTime(function (error, result) { + should.not.exist(error); + assert.deepEqual(result, d); + done(); + }); + }); + }); + + it('should throw an error for invalid UnixTime date anf get null value for UnixTime', function (done) { + testClient.intModel.getInvalidUnixTime(function (error, result) { + should.exist(error); + testClient.intModel.getNullUnixTime(function (error, result) { + should.not.exist(error); + should.not.exist(result); + done(); + }); + }); + }); }); describe('CompositeBoolInt Client', function () { @@ -1891,6 +1914,13 @@ describe('nodejs', function () { }); }); + it('should work when path has a paramaeter in UnixTime format', function (done) { + testClient.paths.unixTimeUrl(new Date('2016-04-13T00:00:00.000Z'), function (error, result) { + should.not.exist(error); + done(); + }); + }); + it('should work when path has datetime', function (done) { testClient.paths.dateTimeValid(new Date('2012-01-01T01:01:01Z'), function (error, result) { should.not.exist(error); diff --git a/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/BodyInteger/operations/index.d.ts b/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/BodyInteger/operations/index.d.ts index 26ce14eb339ea..6fddcb9d06757 100644 --- a/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/BodyInteger/operations/index.d.ts +++ b/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/BodyInteger/operations/index.d.ts @@ -167,4 +167,62 @@ export interface IntModel { */ putMin64(intBody: number, options: { customHeaders? : { [headerName: string]: string; } }, callback: ServiceCallback): void; putMin64(intBody: number, callback: ServiceCallback): void; + + /** + * Get datetime encoded as Unix time value + * + * @param {object} [options] Optional Parameters. + * + * @param {object} [options.customHeaders] Headers that will be added to the + * request + * + * @param {ServiceCallback} [callback] callback function; see ServiceCallback + * doc in ms-rest index.d.ts for details + */ + getUnixTime(options: { customHeaders? : { [headerName: string]: string; } }, callback: ServiceCallback): void; + getUnixTime(callback: ServiceCallback): void; + + /** + * Put datetime encoded as Unix time + * + * @param {date} intBody + * + * @param {object} [options] Optional Parameters. + * + * @param {object} [options.customHeaders] Headers that will be added to the + * request + * + * @param {ServiceCallback} [callback] callback function; see ServiceCallback + * doc in ms-rest index.d.ts for details + */ + putUnixTimeDate(intBody: Date, options: { customHeaders? : { [headerName: string]: string; } }, callback: ServiceCallback): void; + putUnixTimeDate(intBody: Date, callback: ServiceCallback): void; + + /** + * Get invalid Unix time value + * + * @param {object} [options] Optional Parameters. + * + * @param {object} [options.customHeaders] Headers that will be added to the + * request + * + * @param {ServiceCallback} [callback] callback function; see ServiceCallback + * doc in ms-rest index.d.ts for details + */ + getInvalidUnixTime(options: { customHeaders? : { [headerName: string]: string; } }, callback: ServiceCallback): void; + getInvalidUnixTime(callback: ServiceCallback): void; + + /** + * Get null Unix time value + * + * @param {object} [options] Optional Parameters. + * + * @param {object} [options.customHeaders] Headers that will be added to the + * request + * + * @param {ServiceCallback} [callback] callback function; see ServiceCallback + * doc in ms-rest index.d.ts for details + */ + getNullUnixTime(options: { customHeaders? : { [headerName: string]: string; } }, callback: ServiceCallback): void; + getNullUnixTime(callback: ServiceCallback): void; } diff --git a/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/BodyInteger/operations/intModel.js b/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/BodyInteger/operations/intModel.js index 81595128f8a57..290a93e9b35ef 100644 --- a/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/BodyInteger/operations/intModel.js +++ b/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/BodyInteger/operations/intModel.js @@ -1196,5 +1196,469 @@ IntModel.prototype.putMin64 = function (intBody, options, callback) { }); }; +/** + * Get datetime encoded as Unix time value + * + * @param {object} [options] Optional Parameters. + * + * @param {object} [options.customHeaders] Headers that will be added to the + * request + * + * @param {function} callback + * + * @returns {function} callback(err, result, request, response) + * + * {Error} err - The Error object if an error occurred, null otherwise. + * + * {date} [result] - The deserialized result object. + * + * {object} [request] - The HTTP Request object if an error did not occur. + * + * {stream} [response] - The HTTP Response stream if an error did not occur. + */ +IntModel.prototype.getUnixTime = function (options, callback) { + var client = this.client; + if(!callback && typeof options === 'function') { + callback = options; + options = null; + } + if (!callback) { + throw new Error('callback cannot be null.'); + } + + // Construct URL + var requestUrl = this.client.baseUri + + '//int/unixtime'; + // trim all duplicate forward slashes in the url + var regex = /([^:]\/)\/+/gi; + requestUrl = requestUrl.replace(regex, '$1'); + + // Create HTTP transport objects + var httpRequest = new WebResource(); + httpRequest.method = 'GET'; + httpRequest.headers = {}; + httpRequest.url = requestUrl; + // Set Headers + if(options) { + for(var headerName in options['customHeaders']) { + if (options['customHeaders'].hasOwnProperty(headerName)) { + httpRequest.headers[headerName] = options['customHeaders'][headerName]; + } + } + } + httpRequest.headers['Content-Type'] = 'application/json; charset=utf-8'; + httpRequest.body = null; + // Send Request + return client.pipeline(httpRequest, function (err, response, responseBody) { + if (err) { + return callback(err); + } + var statusCode = response.statusCode; + if (statusCode !== 200) { + var error = new Error(responseBody); + error.statusCode = response.statusCode; + error.request = msRest.stripRequest(httpRequest); + error.response = msRest.stripResponse(response); + if (responseBody === '') responseBody = null; + var parsedErrorResponse; + try { + parsedErrorResponse = JSON.parse(responseBody); + if (parsedErrorResponse) { + if (parsedErrorResponse.error) parsedErrorResponse = parsedErrorResponse.error; + if (parsedErrorResponse.code) error.code = parsedErrorResponse.code; + if (parsedErrorResponse.message) error.message = parsedErrorResponse.message; + } + if (parsedErrorResponse !== null && parsedErrorResponse !== undefined) { + var resultMapper = new client.models['ErrorModel']().mapper(); + error.body = client.deserialize(resultMapper, parsedErrorResponse, 'error.body'); + } + } catch (defaultError) { + error.message = util.format('Error "%s" occurred in deserializing the responseBody ' + + '- "%s" for the default response.', defaultError.message, responseBody); + return callback(error); + } + return callback(error); + } + // Create Result + var result = null; + if (responseBody === '') responseBody = null; + // Deserialize Response + if (statusCode === 200) { + var parsedResponse = null; + try { + parsedResponse = JSON.parse(responseBody); + result = JSON.parse(responseBody); + if (parsedResponse !== null && parsedResponse !== undefined) { + var resultMapper = { + required: false, + serializedName: 'parsedResponse', + type: { + name: 'UnixTime' + } + }; + result = client.deserialize(resultMapper, parsedResponse, 'result'); + } + } catch (error) { + var deserializationError = new Error(util.format('Error "%s" occurred in deserializing the responseBody - "%s"', error, responseBody)); + deserializationError.request = msRest.stripRequest(httpRequest); + deserializationError.response = msRest.stripResponse(response); + return callback(deserializationError); + } + } + + return callback(null, result, httpRequest, response); + }); +}; + +/** + * Put datetime encoded as Unix time + * + * @param {date} intBody + * + * @param {object} [options] Optional Parameters. + * + * @param {object} [options.customHeaders] Headers that will be added to the + * request + * + * @param {function} callback + * + * @returns {function} callback(err, result, request, response) + * + * {Error} err - The Error object if an error occurred, null otherwise. + * + * {null} [result] - The deserialized result object. + * + * {object} [request] - The HTTP Request object if an error did not occur. + * + * {stream} [response] - The HTTP Response stream if an error did not occur. + */ +IntModel.prototype.putUnixTimeDate = function (intBody, options, callback) { + var client = this.client; + if(!callback && typeof options === 'function') { + callback = options; + options = null; + } + if (!callback) { + throw new Error('callback cannot be null.'); + } + // Validate + try { + if(!intBody || !(intBody instanceof Date || + (typeof intBody.valueOf() === 'string' && !isNaN(Date.parse(intBody))))) { + throw new Error('intBody cannot be null or undefined and it must be of type date.'); + } + } catch (error) { + return callback(error); + } + + // Construct URL + var requestUrl = this.client.baseUri + + '//int/unixtime'; + // trim all duplicate forward slashes in the url + var regex = /([^:]\/)\/+/gi; + requestUrl = requestUrl.replace(regex, '$1'); + + // Create HTTP transport objects + var httpRequest = new WebResource(); + httpRequest.method = 'PUT'; + httpRequest.headers = {}; + httpRequest.url = requestUrl; + // Set Headers + if(options) { + for(var headerName in options['customHeaders']) { + if (options['customHeaders'].hasOwnProperty(headerName)) { + httpRequest.headers[headerName] = options['customHeaders'][headerName]; + } + } + } + httpRequest.headers['Content-Type'] = 'application/json; charset=utf-8'; + // Serialize Request + var requestContent = null; + var requestModel = null; + try { + if (intBody !== null && intBody !== undefined) { + var requestModelMapper = { + required: true, + serializedName: 'intBody', + type: { + name: 'UnixTime' + } + }; + requestModel = client.serialize(requestModelMapper, intBody, 'intBody'); + requestContent = JSON.stringify(requestModel); + } + } catch (error) { + var serializationError = new Error(util.format('Error "%s" occurred in serializing the ' + + 'payload - "%s"', error.message, util.inspect(intBody, {depth: null}))); + return callback(serializationError); + } + httpRequest.body = requestContent; + // Send Request + return client.pipeline(httpRequest, function (err, response, responseBody) { + if (err) { + return callback(err); + } + var statusCode = response.statusCode; + if (statusCode !== 200) { + var error = new Error(responseBody); + error.statusCode = response.statusCode; + error.request = msRest.stripRequest(httpRequest); + error.response = msRest.stripResponse(response); + if (responseBody === '') responseBody = null; + var parsedErrorResponse; + try { + parsedErrorResponse = JSON.parse(responseBody); + if (parsedErrorResponse) { + if (parsedErrorResponse.error) parsedErrorResponse = parsedErrorResponse.error; + if (parsedErrorResponse.code) error.code = parsedErrorResponse.code; + if (parsedErrorResponse.message) error.message = parsedErrorResponse.message; + } + if (parsedErrorResponse !== null && parsedErrorResponse !== undefined) { + var resultMapper = new client.models['ErrorModel']().mapper(); + error.body = client.deserialize(resultMapper, parsedErrorResponse, 'error.body'); + } + } catch (defaultError) { + error.message = util.format('Error "%s" occurred in deserializing the responseBody ' + + '- "%s" for the default response.', defaultError.message, responseBody); + return callback(error); + } + return callback(error); + } + // Create Result + var result = null; + if (responseBody === '') responseBody = null; + + return callback(null, result, httpRequest, response); + }); +}; + +/** + * Get invalid Unix time value + * + * @param {object} [options] Optional Parameters. + * + * @param {object} [options.customHeaders] Headers that will be added to the + * request + * + * @param {function} callback + * + * @returns {function} callback(err, result, request, response) + * + * {Error} err - The Error object if an error occurred, null otherwise. + * + * {date} [result] - The deserialized result object. + * + * {object} [request] - The HTTP Request object if an error did not occur. + * + * {stream} [response] - The HTTP Response stream if an error did not occur. + */ +IntModel.prototype.getInvalidUnixTime = function (options, callback) { + var client = this.client; + if(!callback && typeof options === 'function') { + callback = options; + options = null; + } + if (!callback) { + throw new Error('callback cannot be null.'); + } + + // Construct URL + var requestUrl = this.client.baseUri + + '//int/invalidunixtime'; + // trim all duplicate forward slashes in the url + var regex = /([^:]\/)\/+/gi; + requestUrl = requestUrl.replace(regex, '$1'); + + // Create HTTP transport objects + var httpRequest = new WebResource(); + httpRequest.method = 'GET'; + httpRequest.headers = {}; + httpRequest.url = requestUrl; + // Set Headers + if(options) { + for(var headerName in options['customHeaders']) { + if (options['customHeaders'].hasOwnProperty(headerName)) { + httpRequest.headers[headerName] = options['customHeaders'][headerName]; + } + } + } + httpRequest.headers['Content-Type'] = 'application/json; charset=utf-8'; + httpRequest.body = null; + // Send Request + return client.pipeline(httpRequest, function (err, response, responseBody) { + if (err) { + return callback(err); + } + var statusCode = response.statusCode; + if (statusCode !== 200) { + var error = new Error(responseBody); + error.statusCode = response.statusCode; + error.request = msRest.stripRequest(httpRequest); + error.response = msRest.stripResponse(response); + if (responseBody === '') responseBody = null; + var parsedErrorResponse; + try { + parsedErrorResponse = JSON.parse(responseBody); + if (parsedErrorResponse) { + if (parsedErrorResponse.error) parsedErrorResponse = parsedErrorResponse.error; + if (parsedErrorResponse.code) error.code = parsedErrorResponse.code; + if (parsedErrorResponse.message) error.message = parsedErrorResponse.message; + } + if (parsedErrorResponse !== null && parsedErrorResponse !== undefined) { + var resultMapper = new client.models['ErrorModel']().mapper(); + error.body = client.deserialize(resultMapper, parsedErrorResponse, 'error.body'); + } + } catch (defaultError) { + error.message = util.format('Error "%s" occurred in deserializing the responseBody ' + + '- "%s" for the default response.', defaultError.message, responseBody); + return callback(error); + } + return callback(error); + } + // Create Result + var result = null; + if (responseBody === '') responseBody = null; + // Deserialize Response + if (statusCode === 200) { + var parsedResponse = null; + try { + parsedResponse = JSON.parse(responseBody); + result = JSON.parse(responseBody); + if (parsedResponse !== null && parsedResponse !== undefined) { + var resultMapper = { + required: false, + serializedName: 'parsedResponse', + type: { + name: 'UnixTime' + } + }; + result = client.deserialize(resultMapper, parsedResponse, 'result'); + } + } catch (error) { + var deserializationError = new Error(util.format('Error "%s" occurred in deserializing the responseBody - "%s"', error, responseBody)); + deserializationError.request = msRest.stripRequest(httpRequest); + deserializationError.response = msRest.stripResponse(response); + return callback(deserializationError); + } + } + + return callback(null, result, httpRequest, response); + }); +}; + +/** + * Get null Unix time value + * + * @param {object} [options] Optional Parameters. + * + * @param {object} [options.customHeaders] Headers that will be added to the + * request + * + * @param {function} callback + * + * @returns {function} callback(err, result, request, response) + * + * {Error} err - The Error object if an error occurred, null otherwise. + * + * {date} [result] - The deserialized result object. + * + * {object} [request] - The HTTP Request object if an error did not occur. + * + * {stream} [response] - The HTTP Response stream if an error did not occur. + */ +IntModel.prototype.getNullUnixTime = function (options, callback) { + var client = this.client; + if(!callback && typeof options === 'function') { + callback = options; + options = null; + } + if (!callback) { + throw new Error('callback cannot be null.'); + } + + // Construct URL + var requestUrl = this.client.baseUri + + '//int/nullunixtime'; + // trim all duplicate forward slashes in the url + var regex = /([^:]\/)\/+/gi; + requestUrl = requestUrl.replace(regex, '$1'); + + // Create HTTP transport objects + var httpRequest = new WebResource(); + httpRequest.method = 'GET'; + httpRequest.headers = {}; + httpRequest.url = requestUrl; + // Set Headers + if(options) { + for(var headerName in options['customHeaders']) { + if (options['customHeaders'].hasOwnProperty(headerName)) { + httpRequest.headers[headerName] = options['customHeaders'][headerName]; + } + } + } + httpRequest.headers['Content-Type'] = 'application/json; charset=utf-8'; + httpRequest.body = null; + // Send Request + return client.pipeline(httpRequest, function (err, response, responseBody) { + if (err) { + return callback(err); + } + var statusCode = response.statusCode; + if (statusCode !== 200) { + var error = new Error(responseBody); + error.statusCode = response.statusCode; + error.request = msRest.stripRequest(httpRequest); + error.response = msRest.stripResponse(response); + if (responseBody === '') responseBody = null; + var parsedErrorResponse; + try { + parsedErrorResponse = JSON.parse(responseBody); + if (parsedErrorResponse) { + if (parsedErrorResponse.error) parsedErrorResponse = parsedErrorResponse.error; + if (parsedErrorResponse.code) error.code = parsedErrorResponse.code; + if (parsedErrorResponse.message) error.message = parsedErrorResponse.message; + } + if (parsedErrorResponse !== null && parsedErrorResponse !== undefined) { + var resultMapper = new client.models['ErrorModel']().mapper(); + error.body = client.deserialize(resultMapper, parsedErrorResponse, 'error.body'); + } + } catch (defaultError) { + error.message = util.format('Error "%s" occurred in deserializing the responseBody ' + + '- "%s" for the default response.', defaultError.message, responseBody); + return callback(error); + } + return callback(error); + } + // Create Result + var result = null; + if (responseBody === '') responseBody = null; + // Deserialize Response + if (statusCode === 200) { + var parsedResponse = null; + try { + parsedResponse = JSON.parse(responseBody); + result = JSON.parse(responseBody); + if (parsedResponse !== null && parsedResponse !== undefined) { + var resultMapper = { + required: false, + serializedName: 'parsedResponse', + type: { + name: 'UnixTime' + } + }; + result = client.deserialize(resultMapper, parsedResponse, 'result'); + } + } catch (error) { + var deserializationError = new Error(util.format('Error "%s" occurred in deserializing the responseBody - "%s"', error, responseBody)); + deserializationError.request = msRest.stripRequest(httpRequest); + deserializationError.response = msRest.stripResponse(response); + return callback(deserializationError); + } + } + + return callback(null, result, httpRequest, response); + }); +}; + module.exports = IntModel; diff --git a/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/CompositeBoolIntClient/operations/index.d.ts b/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/CompositeBoolIntClient/operations/index.d.ts index 8238ac41b5170..507488a58f3f6 100644 --- a/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/CompositeBoolIntClient/operations/index.d.ts +++ b/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/CompositeBoolIntClient/operations/index.d.ts @@ -264,4 +264,62 @@ export interface IntModel { */ putMin64(intBody: number, options: { customHeaders? : { [headerName: string]: string; } }, callback: ServiceCallback): void; putMin64(intBody: number, callback: ServiceCallback): void; + + /** + * Get datetime encoded as Unix time value + * + * @param {object} [options] Optional Parameters. + * + * @param {object} [options.customHeaders] Headers that will be added to the + * request + * + * @param {ServiceCallback} [callback] callback function; see ServiceCallback + * doc in ms-rest index.d.ts for details + */ + getUnixTime(options: { customHeaders? : { [headerName: string]: string; } }, callback: ServiceCallback): void; + getUnixTime(callback: ServiceCallback): void; + + /** + * Put datetime encoded as Unix time + * + * @param {date} intBody + * + * @param {object} [options] Optional Parameters. + * + * @param {object} [options.customHeaders] Headers that will be added to the + * request + * + * @param {ServiceCallback} [callback] callback function; see ServiceCallback + * doc in ms-rest index.d.ts for details + */ + putUnixTimeDate(intBody: Date, options: { customHeaders? : { [headerName: string]: string; } }, callback: ServiceCallback): void; + putUnixTimeDate(intBody: Date, callback: ServiceCallback): void; + + /** + * Get invalid Unix time value + * + * @param {object} [options] Optional Parameters. + * + * @param {object} [options.customHeaders] Headers that will be added to the + * request + * + * @param {ServiceCallback} [callback] callback function; see ServiceCallback + * doc in ms-rest index.d.ts for details + */ + getInvalidUnixTime(options: { customHeaders? : { [headerName: string]: string; } }, callback: ServiceCallback): void; + getInvalidUnixTime(callback: ServiceCallback): void; + + /** + * Get null Unix time value + * + * @param {object} [options] Optional Parameters. + * + * @param {object} [options.customHeaders] Headers that will be added to the + * request + * + * @param {ServiceCallback} [callback] callback function; see ServiceCallback + * doc in ms-rest index.d.ts for details + */ + getNullUnixTime(options: { customHeaders? : { [headerName: string]: string; } }, callback: ServiceCallback): void; + getNullUnixTime(callback: ServiceCallback): void; } diff --git a/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/CompositeBoolIntClient/operations/intModel.js b/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/CompositeBoolIntClient/operations/intModel.js index e7c05cfad0073..d00f8cb625a0c 100644 --- a/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/CompositeBoolIntClient/operations/intModel.js +++ b/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/CompositeBoolIntClient/operations/intModel.js @@ -1196,5 +1196,469 @@ IntModel.prototype.putMin64 = function (intBody, options, callback) { }); }; +/** + * Get datetime encoded as Unix time value + * + * @param {object} [options] Optional Parameters. + * + * @param {object} [options.customHeaders] Headers that will be added to the + * request + * + * @param {function} callback + * + * @returns {function} callback(err, result, request, response) + * + * {Error} err - The Error object if an error occurred, null otherwise. + * + * {date} [result] - The deserialized result object. + * + * {object} [request] - The HTTP Request object if an error did not occur. + * + * {stream} [response] - The HTTP Response stream if an error did not occur. + */ +IntModel.prototype.getUnixTime = function (options, callback) { + var client = this.client; + if(!callback && typeof options === 'function') { + callback = options; + options = null; + } + if (!callback) { + throw new Error('callback cannot be null.'); + } + + // Construct URL + var requestUrl = this.client.baseUri + + '//int/unixtime'; + // trim all duplicate forward slashes in the url + var regex = /([^:]\/)\/+/gi; + requestUrl = requestUrl.replace(regex, '$1'); + + // Create HTTP transport objects + var httpRequest = new WebResource(); + httpRequest.method = 'GET'; + httpRequest.headers = {}; + httpRequest.url = requestUrl; + // Set Headers + if(options) { + for(var headerName in options['customHeaders']) { + if (options['customHeaders'].hasOwnProperty(headerName)) { + httpRequest.headers[headerName] = options['customHeaders'][headerName]; + } + } + } + httpRequest.headers['Content-Type'] = 'application/json; charset=utf-8'; + httpRequest.body = null; + // Send Request + return client.pipeline(httpRequest, function (err, response, responseBody) { + if (err) { + return callback(err); + } + var statusCode = response.statusCode; + if (statusCode !== 200) { + var error = new Error(responseBody); + error.statusCode = response.statusCode; + error.request = msRest.stripRequest(httpRequest); + error.response = msRest.stripResponse(response); + if (responseBody === '') responseBody = null; + var parsedErrorResponse; + try { + parsedErrorResponse = JSON.parse(responseBody); + if (parsedErrorResponse) { + if (parsedErrorResponse.error) parsedErrorResponse = parsedErrorResponse.error; + if (parsedErrorResponse.code) error.code = parsedErrorResponse.code; + if (parsedErrorResponse.message) error.message = parsedErrorResponse.message; + } + if (parsedErrorResponse !== null && parsedErrorResponse !== undefined) { + var resultMapper = new client.models['ErrorModel']().mapper(); + error.body = client.deserialize(resultMapper, parsedErrorResponse, 'error.body'); + } + } catch (defaultError) { + error.message = util.format('Error "%s" occurred in deserializing the responseBody ' + + '- "%s" for the default response.', defaultError.message, responseBody); + return callback(error); + } + return callback(error); + } + // Create Result + var result = null; + if (responseBody === '') responseBody = null; + // Deserialize Response + if (statusCode === 200) { + var parsedResponse = null; + try { + parsedResponse = JSON.parse(responseBody); + result = JSON.parse(responseBody); + if (parsedResponse !== null && parsedResponse !== undefined) { + var resultMapper = { + required: false, + serializedName: 'parsedResponse', + type: { + name: 'UnixTime' + } + }; + result = client.deserialize(resultMapper, parsedResponse, 'result'); + } + } catch (error) { + var deserializationError = new Error(util.format('Error "%s" occurred in deserializing the responseBody - "%s"', error, responseBody)); + deserializationError.request = msRest.stripRequest(httpRequest); + deserializationError.response = msRest.stripResponse(response); + return callback(deserializationError); + } + } + + return callback(null, result, httpRequest, response); + }); +}; + +/** + * Put datetime encoded as Unix time + * + * @param {date} intBody + * + * @param {object} [options] Optional Parameters. + * + * @param {object} [options.customHeaders] Headers that will be added to the + * request + * + * @param {function} callback + * + * @returns {function} callback(err, result, request, response) + * + * {Error} err - The Error object if an error occurred, null otherwise. + * + * {null} [result] - The deserialized result object. + * + * {object} [request] - The HTTP Request object if an error did not occur. + * + * {stream} [response] - The HTTP Response stream if an error did not occur. + */ +IntModel.prototype.putUnixTimeDate = function (intBody, options, callback) { + var client = this.client; + if(!callback && typeof options === 'function') { + callback = options; + options = null; + } + if (!callback) { + throw new Error('callback cannot be null.'); + } + // Validate + try { + if(!intBody || !(intBody instanceof Date || + (typeof intBody.valueOf() === 'string' && !isNaN(Date.parse(intBody))))) { + throw new Error('intBody cannot be null or undefined and it must be of type date.'); + } + } catch (error) { + return callback(error); + } + + // Construct URL + var requestUrl = this.client.baseUri + + '//int/unixtime'; + // trim all duplicate forward slashes in the url + var regex = /([^:]\/)\/+/gi; + requestUrl = requestUrl.replace(regex, '$1'); + + // Create HTTP transport objects + var httpRequest = new WebResource(); + httpRequest.method = 'PUT'; + httpRequest.headers = {}; + httpRequest.url = requestUrl; + // Set Headers + if(options) { + for(var headerName in options['customHeaders']) { + if (options['customHeaders'].hasOwnProperty(headerName)) { + httpRequest.headers[headerName] = options['customHeaders'][headerName]; + } + } + } + httpRequest.headers['Content-Type'] = 'application/json; charset=utf-8'; + // Serialize Request + var requestContent = null; + var requestModel = null; + try { + if (intBody !== null && intBody !== undefined) { + var requestModelMapper = { + required: true, + serializedName: 'intBody', + type: { + name: 'UnixTime' + } + }; + requestModel = client.serialize(requestModelMapper, intBody, 'intBody'); + requestContent = JSON.stringify(requestModel); + } + } catch (error) { + var serializationError = new Error(util.format('Error "%s" occurred in serializing the ' + + 'payload - "%s"', error.message, util.inspect(intBody, {depth: null}))); + return callback(serializationError); + } + httpRequest.body = requestContent; + // Send Request + return client.pipeline(httpRequest, function (err, response, responseBody) { + if (err) { + return callback(err); + } + var statusCode = response.statusCode; + if (statusCode !== 200) { + var error = new Error(responseBody); + error.statusCode = response.statusCode; + error.request = msRest.stripRequest(httpRequest); + error.response = msRest.stripResponse(response); + if (responseBody === '') responseBody = null; + var parsedErrorResponse; + try { + parsedErrorResponse = JSON.parse(responseBody); + if (parsedErrorResponse) { + if (parsedErrorResponse.error) parsedErrorResponse = parsedErrorResponse.error; + if (parsedErrorResponse.code) error.code = parsedErrorResponse.code; + if (parsedErrorResponse.message) error.message = parsedErrorResponse.message; + } + if (parsedErrorResponse !== null && parsedErrorResponse !== undefined) { + var resultMapper = new client.models['ErrorModel']().mapper(); + error.body = client.deserialize(resultMapper, parsedErrorResponse, 'error.body'); + } + } catch (defaultError) { + error.message = util.format('Error "%s" occurred in deserializing the responseBody ' + + '- "%s" for the default response.', defaultError.message, responseBody); + return callback(error); + } + return callback(error); + } + // Create Result + var result = null; + if (responseBody === '') responseBody = null; + + return callback(null, result, httpRequest, response); + }); +}; + +/** + * Get invalid Unix time value + * + * @param {object} [options] Optional Parameters. + * + * @param {object} [options.customHeaders] Headers that will be added to the + * request + * + * @param {function} callback + * + * @returns {function} callback(err, result, request, response) + * + * {Error} err - The Error object if an error occurred, null otherwise. + * + * {date} [result] - The deserialized result object. + * + * {object} [request] - The HTTP Request object if an error did not occur. + * + * {stream} [response] - The HTTP Response stream if an error did not occur. + */ +IntModel.prototype.getInvalidUnixTime = function (options, callback) { + var client = this.client; + if(!callback && typeof options === 'function') { + callback = options; + options = null; + } + if (!callback) { + throw new Error('callback cannot be null.'); + } + + // Construct URL + var requestUrl = this.client.baseUri + + '//int/invalidunixtime'; + // trim all duplicate forward slashes in the url + var regex = /([^:]\/)\/+/gi; + requestUrl = requestUrl.replace(regex, '$1'); + + // Create HTTP transport objects + var httpRequest = new WebResource(); + httpRequest.method = 'GET'; + httpRequest.headers = {}; + httpRequest.url = requestUrl; + // Set Headers + if(options) { + for(var headerName in options['customHeaders']) { + if (options['customHeaders'].hasOwnProperty(headerName)) { + httpRequest.headers[headerName] = options['customHeaders'][headerName]; + } + } + } + httpRequest.headers['Content-Type'] = 'application/json; charset=utf-8'; + httpRequest.body = null; + // Send Request + return client.pipeline(httpRequest, function (err, response, responseBody) { + if (err) { + return callback(err); + } + var statusCode = response.statusCode; + if (statusCode !== 200) { + var error = new Error(responseBody); + error.statusCode = response.statusCode; + error.request = msRest.stripRequest(httpRequest); + error.response = msRest.stripResponse(response); + if (responseBody === '') responseBody = null; + var parsedErrorResponse; + try { + parsedErrorResponse = JSON.parse(responseBody); + if (parsedErrorResponse) { + if (parsedErrorResponse.error) parsedErrorResponse = parsedErrorResponse.error; + if (parsedErrorResponse.code) error.code = parsedErrorResponse.code; + if (parsedErrorResponse.message) error.message = parsedErrorResponse.message; + } + if (parsedErrorResponse !== null && parsedErrorResponse !== undefined) { + var resultMapper = new client.models['ErrorModel']().mapper(); + error.body = client.deserialize(resultMapper, parsedErrorResponse, 'error.body'); + } + } catch (defaultError) { + error.message = util.format('Error "%s" occurred in deserializing the responseBody ' + + '- "%s" for the default response.', defaultError.message, responseBody); + return callback(error); + } + return callback(error); + } + // Create Result + var result = null; + if (responseBody === '') responseBody = null; + // Deserialize Response + if (statusCode === 200) { + var parsedResponse = null; + try { + parsedResponse = JSON.parse(responseBody); + result = JSON.parse(responseBody); + if (parsedResponse !== null && parsedResponse !== undefined) { + var resultMapper = { + required: false, + serializedName: 'parsedResponse', + type: { + name: 'UnixTime' + } + }; + result = client.deserialize(resultMapper, parsedResponse, 'result'); + } + } catch (error) { + var deserializationError = new Error(util.format('Error "%s" occurred in deserializing the responseBody - "%s"', error, responseBody)); + deserializationError.request = msRest.stripRequest(httpRequest); + deserializationError.response = msRest.stripResponse(response); + return callback(deserializationError); + } + } + + return callback(null, result, httpRequest, response); + }); +}; + +/** + * Get null Unix time value + * + * @param {object} [options] Optional Parameters. + * + * @param {object} [options.customHeaders] Headers that will be added to the + * request + * + * @param {function} callback + * + * @returns {function} callback(err, result, request, response) + * + * {Error} err - The Error object if an error occurred, null otherwise. + * + * {date} [result] - The deserialized result object. + * + * {object} [request] - The HTTP Request object if an error did not occur. + * + * {stream} [response] - The HTTP Response stream if an error did not occur. + */ +IntModel.prototype.getNullUnixTime = function (options, callback) { + var client = this.client; + if(!callback && typeof options === 'function') { + callback = options; + options = null; + } + if (!callback) { + throw new Error('callback cannot be null.'); + } + + // Construct URL + var requestUrl = this.client.baseUri + + '//int/nullunixtime'; + // trim all duplicate forward slashes in the url + var regex = /([^:]\/)\/+/gi; + requestUrl = requestUrl.replace(regex, '$1'); + + // Create HTTP transport objects + var httpRequest = new WebResource(); + httpRequest.method = 'GET'; + httpRequest.headers = {}; + httpRequest.url = requestUrl; + // Set Headers + if(options) { + for(var headerName in options['customHeaders']) { + if (options['customHeaders'].hasOwnProperty(headerName)) { + httpRequest.headers[headerName] = options['customHeaders'][headerName]; + } + } + } + httpRequest.headers['Content-Type'] = 'application/json; charset=utf-8'; + httpRequest.body = null; + // Send Request + return client.pipeline(httpRequest, function (err, response, responseBody) { + if (err) { + return callback(err); + } + var statusCode = response.statusCode; + if (statusCode !== 200) { + var error = new Error(responseBody); + error.statusCode = response.statusCode; + error.request = msRest.stripRequest(httpRequest); + error.response = msRest.stripResponse(response); + if (responseBody === '') responseBody = null; + var parsedErrorResponse; + try { + parsedErrorResponse = JSON.parse(responseBody); + if (parsedErrorResponse) { + if (parsedErrorResponse.error) parsedErrorResponse = parsedErrorResponse.error; + if (parsedErrorResponse.code) error.code = parsedErrorResponse.code; + if (parsedErrorResponse.message) error.message = parsedErrorResponse.message; + } + if (parsedErrorResponse !== null && parsedErrorResponse !== undefined) { + var resultMapper = new client.models['ErrorModel']().mapper(); + error.body = client.deserialize(resultMapper, parsedErrorResponse, 'error.body'); + } + } catch (defaultError) { + error.message = util.format('Error "%s" occurred in deserializing the responseBody ' + + '- "%s" for the default response.', defaultError.message, responseBody); + return callback(error); + } + return callback(error); + } + // Create Result + var result = null; + if (responseBody === '') responseBody = null; + // Deserialize Response + if (statusCode === 200) { + var parsedResponse = null; + try { + parsedResponse = JSON.parse(responseBody); + result = JSON.parse(responseBody); + if (parsedResponse !== null && parsedResponse !== undefined) { + var resultMapper = { + required: false, + serializedName: 'parsedResponse', + type: { + name: 'UnixTime' + } + }; + result = client.deserialize(resultMapper, parsedResponse, 'result'); + } + } catch (error) { + var deserializationError = new Error(util.format('Error "%s" occurred in deserializing the responseBody - "%s"', error, responseBody)); + deserializationError.request = msRest.stripRequest(httpRequest); + deserializationError.response = msRest.stripResponse(response); + return callback(deserializationError); + } + } + + return callback(null, result, httpRequest, response); + }); +}; + module.exports = IntModel; diff --git a/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/ModelFlattening/models/simpleProduct.js b/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/ModelFlattening/models/simpleProduct.js index 3e66a747ff5a0..cca28edbd8eda 100644 --- a/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/ModelFlattening/models/simpleProduct.js +++ b/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/ModelFlattening/models/simpleProduct.js @@ -42,7 +42,6 @@ SimpleProduct.prototype.mapper = function () { return { required: false, serializedName: 'SimpleProduct', - defaultValue: {}, type: { name: 'Composite', className: 'SimpleProduct', diff --git a/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/Url/operations/index.d.ts b/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/Url/operations/index.d.ts index 3d9f5f55e7f91..36fd5ba34f312 100644 --- a/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/Url/operations/index.d.ts +++ b/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/Url/operations/index.d.ts @@ -394,6 +394,22 @@ export interface Paths { */ arrayCsvInPath(arrayPath: string[], options: { customHeaders? : { [headerName: string]: string; } }, callback: ServiceCallback): void; arrayCsvInPath(arrayPath: string[], callback: ServiceCallback): void; + + /** + * Get the date 2016-04-13 encoded value as '1460505600' (Unix time) + * + * @param {date} unixTimeUrlPath Unix time encoded value + * + * @param {object} [options] Optional Parameters. + * + * @param {object} [options.customHeaders] Headers that will be added to the + * request + * + * @param {ServiceCallback} [callback] callback function; see ServiceCallback + * doc in ms-rest index.d.ts for details + */ + unixTimeUrl(unixTimeUrlPath: Date, options: { customHeaders? : { [headerName: string]: string; } }, callback: ServiceCallback): void; + unixTimeUrl(unixTimeUrlPath: Date, callback: ServiceCallback): void; } /** diff --git a/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/Url/operations/paths.js b/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/Url/operations/paths.js index ac14e44e195cb..2b5ff16d6bf66 100644 --- a/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/Url/operations/paths.js +++ b/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/Url/operations/paths.js @@ -2458,5 +2458,108 @@ Paths.prototype.arrayCsvInPath = function (arrayPath, options, callback) { }); }; +/** + * Get the date 2016-04-13 encoded value as '1460505600' (Unix time) + * + * @param {date} unixTimeUrlPath Unix time encoded value + * + * @param {object} [options] Optional Parameters. + * + * @param {object} [options.customHeaders] Headers that will be added to the + * request + * + * @param {function} callback + * + * @returns {function} callback(err, result, request, response) + * + * {Error} err - The Error object if an error occurred, null otherwise. + * + * {null} [result] - The deserialized result object. + * + * {object} [request] - The HTTP Request object if an error did not occur. + * + * {stream} [response] - The HTTP Response stream if an error did not occur. + */ +Paths.prototype.unixTimeUrl = function (unixTimeUrlPath, options, callback) { + var client = this.client; + if(!callback && typeof options === 'function') { + callback = options; + options = null; + } + if (!callback) { + throw new Error('callback cannot be null.'); + } + // Validate + try { + if(!unixTimeUrlPath || !(unixTimeUrlPath instanceof Date || + (typeof unixTimeUrlPath.valueOf() === 'string' && !isNaN(Date.parse(unixTimeUrlPath))))) { + throw new Error('unixTimeUrlPath cannot be null or undefined and it must be of type date.'); + } + } catch (error) { + return callback(error); + } + + // Construct URL + var requestUrl = this.client.baseUri + + '//paths/int/1460505600/{unixTimeUrlPath}'; + requestUrl = requestUrl.replace('{unixTimeUrlPath}', encodeURIComponent(client.serialize({required: true, serializedName: 'unixTimeUrlPath', type: {name: 'UnixTime'}}, unixTimeUrlPath, 'unixTimeUrlPath'))); + // trim all duplicate forward slashes in the url + var regex = /([^:]\/)\/+/gi; + requestUrl = requestUrl.replace(regex, '$1'); + + // Create HTTP transport objects + var httpRequest = new WebResource(); + httpRequest.method = 'GET'; + httpRequest.headers = {}; + httpRequest.url = requestUrl; + // Set Headers + if(options) { + for(var headerName in options['customHeaders']) { + if (options['customHeaders'].hasOwnProperty(headerName)) { + httpRequest.headers[headerName] = options['customHeaders'][headerName]; + } + } + } + httpRequest.headers['Content-Type'] = 'application/json; charset=utf-8'; + httpRequest.body = null; + // Send Request + return client.pipeline(httpRequest, function (err, response, responseBody) { + if (err) { + return callback(err); + } + var statusCode = response.statusCode; + if (statusCode !== 200) { + var error = new Error(responseBody); + error.statusCode = response.statusCode; + error.request = msRest.stripRequest(httpRequest); + error.response = msRest.stripResponse(response); + if (responseBody === '') responseBody = null; + var parsedErrorResponse; + try { + parsedErrorResponse = JSON.parse(responseBody); + if (parsedErrorResponse) { + if (parsedErrorResponse.error) parsedErrorResponse = parsedErrorResponse.error; + if (parsedErrorResponse.code) error.code = parsedErrorResponse.code; + if (parsedErrorResponse.message) error.message = parsedErrorResponse.message; + } + if (parsedErrorResponse !== null && parsedErrorResponse !== undefined) { + var resultMapper = new client.models['ErrorModel']().mapper(); + error.body = client.deserialize(resultMapper, parsedErrorResponse, 'error.body'); + } + } catch (defaultError) { + error.message = util.format('Error "%s" occurred in deserializing the responseBody ' + + '- "%s" for the default response.', defaultError.message, responseBody); + return callback(error); + } + return callback(error); + } + // Create Result + var result = null; + if (responseBody === '') responseBody = null; + + return callback(null, result, httpRequest, response); + }); +}; + module.exports = Paths; diff --git a/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/Validation/models/childProduct.js b/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/Validation/models/childProduct.js index 212a2c646ec44..14cb8cf926118 100644 --- a/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/Validation/models/childProduct.js +++ b/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/Validation/models/childProduct.js @@ -31,7 +31,6 @@ ChildProduct.prototype.mapper = function () { return { required: false, serializedName: 'ChildProduct', - defaultValue: {}, type: { name: 'Composite', className: 'ChildProduct', diff --git a/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/Validation/models/constantProduct.js b/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/Validation/models/constantProduct.js index e79e409278475..cd97a2c9285e5 100644 --- a/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/Validation/models/constantProduct.js +++ b/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/Validation/models/constantProduct.js @@ -29,7 +29,6 @@ ConstantProduct.prototype.mapper = function () { return { required: false, serializedName: 'ConstantProduct', - defaultValue: {}, type: { name: 'Composite', className: 'ConstantProduct', diff --git a/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/Validation/models/product.js b/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/Validation/models/product.js index 6af3595ad51bb..ee09ede6f6cac 100644 --- a/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/Validation/models/product.js +++ b/AutoRest/Generators/NodeJS/NodeJS.Tests/Expected/AcceptanceTests/Validation/models/product.js @@ -47,7 +47,6 @@ Product.prototype.mapper = function () { return { required: false, serializedName: 'Product', - defaultValue: {}, type: { name: 'Composite', className: 'Product', diff --git a/AutoRest/Generators/NodeJS/NodeJS/ClientModelExtensions.cs b/AutoRest/Generators/NodeJS/NodeJS/ClientModelExtensions.cs index c842b28b3280b..ba3a24c17bf8f 100644 --- a/AutoRest/Generators/NodeJS/NodeJS/ClientModelExtensions.cs +++ b/AutoRest/Generators/NodeJS/NodeJS/ClientModelExtensions.cs @@ -131,6 +131,12 @@ public static string ToString(this IType type, string reference) return string.Format(CultureInfo.InvariantCulture, "client.serialize({{required: true, serializedName: '{0}', type: {{name: 'Base64Url'}}}}, {0}, '{0}')", reference); } + + if (known.Type == KnownPrimaryType.UnixTime) + { + return string.Format(CultureInfo.InvariantCulture, + "client.serialize({{required: true, serializedName: '{0}', type: {{name: 'UnixTime'}}}}, {0}, '{0}')", reference); + } } return string.Format(CultureInfo.InvariantCulture, "{0}.toString()", reference); @@ -253,7 +259,8 @@ private static string ValidatePrimaryType(this PrimaryType primary, IScopeProvid builder.AppendLine("if ({0} && !Buffer.isBuffer({0})) {{", valueReference, lowercaseTypeName); return ConstructValidationCheck(builder, typeErrorMessage, valueReference, primary.Name).ToString(); } - else if (primary.Type == KnownPrimaryType.DateTime || primary.Type == KnownPrimaryType.Date || primary.Type == KnownPrimaryType.DateTimeRfc1123) + else if (primary.Type == KnownPrimaryType.DateTime || primary.Type == KnownPrimaryType.Date || + primary.Type == KnownPrimaryType.DateTimeRfc1123 || primary.Type == KnownPrimaryType.UnixTime) { if (isRequired) { @@ -302,11 +309,13 @@ private static string PrimaryTSType(this PrimaryType primary) if (primary.Type == KnownPrimaryType.Boolean) return "boolean"; - else if (primary.Type == KnownPrimaryType.Double || primary.Type == KnownPrimaryType.Decimal || primary.Type == KnownPrimaryType.Int || primary.Type == KnownPrimaryType.Long) + else if (primary.Type == KnownPrimaryType.Double || primary.Type == KnownPrimaryType.Decimal || + primary.Type == KnownPrimaryType.Int || primary.Type == KnownPrimaryType.Long) return "number"; else if (primary.Type == KnownPrimaryType.String || primary.Type == KnownPrimaryType.Uuid) return "string"; - else if (primary.Type == KnownPrimaryType.Date || primary.Type == KnownPrimaryType.DateTime || primary.Type == KnownPrimaryType.DateTimeRfc1123) + else if (primary.Type == KnownPrimaryType.Date || primary.Type == KnownPrimaryType.DateTime || + primary.Type == KnownPrimaryType.DateTimeRfc1123 || primary.Type == KnownPrimaryType.UnixTime) return "Date"; else if (primary.Type == KnownPrimaryType.Object) return "any"; // TODO: test this @@ -666,9 +675,9 @@ public static string ValidateType(this IType type, IScopeProvider scope, string public static string ConstructMapper(this IType type, string serializedName, IParameter parameter, bool isPageable, bool expandComposite) { var builder = new IndentedStringBuilder(" "); - string defaultValue = null; - bool isRequired = false; - bool isConstant = false; + string defaultValue = null; + bool isRequired = false; + bool isConstant = false; bool isReadOnly = false; Dictionary constraints = null; var property = parameter as Property; @@ -684,7 +693,7 @@ public static string ConstructMapper(this IType type, string serializedName, IPa isReadOnly = property.IsReadOnly; } CompositeType composite = type as CompositeType; - if (composite != null && composite.ContainsConstantProperties) + if (composite != null && composite.ContainsConstantProperties && (parameter != null && parameter.IsRequired)) { defaultValue = "{}"; } @@ -746,7 +755,8 @@ public static string ConstructMapper(this IType type, string serializedName, IPa { builder.AppendLine("type: {").Indent().AppendLine("name: 'Boolean'").Outdent().AppendLine("}"); } - else if(primary.Type == KnownPrimaryType.Int || primary.Type == KnownPrimaryType.Long || primary.Type == KnownPrimaryType.Decimal || primary.Type == KnownPrimaryType.Double) + else if (primary.Type == KnownPrimaryType.Int || primary.Type == KnownPrimaryType.Long || + primary.Type == KnownPrimaryType.Decimal || primary.Type == KnownPrimaryType.Double) { builder.AppendLine("type: {").Indent().AppendLine("name: 'Number'").Outdent().AppendLine("}"); } @@ -782,6 +792,10 @@ public static string ConstructMapper(this IType type, string serializedName, IPa { builder.AppendLine("type: {").Indent().AppendLine("name: 'TimeSpan'").Outdent().AppendLine("}"); } + else if (primary.Type == KnownPrimaryType.UnixTime) + { + builder.AppendLine("type: {").Indent().AppendLine("name: 'UnixTime'").Outdent().AppendLine("}"); + } else if (primary.Type == KnownPrimaryType.Object) { builder.AppendLine("type: {").Indent().AppendLine("name: 'Object'").Outdent().AppendLine("}"); diff --git a/AutoRest/Generators/NodeJS/NodeJS/GlobalSuppressions.cs b/AutoRest/Generators/NodeJS/NodeJS/GlobalSuppressions.cs index dd0050ebae502..9fecaab118c8e 100644 --- a/AutoRest/Generators/NodeJS/NodeJS/GlobalSuppressions.cs +++ b/AutoRest/Generators/NodeJS/NodeJS/GlobalSuppressions.cs @@ -191,4 +191,7 @@ [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Scope = "member", Target = "Microsoft.Rest.Generator.NodeJS.TemplateModels.ClientModelExtensions.#ConstructMapper(Microsoft.Rest.Generator.ClientModel.IType,System.String,Microsoft.Rest.Generator.ClientModel.IParameter,System.Boolean,System.Boolean)")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Scope = "member", Target = "Microsoft.Rest.Generator.NodeJS.NodeJsCodeNamer.#EscapeDefaultValue(System.String,Microsoft.Rest.Generator.ClientModel.IType)")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "readOnly", Scope = "member", Target = "Microsoft.Rest.Generator.NodeJS.TemplateModels.ClientModelExtensions.#ConstructMapper(Microsoft.Rest.Generator.ClientModel.IType,System.String,Microsoft.Rest.Generator.ClientModel.IParameter,System.Boolean,System.Boolean)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Scope = "member", Target = "Microsoft.Rest.Generator.NodeJS.TemplateModels.ClientModelExtensions.#ValidatePrimaryType(Microsoft.Rest.Generator.ClientModel.PrimaryType,Microsoft.Rest.Generator.Utilities.IScopeProvider,System.String,System.Boolean)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1505:AvoidUnmaintainableCode", Scope = "member", Target = "Microsoft.Rest.Generator.NodeJS.TemplateModels.ClientModelExtensions.#ConstructMapper(Microsoft.Rest.Generator.ClientModel.IType,System.String,Microsoft.Rest.Generator.ClientModel.IParameter,System.Boolean,System.Boolean)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "UnixTime", Scope = "member", Target = "Microsoft.Rest.Generator.NodeJS.TemplateModels.ClientModelExtensions.#ConstructMapper(Microsoft.Rest.Generator.ClientModel.IType,System.String,Microsoft.Rest.Generator.ClientModel.IParameter,System.Boolean,System.Boolean)")] diff --git a/AutoRest/Generators/NodeJS/NodeJS/NodeJsCodeNamer.cs b/AutoRest/Generators/NodeJS/NodeJS/NodeJsCodeNamer.cs index d2f43a402f589..2dc7c2f0edd6a 100644 --- a/AutoRest/Generators/NodeJS/NodeJS/NodeJsCodeNamer.cs +++ b/AutoRest/Generators/NodeJS/NodeJS/NodeJsCodeNamer.cs @@ -365,6 +365,10 @@ private static IType NormalizePrimaryType(PrimaryType primaryType) { primaryType.Name = "Date"; } + else if (primaryType.Type == KnownPrimaryType.UnixTime) + { + primaryType.Name = "Date"; + } else if (primaryType.Type == KnownPrimaryType.Double) { primaryType.Name = "Number"; @@ -393,10 +397,6 @@ private static IType NormalizePrimaryType(PrimaryType primaryType) { primaryType.Name = "moment.duration"; } - else if (primaryType.Type == KnownPrimaryType.UnixTime) - { - primaryType.Name = "Number"; - } else if (primaryType.Type == KnownPrimaryType.Uuid) { primaryType.Name = "Uuid"; diff --git a/AutoRest/Generators/Python/Azure.Python.Tests/Expected/AcceptanceTests/Lro/autorestlongrunningoperationtestservice/operations/lrosa_ds_operations.py b/AutoRest/Generators/Python/Azure.Python.Tests/Expected/AcceptanceTests/Lro/autorestlongrunningoperationtestservice/operations/lrosa_ds_operations.py index f4bb777cedec5..a211b6975e70d 100644 --- a/AutoRest/Generators/Python/Azure.Python.Tests/Expected/AcceptanceTests/Lro/autorestlongrunningoperationtestservice/operations/lrosa_ds_operations.py +++ b/AutoRest/Generators/Python/Azure.Python.Tests/Expected/AcceptanceTests/Lro/autorestlongrunningoperationtestservice/operations/lrosa_ds_operations.py @@ -205,6 +205,92 @@ def get_long_running_output(response): long_running_send, get_long_running_output, get_long_running_status, long_running_operation_timeout) + def put_non_retry201_creating400_invalid_json( + self, product=None, custom_headers={}, raw=False, **operation_config): + """ + Long running put request, service returns a Product with + 'ProvisioningState' = 'Creating' and 201 response code + + :param product: Product to put + :type product: :class:`Product + ` + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :rtype: + :class:`AzureOperationPoller` + instance that returns :class:`Product + ` + :rtype: :class:`ClientRawResponse` + if raw=true + """ + # Construct URL + url = '/lro/nonretryerror/put/201/creating/400/invalidjson' + + # Construct parameters + query_parameters = {} + + # Construct headers + header_parameters = {} + header_parameters['Content-Type'] = 'application/json; charset=utf-8' + if self.config.generate_client_request_id: + header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) + if custom_headers: + header_parameters.update(custom_headers) + if self.config.accept_language is not None: + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') + + # Construct body + if product is not None: + body_content = self._serialize.body(product, 'Product') + else: + body_content = None + + # Construct and send request + def long_running_send(): + + request = self._client.put(url, query_parameters) + return self._client.send( + request, header_parameters, body_content, **operation_config) + + def get_long_running_status(status_link, headers={}): + + request = self._client.get(status_link) + request.headers.update(headers) + return self._client.send( + request, header_parameters, **operation_config) + + def get_long_running_output(response): + + if response.status_code not in [200, 201]: + exp = CloudError(response) + exp.request_id = response.headers.get('x-ms-request-id') + raise exp + + deserialized = None + + if response.status_code == 200: + deserialized = self._deserialize('Product', response) + if response.status_code == 201: + deserialized = self._deserialize('Product', response) + + if raw: + client_raw_response = ClientRawResponse(deserialized, response) + return client_raw_response + + return deserialized + + if raw: + response = long_running_send() + return get_long_running_output(response) + + long_running_operation_timeout = operation_config.get( + 'long_running_operation_timeout', + self.config.long_running_operation_timeout) + return AzureOperationPoller( + long_running_send, get_long_running_output, + get_long_running_status, long_running_operation_timeout) + def put_async_relative_retry400( self, product=None, custom_headers={}, raw=False, **operation_config): """ diff --git a/AutoRest/Generators/Python/Azure.Python/AzurePythonCodeGenerator.cs b/AutoRest/Generators/Python/Azure.Python/AzurePythonCodeGenerator.cs index 0ad15558928b5..eeb311593bb52 100644 --- a/AutoRest/Generators/Python/Azure.Python/AzurePythonCodeGenerator.cs +++ b/AutoRest/Generators/Python/Azure.Python/AzurePythonCodeGenerator.cs @@ -19,7 +19,7 @@ namespace Microsoft.Rest.Generator.Azure.Python { public class AzurePythonCodeGenerator : PythonCodeGenerator { - private const string ClientRuntimePackage = "msrestazure version 0.2.1"; + private const string ClientRuntimePackage = "msrestazure version 0.3.0"; // page extensions class dictionary. private IList pageModels; diff --git a/AutoRest/Generators/Python/Azure.Python/TemplateModels/AzureServiceClientTemplateModel.cs b/AutoRest/Generators/Python/Azure.Python/TemplateModels/AzureServiceClientTemplateModel.cs index f56bc3935547a..0a3b44b0e6446 100644 --- a/AutoRest/Generators/Python/Azure.Python/TemplateModels/AzureServiceClientTemplateModel.cs +++ b/AutoRest/Generators/Python/Azure.Python/TemplateModels/AzureServiceClientTemplateModel.cs @@ -97,7 +97,7 @@ public override string SetupRequires { get { - return "\"msrest>=0.2.0\", \"msrestazure>=0.2.1\""; + return "\"msrest>=0.3.0\", \"msrestazure>=0.3.0\""; } } diff --git a/AutoRest/Generators/Python/Python.Tests/Expected/AcceptanceTests/BodyInteger/autorestintegertestservice/operations/int_model.py b/AutoRest/Generators/Python/Python.Tests/Expected/AcceptanceTests/BodyInteger/autorestintegertestservice/operations/int_model.py index 45d9ed146e114..a2b06061ed5cb 100644 --- a/AutoRest/Generators/Python/Python.Tests/Expected/AcceptanceTests/BodyInteger/autorestintegertestservice/operations/int_model.py +++ b/AutoRest/Generators/Python/Python.Tests/Expected/AcceptanceTests/BodyInteger/autorestintegertestservice/operations/int_model.py @@ -466,3 +466,178 @@ def put_min64( if raw: client_raw_response = ClientRawResponse(None, response) return client_raw_response + + def get_unix_time( + self, custom_headers={}, raw=False, **operation_config): + """ + Get datetime encoded as Unix time value + + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :rtype: long + :rtype: :class:`ClientRawResponse` + if raw=true + """ + # Construct URL + url = '/int/unixtime' + + # Construct parameters + query_parameters = {} + + # Construct headers + header_parameters = {} + header_parameters['Content-Type'] = 'application/json; charset=utf-8' + if custom_headers: + header_parameters.update(custom_headers) + + # Construct and send request + request = self._client.get(url, query_parameters) + response = self._client.send(request, header_parameters, **operation_config) + + if response.status_code not in [200]: + raise models.ErrorException(self._deserialize, response) + + deserialized = None + + if response.status_code == 200: + deserialized = self._deserialize('long', response) + + if raw: + client_raw_response = ClientRawResponse(deserialized, response) + return client_raw_response + + return deserialized + + def put_unix_time_date( + self, int_body, custom_headers={}, raw=False, **operation_config): + """ + Put datetime encoded as Unix time + + :param int_body: + :type int_body: long + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :rtype: None + :rtype: :class:`ClientRawResponse` + if raw=true + """ + # Construct URL + url = '/int/unixtime' + + # Construct parameters + query_parameters = {} + + # Construct headers + header_parameters = {} + header_parameters['Content-Type'] = 'application/json; charset=utf-8' + if custom_headers: + header_parameters.update(custom_headers) + + # Construct body + body_content = self._serialize.body(int_body, 'long') + + # Construct and send request + request = self._client.put(url, query_parameters) + response = self._client.send( + request, header_parameters, body_content, **operation_config) + + if response.status_code not in [200]: + raise models.ErrorException(self._deserialize, response) + + if raw: + client_raw_response = ClientRawResponse(None, response) + return client_raw_response + + def get_invalid_unix_time( + self, custom_headers={}, raw=False, **operation_config): + """ + Get invalid Unix time value + + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :rtype: long + :rtype: :class:`ClientRawResponse` + if raw=true + """ + # Construct URL + url = '/int/invalidunixtime' + + # Construct parameters + query_parameters = {} + + # Construct headers + header_parameters = {} + header_parameters['Content-Type'] = 'application/json; charset=utf-8' + if custom_headers: + header_parameters.update(custom_headers) + + # Construct and send request + request = self._client.get(url, query_parameters) + response = self._client.send(request, header_parameters, **operation_config) + + if response.status_code not in [200]: + raise models.ErrorException(self._deserialize, response) + + deserialized = None + + if response.status_code == 200: + deserialized = self._deserialize('long', response) + + if raw: + client_raw_response = ClientRawResponse(deserialized, response) + return client_raw_response + + return deserialized + + def get_null_unix_time( + self, custom_headers={}, raw=False, **operation_config): + """ + Get null Unix time value + + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :rtype: long + :rtype: :class:`ClientRawResponse` + if raw=true + """ + # Construct URL + url = '/int/nullunixtime' + + # Construct parameters + query_parameters = {} + + # Construct headers + header_parameters = {} + header_parameters['Content-Type'] = 'application/json; charset=utf-8' + if custom_headers: + header_parameters.update(custom_headers) + + # Construct and send request + request = self._client.get(url, query_parameters) + response = self._client.send(request, header_parameters, **operation_config) + + if response.status_code not in [200]: + raise models.ErrorException(self._deserialize, response) + + deserialized = None + + if response.status_code == 200: + deserialized = self._deserialize('long', response) + + if raw: + client_raw_response = ClientRawResponse(deserialized, response) + return client_raw_response + + return deserialized diff --git a/AutoRest/Generators/Python/Python.Tests/Expected/AcceptanceTests/Url/autoresturltestservice/operations/paths.py b/AutoRest/Generators/Python/Python.Tests/Expected/AcceptanceTests/Url/autoresturltestservice/operations/paths.py index 97cd8878c0e6a..c419d607826a2 100644 --- a/AutoRest/Generators/Python/Python.Tests/Expected/AcceptanceTests/Url/autoresturltestservice/operations/paths.py +++ b/AutoRest/Generators/Python/Python.Tests/Expected/AcceptanceTests/Url/autoresturltestservice/operations/paths.py @@ -1114,3 +1114,46 @@ def array_csv_in_path( if raw: client_raw_response = ClientRawResponse(None, response) return client_raw_response + + def unix_time_url( + self, unix_time_url_path, custom_headers={}, raw=False, **operation_config): + """ + Get the date 2016-04-13 encoded value as '1460505600' (Unix time) + + :param unix_time_url_path: Unix time encoded value + :type unix_time_url_path: long + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :rtype: None + :rtype: :class:`ClientRawResponse` + if raw=true + """ + # Construct URL + url = '/paths/int/1460505600/{unixTimeUrlPath}' + path_format_arguments = { + 'unixTimeUrlPath': self._serialize.url("unix_time_url_path", unix_time_url_path, 'long') + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} + + # Construct headers + header_parameters = {} + header_parameters['Content-Type'] = 'application/json; charset=utf-8' + if custom_headers: + header_parameters.update(custom_headers) + + # Construct and send request + request = self._client.get(url, query_parameters) + response = self._client.send(request, header_parameters, **operation_config) + + if response.status_code not in [200]: + raise models.ErrorException(self._deserialize, response) + + if raw: + client_raw_response = ClientRawResponse(None, response) + return client_raw_response diff --git a/AutoRest/Generators/Python/Python/PythonCodeGenerator.cs b/AutoRest/Generators/Python/Python/PythonCodeGenerator.cs index d987055d49f6f..8131b8cba6d34 100644 --- a/AutoRest/Generators/Python/Python/PythonCodeGenerator.cs +++ b/AutoRest/Generators/Python/Python/PythonCodeGenerator.cs @@ -16,7 +16,7 @@ namespace Microsoft.Rest.Generator.Python { public class PythonCodeGenerator : CodeGenerator { - private const string ClientRuntimePackage = "msrest version 0.2.0"; + private const string ClientRuntimePackage = "msrest version 0.3.0"; public PythonCodeGenerator(Settings settings) : base(settings) { diff --git a/AutoRest/Generators/Ruby/Azure.Ruby.Tests/RspecTests/custom_base_uri_more_spec.rb b/AutoRest/Generators/Ruby/Azure.Ruby.Tests/RspecTests/custom_base_uri_more_spec.rb new file mode 100644 index 0000000000000..29a5dff237a7f --- /dev/null +++ b/AutoRest/Generators/Ruby/Azure.Ruby.Tests/RspecTests/custom_base_uri_more_spec.rb @@ -0,0 +1,39 @@ +# encoding: utf-8 + +$: << 'RspecTests/Generated/custom_base_uri_more' + +require 'custom_base_url_more_options' +require 'uri' + +module CustomBaseUriMoreModule + describe 'Custom base uri more options' do + before(:all) do + url = URI(ENV['StubServerURI']) + @vault = "http://#{url.host}" + @key_name = "key1" + + dummyToken = 'dummy12321343423' + @credentials = MsRest::TokenCredentials.new(dummyToken) + + client = CustomBaseUriMoreModule::AutoRestParameterizedCustomHostTestClient.new(@credentials) + client.subscription_id = 'test12' + client.instance_variable_set("@dns_suffix", ":#{url.port.to_s}") + @custom_base_url_client = CustomBaseUriMoreModule::Paths.new(client) + end + + it 'should get empty' do + result = @custom_base_url_client.get_empty_async(@vault, '', @key_name).value! + expect(result.response.status).to eq(200) + end + + it 'should throw on nil vault or secret' do + expect { + @custom_base_url_client.get_empty_async(nil, nil, @key_name).value! + }.to raise_error(ArgumentError) + + expect { + @custom_base_url_client.get_empty_async(@vault, nil, @key_name).value! + }.to raise_error(ArgumentError) + end + end +end diff --git a/AutoRest/Generators/Ruby/Azure.Ruby.Tests/RspecTests/custom_base_uri_spec.rb b/AutoRest/Generators/Ruby/Azure.Ruby.Tests/RspecTests/custom_base_uri_spec.rb new file mode 100644 index 0000000000000..c3eb81c719d54 --- /dev/null +++ b/AutoRest/Generators/Ruby/Azure.Ruby.Tests/RspecTests/custom_base_uri_spec.rb @@ -0,0 +1,33 @@ +# encoding: utf-8 + +$: << 'RspecTests/Generated/custom_base_uri' + +require 'custom_base_url' +require 'uri' + +module CustomBaseUriModule + describe 'Custom base uri' do + before(:all) do + url = URI(ENV['StubServerURI']) + @account_name = url.host + + dummyToken = 'dummy12321343423' + @credentials = MsRest::TokenCredentials.new(dummyToken) + + client = CustomBaseUriModule::AutoRestParameterizedHostTestClient.new(@credentials) + client.instance_variable_set("@host", ":#{url.port.to_s}") + @custom_base_url_client = CustomBaseUriModule::Paths.new(client) + end + + it 'should get empty' do + result = @custom_base_url_client.get_empty_async(@account_name).value! + expect(result.response.status).to eq(200) + end + + it 'should throw on nil account name' do + expect { + @custom_base_url_client.get_empty_async(nil).value! + }.to raise_error(ArgumentError) + end + end +end diff --git a/AutoRest/Generators/Ruby/Ruby.Tests/RspecTests/path_spec.rb b/AutoRest/Generators/Ruby/Ruby.Tests/RspecTests/path_spec.rb index 7e7dc17b5f733..3c2676513fc9f 100644 --- a/AutoRest/Generators/Ruby/Ruby.Tests/RspecTests/path_spec.rb +++ b/AutoRest/Generators/Ruby/Ruby.Tests/RspecTests/path_spec.rb @@ -15,6 +15,8 @@ client = AutoRestUrlTestService.new(@credentials, @base_url) @paths_client = Paths.new(client) + + @array_path = ['ArrayPath1', "begin!*'();:@ &=+$,/?#[]end", nil, ''] end it 'should create test service' do @@ -124,4 +126,9 @@ result = @paths_client.date_time_null_async('null').value! expect(result.response.status).to eq(200) end + + it 'should get array csv in path' do + result = @paths_client.array_csv_in_path_async(@array_path).value! + expect(result.response.status).to eq(200) + end end \ No newline at end of file diff --git a/AutoRest/Generators/Ruby/Ruby/RubyCodeGenerator.cs b/AutoRest/Generators/Ruby/Ruby/RubyCodeGenerator.cs index 5b875665dfa92..368888b082657 100644 --- a/AutoRest/Generators/Ruby/Ruby/RubyCodeGenerator.cs +++ b/AutoRest/Generators/Ruby/Ruby/RubyCodeGenerator.cs @@ -111,24 +111,25 @@ public override string ImplementationFileExtension /// /// Normalizes client model by updating names and types to be language specific. /// - /// - public override void NormalizeClientModel(ServiceClient serviceClientModel) + /// + public override void NormalizeClientModel(ServiceClient serviceClient) { - PopulateAdditionalProperties(serviceClientModel); - CodeNamer.NormalizeClientModel(serviceClientModel); - CodeNamer.ResolveNameCollisions(serviceClientModel, Settings.Namespace, + Extensions.ProcessParameterizedHost(serviceClient, Settings); + PopulateAdditionalProperties(serviceClient); + CodeNamer.NormalizeClientModel(serviceClient); + CodeNamer.ResolveNameCollisions(serviceClient, Settings.Namespace, Settings.Namespace + "::Models"); } /// /// Adds special properties to the service client (e.g. credentials). /// - /// The service client. - private void PopulateAdditionalProperties(ServiceClient serviceClientModel) + /// The service client. + private void PopulateAdditionalProperties(ServiceClient serviceClient) { if (Settings.AddCredentials) { - serviceClientModel.Properties.Add(new Property + serviceClient.Properties.Add(new Property { Name = "Credentials", Type = new PrimaryType(KnownPrimaryType.Credentials), diff --git a/AutoRest/Generators/Ruby/Ruby/TemplateModels/MethodTemplateModel.cs b/AutoRest/Generators/Ruby/Ruby/TemplateModels/MethodTemplateModel.cs index f66881e9294be..e51e53727c910 100644 --- a/AutoRest/Generators/Ruby/Ruby/TemplateModels/MethodTemplateModel.cs +++ b/AutoRest/Generators/Ruby/Ruby/TemplateModels/MethodTemplateModel.cs @@ -1,10 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Net; +using System.Text.RegularExpressions; using Microsoft.Rest.Generator.ClientModel; using Microsoft.Rest.Generator.Ruby.TemplateModels; using Microsoft.Rest.Generator.Utilities; @@ -29,6 +31,173 @@ public MethodTemplateModel(Method source, ServiceClient serviceClient) ServiceClient = serviceClient; } + /// + /// Gets the return type name for the underlying interface method + /// + public virtual string OperationResponseReturnTypeString + { + get + { + return "MsRest::HttpOperationResponse"; + } + } + + /// + /// Gets the type for operation exception + /// + public virtual string OperationExceptionTypeString + { + get + { + return "MsRest::HttpOperationError"; + } + } + + /// + /// Gets the code required to initialize response body. + /// + public virtual string InitializeResponseBody + { + get { return string.Empty; } + } + + /// + /// Gets the list of namespaces where we look for classes that need to + /// be instantiated dynamically due to polymorphism. + /// + public virtual List ClassNamespaces + { + get + { + return new List { }; + } + } + + /// + /// Gets the path parameters as a Ruby dictionary string + /// + public virtual string PathParamsRbDict + { + get + { + return ParamsToRubyDict(EncodingPathParams); + } + } + + /// + /// Gets the skip encoding path parameters as a Ruby dictionary string + /// + public virtual string SkipEncodingPathParamsRbDict + { + get + { + return ParamsToRubyDict(SkipEncodingPathParams); + } + } + + /// + /// Gets the query parameters as a Ruby dictionary string + /// + public virtual string QueryParamsRbDict + { + get + { + return ParamsToRubyDict(EncodingQueryParams); + } + } + + /// + /// Gets the skip encoding query parameters as a Ruby dictionary string + /// + public virtual string SkipEncodingQueryParamsRbDict + { + get + { + return ParamsToRubyDict(SkipEncodingQueryParams); + } + } + + /// + /// Gets the path parameters not including the params that skip encoding + /// + public virtual IEnumerable EncodingPathParams + { + get { return AllPathParams.Where(p => !(p.Extensions.ContainsKey(Generator.Extensions.SkipUrlEncodingExtension) && + String.Equals(p.Extensions[Generator.Extensions.SkipUrlEncodingExtension].ToString(), "true", StringComparison.OrdinalIgnoreCase))); } + } + + /// + /// Gets the skip encoding path parameters + /// + public virtual IEnumerable SkipEncodingPathParams + { + get + { + return AllPathParams.Where(p => + (p.Extensions.ContainsKey(Generator.Extensions.SkipUrlEncodingExtension) && + String.Equals(p.Extensions[Generator.Extensions.SkipUrlEncodingExtension].ToString(), "true", StringComparison.OrdinalIgnoreCase) && + !p.Extensions.ContainsKey("hostParameter"))); + } + } + + /// + /// Gets all path parameters + /// + public virtual IEnumerable AllPathParams + { + get { return ParameterTemplateModels.Where(p => p.Location == ParameterLocation.Path); } + } + + /// + /// Gets the skip encoding query parameters + /// + public virtual IEnumerable SkipEncodingQueryParams + { + get { return AllQueryParams.Where(p => p.Extensions.ContainsKey(Generator.Extensions.SkipUrlEncodingExtension)); } + } + + /// + /// Gets the query parameters not including the params that skip encoding + /// + public virtual IEnumerable EncodingQueryParams + { + get { return AllQueryParams.Where(p => !p.Extensions.ContainsKey(Generator.Extensions.SkipUrlEncodingExtension)); } + } + + /// + /// Gets all of the query parameters + /// + public virtual IEnumerable AllQueryParams + { + get { return ParameterTemplateModels.Where(p => p.Location == ParameterLocation.Query); } + } + + /// + /// Gets the list of middelwares required for HTTP requests. + /// + public virtual IList FaradayMiddlewares + { + get + { + return new List() + { + "[MsRest::RetryPolicyMiddleware, times: 3, retry: 0.02]", + "[:cookie_jar]" + }; + } + } + + /// + /// Gets the expression for default header setting. + /// + public virtual string SetDefaultHeaders + { + get + { + return string.Empty; + } + } + /// /// Gets the reference to the service client object. /// @@ -38,7 +207,7 @@ public MethodTemplateModel(Method source, ServiceClient serviceClient) /// Gets the list of method paramater templates. /// public List ParameterTemplateModels { get; private set; } - + /// /// Gets the list of parameter which need to be included into HTTP header. /// @@ -102,14 +271,11 @@ public string MethodParameterDeclaration PrimaryType type = parameter.Type as PrimaryType; if (type != null) { - if (type.Type == KnownPrimaryType.Boolean || type.Type == KnownPrimaryType.Double || type.Type == KnownPrimaryType.Int || type.Type == KnownPrimaryType.Long) + if (type.Type == KnownPrimaryType.Boolean || type.Type == KnownPrimaryType.Double || + type.Type == KnownPrimaryType.Int || type.Type == KnownPrimaryType.Long || type.Type == KnownPrimaryType.String) { format = "{0} = " + parameter.DefaultValue; } - else if (type.Type == KnownPrimaryType.String) - { - format = "{0} = \"" + parameter.DefaultValue + "\""; - } } } } @@ -152,48 +318,6 @@ public IEnumerable LocalParameters } } - /// - /// Gets the return type name for the underlying interface method - /// - public virtual string OperationResponseReturnTypeString - { - get - { - return "MsRest::HttpOperationResponse"; - } - } - - /// - /// Gets the type for operation exception - /// - public virtual string OperationExceptionTypeString - { - get - { - return "MsRest::HttpOperationError"; - } - } - - /// - /// Gets the code required to initialize response body. - /// - public virtual string InitializeResponseBody - { - get { return string.Empty; } - } - - /// - /// Gets the list of namespaces where we look for classes that need to - /// be instantiated dynamically due to polymorphism. - /// - public virtual List ClassNamespaces - { - get - { - return new List { }; - } - } - /// /// Get the method's request body (or null if there is no request body) /// @@ -229,16 +353,6 @@ public bool UrlWithPath } } - /// - /// Gets the formatted status code. - /// - /// The status code. - /// Formatted status code. - public string GetStatusCodeReference(HttpStatusCode code) - { - return string.Format("{0}", (int)code); - } - /// /// Creates a code in form of string which deserializes given input variable of given type. /// @@ -324,99 +438,52 @@ public virtual string RemoveDuplicateForwardSlashes(string urlVariableName) return builder.ToString(); } - + /// - /// Gets the path parameters as a Ruby dictionary string + /// Generate code to build the URL from a url expression and method parameters /// - public virtual string PathParamsRbDict + /// The variable to store the url in. + /// + public virtual string BuildUrl(string variableName) { - get - { - return ParamsToRubyDict(EncodingPathParams); - } + var builder = new IndentedStringBuilder(" "); + BuildPathParameters(variableName, builder); + + return builder.ToString(); } - + /// - /// Gets the skip encoding path parameters as a Ruby dictionary string + /// Gets the formatted status code. /// - public virtual string SkipEncodingPathParamsRbDict + /// The status code. + /// Formatted status code. + public string GetStatusCodeReference(HttpStatusCode code) { - get - { - return ParamsToRubyDict(SkipEncodingPathParams); - } + return string.Format("{0}", (int)code); } - + /// - /// Gets the query parameters as a Ruby dictionary string + /// Generate code to replace path parameters in the url template with the appropriate values /// - public virtual string QueryParamsRbDict + /// The variable name for the url to be constructed + /// The string builder for url construction + protected virtual void BuildPathParameters(string variableName, IndentedStringBuilder builder) { - get + if (builder == null) { - return ParamsToRubyDict(EncodingQueryParams); + throw new ArgumentNullException("builder"); } - } - - /// - /// Gets the skip encoding query parameters as a Ruby dictionary string - /// - public virtual string SkipEncodingQueryParamsRbDict - { - get + + IEnumerable pathParameters = LogicalParameters.Where(p => p.Extensions.ContainsKey("hostParameter") && p.Location == ParameterLocation.Path); + + foreach (var pathParameter in pathParameters) { - return ParamsToRubyDict(SkipEncodingQueryParams); + var pathReplaceFormat = "{0} = {0}.gsub('{{{1}}}', {2})"; + var urlPathName = UrlPathNameFromPathPattern(pathParameter.SerializedName); + builder.AppendLine(pathReplaceFormat, variableName, urlPathName, pathParameter.GetFormattedReferenceValue()); } } - - /// - /// Gets the skip encoding path parameters - /// - public virtual IEnumerable SkipEncodingPathParams - { - get { return AllPathParams.Where(p => p.Extensions.ContainsKey(Generator.Extensions.SkipUrlEncodingExtension)); } - } - - /// - /// Gets the path parameters not including the params that skip encoding - /// - public virtual IEnumerable EncodingPathParams - { - get { return AllPathParams.Where(p => !p.Extensions.ContainsKey(Generator.Extensions.SkipUrlEncodingExtension)); } - } - - /// - /// Gets all path parameters - /// - public virtual IEnumerable AllPathParams - { - get { return ParameterTemplateModels.Where(p => p.Location == ParameterLocation.Path); } - } - - /// - /// Gets the skip encoding query parameters - /// - public virtual IEnumerable SkipEncodingQueryParams - { - get { return AllQueryParams.Where(p => p.Extensions.ContainsKey(Generator.Extensions.SkipUrlEncodingExtension)); } - } - - /// - /// Gets the query parameters not including the params that skip encoding - /// - public virtual IEnumerable EncodingQueryParams - { - get { return AllQueryParams.Where(p => !p.Extensions.ContainsKey(Generator.Extensions.SkipUrlEncodingExtension)); } - } - - /// - /// Gets all of the query parameters - /// - public virtual IEnumerable AllQueryParams - { - get { return ParameterTemplateModels.Where(p => p.Location == ParameterLocation.Query); } - } - + /// /// Builds the parameters as a Ruby dictionary string /// @@ -428,36 +495,27 @@ protected string ParamsToRubyDict(IEnumerable parameters foreach (var param in parameters) { string variableName = param.Name; - encodedParameters.Add(string.Format("'{0}' => {1}", param.SerializedName, variableName)); + string urlPathName = UrlPathNameFromPathPattern(param.SerializedName); + encodedParameters.Add(string.Format("'{0}' => {1}", urlPathName, param.GetFormattedReferenceValue())); } - return string.Format(CultureInfo.InvariantCulture, "{{{0}}}", string.Join(",", encodedParameters)); } /// - /// Gets the list of middelwares required for HTTP requests. - /// - public virtual IList FaradayMiddlewares - { - get - { - return new List() - { - "[MsRest::RetryPolicyMiddleware, times: 3, retry: 0.02]", - "[:cookie_jar]" - }; - } - } - - /// - /// Gets the expression for default header setting. + /// Builds the url path parameter from the pattern if exists /// - public virtual string SetDefaultHeaders + /// Name of the path parameter to match. + /// url path parameter as a string + private string UrlPathNameFromPathPattern(string urlPathParamName) { - get + string pat = @".*\{" + urlPathParamName + @"(\:\w+)\}"; + Regex r = new Regex(pat); + Match m = r.Match(Url); + if (m.Success) { - return string.Empty; + urlPathParamName += m.Groups[1].Value; } + return urlPathParamName; } } -} +} \ No newline at end of file diff --git a/AutoRest/Generators/Ruby/Ruby/TemplateModels/ServiceClientTemplateModel.cs b/AutoRest/Generators/Ruby/Ruby/TemplateModels/ServiceClientTemplateModel.cs index d7d3bb2b3cec8..cc0fb64a65cf2 100644 --- a/AutoRest/Generators/Ruby/Ruby/TemplateModels/ServiceClientTemplateModel.cs +++ b/AutoRest/Generators/Ruby/Ruby/TemplateModels/ServiceClientTemplateModel.cs @@ -25,6 +25,7 @@ public ServiceClientTemplateModel(ServiceClient serviceClient) MethodTemplateModels = new List(); Methods.Where(m => m.Group == null) .ForEach(m => MethodTemplateModels.Add(new MethodTemplateModel(m, serviceClient))); + this.IsCustomBaseUri = serviceClient.Extensions.ContainsKey(Microsoft.Rest.Generator.Extensions.ParameterizedHostExtension); } /// @@ -37,6 +38,11 @@ public ServiceClientTemplateModel(ServiceClient serviceClient) /// public List MethodTemplateModels { get; set; } + /// + /// Gets the flag indicating whether url is from x-ms-parameterized-host extension. + /// + public bool IsCustomBaseUri { get; private set; } + /// /// Gets the list of modules/classes which need to be included. /// diff --git a/AutoRest/Generators/Ruby/Ruby/Templates/MethodTemplate.cshtml b/AutoRest/Generators/Ruby/Ruby/Templates/MethodTemplate.cshtml index 6b085d99c9ab8..b8d70fabe5b9a 100644 --- a/AutoRest/Generators/Ruby/Ruby/Templates/MethodTemplate.cshtml +++ b/AutoRest/Generators/Ruby/Ruby/Templates/MethodTemplate.cshtml @@ -101,7 +101,6 @@ def @(Model.Name)_async(@(Model.MethodParameterDeclaration)) @:@(parameter.Type.ValidateType(Model.Scope, parameter.Name)) } } - request_headers = {} @if (Model.Parameters.Any(p => p.Location == ParameterLocation.Header)) { @@ -152,7 +151,12 @@ def @(Model.Name)_async(@(Model.MethodParameterDeclaration)) headers: request_headers.merge(custom_headers || {}) } - request = MsRest::HttpOperationRequest.new(@@base_url || @(Model.ClientReference).base_url, path_template, :@Model.HttpMethod.ToString().ToLower(), options) +@EmptyLine + request_url = @@base_url || @(Model.ClientReference).base_url + @(Model.BuildUrl("request_url")) +@EmptyLine + + request = MsRest::HttpOperationRequest.new(request_url, path_template, :@Model.HttpMethod.ToString().ToLower(), options) promise = request.run_promise do |req| @(Model.ClientReference).credentials.sign_request(req) unless @(Model.ClientReference).credentials.nil? end diff --git a/AutoRest/Generators/Ruby/Ruby/Templates/ServiceClientTemplate.cshtml b/AutoRest/Generators/Ruby/Ruby/Templates/ServiceClientTemplate.cshtml index da18fb0e5a68a..1a049baf23861 100644 --- a/AutoRest/Generators/Ruby/Ruby/Templates/ServiceClientTemplate.cshtml +++ b/AutoRest/Generators/Ruby/Ruby/Templates/ServiceClientTemplate.cshtml @@ -23,7 +23,7 @@ module @Settings.Namespace @EmptyLine # @@return [String] the base URI of the service. - attr_accessor :base_url + @(Model.IsCustomBaseUri ? "attr_reader" : "attr_accessor") :base_url @EmptyLine @foreach (var property in Model.Properties) @@ -43,12 +43,29 @@ module @Settings.Namespace # # Creates initializes a new instance of the @Model.Name class. # @@param credentials [MsRest::ServiceClientCredentials] credentials to authorize HTTP requests made by the service client. - # @@param base_url [String] the base URI of the service. + @if (!Model.IsCustomBaseUri) + { + @:# @@param base_url [String] the base URI of the service. + } # @@param options [Array] filters to be applied to the HTTP requests. # - def initialize(credentials, base_url = nil, options = nil) + @if (!Model.IsCustomBaseUri) + { + @:def initialize(credentials, base_url = nil, options = nil) + } + else + { + @:def initialize(credentials, options = nil) + } super(credentials, options) - @@base_url = base_url || '@Model.BaseUrl' + @if (!Model.IsCustomBaseUri) + { + @:@@base_url = base_url || '@Model.BaseUrl' + } + else + { + @:@@base_url = '@Model.BaseUrl' + } @EmptyLine fail ArgumentError, 'credentials is nil' if credentials.nil? fail ArgumentError, 'invalid type of credentials input parameter' unless credentials.is_a?(MsRest::ServiceClientCredentials) diff --git a/AutoRest/TestServer/server/routes/lros.js b/AutoRest/TestServer/server/routes/lros.js index 9d9dc540e16aa..ca11fa50082be 100644 --- a/AutoRest/TestServer/server/routes/lros.js +++ b/AutoRest/TestServer/server/routes/lros.js @@ -940,6 +940,17 @@ var lros = function (coverage) { res.status(400).end('{ "message" : "Error from the server" }'); }); + /* TODO: only C# has implemented this test. Exclude it from code coverage until it is implemented in other languages */ + coverage['LRONonRetryPut201Creating400InvalidJson'] = 1; + router.put('/nonretryerror/put/201/creating/400/invalidjson', function (req, res, next) { + res.status(201).end('{ "properties": { "provisioningState": "Creating"}, "id": "100", "name": "foo" }'); + }); + + router.get('/nonretryerror/put/201/creating/400/invalidjson', function (req, res, next) { + coverage['LRONonRetryPut201Creating400InvalidJson']++; + res.status(400).end('<{ "message" : "Error from the server" }'); + }); + coverage['LRONonRetryPutAsyncRetry400'] = 0; router.put('/nonretryerror/putasync/retry/400', function (req, res, next) { var pollingUri = 'http://localhost.:' + utils.getPort() + '/lro/nonretryerror/putasync/retry/failed/operationResults/400'; diff --git a/AutoRest/TestServer/swagger/lro.json b/AutoRest/TestServer/swagger/lro.json index b064ce8c3aa2d..9f9bba0c26759 100644 --- a/AutoRest/TestServer/swagger/lro.json +++ b/AutoRest/TestServer/swagger/lro.json @@ -1772,6 +1772,46 @@ } } } + }, + "/lro/nonretryerror/put/201/creating/400/invalidjson": { + "put": { + "x-ms-long-running-operation": true, + "operationId": "LROSADs_putNonRetry201Creating400InvalidJson", + "description": "Long running put request, service returns a Product with 'ProvisioningState' = 'Creating' and 201 response code", + "tags": [ + "LROSAD Operations" + ], + "parameters": [ + { + "name": "product", + "description": "Product to put", + "in": "body", + "schema": { + "$ref": "#/definitions/Product" + } + } + ], + "responses": { + "200": { + "description": "Response after completion, with ProvisioningState='Succeeded'", + "schema": { + "$ref": "#/definitions/Product" + } + }, + "201": { + "description": "Initial response, with ProvisioningState = 'Creating'", + "schema": { + "$ref": "#/definitions/Product" + } + }, + "default": { + "description": "Unexpected error", + "schema": { + "$ref": "#/definitions/CloudError" + } + } + } + } }, "/lro/nonretryerror/putasync/retry/400": { "put": { diff --git a/ClientRuntimes/CSharp/Microsoft.Rest.ClientRuntime.Azure.Tests/LongRunningOperationsTest.cs b/ClientRuntimes/CSharp/Microsoft.Rest.ClientRuntime.Azure.Tests/LongRunningOperationsTest.cs index bf999fe9f7c1b..1d0bb2069f1bf 100644 --- a/ClientRuntimes/CSharp/Microsoft.Rest.ClientRuntime.Azure.Tests/LongRunningOperationsTest.cs +++ b/ClientRuntimes/CSharp/Microsoft.Rest.ClientRuntime.Azure.Tests/LongRunningOperationsTest.cs @@ -104,6 +104,19 @@ public void TestAsyncOperationWithMissingProvisioningState() Assert.Equal("100", resource.Id); } + [Fact] + public void TestAsyncOperationWithNonSuccessStatusAndInvalidResponseContent() + { + var tokenCredentials = new TokenCredentials("123", "abc"); + var handler = new PlaybackTestHandler(MockAsyncOperaionWithNonSuccessStatusAndInvalidResponseContent()); + var fakeClient = new RedisManagementClient(tokenCredentials, handler); + fakeClient.LongRunningOperationInitialTimeout = fakeClient.LongRunningOperationRetryTimeout = 0; + var error = Assert.Throws(() => + fakeClient.RedisOperations.Delete("rg", "redis", "1234")); + Assert.Equal("Long running operation failed with status 'BadRequest'.", error.Message); + Assert.Null(error.Body); + } + [Fact] public void TestPutOperationWithoutProvisioningState() { @@ -737,6 +750,22 @@ private IEnumerable MockAsyncOperaionWithMissingProvisionin yield return response3; } + private IEnumerable MockAsyncOperaionWithNonSuccessStatusAndInvalidResponseContent() + { + var response1 = new HttpResponseMessage(HttpStatusCode.Accepted) + { + Content = new StringContent("") + }; + response1.Headers.Add("Location", "http://custom/status"); + yield return response1; + + var response2 = new HttpResponseMessage(HttpStatusCode.BadRequest) + { + Content = new StringContent("<") + }; + yield return response2; + } + private IEnumerable MockPutOperaionWithoutProvisioningStateInResponse() { var response1 = new HttpResponseMessage(HttpStatusCode.Created) diff --git a/ClientRuntimes/CSharp/Microsoft.Rest.ClientRuntime.Azure.Tests/ODataTests.cs b/ClientRuntimes/CSharp/Microsoft.Rest.ClientRuntime.Azure.Tests/ODataTests.cs index 639023af44855..e267142696404 100644 --- a/ClientRuntimes/CSharp/Microsoft.Rest.ClientRuntime.Azure.Tests/ODataTests.cs +++ b/ClientRuntimes/CSharp/Microsoft.Rest.ClientRuntime.Azure.Tests/ODataTests.cs @@ -7,6 +7,7 @@ using Microsoft.Rest.Azure.OData; using Newtonsoft.Json; using Xunit; +using System.Collections.Generic; namespace Microsoft.Rest.ClientRuntime.Azure.Test { @@ -227,7 +228,6 @@ public void EncodingTheParameters() [Fact] public void ODataQuerySupportsAllParameters() { - var queryString = "foo eq 'bar'"; var query = new ODataQuery(p => p.Foo == "bar") { Expand = "param1", @@ -235,7 +235,7 @@ public void ODataQuerySupportsAllParameters() Skip = 10, Top = 100 }; - Assert.Equal(string.Format("$filter={0}&$orderby=d&$expand=param1&$top=100&$skip=10", Uri.EscapeDataString(queryString)), query.ToString()); + Assert.Equal("$filter=foo eq 'bar'&$orderby=d&$expand=param1&$top=100&$skip=10", query.ToString()); } [Fact] @@ -249,49 +249,86 @@ public void ODataQuerySupportsEmptyState() { Value = null }; + var paramEncoded = new InputParam1 + { + Value = "bar/car" + }; query = new ODataQuery(p => p.Foo == param.Value); Assert.Equal("", query.ToString()); query = new ODataQuery(p => p.Foo == param.Value && p.AssignedTo(param.Value)); Assert.Equal("", query.ToString()); query = new ODataQuery(p => p.AssignedTo(param.Value)); Assert.Equal("", query.ToString()); + query = new ODataQuery(p => p.AssignedTo(paramEncoded.Value)); + Assert.Equal("$filter=assignedTo('bar%2Fcar')", query.ToString()); + } + + [Fact] + public void ODataQuerySupportsCustomDateTimeOffsetFilter() + { + var param = new Param1 + { + SubmitTime = DateTimeOffset.Parse("2016-03-28T08:15:00.0971693+00:00"), + State = "Ended" + + }; + + var filter = new List(); + filter.Add(string.Format("submitTime lt datetimeoffset'{0}'", Uri.EscapeDataString(param.SubmitTime.Value.ToString("O")))); + filter.Add(string.Format("state ne '{0}'", param.State)); + var filterString = string.Join(" and ", filter.ToArray()); + + + var query = new ODataQuery + { + Filter = filterString + }; + Assert.Equal("$filter=submitTime lt datetimeoffset'2016-03-28T08%3A15%3A00.0971693%2B00%3A00' and state ne 'Ended'", query.ToString()); } + [Fact] public void ODataQuerySupportsPartialState() { - var queryString = "foo eq 'bar'"; var query = new ODataQuery(p => p.Foo == "bar") { Top = 100 }; - Assert.Equal(string.Format("$filter={0}&$top=100", Uri.EscapeDataString(queryString)), query.ToString()); + Assert.Equal("$filter=foo eq 'bar'&$top=100", query.ToString()); + } + + [Fact] + public void ODataQuerySupportsPartialStateWithSlashes() + { + var queryString = "$filter=foo eq 'bar%2Fclub'&$top=100"; + var query = new ODataQuery(p => p.Foo == "bar/club") + { + Top = 100 + }; + Assert.Equal(queryString, query.ToString()); } [Fact] public void ODataQuerySupportsImplicitConversionFromFilterString() { - var queryString = "foo eq 'bar'"; - ODataQuery query = queryString; + ODataQuery query = "foo eq 'bar'"; query.Top = 100; - Assert.Equal(string.Format("$filter={0}&$top=100", Uri.EscapeDataString(queryString)), query.ToString()); + Assert.Equal("$filter=foo eq 'bar'&$top=100", query.ToString()); } [Fact] public void ODataQuerySupportsImplicitConversionFromFullFilterString() { - var queryString = "foo eq 'bar'"; - ODataQuery query = string.Format("$filter={0}", queryString); + ODataQuery query = "$filter=foo eq 'bar'"; query.Top = 100; - Assert.Equal(string.Format("$filter={0}&$top=100", Uri.EscapeDataString(queryString)), query.ToString()); + Assert.Equal("$filter=foo eq 'bar'&$top=100", query.ToString()); } [Fact] public void ODataQuerySupportsImplicitConversionFromQueryString() { - var queryString = "foo eq 'bar'"; - ODataQuery query = string.Format("$filter={0}&$top=100", queryString); - Assert.Equal(string.Format("$filter={0}&$top=100", Uri.EscapeDataString(queryString)), query.ToString()); + ODataQuery query = "$filter=foo eq 'bar'&$top=100"; + Assert.Equal("$filter=foo eq 'bar'&$top=100", query.ToString()); } [Fact] @@ -323,7 +360,7 @@ public void ODataQuerySupportsMethod() var filterString = FilterString.Generate(parameters => parameters.AtScope() && parameters.AssignedTo(param.Value)); - Assert.Equal(filterString, "atScope() and assignedTo('Microsoft.Web%2Fsites')"); + Assert.Equal("atScope() and assignedTo('Microsoft.Web%2Fsites')", filterString); } } @@ -361,6 +398,10 @@ public class Param1 [JsonProperty("d")] public DateTime Date { get; set; } public DateTime Date2 { get; set; } + [JsonProperty("submitTime")] + public DateTimeOffset? SubmitTime { get; set; } + [JsonProperty("state")] + public string State { get; set; } [JsonProperty("vals")] public string[] Values { get; set; } [JsonProperty("param2")] diff --git a/ClientRuntimes/CSharp/Microsoft.Rest.ClientRuntime.Azure/AzureClientExtensions.cs b/ClientRuntimes/CSharp/Microsoft.Rest.ClientRuntime.Azure/AzureClientExtensions.cs index 9a38463a88e08..422f074bd3028 100644 --- a/ClientRuntimes/CSharp/Microsoft.Rest.ClientRuntime.Azure/AzureClientExtensions.cs +++ b/ClientRuntimes/CSharp/Microsoft.Rest.ClientRuntime.Azure/AzureClientExtensions.cs @@ -631,7 +631,16 @@ public static class AzureClientExtensions statusCode != HttpStatusCode.Created && statusCode != HttpStatusCode.NoContent) { - CloudError errorBody = SafeJsonConvert.DeserializeObject(responseContent, client.DeserializationSettings); + CloudError errorBody = null; + try + { + errorBody = SafeJsonConvert.DeserializeObject(responseContent, client.DeserializationSettings); + } + catch (JsonException) + { + // failed to deserialize, return empty body + } + throw new CloudException(string.Format(CultureInfo.InvariantCulture, Resources.LongRunningOperationFailed, statusCode)) { diff --git a/ClientRuntimes/CSharp/Microsoft.Rest.ClientRuntime.Azure/OData/ODataQuery.cs b/ClientRuntimes/CSharp/Microsoft.Rest.ClientRuntime.Azure/OData/ODataQuery.cs index 99fed407ca114..252c7739db668 100644 --- a/ClientRuntimes/CSharp/Microsoft.Rest.ClientRuntime.Azure/OData/ODataQuery.cs +++ b/ClientRuntimes/CSharp/Microsoft.Rest.ClientRuntime.Azure/OData/ODataQuery.cs @@ -146,17 +146,17 @@ public override string ToString() if (!string.IsNullOrEmpty(Filter)) { queryStringList.Add(string.Format(CultureInfo.InvariantCulture, - "$filter={0}", Uri.EscapeDataString(Filter))); + "$filter={0}", Filter)); } if (!string.IsNullOrEmpty(OrderBy)) { queryStringList.Add(string.Format(CultureInfo.InvariantCulture, - "$orderby={0}", Uri.EscapeDataString(OrderBy))); + "$orderby={0}", OrderBy)); } if (!string.IsNullOrEmpty(Expand)) { queryStringList.Add(string.Format(CultureInfo.InvariantCulture, - "$expand={0}", Uri.EscapeDataString(Expand))); + "$expand={0}", Expand)); } if (Top != null) { diff --git a/ClientRuntimes/CSharp/Microsoft.Rest.ClientRuntime/ServiceClient.cs b/ClientRuntimes/CSharp/Microsoft.Rest.ClientRuntime/ServiceClient.cs index e80afc887e0f8..6763f4e6641fa 100644 --- a/ClientRuntimes/CSharp/Microsoft.Rest.ClientRuntime/ServiceClient.cs +++ b/ClientRuntimes/CSharp/Microsoft.Rest.ClientRuntime/ServiceClient.cs @@ -208,25 +208,53 @@ protected void InitializeHttpClient(HttpClientHandler httpClientHandler, params HttpClient = newClient; Type type = this.GetType(); HttpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue(type.FullName, - GetAssemblyVersion())); + GetClientVersion())); } /// - /// Get the assembly version of a service client. + /// Gets the AssemblyInformationalVersion if available + /// if not it gets the AssemblyFileVerion + /// if neither are available it will default to the Assembly Version of a service client. /// - /// The assembly version of the client. - private string GetAssemblyVersion() + /// The version of the client. + private string GetClientVersion() { + + string version = String.Empty; Type type = this.GetType(); - string version = - type - .GetTypeInfo() - .Assembly - .FullName - .Split(',') - .Select(c => c.Trim()) - .First(c => c.StartsWith("Version=", StringComparison.OrdinalIgnoreCase)) - .Substring("Version=".Length); + Assembly assembly = type.GetTypeInfo().Assembly; + + try + { + // try to get AssemblyInformationalVersion first + AssemblyInformationalVersionAttribute aivAttribute = + assembly.GetCustomAttribute(typeof(AssemblyInformationalVersionAttribute)) as AssemblyInformationalVersionAttribute; + version = aivAttribute?.InformationalVersion; + + // if not available try to get AssemblyFileVersion + if (String.IsNullOrEmpty(version)) + { + AssemblyFileVersionAttribute fvAttribute = + assembly.GetCustomAttribute(typeof(AssemblyFileVersionAttribute)) as AssemblyFileVersionAttribute; + version = fvAttribute?.Version; + } + } + catch (AmbiguousMatchException) + { + // in case there are more then one attribute of the type + } + + // no usable version attribute found so default to Assembly Version + if (String.IsNullOrEmpty(version)) + { + version = + assembly + .FullName + .Split(',') + .Select(c => c.Trim()) + .First(c => c.StartsWith("Version=", StringComparison.OrdinalIgnoreCase)) + .Substring("Version=".Length); + } return version; } } diff --git a/ClientRuntimes/NodeJS/ms-rest-azure/lib/azureEnvironment.js b/ClientRuntimes/NodeJS/ms-rest-azure/lib/azureEnvironment.js index 9aa5e6fb2a48d..e902c471c5d30 100644 --- a/ClientRuntimes/NodeJS/ms-rest-azure/lib/azureEnvironment.js +++ b/ClientRuntimes/NodeJS/ms-rest-azure/lib/azureEnvironment.js @@ -2,48 +2,158 @@ // Licensed under the MIT License. See License.txt in the project root for license information. 'use strict'; - -var _ = require('underscore'); - +var util = require('util'); /** * @class * Initializes a new instance of the AzureEnvironment class. * @constructor - * @param {string} authenticationEndpoint - ActiveDirectory Endpoint for the Azure Environment. - * @param {string} tokenAudience - Token audience for an endpoint. - * @param {bool} [validateAuthority] - Determines whether the authentication endpoint should + * @param {string} parameters.name - The Environment name + * @param {string} parameters.portalUrl - the management portal URL + * @param {string} parameters.managementEndpointUrl - the management service endpoint + * @param {string} parameters.resourceManagerEndpointUrl - the resource management endpoint + * @param {string} parameters.activeDirectoryEndpointUrl - the Active Directory login endpoint + * @param {string} parameters.activeDirectoryResourceId - The resource ID to obtain AD tokens for + * @param {string} [parameters.publishingProfileUrl] - the publish settings file URL + * @param {string} [parameters.sqlManagementEndpointUrl] - the sql server management endpoint for mobile commands + * @param {string} [parameters.sqlServerHostnameSuffix] - the dns suffix for sql servers + * @param {string} [parameters.galleryEndpointUrl] - the template gallery endpoint + * @param {string} [parameters.activeDirectoryGraphResourceId] - the Active Directory resource ID + * @param {string} [parameters.activeDirectoryGraphApiVersion] - the Active Directory api version + * @param {string} [parameters.storageEndpointSuffix] - the endpoint suffix for storage accounts + * @param {string} [parameters.keyVaultDnsSuffix] - the keyvault service dns suffix + * @param {string} [parameters.azureDataLakeStoreFileSystemEndpointSuffix] - the data lake store filesystem service dns suffix + * @param {string} [parameters.azureDataLakeAnalyticsCatalogAndJobEndpointSuffix] - the data lake analytics job and catalog service dns suffix + * @param {bool} [parameters.validateAuthority] - Determines whether the authentication endpoint should * be validated with Azure AD. Default value is true. */ -function AzureEnvironment(authenticationEndpoint, tokenAudience, validateAuthority) { - this.authenticationEndpoint = authenticationEndpoint; - this.tokenAudience = tokenAudience; - this.validateAuthority = validateAuthority; -} +function AzureEnvironment(parameters) { + //Set defaults. + this.validateAuthority = true; -/** - * Provides the settings for authentication with Azure - */ -var Azure = new AzureEnvironment('https://login.microsoftonline.com/', - 'https://management.core.windows.net/', - true); + if (parameters) { + //Validate required parameters + var requiredParams = [ 'name', 'portalUrl', 'managementEndpointUrl', 'resourceManagerEndpointUrl', + 'activeDirectoryEndpointUrl', 'activeDirectoryResourceId']; + requiredParams.forEach(function (param) { + if (!parameters[param] || typeof parameters[param].valueOf() !== 'string') { + throw new Error(util.format('Please provide "%s" for the environment and it must be of type "string".', param)); + } + }); + //Assign provided parameters + for (var prop in parameters) { + this[prop] = parameters[prop]; + } + } +} +var supportedEnvironments = { + Azure: { + name: 'Azure', + portalUrl: 'http://go.microsoft.com/fwlink/?LinkId=254433', + publishingProfileUrl: 'http://go.microsoft.com/fwlink/?LinkId=254432', + managementEndpointUrl: 'https://management.core.windows.net', + resourceManagerEndpointUrl: 'https://management.azure.com/', + sqlManagementEndpointUrl: 'https://management.core.windows.net:8443/', + sqlServerHostnameSuffix: '.database.windows.net', + galleryEndpointUrl: 'https://gallery.azure.com/', + activeDirectoryEndpointUrl: 'https://login.microsoftonline.com', + activeDirectoryResourceId: 'https://management.core.windows.net/', + activeDirectoryGraphResourceId: 'https://graph.windows.net/', + activeDirectoryGraphApiVersion: '2013-04-05', + storageEndpointSuffix: '.core.windows.net', + keyVaultDnsSuffix: '.vault.azure.net', + azureDataLakeStoreFileSystemEndpointSuffix: 'azuredatalakestore.net', + azureDataLakeAnalyticsCatalogAndJobEndpointSuffix: 'azuredatalakeanalytics.net' + }, + AzureChina: { + name: 'AzureChina', + portalUrl: 'http://go.microsoft.com/fwlink/?LinkId=301902', + publishingProfileUrl: 'http://go.microsoft.com/fwlink/?LinkID=301774', + managementEndpointUrl: 'https://management.core.chinacloudapi.cn', + resourceManagerEndpointUrl: 'https://management.chinacloudapi.cn', + sqlManagementEndpointUrl: 'https://management.core.chinacloudapi.cn:8443/', + sqlServerHostnameSuffix: '.database.chinacloudapi.cn', + galleryEndpointUrl: 'https://gallery.chinacloudapi.cn/', + activeDirectoryEndpointUrl: 'https://login.chinacloudapi.cn', + activeDirectoryResourceId: 'https://management.core.chinacloudapi.cn/', + activeDirectoryGraphResourceId: 'https://graph.chinacloudapi.cn/', + activeDirectoryGraphApiVersion: '2013-04-05', + storageEndpointSuffix: '.core.chinacloudapi.cn', + keyVaultDnsSuffix: '.vault.azure.cn', + // TODO: add dns suffixes for the china cloud for datalake store and datalake analytics once they are defined. + azureDataLakeStoreFileSystemEndpointSuffix: 'N/A', + azureDataLakeAnalyticsCatalogAndJobEndpointSuffix: 'N/A' + }, + AzureUSGovernment: { + name: 'AzureUSGovernment', + portalUrl: 'https://manage.windowsazure.us', + publishingProfileUrl: 'https://manage.windowsazure.us/publishsettings/index', + managementEndpointUrl: 'https://management.core.usgovcloudapi.net', + resourceManagerEndpointUrl: 'https://management.usgovcloudapi.net', + sqlManagementEndpointUrl: 'https://management.core.usgovcloudapi.net:8443/', + sqlServerHostnameSuffix: '.database.usgovcloudapi.net', + galleryEndpointUrl: 'https://gallery.usgovcloudapi.net/', + activeDirectoryEndpointUrl: 'https://login.microsoftonline.com', + activeDirectoryResourceId: 'https://management.core.usgovcloudapi.net/', + activeDirectoryGraphResourceId: 'https://graph.windows.net/', + activeDirectoryGraphApiVersion: '2013-04-05', + storageEndpointSuffix: '.core.usgovcloudapi.net', + keyVaultDnsSuffix: '.vault.usgovcloudapi.net', + // TODO: add dns suffixes for the US government for datalake store and datalake analytics once they are defined. + azureDataLakeStoreFileSystemEndpointSuffix: 'N/A', + azureDataLakeAnalyticsCatalogAndJobEndpointSuffix: 'N/A' + }, + AzureGermanCloud: { + name: 'AzureGermanCloud', + portalUrl: 'http://portal.microsoftazure.de/', + publishingProfileUrl: 'https://manage.microsoftazure.de/publishsettings/index', + managementEndpointUrl: 'https://management.core.cloudapi.de', + resourceManagerEndpointUrl: 'https://management.microsoftazure.de', + sqlManagementEndpointUrl: 'https://management.core.cloudapi.de:8443/', + sqlServerHostnameSuffix: '.database.cloudapi.de', + galleryEndpointUrl: 'https://gallery.cloudapi.de/', + activeDirectoryEndpointUrl: 'https://login.microsoftonline.de', + activeDirectoryResourceId: 'https://management.core.cloudapi.de/', + activeDirectoryGraphResourceId: 'https://graph.cloudapi.de/', + activeDirectoryGraphApiVersion: '2013-04-05', + storageEndpointSuffix: '.core.cloudapi.de', + keyVaultDnsSuffix: '.vault.microsoftazure.de', + // TODO: add dns suffixes for the US government for datalake store and datalake analytics once they are defined. + azureDataLakeStoreFileSystemEndpointSuffix: 'N/A', + azureDataLakeAnalyticsCatalogAndJobEndpointSuffix: 'N/A' + } +}; /** - * Provides the settings for authentication with Azure China + * Adds a new instance of the AzureEnvironment to the prototype. + * @param {string} parameters.name - The Environment name + * @param {string} parameters.portalUrl - the management portal URL + * @param {string} parameters.managementEndpointUrl - the management service endpoint + * @param {string} parameters.resourceManagerEndpointUrl - the resource management endpoint + * @param {string} parameters.activeDirectoryEndpointUrl - the Active Directory login endpoint + * @param {string} parameters.activeDirectoryResourceId - The resource ID to obtain AD tokens for + * @param {string} [parameters.publishingProfileUrl] - the publish settings file URL + * @param {string} [parameters.sqlManagementEndpointUrl] - the sql server management endpoint for mobile commands + * @param {string} [parameters.sqlServerHostnameSuffix] - the dns suffix for sql servers + * @param {string} [parameters.galleryEndpointUrl] - the template gallery endpoint + * @param {string} [parameters.activeDirectoryGraphResourceId] - the Active Directory resource ID + * @param {string} [parameters.activeDirectoryGraphApiVersion] - the Active Directory api version + * @param {string} [parameters.storageEndpointSuffix] - the endpoint suffix for storage accounts + * @param {string} [parameters.keyVaultDnsSuffix] - the keyvault service dns suffix + * @param {string} [parameters.azureDataLakeStoreFileSystemEndpointSuffix] - the data lake store filesystem service dns suffix + * @param {string} [parameters.azureDataLakeAnalyticsCatalogAndJobEndpointSuffix] - the data lake analytics job and catalog service dns suffix + * @param {bool} [parameters.validateAuthority] - Determines whether the authentication endpoint should + * be validated with Azure AD. Default value is true. + * @return {AzureEnvironment} - Reference to the newly added Environment */ -var AzureChina = new AzureEnvironment('https://login.chinacloudapi.cn/', - 'https://management.core.chinacloudapi.cn/', - true); +AzureEnvironment.prototype.add = function(parameters) { + var _environment = new AzureEnvironment(parameters); + AzureEnvironment.prototype[_environment.name] = _environment; + return _environment; +}; -/** - * Provides the settings for authentication with Azure US Government - */ -var AzureUSGovernment = new AzureEnvironment('https://login.microsoftonline.com/', - 'https://management.core.usgovcloudapi.net/', - true); +//Adding the supported environments +for(var key in supportedEnvironments) { + AzureEnvironment.prototype.add(supportedEnvironments[key]); +} -_.extend(module.exports, { - Azure: Azure, - AzureChina: AzureChina, - AzureEnvironment: AzureEnvironment, - AzureUSGovernment: AzureUSGovernment -}); +module.exports = new AzureEnvironment(); \ No newline at end of file diff --git a/ClientRuntimes/NodeJS/ms-rest-azure/lib/azureServiceClient.js b/ClientRuntimes/NodeJS/ms-rest-azure/lib/azureServiceClient.js index ae1798dc5e56a..ca4413b85a00b 100644 --- a/ClientRuntimes/NodeJS/ms-rest-azure/lib/azureServiceClient.js +++ b/ClientRuntimes/NodeJS/ms-rest-azure/lib/azureServiceClient.js @@ -57,92 +57,32 @@ function AzureServiceClient(credentials, options) { util.inherits(AzureServiceClient, msRest.ServiceClient); /** - * Poll Azure long running PUT operation. + * Poll Azure long running PUT or PATCH operation. (Deprecated, new version of the code-gen will generate code to call getLongRunningOperationResult) * @param {object} [resultOfInitialRequest] - Response of the initial request for the long running operation. * @param {object} [options] * @param {object} [options.customHeaders] headers that will be added to request */ AzureServiceClient.prototype.getPutOrPatchOperationResult = function (resultOfInitialRequest, options, callback) { - var self = this; - - if(!callback && typeof options === 'function') { - callback = options; - options = null; - } - if (!callback) { - throw new Error('Missing callback'); - } - - if (!resultOfInitialRequest) { - return callback(new Error('Missing resultOfInitialRequest parameter')); - } - - if (resultOfInitialRequest.response.statusCode !== 200 && - resultOfInitialRequest.response.statusCode !== 201 && - resultOfInitialRequest.response.statusCode !== 202) { - return callback(new Error(util.format('Unexpected polling status code from long running operation \'%s\'', - resultOfInitialRequest.response.statusCode))); - } - var pollingState = null; - try { - pollingState = new PollingState(resultOfInitialRequest, this.longRunningOperationRetryTimeout); - } catch (error) { - callback(error); - } - - var resourceUrl = resultOfInitialRequest.request.url; - this._options = options; - - async.whilst( - //while condition - function () { - var finished = [LroStates.Succeeded, LroStates.Failed, LroStates.Canceled].some(function (e) { - return pollingState.status === e; - }); - return !finished; - }, - //while loop body - function (callback) { - setTimeout(function () { - if (pollingState.azureAsyncOperationHeaderLink) { - self._updateStateFromAzureAsyncOperationHeader(pollingState, false, function (err) { - return callback(err); - }); - } else if (pollingState.locationHeaderLink) { - self._updateStateFromLocationHeaderOnPut(pollingState, function (err) { - return callback(err); - }); - } else { - self._updateStateFromGetResourceOperation(resourceUrl, pollingState, function (err) { - return callback(err); - }); - } - }, pollingState.getTimeout()); - }, - //when done - function (err) { - if (pollingState.status === LroStates.Succeeded) { - if (!pollingState.resource) { - self._updateStateFromGetResourceOperation(resourceUrl, pollingState, function (err) { - return callback(err, pollingState.getOperationResponse()); - }); - } else { - return callback(null, pollingState.getOperationResponse()); - } - } else { - return callback(pollingState.getCloudError(err)); - } - }); + return this.getLongRunningOperationResult(resultOfInitialRequest, options, callback); }; - /** - * Poll Azure long running POST or DELETE operations. + * Poll Azure long running POST or DELETE operations. (Deprecated, new version of the code-gen will generate code to call getLongRunningOperationResult) * @param {object} [resultOfInitialRequest] - result of the initial request. * @param {object} [options] * @param {object} [options.customHeaders] headers that will be added to request */ AzureServiceClient.prototype.getPostOrDeleteOperationResult = function (resultOfInitialRequest, options, callback) { + return this.getLongRunningOperationResult(resultOfInitialRequest, options, callback); +}; + +/** + * Poll Azure long running PUT, PATCH, POST or DELETE operations. + * @param {object} [resultOfInitialRequest] - result of the initial request. + * @param {object} [options] + * @param {object} [options.customHeaders] headers that will be added to request + */ +AzureServiceClient.prototype.getLongRunningOperationResult = function (resultOfInitialRequest, options, callback) { var self = this; if (!callback && typeof options === 'function') { @@ -152,7 +92,7 @@ AzureServiceClient.prototype.getPostOrDeleteOperationResult = function (resultOf if (!callback) { throw new Error('Missing callback'); } - + if (!resultOfInitialRequest) { return callback(new Error('Missing resultOfInitialRequest parameter')); } @@ -161,36 +101,51 @@ AzureServiceClient.prototype.getPostOrDeleteOperationResult = function (resultOf return callback(new Error('Missing resultOfInitialRequest.response')); } - if (resultOfInitialRequest.response.statusCode !== 200 && - resultOfInitialRequest.response.statusCode !== 202 && - resultOfInitialRequest.response.statusCode !== 204) { - return callback(new Error(util.format('Unexpected polling status code from long running operation \'%s\'', - resultOfInitialRequest.response.statusCode))); + if (!resultOfInitialRequest.request) { + return callback(new Error('Missing resultOfInitialRequest.request')); + } + + if (!resultOfInitialRequest.request.method) { + return callback(new Error('Missing resultOfInitialRequest.request.method')); + } + + var initialRequestMethod = resultOfInitialRequest.request.method; + + if (this._checkResponseStatusCodeFailed(resultOfInitialRequest)) { + return callback(new Error(util.format('Unexpected polling status code from long running operation \'%s\' for method \'%s\'', + resultOfInitialRequest.response.statusCode, + initialRequestMethod))); } var pollingState = null; + try { pollingState = new PollingState(resultOfInitialRequest, this.longRunningOperationRetryTimeout); } catch (error) { callback(error); } + var resourceUrl = resultOfInitialRequest.request.url; this._options = options; async.whilst( - function () { - var finished = [LroStates.Succeeded, LroStates.Failed, LroStates.Canceled].some(function (e) { + function() { + var finished = [LroStates.Succeeded, LroStates.Failed, LroStates.Canceled].some(function(e) { return e === pollingState.status; }); return !finished; }, function (callback) { - setTimeout(function () { + setTimeout(function() { if (pollingState.azureAsyncOperationHeaderLink) { - self._updateStateFromAzureAsyncOperationHeader(pollingState, true, function (err) { + self._updateStateFromAzureAsyncOperationHeader(pollingState, true, function(err) { return callback(err); }); } else if (pollingState.locationHeaderLink) { - self._updateStateFromLocationHeaderOnPostOrDelete(pollingState, function (err) { + self._updateStateFromLocationHeader(initialRequestMethod, pollingState, function(err) { + return callback(err); + }); + } else if (initialRequestMethod === 'PUT') { + self._updateStateFromGetResourceOperation(resourceUrl, pollingState, function(err) { return callback(err); }); } else { @@ -198,15 +153,36 @@ AzureServiceClient.prototype.getPostOrDeleteOperationResult = function (resultOf } }, pollingState.getTimeout()); }, + //when done function (err) { - if (pollingState.status === LroStates.Succeeded ) { - return callback(null, pollingState.getOperationResponse()); + if (pollingState.status === LroStates.Succeeded) { + if ((pollingState.azureAsyncOperationHeaderLink || !pollingState.resource) && + (initialRequestMethod === 'PUT' || initialRequestMethod === 'PATCH')) { + self._updateStateFromGetResourceOperation(resourceUrl, pollingState, function(err) { + return callback(err, pollingState.getOperationResponse()); + }); + } else { + return callback(null, pollingState.getOperationResponse()); + } } else { return callback(pollingState.getCloudError(err)); } }); }; +AzureServiceClient.prototype._checkResponseStatusCodeFailed = function (initialRequest) { + var statusCode = initialRequest.response.statusCode; + var method = initialRequest.request.method; + if (statusCode === 200 || statusCode === 202 || + (statusCode === 201 && method === 'PUT') || + (statusCode === 204 && (method === 'DELETE' || method === 'POST'))) { + return false; + } else { + return true; + } +}; + + /** * Retrieve operation status by polling from 'azure-asyncoperation' header. * @param {object} [pollingState] - The object to persist current operation state. @@ -236,8 +212,8 @@ AzureServiceClient.prototype._updateStateFromAzureAsyncOperationHeader = functio * Retrieve PUT operation status by polling from 'location' header. * @param {object} [pollingState] - The object to persist current operation state. */ -AzureServiceClient.prototype._updateStateFromLocationHeaderOnPut = function (pollingState, callback) { - this._getStatus(pollingState.locationHeaderLink, function (err, result) { +AzureServiceClient.prototype._updateStateFromLocationHeader = function (method, pollingState, callback) { + this._getStatus(pollingState.locationHeaderLink, function(err, result) { if (err) return callback(err); pollingState.updateResponse(result.response); @@ -246,54 +222,20 @@ AzureServiceClient.prototype._updateStateFromLocationHeaderOnPut = function (pol var statusCode = result.response.statusCode; if (statusCode === 202) { pollingState.status = LroStates.InProgress; - } - else if (statusCode === 200 || - statusCode === 201) { - - if (!result.body) { - return callback(new Error('The response from long running operation does not contain a body.')); - } - - // In 202 pattern on PUT ProvisioningState may not be present in - // the response. In that case the assumption is the status is Succeeded. - if (result.body.properties && result.body.properties.provisioningState) { - pollingState.status = result.body.properties.provisioningState; - } - else { - pollingState.status = LroStates.Succeeded; - } - + } else if (statusCode === 200 || + (statusCode === 201 && method === 'PUT') || + (statusCode === 204 && (method === 'DELETE' || method === 'POST'))) { + + pollingState.status = LroStates.Succeeded; + pollingState.error = { code: pollingState.Status, message: util.format('Long running operation failed with status \'%s\'.', pollingState.status) }; pollingState.resource = result.body; - } - callback(null); - }); -}; - -/** - * Retrieve POST or DELETE operation status by polling from 'location' header. - * @param {object} [pollingState] - The object to persist current operation state. - */ -AzureServiceClient.prototype._updateStateFromLocationHeaderOnPostOrDelete = function (pollingState, callback) { - this._getStatus(pollingState.locationHeaderLink, function (err, result) { - if (err) return callback(err); - - pollingState.updateResponse(result.response); - pollingState.request = result.request; - - var statusCode = result.response.statusCode; - if (statusCode === 202) { - pollingState.status = LroStates.InProgress; - } - else if (statusCode === 200 || - statusCode === 201 || - statusCode === 204) { - pollingState.status = LroStates.Succeeded; - pollingState.resource = result.body; - } + } else { + return callback(new Error('The response from long running operation does not have a valid status code.')); + } callback(null); }); }; diff --git a/ClientRuntimes/NodeJS/ms-rest-azure/lib/credentials/applicationTokenCredentials.js b/ClientRuntimes/NodeJS/ms-rest-azure/lib/credentials/applicationTokenCredentials.js index 0c4fe85033edf..e096edbff2049 100644 --- a/ClientRuntimes/NodeJS/ms-rest-azure/lib/credentials/applicationTokenCredentials.js +++ b/ClientRuntimes/NodeJS/ms-rest-azure/lib/credentials/applicationTokenCredentials.js @@ -65,10 +65,10 @@ function ApplicationTokenCredentials(clientId, domain, secret, options) { */ ApplicationTokenCredentials.prototype.signRequest = function (webResource, callback) { var self = this; - var authorityUrl = self.environment.authenticationEndpoint + self.domain; + var authorityUrl = self.environment.activeDirectoryEndpointUrl + self.domain; var context = new adal.AuthenticationContext(authorityUrl, self.environment.validateAuthority, self.tokenCache); - context.acquireTokenWithClientCredentials(self.environment.tokenAudience, self.clientId, self.secret, function (err, result) { + context.acquireTokenWithClientCredentials(self.environment.activeDirectoryResourceId, self.clientId, self.secret, function (err, result) { if (err) { return callback(new Error('Failed to acquire token for application. \n' + err)); } diff --git a/ClientRuntimes/NodeJS/ms-rest-azure/lib/credentials/userTokenCredentials.js b/ClientRuntimes/NodeJS/ms-rest-azure/lib/credentials/userTokenCredentials.js index ea25138765cd9..7b4f02cf720bf 100644 --- a/ClientRuntimes/NodeJS/ms-rest-azure/lib/credentials/userTokenCredentials.js +++ b/ClientRuntimes/NodeJS/ms-rest-azure/lib/credentials/userTokenCredentials.js @@ -78,10 +78,10 @@ function UserTokenCredentials(clientId, domain, username, password, clientRedire */ UserTokenCredentials.prototype.signRequest = function (webResource, callback) { var self = this; - var authorityUrl = self.environment.authenticationEndpoint + self.domain; + var authorityUrl = self.environment.activeDirectoryEndpointUrl + self.domain; var context = new adal.AuthenticationContext(authorityUrl, self.environment.validateAuthority, self.tokenCache); - context.acquireTokenWithUsernamePassword(self.environment.tokenAudience, self.username, self.password, self.clientId, function (err, result) { + context.acquireTokenWithUsernamePassword(self.environment.activeDirectoryResourceId, self.username, self.password, self.clientId, function (err, result) { if (err) { return callback(new Error('Failed to acquire token. \n' + err)); } diff --git a/ClientRuntimes/NodeJS/ms-rest-azure/lib/index.d.ts b/ClientRuntimes/NodeJS/ms-rest-azure/lib/index.d.ts index 818d584985ec7..ef4378cff4e40 100644 --- a/ClientRuntimes/NodeJS/ms-rest-azure/lib/index.d.ts +++ b/ClientRuntimes/NodeJS/ms-rest-azure/lib/index.d.ts @@ -1,22 +1,22 @@ import * as msRest from 'ms-rest'; export interface AzureServiceClientOptions extends msRest.ServiceClientOptions { - // TODO: Make this property have right type - // * @param {Array} [options.longRunningOperationRetryTimeout] - Retry timeout - longRunningOperationRetryTimeout?: any; + // TODO: Make this property have right type + // * @param {Array} [options.longRunningOperationRetryTimeout] - Retry timeout + longRunningOperationRetryTimeout?: any; } export class AzureServiceClient extends msRest.ServiceClient { - /** - * @class - * Initializes a new instance of the AzureServiceClient class. - * @constructor - * @param {ServiceClientCredentials} credentials - ApplicationTokenCredentials or - * UserTokenCredentials object used for authentication. - * - * @param {object} options - The parameter options used by ServiceClient - * - * @param {string} [options.acceptLanguage] - Gets or sets the preferred language for the response. + /** + * @class + * Initializes a new instance of the AzureServiceClient class. + * @constructor + * @param {ServiceClientCredentials} credentials - ApplicationTokenCredentials or + * UserTokenCredentials object used for authentication. + * + * @param {object} options - The parameter options used by ServiceClient + * + * @param {string} [options.acceptLanguage] - Gets or sets the preferred language for the response. * Default value is: 'en-US'. * * @param {boolean} [options.generateClientRequestId] - When set to true a unique x-ms-client-request-id value @@ -24,81 +24,165 @@ export class AzureServiceClient extends msRest.ServiceClient { * * @param {number} [options.longRunningOperationRetryTimeout] - Gets or sets the retry timeout in seconds for * Long Running Operations. Default value is 30. - */ - constructor(credentials: msRest.ServiceClientCredentials, options: AzureServiceClientOptions) + */ + constructor(credentials: msRest.ServiceClientCredentials, options: AzureServiceClientOptions) } export class AzureEnvironment { - /** - * Initializes a new instance of the AzureEnvironment class. - * @param {string} authenticationEndpoint - ActiveDirectory Endpoint for the Azure Environment. - * @param {string} tokenAudience - Token audience for an endpoint. - * @param {bool} [validateAuthority] - Determines whether the authentication endpoint should - * be validated with Azure AD. Default value is true. - */ - constructor(authenticationEndpoint: string, tokenAudience: string, validateAuthority: boolean); - - /** - * ActiveDirectory Endpoint for the Azure Environment - */ - authenticationEndpoint: string; - - /** - * Token audience for an endpoint. - */ - tokenAudience: string; - - /** - * Determines whether the authentication endpoint should be validated with Azure AD. Default value is true. - */ - validateAuthority: boolean; + /** + * Initializes a new instance of the AzureEnvironment class. + * @param {string} parameters.name - The Environment name + * @param {string} parameters.portalUrl - The management portal URL + * @param {string} parameters.managementEndpointUrl - The management service endpoint + * @param {string} parameters.resourceManagerEndpointUrl - The resource management endpoint + * @param {string} parameters.activeDirectoryEndpointUrl - The Active Directory login endpoint + * @param {string} parameters.activeDirectoryResourceId - The resource ID to obtain AD tokens for (token audience) + * @param {string} [parameters.publishingProfileUrl] - The publish settings file URL + * @param {string} [parameters.sqlManagementEndpointUrl] - The sql server management endpoint for mobile commands + * @param {string} [parameters.sqlServerHostnameSuffix] - The dns suffix for sql servers + * @param {string} [parameters.galleryEndpointUrl] - The template gallery endpoint + * @param {string} [parameters.activeDirectoryGraphResourceId] - The Active Directory resource ID + * @param {string} [parameters.activeDirectoryGraphApiVersion] - The Active Directory api version + * @param {string} [parameters.storageEndpointSuffix] - The endpoint suffix for storage accounts + * @param {string} [parameters.keyVaultDnsSuffix] - The keyvault service dns suffix + * @param {string} [parameters.azureDataLakeStoreFileSystemEndpointSuffix] - The data lake store filesystem service dns suffix + * @param {string} [parameters.azureDataLakeAnalyticsCatalogAndJobEndpointSuffix] - The data lake analytics job and catalog service dns suffix + * @param {bool} [parameters.validateAuthority] - Determines whether the authentication endpoint should + * be validated with Azure AD. Default value is true. + */ + constructor(parameters: any); + + /** + * The Environment name. + */ + name: string; + + /** + * The management portal URL. + */ + portalUrl: string; + + /** + * The management service endpoint. + */ + managementEndpointUrl: string; + + /** + * The resource management endpoint. + */ + resourceManagerEndpointUrl: string; + + /** + * The Active Directory login endpoint. + */ + activeDirectoryEndpointUrl: string; + + /** + * The resource ID to obtain AD tokens for (token audience). + */ + activeDirectoryResourceId: string; + + /** + * The publish settings file URL. + */ + publishingProfileUrl: string; + + /** + * The sql server management endpoint for mobile commands. + */ + sqlManagementEndpointUrl: string; + + /** + * The dns suffix for sql servers. + */ + sqlServerHostnameSuffix: string; + + /** + * The template gallery endpoint. + */ + galleryEndpointUrl: string; + + /** + * The Active Directory resource ID. + */ + activeDirectoryGraphResourceId: string; + + /** + * The Active Directory api version. + */ + activeDirectoryGraphApiVersion: string; + + /** + * The endpoint suffix for storage accounts. + */ + storageEndpointSuffix: string; + + /** + * The keyvault service dns suffix. + */ + keyVaultDnsSuffix: string; + + /** + * The data lake store filesystem service dns suffix. + */ + azureDataLakeStoreFileSystemEndpointSuffix: string; + + /** + * The data lake analytics job and catalog service dns suffix. + */ + azureDataLakeAnalyticsCatalogAndJobEndpointSuffix: string; + + /** + * Determines whether the authentication endpoint should be validated with Azure AD. Default value is true. + */ + validateAuthority: boolean; } export interface AzureTokenCredentialsOptions { - /** - * The Azure environment to authenticate with. - */ - environment?: AzureEnvironment; - - /** - * The authorization scheme. Default value is 'Bearer'. - */ - authorizationScheme?: string; - - // TODO: What type should this really have? How is it used? - /** - * The token cache. Default value is null. - */ - tokenCache?: any; + /** + * The Azure environment to authenticate with. + */ + environment?: AzureEnvironment; + + /** + * The authorization scheme. Default value is 'Bearer'. + */ + authorizationScheme?: string; + + // TODO: What type should this really have? How is it used? + /** + * The token cache. Default value is null. + */ + tokenCache?: any; } export class ApplicationTokenCredentials extends msRest.ServiceClientCredentials { - /** - * Creates a new ApplicationTokenCredentials object. - * See {@link https://azure.microsoft.com/en-us/documentation/articles/active-directory-devquickstarts-dotnet/ Active Directory Quickstart for .Net} - * for detailed instructions on creating an Azure Active Directory application. - * @param {string} clientId The active directory application client id. - * @param {string} domain The domain or tenant id containing this application. - * @param {string} secret The authentication secret for the application. - * @param {AzureTokenCredentialsOptions} options Object representing optional parameters. - */ - constructor(clientId: string, domain: string, secret: string, options?: AzureTokenCredentialsOptions); + /** + * Creates a new ApplicationTokenCredentials object. + * See {@link https://azure.microsoft.com/en-us/documentation/articles/active-directory-devquickstarts-dotnet/ Active Directory Quickstart for .Net} + * for detailed instructions on creating an Azure Active Directory application. + * @param {string} clientId The active directory application client id. + * @param {string} domain The domain or tenant id containing this application. + * @param {string} secret The authentication secret for the application. + * @param {AzureTokenCredentialsOptions} options Object representing optional parameters. + */ + constructor(clientId: string, domain: string, secret: string, options?: AzureTokenCredentialsOptions); } export class UserTokenCredentials extends msRest.ServiceClientCredentials { - /** - * Creates a new UserTokenCredentials object. - * See {@link https://azure.microsoft.com/en-us/documentation/articles/active-directory-devquickstarts-dotnet/ Active Directory Quickstart for .Net} - * for an example. - * @param {string} clientId The active directory application client id. - * @param {string} domain The domain or tenant id containing this application. - * @param {string} username The user name for the Organization Id account. - * @param {string} password The password for the Organization Id account. - * @param {string} clientRedirectUri The Uri where the user will be redirected after authenticating with AD. - * @param {AzureTokenCredentialsOptions} options Object representing optional parameters. - */ - constructor(clientId: string, domain: string, username: string, password: string, clientRedirectUri: string, options?: AzureTokenCredentialsOptions); + /** + * Creates a new UserTokenCredentials object. + * See {@link https://azure.microsoft.com/en-us/documentation/articles/active-directory-devquickstarts-dotnet/ Active Directory Quickstart for .Net} + * for an example. + * @param {string} clientId The active directory application client id. + * @param {string} domain The domain or tenant id containing this application. + * @param {string} username The user name for the Organization Id account. + * @param {string} password The password for the Organization Id account. + * @param {string} clientRedirectUri The Uri where the user will be redirected after authenticating with AD. + * @param {AzureTokenCredentialsOptions} options Object representing optional parameters. + */ + constructor(clientId: string, domain: string, username: string, password: string, clientRedirectUri: string, options?: AzureTokenCredentialsOptions); } // TODO: WHAT SHOULD WE EXPOSE HERE? diff --git a/ClientRuntimes/NodeJS/ms-rest-azure/lib/pollingState.js b/ClientRuntimes/NodeJS/ms-rest-azure/lib/pollingState.js index 87a68bf6dfc25..114eedf25c573 100644 --- a/ClientRuntimes/NodeJS/ms-rest-azure/lib/pollingState.js +++ b/ClientRuntimes/NodeJS/ms-rest-azure/lib/pollingState.js @@ -40,24 +40,31 @@ function PollingState(resultOfInitialRequest, retryTimeout) { throw deserializationError; } - if (this.resource && this.resource.properties && this.resource.properties.provisioningState) { - this.status = this.resource.properties.provisioningState; - } else { - switch (this.response.statusCode) { - case 202: - this.status = LroStates.InProgress; - break; + switch (this.response.statusCode) { + case 202: + this.status = LroStates.InProgress; + break; - case 204: - case 201: - case 200: + case 204: + this.status = LroStates.Succeeded; + break; + case 201: + if (this.resource && this.resource.properties && this.resource.properties.provisioningState) { + this.status = this.resource.properties.provisioningState; + } else { + this.status = LroStates.InProgress; + } + break; + case 200: + if (this.resource && this.resource.properties && this.resource.properties.provisioningState) { + this.status = this.resource.properties.provisioningState; + } else { this.status = LroStates.Succeeded; - break; - - default: - this.status = LroStates.Failed; - break; - } + } + break; + default: + this.status = LroStates.Failed; + break; } } diff --git a/ClientRuntimes/NodeJS/ms-rest-azure/package.json b/ClientRuntimes/NodeJS/ms-rest-azure/package.json index 0cb2731447104..9ca0985902e48 100644 --- a/ClientRuntimes/NodeJS/ms-rest-azure/package.json +++ b/ClientRuntimes/NodeJS/ms-rest-azure/package.json @@ -24,7 +24,6 @@ "uuid": "2.0.1", "adal-node": "0.1.17", "ms-rest": "^1.12.0", - "underscore": "^1.4.0", "moment": "^2.6.0" }, "devDependencies": { diff --git a/ClientRuntimes/NodeJS/ms-rest-azure/test/azureEnvironmentTests.js b/ClientRuntimes/NodeJS/ms-rest-azure/test/azureEnvironmentTests.js new file mode 100644 index 0000000000000..01b6fbfd81708 --- /dev/null +++ b/ClientRuntimes/NodeJS/ms-rest-azure/test/azureEnvironmentTests.js @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +var should = require('should'); +var msRestAzure = require('../lib/msRestAzure'); + +describe('AzureEnvironment', function() { + it('can be properly required', function(done) { + var tempEnv = msRestAzure.AzureEnvironment; + tempEnv.validateAuthority.should.equal(true); + done(); + }); + + it('should show the details of Azure Production environment correctly', function(done) { + var tempEnv = msRestAzure.AzureEnvironment.Azure; + tempEnv.name.should.equal('Azure'); + tempEnv.activeDirectoryEndpointUrl.should.equal('https://login.microsoftonline.com'); + tempEnv.activeDirectoryResourceId.should.equal('https://management.core.windows.net/'); + tempEnv.managementEndpointUrl.should.equal('https://management.core.windows.net'); + tempEnv.resourceManagerEndpointUrl.should.equal('https://management.azure.com/'); + tempEnv.portalUrl.should.equal('http://go.microsoft.com/fwlink/?LinkId=254433'); + tempEnv.validateAuthority.should.equal(true); + done(); + }); + + it('should show the details of Azure China environment correctly', function(done) { + var tempEnv = msRestAzure.AzureEnvironment.AzureChina; + tempEnv.name.should.equal('AzureChina'); + tempEnv.activeDirectoryEndpointUrl.should.equal('https://login.chinacloudapi.cn'); + tempEnv.activeDirectoryResourceId.should.equal('https://management.core.chinacloudapi.cn/'); + tempEnv.managementEndpointUrl.should.equal('https://management.core.chinacloudapi.cn'); + tempEnv.resourceManagerEndpointUrl.should.equal('https://management.chinacloudapi.cn'); + tempEnv.portalUrl.should.equal('http://go.microsoft.com/fwlink/?LinkId=301902'); + tempEnv.validateAuthority.should.equal(true); + done(); + }); + + it('should show the details of Azure USGovernment environment correctly', function(done) { + var tempEnv = msRestAzure.AzureEnvironment.AzureUSGovernment; + tempEnv.name.should.equal('AzureUSGovernment'); + tempEnv.activeDirectoryEndpointUrl.should.equal('https://login.microsoftonline.com'); + tempEnv.activeDirectoryResourceId.should.equal('https://management.core.usgovcloudapi.net/'); + tempEnv.managementEndpointUrl.should.equal('https://management.core.usgovcloudapi.net'); + tempEnv.resourceManagerEndpointUrl.should.equal('https://management.usgovcloudapi.net'); + tempEnv.portalUrl.should.equal('https://manage.windowsazure.us'); + tempEnv.validateAuthority.should.equal(true); + done(); + }); + + it('should show the details of Azure GermanCloud environment correctly', function(done) { + var tempEnv = msRestAzure.AzureEnvironment.AzureGermanCloud; + tempEnv.name.should.equal('AzureGermanCloud'); + tempEnv.activeDirectoryEndpointUrl.should.equal('https://login.microsoftonline.de'); + tempEnv.activeDirectoryResourceId.should.equal('https://management.core.cloudapi.de/'); + tempEnv.managementEndpointUrl.should.equal('https://management.core.cloudapi.de'); + tempEnv.resourceManagerEndpointUrl.should.equal('https://management.microsoftazure.de'); + tempEnv.portalUrl.should.equal('http://portal.microsoftazure.de/'); + tempEnv.validateAuthority.should.equal(true); + done(); + }); + + it('should be able to add a new environment', function(done) { + var df = { + name: 'Dogfood', + portalUrl: 'http://go.microsoft.com/fwlink/?LinkId=254433', + managementEndpointUrl: 'https://management.core.windows.net', + resourceManagerEndpointUrl: 'https://management.azure.com/', + activeDirectoryEndpointUrl: 'https://login.microsoftonline.com', + activeDirectoryResourceId: 'https://management.core.windows.net/' + }; + var tempEnv = msRestAzure.AzureEnvironment; + var dfood = tempEnv.add(df); + dfood.name.should.equal('Dogfood'); + dfood.activeDirectoryEndpointUrl.should.equal('https://login.microsoftonline.com'); + dfood.activeDirectoryResourceId.should.equal('https://management.core.windows.net/'); + dfood.managementEndpointUrl.should.equal('https://management.core.windows.net'); + dfood.resourceManagerEndpointUrl.should.equal('https://management.azure.com/'); + dfood.portalUrl.should.equal('http://go.microsoft.com/fwlink/?LinkId=254433'); + dfood.validateAuthority.should.equal(true); + + //Verify that the environment properly got added to the prototype + tempEnv.Dogfood.name.should.equal('Dogfood'); + tempEnv.Dogfood.activeDirectoryEndpointUrl.should.equal('https://login.microsoftonline.com'); + tempEnv.Dogfood.activeDirectoryResourceId.should.equal('https://management.core.windows.net/'); + tempEnv.Dogfood.managementEndpointUrl.should.equal('https://management.core.windows.net'); + tempEnv.Dogfood.resourceManagerEndpointUrl.should.equal('https://management.azure.com/'); + tempEnv.Dogfood.portalUrl.should.equal('http://go.microsoft.com/fwlink/?LinkId=254433'); + tempEnv.Dogfood.validateAuthority.should.equal(true); + done(); + }); +}); \ No newline at end of file diff --git a/ClientRuntimes/NodeJS/ms-rest-azure/test/azureServiceClientTests.js b/ClientRuntimes/NodeJS/ms-rest-azure/test/azureServiceClientTests.js index e28f44bf5ad68..8e11e689690b7 100644 --- a/ClientRuntimes/NodeJS/ms-rest-azure/test/azureServiceClientTests.js +++ b/ClientRuntimes/NodeJS/ms-rest-azure/test/azureServiceClientTests.js @@ -92,9 +92,10 @@ describe('AzureServiceClient', function () { describe('Put', function () { resultOfInitialRequest.response.statusCode = 201; - + resultOfInitialRequest.request.method = 'PUT'; + it('throw on not Lro related status code', function (done) { - client.getPutOrPatchOperationResult({ response: {statusCode: 10000}, request: { url:"http://foo" }}, function (err, result) { + client.getPutOrPatchOperationResult({ response: {statusCode: 10000}, request: { url:"http://foo", method:'PUT' }}, function (err, result) { err.message.should.containEql('Unexpected polling status code from long running operation'); done(); }); @@ -156,11 +157,57 @@ describe('AzureServiceClient', function () { }); }); + describe('Patch', function () { + resultOfInitialRequest.response.statusCode = 202; + resultOfInitialRequest.body.properties.provisioningState = LroStates.Succeeded; + resultOfInitialRequest.request.method = 'PATCH'; + + it('works by polling from location header', function (done) { + resultOfInitialRequest.response.headers['azure-asyncoperation'] = ''; + resultOfInitialRequest.response.headers['location'] = urlFromLocationHeader_Return200; + client.getLongRunningOperationResult(resultOfInitialRequest, function (err, result) { + should.not.exist(err); + JSON.parse(result.body).name.should.equal(testResourceName); + should.exist(result.response.randomFieldFromPollLocationHeader); + done(); + }); + }); + + it('works by polling from azure-asyncoperation header', function (done) { + resultOfInitialRequest.response.headers['azure-asyncoperation'] = urlFromAzureAsyncOPHeader_Return200; + resultOfInitialRequest.response.headers['location'] = ''; + client.getLongRunningOperationResult(resultOfInitialRequest, function (err, result) { + should.not.exist(err); + JSON.parse(result.body).name.should.equal(testResourceName); + done(); + }); + }); + + it('returns error if failed to poll from the azure-asyncoperation header', function (done) { + resultOfInitialRequest.response.headers['azure-asyncoperation'] = url_ReturnError; + resultOfInitialRequest.response.headers['location'] = ''; + client.getLongRunningOperationResult(resultOfInitialRequest, function (err, result) { + err.message.should.containEql(testError); + done(); + }); + }); + + it('returns error if failed to poll from the location header', function (done) { + resultOfInitialRequest.response.headers['azure-asyncoperation'] = ''; + resultOfInitialRequest.response.headers['location'] = url_ReturnError; + client.getLongRunningOperationResult(resultOfInitialRequest, function (err, result) { + err.message.should.containEql(testError); + done(); + }); + }); + }); + describe('Post-or-Delete', function () { resultOfInitialRequest.response.statusCode = 202; - + resultOfInitialRequest.body.properties.provisioningState = LroStates.Succeeded; + it('throw on not Lro related status code', function (done) { - client.getPostOrDeleteOperationResult({ response: { statusCode: 201 } }, function (err, result) { + client.getPostOrDeleteOperationResult({ response: { statusCode: 201 }, request: {url: url_resource, method: 'POST'}}, function (err, result) { err.message.should.containEql('Unexpected polling status code from long running operation'); done(); }); @@ -169,6 +216,7 @@ describe('AzureServiceClient', function () { it('works by polling from the azure-asyncoperation header', function (done) { resultOfInitialRequest.response.headers['azure-asyncoperation'] = urlFromAzureAsyncOPHeader_Return200; resultOfInitialRequest.response.headers['location'] = ''; + resultOfInitialRequest.request.method = 'POST'; client.getPostOrDeleteOperationResult(resultOfInitialRequest, function (err, result) { should.not.exist(err); should.exist(result.response.randomFieldFromPollAsyncOpHeader); @@ -219,7 +267,7 @@ describe('AzureServiceClient', function () { negativeClient.addFilter(mockFilter({ statusCode: 200, body: badResponseBody }, badResponseBody)); resultOfInitialRequest.response.headers['azure-asyncoperation'] = ''; resultOfInitialRequest.response.headers['location'] = urlFromLocationHeader_Return200; - negativeClient.getPutOrPatchOperationResult(resultOfInitialRequest, function (err, result) { + negativeClient.getLongRunningOperationResult(resultOfInitialRequest, function (err, result) { should.exist(err); should.exist(err.response); should.exist(err.message); @@ -234,7 +282,7 @@ describe('AzureServiceClient', function () { negativeClient.addFilter(mockFilter({ statusCode: 200, body: badResponseBody }, badResponseBody)); resultOfInitialRequest.response.headers['azure-asyncoperation'] = ''; resultOfInitialRequest.response.headers['location'] = urlFromLocationHeader_Return200; - negativeClient.getPutOrPatchOperationResult(resultOfInitialRequest, negativeClient._getStatus, function (err, result) { + negativeClient.getLongRunningOperationResult(resultOfInitialRequest, negativeClient._getStatus, function (err, result) { should.exist(err); should.exist(err.response); should.exist(err.message); @@ -249,7 +297,7 @@ describe('AzureServiceClient', function () { negativeClient.addFilter(mockFilter({ statusCode: 203, body: badResponseBody }, badResponseBody)); resultOfInitialRequest.response.headers['azure-asyncoperation'] = ''; resultOfInitialRequest.response.headers['location'] = urlFromLocationHeader_Return200; - negativeClient.getPutOrPatchOperationResult(resultOfInitialRequest, function (err, result) { + negativeClient.getLongRunningOperationResult(resultOfInitialRequest, function (err, result) { should.exist(err); should.exist(err.response); should.exist(err.message); diff --git a/ClientRuntimes/NodeJS/ms-rest-azure/test/package.json b/ClientRuntimes/NodeJS/ms-rest-azure/test/package.json index a4970d007d2f2..248a41a8851c5 100644 --- a/ClientRuntimes/NodeJS/ms-rest-azure/test/package.json +++ b/ClientRuntimes/NodeJS/ms-rest-azure/test/package.json @@ -31,8 +31,7 @@ "xunit-file": "0.0.5", "mocha": "2.2.5", "should": "5.2.0", - "moment": "*", - "underscore": "*" + "moment": "*" }, "homepage": "https://github.com/Azure/AutoRest", "repository": { diff --git a/ClientRuntimes/NodeJS/ms-rest-azure/test/testlist.txt b/ClientRuntimes/NodeJS/ms-rest-azure/test/testlist.txt index 611875592179e..83a9769333bf7 100644 --- a/ClientRuntimes/NodeJS/ms-rest-azure/test/testlist.txt +++ b/ClientRuntimes/NodeJS/ms-rest-azure/test/testlist.txt @@ -1 +1,2 @@ -azureServiceClientTests.js \ No newline at end of file +azureServiceClientTests.js +azureEnvironmentTests.js \ No newline at end of file diff --git a/ClientRuntimes/NodeJS/ms-rest/README.md b/ClientRuntimes/NodeJS/ms-rest/README.md index cb4aca73ab405..1da52bff1ac92 100644 --- a/ClientRuntimes/NodeJS/ms-rest/README.md +++ b/ClientRuntimes/NodeJS/ms-rest/README.md @@ -18,7 +18,7 @@ var msrest = require('ms-rest'); ## Serialization/Deserialization Features - Type checking - - (String, Number, Boolean, ByteArray, Date, DateTime, Enum, TimeSpan, DateTimeRfc1123, Object, Stream, Sequence, Dictionary, Composite, Uuid(as a string)) + - (String, Number, Boolean, ByteArray, Base64Url, Date, DateTime, Enum, TimeSpan, DateTimeRfc1123, UnixTime, Object, Stream, Sequence, Dictionary, Composite, Uuid(as a string)) - Validation of specified constraints - ExclusiveMaximum, ExclusiveMinimum, InclusiveMaximum, InclusiveMinimum, MaxItems, MaxLength, MinItems, MinLength, MultipleOf, Pattern, UniqueItems - Flattening/Unflattening properties @@ -26,6 +26,7 @@ Features - Model Properties marked as constant are set during serialization, irrespective of they being provided or not - Required check (If a model or property is marked required and is not provided in the object then an error is thrown) - Readonly check (If a model or property is marked readonly then it is not sent on the wire during, serialization) +- Serializing Constant values - serialize an array of dictionary of primitive values ```javascript diff --git a/ClientRuntimes/NodeJS/ms-rest/lib/serialization.js b/ClientRuntimes/NodeJS/ms-rest/lib/serialization.js index de8d0778efd92..671292b9f43ba 100644 --- a/ClientRuntimes/NodeJS/ms-rest/lib/serialization.js +++ b/ClientRuntimes/NodeJS/ms-rest/lib/serialization.js @@ -74,7 +74,7 @@ exports.serialize = function (mapper, object, objectName) { payload = serializeBasicTypes.call(this, mapperType, objectName, object); } else if (mapperType.match(/^Enum$/ig) !== null) { payload = serializeEnumType.call(this, objectName, mapper.type.allowedValues, object); - } else if (mapperType.match(/^(Date|DateTime|TimeSpan|DateTimeRfc1123)$/ig) !== null) { + } else if (mapperType.match(/^(Date|DateTime|TimeSpan|DateTimeRfc1123|UnixTime)$/ig) !== null) { payload = serializeDateTypes.call(this, mapperType, object, objectName); } else if (mapperType.match(/^ByteArray$/ig) !== null) { payload = serializeBufferType.call(this, objectName, object); @@ -370,6 +370,13 @@ function serializeDateTypes(typeName, value, objectName) { throw new Error(util.format('%s must be an instanceof Date or a string in RFC-1123 format.', objectName)); } value = (value instanceof Date) ? value.toUTCString() : new Date(value).toUTCString(); + } else if (typeName.match(/^UnixTime$/ig) !== null) { + if (!(value instanceof Date || + (typeof value.valueOf() === 'string' && !isNaN(Date.parse(value))))) { + throw new Error(util.format('%s must be an instanceof Date or a string in RFC-1123/ISO8601 format ' + + 'for it to be serialized in UnixTime/Epoch format.', objectName)); + } + value = dateToUnixTime(value); } else if (typeName.match(/^TimeSpan$/ig) !== null) { if (!moment.isDuration(value)) { throw new Error(util.format('%s must be a TimeSpan/Duration.', objectName)); @@ -402,8 +409,10 @@ exports.deserialize = function (mapper, responseBody, objectName) { payload = responseBody; } else if (mapperType.match(/^(Date|DateTime|DateTimeRfc1123)$/ig) !== null) { payload = new Date(responseBody); - } else if (mapperType.match(/^(TimeSpan)$/ig) !== null) { + } else if (mapperType.match(/^TimeSpan$/ig) !== null) { payload = moment.duration(responseBody); + } else if (mapperType.match(/^UnixTime$/ig) !== null) { + payload = unixTimeToDate(responseBody); } else if (mapperType.match(/^ByteArray$/ig) !== null) { payload = new Buffer(responseBody, 'base64'); } else if (mapperType.match(/^Base64Url$/ig) !== null) { @@ -595,4 +604,21 @@ function base64UrlToBuffer(str) { return new Buffer(str, 'base64'); } +function dateToUnixTime(d) { + if (!d) { + return null; + } + if (typeof d.valueOf() === 'string') { + d = new Date(d); + } + return parseInt(d.getTime() / 1000); +} + +function unixTimeToDate(n) { + if (!n) { + return null; + } + return new Date(n*1000); +} + exports = module.exports; \ No newline at end of file diff --git a/ClientRuntimes/NodeJS/ms-rest/test/serializationTests.js b/ClientRuntimes/NodeJS/ms-rest/test/serializationTests.js index d9be4bd39fba9..32c89671d37cf 100644 --- a/ClientRuntimes/NodeJS/ms-rest/test/serializationTests.js +++ b/ClientRuntimes/NodeJS/ms-rest/test/serializationTests.js @@ -195,6 +195,12 @@ describe('msrest', function () { serializedDateString.should.equal('+010000-01-01T11:59:59.000Z'); done(); }); + it('should correctly serialize a Date object with max value and format UnixTime', function (done) { + mapper = { type : { name: 'UnixTime' } }; + var serializedDate = msRest.serialize(mapper, new Date('9999-12-31T23:59:59-12:00'), 'dateTimeObj'); + serializedDate.should.equal(253402343999); + done(); + }); it('should correctly serialize a string in DateTimeRfc1123', function (done) { mapper = { type : { name: 'DateTimeRfc1123' } }; var rfc = new Date('Mon, 01 Jan 0001 00:00:00 GMT'); diff --git a/ClientRuntimes/Python/msrest/doc/conf.py b/ClientRuntimes/Python/msrest/doc/conf.py index 1dfe56981ffc9..169d6053b55f8 100644 --- a/ClientRuntimes/Python/msrest/doc/conf.py +++ b/ClientRuntimes/Python/msrest/doc/conf.py @@ -57,9 +57,9 @@ # built documents. # # The short X.Y version. -version = '0.2.0' +version = '0.3.0' # The full version, including alpha/beta/rc tags. -release = '0.2.0' +release = '0.3.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/ClientRuntimes/Python/msrest/msrest/version.py b/ClientRuntimes/Python/msrest/msrest/version.py index 11739ebc3606c..527b2a717c20b 100644 --- a/ClientRuntimes/Python/msrest/msrest/version.py +++ b/ClientRuntimes/Python/msrest/msrest/version.py @@ -25,4 +25,4 @@ # -------------------------------------------------------------------------- -msrest_version = "0.2.0" +msrest_version = "0.3.0" diff --git a/ClientRuntimes/Python/msrest/readme.rst b/ClientRuntimes/Python/msrest/readme.rst index 77e50e0da4bb2..b65e1bf5b13a5 100644 --- a/ClientRuntimes/Python/msrest/readme.rst +++ b/ClientRuntimes/Python/msrest/readme.rst @@ -15,6 +15,19 @@ To install: Release History --------------- +2016-04-26 Version 0.3.0 +++++++++++++++++++++++++ + +**Bugfixes** + +- Read only values are no longer in __init__ or sent to the server (https://github.com/Azure/autorest/pull/959) +- Useless kwarg removed + +**Behaviour changes** + +- Needs Autorest > 0.16.0 Nightly 20160426 + + 2016-03-25 Version 0.2.0 ++++++++++++++++++++++++ @@ -23,7 +36,7 @@ Release History - Manage integer enum values (https://github.com/Azure/autorest/pull/879) - Add missing application/json Accept HTTP header (https://github.com/Azure/azure-sdk-for-python/issues/553) -**Beheviour changes** +**Behaviour changes** - Needs Autorest > 0.16.0 Nightly 20160324 diff --git a/ClientRuntimes/Python/msrest/setup.py b/ClientRuntimes/Python/msrest/setup.py index b3dca9089b534..02bdd49b71aab 100644 --- a/ClientRuntimes/Python/msrest/setup.py +++ b/ClientRuntimes/Python/msrest/setup.py @@ -28,7 +28,7 @@ setup( name='msrest', - version='0.2.0', + version='0.3.0', author='Microsoft Corporation', packages=['msrest'], url=("https://github.com/xingwu1/autorest/tree/python/" diff --git a/ClientRuntimes/Python/msrestazure/doc/conf.py b/ClientRuntimes/Python/msrestazure/doc/conf.py index 9a76b3204d5c2..1225f72e6ec9d 100644 --- a/ClientRuntimes/Python/msrestazure/doc/conf.py +++ b/ClientRuntimes/Python/msrestazure/doc/conf.py @@ -58,9 +58,9 @@ # built documents. # # The short X.Y version. -version = '0.2.1' +version = '0.3.0' # The full version, including alpha/beta/rc tags. -release = '0.2.1' +release = '0.3.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/ClientRuntimes/Python/msrestazure/msrestazure/version.py b/ClientRuntimes/Python/msrestazure/msrestazure/version.py index 23c80b2514da3..edb859f0a87d2 100644 --- a/ClientRuntimes/Python/msrestazure/msrestazure/version.py +++ b/ClientRuntimes/Python/msrestazure/msrestazure/version.py @@ -24,4 +24,4 @@ # # -------------------------------------------------------------------------- -msrestazure_version = "0.2.1" +msrestazure_version = "0.3.0" diff --git a/ClientRuntimes/Python/msrestazure/readme.rst b/ClientRuntimes/Python/msrestazure/readme.rst index 18a49a8035f2b..7ba256b12c10a 100644 --- a/ClientRuntimes/Python/msrestazure/readme.rst +++ b/ClientRuntimes/Python/msrestazure/readme.rst @@ -15,6 +15,21 @@ To install: Release History --------------- +2016-04-26 Version 0.3.0 +++++++++++++++++++++++++ + +Update msrest dependency to 0.3.0 + +**Bugfixes** + +- Read only values are no longer in __init__ or sent to the server (https://github.com/Azure/autorest/pull/959) +- Useless kwarg removed + +**Behaviour changes** + +- Needs Autorest > 0.16.0 Nightly 20160426 + + 2016-03-31 Version 0.2.1 ++++++++++++++++++++++++ diff --git a/ClientRuntimes/Python/msrestazure/setup.py b/ClientRuntimes/Python/msrestazure/setup.py index d25ce47f33493..7778b0185d42b 100644 --- a/ClientRuntimes/Python/msrestazure/setup.py +++ b/ClientRuntimes/Python/msrestazure/setup.py @@ -28,7 +28,7 @@ setup( name='msrestazure', - version='0.2.1', + version='0.3.0', author='Microsoft Corporation', packages=['msrestazure'], url=('https://github.com/xingwu1/autorest/tree/python/' @@ -49,5 +49,5 @@ 'License :: OSI Approved :: MIT License', 'Topic :: Software Development'], install_requires=[ - "msrest>=0.2.0"], + "msrest>=0.3.0"], ) diff --git a/Documentation/README.md b/Documentation/README.md index 890f11b09d4bf..6b77f525787bb 100644 --- a/Documentation/README.md +++ b/Documentation/README.md @@ -18,6 +18,7 @@ - Code Generators - Modelers 5. [Building AutoRest](building-code.md) -6. Contributing to the code +6. [Writing Tests](writing-tests.md) +7. Contributing to the code [Swagger2.0]:https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md diff --git a/Documentation/writing-tests.md b/Documentation/writing-tests.md new file mode 100644 index 0000000000000..7712f32f74753 --- /dev/null +++ b/Documentation/writing-tests.md @@ -0,0 +1,52 @@ +# Writing Tests + +## Build Prerequisites +To test AutoRest in each language, you must set up your machine according to the requirements on the [Building Code](building-code.md) page. + +## Architecture +Tests are split into unit and acceptance tests. Unit tests validate the AutoRest application itself and how it interprets Swagger documents. Acceptance tests validate the generated code in each language and are written in those languages. + +### Unit tests +Unit tests need to be updated when core parts of AutoRest change, not when the language-specific generator code changes. Unit tests are located in: +
+
\AutoRest\AutoRest.Core.Tests
+
These need to be updated when the command-line AutoRest application itself changes
+
\AutoRest\Modelers\Swagger.Tests
+ \AutoRest\Modelers\Swagger.Composite.Tests
+
These need to be updated when there are changes to how AutoRest processes Swagger files
+
+ +### Acceptance tests (and test server) +Acceptance tests are run against a Node.js test server (which uses [Express framework](http://expressjs.com/)). The code for the test server is checked in to the [\\AutoRest\\TestServer](../AutoRest/TestServer/) folder in the repository. + +There are two main components to the test server: the Swagger definitions that describe the server and the code that handles requests to the server and responds with the appropriate status code, payload, etc. if the request is constructed correctly. + +## How to add acceptance tests for scenarios +1. Add your scenarios to the Swagger files that describe the test server (located in the [\\AutoRest\\TestServer\\swagger](../AutoRest/TestServer/swagger/) folder). +2. Update the test server + - Update the routes to generate appropriate responses for your scenarios at paths specified in the Swagger files in step 1. This code is located in the [\\AutoRest\\TestServer\\server\\routes\\*.js](../AutoRest/TestServer/server/routes) files. + - For each scenario, the `coverage` dictionary needs to be incremented for the name of your scenario. This name will be used in the test report coverage. + - Update the `coverage` dictionary in [\\AutoRest\\TestServer\\server\\app.js](../AutoRest/TestServer/server/app.js) to include the names of your new scenarios. This lets the final test report include your scenarios when reporting on the coverage for each language. +3. Regenerate the expected code using `gulp regenerate` (this will use the Swagger files to generate client libraries for the test server). +4. In each language, write tests that cover your scenarios (for example, in C#, you must update [\\AutoRest\\Generators\\CSharp\CSharp.Tests\\AcceptanceTests.cs](../AutoRest/Generators/CSharp/CSharp.Tests/AcceptanceTests.cs) or [\\AutoRest\\Generators\\CSharp\\Azure.CSharp.Tests\\AcceptanceTests.cs](../AutoRest/Generators/CSharp/Azure.CSharp.Tests/AcceptanceTests.cs)). You will make calls to the test server using the generated code from step 3. +5. [Run the tests](#running-tests) + +## Running Tests +When you run tests, the test server is automatically started and the code that is generated for the test server Swagger files will correctly target this new instance. + +### Command Line +Tests can be run with `gulp test`. You can run tests for each language individually with `gulp:test:[language name]`. Use `gulp -T` to find the correct names. + +### Visual Studio +In Visual Studio, you can run tests for all languages using Task Runner Explorer. C# tests can also be run and debugged in Test Explorer. + +## Debugging the test server +When updating the test server code to return the appropriate responses for your scenarios, it can be useful to debug the code to make sure the test code calls the paths that you are expecting. + +### Visual Studio +1. Install [Node.js Tools for Visual Studio](https://www.visualstudio.com/en-us/features/node-js-vs.aspx) solution. +2. Open the [\\AutoRest\\TestServer\\server\\SwaggerBATServer.sln](../AutoRest/TestServer/server/SwaggerBATServer.sln). +3. Run the [SwaggerBATServer project](../AutoRest/TestServer/server/SwaggerBATServer.njsproj). +4. Make sure that the port that the test server is using matches the port that is used by the tests when you run them. + - For Node.js, this is straightforward because the server and tests both use port 3000 by default. + - For C#, the infrastructure is set up to use a random port to avoid conflicts. You must change the logic in [\\AutoRest\\Generators\\CSharp\\CSharp.Tests\\Utilities\\ServiceController.cs](../AutoRest/Generators/CSharp/CSharp.Tests/Utilities/ServiceController.cs).`GetRandomPort()` to use the same port as the test server. \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index 1e9ac0f0fb9b6..0200a15c8c7f6 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -128,6 +128,8 @@ var rubyAzureMappings = { 'azure_url':['../../../TestServer/swagger/subscriptionId-apiVersion.json', 'AzureUrlModule'], 'azure_special_properties': ['../../../TestServer/swagger/azure-special-properties.json', 'AzureSpecialPropertiesModule'], 'azure_report':['../../../TestServer/swagger/azure-report.json', 'AzureReportModule'], + 'custom_base_uri':['../../../TestServer/swagger/custom-baseUrl.json', 'CustomBaseUriModule'], + 'custom_base_uri_more':['../../../TestServer/swagger/custom-baseUrl-more-options.json', 'CustomBaseUriMoreModule'], }; gulp.task('regenerate:expected', function(cb){