blob: 57330d2172d7755e7bf5d2da2414432c0cbbfb74 [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
91 o.of_id = None
Matteo Scandolo096a3cf2018-06-20 13:56:13 -070092 o.id = 1
Matteo Scandolob8621cd2018-04-04 17:12:37 -070093
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -080094 o.tologdict.return_value = {'name': "Mock VOLTServiceInstance"}
95
Andy Bavier00c573c2019-02-08 16:19:11 -070096 o.save_changed_fields.return_value = "Saved"
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -080097
Matteo Scandolo6be6ee92018-05-24 15:07:51 -070098 o.pon_ports.all.return_value = [pon_port]
Matteo Scandolob8621cd2018-04-04 17:12:37 -070099
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800100 self.o = o
101
Matteo Scandolod6fce512018-10-16 10:35:29 -0700102 self.voltha_devices_response = {"id": "123", "serial_number": "foobar"}
103
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700104 self.tp = TechnologyProfile(
105 technology="xgspon",
106 profile_id=64,
107 profile_value="{}"
108 )
109
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800110 def tearDown(self):
111 self.o = None
Matteo Scandoloce27e9c2018-04-06 10:06:53 -0700112 sys.path = self.sys_path_save
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800113
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800114 @requests_mock.Mocker()
115 def test_get_of_id_from_device(self, m):
116 logical_devices = {
117 "items": [
Matteo Scandolof6337eb2018-04-05 15:58:37 -0700118 {"root_device_id": "123", "id": "0001000ce2314000", "datapath_id": "55334486016"},
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800119 {"root_device_id": "0001cc4974a62b87", "id": "0001000000000001"}
120 ]
121 }
Luca Preteca974c82018-05-01 18:06:16 -0700122 m.get("http://voltha_url:1234/api/v1/logical_devices", status_code=200, json=logical_devices)
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800123 self.o.device_id = "123"
Matteo Scandolof6337eb2018-04-05 15:58:37 -0700124 self.o = self.sync_step.get_ids_from_logical_device(self.o)
125 self.assertEqual(self.o.of_id, "0001000ce2314000")
126 self.assertEqual(self.o.dp_id, "of:0000000ce2314000")
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800127
128 with self.assertRaises(Exception) as e:
129 self.o.device_id = "idonotexist"
Matteo Scandolof6337eb2018-04-05 15:58:37 -0700130 self.sync_step.get_ids_from_logical_device(self.o)
Matteo Scandolo2c144932018-05-04 14:06:24 -0700131 self.assertEqual(e.exception.message, "Can't find a logical_device for OLT device id: idonotexist")
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800132
133 @requests_mock.Mocker()
134 def test_sync_record_fail_add(self, m):
135 """
136 Should print an error if we can't add the device in VOLTHA
137 """
Luca Preteca974c82018-05-01 18:06:16 -0700138 m.post("http://voltha_url:1234/api/v1/devices", status_code=500, text="MockError")
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800139
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700140 with self.assertRaises(Exception) as e, \
141 patch.object(TechnologyProfile.objects, "get") as tp_mock:
142 tp_mock.return_value = self.tp
143
Scott Baker47b47302019-01-30 16:55:07 -0800144 self.sync_step(model_accessor=self.model_accessor).sync_record(self.o)
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700145
Matteo Scandolo2c144932018-05-04 14:06:24 -0700146 self.assertEqual(e.exception.message, "Failed to add OLT device: MockError")
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800147
148 @requests_mock.Mocker()
149 def test_sync_record_fail_no_id(self, m):
150 """
151 Should print an error if VOLTHA does not return the device id
152 """
Luca Preteca974c82018-05-01 18:06:16 -0700153 m.post("http://voltha_url:1234/api/v1/devices", status_code=200, json={"id": ""})
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800154
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700155 with self.assertRaises(Exception) as e, \
156 patch.object(TechnologyProfile.objects, "get") as tp_mock:
157 tp_mock.return_value = self.tp
158
Scott Baker47b47302019-01-30 16:55:07 -0800159 self.sync_step(model_accessor=self.model_accessor).sync_record(self.o)
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700160
Matteo Scandolo2c144932018-05-04 14:06:24 -0700161 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 -0800162
163 @requests_mock.Mocker()
164 def test_sync_record_fail_enable(self, m):
165 """
166 Should print an error if device.enable fails
167 """
Matteo Scandolod6fce512018-10-16 10:35:29 -0700168 m.post("http://voltha_url:1234/api/v1/devices", status_code=200, json=self.voltha_devices_response)
Luca Preteca974c82018-05-01 18:06:16 -0700169 m.post("http://voltha_url:1234/api/v1/devices/123/enable", status_code=500, text="EnableError")
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800170
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700171 with self.assertRaises(Exception) as e, \
172 patch.object(TechnologyProfile.objects, "get") as tp_mock:
173 tp_mock.return_value = self.tp
174
Scott Baker47b47302019-01-30 16:55:07 -0800175 self.sync_step(model_accessor=self.model_accessor).sync_record(self.o)
Matteo Scandolo2c144932018-05-04 14:06:24 -0700176
177 self.assertEqual(e.exception.message, "Failed to enable OLT device: EnableError")
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800178
179 @requests_mock.Mocker()
180 def test_sync_record_success(self, m):
181 """
182 If device.enable succed should fetch the state, retrieve the of_id and push it to ONOS
183 """
Matteo Scandolo2ed64b92018-06-18 10:32:56 -0700184
185 expected_conf = {
186 "type": self.o.device_type,
187 "host_and_port": "%s:%s" % (self.o.host, self.o.port)
188 }
189
Matteo Scandolod6fce512018-10-16 10:35:29 -0700190 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 -0700191 m.post("http://voltha_url:1234/api/v1/devices/123/enable", status_code=200)
Matteo Scandolo45876652018-10-16 16:03:17 -0700192 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 -0800193 logical_devices = {
194 "items": [
Matteo Scandolof6337eb2018-04-05 15:58:37 -0700195 {"root_device_id": "123", "id": "0001000ce2314000", "datapath_id": "55334486016"},
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800196 {"root_device_id": "0001cc4974a62b87", "id": "0001000000000001"}
197 ]
198 }
Luca Preteca974c82018-05-01 18:06:16 -0700199 m.get("http://voltha_url:1234/api/v1/logical_devices", status_code=200, json=logical_devices)
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800200
Matteo Scandoloa79395f2018-10-08 13:34:49 -0700201 onos_expected_conf = {
202 "devices": {
203 "of:0000000ce2314000": {
204 "basic": {
205 "name": self.o.name
206 }
207 }
208 }
209 }
210 m.post("http://onos:4321/onos/v1/network/configuration/", status_code=200, json=onos_expected_conf,
211 additional_matcher=functools.partial(match_json, onos_expected_conf))
212
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700213 with patch.object(TechnologyProfile.objects, "get") as tp_mock:
214 tp_mock.return_value = self.tp
Scott Baker09798d82019-01-17 08:34:59 -0800215
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700216 self.sync_step(model_accessor=self.model_accessor).sync_record(self.o)
217 self.assertEqual(self.o.admin_state, "ENABLED")
218 self.assertEqual(self.o.oper_status, "ACTIVE")
219 self.assertEqual(self.o.serial_number, "foobar")
220 self.assertEqual(self.o.of_id, "0001000ce2314000")
221
222 # One save during preprovision
223 # One save during activation to set backend_status to "Waiting for device to activate"
224 # One save after activation has succeeded
225 self.assertEqual(self.o.save_changed_fields.call_count, 3)
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800226
227 @requests_mock.Mocker()
Matteo Scandolo2ed64b92018-06-18 10:32:56 -0700228 def test_sync_record_success_mac_address(self, m):
229 """
230 A device should be pre-provisioned via mac_address, the the process is the same
231 """
232
233 del self.o.host
234 del self.o.port
235 self.o.mac_address = "00:0c:e2:31:40:00"
236
237 expected_conf = {
238 "type": self.o.device_type,
239 "mac_address": self.o.mac_address
240 }
241
Matteo Scandoloa79395f2018-10-08 13:34:49 -0700242 onos_expected_conf = {
243 "devices": {
244 "of:0000000ce2314000": {
245 "basic": {
246 "name": self.o.name
247 }
248 }
249 }
250 }
251 m.post("http://onos:4321/onos/v1/network/configuration/", status_code=200, json=onos_expected_conf,
252 additional_matcher=functools.partial(match_json, onos_expected_conf))
253
Matteo Scandolod6fce512018-10-16 10:35:29 -0700254 m.post("http://voltha_url:1234/api/v1/devices", status_code=200, json=self.voltha_devices_response,
Matteo Scandolo2ed64b92018-06-18 10:32:56 -0700255 additional_matcher=functools.partial(match_json, expected_conf))
256 m.post("http://voltha_url:1234/api/v1/devices/123/enable", status_code=200)
Matteo Scandolo45876652018-10-16 16:03:17 -0700257 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 -0700258 logical_devices = {
259 "items": [
260 {"root_device_id": "123", "id": "0001000ce2314000", "datapath_id": "55334486016"},
261 {"root_device_id": "0001cc4974a62b87", "id": "0001000000000001"}
262 ]
263 }
264 m.get("http://voltha_url:1234/api/v1/logical_devices", status_code=200, json=logical_devices)
265
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700266 with patch.object(TechnologyProfile.objects, "get") as tp_mock:
267 tp_mock.return_value = self.tp
Scott Baker09798d82019-01-17 08:34:59 -0800268
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700269 self.sync_step(model_accessor=self.model_accessor).sync_record(self.o)
270 self.assertEqual(self.o.admin_state, "ENABLED")
271 self.assertEqual(self.o.oper_status, "ACTIVE")
272 self.assertEqual(self.o.of_id, "0001000ce2314000")
273
274 # One save during preprovision
275 # One save during activation to set backend_status to "Waiting for device to activate"
276 # One save after activation has succeeded
277 self.assertEqual(self.o.save_changed_fields.call_count, 3)
Matteo Scandolo096a3cf2018-06-20 13:56:13 -0700278
279 @requests_mock.Mocker()
280 def test_sync_record_enable_timeout(self, m):
281 """
Scott Baker09798d82019-01-17 08:34:59 -0800282 If device activation fails we need to tell the user.
283
284 OLT will be preprovisioned.
285 OLT will return "ERROR" for oper_status during activate and will eventually exceed retries.s
Matteo Scandolo096a3cf2018-06-20 13:56:13 -0700286 """
287
288 expected_conf = {
289 "type": self.o.device_type,
290 "host_and_port": "%s:%s" % (self.o.host, self.o.port)
291 }
292
Matteo Scandolod6fce512018-10-16 10:35:29 -0700293 m.post("http://voltha_url:1234/api/v1/devices", status_code=200, json=self.voltha_devices_response,
Matteo Scandolo096a3cf2018-06-20 13:56:13 -0700294 additional_matcher=functools.partial(match_json, expected_conf))
295 m.post("http://voltha_url:1234/api/v1/devices/123/enable", status_code=200)
296 m.get("http://voltha_url:1234/api/v1/devices/123", [
Matteo Scandolo45876652018-10-16 16:03:17 -0700297 {"json": {"oper_status": "ACTIVATING", "admin_state": "ENABLED", "serial_number": "foobar"}, "status_code": 200},
Scott Baker09798d82019-01-17 08:34:59 -0800298 {"json": {"oper_status": "ERROR", "admin_state": "ENABLED", "serial_number": "foobar"}, "status_code": 200}
Matteo Scandolo096a3cf2018-06-20 13:56:13 -0700299 ])
300
301 logical_devices = {
302 "items": [
303 {"root_device_id": "123", "id": "0001000ce2314000", "datapath_id": "55334486016"},
304 {"root_device_id": "0001cc4974a62b87", "id": "0001000000000001"}
305 ]
306 }
307 m.get("http://voltha_url:1234/api/v1/logical_devices", status_code=200, json=logical_devices)
308
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700309 with self.assertRaises(Exception) as e, \
310 patch.object(TechnologyProfile.objects, "get") as tp_mock:
311 tp_mock.return_value = self.tp
312
Scott Baker47b47302019-01-30 16:55:07 -0800313 self.sync_step(model_accessor=self.model_accessor).sync_record(self.o)
Matteo Scandolo096a3cf2018-06-20 13:56:13 -0700314
315 self.assertEqual(e.exception.message, "It was not possible to activate OLTDevice with id 1")
316 self.assertEqual(self.o.oper_status, "ERROR")
Scott Baker09798d82019-01-17 08:34:59 -0800317 self.assertEqual(self.o.admin_state, "ENABLED")
318 self.assertEqual(self.o.device_id, "123")
319 self.assertEqual(self.o.serial_number, "foobar")
320
321 # One save from preprovision to set device_id, serial_number
322 # One save from activate to set backend_status to "Waiting for device to be activated"
Andy Bavier00c573c2019-02-08 16:19:11 -0700323 self.assertEqual(self.o.save_changed_fields.call_count, 2)
Matteo Scandolo2ed64b92018-06-18 10:32:56 -0700324
325 @requests_mock.Mocker()
Matteo Scandolob8621cd2018-04-04 17:12:37 -0700326 def test_sync_record_already_existing_in_voltha(self, m):
Scott Baker09798d82019-01-17 08:34:59 -0800327 """
328 If device.admin_state == "ENABLED" and oper_status == "ACTIVE", then the OLT should not be reactivated.
329 """
330
Matteo Scandolob8621cd2018-04-04 17:12:37 -0700331 # mock device feedback state
332 self.o.device_id = "123"
Matteo Scandolo096a3cf2018-06-20 13:56:13 -0700333 self.o.admin_state = "ENABLED"
334 self.o.oper_status = "ACTIVE"
Matteo Scandolof6337eb2018-04-05 15:58:37 -0700335 self.o.dp_id = "of:0000000ce2314000"
Matteo Scandolo2c144932018-05-04 14:06:24 -0700336 self.o.of_id = "0001000ce2314000"
Matteo Scandolob8621cd2018-04-04 17:12:37 -0700337
Matteo Scandoloa79395f2018-10-08 13:34:49 -0700338 expected_conf = {
339 "devices": {
340 self.o.dp_id: {
341 "basic": {
342 "name": self.o.name
343 }
344 }
345 }
346 }
347 m.post("http://onos:4321/onos/v1/network/configuration/", status_code=200, json=expected_conf,
348 additional_matcher=functools.partial(match_json, expected_conf))
349
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700350 with patch.object(TechnologyProfile.objects, "get") as tp_mock:
351 tp_mock.return_value = self.tp
Andy Bavier00c573c2019-02-08 16:19:11 -0700352
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700353 self.sync_step(model_accessor=self.model_accessor).sync_record(self.o)
354 self.o.save.assert_not_called()
355 self.o.save_changed_fields.assert_not_called()
Matteo Scandolob8621cd2018-04-04 17:12:37 -0700356
Matteo Scandolob8621cd2018-04-04 17:12:37 -0700357 @requests_mock.Mocker()
Scott Baker09798d82019-01-17 08:34:59 -0800358 def test_sync_record_deactivate(self, m):
359 """
360 If device.admin_state == "DISABLED" and oper_status == "ACTIVE", then OLT should be deactivated.
361 """
362
363 expected_conf = {
364 "type": self.o.device_type,
365 "host_and_port": "%s:%s" % (self.o.host, self.o.port)
366 }
367
368 # Make it look like we have an active OLT that we are deactivating.
369 self.o.admin_state = "DISABLED"
370 self.o.oper_status = "ACTIVE"
371 self.o.serial_number = "foobar"
372 self.o.device_id = "123"
373 self.o.of_id = "0001000ce2314000"
374
375 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))
376 m.post("http://voltha_url:1234/api/v1/devices/123/disable", status_code=200)
377
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700378 with patch.object(TechnologyProfile.objects, "get") as tp_mock:
379 tp_mock.return_value = self.tp
Scott Baker09798d82019-01-17 08:34:59 -0800380
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700381 self.sync_step(model_accessor=self.model_accessor).sync_record(self.o)
Andy Bavier00c573c2019-02-08 16:19:11 -0700382
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700383 # No saves as state has not changed (will eventually be saved
384 # by the synchronizer framework to update backend_status)
385 self.assertEqual(self.o.save.call_count, 0)
386 self.assertEqual(self.o.save_changed_fields.call_count, 0)
Scott Baker09798d82019-01-17 08:34:59 -0800387
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700388 # Make sure disable was called
389 urls = [x.url for x in m.request_history]
390 self.assertIn("http://voltha_url:1234/api/v1/devices/123/disable", urls)
Scott Baker09798d82019-01-17 08:34:59 -0800391
392 @requests_mock.Mocker()
393 def test_sync_record_deactivate_already_inactive(self, m):
394 """
395 If device.admin_state == "DISABLED" and device.oper_status == "UNKNOWN", then the device is already deactivated
396 and VOLTHA should not be called.
397 """
398
399 expected_conf = {
400 "type": self.o.device_type,
401 "host_and_port": "%s:%s" % (self.o.host, self.o.port)
402 }
403
404 # Make it look like we have an active OLT that we are deactivating.
405 self.o.admin_state = "DISABLED"
406 self.o.oper_status = "UNKNOWN"
407 self.o.serial_number = "foobar"
408 self.o.device_id = "123"
409 self.o.of_id = "0001000ce2314000"
410
411 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))
412
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700413 with patch.object(TechnologyProfile.objects, "get") as tp_mock:
414 tp_mock.return_value = self.tp
Scott Baker09798d82019-01-17 08:34:59 -0800415
Matteo Scandolo2b4c8472019-06-26 18:06:47 -0700416 self.sync_step(model_accessor=self.model_accessor).sync_record(self.o)
417
418 # No saves as state has not changed (will eventually be saved by synchronizer framework
419 # to update backend_status)
420 self.assertEqual(self.o.save.call_count, 0)
421 self.assertEqual(self.o.save_changed_fields.call_count, 0)
422
423 def test_do_not_sync_without_tech_profile(self):
424 self.o.technology = "xgspon"
425 with self.assertRaises(DeferredException) as e:
426
427 self.sync_step(model_accessor=self.model_accessor).sync_record(self.o)
428
429 self.assertEqual(e.exception.message, "Waiting for a TechnologyProfile (technology=xgspon) to be synchronized")
Scott Baker09798d82019-01-17 08:34:59 -0800430
431 @requests_mock.Mocker()
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800432 def test_delete_record(self, m):
Matteo Scandolof6337eb2018-04-05 15:58:37 -0700433 self.o.of_id = "0001000ce2314000"
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800434 self.o.device_id = "123"
435
Luca Preteca974c82018-05-01 18:06:16 -0700436 m.post("http://voltha_url:1234/api/v1/devices/123/disable", status_code=200)
437 m.delete("http://voltha_url:1234/api/v1/devices/123/delete", status_code=200)
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800438
Scott Baker47b47302019-01-30 16:55:07 -0800439 self.sync_step(model_accessor=self.model_accessor).delete_record(self.o)
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800440
Matteo Scandolo563891c2018-08-21 11:56:32 -0700441 self.assertEqual(m.call_count, 2)
442
Scott Baker22b46c52018-11-15 15:15:29 -0800443 @patch('requests.post')
444 def test_delete_record_connectionerror(self, m):
445 self.o.of_id = "0001000ce2314000"
446 self.o.device_id = "123"
447
448 m.side_effect = ConnectionError()
449
Scott Baker47b47302019-01-30 16:55:07 -0800450 self.sync_step(model_accessor=self.model_accessor).delete_record(self.o)
Scott Baker22b46c52018-11-15 15:15:29 -0800451
452 # No exception thrown, as ConnectionError will be caught
453
454
Matteo Scandolo563891c2018-08-21 11:56:32 -0700455 @requests_mock.Mocker()
456 def test_delete_unsynced_record(self, m):
457
Scott Baker47b47302019-01-30 16:55:07 -0800458 self.sync_step(model_accessor=self.model_accessor).delete_record(self.o)
Matteo Scandolo563891c2018-08-21 11:56:32 -0700459
460 self.assertEqual(m.call_count, 0)
Matteo Scandolo4a8b4d62018-03-06 17:18:46 -0800461
462if __name__ == "__main__":
Luca Preteca974c82018-05-01 18:06:16 -0700463 unittest.main()