blob: 62c8d5b2cea9018a920aea70ba45815ebc1581fd [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 Baker547dea02018-07-18 15:24:26 -070018from mock import patch, call, Mock, PropertyMock, MagicMock
Scott Bakera6c687c2018-07-16 15:08:49 -070019import requests_mock
20import multistructlog
21from multistructlog import create_logger
22
23import os, sys
24
Scott Bakera6c687c2018-07-16 15:08:49 -070025test_path=os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
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
30def match_json(desired, req):
31 if desired!=req.json():
32 raise Exception("Got request %s, but body is not matching" % req.url)
33 return False
34 return True
35
Scott Baker547dea02018-07-18 15:24:26 -070036class TestSyncFabricCrossconnectServiceInstance(unittest.TestCase):
Scott Bakera6c687c2018-07-16 15:08:49 -070037
38 def setUp(self):
39 global DeferredException
40
41 self.sys_path_save = sys.path
Scott Bakera6c687c2018-07-16 15:08:49 -070042
43 # Setting up the config module
44 from xosconfig import Config
45 config = os.path.join(test_path, "../test_fabric_crossconnect_config.yaml")
46 Config.clear()
47 Config.init(config, "synchronizer-config-schema.yaml")
48 # END Setting up the config module
49
Scott Baker63afcc12019-02-01 15:41:46 -080050 from xossynchronizer.mock_modelaccessor_build import mock_modelaccessor_config
51 mock_modelaccessor_config(test_path, [("fabric-crossconnect", "fabric-crossconnect.xproto"),])
Scott Bakera6c687c2018-07-16 15:08:49 -070052
Scott Baker63afcc12019-02-01 15:41:46 -080053 import xossynchronizer.modelaccessor
54 import mock_modelaccessor
55 reload(mock_modelaccessor) # in case nose2 loaded it in a previous test
56 reload(xossynchronizer.modelaccessor) # in case nose2 loaded it in a previous test
57
58 from xossynchronizer.modelaccessor import model_accessor
59 self.model_accessor = model_accessor
60
61 from sync_fabric_crossconnect_service_instance import SyncFabricCrossconnectServiceInstance, model_accessor, \
62 DeferredException
Scott Bakera6c687c2018-07-16 15:08:49 -070063
64 # import all class names to globals
65 for (k, v) in model_accessor.all_model_classes.items():
66 globals()[k] = v
67
Scott Bakera6c687c2018-07-16 15:08:49 -070068 self.sync_step = SyncFabricCrossconnectServiceInstance
69 self.sync_step.log = Mock()
70
Scott Baker547dea02018-07-18 15:24:26 -070071 # mock onos-fabric
72 self.onos_fabric = Service(name = "onos-fabric",
73 rest_hostname = "onos-fabric",
74 rest_port = "8181",
75 rest_username = "onos",
76 rest_password = "rocks")
Scott Bakera6c687c2018-07-16 15:08:49 -070077
Scott Baker547dea02018-07-18 15:24:26 -070078 self.service = FabricCrossconnectService(name = "fcservice",
79 provider_services = [self.onos_fabric])
80
81 def mock_westbound(self, fsi, s_tag, switch_datapath_id, switch_port):
82 # Mock out a ServiceInstance so the syncstep can call get_westbound_service_instance_properties on it
83 si = ServiceInstance(id=fsi.id)
84 si.get_westbound_service_instance_properties = functools.partial(
85 mock_get_westbound_service_instance_properties,
86 {"s_tag": s_tag,
87 "switch_datapath_id": switch_datapath_id,
88 "switch_port": switch_port})
89 return si
90
91 def test_format_url(self):
Scott Baker63afcc12019-02-01 15:41:46 -080092 url = self.sync_step(model_accessor=self.model_accessor).format_url("foo.com/bar")
Scott Baker547dea02018-07-18 15:24:26 -070093 self.assertEqual(url, "http://foo.com/bar")
94
Scott Baker63afcc12019-02-01 15:41:46 -080095 url = self.sync_step(model_accessor=self.model_accessor).format_url("http://foo.com/bar")
Scott Baker547dea02018-07-18 15:24:26 -070096 self.assertEqual(url, "http://foo.com/bar")
97
98 def test_make_handle_extract_handle(self):
Scott Baker63afcc12019-02-01 15:41:46 -080099 h = self.sync_step(model_accessor=self.model_accessor).make_handle(222, "of:0000000000000201")
100 (s_tag, switch_datapath_id) = self.sync_step(model_accessor=self.model_accessor).extract_handle(h)
Scott Baker547dea02018-07-18 15:24:26 -0700101
102 self.assertEqual(s_tag, 222)
Scott Baker82565472018-08-20 11:40:03 -0700103 self.assertEqual(switch_datapath_id, "of:0000000000000201")
Scott Baker547dea02018-07-18 15:24:26 -0700104
105 def test_get_fabric_onos_init(self):
106 fsi = FabricCrossconnectServiceInstance(id=7777, owner=self.service)
107
Scott Baker63afcc12019-02-01 15:41:46 -0800108 d = self.sync_step(model_accessor=self.model_accessor).get_fabric_onos_info(fsi)
Scott Baker547dea02018-07-18 15:24:26 -0700109
110 self.assertEqual(d["url"], "http://onos-fabric:8181")
111 self.assertEqual(d["user"], "onos")
112 self.assertEqual(d["pass"], "rocks")
113
Scott Bakerd443ea72018-08-07 13:50:06 -0700114 def test_range_matches_single(self):
Scott Baker63afcc12019-02-01 15:41:46 -0800115 self.assertTrue(self.sync_step(model_accessor=self.model_accessor).range_matches(123, "123"))
Scott Bakerd443ea72018-08-07 13:50:06 -0700116
117 def test_range_matches_single_incorrect(self):
Scott Baker63afcc12019-02-01 15:41:46 -0800118 self.assertFalse(self.sync_step(model_accessor=self.model_accessor).range_matches(123, "456"))
Scott Bakerd443ea72018-08-07 13:50:06 -0700119
120 def test_range_matches_range(self):
Scott Baker63afcc12019-02-01 15:41:46 -0800121 self.assertTrue(self.sync_step(model_accessor=self.model_accessor).range_matches(123, "122-124"))
Scott Bakerd443ea72018-08-07 13:50:06 -0700122
123 def test_range_matches_range_incorrect(self):
Scott Baker63afcc12019-02-01 15:41:46 -0800124 self.assertFalse(self.sync_step(model_accessor=self.model_accessor).range_matches(123, "110-113"))
Scott Bakerd443ea72018-08-07 13:50:06 -0700125
126 def test_range_matches_any(self):
Scott Baker63afcc12019-02-01 15:41:46 -0800127 self.assertTrue(self.sync_step(model_accessor=self.model_accessor).range_matches(123, "ANY"))
128 self.assertTrue(self.sync_step(model_accessor=self.model_accessor).range_matches(123, "any"))
Scott Bakerd443ea72018-08-07 13:50:06 -0700129
130 def test_find_bng_single(self):
131 with patch.object(BNGPortMapping.objects, "get_items") as bng_objects, \
132 patch.object(self.sync_step, "range_matches") as range_matches:
133 bngmapping = BNGPortMapping(s_tag="111", switch_port=4)
134 bng_objects.return_value = [bngmapping]
135
136 # this should not be called
137 range_matches.return_value = False
138
Scott Baker63afcc12019-02-01 15:41:46 -0800139 found_bng = self.sync_step(model_accessor=self.model_accessor).find_bng(111)
Scott Bakerd443ea72018-08-07 13:50:06 -0700140 self.assertTrue(found_bng)
141 self.assertEqual(found_bng.switch_port, 4)
142
143 range_matches.assert_not_called()
144
145 def test_find_bng_any(self):
146 with patch.object(BNGPortMapping.objects, "get_items") as bng_objects:
147 bngmapping = BNGPortMapping(s_tag="ANY", switch_port=4)
148 bng_objects.return_value = [bngmapping]
149
Scott Baker63afcc12019-02-01 15:41:46 -0800150 found_bng = self.sync_step(model_accessor=self.model_accessor).find_bng(111)
Scott Bakerd443ea72018-08-07 13:50:06 -0700151 self.assertTrue(found_bng)
152 self.assertEqual(found_bng.switch_port, 4)
153
154 def test_find_bng_range(self):
155 with patch.object(BNGPortMapping.objects, "get_items") as bng_objects:
156 bngmapping = BNGPortMapping(s_tag="100-200", switch_port=4)
157 bng_objects.return_value = [bngmapping]
158
Scott Baker63afcc12019-02-01 15:41:46 -0800159 found_bng = self.sync_step(model_accessor=self.model_accessor).find_bng(111)
Scott Bakerd443ea72018-08-07 13:50:06 -0700160 self.assertTrue(found_bng)
161 self.assertEqual(found_bng.switch_port, 4)
Scott Baker547dea02018-07-18 15:24:26 -0700162
163 @requests_mock.Mocker()
164 def test_sync(self, m):
165 with patch.object(ServiceInstance.objects, "get_items") as serviceinstance_objects, \
166 patch.object(BNGPortMapping.objects, "get_items") as bng_objects, \
167 patch.object(FabricCrossconnectServiceInstance, "save") as fcsi_save:
168
Scott Baker82565472018-08-20 11:40:03 -0700169 fsi = FabricCrossconnectServiceInstance(id=7777, owner=self.service, s_tag=111, source_port=3,
170 switch_datapath_id="of:0000000000000201", updated=1, policed=2)
Scott Baker547dea02018-07-18 15:24:26 -0700171
Scott Baker82565472018-08-20 11:40:03 -0700172 serviceinstance_objects.return_value = [fsi]
Scott Baker547dea02018-07-18 15:24:26 -0700173
Scott Bakerd443ea72018-08-07 13:50:06 -0700174 bngmapping = BNGPortMapping(s_tag="111", switch_port=4)
Scott Baker547dea02018-07-18 15:24:26 -0700175 bng_objects.return_value = [bngmapping]
176
177 desired_data = {"deviceId": "of:0000000000000201",
178 "vlanId": 111,
179 "ports": [3, 4]}
180
181 m.post("http://onos-fabric:8181/onos/segmentrouting/xconnect",
182 status_code=200,
183 additional_matcher=functools.partial(match_json, desired_data))
184
Scott Baker63afcc12019-02-01 15:41:46 -0800185 self.sync_step(model_accessor=self.model_accessor).sync_record(fsi)
Scott Baker547dea02018-07-18 15:24:26 -0700186 self.assertTrue(m.called)
187
188 self.assertEqual(fsi.backend_handle, "111/of:0000000000000201")
189 fcsi_save.assert_called()
190
191 def test_sync_no_bng_mapping(self):
192 with patch.object(ServiceInstance.objects, "get_items") as serviceinstance_objects, \
193 patch.object(FabricCrossconnectServiceInstance, "save") as fcsi_save:
194
Scott Baker82565472018-08-20 11:40:03 -0700195 fsi = FabricCrossconnectServiceInstance(id=7777, owner=self.service, s_tag=111, source_port=3,
196 switch_datapath_id="of:0000000000000201", updated=1, policed=2)
Scott Baker547dea02018-07-18 15:24:26 -0700197
Scott Baker82565472018-08-20 11:40:03 -0700198 serviceinstance_objects.return_value = [fsi]
Scott Baker547dea02018-07-18 15:24:26 -0700199
200 with self.assertRaises(Exception) as e:
Scott Baker63afcc12019-02-01 15:41:46 -0800201 self.sync_step(model_accessor=self.model_accessor).sync_record(fsi)
Scott Baker547dea02018-07-18 15:24:26 -0700202
203 self.assertEqual(e.exception.message, "Unable to determine BNG port for s_tag 111")
204
Scott Baker82565472018-08-20 11:40:03 -0700205 def test_sync_not_policed(self):
206 with patch.object(ServiceInstance.objects, "get_items") as serviceinstance_objects, \
207 patch.object(FabricCrossconnectServiceInstance, "save") as fcsi_save:
208
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):
220 with patch.object(ServiceInstance.objects, "get_items") as serviceinstance_objects, \
221 patch.object(FabricCrossconnectServiceInstance, "save") as fcsi_save:
222
223 fsi = FabricCrossconnectServiceInstance(id=7777, owner=self.service, source_port=3,
224 switch_datapath_id="of:0000000000000201", updated=1, policed=2)
225
226 serviceinstance_objects.return_value = [fsi]
227
228 with self.assertRaises(Exception) as e:
Scott Baker63afcc12019-02-01 15:41:46 -0800229 self.sync_step(model_accessor=self.model_accessor).sync_record(fsi)
Scott Baker82565472018-08-20 11:40:03 -0700230
231 self.assertEqual(e.exception.message, "Cannot sync FabricCrossconnectServiceInstance if s_tag is None on fcsi 7777")
232
233 def test_sync_no_switch_datapath_id(self):
234 with patch.object(ServiceInstance.objects, "get_items") as serviceinstance_objects, \
235 patch.object(FabricCrossconnectServiceInstance, "save") as fcsi_save:
236
237 fsi = FabricCrossconnectServiceInstance(id=7777, owner=self.service, source_port=3, s_tag=111,
238 updated=1, policed=2)
239
240 serviceinstance_objects.return_value = [fsi]
241
242 with self.assertRaises(Exception) as e:
Scott Baker63afcc12019-02-01 15:41:46 -0800243 self.sync_step(model_accessor=self.model_accessor).sync_record(fsi)
Scott Baker82565472018-08-20 11:40:03 -0700244
245 self.assertEqual(e.exception.message, "Cannot sync FabricCrossconnectServiceInstance if switch_datapath_id is unset on fcsi 7777")
246
247 def test_sync_no_source_port(self):
248 with patch.object(ServiceInstance.objects, "get_items") as serviceinstance_objects, \
249 patch.object(FabricCrossconnectServiceInstance, "save") as fcsi_save:
250
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
259 self.assertEqual(e.exception.message, "Cannot sync FabricCrossconnectServiceInstance if source_port is None on fcsi 7777")
260
Scott Baker547dea02018-07-18 15:24:26 -0700261 @requests_mock.Mocker()
262 def test_delete(self, m):
263 with patch.object(FabricCrossconnectServiceInstance.objects, "get_items") as fcsi_objects, \
264 patch.object(FabricCrossconnectServiceInstance, "save") as fcsi_save:
265 fsi = FabricCrossconnectServiceInstance(id=7777, owner=self.service,
266 backend_handle="111/of:0000000000000201",
267 enacted=True)
268
269 fcsi_objects.return_value=[fsi]
270
271 desired_data = {"deviceId": "of:0000000000000201",
272 "vlanId": 111}
273
274 m.delete("http://onos-fabric:8181/onos/segmentrouting/xconnect",
275 status_code=204,
276 additional_matcher=functools.partial(match_json, desired_data))
277
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
285if __name__ == '__main__':
286 unittest.main()