blob: 40f13d88ec3b9c8fa29d1856402b6c0b2413276a [file] [log] [blame]
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -08001# 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 Baker22b46c52018-11-15 15:15:29 -080015from requests import ConnectionError
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -080016import unittest
Matteo Scandolo2ed64b92018-06-18 10:32:56 -070017import functools
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -080018from mock import patch, call, Mock, PropertyMock
19import requests_mock
20
21import os, sys
22
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -080023test_path=os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -080024
Matteo Scandolo2ed64b92018-06-18 10:32:56 -070025def match_json(desired, req):
26 if desired!=req.json():
27 raise Exception("Got request %s, but body is not matching" % req.url)
28 return False
29 return True
30
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -080031class TestSyncOLTDevice(unittest.TestCase):
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -080032 def setUp(self):
Matteo Scandolo6be6ee92018-05-24 15:07:51 -070033 global DeferredException
Matteo Scandoloce27e9c2018-04-06 10:06:53 -070034 self.sys_path_save = sys.path
Matteo Scandoloce27e9c2018-04-06 10:06:53 -070035
36 # Setting up the config module
37 from xosconfig import Config
Matteo Scandolof7ebb112018-09-18 16:17:22 -070038 config = os.path.join(test_path, "../test_config.yaml")
Matteo Scandoloce27e9c2018-04-06 10:06:53 -070039 Config.clear()
40 Config.init(config, "synchronizer-config-schema.yaml")
Luca Preteca974c82018-05-01 18:06:16 -070041 # END setting up the config module
Matteo Scandoloce27e9c2018-04-06 10:06:53 -070042
Scott Baker47b47302019-01-30 16:55:07 -080043 from xossynchronizer.mock_modelaccessor_build import mock_modelaccessor_config
44 mock_modelaccessor_config(test_path, [("olt-service", "volt.xproto"),
Matteo Scandolo35207b72019-05-10 08:46:48 -070045 ("rcord", "rcord.xproto")])
Matteo Scandolo19466a02018-05-16 17:43:39 -070046
Scott Baker47b47302019-01-30 16:55:07 -080047 import xossynchronizer.modelaccessor
48 reload(xossynchronizer.modelaccessor) # in case nose2 loaded it in a previous test
Matteo Scandolo19466a02018-05-16 17:43:39 -070049
Scott Baker47b47302019-01-30 16:55:07 -080050 from xossynchronizer.modelaccessor import model_accessor
51 self.model_accessor = model_accessor
52
Matteo Scandolo2b4c8472019-06-26 18:06:47 -070053 # import all class names to globals
54 for (k, v) in model_accessor.all_model_classes.items():
55 globals()[k] = v
56
Matteo Scandolo6be6ee92018-05-24 15:07:51 -070057 from sync_olt_device import SyncOLTDevice, DeferredException
Matteo Scandoloce27e9c2018-04-06 10:06:53 -070058 self.sync_step = SyncOLTDevice
59
Matteo Scandolob8621cd2018-04-04 17:12:37 -070060 pon_port = Mock()
61 pon_port.port_id = "00ff00"
Matteo Scandolob8621cd2018-04-04 17:12:37 -070062
Matteo Scandolo0d756f22019-06-10 14:55:55 -070063 # create a mock ONOS Service
64 onos = Mock()
65 onos.name = "ONOS"
66 onos.leaf_model.rest_hostname = "onos"
67 onos.leaf_model.rest_port = 4321
68 onos.leaf_model.rest_username = "karaf"
69 onos.leaf_model.rest_password = "karaf"
70
Matteo Scandolo2ed64b92018-06-18 10:32:56 -070071 # Create a mock OLTDevice
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -080072 o = Mock()
73 o.volt_service.voltha_url = "voltha_url"
Luca Preteca974c82018-05-01 18:06:16 -070074 o.volt_service.voltha_port = 1234
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -080075 o.volt_service.voltha_user = "voltha_user"
76 o.volt_service.voltha_pass = "voltha_pass"
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -080077
Matteo Scandolo0d756f22019-06-10 14:55:55 -070078 o.volt_service.provider_services = [onos]
Matteo Scandoloa79395f2018-10-08 13:34:49 -070079
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -080080 o.device_type = "ponsim_olt"
81 o.host = "172.17.0.1"
82 o.port = "50060"
Scott Baker0bbbfd12018-12-11 07:01:06 +000083 o.uplink = "129"
Luca Prete244e6ec2018-07-02 14:30:24 +020084 o.driver = "voltha"
Matteo Scandoloa79395f2018-10-08 13:34:49 -070085 o.name = "Test Device"
Scott Baker09798d82019-01-17 08:34:59 -080086 o.admin_state = "ENABLED"
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -080087
Matteo Scandolob8621cd2018-04-04 17:12:37 -070088 # feedback state
89 o.device_id = None
Matteo Scandolob8621cd2018-04-04 17:12:37 -070090 o.oper_status = None
Scott Baker3581f642019-06-26 14:24:20 -070091 o.serial_number= None
Matteo Scandolob8621cd2018-04-04 17:12:37 -070092 o.of_id = None
Matteo Scandolo096a3cf2018-06-20 13:56:13 -070093 o.id = 1
Matteo Scandolob8621cd2018-04-04 17:12:37 -070094
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -080095 o.tologdict.return_value = {'name': "Mock VOLTServiceInstance"}
96
Andy Bavier00c573c2019-02-08 16:19:11 -070097 o.save_changed_fields.return_value = "Saved"
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -080098
Matteo Scandolo6be6ee92018-05-24 15:07:51 -070099 o.pon_ports.all.return_value = [pon_port]
Matteo Scandolob8621cd2018-04-04 17:12:37 -0700100
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800101 self.o = o
102
Matteo Scandolod6fce512018-10-16 10:35:29 -0700103 self.voltha_devices_response = {"id": "123", "serial_number": "foobar"}
104
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700105 self.tp = TechnologyProfile(
106 technology="xgspon",
107 profile_id=64,
108 profile_value="{}"
109 )
110
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800111 def tearDown(self):
112 self.o = None
Matteo Scandoloce27e9c2018-04-06 10:06:53 -0700113 sys.path = self.sys_path_save
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800114
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800115 @requests_mock.Mocker()
116 def test_get_of_id_from_device(self, m):
117 logical_devices = {
118 "items": [
Matteo Scandolof6337eb2018-04-05 15:58:37 -0700119 {"root_device_id": "123", "id": "0001000ce2314000", "datapath_id": "55334486016"},
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800120 {"root_device_id": "0001cc4974a62b87", "id": "0001000000000001"}
121 ]
122 }
Luca Preteca974c82018-05-01 18:06:16 -0700123 m.get("http://voltha_url:1234/api/v1/logical_devices", status_code=200, json=logical_devices)
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800124 self.o.device_id = "123"
Matteo Scandolof6337eb2018-04-05 15:58:37 -0700125 self.o = self.sync_step.get_ids_from_logical_device(self.o)
126 self.assertEqual(self.o.of_id, "0001000ce2314000")
127 self.assertEqual(self.o.dp_id, "of:0000000ce2314000")
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800128
129 with self.assertRaises(Exception) as e:
130 self.o.device_id = "idonotexist"
Matteo Scandolof6337eb2018-04-05 15:58:37 -0700131 self.sync_step.get_ids_from_logical_device(self.o)
Matteo Scandolo2c144932018-05-04 14:06:24 -0700132 self.assertEqual(e.exception.message, "Can't find a logical_device for OLT device id: idonotexist")
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800133
134 @requests_mock.Mocker()
135 def test_sync_record_fail_add(self, m):
136 """
137 Should print an error if we can't add the device in VOLTHA
138 """
Luca Preteca974c82018-05-01 18:06:16 -0700139 m.post("http://voltha_url:1234/api/v1/devices", status_code=500, text="MockError")
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800140
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700141 with self.assertRaises(Exception) as e, \
142 patch.object(TechnologyProfile.objects, "get") as tp_mock:
143 tp_mock.return_value = self.tp
144
Scott Baker47b47302019-01-30 16:55:07 -0800145 self.sync_step(model_accessor=self.model_accessor).sync_record(self.o)
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700146
Matteo Scandolo2c144932018-05-04 14:06:24 -0700147 self.assertEqual(e.exception.message, "Failed to add OLT device: MockError")
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800148
149 @requests_mock.Mocker()
150 def test_sync_record_fail_no_id(self, m):
151 """
152 Should print an error if VOLTHA does not return the device id
153 """
Luca Preteca974c82018-05-01 18:06:16 -0700154 m.post("http://voltha_url:1234/api/v1/devices", status_code=200, json={"id": ""})
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800155
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700156 with self.assertRaises(Exception) as e, \
157 patch.object(TechnologyProfile.objects, "get") as tp_mock:
158 tp_mock.return_value = self.tp
159
Scott Baker47b47302019-01-30 16:55:07 -0800160 self.sync_step(model_accessor=self.model_accessor).sync_record(self.o)
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700161
Matteo Scandolo2c144932018-05-04 14:06:24 -0700162 self.assertEqual(e.exception.message, "VOLTHA Device Id is empty. This probably means that the OLT device is already provisioned in VOLTHA")
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800163
164 @requests_mock.Mocker()
165 def test_sync_record_fail_enable(self, m):
166 """
167 Should print an error if device.enable fails
168 """
Matteo Scandolod6fce512018-10-16 10:35:29 -0700169 m.post("http://voltha_url:1234/api/v1/devices", status_code=200, json=self.voltha_devices_response)
Luca Preteca974c82018-05-01 18:06:16 -0700170 m.post("http://voltha_url:1234/api/v1/devices/123/enable", status_code=500, text="EnableError")
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800171
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700172 with self.assertRaises(Exception) as e, \
173 patch.object(TechnologyProfile.objects, "get") as tp_mock:
174 tp_mock.return_value = self.tp
175
Scott Baker47b47302019-01-30 16:55:07 -0800176 self.sync_step(model_accessor=self.model_accessor).sync_record(self.o)
Matteo Scandolo2c144932018-05-04 14:06:24 -0700177
178 self.assertEqual(e.exception.message, "Failed to enable OLT device: EnableError")
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800179
180 @requests_mock.Mocker()
181 def test_sync_record_success(self, m):
182 """
183 If device.enable succed should fetch the state, retrieve the of_id and push it to ONOS
184 """
Matteo Scandolo2ed64b92018-06-18 10:32:56 -0700185
186 expected_conf = {
187 "type": self.o.device_type,
188 "host_and_port": "%s:%s" % (self.o.host, self.o.port)
189 }
190
Matteo Scandolod6fce512018-10-16 10:35:29 -0700191 m.post("http://voltha_url:1234/api/v1/devices", status_code=200, json=self.voltha_devices_response, additional_matcher=functools.partial(match_json, expected_conf))
Luca Preteca974c82018-05-01 18:06:16 -0700192 m.post("http://voltha_url:1234/api/v1/devices/123/enable", status_code=200)
Matteo Scandolo45876652018-10-16 16:03:17 -0700193 m.get("http://voltha_url:1234/api/v1/devices/123", json={"oper_status": "ACTIVE", "admin_state": "ENABLED", "serial_number": "foobar"})
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800194 logical_devices = {
195 "items": [
Matteo Scandolof6337eb2018-04-05 15:58:37 -0700196 {"root_device_id": "123", "id": "0001000ce2314000", "datapath_id": "55334486016"},
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800197 {"root_device_id": "0001cc4974a62b87", "id": "0001000000000001"}
198 ]
199 }
Luca Preteca974c82018-05-01 18:06:16 -0700200 m.get("http://voltha_url:1234/api/v1/logical_devices", status_code=200, json=logical_devices)
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800201
Matteo Scandoloa79395f2018-10-08 13:34:49 -0700202 onos_expected_conf = {
203 "devices": {
204 "of:0000000ce2314000": {
205 "basic": {
206 "name": self.o.name
207 }
208 }
209 }
210 }
211 m.post("http://onos:4321/onos/v1/network/configuration/", status_code=200, json=onos_expected_conf,
212 additional_matcher=functools.partial(match_json, onos_expected_conf))
213
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700214 with patch.object(TechnologyProfile.objects, "get") as tp_mock:
215 tp_mock.return_value = self.tp
Scott Baker09798d82019-01-17 08:34:59 -0800216
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700217 self.sync_step(model_accessor=self.model_accessor).sync_record(self.o)
218 self.assertEqual(self.o.admin_state, "ENABLED")
219 self.assertEqual(self.o.oper_status, "ACTIVE")
220 self.assertEqual(self.o.serial_number, "foobar")
221 self.assertEqual(self.o.of_id, "0001000ce2314000")
222
223 # One save during preprovision
224 # One save during activation to set backend_status to "Waiting for device to activate"
225 # One save after activation has succeeded
226 self.assertEqual(self.o.save_changed_fields.call_count, 3)
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800227
228 @requests_mock.Mocker()
Matteo Scandolo2ed64b92018-06-18 10:32:56 -0700229 def test_sync_record_success_mac_address(self, m):
230 """
231 A device should be pre-provisioned via mac_address, the the process is the same
232 """
233
234 del self.o.host
235 del self.o.port
236 self.o.mac_address = "00:0c:e2:31:40:00"
237
238 expected_conf = {
239 "type": self.o.device_type,
240 "mac_address": self.o.mac_address
241 }
242
Matteo Scandoloa79395f2018-10-08 13:34:49 -0700243 onos_expected_conf = {
244 "devices": {
245 "of:0000000ce2314000": {
246 "basic": {
247 "name": self.o.name
248 }
249 }
250 }
251 }
252 m.post("http://onos:4321/onos/v1/network/configuration/", status_code=200, json=onos_expected_conf,
253 additional_matcher=functools.partial(match_json, onos_expected_conf))
254
Matteo Scandolod6fce512018-10-16 10:35:29 -0700255 m.post("http://voltha_url:1234/api/v1/devices", status_code=200, json=self.voltha_devices_response,
Matteo Scandolo2ed64b92018-06-18 10:32:56 -0700256 additional_matcher=functools.partial(match_json, expected_conf))
257 m.post("http://voltha_url:1234/api/v1/devices/123/enable", status_code=200)
Matteo Scandolo45876652018-10-16 16:03:17 -0700258 m.get("http://voltha_url:1234/api/v1/devices/123", json={"oper_status": "ACTIVE", "admin_state": "ENABLED", "serial_number": "foobar"})
Matteo Scandolo2ed64b92018-06-18 10:32:56 -0700259 logical_devices = {
260 "items": [
261 {"root_device_id": "123", "id": "0001000ce2314000", "datapath_id": "55334486016"},
262 {"root_device_id": "0001cc4974a62b87", "id": "0001000000000001"}
263 ]
264 }
265 m.get("http://voltha_url:1234/api/v1/logical_devices", status_code=200, json=logical_devices)
266
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700267 with patch.object(TechnologyProfile.objects, "get") as tp_mock:
268 tp_mock.return_value = self.tp
Scott Baker09798d82019-01-17 08:34:59 -0800269
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700270 self.sync_step(model_accessor=self.model_accessor).sync_record(self.o)
271 self.assertEqual(self.o.admin_state, "ENABLED")
272 self.assertEqual(self.o.oper_status, "ACTIVE")
273 self.assertEqual(self.o.of_id, "0001000ce2314000")
274
275 # One save during preprovision
276 # One save during activation to set backend_status to "Waiting for device to activate"
277 # One save after activation has succeeded
278 self.assertEqual(self.o.save_changed_fields.call_count, 3)
Matteo Scandolo096a3cf2018-06-20 13:56:13 -0700279
280 @requests_mock.Mocker()
281 def test_sync_record_enable_timeout(self, m):
282 """
Scott Baker09798d82019-01-17 08:34:59 -0800283 If device activation fails we need to tell the user.
284
285 OLT will be preprovisioned.
286 OLT will return "ERROR" for oper_status during activate and will eventually exceed retries.s
Matteo Scandolo096a3cf2018-06-20 13:56:13 -0700287 """
288
289 expected_conf = {
290 "type": self.o.device_type,
291 "host_and_port": "%s:%s" % (self.o.host, self.o.port)
292 }
293
Matteo Scandolod6fce512018-10-16 10:35:29 -0700294 m.post("http://voltha_url:1234/api/v1/devices", status_code=200, json=self.voltha_devices_response,
Matteo Scandolo096a3cf2018-06-20 13:56:13 -0700295 additional_matcher=functools.partial(match_json, expected_conf))
296 m.post("http://voltha_url:1234/api/v1/devices/123/enable", status_code=200)
297 m.get("http://voltha_url:1234/api/v1/devices/123", [
Matteo Scandolo45876652018-10-16 16:03:17 -0700298 {"json": {"oper_status": "ACTIVATING", "admin_state": "ENABLED", "serial_number": "foobar"}, "status_code": 200},
Scott Baker09798d82019-01-17 08:34:59 -0800299 {"json": {"oper_status": "ERROR", "admin_state": "ENABLED", "serial_number": "foobar"}, "status_code": 200}
Matteo Scandolo096a3cf2018-06-20 13:56:13 -0700300 ])
301
302 logical_devices = {
303 "items": [
304 {"root_device_id": "123", "id": "0001000ce2314000", "datapath_id": "55334486016"},
305 {"root_device_id": "0001cc4974a62b87", "id": "0001000000000001"}
306 ]
307 }
308 m.get("http://voltha_url:1234/api/v1/logical_devices", status_code=200, json=logical_devices)
309
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700310 with self.assertRaises(Exception) as e, \
311 patch.object(TechnologyProfile.objects, "get") as tp_mock:
312 tp_mock.return_value = self.tp
313
Scott Baker47b47302019-01-30 16:55:07 -0800314 self.sync_step(model_accessor=self.model_accessor).sync_record(self.o)
Matteo Scandolo096a3cf2018-06-20 13:56:13 -0700315
316 self.assertEqual(e.exception.message, "It was not possible to activate OLTDevice with id 1")
317 self.assertEqual(self.o.oper_status, "ERROR")
Scott Baker09798d82019-01-17 08:34:59 -0800318 self.assertEqual(self.o.admin_state, "ENABLED")
319 self.assertEqual(self.o.device_id, "123")
320 self.assertEqual(self.o.serial_number, "foobar")
321
322 # One save from preprovision to set device_id, serial_number
323 # One save from activate to set backend_status to "Waiting for device to be activated"
Andy Bavier00c573c2019-02-08 16:19:11 -0700324 self.assertEqual(self.o.save_changed_fields.call_count, 2)
Matteo Scandolo2ed64b92018-06-18 10:32:56 -0700325
326 @requests_mock.Mocker()
Matteo Scandolob8621cd2018-04-04 17:12:37 -0700327 def test_sync_record_already_existing_in_voltha(self, m):
Scott Baker09798d82019-01-17 08:34:59 -0800328 """
329 If device.admin_state == "ENABLED" and oper_status == "ACTIVE", then the OLT should not be reactivated.
330 """
331
Matteo Scandolob8621cd2018-04-04 17:12:37 -0700332 # mock device feedback state
333 self.o.device_id = "123"
Matteo Scandolo096a3cf2018-06-20 13:56:13 -0700334 self.o.admin_state = "ENABLED"
335 self.o.oper_status = "ACTIVE"
Matteo Scandolof6337eb2018-04-05 15:58:37 -0700336 self.o.dp_id = "of:0000000ce2314000"
Matteo Scandolo2c144932018-05-04 14:06:24 -0700337 self.o.of_id = "0001000ce2314000"
Matteo Scandolob8621cd2018-04-04 17:12:37 -0700338
Matteo Scandoloa79395f2018-10-08 13:34:49 -0700339 expected_conf = {
340 "devices": {
341 self.o.dp_id: {
342 "basic": {
343 "name": self.o.name
344 }
345 }
346 }
347 }
348 m.post("http://onos:4321/onos/v1/network/configuration/", status_code=200, json=expected_conf,
349 additional_matcher=functools.partial(match_json, expected_conf))
350
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700351 with patch.object(TechnologyProfile.objects, "get") as tp_mock:
352 tp_mock.return_value = self.tp
Andy Bavier00c573c2019-02-08 16:19:11 -0700353
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700354 self.sync_step(model_accessor=self.model_accessor).sync_record(self.o)
355 self.o.save.assert_not_called()
356 self.o.save_changed_fields.assert_not_called()
Matteo Scandolob8621cd2018-04-04 17:12:37 -0700357
Matteo Scandolob8621cd2018-04-04 17:12:37 -0700358 @requests_mock.Mocker()
Scott Baker09798d82019-01-17 08:34:59 -0800359 def test_sync_record_deactivate(self, m):
360 """
361 If device.admin_state == "DISABLED" and oper_status == "ACTIVE", then OLT should be deactivated.
362 """
363
364 expected_conf = {
365 "type": self.o.device_type,
366 "host_and_port": "%s:%s" % (self.o.host, self.o.port)
367 }
368
369 # Make it look like we have an active OLT that we are deactivating.
370 self.o.admin_state = "DISABLED"
371 self.o.oper_status = "ACTIVE"
372 self.o.serial_number = "foobar"
373 self.o.device_id = "123"
374 self.o.of_id = "0001000ce2314000"
375
376 m.post("http://voltha_url:1234/api/v1/devices", status_code=200, json=self.voltha_devices_response, additional_matcher=functools.partial(match_json, expected_conf))
377 m.post("http://voltha_url:1234/api/v1/devices/123/disable", status_code=200)
378
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700379 with patch.object(TechnologyProfile.objects, "get") as tp_mock:
380 tp_mock.return_value = self.tp
Scott Baker09798d82019-01-17 08:34:59 -0800381
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700382 self.sync_step(model_accessor=self.model_accessor).sync_record(self.o)
Andy Bavier00c573c2019-02-08 16:19:11 -0700383
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700384 # No saves as state has not changed (will eventually be saved
385 # by the synchronizer framework to update backend_status)
386 self.assertEqual(self.o.save.call_count, 0)
387 self.assertEqual(self.o.save_changed_fields.call_count, 0)
Scott Baker09798d82019-01-17 08:34:59 -0800388
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700389 # Make sure disable was called
390 urls = [x.url for x in m.request_history]
391 self.assertIn("http://voltha_url:1234/api/v1/devices/123/disable", urls)
Scott Baker09798d82019-01-17 08:34:59 -0800392
393 @requests_mock.Mocker()
394 def test_sync_record_deactivate_already_inactive(self, m):
395 """
396 If device.admin_state == "DISABLED" and device.oper_status == "UNKNOWN", then the device is already deactivated
397 and VOLTHA should not be called.
398 """
399
400 expected_conf = {
401 "type": self.o.device_type,
402 "host_and_port": "%s:%s" % (self.o.host, self.o.port)
403 }
404
405 # Make it look like we have an active OLT that we are deactivating.
406 self.o.admin_state = "DISABLED"
407 self.o.oper_status = "UNKNOWN"
408 self.o.serial_number = "foobar"
409 self.o.device_id = "123"
410 self.o.of_id = "0001000ce2314000"
411
412 m.post("http://voltha_url:1234/api/v1/devices", status_code=200, json=self.voltha_devices_response, additional_matcher=functools.partial(match_json, expected_conf))
413
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700414 with patch.object(TechnologyProfile.objects, "get") as tp_mock:
415 tp_mock.return_value = self.tp
Scott Baker09798d82019-01-17 08:34:59 -0800416
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700417 self.sync_step(model_accessor=self.model_accessor).sync_record(self.o)
418
419 # No saves as state has not changed (will eventually be saved by synchronizer framework
420 # to update backend_status)
421 self.assertEqual(self.o.save.call_count, 0)
422 self.assertEqual(self.o.save_changed_fields.call_count, 0)
423
424 def test_do_not_sync_without_tech_profile(self):
425 self.o.technology = "xgspon"
426 with self.assertRaises(DeferredException) as e:
427
428 self.sync_step(model_accessor=self.model_accessor).sync_record(self.o)
429
430 self.assertEqual(e.exception.message, "Waiting for a TechnologyProfile (technology=xgspon) to be synchronized")
Scott Baker09798d82019-01-17 08:34:59 -0800431
432 @requests_mock.Mocker()
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800433 def test_delete_record(self, m):
Matteo Scandolof6337eb2018-04-05 15:58:37 -0700434 self.o.of_id = "0001000ce2314000"
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800435 self.o.device_id = "123"
436
Luca Preteca974c82018-05-01 18:06:16 -0700437 m.post("http://voltha_url:1234/api/v1/devices/123/disable", status_code=200)
438 m.delete("http://voltha_url:1234/api/v1/devices/123/delete", status_code=200)
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800439
Scott Baker47b47302019-01-30 16:55:07 -0800440 self.sync_step(model_accessor=self.model_accessor).delete_record(self.o)
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800441
Matteo Scandolo563891c2018-08-21 11:56:32 -0700442 self.assertEqual(m.call_count, 2)
443
Scott Baker22b46c52018-11-15 15:15:29 -0800444 @patch('requests.post')
445 def test_delete_record_connectionerror(self, m):
446 self.o.of_id = "0001000ce2314000"
447 self.o.device_id = "123"
448
449 m.side_effect = ConnectionError()
450
Scott Baker47b47302019-01-30 16:55:07 -0800451 self.sync_step(model_accessor=self.model_accessor).delete_record(self.o)
Scott Baker22b46c52018-11-15 15:15:29 -0800452
453 # No exception thrown, as ConnectionError will be caught
454
455
Matteo Scandolo563891c2018-08-21 11:56:32 -0700456 @requests_mock.Mocker()
457 def test_delete_unsynced_record(self, m):
458
Scott Baker47b47302019-01-30 16:55:07 -0800459 self.sync_step(model_accessor=self.model_accessor).delete_record(self.o)
Matteo Scandolo563891c2018-08-21 11:56:32 -0700460
461 self.assertEqual(m.call_count, 0)
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800462
463if __name__ == "__main__":
Luca Preteca974c82018-05-01 18:06:16 -0700464 unittest.main()