blob: 44f3b919d66f57d50e8ecf6c43aa3f55c33c5458 [file] [log] [blame]
Scott Bakera6c687c2018-07-16 15:08:49 -07001# Copyright 2017-present Open Networking Foundation
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import unittest
16
17import functools
Scott Bakere7b55e42019-04-01 17:18:03 -070018from mock import patch, Mock
Scott Bakera6c687c2018-07-16 15:08:49 -070019import requests_mock
Scott Bakera6c687c2018-07-16 15:08:49 -070020
Scott Bakere7b55e42019-04-01 17:18:03 -070021import os
22import sys
Scott Bakera6c687c2018-07-16 15:08:49 -070023
Scott Bakere7b55e42019-04-01 17:18:03 -070024test_path = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
25
Scott Bakera6c687c2018-07-16 15:08:49 -070026
Scott Baker547dea02018-07-18 15:24:26 -070027def mock_get_westbound_service_instance_properties(props, prop):
28 return props[prop]
Scott Bakera6c687c2018-07-16 15:08:49 -070029
Scott Bakere7b55e42019-04-01 17:18:03 -070030
Scott Bakera6c687c2018-07-16 15:08:49 -070031def match_json(desired, req):
Scott Bakere7b55e42019-04-01 17:18:03 -070032 if desired != req.json():
Scott Bakera6c687c2018-07-16 15:08:49 -070033 raise Exception("Got request %s, but body is not matching" % req.url)
34 return False
35 return True
36
Scott Bakere7b55e42019-04-01 17:18:03 -070037
Scott Baker547dea02018-07-18 15:24:26 -070038class TestSyncFabricCrossconnectServiceInstance(unittest.TestCase):
Scott Bakera6c687c2018-07-16 15:08:49 -070039
40 def setUp(self):
41 global DeferredException
42
43 self.sys_path_save = sys.path
Scott Bakera6c687c2018-07-16 15:08:49 -070044
45 # Setting up the config module
46 from xosconfig import Config
47 config = os.path.join(test_path, "../test_fabric_crossconnect_config.yaml")
48 Config.clear()
49 Config.init(config, "synchronizer-config-schema.yaml")
50 # END Setting up the config module
51
Scott Baker63afcc12019-02-01 15:41:46 -080052 from xossynchronizer.mock_modelaccessor_build import mock_modelaccessor_config
Scott Bakere7b55e42019-04-01 17:18:03 -070053 mock_modelaccessor_config(test_path, [("fabric-crossconnect", "fabric-crossconnect.xproto"), ])
Scott Bakera6c687c2018-07-16 15:08:49 -070054
Scott Baker63afcc12019-02-01 15:41:46 -080055 import xossynchronizer.modelaccessor
56 import mock_modelaccessor
Scott Bakere7b55e42019-04-01 17:18:03 -070057 reload(mock_modelaccessor) # in case nose2 loaded it in a previous test
Scott Baker63afcc12019-02-01 15:41:46 -080058 reload(xossynchronizer.modelaccessor) # in case nose2 loaded it in a previous test
59
60 from xossynchronizer.modelaccessor import model_accessor
61 self.model_accessor = model_accessor
62
63 from sync_fabric_crossconnect_service_instance import SyncFabricCrossconnectServiceInstance, model_accessor, \
64 DeferredException
Scott Bakera6c687c2018-07-16 15:08:49 -070065
66 # import all class names to globals
67 for (k, v) in model_accessor.all_model_classes.items():
68 globals()[k] = v
69
Scott Bakera6c687c2018-07-16 15:08:49 -070070 self.sync_step = SyncFabricCrossconnectServiceInstance
71 self.sync_step.log = Mock()
72
Scott Baker547dea02018-07-18 15:24:26 -070073 # mock onos-fabric
Scott Bakere7b55e42019-04-01 17:18:03 -070074 self.onos_fabric = Service(name="onos-fabric",
75 rest_hostname="onos-fabric",
76 rest_port="8181",
77 rest_username="onos",
78 rest_password="rocks")
Scott Bakera6c687c2018-07-16 15:08:49 -070079
Scott Bakere7b55e42019-04-01 17:18:03 -070080 self.service = FabricCrossconnectService(name="fcservice",
81 provider_services=[self.onos_fabric])
Scott Baker547dea02018-07-18 15:24:26 -070082
83 def mock_westbound(self, fsi, s_tag, switch_datapath_id, switch_port):
84 # Mock out a ServiceInstance so the syncstep can call get_westbound_service_instance_properties on it
85 si = ServiceInstance(id=fsi.id)
86 si.get_westbound_service_instance_properties = functools.partial(
87 mock_get_westbound_service_instance_properties,
88 {"s_tag": s_tag,
89 "switch_datapath_id": switch_datapath_id,
90 "switch_port": switch_port})
91 return si
92
93 def test_format_url(self):
Scott Baker63afcc12019-02-01 15:41:46 -080094 url = self.sync_step(model_accessor=self.model_accessor).format_url("foo.com/bar")
Scott Baker547dea02018-07-18 15:24:26 -070095 self.assertEqual(url, "http://foo.com/bar")
96
Scott Baker63afcc12019-02-01 15:41:46 -080097 url = self.sync_step(model_accessor=self.model_accessor).format_url("http://foo.com/bar")
Scott Baker547dea02018-07-18 15:24:26 -070098 self.assertEqual(url, "http://foo.com/bar")
99
100 def test_make_handle_extract_handle(self):
Scott Baker63afcc12019-02-01 15:41:46 -0800101 h = self.sync_step(model_accessor=self.model_accessor).make_handle(222, "of:0000000000000201")
102 (s_tag, switch_datapath_id) = self.sync_step(model_accessor=self.model_accessor).extract_handle(h)
Scott Baker547dea02018-07-18 15:24:26 -0700103
104 self.assertEqual(s_tag, 222)
Scott Baker82565472018-08-20 11:40:03 -0700105 self.assertEqual(switch_datapath_id, "of:0000000000000201")
Scott Baker547dea02018-07-18 15:24:26 -0700106
107 def test_get_fabric_onos_init(self):
108 fsi = FabricCrossconnectServiceInstance(id=7777, owner=self.service)
109
Scott Baker63afcc12019-02-01 15:41:46 -0800110 d = self.sync_step(model_accessor=self.model_accessor).get_fabric_onos_info(fsi)
Scott Baker547dea02018-07-18 15:24:26 -0700111
112 self.assertEqual(d["url"], "http://onos-fabric:8181")
113 self.assertEqual(d["user"], "onos")
114 self.assertEqual(d["pass"], "rocks")
115
Scott Bakerd443ea72018-08-07 13:50:06 -0700116 def test_range_matches_single(self):
Scott Baker63afcc12019-02-01 15:41:46 -0800117 self.assertTrue(self.sync_step(model_accessor=self.model_accessor).range_matches(123, "123"))
Scott Bakerd443ea72018-08-07 13:50:06 -0700118
119 def test_range_matches_single_incorrect(self):
Scott Baker63afcc12019-02-01 15:41:46 -0800120 self.assertFalse(self.sync_step(model_accessor=self.model_accessor).range_matches(123, "456"))
Scott Bakerd443ea72018-08-07 13:50:06 -0700121
122 def test_range_matches_range(self):
Scott Baker63afcc12019-02-01 15:41:46 -0800123 self.assertTrue(self.sync_step(model_accessor=self.model_accessor).range_matches(123, "122-124"))
Scott Bakerd443ea72018-08-07 13:50:06 -0700124
125 def test_range_matches_range_incorrect(self):
Scott Baker63afcc12019-02-01 15:41:46 -0800126 self.assertFalse(self.sync_step(model_accessor=self.model_accessor).range_matches(123, "110-113"))
Scott Bakerd443ea72018-08-07 13:50:06 -0700127
128 def test_range_matches_any(self):
Scott Baker63afcc12019-02-01 15:41:46 -0800129 self.assertTrue(self.sync_step(model_accessor=self.model_accessor).range_matches(123, "ANY"))
130 self.assertTrue(self.sync_step(model_accessor=self.model_accessor).range_matches(123, "any"))
Scott Bakerd443ea72018-08-07 13:50:06 -0700131
132 def test_find_bng_single(self):
133 with patch.object(BNGPortMapping.objects, "get_items") as bng_objects, \
134 patch.object(self.sync_step, "range_matches") as range_matches:
135 bngmapping = BNGPortMapping(s_tag="111", switch_port=4)
136 bng_objects.return_value = [bngmapping]
137
138 # this should not be called
139 range_matches.return_value = False
140
Scott Baker63afcc12019-02-01 15:41:46 -0800141 found_bng = self.sync_step(model_accessor=self.model_accessor).find_bng(111)
Scott Bakerd443ea72018-08-07 13:50:06 -0700142 self.assertTrue(found_bng)
143 self.assertEqual(found_bng.switch_port, 4)
144
145 range_matches.assert_not_called()
146
147 def test_find_bng_any(self):
148 with patch.object(BNGPortMapping.objects, "get_items") as bng_objects:
149 bngmapping = BNGPortMapping(s_tag="ANY", switch_port=4)
150 bng_objects.return_value = [bngmapping]
151
Scott Baker63afcc12019-02-01 15:41:46 -0800152 found_bng = self.sync_step(model_accessor=self.model_accessor).find_bng(111)
Scott Bakerd443ea72018-08-07 13:50:06 -0700153 self.assertTrue(found_bng)
154 self.assertEqual(found_bng.switch_port, 4)
155
156 def test_find_bng_range(self):
157 with patch.object(BNGPortMapping.objects, "get_items") as bng_objects:
158 bngmapping = BNGPortMapping(s_tag="100-200", switch_port=4)
159 bng_objects.return_value = [bngmapping]
160
Scott Baker63afcc12019-02-01 15:41:46 -0800161 found_bng = self.sync_step(model_accessor=self.model_accessor).find_bng(111)
Scott Bakerd443ea72018-08-07 13:50:06 -0700162 self.assertTrue(found_bng)
163 self.assertEqual(found_bng.switch_port, 4)
Scott Baker547dea02018-07-18 15:24:26 -0700164
165 @requests_mock.Mocker()
166 def test_sync(self, m):
167 with patch.object(ServiceInstance.objects, "get_items") as serviceinstance_objects, \
Scott Bakere7b55e42019-04-01 17:18:03 -0700168 patch.object(BNGPortMapping.objects, "get_items") as bng_objects, \
169 patch.object(FabricCrossconnectServiceInstance, "save") as fcsi_save:
Scott Baker547dea02018-07-18 15:24:26 -0700170
Scott Baker82565472018-08-20 11:40:03 -0700171 fsi = FabricCrossconnectServiceInstance(id=7777, owner=self.service, s_tag=111, source_port=3,
172 switch_datapath_id="of:0000000000000201", updated=1, policed=2)
Scott Baker547dea02018-07-18 15:24:26 -0700173
Scott Baker82565472018-08-20 11:40:03 -0700174 serviceinstance_objects.return_value = [fsi]
Scott Baker547dea02018-07-18 15:24:26 -0700175
Scott Bakerd443ea72018-08-07 13:50:06 -0700176 bngmapping = BNGPortMapping(s_tag="111", switch_port=4)
Scott Baker547dea02018-07-18 15:24:26 -0700177 bng_objects.return_value = [bngmapping]
178
179 desired_data = {"deviceId": "of:0000000000000201",
Scott Bakere7b55e42019-04-01 17:18:03 -0700180 "vlanId": 111,
181 "ports": [3, 4]}
Scott Baker547dea02018-07-18 15:24:26 -0700182
183 m.post("http://onos-fabric:8181/onos/segmentrouting/xconnect",
184 status_code=200,
185 additional_matcher=functools.partial(match_json, desired_data))
186
Scott Baker63afcc12019-02-01 15:41:46 -0800187 self.sync_step(model_accessor=self.model_accessor).sync_record(fsi)
Scott Baker547dea02018-07-18 15:24:26 -0700188 self.assertTrue(m.called)
189
190 self.assertEqual(fsi.backend_handle, "111/of:0000000000000201")
191 fcsi_save.assert_called()
192
193 def test_sync_no_bng_mapping(self):
Scott Bakere7b55e42019-04-01 17:18:03 -0700194 with patch.object(ServiceInstance.objects, "get_items") as serviceinstance_objects:
Scott Baker547dea02018-07-18 15:24:26 -0700195
Scott Baker82565472018-08-20 11:40:03 -0700196 fsi = FabricCrossconnectServiceInstance(id=7777, owner=self.service, s_tag=111, source_port=3,
197 switch_datapath_id="of:0000000000000201", updated=1, policed=2)
Scott Baker547dea02018-07-18 15:24:26 -0700198
Scott Baker82565472018-08-20 11:40:03 -0700199 serviceinstance_objects.return_value = [fsi]
Scott Baker547dea02018-07-18 15:24:26 -0700200
201 with self.assertRaises(Exception) as e:
Scott Baker63afcc12019-02-01 15:41:46 -0800202 self.sync_step(model_accessor=self.model_accessor).sync_record(fsi)
Scott Baker547dea02018-07-18 15:24:26 -0700203
204 self.assertEqual(e.exception.message, "Unable to determine BNG port for s_tag 111")
205
Scott Baker82565472018-08-20 11:40:03 -0700206 def test_sync_not_policed(self):
Scott Bakere7b55e42019-04-01 17:18:03 -0700207 with patch.object(ServiceInstance.objects, "get_items") as serviceinstance_objects:
Scott Baker82565472018-08-20 11:40:03 -0700208
209 fsi = FabricCrossconnectServiceInstance(id=7777, owner=self.service, source_port=3,
210 switch_datapath_id="of:0000000000000201", updated=1, policed=0)
211
212 serviceinstance_objects.return_value = [fsi]
213
214 with self.assertRaises(Exception) as e:
Scott Baker63afcc12019-02-01 15:41:46 -0800215 self.sync_step(model_accessor=self.model_accessor).sync_record(fsi)
Scott Baker82565472018-08-20 11:40:03 -0700216
217 self.assertEqual(e.exception.message, "Waiting for model_policy to run on fcsi 7777")
218
219 def test_sync_no_s_tag(self):
Scott Bakere7b55e42019-04-01 17:18:03 -0700220 with patch.object(ServiceInstance.objects, "get_items") as serviceinstance_objects:
Scott Baker82565472018-08-20 11:40:03 -0700221
222 fsi = FabricCrossconnectServiceInstance(id=7777, owner=self.service, source_port=3,
223 switch_datapath_id="of:0000000000000201", updated=1, policed=2)
224
225 serviceinstance_objects.return_value = [fsi]
226
227 with self.assertRaises(Exception) as e:
Scott Baker63afcc12019-02-01 15:41:46 -0800228 self.sync_step(model_accessor=self.model_accessor).sync_record(fsi)
Scott Baker82565472018-08-20 11:40:03 -0700229
Scott Bakere7b55e42019-04-01 17:18:03 -0700230 self.assertEqual(e.exception.message,
231 "Cannot sync FabricCrossconnectServiceInstance if s_tag is None on fcsi 7777")
Scott Baker82565472018-08-20 11:40:03 -0700232
233 def test_sync_no_switch_datapath_id(self):
Scott Bakere7b55e42019-04-01 17:18:03 -0700234 with patch.object(ServiceInstance.objects, "get_items") as serviceinstance_objects:
Scott Baker82565472018-08-20 11:40:03 -0700235
236 fsi = FabricCrossconnectServiceInstance(id=7777, owner=self.service, source_port=3, s_tag=111,
237 updated=1, policed=2)
238
239 serviceinstance_objects.return_value = [fsi]
240
241 with self.assertRaises(Exception) as e:
Scott Baker63afcc12019-02-01 15:41:46 -0800242 self.sync_step(model_accessor=self.model_accessor).sync_record(fsi)
Scott Baker82565472018-08-20 11:40:03 -0700243
Scott Bakere7b55e42019-04-01 17:18:03 -0700244 self.assertEqual(
245 e.exception.message,
246 "Cannot sync FabricCrossconnectServiceInstance if switch_datapath_id is unset on fcsi 7777")
Scott Baker82565472018-08-20 11:40:03 -0700247
248 def test_sync_no_source_port(self):
Scott Bakere7b55e42019-04-01 17:18:03 -0700249 with patch.object(ServiceInstance.objects, "get_items") as serviceinstance_objects:
Scott Baker82565472018-08-20 11:40:03 -0700250
251 fsi = FabricCrossconnectServiceInstance(id=7777, owner=self.service, s_tag=111,
252 switch_datapath_id="of:0000000000000201", updated=1, policed=2)
253
254 serviceinstance_objects.return_value = [fsi]
255
256 with self.assertRaises(Exception) as e:
Scott Baker63afcc12019-02-01 15:41:46 -0800257 self.sync_step(model_accessor=self.model_accessor).sync_record(fsi)
Scott Baker82565472018-08-20 11:40:03 -0700258
Scott Bakere7b55e42019-04-01 17:18:03 -0700259 self.assertEqual(e.exception.message,
260 "Cannot sync FabricCrossconnectServiceInstance if source_port is None on fcsi 7777")
Scott Baker82565472018-08-20 11:40:03 -0700261
Scott Baker547dea02018-07-18 15:24:26 -0700262 @requests_mock.Mocker()
263 def test_delete(self, m):
Scott Bakere7b55e42019-04-01 17:18:03 -0700264 with patch.object(FabricCrossconnectServiceInstance.objects, "get_items") as fcsi_objects:
Scott Baker547dea02018-07-18 15:24:26 -0700265 fsi = FabricCrossconnectServiceInstance(id=7777, owner=self.service,
266 backend_handle="111/of:0000000000000201",
267 enacted=True)
268
Scott Bakere7b55e42019-04-01 17:18:03 -0700269 fcsi_objects.return_value = [fsi]
Scott Baker547dea02018-07-18 15:24:26 -0700270
271 desired_data = {"deviceId": "of:0000000000000201",
272 "vlanId": 111}
273
274 m.delete("http://onos-fabric:8181/onos/segmentrouting/xconnect",
Scott Bakere7b55e42019-04-01 17:18:03 -0700275 status_code=204,
276 additional_matcher=functools.partial(match_json, desired_data))
Scott Baker547dea02018-07-18 15:24:26 -0700277
Scott Baker63afcc12019-02-01 15:41:46 -0800278 self.sync_step(model_accessor=self.model_accessor).delete_record(fsi)
Scott Baker547dea02018-07-18 15:24:26 -0700279 self.assertTrue(m.called)
280
Scott Bakera6c687c2018-07-16 15:08:49 -0700281 def tearDown(self):
282 self.o = None
283 sys.path = self.sys_path_save
284
Scott Bakere7b55e42019-04-01 17:18:03 -0700285
Scott Bakera6c687c2018-07-16 15:08:49 -0700286if __name__ == '__main__':
287 unittest.main()