python-boto3/tests/unit/resources/test_response.py

369 lines
12 KiB
Python
Raw Normal View History

2015-11-27 23:25:33 +01:00
# Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the 'License'). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
2021-09-22 18:34:33 +02:00
# https://aws.amazon.com/apache2.0/
2015-11-27 23:25:33 +01:00
#
# or in the 'license' file accompanying this file. This file is
# distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
2021-10-04 19:51:32 +02:00
import pytest
2015-11-27 23:25:33 +01:00
from boto3.resources.base import ResourceMeta, ServiceResource
from boto3.resources.factory import ResourceFactory
2022-05-26 01:13:54 +02:00
from boto3.resources.model import Parameter, ResponseResource
2021-11-03 18:27:47 +01:00
from boto3.resources.response import (
2022-05-26 01:13:54 +02:00
RawHandler,
ResourceHandler,
build_empty_response,
build_identifiers,
2021-11-03 18:27:47 +01:00
)
2022-05-26 01:13:54 +02:00
from boto3.utils import ServiceContext
from tests import BaseTestCase, mock
2015-11-27 23:25:33 +01:00
class TestBuildIdentifiers(BaseTestCase):
def test_build_identifier_from_res_path_scalar(self):
2022-05-26 01:13:54 +02:00
identifiers = [
Parameter(target='Id', source='response', path='Container.Frob.Id')
]
2015-11-27 23:25:33 +01:00
parent = mock.Mock()
params = {}
2022-05-26 01:13:54 +02:00
response = {'Container': {'Frob': {'Id': 'response-path'}}}
2015-11-27 23:25:33 +01:00
values = build_identifiers(identifiers, parent, params, response)
2021-10-04 19:51:32 +02:00
# Verify identifier loaded from responsePath scalar set
assert values[0][1] == 'response-path'
2015-11-27 23:25:33 +01:00
def test_build_identifier_from_res_path_list(self):
2022-05-26 01:13:54 +02:00
identifiers = [
Parameter(
target='Id', source='response', path='Container.Frobs[].Id'
)
]
2015-11-27 23:25:33 +01:00
parent = mock.Mock()
params = {}
2022-05-26 01:13:54 +02:00
response = {'Container': {'Frobs': [{'Id': 'response-path'}]}}
2015-11-27 23:25:33 +01:00
values = build_identifiers(identifiers, parent, params, response)
2021-10-04 19:51:32 +02:00
# Verify identifier loaded from responsePath scalar set
assert values[0][1] == ['response-path']
2015-11-27 23:25:33 +01:00
def test_build_identifier_from_parent_identifier(self):
2022-05-26 01:13:54 +02:00
identifiers = [Parameter(target='Id', source='identifier', name='Id')]
2015-11-27 23:25:33 +01:00
parent = mock.Mock()
parent.id = 'identifier'
params = {}
2022-05-26 01:13:54 +02:00
response = {'Container': {'Frobs': []}}
2015-11-27 23:25:33 +01:00
values = build_identifiers(identifiers, parent, params, response)
2021-10-04 19:51:32 +02:00
# Verify identifier loaded from responsePath scalar set
assert values[0][1] == 'identifier'
2015-11-27 23:25:33 +01:00
def test_build_identifier_from_parent_data_member(self):
2022-05-26 01:13:54 +02:00
identifiers = [Parameter(target='Id', source='data', path='Member')]
2015-11-27 23:25:33 +01:00
parent = mock.Mock()
2022-05-26 01:13:54 +02:00
parent.meta = ResourceMeta('test', data={'Member': 'data-member'})
2015-11-27 23:25:33 +01:00
params = {}
2022-05-26 01:13:54 +02:00
response = {'Container': {'Frobs': []}}
2015-11-27 23:25:33 +01:00
values = build_identifiers(identifiers, parent, params, response)
2021-10-04 19:51:32 +02:00
# Verify identifier loaded from responsePath scalar set
assert values[0][1] == 'data-member'
2015-11-27 23:25:33 +01:00
def test_build_identifier_from_req_param(self):
2022-05-26 01:13:54 +02:00
identifiers = [
Parameter(target='Id', source='requestParameter', path='Param')
]
2015-11-27 23:25:33 +01:00
parent = mock.Mock()
2022-05-26 01:13:54 +02:00
params = {'Param': 'request-param'}
response = {'Container': {'Frobs': []}}
2015-11-27 23:25:33 +01:00
values = build_identifiers(identifiers, parent, params, response)
2021-10-04 19:51:32 +02:00
# Verify identifier loaded from responsePath scalar set
assert values[0][1] == 'request-param'
2015-11-27 23:25:33 +01:00
def test_build_identifier_from_invalid_source_type(self):
identifiers = [Parameter(target='Id', source='invalid')]
parent = mock.Mock()
params = {}
2022-05-26 01:13:54 +02:00
response = {'Container': {'Frobs': []}}
2015-11-27 23:25:33 +01:00
2021-10-04 19:51:32 +02:00
with pytest.raises(NotImplementedError):
2015-11-27 23:25:33 +01:00
build_identifiers(identifiers, parent, params, response)
class TestBuildEmptyResponse(BaseTestCase):
def setUp(self):
2022-05-26 01:13:54 +02:00
super().setUp()
2015-11-27 23:25:33 +01:00
self.search_path = ''
self.operation_name = 'GetFrobs'
self.output_shape = mock.Mock()
operation_model = mock.Mock()
operation_model.output_shape = self.output_shape
self.service_model = mock.Mock()
self.service_model.operation_model.return_value = operation_model
def get_response(self):
2022-05-26 01:13:54 +02:00
return build_empty_response(
self.search_path, self.operation_name, self.service_model
)
2015-11-27 23:25:33 +01:00
def test_empty_structure(self):
self.output_shape.type_name = 'structure'
response = self.get_response()
2021-10-04 19:51:32 +02:00
# Structure should default to empty dictionary
assert isinstance(response, dict)
assert response == {}
2015-11-27 23:25:33 +01:00
def test_empty_list(self):
self.output_shape.type_name = 'list'
response = self.get_response()
2021-10-04 19:51:32 +02:00
assert isinstance(response, list)
assert len(response) == 0
2015-11-27 23:25:33 +01:00
def test_empty_map(self):
self.output_shape.type_name = 'map'
response = self.get_response()
2021-10-04 19:51:32 +02:00
assert isinstance(response, dict)
assert response == {}
2015-11-27 23:25:33 +01:00
def test_empty_string(self):
2021-10-04 19:51:32 +02:00
self.output_shape.type_name = "string"
2015-11-27 23:25:33 +01:00
response = self.get_response()
2021-10-04 19:51:32 +02:00
assert response is None
2015-11-27 23:25:33 +01:00
def test_empty_integer(self):
2021-10-04 19:51:32 +02:00
self.output_shape.type_name = "integer"
2015-11-27 23:25:33 +01:00
response = self.get_response()
2021-10-04 19:51:32 +02:00
assert response is None
2015-11-27 23:25:33 +01:00
2021-10-04 19:51:32 +02:00
def test_empty_unknown_returns_none(self):
self.output_shape.type_name = "invalid"
2015-11-27 23:25:33 +01:00
response = self.get_response()
2021-10-04 19:51:32 +02:00
assert response is None
2015-11-27 23:25:33 +01:00
def test_path_structure(self):
self.search_path = 'Container.Frob'
frob = mock.Mock()
frob.type_name = 'integer'
container = mock.Mock()
container.type_name = 'structure'
2022-05-26 01:13:54 +02:00
container.members = {'Frob': frob}
2015-11-27 23:25:33 +01:00
self.output_shape.type_name = 'structure'
2022-05-26 01:13:54 +02:00
self.output_shape.members = {'Container': container}
2015-11-27 23:25:33 +01:00
response = self.get_response()
2021-10-04 19:51:32 +02:00
assert response is None
2015-11-27 23:25:33 +01:00
def test_path_list(self):
self.search_path = 'Container[1].Frob'
frob = mock.Mock()
frob.type_name = 'integer'
container = mock.Mock()
container.type_name = 'list'
container.member = frob
self.output_shape.type_name = 'structure'
2022-05-26 01:13:54 +02:00
self.output_shape.members = {'Container': container}
2015-11-27 23:25:33 +01:00
response = self.get_response()
2021-10-04 19:51:32 +02:00
assert response is None
2015-11-27 23:25:33 +01:00
def test_path_invalid(self):
self.search_path = 'Container.Invalid'
container = mock.Mock()
container.type_name = 'invalid'
self.output_shape.type_name = 'structure'
2022-05-26 01:13:54 +02:00
self.output_shape.members = {'Container': container}
2015-11-27 23:25:33 +01:00
2021-10-04 19:51:32 +02:00
with pytest.raises(NotImplementedError):
2015-11-27 23:25:33 +01:00
self.get_response()
class TestRawHandler(BaseTestCase):
def test_raw_handler_response(self):
parent = mock.Mock()
params = {}
2022-05-26 01:13:54 +02:00
response = {'Id': 'foo'}
2015-11-27 23:25:33 +01:00
handler = RawHandler(search_path=None)
parsed_response = handler(parent, params, response)
2021-10-04 19:51:32 +02:00
# verify response is unmodified
assert parsed_response == response
2015-11-27 23:25:33 +01:00
def test_raw_handler_response_path(self):
parent = mock.Mock()
params = {}
2022-05-26 01:13:54 +02:00
frob = {'Id': 'foo'}
response = {'Container': {'Frob': frob}}
2015-11-27 23:25:33 +01:00
handler = RawHandler(search_path='Container.Frob')
parsed_response = handler(parent, params, response)
2021-10-04 19:51:32 +02:00
assert parsed_response == frob
2015-11-27 23:25:33 +01:00
class TestResourceHandler(BaseTestCase):
def setUp(self):
2022-05-26 01:13:54 +02:00
super().setUp()
2015-11-27 23:25:33 +01:00
self.identifier_path = ''
self.factory = ResourceFactory(mock.Mock())
self.resource_defs = {
2022-05-26 01:13:54 +02:00
'Frob': {'shape': 'Frob', 'identifiers': [{'name': 'Id'}]}
2015-11-27 23:25:33 +01:00
}
self.service_model = mock.Mock()
shape = mock.Mock()
shape.members = {}
self.service_model.shape_for.return_value = shape
frobs = mock.Mock()
frobs.type_name = 'list'
container = mock.Mock()
container.type_name = 'structure'
2022-05-26 01:13:54 +02:00
container.members = {'Frobs': frobs}
2015-11-27 23:25:33 +01:00
self.output_shape = mock.Mock()
self.output_shape.type_name = 'structure'
2022-05-26 01:13:54 +02:00
self.output_shape.members = {'Container': container}
2015-11-27 23:25:33 +01:00
operation_model = mock.Mock()
operation_model.output_shape = self.output_shape
self.service_model.operation_model.return_value = operation_model
self.parent = mock.Mock()
self.parent.meta = ResourceMeta('test', client=mock.Mock())
self.params = {}
def get_resource(self, search_path, response):
request_resource_def = {
'type': 'Frob',
'identifiers': [
2022-05-26 01:13:54 +02:00
{
'target': 'Id',
'source': 'response',
'path': self.identifier_path,
},
],
2015-11-27 23:25:33 +01:00
}
resource_model = ResponseResource(
2022-05-26 01:13:54 +02:00
request_resource_def, self.resource_defs
)
2015-11-27 23:25:33 +01:00
handler = ResourceHandler(
2022-05-26 01:13:54 +02:00
search_path=search_path,
factory=self.factory,
2015-11-27 23:25:33 +01:00
resource_model=resource_model,
service_context=ServiceContext(
service_name='myservice',
resource_json_definitions=self.resource_defs,
service_model=self.service_model,
2022-05-26 01:13:54 +02:00
service_waiter_model=None,
2015-11-27 23:25:33 +01:00
),
2022-05-26 01:13:54 +02:00
operation_name='GetFrobs',
2015-11-27 23:25:33 +01:00
)
return handler(self.parent, self.params, response)
def test_create_resource_scalar(self):
self.identifier_path = 'Container.Id'
search_path = 'Container'
response = {
'Container': {
'Id': 'a-frob',
'OtherValue': 'other',
}
}
resource = self.get_resource(search_path, response)
2021-10-04 19:51:32 +02:00
assert isinstance(resource, ServiceResource)
2015-11-27 23:25:33 +01:00
@mock.patch('boto3.resources.response.build_empty_response')
def test_missing_data_scalar_builds_empty_response(self, build_mock):
self.identifier_path = 'Container.Id'
search_path = 'Container'
2022-05-26 01:13:54 +02:00
response = {'something': 'irrelevant'}
2015-11-27 23:25:33 +01:00
resources = self.get_resource(search_path, response)
2021-10-04 19:51:32 +02:00
assert build_mock.called
assert resources == build_mock.return_value
2015-11-27 23:25:33 +01:00
def test_create_resource_list(self):
self.identifier_path = 'Container.Frobs[].Id'
search_path = 'Container.Frobs[]'
response = {
'Container': {
'Frobs': [
{
'Id': 'a-frob',
'OtherValue': 'other',
},
{
'Id': 'another-frob',
'OtherValue': 'foo',
2022-05-26 01:13:54 +02:00
},
2015-11-27 23:25:33 +01:00
]
}
}
resources = self.get_resource(search_path, response)
2021-10-04 19:51:32 +02:00
assert isinstance(resources, list)
assert len(resources) == 2
assert isinstance(resources[0], ServiceResource)
2015-11-27 23:25:33 +01:00
def test_create_resource_list_no_search_path(self):
self.identifier_path = '[].Id'
search_path = ''
2022-05-26 01:13:54 +02:00
response = [{'Id': 'a-frob', 'OtherValue': 'other'}]
2015-11-27 23:25:33 +01:00
resources = self.get_resource(search_path, response)
2021-10-04 19:51:32 +02:00
assert isinstance(resources, list)
assert len(resources) == 1
assert isinstance(resources[0], ServiceResource)
2015-11-27 23:25:33 +01:00
@mock.patch('boto3.resources.response.build_empty_response')
def test_missing_data_list_builds_empty_response(self, build_mock):
self.identifier_path = 'Container.Frobs[].Id'
search_path = 'Container.Frobs[]'
2022-05-26 01:13:54 +02:00
response = {'something': 'irrelevant'}
2015-11-27 23:25:33 +01:00
resources = self.get_resource(search_path, response)
2021-10-04 19:51:32 +02:00
assert build_mock.called, 'build_empty_response was never called'
assert resources == build_mock.return_value