blob: 4d64783985f43b28728f7580888afeab46b3f500 [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
23# Hack to load synchronizer framework
24test_path=os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
25xos_dir=os.path.join(test_path, "../../..")
26if not os.path.exists(os.path.join(test_path, "new_base")):
27 xos_dir=os.path.join(test_path, "../../../../../../orchestration/xos/xos")
28 services_dir = os.path.join(xos_dir, "../../xos_services")
29sys.path.append(xos_dir)
30sys.path.append(os.path.join(xos_dir, 'synchronizers', 'new_base'))
31# END Hack to load synchronizer framework
32
33# generate model from xproto
34def get_models_fn(service_name, xproto_name):
35 name = os.path.join(service_name, "xos", xproto_name)
36 if os.path.exists(os.path.join(services_dir, name)):
37 return name
38 else:
39 name = os.path.join(service_name, "xos", "synchronizer", "models", xproto_name)
40 if os.path.exists(os.path.join(services_dir, name)):
41 return name
42 raise Exception("Unable to find service=%s xproto=%s" % (service_name, xproto_name))
43# END generate model from xproto
44
45def match_none(req):
46 return req.text == None
47
48def match_json(desired, req):
49 if desired!=req.json():
50 raise Exception("Got request %s, but body is not matching" % req.url)
51 return False
52 return True
53
54class TestSyncOnosApp(unittest.TestCase):
55
56 def setUp(self):
57 global DeferredException
58
59 self.sys_path_save = sys.path
60 sys.path.append(xos_dir)
61 sys.path.append(os.path.join(xos_dir, 'synchronizers', 'new_base'))
62
63 # Setting up the config module
64 from xosconfig import Config
65 config = os.path.join(test_path, "../test_config.yaml")
66 Config.clear()
67 Config.init(config, "synchronizer-config-schema.yaml")
68 # END Setting up the config module
69
70 from synchronizers.new_base.mock_modelaccessor_build import build_mock_modelaccessor
71 build_mock_modelaccessor(xos_dir, services_dir, [
72 get_models_fn("onos-service", "onos.xproto")
73 ])
74 import synchronizers.new_base.modelaccessor
75
76 from sync_onos_app import SyncONOSApp, DeferredException, model_accessor
77
78 # import all class names to globals
79 for (k, v) in model_accessor.all_model_classes.items():
80 globals()[k] = v
81
82
83 self.sync_step = SyncONOSApp
84
85 onos = ONOSService()
86 onos.rest_hostname = "onos-url"
87 onos.rest_port = "8181"
88 onos.rest_username = "karaf"
89 onos.rest_password = "karaf"
90
91 self.onos_app = Mock(spec=[
92 'id',
93 'name',
94 'app_id',
95 'dependencies',
96 'owner',
97 'url',
98 'backend_code',
99 'version',
100 'tologdict'
101 ])
102 self.onos_app.id = 1
103 self.onos_app.name = "vrouter"
104 self.onos_app.app_id = "org.onosproject.vrouter"
105 self.onos_app.dependencies = ""
106 self.onos_app.owner.leaf_model = onos
107 self.onos_app.url = None
108 self.onos_app.class_names = "ONOSApp"
109 self.onos_app.tologdict.return_value = ""
110
111 self.si = Mock()
112 self.si.id = 1
113 self.si.leaf_model = self.onos_app
114
115 self.vrouter_app_response = {
116 "name": "org.onosproject.vrouter",
117 "version": "1.13.1",
118 }
119
120 self.onos_app_attribute = Mock(spec=[
121 'id',
122 'service_instance',
123 'name',
124 'value'
125 ])
126 self.onos_app_attribute.id = 1
127 self.onos_app_attribute.service_instance = self.si
128 self.onos_app_attribute.name = "/onos/v1/network/configuration/apps/org.opencord.olt"
129 self.onos_app_attribute.value = {
130 "kafka" : {
131 "bootstrapServers" : "cord-kafka-kafka.default.svc.cluster.local:9092"
132 }
133 }
134
135 def tearDown(self):
136 self.onos = None
137 sys.path = self.sys_path_save
138
139 @requests_mock.Mocker()
140 def test_defer_app_sync(self, m):
141 self.onos_app.dependencies = "org.onosproject.segmentrouting, org.onosproject.openflow"
142
143 segment_routing = Mock()
144 segment_routing.app_id = "org.onosproject.segmentrouting"
145 segment_routing.backend_code = 1
146
147 openflow = Mock()
148 openflow.app_id = "org.onosproject.openflow"
149 openflow.backend_code = 0
150
151 with patch.object(ONOSApp.objects, "get_items") as app_get, \
152 patch.object(ServiceInstance.objects, "get_items") as mock_si, \
153 self.assertRaises(DeferredException) as e:
154
155 app_get.return_value = [segment_routing, openflow]
156 mock_si.return_value = [self.si]
157 self.sync_step().sync_record(self.onos_app)
158
159 self.assertEqual(e.exception.message, 'Deferring installation of ONOSApp with id 1 as dependencies are not met')
160 self.assertFalse(m.called)
161
162 @requests_mock.Mocker()
163 def test_app_sync_local_app_no_config(self, m):
164 """
165 Activate an application that is already installed in ONOS
166 """
167
168 m.post("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter/active",
169 status_code=200,
170 additional_matcher=match_none)
171
172 m.get("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter",
173 status_code=200,
174 json=self.vrouter_app_response)
175
176 self.si.serviceinstanceattribute_dict = {}
177
178 with patch.object(ServiceInstance.objects, "get_items") as mock_si:
179 mock_si.return_value = [self.si]
180 self.sync_step().sync_record(self.onos_app)
181
182 self.assertTrue(m.called)
183 self.assertEqual(m.call_count, 2)
184 self.assertEqual(self.onos_app.version, self.vrouter_app_response["version"])
185
186 @requests_mock.Mocker()
187 def test_app_sync_local_app_with_config(self, m):
188
189 m.post("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter/active",
190 status_code=200,
191 additional_matcher=match_none)
192
193 m.get("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter",
194 status_code=200,
195 json=self.vrouter_app_response)
196
197 with patch.object(ServiceInstance.objects, "get_items") as mock_si:
198 mock_si.return_value = [self.si]
199 self.sync_step().sync_record(self.onos_app)
200 self.assertTrue(m.called)
201 self.assertEqual(m.call_count, 2)
202 self.assertEqual(self.onos_app.version, self.vrouter_app_response["version"])
203
204 @requests_mock.Mocker()
205 def test_app_install_remote_app_no_config(self, m):
206 """
207 Install an application that has to be downloaded from a remote source
208 """
209
210 self.onos_app.url = 'http://onf.org/maven/...'
211 self.onos_app.version = "1.13.1"
212 self.onos_app.app_id = None
213
214 expected = {
215 'activate': True,
216 'url': self.onos_app.url
217 }
218
219 m.post("/onos/v1/applications",
220 status_code=200,
221 additional_matcher=functools.partial(match_json, expected),
222 json=self.vrouter_app_response)
223
224 m.get("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter",
225 status_code=200,
226 json=self.vrouter_app_response)
227
228 self.si.serviceinstanceattribute_dict = {}
229
230 with patch.object(ServiceInstance.objects, "get_items") as mock_si:
231 mock_si.return_value = [self.si]
232 self.sync_step().sync_record(self.onos_app)
233 self.assertTrue(m.called)
234 self.assertEqual(m.call_count, 2)
235 self.assertEqual(self.onos_app.app_id, self.vrouter_app_response["name"])
236
237 @requests_mock.Mocker()
238 def test_update_remote_app(self, m):
239 self.onos_app.url = 'http://onf.org/maven/...'
240 self.onos_app.version = "1.14.1"
241
242 expected = {
243 'activate': True,
244 'url': self.onos_app.url
245 }
246
247 self.vrouter_app_response_updated = self.vrouter_app_response.copy()
248 self.vrouter_app_response_updated["version"] = "1.14.1"
249
250 m.post("/onos/v1/applications",
251 status_code=200,
252 additional_matcher=functools.partial(match_json, expected),
253 json=self.vrouter_app_response)
254
255
256 m.get("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter",
257 [
258 {"json": self.vrouter_app_response, "status_code": 200},
259 {"json": self.vrouter_app_response_updated, "status_code": 200}
260 ]
261 )
262
263 m.delete("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter",
264 status_code=204)
265
266 self.si.serviceinstanceattribute_dict = {}
267
268 with patch.object(ServiceInstance.objects, "get_items") as mock_si:
269 mock_si.return_value = [self.si]
270 self.sync_step().sync_record(self.onos_app)
271 self.assertTrue(m.called)
272 self.assertEqual(m.call_count, 4)
273 self.assertEqual(self.onos_app.app_id, self.vrouter_app_response_updated["name"])
274
275 @requests_mock.Mocker()
276 def test_app_sync_remote_app_no_config_fail_version(self, m):
277 """
278 Activate an application that has to be downloaded from a remote source
279 """
280
281 self.onos_app.url = 'http://onf.org/maven/...'
282 self.onos_app.version = "1.14.2"
283 self.onos_app.app_id = None
284
285 expected = {
286 'activate': True,
287 'url': self.onos_app.url
288 }
289
290 m.post("/onos/v1/applications",
291 status_code=200,
292 additional_matcher=functools.partial(match_json, expected),
293 json=self.vrouter_app_response)
294
295 m.get("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter",
296 status_code=200,
297 json=self.vrouter_app_response)
298
299 self.si.serviceinstanceattribute_dict = {}
300
301 with patch.object(ServiceInstance.objects, "get_items") as mock_si, \
302 self.assertRaises(Exception) as e:
303 mock_si.return_value = [self.si]
304 self.sync_step().sync_record(self.onos_app)
305
306 self.assertTrue(m.called)
307 self.assertEqual(m.call_count, 2)
308 self.assertEqual(self.onos_app.app_id, self.vrouter_app_response["name"])
309 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)")
310
311 @requests_mock.Mocker()
312 def test_config_delete(self, m):
313 m.delete("http://onos-url:8181%s" % self.onos_app_attribute.name,
314 status_code=204)
315
316 self.sync_step().delete_record(self.onos_app_attribute)
317 self.assertTrue(m.called)
318 self.assertEqual(m.call_count, 1)
319
320 @requests_mock.Mocker()
321 def test_app_deactivate(self, m):
322 m.delete("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter/active",
323 status_code=204)
324
325 self.sync_step().delete_record(self.onos_app)
326 self.assertTrue(m.called)
327 self.assertEqual(m.call_count, 1)
328
329 @requests_mock.Mocker()
330 def test_app_uninstall(self, m):
331 self.onos_app.url = 'http://onf.org/maven/...'
332 self.onos_app.version = "1.14.2"
333 self.onos_app.backend_code = 1
334
335 m.delete("http://onos-url:8181/onos/v1/applications/org.onosproject.vrouter",
336 status_code=204)
337
338 self.sync_step().delete_record(self.onos_app)
339 self.assertTrue(m.called)
340 self.assertEqual(m.call_count, 1)
341
342
343