diff --git a/AutoRest/Generators/Extensions/Azure.Extensions/AzureExtensions.cs b/AutoRest/Generators/Extensions/Azure.Extensions/AzureExtensions.cs index 6898c3ec096ac..eff59af7029f6 100644 --- a/AutoRest/Generators/Extensions/Azure.Extensions/AzureExtensions.cs +++ b/AutoRest/Generators/Extensions/Azure.Extensions/AzureExtensions.cs @@ -423,7 +423,7 @@ public static void AddPageableMethod(ServiceClient serviceClient, CodeNamer code nextLinkMethod.Parameters.Add(newGroupingParam); //grouping.Key.Name = newGroupingParam.Name; var inputParameter = (Parameter) nextLinkMethod.InputParameterTransformation.First().ParameterMappings[0].InputParameter.Clone(); - inputParameter.Name = newGroupingParam.Name.ToCamelCase(); + inputParameter.Name = codeNamer.GetParameterName(newGroupingParam.Name); nextLinkMethod.InputParameterTransformation.ForEach(t => t.ParameterMappings[0].InputParameter = inputParameter); } }); diff --git a/AutoRest/Generators/Ruby/Azure.Ruby.Tests/RspecTests/lro_spec.rb b/AutoRest/Generators/Ruby/Azure.Ruby.Tests/RspecTests/lro_spec.rb index 508ee7144edea..02895779f1426 100644 --- a/AutoRest/Generators/Ruby/Azure.Ruby.Tests/RspecTests/lro_spec.rb +++ b/AutoRest/Generators/Ruby/Azure.Ruby.Tests/RspecTests/lro_spec.rb @@ -25,7 +25,7 @@ # Happy path tests it 'should wait for succeeded status for create operation' do result = @client.lros.put201creating_succeeded200(@product).value! - expect(result.body.properties.provisioning_state).to eq("Succeeded") + expect(result.body.provisioning_state).to eq("Succeeded") end it 'should rise error on "failed" operation result' do @@ -34,7 +34,7 @@ it 'should wait for succeeded status for update operation' do result = @client.lros.put200updating_succeeded204(@product).value! - expect(result.body.properties.provisioning_state).to eq("Succeeded") + expect(result.body.provisioning_state).to eq("Succeeded") end it 'should rise error on "canceled" operation result' do @@ -48,24 +48,24 @@ it 'should serve success responce on initial PUT request' do result = @client.lros.put200succeeded(@product).value! - expect(result.body.properties.provisioning_state).to eq("Succeeded") + expect(result.body.provisioning_state).to eq("Succeeded") end it 'should serve success responce on initial request without provision state' do result = @client.lros.put200succeeded_no_state(@product).value! expect(result.body.id).to eq("100") - expect(result.body.properties).to eq(nil) + expect(result.body.provisioning_state).to eq(nil) end it 'should serve 202 on initial responce and status responce without provision state' do result = @client.lros.put202retry200(@product).value! expect(result.body.id).to eq("100") - expect(result.body.properties).to eq(nil) + expect(result.body.provisioning_state).to eq(nil) end it 'should retry on 500 server responce in PUT request' do result = @client.lroretrys.put_async_relative_retry_succeeded(@product).value! - expect(result.body.properties.provisioning_state).to eq("Succeeded") + expect(result.body.provisioning_state).to eq("Succeeded") end # TODO: Fix flakey test @@ -96,12 +96,12 @@ # Retryable errors it 'should retry PUT request on 500 responce' do result = @client.lroretrys.put201creating_succeeded200(@product).value! - expect(result.body.properties.provisioning_state).to eq("Succeeded") + expect(result.body.provisioning_state).to eq("Succeeded") end it 'should retry PUT request on 500 responce for async operation' do result = @client.lroretrys.put_async_relative_retry_succeeded(@product).value! - expect(result.body.properties.provisioning_state).to eq("Succeeded") + expect(result.body.provisioning_state).to eq("Succeeded") end it 'should retry DELETE request for provisioning status' do diff --git a/AutoRest/Generators/Ruby/Azure.Ruby/AzureRubyCodeGenerator.cs b/AutoRest/Generators/Ruby/Azure.Ruby/AzureRubyCodeGenerator.cs index d11067a9903af..d3aa58bea0991 100644 --- a/AutoRest/Generators/Ruby/Azure.Ruby/AzureRubyCodeGenerator.cs +++ b/AutoRest/Generators/Ruby/Azure.Ruby/AzureRubyCodeGenerator.cs @@ -55,13 +55,7 @@ public override string UsageInstructions public override void NormalizeClientModel(ServiceClient serviceClient) { Settings.AddCredentials = true; - AzureExtensions.ProcessClientRequestIdExtension(serviceClient); - AzureExtensions.UpdateHeadMethods(serviceClient); - AzureExtensions.ParseODataExtension(serviceClient); - AzureExtensions.AddPageableMethod(serviceClient, CodeNamer); - AzureExtensions.AddLongRunningOperations(serviceClient); - AzureExtensions.AddAzureProperties(serviceClient); - AzureExtensions.SetDefaultResponses(serviceClient); + AzureExtensions.NormalizeAzureClientModel(serviceClient, Settings, CodeNamer); CorrectFilterParameters(serviceClient); base.NormalizeClientModel(serviceClient); } diff --git a/AutoRest/Generators/Ruby/Ruby.Tests/RspecTests/model_flattening_spec.rb b/AutoRest/Generators/Ruby/Ruby.Tests/RspecTests/model_flattening_spec.rb index 2cb9be3a05b67..4f78dae9e2244 100644 --- a/AutoRest/Generators/Ruby/Ruby.Tests/RspecTests/model_flattening_spec.rb +++ b/AutoRest/Generators/Ruby/Ruby.Tests/RspecTests/model_flattening_spec.rb @@ -8,7 +8,7 @@ include ModelFlatteningModule include ModelFlatteningModule::Models -describe 'ModelFlattening' do +describe 'Resource Flattening Operations' do before(:all) do @base_url = ENV['StubServerURI'] @@ -17,39 +17,44 @@ @client = AutoRestResourceFlatteningTestService.new(@credentials, @base_url) - product1 = FlattenedProduct.new - product1.location = "West US" - product1.tags = { + @product1 = FlattenedProduct.new + @product1.location = "West US" + @product1.tags = { "tag1" => "value1", "tag2" => "value3" } - - # product1.pname = "Product1" + @product1.pname = "Product1" + @product1.flattened_product_type = "Flat" product2 = FlattenedProduct.new product2.location = "Building 44" - # product2.pname = "Product2" + product2.pname = "Product2" + product2.flattened_product_type = "Flat" @dict_resource = { - "Resource1" => product1, + "Resource1" => @product1, "Resource2" => product2 } - @array_resource = [product1, product2] + @array_resource = [@product1, product2] end - # Array tests - it 'should get array' do + it 'should get external resource as an array' do result = @client.get_array_async().value! - # Resource 1 + expect(result.body.count).to eq(3) + result.body.each do |flatten_product| + expect(flatten_product).to be_instance_of(FlattenedProduct) + end + + # Resource 1 expect(result.body[0].id).to eq("1") expect(result.body[0].name).to eq("Resource1") expect(result.body[0].location).to eq("Building 44") expect(result.body[0].type).to eq("Microsoft.Web/sites") - expect(result.body[0].properties.pname).to eq("Product1") - expect(result.body[0].properties.provisioning_state).to eq("Succeeded") - expect(result.body[0].properties.provisioning_state_values).to eq("OK") + expect(result.body[0].pname).to eq("Product1") + expect(result.body[0].provisioning_state).to eq("Succeeded") + expect(result.body[0].provisioning_state_values).to eq("OK") expect(result.body[0].tags["tag1"]).to eq("value1") expect(result.body[0].tags["tag2"]).to eq("value3") @@ -63,25 +68,27 @@ expect(result.body[2].name).to eq("Resource3") end - # it 'should put array' do - # result = @client.resource_flattening.put_array_async(@array_resource).value! - # expect(result).to be_an_instance_of(Net::HTTPOK) - # end + it 'should put external resource as an array' do + result = @client.put_array_async(@array_resource).value! + expect(result.response.status).to eq(200) + end - # Dictionary tests - it 'should get dictionary' do + it 'should get external resource as a dictionary' do result = @client.get_dictionary_async().value! - # Resource 1 expect(result.body.count).to eq(3) + + result.body do |_, value| + expect(value).to be_instance_of(FlattenedProduct) + end + + # Resource 1 expect(result.body["Product1"].id).to eq("1") expect(result.body["Product1"].location).to eq("Building 44") expect(result.body["Product1"].name).to eq("Resource1") expect(result.body["Product1"].type).to eq("Microsoft.Web/sites") - - expect(result.body["Product1"].properties.provisioning_state_values).to eq("OK") - expect(result.body["Product1"].properties.pname).to eq("Product1") - expect(result.body["Product1"].properties.provisioning_state).to eq("Succeeded") - + expect(result.body["Product1"].provisioning_state_values).to eq("OK") + expect(result.body["Product1"].pname).to eq("Product1") + expect(result.body["Product1"].provisioning_state).to eq("Succeeded") expect(result.body["Product1"].tags["tag1"]).to eq("value1") expect(result.body["Product1"].tags["tag2"]).to eq("value3") @@ -95,13 +102,12 @@ expect(result.body["Product3"].name).to eq("Resource3") end - # it 'should put dictionary' do - # result = @client.resource_flattening.put_dictionary_async(@dict_resource).value!.response - # expect(result).to be_an_instance_of(Net::HTTPOK) - # end + it 'should put external resource as a dictionary' do + result = @client.put_dictionary_async(@dict_resource).value! + expect(result.response.status).to eq(200) + end - # Complex tests - it 'should get resource collection' do + it 'should get external resource as a complex type' do result = @client.get_resource_collection_async().value! # Resource 1 @@ -110,13 +116,11 @@ expect(result.body.dictionaryofresources["Product1"].location).to eq("Building 44") expect(result.body.dictionaryofresources["Product1"].name).to eq("Resource1") expect(result.body.dictionaryofresources["Product1"].type).to eq("Microsoft.Web/sites") - expect(result.body.dictionaryofresources["Product1"].tags["tag1"]).to eq("value1") expect(result.body.dictionaryofresources["Product1"].tags["tag2"]).to eq("value3") - - expect(result.body.dictionaryofresources["Product1"].properties.provisioning_state_values).to eq("OK") - expect(result.body.dictionaryofresources["Product1"].properties.pname).to eq("Product1") - expect(result.body.dictionaryofresources["Product1"].properties.provisioning_state).to eq("Succeeded") + expect(result.body.dictionaryofresources["Product1"].provisioning_state_values).to eq("OK") + expect(result.body.dictionaryofresources["Product1"].pname).to eq("Product1") + expect(result.body.dictionaryofresources["Product1"].provisioning_state).to eq("Succeeded") # Resource 2 expect(result.body.dictionaryofresources["Product2"].id).to eq("2") @@ -133,11 +137,9 @@ expect(result.body.arrayofresources[0].name).to eq("Resource4") expect(result.body.arrayofresources[0].location).to eq("Building 44") expect(result.body.arrayofresources[0].type).to eq("Microsoft.Web/sites") - - expect(result.body.arrayofresources[0].properties.provisioning_state_values).to eq("OK") - expect(result.body.arrayofresources[0].properties.pname).to eq("Product4") - expect(result.body.arrayofresources[0].properties.provisioning_state).to eq("Succeeded") - + expect(result.body.arrayofresources[0].provisioning_state_values).to eq("OK") + expect(result.body.arrayofresources[0].pname).to eq("Product4") + expect(result.body.arrayofresources[0].provisioning_state).to eq("Succeeded") expect(result.body.arrayofresources[0].tags["tag1"]).to eq("value1") expect(result.body.arrayofresources[0].tags["tag2"]).to eq("value3") @@ -151,12 +153,70 @@ expect(result.body.arrayofresources[2].name).to eq("Resource6") end - # it 'should put complex object' do - # complex_resource = ResourceCollection.new - # complex_resource.dictionaryOfResources = @dict_resource - # complex_resource.arrayOfResources = @array_resource - # result = @client.resource_flattening.put_resource_collection_async(complex_resource).value!.response - # expect(result).to be_an_instance_of(Net::HTTPOK) - # end + it 'should put external resource as a complex type' do + complex_resource = ResourceCollection.new + + product2 = FlattenedProduct.new + product2.location = "East US" + product2.pname = "Product2" + product2.flattened_product_type = "Flat" + + product = FlattenedProduct.new + product.location = "India" + product.pname = "Azure" + product.flattened_product_type = "Flat" + + complex_resource.dictionaryofresources = @dict_resource + complex_resource.arrayofresources = [@product1, product2] + complex_resource.productresource = product + result = @client.put_resource_collection_async(complex_resource).value! + expect(result.response.status).to eq(200) + end + + it 'should put simple product to flatten' do + simple_product = SimpleProduct.new + simple_product.product_id = '123' + simple_product.description = 'product description' + simple_product.max_product_display_name = 'max name' + simple_product.odatavalue = 'http://foo' + simple_product.generic_value = 'https://generic' + + result = @client.put_simple_product_async(simple_product).value! + expect(result.response.status).to eq(200) + end + + it 'should post simple product with param flattening' do + result = @client.post_flattened_simple_product_async('123', 'max name', 'product description', nil, 'http://foo').value! + expect(result.response.status).to eq(200) + + simple_product = result.body + expect(simple_product).to be_instance_of(SimpleProduct) + expect(simple_product.product_id).to eq('123') + expect(simple_product.max_product_display_name).to eq('max name') + expect(simple_product.description).to eq('product description') + expect(simple_product.odatavalue).to eq('http://foo') + expect(simple_product.capacity).to eq('Large') + expect(simple_product.generic_value).to be_nil + end + it 'should put flattened and grouped product' do + param_group = FlattenParameterGroup.new + param_group.product_id = '123' + param_group.description = 'product description' + param_group.max_product_display_name = 'max name' + param_group.odatavalue = 'http://foo' + param_group.name = 'groupproduct' + + result = @client.put_simple_product_with_grouping_async(param_group).value! + expect(result.response.status).to eq(200) + + simple_product = result.body + expect(simple_product).to be_instance_of(SimpleProduct) + expect(simple_product.product_id).to eq('123') + expect(simple_product.max_product_display_name).to eq('max name') + expect(simple_product.description).to eq('product description') + expect(simple_product.odatavalue).to eq('http://foo') + expect(simple_product.capacity).to eq('Large') + expect(simple_product.generic_value).to be_nil + 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 03c68c94927d9..e111d37612e4a 100644 --- a/AutoRest/Generators/Ruby/Ruby/RubyCodeGenerator.cs +++ b/AutoRest/Generators/Ruby/Ruby/RubyCodeGenerator.cs @@ -114,8 +114,7 @@ public override string ImplementationFileExtension /// public override void NormalizeClientModel(ServiceClient serviceClient) { - ParameterGroupExtensionHelper.AddParameterGroups(serviceClient); - Extensions.ProcessParameterizedHost(serviceClient, Settings); + Extensions.NormalizeClientModel(serviceClient, Settings); PopulateAdditionalProperties(serviceClient); CodeNamer.NormalizeClientModel(serviceClient); CodeNamer.ResolveNameCollisions(serviceClient, Settings.Namespace, diff --git a/ClientRuntimes/Ruby/ms-rest-azure/lib/ms_rest_azure/azure_service_client.rb b/ClientRuntimes/Ruby/ms-rest-azure/lib/ms_rest_azure/azure_service_client.rb index afa7016bb7c5a..0dc6edd7f97a7 100644 --- a/ClientRuntimes/Ruby/ms-rest-azure/lib/ms_rest_azure/azure_service_client.rb +++ b/ClientRuntimes/Ruby/ms-rest-azure/lib/ms_rest_azure/azure_service_client.rb @@ -122,8 +122,8 @@ def update_state_from_get_resource_operation(request, polling_state, custom_dese fail AzureOperationError, 'The response from long running operation does not contain a body' if result.response.body.nil? || result.response.body.empty? - if result.body.respond_to?(:properties) && result.body.properties.respond_to?(:provisioning_state) && !result.body.properties.provisioning_state.nil? - polling_state.status = result.body.properties.provisioning_state + if result.body.respond_to?(:provisioning_state) && !result.body.provisioning_state.nil? + polling_state.status = result.body.provisioning_state else polling_state.status = AsyncOperationStatus::SUCCESS_STATUS end diff --git a/ClientRuntimes/Ruby/ms-rest-azure/lib/ms_rest_azure/polling_state.rb b/ClientRuntimes/Ruby/ms-rest-azure/lib/ms_rest_azure/polling_state.rb index a9916ef4edcd8..28d4bffab9ff0 100644 --- a/ClientRuntimes/Ruby/ms-rest-azure/lib/ms_rest_azure/polling_state.rb +++ b/ClientRuntimes/Ruby/ms-rest-azure/lib/ms_rest_azure/polling_state.rb @@ -35,8 +35,8 @@ def initialize(azure_response, retry_timeout) update_response(azure_response.response) @resource = azure_response.body - if (!@resource.nil? && @resource.respond_to?(:properties) && @resource.properties.respond_to?(:provisioning_state) && !@resource.properties.provisioning_state.nil?) - @status = @resource.properties.provisioning_state + if (!@resource.nil? && @resource.respond_to?(:provisioning_state) && !@resource.provisioning_state.nil?) + @status = @resource.provisioning_state else case @response.status when 202 diff --git a/ClientRuntimes/Ruby/ms-rest-azure/spec/polling_state_spec.rb b/ClientRuntimes/Ruby/ms-rest-azure/spec/polling_state_spec.rb index 6d2b2e2e69398..899fd898eec47 100644 --- a/ClientRuntimes/Ruby/ms-rest-azure/spec/polling_state_spec.rb +++ b/ClientRuntimes/Ruby/ms-rest-azure/spec/polling_state_spec.rb @@ -9,8 +9,7 @@ module MsRestAzure describe PollingState do it 'should initialize status from response header' do - response_body_properties = double('response_body_properties', :provisioning_state => 'InProgress') - response_body = double('response_body', :properties => response_body_properties) + response_body = double('response_body', :provisioning_state => 'InProgress') response = double('response', :request => nil, :response => nil, diff --git a/ClientRuntimes/Ruby/ms-rest/lib/ms_rest/serialization.rb b/ClientRuntimes/Ruby/ms-rest/lib/ms_rest/serialization.rb index 6772d5d90fde8..a24f02e690ef6 100644 --- a/ClientRuntimes/Ruby/ms-rest/lib/ms_rest/serialization.rb +++ b/ClientRuntimes/Ruby/ms-rest/lib/ms_rest/serialization.rb @@ -158,7 +158,17 @@ def deserialize_composite_type(mapper, response_body, object_name) unless model_props.nil? model_props.each do |key, val| - result.instance_variable_set("@#{key}", deserialize(val, response_body[val[:serialized_name].to_s], object_name)) + sub_response_body = nil + unless val[:serialized_name].to_s.include? '.' + sub_response_body = response_body[val[:serialized_name].to_s] + else + # Flattened properties will be dicovered at deeper level in payload but must be deserialized to higher levels in model class + sub_response_body = response_body + levels = split_serialized_name(val[:serialized_name].to_s) + levels.each { |level| sub_response_body = sub_response_body.nil? ? nil : sub_response_body[level.to_s] } + end + + result.instance_variable_set("@#{key}", deserialize(val, sub_response_body, object_name)) unless sub_response_body.nil? end end result @@ -310,7 +320,20 @@ def serialize_composite_type(mapper, object, object_name) end sub_payload = serialize(value, instance_variable, object_name) - payload[value[:serialized_name].to_s] = sub_payload unless instance_variable.nil? + + unless value[:serialized_name].to_s.include? '.' + payload[value[:serialized_name].to_s] = sub_payload unless instance_variable.nil? + else + # Flattened properties will be discovered at higher levels in model class but must be serialized to deeper level in payload + levels = split_serialized_name(value[:serialized_name].to_s) + last_level = levels.pop + temp_payload = payload + levels.each do |level| + temp_payload[level] = Hash.new unless temp_payload.key?(level) + temp_payload = temp_payload[level] + end + temp_payload[last_level] = sub_payload unless sub_payload.nil? + end end end payload @@ -361,6 +384,28 @@ def enum_is_valid(mapper, enum_value) model = get_model(mapper[:type][:module]) model.constants.any? { |e| model.const_get(e).to_s.downcase == enum_value.downcase } end + + # Splits serialized_name with '.' to compute levels of object hierarchy + # + # @param serialized_name [String] Name to split + # + def split_serialized_name(serialized_name) + result = Array.new + element = '' + + levels = serialized_name.to_s.split('.') + levels.each do |level| + unless level.match(/.*\\$/).nil? + # Flattened properties will be discovered at different levels in model class and response body + element = "#{element}#{level.gsub!('\\','')}." + else + element = "#{element}#{level}" + result.push(element) unless element.empty? + element = '' + end + end + result + end end end end diff --git a/gulpfile.js b/gulpfile.js index 9750f82c8bb89..004603bf2dc52 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -86,7 +86,8 @@ var rubyMappings = { 'http_infrastructure':['../../../TestServer/swagger/httpInfrastructure.json','HttpInfrastructureModule'], 'required_optional':['../../../TestServer/swagger/required-optional.json','RequiredOptionalModule'], 'report':['../../../TestServer/swagger/report.json','ReportModule'], - 'model_flattening':['../../../TestServer/swagger/model-flattening.json', 'ModelFlatteningModule'], + 'model_flattening':['../../../TestServer/swagger/model-flattening.json', 'ModelFlatteningModule'], + 'parameter_flattening':['../../../TestServer/swagger/parameter-flattening.json', 'ParameterFlatteningModule'], 'parameter_grouping':['../../../TestServer/swagger/azure-parameter-grouping.json', 'ParameterGroupingModule'], };