Pecan: Bulk create with one item returns plural
If a bulk create happened with a single item, the pecan code would return back to the user the singular version of the resource in the body. For example, to bulk create many security group rules, the user would give in the body of the request the json with a parent key of "security-group-rules" with a value of a list of json security group rules. If this list is of length one, then after the creation of the one security group rule, the API would return back to the client "security-group-rule" as the parent key. This is not how the legacy wsgi layer behaved. The behavior is expected when nova creates security group rules by calling the neutron API through its deprecated security groups API. Change-Id: I8757630403e4d486cd3c8dd6f041e9ee326ba3b4 Closes-Bug: #1633671
This commit is contained in:
parent
7fdb98cf17
commit
64252405c4
@ -152,7 +152,7 @@ class CollectionsController(utils.NeutronPecanController):
|
|||||||
return self.create(resources)
|
return self.create(resources)
|
||||||
|
|
||||||
def create(self, resources):
|
def create(self, resources):
|
||||||
if len(resources) > 1:
|
if request.context['is_bulk']:
|
||||||
# Bulk!
|
# Bulk!
|
||||||
creator = self.plugin_bulk_creator
|
creator = self.plugin_bulk_creator
|
||||||
key = self.collection
|
key = self.collection
|
||||||
|
@ -63,5 +63,7 @@ class BodyValidationHook(hooks.PecanHook):
|
|||||||
if collection in data:
|
if collection in data:
|
||||||
state.request.context['resources'] = [item[resource] for item in
|
state.request.context['resources'] = [item[resource] for item in
|
||||||
data[collection]]
|
data[collection]]
|
||||||
|
state.request.context['is_bulk'] = True
|
||||||
else:
|
else:
|
||||||
state.request.context['resources'] = [data[resource]]
|
state.request.context['resources'] = [data[resource]]
|
||||||
|
state.request.context['is_bulk'] = False
|
||||||
|
@ -366,6 +366,35 @@ class TestResourceController(TestRootController):
|
|||||||
self._test_method_returns_code('head', 405)
|
self._test_method_returns_code('head', 405)
|
||||||
self._test_method_returns_code('delete', 405)
|
self._test_method_returns_code('delete', 405)
|
||||||
|
|
||||||
|
def test_bulk_create(self):
|
||||||
|
response = self.app.post_json(
|
||||||
|
'/v2.0/ports.json',
|
||||||
|
params={'ports': [{'network_id': self.port['network_id'],
|
||||||
|
'admin_state_up': True,
|
||||||
|
'tenant_id': 'tenid'},
|
||||||
|
{'network_id': self.port['network_id'],
|
||||||
|
'admin_state_up': True,
|
||||||
|
'tenant_id': 'tenid'}]
|
||||||
|
},
|
||||||
|
headers={'X-Project-Id': 'tenid'})
|
||||||
|
self.assertEqual(response.status_int, 201)
|
||||||
|
json_body = jsonutils.loads(response.body)
|
||||||
|
self.assertIn('ports', json_body)
|
||||||
|
self.assertEqual(2, len(json_body['ports']))
|
||||||
|
|
||||||
|
def test_bulk_create_one_item(self):
|
||||||
|
response = self.app.post_json(
|
||||||
|
'/v2.0/ports.json',
|
||||||
|
params={'ports': [{'network_id': self.port['network_id'],
|
||||||
|
'admin_state_up': True,
|
||||||
|
'tenant_id': 'tenid'}]
|
||||||
|
},
|
||||||
|
headers={'X-Project-Id': 'tenid'})
|
||||||
|
self.assertEqual(response.status_int, 201)
|
||||||
|
json_body = jsonutils.loads(response.body)
|
||||||
|
self.assertIn('ports', json_body)
|
||||||
|
self.assertEqual(1, len(json_body['ports']))
|
||||||
|
|
||||||
|
|
||||||
class TestPaginationAndSorting(test_functional.PecanFunctionalTest):
|
class TestPaginationAndSorting(test_functional.PecanFunctionalTest):
|
||||||
|
|
||||||
@ -535,9 +564,11 @@ class TestRequestProcessing(TestRootController):
|
|||||||
self.assertEqual('network', self.captured_context['resource'])
|
self.assertEqual('network', self.captured_context['resource'])
|
||||||
self.assertEqual('networks', self.captured_context['collection'])
|
self.assertEqual('networks', self.captured_context['collection'])
|
||||||
resources = self.captured_context['resources']
|
resources = self.captured_context['resources']
|
||||||
|
is_bulk = self.captured_context['is_bulk']
|
||||||
self.assertEqual(1, len(resources))
|
self.assertEqual(1, len(resources))
|
||||||
self.assertEqual('the_net', resources[0]['name'])
|
self.assertEqual('the_net', resources[0]['name'])
|
||||||
self.assertTrue(resources[0]['admin_state_up'])
|
self.assertTrue(resources[0]['admin_state_up'])
|
||||||
|
self.assertFalse(is_bulk)
|
||||||
|
|
||||||
def test_resource_processing_post_bulk(self):
|
def test_resource_processing_post_bulk(self):
|
||||||
self.app.post_json(
|
self.app.post_json(
|
||||||
@ -548,11 +579,24 @@ class TestRequestProcessing(TestRootController):
|
|||||||
'admin_state_up': False}]},
|
'admin_state_up': False}]},
|
||||||
headers={'X-Project-Id': 'tenid'})
|
headers={'X-Project-Id': 'tenid'})
|
||||||
resources = self.captured_context['resources']
|
resources = self.captured_context['resources']
|
||||||
|
is_bulk = self.captured_context['is_bulk']
|
||||||
self.assertEqual(2, len(resources))
|
self.assertEqual(2, len(resources))
|
||||||
self.assertTrue(resources[0]['admin_state_up'])
|
self.assertTrue(resources[0]['admin_state_up'])
|
||||||
self.assertEqual('the_net_1', resources[0]['name'])
|
self.assertEqual('the_net_1', resources[0]['name'])
|
||||||
self.assertFalse(resources[1]['admin_state_up'])
|
self.assertFalse(resources[1]['admin_state_up'])
|
||||||
self.assertEqual('the_net_2', resources[1]['name'])
|
self.assertEqual('the_net_2', resources[1]['name'])
|
||||||
|
self.assertTrue(is_bulk)
|
||||||
|
|
||||||
|
def test_resource_processing_post_bulk_one_item(self):
|
||||||
|
self.app.post_json(
|
||||||
|
'/v2.0/networks.json',
|
||||||
|
params={'networks': [{'name': 'the_net_1',
|
||||||
|
'admin_state_up': True}]},
|
||||||
|
headers={'X-Project-Id': 'tenid'})
|
||||||
|
resources = self.captured_context['resources']
|
||||||
|
is_bulk = self.captured_context['is_bulk']
|
||||||
|
self.assertEqual(1, len(resources))
|
||||||
|
self.assertTrue(is_bulk)
|
||||||
|
|
||||||
def test_resource_processing_post_unknown_attribute_returns_400(self):
|
def test_resource_processing_post_unknown_attribute_returns_400(self):
|
||||||
response = self.app.post_json(
|
response = self.app.post_json(
|
||||||
|
Loading…
Reference in New Issue
Block a user