@ -14,10 +14,13 @@ import mock
from mock import patch
from oslo_utils import uuidutils
import six
from six . moves import xrange
import unittest
from oslo_config import cfg
import pecan
from tricircle . api import app
from tricircle . api . controllers import pod
from tricircle . api . controllers import routing
from tricircle . common import context
@ -35,6 +38,8 @@ class FakeResponse(object):
class RoutingControllerTest ( unittest . TestCase ) :
def setUp ( self ) :
cfg . CONF . clear ( )
cfg . CONF . register_opts ( app . common_opts )
core . initialize ( )
core . ModelBase . metadata . create_all ( core . get_engine ( ) )
self . controller = routing . RoutingController ( )
@ -49,45 +54,24 @@ class RoutingControllerTest(unittest.TestCase):
def test_post ( self , mock_context ) :
mock_context . return_value = self . context
# prepare the foreign key: pod_id
kw_pod = { ' pod ' : { ' region_name ' : ' pod1 ' , ' az_name ' : ' az1 ' } }
pod_id = pod . PodsController ( ) . post ( * * kw_pod ) [ ' pod ' ] [ ' pod_id ' ]
# a variable used for later test
project_id = uuidutils . generate_uuid ( )
kw_routing = { ' routing ' :
{ ' top_id ' : ' 09fd7cc9-d169-4b5a-88e8-436ecf4d0bfe ' ,
' bottom_id ' : ' dc80f9de-abb7-4ec6-ab7a-94f8fd1e20ef ' ,
' pod_id ' : pod_id ,
' project_id ' : project_id ,
' resource_type ' : ' subnet '
} }
kw_routing = self . _prepare_routing_element ( ' subnet ' )
id = self . controller . post ( * * kw_routing ) [ ' routing ' ] [ ' id ' ]
routing = db_api . get_resource_routing ( self . context , id )
self . assertEqual ( ' 09fd7cc9-d169-4b5a-88e8-436ecf4d0bfe ' ,
routing [ ' top_id ' ] )
self . assertEqual ( ' dc80f9de-abb7-4ec6-ab7a-94f8fd1e20ef ' ,
routing [ ' bottom_id ' ] )
self . assertEqual ( pod_id , routing [ ' pod_id ' ] )
self . assertEqual ( project_id , routing [ ' project_id ' ] )
self . assertEqual ( ' subnet ' , routing [ ' resource_type ' ] )
routings = db_api . list_resource_routings ( self . context ,
[ { ' key ' : ' top_id ' ,
[ { ' key ' : ' resource_type ' ,
' comparator ' : ' eq ' ,
' value ' :
' 09fd7cc9-d169-4b5a- '
' 88e8-436ecf4d0bfe '
' subnet '
} ,
{ ' key ' : ' pod_id ' ,
' comparator ' : ' eq ' ,
' value ' : pod_id }
] , [ ] )
] )
self . assertEqual ( 1 , len ( routings ) )
# failure case, only admin can create resource routing
self . context . is_admin = False
kw_routing = self . _prepare_routing_element ( ' subnet ' )
res = self . controller . post ( * * kw_routing )
self . _validate_error_code ( res , 403 )
@ -95,60 +79,39 @@ class RoutingControllerTest(unittest.TestCase):
# failure case, request body not found
kw_routing1 = { ' route ' :
{ ' top_id ' : ' 109fd7cc9-d169-4b5a-88e8-436ecf4d0bfe ' ,
' bottom_id ' : ' 2dc80f9de-abb7-4ec6-ab7a-94f8fd1e20ef ' ,
' pod_id ' : pod_id ,
' project_id ' : project_id ,
' resource_type ' : ' subnet '
{ ' top_id ' : uuidutils . generate_uuid ( ) ,
' bottom_id ' : uuidutils . generate_uuid ( ) ,
} }
res = self . controller . post ( * * kw_routing1 )
self . _validate_error_code ( res , 400 )
# failure case, top_id is not given
kw_routing2 = { ' routing ' :
{ ' bottom_id ' : ' 2dc80f9de-abb7-4ec6-ab7a-94f8fd1e20ef ' ,
' pod_id ' : pod_id ,
' project_id ' : project_id ,
' resource_type ' : ' subnet '
} }
kw_routing2 = self . _prepare_routing_element ( ' router ' )
kw_routing2 [ ' routing ' ] . pop ( ' top_id ' )
res = self . controller . post ( * * kw_routing2 )
self . _validate_error_code ( res , 400 )
# failure case, top_id is empty
kw_routing3 = { ' routing ' :
{ ' top_id ' : ' ' ,
' bottom_id ' : ' 2dc80f9de-abb7-4ec6-ab7a-94f8fd1e20ef ' ,
' pod_id ' : pod_id ,
' project_id ' : project_id ,
' resource_type ' : ' subnet '
} }
kw_routing3 = self . _prepare_routing_element ( ' router ' )
kw_routing3 [ ' routing ' ] . update ( { ' top_id ' : ' ' } )
res = self . controller . post ( * * kw_routing3 )
self . _validate_error_code ( res , 400 )
# failure case, top_id is given value 'None'
kw_routing4 = { ' routing ' :
{ ' top_id ' : None ,
' bottom_id ' : ' 2dc80f9de-abb7-4ec6-ab7a-94f8fd1e20ef ' ,
' pod_id ' : pod_id ,
' project_id ' : project_id ,
' resource_type ' : ' subnet '
} }
kw_routing4 = self . _prepare_routing_element ( ' security_group ' )
kw_routing4 [ ' routing ' ] . update ( { ' top_id ' : None } )
res = self . controller . post ( * * kw_routing4 )
self . _validate_error_code ( res , 400 )
# failure case, wrong resource type
kw_routing6 = { ' routing ' :
{ ' top_id ' : ' 09fd7cc9-d169-4b5a-88e8-436ecf4d0b09 ' ,
' bottom_id ' : ' dc80f9de-abb7-4ec6-ab7a-94f8fd1e2031f ' ,
' pod_id ' : pod_id ,
' project_id ' : project_id ,
' resource_type ' : ' server '
} }
res = self . controller . post ( * * kw_routing6 )
kw_routing6 = self . _prepare_routing_element ( ' server ' )
self . controller . post ( * * kw_routing6 )
self . _validate_error_code ( res , 400 )
# failure case, the resource routing already exists
res = self . controller . post ( * * kw_routing )
kw_routing7 = self . _prepare_routing_element ( ' router ' )
self . controller . post ( * * kw_routing7 )
res = self . controller . post ( * * kw_routing7 )
self . _validate_error_code ( res , 409 )
@patch . object ( pecan , ' response ' , new = FakeResponse )
@ -156,30 +119,10 @@ class RoutingControllerTest(unittest.TestCase):
def test_get_one ( self , mock_context ) :
mock_context . return_value = self . context
# prepare the foreign key: pod_id
kw_pod = { ' pod ' : { ' region_name ' : ' pod1 ' , ' az_name ' : ' az1 ' } }
pod_id = pod . PodsController ( ) . post ( * * kw_pod ) [ ' pod ' ] [ ' pod_id ' ]
# a variable used for later test
project_id = uuidutils . generate_uuid ( )
kw_routing = { ' routing ' :
{ ' top_id ' : ' 09fd7cc9-d169-4b5a-88e8-436ecf4d0bfe ' ,
' bottom_id ' : ' dc80f9de-abb7-4ec6-ab7a-94f8fd1e20ef ' ,
' pod_id ' : pod_id ,
' project_id ' : project_id ,
' resource_type ' : ' port '
} }
kw_routing = self . _prepare_routing_element ( ' port ' )
id = self . controller . post ( * * kw_routing ) [ ' routing ' ] [ ' id ' ]
routing = self . controller . get_one ( id )
self . assertEqual ( ' 09fd7cc9-d169-4b5a-88e8-436ecf4d0bfe ' ,
routing [ ' routing ' ] [ ' top_id ' ] )
self . assertEqual ( ' dc80f9de-abb7-4ec6-ab7a-94f8fd1e20ef ' ,
routing [ ' routing ' ] [ ' bottom_id ' ] )
self . assertEqual ( pod_id , routing [ ' routing ' ] [ ' pod_id ' ] )
self . assertEqual ( project_id , routing [ ' routing ' ] [ ' project_id ' ] )
self . assertEqual ( ' port ' , routing [ ' routing ' ] [ ' resource_type ' ] )
# failure case, only admin can get resource routing
@ -195,74 +138,131 @@ class RoutingControllerTest(unittest.TestCase):
@patch . object ( pecan , ' response ' , new = FakeResponse )
@patch . object ( context , ' extract_context_from_environ ' )
def test_get_all ( self , mock_context ) :
def test_get_routings_with_pagination ( self , mock_context ) :
mock_context . return_value = self . context
# prepare the foreign key: pod_id
kw_pod1 = { ' pod ' : { ' region_name ' : ' pod1 ' , ' az_name ' : ' az1 ' } }
pod_id1 = pod . PodsController ( ) . post ( * * kw_pod1 ) [ ' pod ' ] [ ' pod_id ' ]
# a variable used for later test
project_id = uuidutils . generate_uuid ( )
kw_routing1 = { ' routing ' :
{ ' top_id ' : ' c7f641c9-8462-4007-84b2-3035d8cfb7a3 ' ,
' bottom_id ' : ' dc80f9de-abb7-4ec6-ab7a-94f8fd1e20ef ' ,
' pod_id ' : pod_id1 ,
' project_id ' : project_id ,
' resource_type ' : ' subnet '
} }
# test when no pagination and filters are applied to the list
# operation, then all of the routings will be retrieved.
for resource_type in ( ' subnet ' , ' router ' , ' security_group ' , ' network ' ) :
kw_routing = self . _prepare_routing_element ( resource_type )
self . controller . post ( * * kw_routing )
# prepare the foreign key: pod_id
kw_pod2 = { ' pod ' : { ' region_name ' : ' pod2 ' , ' az_name ' : ' az1 ' } }
pod_id2 = pod . PodsController ( ) . post ( * * kw_pod2 ) [ ' pod ' ] [ ' pod_id ' ]
kw_routing2 = { ' routing ' :
{ ' top_id ' : ' b669a2da-ca95-47db-a2a9-ba9e546d82ee ' ,
' bottom_id ' : ' fd72c010-6e62-4866-b999-6dcb718dd7b4 ' ,
' pod_id ' : pod_id2 ,
' project_id ' : project_id ,
' resource_type ' : ' port '
} }
self . controller . post ( * * kw_routing1 )
self . controller . post ( * * kw_routing2 )
# no filters are applied to the routings, so all of the routings will
# be retrieved.
routings = self . controller . get_all ( )
actual = [ ( routing [ ' top_id ' ] , routing [ ' pod_id ' ] )
for routing in routings [ ' routings ' ] ]
expect = [ ( ' c7f641c9-8462-4007-84b2-3035d8cfb7a3 ' , pod_id1 ) ,
( ' b669a2da-ca95-47db-a2a9-ba9e546d82ee ' , pod_id2 ) ]
six . assertCountEqual ( self , expect , actual )
# apply a resource type filter to the retrieved routings.
kw_filter1 = { ' resource_type ' : ' port ' }
routings = self . controller . get_all ( * * kw_filter1 )
actual = [ ( routing [ ' top_id ' ] , routing [ ' pod_id ' ] ,
routing [ ' resource_type ' ] )
for routing in routings [ ' routings ' ] ]
expect = [ ( ' b669a2da-ca95-47db-a2a9-ba9e546d82ee ' , pod_id2 , ' port ' ) ]
six . assertCountEqual ( self , expect , actual )
ids = [ routing [ ' id ' ]
for key , values in six . iteritems ( routings )
for routing in values ]
self . assertEqual ( [ 4 , 3 , 2 , 1 ] , ids )
for filter_name in ( ' subnet ' , ' router ' , ' security_group ' , ' network ' ) :
filters = { ' resource_type ' : filter_name }
routings = self . controller . get_all ( * * filters )
items = [ routing [ ' resource_type ' ]
for key , values in six . iteritems ( routings )
for routing in values ]
self . assertEqual ( 1 , len ( items ) )
# test when pagination limit varies in range [1, 5)
for i in xrange ( 1 , 5 ) :
routings = [ ]
total_pages = 0
routing = self . controller . get_all ( limit = i )
total_pages + = 1
routings . extend ( routing [ ' routings ' ] )
while ' routings_links ' in routing :
link = routing [ ' routings_links ' ] [ 0 ] [ ' href ' ]
_ , marker_dict = link . split ( ' & ' )
# link is like '/v1.0/routings?limit=1&marker=1', after split,
# marker_dict is a string like 'marker=1'.
_ , marker_value = marker_dict . split ( ' = ' )
routing = self . controller . get_all ( limit = i , marker = marker_value )
if len ( routing [ ' routings ' ] ) > 0 :
total_pages + = 1
routings . extend ( routing [ ' routings ' ] )
# assert that total pages will decrease as the limit increase.
pages = int ( 4 / i )
if 4 % i :
pages + = 1
self . assertEqual ( pages , total_pages )
self . assertEqual ( 4 , len ( routings ) )
for i in xrange ( 4 ) :
self . assertEqual ( 4 - i , routings [ i ] [ ' id ' ] )
set1 = set ( [ ' subnet ' , ' router ' , ' security_group ' , ' network ' ] )
set2 = set ( [ routing1 [ ' resource_type ' ] for routing1 in routings ] )
self . assertEqual ( set1 , set2 )
# test cases when pagination and filters are used
routings = self . controller . get_all ( resource_type = ' network ' , limit = 1 )
self . assertEqual ( 1 , len ( routings [ ' routings ' ] ) )
routings = self . controller . get_all ( resource_type = ' subnet ' , limit = 2 )
self . assertEqual ( 1 , len ( routings [ ' routings ' ] ) )
# apply a filter and if it doesn't match with any of the retrieved
# routings, then all of them will be discarded and the method returns
# with []
# with [].
kw_filter2 = { ' resource_type ' : ' port2 ' }
routings = self . controller . get_all ( * * kw_filter2 )
self . assertEqual ( [ ] , routings [ ' routings ' ] )
# test cases when limit from client is abnormal
routings = self . controller . get_all ( limit = 0 )
self . assertEqual ( 4 , len ( routings [ ' routings ' ] ) )
routings = self . controller . get_all ( limit = - 1 )
self . assertEqual ( 4 , len ( routings [ ' routings ' ] ) )
res = self . controller . get_all ( limit = ' 20x ' )
self . _validate_error_code ( res , 400 )
# test cases when pagination limit from client is greater than
# max limit
pagination_max_limit_backup = cfg . CONF . pagination_max_limit
cfg . CONF . set_override ( ' pagination_max_limit ' , 2 )
routings = self . controller . get_all ( limit = 3 )
self . assertEqual ( 2 , len ( routings [ ' routings ' ] ) )
cfg . CONF . set_override ( ' pagination_max_limit ' ,
pagination_max_limit_backup )
# test case when marker reaches 1, then no link to next page
routings = self . controller . get_all ( limit = 2 , marker = 3 )
self . assertNotIn ( ' routings_links ' , routings )
# test cases when marker is abnormal
res = self . controller . get_all ( limit = 2 , marker = - 1 )
self . _validate_error_code ( res , 400 )
res = self . controller . get_all ( limit = 2 , marker = 0 )
self . _validate_error_code ( res , 400 )
res = self . controller . get_all ( limit = 2 , marker = " last " )
self . _validate_error_code ( res , 400 )
# failure case, use an unsupported filter type
kw_filter3 = { ' resource ' : ' port ' }
res = self . controller . get_all ( * * kw_filter3 )
self . _validate_error_code ( res , 400 )
kw_filter4 = { ' pod_id ' : pod_id1 ,
kw_filter4 = { ' pod_id ' : " pod_id_ 1" ,
' resource ' : ' port ' }
res = self . controller . get_all ( * * kw_filter4 )
self . _validate_error_code ( res , 400 )
# failure case, id can't be converted to an integer
kw_filter5 = { ' id ' : ' 4s ' }
res = self . controller . get_all ( * * kw_filter5 )
self . _validate_error_code ( res , 400 )
@patch . object ( pecan , ' response ' , new = FakeResponse )
@patch . object ( context , ' extract_context_from_environ ' )
def test_get_all_non_admin ( self , mock_context ) :
mock_context . return_value = self . context
kw_routing1 = self . _prepare_routing_element ( ' subnet ' )
self . controller . post ( * * kw_routing1 )
# failure case, only admin can show all resource routings
self . context . is_admin = False
res = self . controller . get_all ( )
@ -305,7 +305,7 @@ class RoutingControllerTest(unittest.TestCase):
{ ' key ' : ' pod_id ' ,
' comparator ' : ' eq ' ,
' value ' : pod_id
} ] , [ ] )
} ] )
self . assertEqual ( 0 , len ( routings ) )
# failure case, only admin can delete resource routing
@ -325,24 +325,11 @@ class RoutingControllerTest(unittest.TestCase):
def test_put ( self , mock_context ) :
mock_context . return_value = self . context
# prepare the foreign key: pod_id
kw_pod1 = { ' pod ' : { ' region_name ' : ' pod1 ' , ' az_name ' : ' az1 ' } }
pod_id1 = pod . PodsController ( ) . post ( * * kw_pod1 ) [ ' pod ' ] [ ' pod_id ' ]
# a variable used for later test
project_id = uuidutils . generate_uuid ( )
body = { ' routing ' :
{ ' top_id ' : ' c7f641c9-8462-4007-84b2-3035d8cfb7a3 ' ,
' bottom_id ' : ' dc80f9de-abb7-4ec6-ab7a-94f8fd1e20ef ' ,
' pod_id ' : pod_id1 ,
' project_id ' : project_id ,
' resource_type ' : ' router '
} }
body = self . _prepare_routing_element ( ' subnet ' )
# both bottom_id and resource type have been changed
body_update1 = { ' routing ' :
{ ' bottom_id ' : ' fd72c010-6e62-4866-b999-6dcb718dd7b4 ' ,
{ ' bottom_id ' : uuidutils . generate_uuid ( ) ,
' resource_type ' : ' port '
} }
@ -351,9 +338,8 @@ class RoutingControllerTest(unittest.TestCase):
self . assertEqual ( ' port ' ,
routing [ ' routing ' ] [ ' resource_type ' ] )
self . assertEqual ( ' fd72c010-6e62-4866-b999-6dcb718dd7b4 ' ,
self . assertEqual ( body_update1 [ ' routing ' ] [ ' bottom_id ' ] ,
routing [ ' routing ' ] [ ' bottom_id ' ] )
self . assertEqual ( pod_id1 , routing [ ' routing ' ] [ ' pod_id ' ] )
# failure case, only admin can update resource routing
self . context . is_admin = False
@ -364,7 +350,7 @@ class RoutingControllerTest(unittest.TestCase):
# failure case, request body not found
body_update2 = { ' route ' :
{ ' bottom_id ' : ' fd72c010-6e62-4866-b999-6dcb718dd7b4 ' ,
{ ' bottom_id ' : uuidutils . generate_uuid ( ) ,
' resource_type ' : ' port '
} }
res = self . controller . put ( id , * * body_update2 )
@ -401,5 +387,25 @@ class RoutingControllerTest(unittest.TestCase):
res = self . controller . put ( id , * * body_update6 )
self . _validate_error_code ( res , 400 )
def _prepare_routing_element ( self , resource_type ) :
""" Prepare routing fields except id
: return : A Dictionary with top_id , bottom_id , pod_id ,
project_id , resource_type
"""
fake_routing = {
' routing ' : {
' top_id ' : uuidutils . generate_uuid ( ) ,
' bottom_id ' : uuidutils . generate_uuid ( ) ,
' pod_id ' : uuidutils . generate_uuid ( ) ,
' project_id ' : uuidutils . generate_uuid ( ) ,
' resource_type ' : resource_type ,
}
}
return fake_routing
def tearDown ( self ) :
cfg . CONF . unregister_opts ( app . common_opts )
core . ModelBase . metadata . drop_all ( core . get_engine ( ) )