blob: fb38a50e20acf36774001c8488d2d00ddb9e030d [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
16import json
17import functools
18from mock import patch, call, Mock, PropertyMock
19import requests_mock
20
21import os, sys
22
Matteo Scandolo0b986e22018-06-04 14:07:33 -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):
27 return req.text == None
28
29def match_json(desired, req):
30 if desired!=req.json():
31 raise Exception("Got request %s, but body is not matching" % req.url)
32 return False
33 return True
34
35class TestSyncOnosApp(unittest.TestCase):
36
37 def setUp(self):
38 global DeferredException
39
40 self.sys_path_save = sys.path
Matteo Scandolo0b986e22018-06-04 14:07:33 -070041
42 # Setting up the config module
43 from xosconfig import Config
44 config = os.path.join(test_path, "../test_config.yaml")
45 Config.clear()
46 Config.init(config, "synchronizer-config-schema.yaml")
47 # END Setting up the config module
48
Scott Baker806d4b72019-02-26 19:01:59 -080049 from xossynchronizer.mock_modelaccessor_build import mock_modelaccessor_config
50 mock_modelaccessor_config(test_path, [("onos-service", "onos.xproto"),])
51
52 import xossynchronizer.modelaccessor
53 import mock_modelaccessor
54 reload(mock_modelaccessor) # in case nose2 loaded it in a previous test
55 reload(xossynchronizer.modelaccessor) # in case nose2 loaded it in a previous test
Matteo Scandolo0b986e22018-06-04 14:07:33 -070056
57 from sync_onos_app import SyncONOSApp, DeferredException, model_accessor
58
Scott Baker806d4b72019-02-26 19:01:59 -080059 self.model_accessor = model_accessor
60
Matteo Scandolo0b986e22018-06-04 14:07:33 -070061 # import all class names to globals
62 for (k, v) in model_accessor.all_model_classes.items():
63 globals()[k] = v
64
65
66 self.sync_step = SyncONOSApp
67
68 onos = ONOSService()
69 onos.rest_hostname = "onos-url"
70 onos.rest_port = "8181"
71 onos.rest_username = "karaf"
72 onos.rest_password = "karaf"
73
74 self.onos_app = Mock(spec=[
75 'id',
76 'name',
77 'app_id',
78 'dependencies',
79 'owner',
80 'url',
81 'backend_code',
82 'version',
83 'tologdict'
84 ])
85 self.onos_app.id = 1
86 self.onos_app.name = "vrouter"
87 self.onos_app.app_id = "org.onosproject.vrouter"
88 self.onos_app.dependencies = ""
89 self.onos_app.owner.leaf_model = onos
90 self.onos_app.url = None
91 self.onos_app.class_names = "ONOSApp"
92 self.onos_app.tologdict.return_value = ""
93
94 self.si = Mock()
95 self.si.id = 1
96 self.si.leaf_model = self.onos_app
97
98 self.vrouter_app_response = {
99 "name": "org.onosproject.vrouter",
100 "version": "1.13.1",
101 }
102
103 self.onos_app_attribute = Mock(spec=[
104 'id',
105 'service_instance',
106 'name',
107 'value'
108 ])
109 self.onos_app_attribute.id = 1
110 self.onos_app_attribute.service_instance = self.si
111 self.onos_app_attribute.name = "/onos/v1/network/configuration/apps/org.opencord.olt"
112 self.onos_app_attribute.value = {
113 "kafka" : {
114 "bootstrapServers" : "cord-kafka-kafka.default.svc.cluster.local:9092"
115 }
116 }
117
118 def tearDown(self):
119 self.onos = None
120 sys.path = self.sys_path_save
121
122 @requests_mock.Mocker()
123 def test_defer_app_sync(self, m):
124 self.onos_app.dependencies = "org.onosproject.segmentrouting, org.onosproject.openflow"
125
126 segment_routing = Mock()
127 segment_routing.app_id = "org.onosproject.segmentrouting"
128 segment_routing.backend_code = 1
129
130 openflow = Mock()
131 openflow.app_id = "org.onosproject.openflow"
132 openflow.backend_code = 0
133
134 with patch.object(ONOSApp.objects, "get_items") as app_get, \
135 patch.object(ServiceInstance.objects, "get_items") as mock_si, \
136 self.assertRaises(DeferredException) as e:
137
138 app_get.return_value = [segment_routing, openflow]
139 mock_si.return_value = [self.si]
Scott Baker806d4b72019-02-26 19:01:59 -0800140 self.sync_step(model_accessor=self.model_accessor).sync_record(self.onos_app)
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700141
142 self.assertEqual(e.exception.message, 'Deferring installation of ONOSApp with id 1 as dependencies are not met')
143 self.assertFalse(m.called)
144
145 @requests_mock.Mocker()
Scott Baker9ee45e12018-08-21 16:58:39 -0700146 def test_dependencies_none(self, m):
147 """ App should sync if dependencies is set to None """
148
149 self.onos_app.dependencies = None
150
151 m.post("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter/active",
152 status_code=200,
153 additional_matcher=match_none)
154
155 m.get("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter",
156 status_code=200,
157 json=self.vrouter_app_response)
158
159 self.si.serviceinstanceattribute_dict = {}
160
161 with patch.object(ServiceInstance.objects, "get_items") as mock_si:
162 mock_si.return_value = [self.si]
Scott Baker806d4b72019-02-26 19:01:59 -0800163 self.sync_step(model_accessor=self.model_accessor).sync_record(self.onos_app)
Scott Baker9ee45e12018-08-21 16:58:39 -0700164
165 self.assertTrue(m.called)
166 self.assertEqual(m.call_count, 2)
167 self.assertEqual(self.onos_app.version, self.vrouter_app_response["version"])
168
169 @requests_mock.Mocker()
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700170 def test_app_sync_local_app_no_config(self, m):
171 """
172 Activate an application that is already installed in ONOS
173 """
174
175 m.post("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter/active",
176 status_code=200,
177 additional_matcher=match_none)
178
179 m.get("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter",
180 status_code=200,
181 json=self.vrouter_app_response)
182
183 self.si.serviceinstanceattribute_dict = {}
184
185 with patch.object(ServiceInstance.objects, "get_items") as mock_si:
186 mock_si.return_value = [self.si]
Scott Baker806d4b72019-02-26 19:01:59 -0800187 self.sync_step(model_accessor=self.model_accessor).sync_record(self.onos_app)
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700188
189 self.assertTrue(m.called)
190 self.assertEqual(m.call_count, 2)
191 self.assertEqual(self.onos_app.version, self.vrouter_app_response["version"])
192
193 @requests_mock.Mocker()
194 def test_app_sync_local_app_with_config(self, m):
195
196 m.post("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter/active",
197 status_code=200,
198 additional_matcher=match_none)
199
200 m.get("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter",
201 status_code=200,
202 json=self.vrouter_app_response)
203
204 with patch.object(ServiceInstance.objects, "get_items") as mock_si:
205 mock_si.return_value = [self.si]
Scott Baker806d4b72019-02-26 19:01:59 -0800206 self.sync_step(model_accessor=self.model_accessor).sync_record(self.onos_app)
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700207 self.assertTrue(m.called)
208 self.assertEqual(m.call_count, 2)
209 self.assertEqual(self.onos_app.version, self.vrouter_app_response["version"])
210
211 @requests_mock.Mocker()
212 def test_app_install_remote_app_no_config(self, m):
213 """
214 Install an application that has to be downloaded from a remote source
215 """
216
217 self.onos_app.url = 'http://onf.org/maven/...'
218 self.onos_app.version = "1.13.1"
Matteo Scandolo3b672572018-06-25 14:28:36 -0700219 self.onos_app.app_id = "org.onosproject.vrouter"
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700220
221 expected = {
222 'activate': True,
223 'url': self.onos_app.url
224 }
225
226 m.post("/onos/v1/applications",
227 status_code=200,
228 additional_matcher=functools.partial(match_json, expected),
229 json=self.vrouter_app_response)
230
Matteo Scandolo3b672572018-06-25 14:28:36 -0700231 m.get("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter", [
232 {'status_code': 404, 'text': "foo"},
233 {'status_code': 200, 'json': self.vrouter_app_response}
234 ])
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700235
236 self.si.serviceinstanceattribute_dict = {}
237
238 with patch.object(ServiceInstance.objects, "get_items") as mock_si:
239 mock_si.return_value = [self.si]
Scott Baker806d4b72019-02-26 19:01:59 -0800240 self.sync_step(model_accessor=self.model_accessor).sync_record(self.onos_app)
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700241 self.assertTrue(m.called)
Matteo Scandolo3b672572018-06-25 14:28:36 -0700242 self.assertEqual(m.call_count, 3)
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700243 self.assertEqual(self.onos_app.app_id, self.vrouter_app_response["name"])
244
245 @requests_mock.Mocker()
246 def test_update_remote_app(self, m):
247 self.onos_app.url = 'http://onf.org/maven/...'
248 self.onos_app.version = "1.14.1"
249
250 expected = {
251 'activate': True,
252 'url': self.onos_app.url
253 }
254
255 self.vrouter_app_response_updated = self.vrouter_app_response.copy()
256 self.vrouter_app_response_updated["version"] = "1.14.1"
257
258 m.post("/onos/v1/applications",
259 status_code=200,
260 additional_matcher=functools.partial(match_json, expected),
261 json=self.vrouter_app_response)
262
263
264 m.get("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter",
265 [
266 {"json": self.vrouter_app_response, "status_code": 200},
267 {"json": self.vrouter_app_response_updated, "status_code": 200}
268 ]
269 )
270
271 m.delete("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter",
272 status_code=204)
273
274 self.si.serviceinstanceattribute_dict = {}
275
276 with patch.object(ServiceInstance.objects, "get_items") as mock_si:
277 mock_si.return_value = [self.si]
Scott Baker806d4b72019-02-26 19:01:59 -0800278 self.sync_step(model_accessor=self.model_accessor).sync_record(self.onos_app)
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700279 self.assertTrue(m.called)
280 self.assertEqual(m.call_count, 4)
281 self.assertEqual(self.onos_app.app_id, self.vrouter_app_response_updated["name"])
282
283 @requests_mock.Mocker()
284 def test_app_sync_remote_app_no_config_fail_version(self, m):
285 """
286 Activate an application that has to be downloaded from a remote source
287 """
288
289 self.onos_app.url = 'http://onf.org/maven/...'
290 self.onos_app.version = "1.14.2"
Matteo Scandolo3b672572018-06-25 14:28:36 -0700291 self.onos_app.app_id = "org.onosproject.vrouter"
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700292
293 expected = {
294 'activate': True,
295 'url': self.onos_app.url
296 }
297
298 m.post("/onos/v1/applications",
299 status_code=200,
300 additional_matcher=functools.partial(match_json, expected),
301 json=self.vrouter_app_response)
302
Matteo Scandolo3b672572018-06-25 14:28:36 -0700303 m.get("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter", [
304 {'status_code': 404, 'text': "foo"},
305 {'status_code': 200, 'json': self.vrouter_app_response}
306 ])
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700307
308 self.si.serviceinstanceattribute_dict = {}
309
310 with patch.object(ServiceInstance.objects, "get_items") as mock_si, \
311 self.assertRaises(Exception) as e:
312 mock_si.return_value = [self.si]
Scott Baker806d4b72019-02-26 19:01:59 -0800313 self.sync_step(model_accessor=self.model_accessor).sync_record(self.onos_app)
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700314
315 self.assertTrue(m.called)
Matteo Scandolo3b672572018-06-25 14:28:36 -0700316 self.assertEqual(m.call_count, 3)
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700317 self.assertEqual(self.onos_app.app_id, self.vrouter_app_response["name"])
318 self.assertEqual(e.exception.message, "The version of org.onosproject.vrouter you installed (1.13.1) is not the same you requested (1.14.2)")
319
320 @requests_mock.Mocker()
Matteo Scandolo3b672572018-06-25 14:28:36 -0700321 def test_handle_409(self, m):
322 """
323 A 409 "Application Already installed" response is not an error. This should not happen as we check if the app is installed.
324 """
325
326 self.onos_app.url = 'http://onf.org/maven/...'
327 self.onos_app.version = "1.14.2"
328 self.onos_app.app_id = "org.onosproject.vrouter"
329
330 m.post("/onos/v1/applications",
331 status_code=409)
332
Scott Baker806d4b72019-02-26 19:01:59 -0800333 step = self.sync_step(model_accessor=self.model_accessor)
Matteo Scandolo3b672572018-06-25 14:28:36 -0700334 with patch.object(step, "check_app_installed") as mock_check_installed:
335 mock_check_installed.return_value = False
336
337 step.sync_record(self.onos_app)
338
339 self.assertTrue(m.called)
340 self.assertEqual(m.call_count, 1)
341
342 @requests_mock.Mocker()
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700343 def test_config_delete(self, m):
344 m.delete("http://onos-url:8181%s" % self.onos_app_attribute.name,
345 status_code=204)
346
Scott Baker806d4b72019-02-26 19:01:59 -0800347 self.sync_step(model_accessor=self.model_accessor).delete_record(self.onos_app_attribute)
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700348 self.assertTrue(m.called)
349 self.assertEqual(m.call_count, 1)
350
351 @requests_mock.Mocker()
352 def test_app_deactivate(self, m):
353 m.delete("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter/active",
354 status_code=204)
355
Scott Baker806d4b72019-02-26 19:01:59 -0800356 self.sync_step(model_accessor=self.model_accessor).delete_record(self.onos_app)
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700357 self.assertTrue(m.called)
358 self.assertEqual(m.call_count, 1)
359
360 @requests_mock.Mocker()
361 def test_app_uninstall(self, m):
362 self.onos_app.url = 'http://onf.org/maven/...'
363 self.onos_app.version = "1.14.2"
364 self.onos_app.backend_code = 1
365
366 m.delete("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter",
367 status_code=204)
368
Scott Baker806d4b72019-02-26 19:01:59 -0800369 self.sync_step(model_accessor=self.model_accessor).delete_record(self.onos_app)
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700370 self.assertTrue(m.called)
371 self.assertEqual(m.call_count, 1)
372
Scott Baker806d4b72019-02-26 19:01:59 -0800373if __name__ == '__main__':
374 unittest.main()
Matteo Scandolo0b986e22018-06-04 14:07:33 -0700375