blob: af370cbc5c1d10673642c61065bcd69f938c6e5c [file] [log] [blame]
Matteo Scandolo6739b512018-05-30 18:55:29 -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
Scott Bakere9855012019-04-01 15:01:34 -070015#from __future__ import absolute_import
16
17import imp
Matteo Scandolo6739b512018-05-30 18:55:29 -070018import unittest
Matteo Scandolodb7adc32018-06-15 16:05:19 -070019import urllib
Matteo Scandolo6739b512018-05-30 18:55:29 -070020import functools
Scott Baker91bf91b2019-03-15 16:13:51 -070021from mock import patch, Mock
Matteo Scandolo6739b512018-05-30 18:55:29 -070022import requests_mock
Matteo Scandolo6739b512018-05-30 18:55:29 -070023
Scott Baker91bf91b2019-03-15 16:13:51 -070024import os
25import sys
Matteo Scandolo6739b512018-05-30 18:55:29 -070026
Scott Baker91bf91b2019-03-15 16:13:51 -070027test_path = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
28
Matteo Scandolo6739b512018-05-30 18:55:29 -070029
30def match_json(desired, req):
Scott Baker91bf91b2019-03-15 16:13:51 -070031 if desired != req.json():
Matteo Scandolo6739b512018-05-30 18:55:29 -070032 raise Exception("Got request %s, but body is not matching" % req.url)
33 return False
34 return True
35
Scott Bakere9855012019-04-01 15:01:34 -070036
Matteo Scandolo6739b512018-05-30 18:55:29 -070037class TestSyncFabricPort(unittest.TestCase):
38
39 def setUp(self):
40 global DeferredException
41
42 self.sys_path_save = sys.path
Matteo Scandolo6739b512018-05-30 18:55:29 -070043
44 # Setting up the config module
45 from xosconfig import Config
46 config = os.path.join(test_path, "../test_config.yaml")
47 Config.clear()
48 Config.init(config, "synchronizer-config-schema.yaml")
49 # END Setting up the config module
50
Scott Baker382366d2019-02-04 10:58:43 -080051 from xossynchronizer.mock_modelaccessor_build import mock_modelaccessor_config
52 mock_modelaccessor_config(test_path, [("fabric", "fabric.xproto")])
Matteo Scandolo6739b512018-05-30 18:55:29 -070053
Scott Baker382366d2019-02-04 10:58:43 -080054 import xossynchronizer.modelaccessor
55 import mock_modelaccessor
Scott Bakere9855012019-04-01 15:01:34 -070056 imp.reload(mock_modelaccessor) # in case nose2 loaded it in a previous test
57 imp.reload(xossynchronizer.modelaccessor) # in case nose2 loaded it in a previous test
Scott Baker382366d2019-02-04 10:58:43 -080058
59 from xossynchronizer.modelaccessor import model_accessor
60 self.model_accessor = model_accessor
61
62 from sync_fabric_port import SyncFabricPort
Matteo Scandolo6739b512018-05-30 18:55:29 -070063
64 # import all class names to globals
65 for (k, v) in model_accessor.all_model_classes.items():
66 globals()[k] = v
67
Matteo Scandolo6739b512018-05-30 18:55:29 -070068 self.sync_step = SyncFabricPort
69 self.sync_step.log = Mock()
70
Matteo Scandolo6739b512018-05-30 18:55:29 -070071 # mock onos-fabric
72 onos_fabric = Mock()
73 onos_fabric.name = "onos-fabric"
74 onos_fabric.rest_hostname = "onos-fabric"
75 onos_fabric.rest_port = "8181"
76 onos_fabric.rest_username = "onos"
77 onos_fabric.rest_password = "rocks"
78
79 onos_fabric_base = Mock()
80 onos_fabric_base.leaf_model = onos_fabric
81
82 self.fabric = Mock()
83 self.fabric.name = "fabric"
Scott Bakerafdf11d2018-08-16 15:47:55 -070084 self.fabric.provider_services = [onos_fabric_base]
Matteo Scandolo6739b512018-05-30 18:55:29 -070085
Matteo Scandolo6739b512018-05-30 18:55:29 -070086 def tearDown(self):
Matteo Scandolo6739b512018-05-30 18:55:29 -070087 sys.path = self.sys_path_save
88
89 @requests_mock.Mocker()
90 def test_sync_port(self, m):
Luca Prete15377872018-09-11 17:32:55 -070091 # IPs
92 ip1 = Mock()
93 ip1.ip = "1.1.1.1/16"
94 ip1.description = "My IPv4 ip"
95 ip2 = Mock()
96 ip2.ip = "2001:0db8:85a3:0000:0000:8a2e:0370:7334/64"
97 ip2.description = "My IPv6 ip"
98 ip3 = Mock()
99 ip3.ip = "2.2.2.2/8"
100 ip3.description = "My other IPv4 ip"
101
Matteo Scandolo6739b512018-05-30 18:55:29 -0700102 intf1 = Mock()
103 intf1.name = "intf1"
Matteo Scandolo6739b512018-05-30 18:55:29 -0700104 intf1.vlanUntagged = None
Luca Prete15377872018-09-11 17:32:55 -0700105 intf1.ips.all.return_value = [ip1, ip2]
106 intf2 = Mock()
107 intf2.name = "intf2"
108 intf2.vlanUntagged = 42
109 intf2.ips.all.return_value = [ip3]
Matteo Scandolo6739b512018-05-30 18:55:29 -0700110
Luca Prete15377872018-09-11 17:32:55 -0700111 port = Mock()
112 port.id = 1
113 port.tologdict.return_value = {}
114 port.host_learning = True
115 port.interfaces.all.return_value = [intf1, intf2]
116 port.switch.ofId = "of:1234"
117 port.portId = "1"
Scott Baker91bf91b2019-03-15 16:13:51 -0700118 port.admin_state = "enabled"
Matteo Scandolo6739b512018-05-30 18:55:29 -0700119
120 expected_conf = {
121 "ports": {
Luca Prete15377872018-09-11 17:32:55 -0700122 "%s/%s" % (port.switch.ofId, port.portId): {
Matteo Scandolo6739b512018-05-30 18:55:29 -0700123 "interfaces": [
124 {
125 "name": intf1.name,
Scott Baker91bf91b2019-03-15 16:13:51 -0700126 "ips": [ip1.ip, ip2.ip]
Luca Prete15377872018-09-11 17:32:55 -0700127 },
128 {
129 "name": intf2.name,
130 "ips": [ip3.ip],
131 "vlan-untagged": intf2.vlanUntagged
Matteo Scandolo6739b512018-05-30 18:55:29 -0700132 }
Matteo Scandolodfe75ff2018-06-15 10:52:09 -0700133 ],
134 "hostLearning": {
Luca Prete15377872018-09-11 17:32:55 -0700135 "enabled": port.host_learning
Matteo Scandolodfe75ff2018-06-15 10:52:09 -0700136 }
Matteo Scandolo6739b512018-05-30 18:55:29 -0700137 }
138 }
139 }
140
141 m.post("http://onos-fabric:8181/onos/v1/network/configuration/",
142 status_code=200,
143 additional_matcher=functools.partial(match_json, expected_conf))
144
Scott Baker91bf91b2019-03-15 16:13:51 -0700145 expected_activation = {"enabled": True}
146
147 m.post("http://onos-fabric:8181/onos/v1/devices/%s/portstate/%s" % (port.switch.ofId, port.portId),
148 status_code=200,
149 additional_matcher=functools.partial(match_json, expected_activation))
150
151 with patch.object(Service.objects, "get") as onos_fabric_get:
152 onos_fabric_get.return_value = self.fabric
153 self.sync_step(model_accessor=self.model_accessor).sync_record(port)
154 self.assertTrue(m.called)
155
156 @requests_mock.Mocker()
157 def test_sync_port_disabled(self, m):
158 # IPs
159 ip1 = Mock()
160 ip1.ip = "1.1.1.1/16"
161 ip1.description = "My IPv4 ip"
162 ip2 = Mock()
163 ip2.ip = "2001:0db8:85a3:0000:0000:8a2e:0370:7334/64"
164 ip2.description = "My IPv6 ip"
165 ip3 = Mock()
166 ip3.ip = "2.2.2.2/8"
167 ip3.description = "My other IPv4 ip"
168
169 intf1 = Mock()
170 intf1.name = "intf1"
171 intf1.vlanUntagged = None
172 intf1.ips.all.return_value = [ip1, ip2]
173 intf2 = Mock()
174 intf2.name = "intf2"
175 intf2.vlanUntagged = 42
176 intf2.ips.all.return_value = [ip3]
177
178 port = Mock()
179 port.id = 1
180 port.tologdict.return_value = {}
181 port.host_learning = True
182 port.interfaces.all.return_value = [intf1, intf2]
183 port.switch.ofId = "of:1234"
184 port.portId = "1"
185 port.admin_state = "disabled"
186
187 expected_conf = {
188 "ports": {
189 "%s/%s" % (port.switch.ofId, port.portId): {
190 "interfaces": [
191 {
192 "name": intf1.name,
193 "ips": [ip1.ip, ip2.ip]
194 },
195 {
196 "name": intf2.name,
197 "ips": [ip3.ip],
198 "vlan-untagged": intf2.vlanUntagged
199 }
200 ],
201 "hostLearning": {
202 "enabled": port.host_learning
203 }
204 }
205 }
206 }
207
208 m.post("http://onos-fabric:8181/onos/v1/network/configuration/",
209 status_code=200,
210 additional_matcher=functools.partial(match_json, expected_conf))
211
212 expected_activation = {"enabled": False}
213
214 m.post("http://onos-fabric:8181/onos/v1/devices/%s/portstate/%s" % (port.switch.ofId, port.portId),
215 status_code=200,
216 additional_matcher=functools.partial(match_json, expected_activation))
217
Matteo Scandolo6739b512018-05-30 18:55:29 -0700218 with patch.object(Service.objects, "get") as onos_fabric_get:
219 onos_fabric_get.return_value = self.fabric
Scott Baker382366d2019-02-04 10:58:43 -0800220 self.sync_step(model_accessor=self.model_accessor).sync_record(port)
Matteo Scandolo6739b512018-05-30 18:55:29 -0700221 self.assertTrue(m.called)
222
223 @requests_mock.Mocker()
224 def test_delete_port(self, m):
Luca Prete15377872018-09-11 17:32:55 -0700225 # create a mock SwitchPort instance
226 port = Mock()
227 port.id = 1
228 port.tologdict.return_value = {}
229 port.host_learning = True
230 port.switch.ofId = "of:1234"
231 port.portId = "1"
Matteo Scandolo6739b512018-05-30 18:55:29 -0700232
Matteo Scandolodb7adc32018-06-15 16:05:19 -0700233 key = urllib.quote("of:1234/1", safe='')
Matteo Scandolodb7adc32018-06-15 16:05:19 -0700234 m.delete("http://onos-fabric:8181/onos/v1/network/configuration/ports/%s" % key,
Scott Baker91bf91b2019-03-15 16:13:51 -0700235 status_code=204)
Matteo Scandolodb7adc32018-06-15 16:05:19 -0700236
Matteo Scandolo6739b512018-05-30 18:55:29 -0700237 with patch.object(Service.objects, "get") as onos_fabric_get:
238 onos_fabric_get.return_value = self.fabric
Scott Baker382366d2019-02-04 10:58:43 -0800239 self.sync_step(model_accessor=self.model_accessor).delete_record(port)
Luca Prete15377872018-09-11 17:32:55 -0700240 self.assertTrue(m.called)
Matteo Scandolo6739b512018-05-30 18:55:29 -0700241
Luca Prete15377872018-09-11 17:32:55 -0700242 @requests_mock.Mocker()
243 def test_delete_interface(self, m):
244 ip1 = Mock()
245 ip1.ip = "1.1.1.1/16"
246 ip1.description = "My IPv4 ip"
247 ip2 = Mock()
248 ip2.ip = "2001:0db8:85a3:0000:0000:8a2e:0370:7334/64"
249 ip2.description = "My IPv6 ip"
Matteo Scandolo6739b512018-05-30 18:55:29 -0700250
Luca Prete15377872018-09-11 17:32:55 -0700251 # interfaces
252 intf1 = Mock()
253 intf1.name = "intf1"
254 intf1.vlanUntagged = None
255 intf1.ips.all.return_value = [ip1, ip2]
256
257 # bindings
258 # create a mock SwitchPort instance
259 interface_to_remove = Mock()
260 interface_to_remove.id = 1
261 interface_to_remove.tologdict.return_value = {}
262 interface_to_remove.leaf_model_name = "PortInterface"
263 interface_to_remove.port.interfaces.all.return_value = [intf1]
264 interface_to_remove.port.switch.ofId = "of:1234"
265 interface_to_remove.port.portId = "1"
266 interface_to_remove.port.host_learning = True
267
268 m.post("http://onos-fabric:8181/onos/v1/network/configuration/", status_code=200)
269
Scott Baker91bf91b2019-03-15 16:13:51 -0700270 m.post("http://onos-fabric:8181/onos/v1/devices/%s/portstate/%s" % (interface_to_remove.port.switch.ofId,
271 interface_to_remove.port.portId),
272 status_code=200)
273
Luca Prete15377872018-09-11 17:32:55 -0700274 with patch.object(Service.objects, "get") as onos_fabric_get:
275 onos_fabric_get.return_value = self.fabric
Scott Baker382366d2019-02-04 10:58:43 -0800276 self.sync_step(model_accessor=self.model_accessor).delete_record(interface_to_remove)
Luca Prete15377872018-09-11 17:32:55 -0700277 self.assertTrue(m.called)
278
279 @requests_mock.Mocker()
280 def test_delete_ip(self, m):
281 ip1 = Mock()
282 ip1.ip = "1.1.1.1/16"
283 ip1.description = "My IPv4 ip"
284
285 intf1 = Mock()
286 intf1.name = "intf1"
287 intf1.vlanUntagged = None
288 intf1.ips.all.return_value = [ip1]
289
290 ip_to_remove = Mock()
291 ip_to_remove.id = 1
292 ip_to_remove.leaf_model_name = "FabricIpAddress"
Scott Baker91bf91b2019-03-15 16:13:51 -0700293 ip_to_remove.interface.port.interfaces.all.return_value = [intf1]
Luca Prete15377872018-09-11 17:32:55 -0700294 ip_to_remove.interface.port.switch.ofId = "of:1234"
295 ip_to_remove.interface.port.portId = "1"
296 ip_to_remove.interface.port.host_learning = True
297
298 m.post("http://onos-fabric:8181/onos/v1/network/configuration/", status_code=200)
299
Scott Baker91bf91b2019-03-15 16:13:51 -0700300 m.post("http://onos-fabric:8181/onos/v1/devices/%s/portstate/%s" % (ip_to_remove.interface.port.switch.ofId,
301 ip_to_remove.interface.port.portId),
302 status_code=200)
303
Luca Prete15377872018-09-11 17:32:55 -0700304 with patch.object(Service.objects, "get") as onos_fabric_get:
305 onos_fabric_get.return_value = self.fabric
Scott Baker382366d2019-02-04 10:58:43 -0800306 self.sync_step(model_accessor=self.model_accessor).delete_record(ip_to_remove)
Scott Bakerafdf11d2018-08-16 15:47:55 -0700307 self.assertTrue(m.called)
Scott Baker382366d2019-02-04 10:58:43 -0800308
Scott Baker91bf91b2019-03-15 16:13:51 -0700309
Scott Baker382366d2019-02-04 10:58:43 -0800310if __name__ == '__main__':
311 unittest.main()