blob: 4dffeec6bd029d2ec65c74b4d6a60a7338cf3dbd [file] [log] [blame]
Matteo Scandolo0b986e22018-06-04 14:07:33 -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 Scandolo0b986e22018-06-04 14:07:33 -070016import functools
Scott Baker7848fa52019-04-01 17:54:36 -070017from mock import patch, Mock
Matteo Scandolo0b986e22018-06-04 14:07:33 -070018import requests_mock
19
Scott Baker7848fa52019-04-01 17:54:36 -070020import os
21import sys
Matteo Scandolo0b986e22018-06-04 14:07:33 -070022
Scott Baker7848fa52019-04-01 17:54:36 -070023test_path = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
Matteo Scandolo0b986e22018-06-04 14:07:33 -070024
Matteo Scandolo0b986e22018-06-04 14:07:33 -070025
26def match_none(req):
Scott Baker7848fa52019-04-01 17:54:36 -070027 return req.text is None
28
Matteo Scandolo0b986e22018-06-04 14:07:33 -070029
30def match_json(desired, req):
Scott Baker7848fa52019-04-01 17:54:36 -070031 if desired != req.json():
Matteo Scandolo0b986e22018-06-04 14:07:33 -070032 raise Exception("Got request %s, but body is not matching" % req.url)
33 return False
34 return True
35
Scott Baker7848fa52019-04-01 17:54:36 -070036
Matteo Scandolo0b986e22018-06-04 14:07:33 -070037class TestSyncOnosApp(unittest.TestCase):
38
39 def setUp(self):
40 global DeferredException
41
42 self.sys_path_save = sys.path
Matteo Scandolo0b986e22018-06-04 14:07:33 -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 Baker806d4b72019-02-26 19:01:59 -080051 from xossynchronizer.mock_modelaccessor_build import mock_modelaccessor_config
Scott Baker7848fa52019-04-01 17:54:36 -070052 mock_modelaccessor_config(test_path, [("onos-service", "onos.xproto"), ])
Scott Baker806d4b72019-02-26 19:01:59 -080053
54 import xossynchronizer.modelaccessor
55 import mock_modelaccessor
Scott Baker7848fa52019-04-01 17:54:36 -070056 reload(mock_modelaccessor) # in case nose2 loaded it in a previous test
Scott Baker806d4b72019-02-26 19:01:59 -080057 reload(xossynchronizer.modelaccessor) # in case nose2 loaded it in a previous test
Matteo Scandolo0b986e22018-06-04 14:07:33 -070058
59 from sync_onos_app import SyncONOSApp, DeferredException, model_accessor
60
Scott Baker806d4b72019-02-26 19:01:59 -080061 self.model_accessor = model_accessor
62
Matteo Scandolo0b986e22018-06-04 14:07:33 -070063 # import all class names to globals
64 for (k, v) in model_accessor.all_model_classes.items():
65 globals()[k] = v
66
Matteo Scandolo0b986e22018-06-04 14:07:33 -070067 self.sync_step = SyncONOSApp
68
69 onos = ONOSService()
70 onos.rest_hostname = "onos-url"
71 onos.rest_port = "8181"
72 onos.rest_username = "karaf"
73 onos.rest_password = "karaf"
74
75 self.onos_app = Mock(spec=[
76 'id',
77 'name',
78 'app_id',
79 'dependencies',
80 'owner',
81 'url',
82 'backend_code',
83 'version',
84 'tologdict'
85 ])
86 self.onos_app.id = 1
87 self.onos_app.name = "vrouter"
88 self.onos_app.app_id = "org.onosproject.vrouter"
89 self.onos_app.dependencies = ""
90 self.onos_app.owner.leaf_model = onos
91 self.onos_app.url = None
92 self.onos_app.class_names = "ONOSApp"
93 self.onos_app.tologdict.return_value = ""
94
95 self.si = Mock()
96 self.si.id = 1
97 self.si.leaf_model = self.onos_app
98
99 self.vrouter_app_response = {
100 "name": "org.onosproject.vrouter",
101 "version": "1.13.1",
102 }
103
104 self.onos_app_attribute = Mock(spec=[
105 'id',
106 'service_instance',
107 'name',
108 'value'
109 ])
110 self.onos_app_attribute.id = 1
111 self.onos_app_attribute.service_instance = self.si
112 self.onos_app_attribute.name = "/onos/v1/network/configuration/apps/org.opencord.olt"
113 self.onos_app_attribute.value = {
Scott Baker7848fa52019-04-01 17:54:36 -0700114 "kafka": {
115 "bootstrapServers": "cord-kafka-kafka.default.svc.cluster.local:9092"
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700116 }
117 }
118
119 def tearDown(self):
120 self.onos = None
121 sys.path = self.sys_path_save
122
123 @requests_mock.Mocker()
124 def test_defer_app_sync(self, m):
125 self.onos_app.dependencies = "org.onosproject.segmentrouting, org.onosproject.openflow"
126
127 segment_routing = Mock()
128 segment_routing.app_id = "org.onosproject.segmentrouting"
129 segment_routing.backend_code = 1
130
131 openflow = Mock()
132 openflow.app_id = "org.onosproject.openflow"
133 openflow.backend_code = 0
134
135 with patch.object(ONOSApp.objects, "get_items") as app_get, \
Scott Baker7848fa52019-04-01 17:54:36 -0700136 patch.object(ServiceInstance.objects, "get_items") as mock_si, \
137 self.assertRaises(DeferredException) as e:
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700138
139 app_get.return_value = [segment_routing, openflow]
140 mock_si.return_value = [self.si]
Scott Baker806d4b72019-02-26 19:01:59 -0800141 self.sync_step(model_accessor=self.model_accessor).sync_record(self.onos_app)
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700142
Scott Baker7848fa52019-04-01 17:54:36 -0700143 self.assertEqual(
144 e.exception.message,
145 'Deferring installation of ONOSApp with id 1 as dependencies are not met')
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700146 self.assertFalse(m.called)
147
148 @requests_mock.Mocker()
Scott Baker9ee45e12018-08-21 16:58:39 -0700149 def test_dependencies_none(self, m):
150 """ App should sync if dependencies is set to None """
151
152 self.onos_app.dependencies = None
153
154 m.post("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter/active",
155 status_code=200,
156 additional_matcher=match_none)
157
158 m.get("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter",
Scott Baker7848fa52019-04-01 17:54:36 -0700159 status_code=200,
160 json=self.vrouter_app_response)
Scott Baker9ee45e12018-08-21 16:58:39 -0700161
162 self.si.serviceinstanceattribute_dict = {}
163
164 with patch.object(ServiceInstance.objects, "get_items") as mock_si:
165 mock_si.return_value = [self.si]
Scott Baker806d4b72019-02-26 19:01:59 -0800166 self.sync_step(model_accessor=self.model_accessor).sync_record(self.onos_app)
Scott Baker9ee45e12018-08-21 16:58:39 -0700167
168 self.assertTrue(m.called)
169 self.assertEqual(m.call_count, 2)
170 self.assertEqual(self.onos_app.version, self.vrouter_app_response["version"])
171
172 @requests_mock.Mocker()
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700173 def test_app_sync_local_app_no_config(self, m):
174 """
175 Activate an application that is already installed in ONOS
176 """
177
178 m.post("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter/active",
179 status_code=200,
180 additional_matcher=match_none)
181
182 m.get("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter",
Scott Baker7848fa52019-04-01 17:54:36 -0700183 status_code=200,
184 json=self.vrouter_app_response)
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700185
186 self.si.serviceinstanceattribute_dict = {}
187
188 with patch.object(ServiceInstance.objects, "get_items") as mock_si:
189 mock_si.return_value = [self.si]
Scott Baker806d4b72019-02-26 19:01:59 -0800190 self.sync_step(model_accessor=self.model_accessor).sync_record(self.onos_app)
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700191
192 self.assertTrue(m.called)
193 self.assertEqual(m.call_count, 2)
194 self.assertEqual(self.onos_app.version, self.vrouter_app_response["version"])
195
196 @requests_mock.Mocker()
197 def test_app_sync_local_app_with_config(self, m):
198
199 m.post("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter/active",
200 status_code=200,
201 additional_matcher=match_none)
202
203 m.get("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter",
204 status_code=200,
205 json=self.vrouter_app_response)
206
207 with patch.object(ServiceInstance.objects, "get_items") as mock_si:
208 mock_si.return_value = [self.si]
Scott Baker806d4b72019-02-26 19:01:59 -0800209 self.sync_step(model_accessor=self.model_accessor).sync_record(self.onos_app)
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700210 self.assertTrue(m.called)
211 self.assertEqual(m.call_count, 2)
212 self.assertEqual(self.onos_app.version, self.vrouter_app_response["version"])
213
214 @requests_mock.Mocker()
215 def test_app_install_remote_app_no_config(self, m):
216 """
217 Install an application that has to be downloaded from a remote source
218 """
219
220 self.onos_app.url = 'http://onf.org/maven/...'
221 self.onos_app.version = "1.13.1"
Matteo Scandolo3b672572018-06-25 14:28:36 -0700222 self.onos_app.app_id = "org.onosproject.vrouter"
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700223
224 expected = {
225 'activate': True,
226 'url': self.onos_app.url
227 }
228
229 m.post("/onos/v1/applications",
230 status_code=200,
231 additional_matcher=functools.partial(match_json, expected),
232 json=self.vrouter_app_response)
233
Matteo Scandolo3b672572018-06-25 14:28:36 -0700234 m.get("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter", [
235 {'status_code': 404, 'text': "foo"},
236 {'status_code': 200, 'json': self.vrouter_app_response}
237 ])
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700238
239 self.si.serviceinstanceattribute_dict = {}
240
241 with patch.object(ServiceInstance.objects, "get_items") as mock_si:
242 mock_si.return_value = [self.si]
Scott Baker806d4b72019-02-26 19:01:59 -0800243 self.sync_step(model_accessor=self.model_accessor).sync_record(self.onos_app)
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700244 self.assertTrue(m.called)
Matteo Scandolo3b672572018-06-25 14:28:36 -0700245 self.assertEqual(m.call_count, 3)
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700246 self.assertEqual(self.onos_app.app_id, self.vrouter_app_response["name"])
247
248 @requests_mock.Mocker()
249 def test_update_remote_app(self, m):
250 self.onos_app.url = 'http://onf.org/maven/...'
251 self.onos_app.version = "1.14.1"
252
253 expected = {
254 'activate': True,
255 'url': self.onos_app.url
256 }
257
258 self.vrouter_app_response_updated = self.vrouter_app_response.copy()
259 self.vrouter_app_response_updated["version"] = "1.14.1"
260
261 m.post("/onos/v1/applications",
262 status_code=200,
263 additional_matcher=functools.partial(match_json, expected),
264 json=self.vrouter_app_response)
265
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700266 m.get("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter",
267 [
268 {"json": self.vrouter_app_response, "status_code": 200},
269 {"json": self.vrouter_app_response_updated, "status_code": 200}
270 ]
Scott Baker7848fa52019-04-01 17:54:36 -0700271 )
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700272
273 m.delete("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter",
274 status_code=204)
275
276 self.si.serviceinstanceattribute_dict = {}
277
278 with patch.object(ServiceInstance.objects, "get_items") as mock_si:
279 mock_si.return_value = [self.si]
Scott Baker806d4b72019-02-26 19:01:59 -0800280 self.sync_step(model_accessor=self.model_accessor).sync_record(self.onos_app)
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700281 self.assertTrue(m.called)
282 self.assertEqual(m.call_count, 4)
283 self.assertEqual(self.onos_app.app_id, self.vrouter_app_response_updated["name"])
284
285 @requests_mock.Mocker()
286 def test_app_sync_remote_app_no_config_fail_version(self, m):
287 """
288 Activate an application that has to be downloaded from a remote source
289 """
290
291 self.onos_app.url = 'http://onf.org/maven/...'
292 self.onos_app.version = "1.14.2"
Matteo Scandolo3b672572018-06-25 14:28:36 -0700293 self.onos_app.app_id = "org.onosproject.vrouter"
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700294
295 expected = {
296 'activate': True,
297 'url': self.onos_app.url
298 }
299
300 m.post("/onos/v1/applications",
301 status_code=200,
302 additional_matcher=functools.partial(match_json, expected),
303 json=self.vrouter_app_response)
304
Matteo Scandolo3b672572018-06-25 14:28:36 -0700305 m.get("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter", [
306 {'status_code': 404, 'text': "foo"},
307 {'status_code': 200, 'json': self.vrouter_app_response}
308 ])
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700309
310 self.si.serviceinstanceattribute_dict = {}
311
312 with patch.object(ServiceInstance.objects, "get_items") as mock_si, \
Scott Baker7848fa52019-04-01 17:54:36 -0700313 self.assertRaises(Exception) as e:
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700314 mock_si.return_value = [self.si]
Scott Baker806d4b72019-02-26 19:01:59 -0800315 self.sync_step(model_accessor=self.model_accessor).sync_record(self.onos_app)
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700316
317 self.assertTrue(m.called)
Matteo Scandolo3b672572018-06-25 14:28:36 -0700318 self.assertEqual(m.call_count, 3)
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700319 self.assertEqual(self.onos_app.app_id, self.vrouter_app_response["name"])
Scott Baker7848fa52019-04-01 17:54:36 -0700320 self.assertEqual(
321 e.exception.message,
322 "The version of org.onosproject.vrouter you installed (1.13.1) is not the same you requested (1.14.2)")
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700323
324 @requests_mock.Mocker()
Matteo Scandolo3b672572018-06-25 14:28:36 -0700325 def test_handle_409(self, m):
326 """
Scott Baker7848fa52019-04-01 17:54:36 -0700327 A 409 "Application Already installed" response is not an error. This should not happen as we check
328 if the app is installed.
Matteo Scandolo3b672572018-06-25 14:28:36 -0700329 """
330
331 self.onos_app.url = 'http://onf.org/maven/...'
332 self.onos_app.version = "1.14.2"
333 self.onos_app.app_id = "org.onosproject.vrouter"
334
335 m.post("/onos/v1/applications",
336 status_code=409)
337
Scott Baker806d4b72019-02-26 19:01:59 -0800338 step = self.sync_step(model_accessor=self.model_accessor)
Matteo Scandolo3b672572018-06-25 14:28:36 -0700339 with patch.object(step, "check_app_installed") as mock_check_installed:
340 mock_check_installed.return_value = False
341
342 step.sync_record(self.onos_app)
343
344 self.assertTrue(m.called)
345 self.assertEqual(m.call_count, 1)
346
347 @requests_mock.Mocker()
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700348 def test_config_delete(self, m):
349 m.delete("http://onos-url:8181%s" % self.onos_app_attribute.name,
Scott Baker7848fa52019-04-01 17:54:36 -0700350 status_code=204)
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700351
Scott Baker806d4b72019-02-26 19:01:59 -0800352 self.sync_step(model_accessor=self.model_accessor).delete_record(self.onos_app_attribute)
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700353 self.assertTrue(m.called)
354 self.assertEqual(m.call_count, 1)
355
356 @requests_mock.Mocker()
357 def test_app_deactivate(self, m):
358 m.delete("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter/active",
Scott Baker7848fa52019-04-01 17:54:36 -0700359 status_code=204)
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700360
Scott Baker806d4b72019-02-26 19:01:59 -0800361 self.sync_step(model_accessor=self.model_accessor).delete_record(self.onos_app)
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700362 self.assertTrue(m.called)
363 self.assertEqual(m.call_count, 1)
364
365 @requests_mock.Mocker()
366 def test_app_uninstall(self, m):
367 self.onos_app.url = 'http://onf.org/maven/...'
368 self.onos_app.version = "1.14.2"
369 self.onos_app.backend_code = 1
370
371 m.delete("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter",
372 status_code=204)
373
Scott Baker806d4b72019-02-26 19:01:59 -0800374 self.sync_step(model_accessor=self.model_accessor).delete_record(self.onos_app)
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700375 self.assertTrue(m.called)
376 self.assertEqual(m.call_count, 1)
377
Scott Baker7848fa52019-04-01 17:54:36 -0700378
Scott Baker806d4b72019-02-26 19:01:59 -0800379if __name__ == '__main__':
380 unittest.main()