Azure/azure-sdk-for-ruby

[BUG][Face] OperationStatus does not deserialize correctly due to attribute map mismatch

v-jaswel opened this issue · 2 comments

  • Package Name: azure_cognitiveservices_face
  • Package Version: 0.19.1
  • Operating System: Windows 10 Enterprise 1909
  • Ruby Version: ruby 2.6.3p62 (2019-04-16 revision 67580) [x64-mingw32]

Describe the bug
When I take a snapshot and then call client.snapshot_operations.get_operation_status, the server's response is not deserialized into an OperationStatus object correctly.

To Reproduce
Steps to reproduce the behavior:

  1. Run gem install azure_cognitiveservices_face
  2. Run the following code.

Notes:

  1. On line 11 assign FACE_SUBSCRIPTION_KEY your Face subscription key.
  2. On line 17 assign FACE_ENDPOINT your Face endpoint.
  3. On line 19 you might need to change the person group ID in case mine doesn't work for you.
# Install Face package with the following command
# gem install azure_cognitiveservices_face

require 'azure_cognitiveservices_face'
include Azure::CognitiveServices::Face::V1_0::Models

key_var_name = 'FACE_SUBSCRIPTION_KEY'
if nil == ENV[key_var_name]
	raise Exception("Please set/export the environment variable: #{key_var_name}\n")
end
subscription_key = ENV[key_var_name]

endpoint_var_name = 'FACE_ENDPOINT'
if nil == ENV[endpoint_var_name]
	raise Exception("Please set/export the environment variable: #{endpoint_var_name}\n")
end
endpoint = ENV[endpoint_var_name]

person_group_id = 'd776b090-4e07-4687-a6e8-5b0f69b9d5d6'

credentials = MsRestAzure::CognitiveServicesCredentials.new(subscription_key)
client = Azure::CognitiveServices::Face::V1_0::FaceClient.new(credentials)
client.endpoint = endpoint

def wait_for_operation(client, operation_id)
	operation_state = nil
	for i in 1..20
		operation_state = client.snapshot_operations.get_operation_status(operation_id)
		if ["notstarted", "running"].include?(operation_state.status)
			print("Waiting for operation: #{operation_id} to complete.\n")
			sleep(10)
		else
			break
		end
	end
	if operation_state == nil || operation_state.status != "succeeded"
		raise Exception("Operation #{operation_id} failed to complete.")
	end
	return operation_state
end

response = client.snapshot_operations.take_async(
	type="PersonGroup",
	object_id=person_group_id,
	apply_scope=[subscription_key]
	).value!
operation_id = response.response['Operation-Location'].sub! '/operations/', ''
take_status = wait_for_operation(client, operation_id)
snapshot_id = take_status.resource_location.sub! '/snapshots/', ''
print("#{snapshot_id}\n")

Output:

C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/azure_cognitiveservices_face-0.19.1/lib/1.0/generated/azure_cognitiveservices_face/snapshot_operations.rb:193: warning: character class has '-' without escape: /^^[a-z0-9-_]+$$/
C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/ms_rest-0.7.6/lib/ms_rest/serialization.rb:273: warning: character class has '-' without escape: /^^[a-z0-9-_]+$$/
Waiting for operation: 606a1ffe-9538-40a3-b356-f31a812a86cd to complete.
Traceback (most recent call last):
test_snapshot.rb:49:in `<main>': undefined method `sub!' for nil:NilClass (NoMethodError)

Expected behavior

OperationStatus.resource_location should contain a value.

Additional context

See the following related issue.
Azure/azure-sdk-for-net#15120

This issue is happening because of the OperationStatus attribute map, specifically the following line.

The OperationStatus.resource_location property has the serialized name resourceLocation.

However, in the response returned by the server, the corresponding field is "location", not "resourceLocation":

{
  "status": "succeeded",
  "createdDateTime": "2020-09-11T19:41:07.2046017+00:00",
  "location": "/snapshots/e7bde61d-63ef-4c40-9e4f-08ec38bd576e"
}

You can verify this by using API testing consoles, e.g.:
https://westcentralus.dev.cognitive.microsoft.com/docs/services/563879b61984550e40cbbe8d/operations/snapshot-take/console
https://westcentralus.dev.cognitive.microsoft.com/docs/services/563879b61984550e40cbbe8d/operations/operationstatus-get/console
An example operation ID is 5f0ddbe6-82fd-4ae9-a04c-6805c433cf28, though I don't know if that will work for you.

The OperationStatus.resource_location property should be mapped as follows:

              resource_location: {
                client_side_validation: true,
                required: false,
                serialized_name: 'location',
                type: {
                  name: 'String'
                }
              },

Note the created_time property mapping also needs changing. It should have serialized_name createdDateTime.
I made these changes to my local copy of the package (specifically in
C:\Ruby26-x64\lib\ruby\gems\2.6.0\gems\azure_cognitiveservices_face-0.19.1\lib\1.0\generated\azure_cognitiveservices_face\models\operation_status.rb, line 93).
I was then able to run my sample code successfully with the following output.

C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/azure_cognitiveservices_face-0.19.1/lib/1.0/generated/azure_cognitiveservices_face/snapshot_operations.rb:193: warning: character class has '-' without escape: /^^[a-z0-9-_]+$$/
C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/ms_rest-0.7.6/lib/ms_rest/serialization.rb:273: warning: character class has '-' without escape: /^^[a-z0-9-_]+$$/
Waiting for operation: 5062e0c3-d10d-4e38-9a48-2458949c8bea to complete.
7f1f2b2b-a4f5-48c1-bb52-847f14e3c38a

The last line of output is the printed snapshot ID.

Thanks for the feedback! We are routing this to the appropriate team for follow-up. cc @JinyuID, @dipidoo, @SteveMSFT.

Per sbowles, this is going to be fixed on the server side and not the SDK side. Therefore I am closing.