blob: 234a04806d2ebe1aec3c9dfd0ed8c5a76c283b9f [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
15import unittest
Matteo Scandolodb7adc32018-06-15 16:05:19 -070016import urllib
Matteo Scandolo6739b512018-05-30 18:55:29 -070017import functools
Scott Baker91bf91b2019-03-15 16:13:51 -070018from mock import patch, Mock
Matteo Scandolo6739b512018-05-30 18:55:29 -070019import requests_mock
Matteo Scandolo6739b512018-05-30 18:55:29 -070020
Scott Baker91bf91b2019-03-15 16:13:51 -070021import os
22import sys
Matteo Scandolo6739b512018-05-30 18:55:29 -070023
Scott Baker91bf91b2019-03-15 16:13:51 -070024test_path = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
25
Matteo Scandolo6739b512018-05-30 18:55:29 -070026
27def match_json(desired, req):
Scott Baker91bf91b2019-03-15 16:13:51 -070028 if desired != req.json():
Matteo Scandolo6739b512018-05-30 18:55:29 -070029 raise Exception("Got request %s, but body is not matching" % req.url)
30 return False
31 return True
32
33class TestSyncFabricPort(unittest.TestCase):
34
35 def setUp(self):
36 global DeferredException
37
38 self.sys_path_save = sys.path
Matteo Scandolo6739b512018-05-30 18:55:29 -070039
40 # Setting up the config module
41 from xosconfig import Config
42 config = os.path.join(test_path, "../test_config.yaml")
43 Config.clear()
44 Config.init(config, "synchronizer-config-schema.yaml")
45 # END Setting up the config module
46
Scott Baker382366d2019-02-04 10:58:43 -080047 from xossynchronizer.mock_modelaccessor_build import mock_modelaccessor_config
48 mock_modelaccessor_config(test_path, [("fabric", "fabric.xproto")])
Matteo Scandolo6739b512018-05-30 18:55:29 -070049
Scott Baker382366d2019-02-04 10:58:43 -080050 import xossynchronizer.modelaccessor
51 import mock_modelaccessor
Scott Baker91bf91b2019-03-15 16:13:51 -070052 reload(mock_modelaccessor) # in case nose2 loaded it in a previous test
53 reload(xossynchronizer.modelaccessor) # in case nose2 loaded it in a previous test
Scott Baker382366d2019-02-04 10:58:43 -080054
55 from xossynchronizer.modelaccessor import model_accessor
56 self.model_accessor = model_accessor
57
58 from sync_fabric_port import SyncFabricPort
Matteo Scandolo6739b512018-05-30 18:55:29 -070059
60 # import all class names to globals
61 for (k, v) in model_accessor.all_model_classes.items():
62 globals()[k] = v
63
Matteo Scandolo6739b512018-05-30 18:55:29 -070064 self.sync_step = SyncFabricPort
65 self.sync_step.log = Mock()
66
Matteo Scandolo6739b512018-05-30 18:55:29 -070067 # mock onos-fabric
68 onos_fabric = Mock()
69 onos_fabric.name = "onos-fabric"
70 onos_fabric.rest_hostname = "onos-fabric"
71 onos_fabric.rest_port = "8181"
72 onos_fabric.rest_username = "onos"
73 onos_fabric.rest_password = "rocks"
74
75 onos_fabric_base = Mock()
76 onos_fabric_base.leaf_model = onos_fabric
77
78 self.fabric = Mock()
79 self.fabric.name = "fabric"
Scott Bakerafdf11d2018-08-16 15:47:55 -070080 self.fabric.provider_services = [onos_fabric_base]
Matteo Scandolo6739b512018-05-30 18:55:29 -070081
Matteo Scandolo6739b512018-05-30 18:55:29 -070082 def tearDown(self):
Matteo Scandolo6739b512018-05-30 18:55:29 -070083 sys.path = self.sys_path_save
84
85 @requests_mock.Mocker()
86 def test_sync_port(self, m):
Luca Prete15377872018-09-11 17:32:55 -070087 # IPs
88 ip1 = Mock()
89 ip1.ip = "1.1.1.1/16"
90 ip1.description = "My IPv4 ip"
91 ip2 = Mock()
92 ip2.ip = "2001:0db8:85a3:0000:0000:8a2e:0370:7334/64"
93 ip2.description = "My IPv6 ip"
94 ip3 = Mock()
95 ip3.ip = "2.2.2.2/8"
96 ip3.description = "My other IPv4 ip"
97
Matteo Scandolo6739b512018-05-30 18:55:29 -070098 intf1 = Mock()
99 intf1.name = "intf1"
Matteo Scandolo6739b512018-05-30 18:55:29 -0700100 intf1.vlanUntagged = None
Luca Prete15377872018-09-11 17:32:55 -0700101 intf1.ips.all.return_value = [ip1, ip2]
102 intf2 = Mock()
103 intf2.name = "intf2"
104 intf2.vlanUntagged = 42
105 intf2.ips.all.return_value = [ip3]
Matteo Scandolo6739b512018-05-30 18:55:29 -0700106
Luca Prete15377872018-09-11 17:32:55 -0700107 port = Mock()
108 port.id = 1
109 port.tologdict.return_value = {}
110 port.host_learning = True
111 port.interfaces.all.return_value = [intf1, intf2]
112 port.switch.ofId = "of:1234"
113 port.portId = "1"
Scott Baker91bf91b2019-03-15 16:13:51 -0700114 port.admin_state = "enabled"
Matteo Scandolo6739b512018-05-30 18:55:29 -0700115
116 expected_conf = {
117 "ports": {
Luca Prete15377872018-09-11 17:32:55 -0700118 "%s/%s" % (port.switch.ofId, port.portId): {
Matteo Scandolo6739b512018-05-30 18:55:29 -0700119 "interfaces": [
120 {
121 "name": intf1.name,
Scott Baker91bf91b2019-03-15 16:13:51 -0700122 "ips": [ip1.ip, ip2.ip]
Luca Prete15377872018-09-11 17:32:55 -0700123 },
124 {
125 "name": intf2.name,
126 "ips": [ip3.ip],
127 "vlan-untagged": intf2.vlanUntagged
Matteo Scandolo6739b512018-05-30 18:55:29 -0700128 }
Matteo Scandolodfe75ff2018-06-15 10:52:09 -0700129 ],
130 "hostLearning": {
Luca Prete15377872018-09-11 17:32:55 -0700131 "enabled": port.host_learning
Matteo Scandolodfe75ff2018-06-15 10:52:09 -0700132 }
Matteo Scandolo6739b512018-05-30 18:55:29 -0700133 }
134 }
135 }
136
137 m.post("http://onos-fabric:8181/onos/v1/network/configuration/",
138 status_code=200,
139 additional_matcher=functools.partial(match_json, expected_conf))
140
Scott Baker91bf91b2019-03-15 16:13:51 -0700141 expected_activation = {"enabled": True}
142
143 m.post("http://onos-fabric:8181/onos/v1/devices/%s/portstate/%s" % (port.switch.ofId, port.portId),
144 status_code=200,
145 additional_matcher=functools.partial(match_json, expected_activation))
146
147 with patch.object(Service.objects, "get") as onos_fabric_get:
148 onos_fabric_get.return_value = self.fabric
149 self.sync_step(model_accessor=self.model_accessor).sync_record(port)
150 self.assertTrue(m.called)
151
152 @requests_mock.Mocker()
153 def test_sync_port_disabled(self, m):
154 # IPs
155 ip1 = Mock()
156 ip1.ip = "1.1.1.1/16"
157 ip1.description = "My IPv4 ip"
158 ip2 = Mock()
159 ip2.ip = "2001:0db8:85a3:0000:0000:8a2e:0370:7334/64"
160 ip2.description = "My IPv6 ip"
161 ip3 = Mock()
162 ip3.ip = "2.2.2.2/8"
163 ip3.description = "My other IPv4 ip"
164
165 intf1 = Mock()
166 intf1.name = "intf1"
167 intf1.vlanUntagged = None
168 intf1.ips.all.return_value = [ip1, ip2]
169 intf2 = Mock()
170 intf2.name = "intf2"
171 intf2.vlanUntagged = 42
172 intf2.ips.all.return_value = [ip3]
173
174 port = Mock()
175 port.id = 1
176 port.tologdict.return_value = {}
177 port.host_learning = True
178 port.interfaces.all.return_value = [intf1, intf2]
179 port.switch.ofId = "of:1234"
180 port.portId = "1"
181 port.admin_state = "disabled"
182
183 expected_conf = {
184 "ports": {
185 "%s/%s" % (port.switch.ofId, port.portId): {
186 "interfaces": [
187 {
188 "name": intf1.name,
189 "ips": [ip1.ip, ip2.ip]
190 },
191 {
192 "name": intf2.name,
193 "ips": [ip3.ip],
194 "vlan-untagged": intf2.vlanUntagged
195 }
196 ],
197 "hostLearning": {
198 "enabled": port.host_learning
199 }
200 }
201 }
202 }
203
204 m.post("http://onos-fabric:8181/onos/v1/network/configuration/",
205 status_code=200,
206 additional_matcher=functools.partial(match_json, expected_conf))
207
208 expected_activation = {"enabled": False}
209
210 m.post("http://onos-fabric:8181/onos/v1/devices/%s/portstate/%s" % (port.switch.ofId, port.portId),
211 status_code=200,
212 additional_matcher=functools.partial(match_json, expected_activation))
213
Matteo Scandolo6739b512018-05-30 18:55:29 -0700214 with patch.object(Service.objects, "get") as onos_fabric_get:
215 onos_fabric_get.return_value = self.fabric
Scott Baker382366d2019-02-04 10:58:43 -0800216 self.sync_step(model_accessor=self.model_accessor).sync_record(port)
Matteo Scandolo6739b512018-05-30 18:55:29 -0700217 self.assertTrue(m.called)
218
219 @requests_mock.Mocker()
220 def test_delete_port(self, m):
Luca Prete15377872018-09-11 17:32:55 -0700221 # create a mock SwitchPort instance
222 port = Mock()
223 port.id = 1
224 port.tologdict.return_value = {}
225 port.host_learning = True
226 port.switch.ofId = "of:1234"
227 port.portId = "1"
Matteo Scandolo6739b512018-05-30 18:55:29 -0700228
Matteo Scandolodb7adc32018-06-15 16:05:19 -0700229 key = urllib.quote("of:1234/1", safe='')
Matteo Scandolodb7adc32018-06-15 16:05:19 -0700230 m.delete("http://onos-fabric:8181/onos/v1/network/configuration/ports/%s" % key,
Scott Baker91bf91b2019-03-15 16:13:51 -0700231 status_code=204)
Matteo Scandolodb7adc32018-06-15 16:05:19 -0700232
Matteo Scandolo6739b512018-05-30 18:55:29 -0700233 with patch.object(Service.objects, "get") as onos_fabric_get:
234 onos_fabric_get.return_value = self.fabric
Scott Baker382366d2019-02-04 10:58:43 -0800235 self.sync_step(model_accessor=self.model_accessor).delete_record(port)
Luca Prete15377872018-09-11 17:32:55 -0700236 self.assertTrue(m.called)
Matteo Scandolo6739b512018-05-30 18:55:29 -0700237
Luca Prete15377872018-09-11 17:32:55 -0700238 @requests_mock.Mocker()
239 def test_delete_interface(self, m):
240 ip1 = Mock()
241 ip1.ip = "1.1.1.1/16"
242 ip1.description = "My IPv4 ip"
243 ip2 = Mock()
244 ip2.ip = "2001:0db8:85a3:0000:0000:8a2e:0370:7334/64"
245 ip2.description = "My IPv6 ip"
Matteo Scandolo6739b512018-05-30 18:55:29 -0700246
Luca Prete15377872018-09-11 17:32:55 -0700247 # interfaces
248 intf1 = Mock()
249 intf1.name = "intf1"
250 intf1.vlanUntagged = None
251 intf1.ips.all.return_value = [ip1, ip2]
252
253 # bindings
254 # create a mock SwitchPort instance
255 interface_to_remove = Mock()
256 interface_to_remove.id = 1
257 interface_to_remove.tologdict.return_value = {}
258 interface_to_remove.leaf_model_name = "PortInterface"
259 interface_to_remove.port.interfaces.all.return_value = [intf1]
260 interface_to_remove.port.switch.ofId = "of:1234"
261 interface_to_remove.port.portId = "1"
262 interface_to_remove.port.host_learning = True
263
264 m.post("http://onos-fabric:8181/onos/v1/network/configuration/", status_code=200)
265
Scott Baker91bf91b2019-03-15 16:13:51 -0700266 m.post("http://onos-fabric:8181/onos/v1/devices/%s/portstate/%s" % (interface_to_remove.port.switch.ofId,
267 interface_to_remove.port.portId),
268 status_code=200)
269
Luca Prete15377872018-09-11 17:32:55 -0700270 with patch.object(Service.objects, "get") as onos_fabric_get:
271 onos_fabric_get.return_value = self.fabric
Scott Baker382366d2019-02-04 10:58:43 -0800272 self.sync_step(model_accessor=self.model_accessor).delete_record(interface_to_remove)
Luca Prete15377872018-09-11 17:32:55 -0700273 self.assertTrue(m.called)
274
275 @requests_mock.Mocker()
276 def test_delete_ip(self, m):
277 ip1 = Mock()
278 ip1.ip = "1.1.1.1/16"
279 ip1.description = "My IPv4 ip"
280
281 intf1 = Mock()
282 intf1.name = "intf1"
283 intf1.vlanUntagged = None
284 intf1.ips.all.return_value = [ip1]
285
286 ip_to_remove = Mock()
287 ip_to_remove.id = 1
288 ip_to_remove.leaf_model_name = "FabricIpAddress"
Scott Baker91bf91b2019-03-15 16:13:51 -0700289 ip_to_remove.interface.port.interfaces.all.return_value = [intf1]
Luca Prete15377872018-09-11 17:32:55 -0700290 ip_to_remove.interface.port.switch.ofId = "of:1234"
291 ip_to_remove.interface.port.portId = "1"
292 ip_to_remove.interface.port.host_learning = True
293
294 m.post("http://onos-fabric:8181/onos/v1/network/configuration/", status_code=200)
295
Scott Baker91bf91b2019-03-15 16:13:51 -0700296 m.post("http://onos-fabric:8181/onos/v1/devices/%s/portstate/%s" % (ip_to_remove.interface.port.switch.ofId,
297 ip_to_remove.interface.port.portId),
298 status_code=200)
299
Luca Prete15377872018-09-11 17:32:55 -0700300 with patch.object(Service.objects, "get") as onos_fabric_get:
301 onos_fabric_get.return_value = self.fabric
Scott Baker382366d2019-02-04 10:58:43 -0800302 self.sync_step(model_accessor=self.model_accessor).delete_record(ip_to_remove)
Scott Bakerafdf11d2018-08-16 15:47:55 -0700303 self.assertTrue(m.called)
Scott Baker382366d2019-02-04 10:58:43 -0800304
Scott Baker91bf91b2019-03-15 16:13:51 -0700305
Scott Baker382366d2019-02-04 10:58:43 -0800306if __name__ == '__main__':
307 unittest.main()