1 |
1 |
import pytest
|
|
2 |
import json
|
2 |
3 |
import mock
|
3 |
4 |
import StringIO
|
4 |
5 |
|
|
6 |
from django.contrib.auth.models import User
|
|
7 |
from django.contrib.contenttypes.models import ContentType
|
5 |
8 |
from django.core.management.base import CommandError
|
6 |
9 |
|
7 |
|
from hobo.environment.models import ServiceBase
|
|
10 |
from hobo.environment.models import Authentic, Combo, ServiceBase, Variable
|
8 |
11 |
from hobo.environment.management.commands.cook import Command
|
9 |
|
|
|
12 |
from hobo.profile.models import AttributeDefinition
|
10 |
13 |
|
11 |
14 |
def test_check_action(monkeypatch):
|
12 |
15 |
"""no exception raised if url are available"""
|
... | ... | |
55 |
58 |
command.check_action(action, action_args)
|
56 |
59 |
assert 'has no valid certificate' in str(e_info.value)
|
57 |
60 |
|
|
61 |
def test_handle():
|
|
62 |
expected = "[call('recipe_me.json')]"
|
|
63 |
|
|
64 |
kwargs = {'verbosity': 'verbosity value',
|
|
65 |
'timeout': 'timeout value',
|
|
66 |
'permissive': 'permissive value'}
|
|
67 |
command = Command()
|
|
68 |
command.run_cook = mock.MagicMock()
|
|
69 |
|
|
70 |
command.handle('recipe_me.json', **kwargs)
|
|
71 |
assert command.verbosity == 'verbosity value'
|
|
72 |
assert command.timeout == 'timeout value'
|
|
73 |
assert command.permissive == 'permissive value'
|
|
74 |
assert str(command.run_cook.mock_calls) == expected
|
|
75 |
|
|
76 |
@mock.patch('hobo.environment.management.commands.cook.open')
|
|
77 |
@mock.patch('hobo.environment.management.commands.cook.notify_agents')
|
|
78 |
def test_cook(mocked_notify_agents, mocked_open):
|
|
79 |
receipe = """{
|
|
80 |
"steps": [
|
|
81 |
{"create-hobo": {
|
|
82 |
"url": "https://entrouvert.org/"
|
|
83 |
}}
|
|
84 |
]
|
|
85 |
}"""
|
|
86 |
expected1 = "[call(u'create-hobo', {u'url': u'https://entrouvert.org/'})]"
|
|
87 |
expected2 = "[call(url=u'https://entrouvert.org/')]"
|
|
88 |
expected3 = "[]"
|
|
89 |
expected4 = "[call(timeout=42)]"
|
|
90 |
|
|
91 |
command = Command()
|
|
92 |
command.permissive = False
|
|
93 |
command.must_notify = True
|
|
94 |
command.timeout = 42
|
|
95 |
command.check_action = mock.Mock()
|
|
96 |
command.create_hobo = mock.Mock()
|
|
97 |
mocked_notify_agents = mock.Mock()
|
|
98 |
command.wait_operationals = mock.Mock()
|
|
99 |
|
|
100 |
mocked_open.side_effect = [StringIO.StringIO(receipe)]
|
|
101 |
command.run_cook('recipe_me.json')
|
|
102 |
assert str(command.check_action.mock_calls) == expected1
|
|
103 |
assert str(command.create_hobo.mock_calls) == expected2
|
|
104 |
assert str(mocked_notify_agents.mock_calls) == expected3
|
|
105 |
assert str(command.wait_operationals.mock_calls) == expected4
|
|
106 |
|
58 |
107 |
@mock.patch('hobo.environment.management.commands.cook.open')
|
59 |
108 |
def test_having_several_action_args(mocked_open):
|
60 |
|
"""load variables from a file"""
|
61 |
109 |
receipe = """{
|
62 |
110 |
"steps": [
|
63 |
111 |
{"create-authentic": {
|
... | ... | |
75 |
123 |
mocked_open.side_effect = [StringIO.StringIO(receipe)]
|
76 |
124 |
command.run_cook('recipe_me.json')
|
77 |
125 |
assert str(command.create_authentic.mock_calls) == expected_a2
|
|
126 |
|
|
127 |
@mock.patch('hobo.environment.management.commands.cook.open')
|
|
128 |
def test_load_variables_from(mocked_open):
|
|
129 |
"""load variables from a file"""
|
|
130 |
receipe = """{
|
|
131 |
"load-variables-from": "variables.json",
|
|
132 |
"variables": {
|
|
133 |
"domain": "entrouvert.org",
|
|
134 |
"bar": "bar2"
|
|
135 |
},
|
|
136 |
"steps": [
|
|
137 |
{"create-hobo": {
|
|
138 |
"url": "https://${domain}/"
|
|
139 |
}},
|
|
140 |
{"create-authentic": {
|
|
141 |
"url": "https://${foo}/"
|
|
142 |
}},
|
|
143 |
{"create-combo": {
|
|
144 |
"url": "https://${bar}/",
|
|
145 |
"not_a_string": []
|
|
146 |
}}
|
|
147 |
]
|
|
148 |
}"""
|
|
149 |
variables = """{
|
|
150 |
"foo": "foo1",
|
|
151 |
"bar": "bar1"
|
|
152 |
}"""
|
|
153 |
expected_hobo = "[call(url=u'https://entrouvert.org/')]"
|
|
154 |
expected_a2 = "[call(url=u'https://foo1/')]"
|
|
155 |
expected_combo = "[call(not_a_string=[], url=u'https://bar2/')]"
|
|
156 |
|
|
157 |
command = Command()
|
|
158 |
command.permissive = True
|
|
159 |
command.create_hobo = mock.MagicMock()
|
|
160 |
command.create_authentic = mock.MagicMock()
|
|
161 |
command.create_combo = mock.MagicMock()
|
|
162 |
|
|
163 |
mocked_open.side_effect = [StringIO.StringIO(receipe),
|
|
164 |
StringIO.StringIO(variables)]
|
|
165 |
command.run_cook('recipe_me.json')
|
|
166 |
assert str(command.create_hobo.mock_calls) == expected_hobo
|
|
167 |
assert str(command.create_authentic.mock_calls) == expected_a2
|
|
168 |
assert str(command.create_combo.mock_calls) == expected_combo
|
|
169 |
|
|
170 |
def test_wait_operationals(db, monkeypatch):
|
|
171 |
service1 = mock.MagicMock()
|
|
172 |
service2 = mock.MagicMock()
|
|
173 |
obj1 = mock.MagicMock()
|
|
174 |
obj2 = mock.MagicMock()
|
|
175 |
|
|
176 |
def do_nothing(*args, **kwargs):
|
|
177 |
pass
|
|
178 |
|
|
179 |
obj1.check_operational = do_nothing
|
|
180 |
obj2.check_operational = do_nothing
|
|
181 |
obj1.base_url = 'url1'
|
|
182 |
obj2.base_url = 'url2'
|
|
183 |
|
|
184 |
service1.objects.all = mock.MagicMock(return_value = [obj1])
|
|
185 |
service2.objects.all = mock.MagicMock(return_value = [obj2])
|
|
186 |
monkeypatch.setattr(
|
|
187 |
'hobo.environment.management.commands.cook.AVAILABLE_SERVICES',
|
|
188 |
[service1, service2])
|
|
189 |
command = Command()
|
|
190 |
|
|
191 |
# already operational
|
|
192 |
obj1.last_operational_success_timestamp = 'some date'
|
|
193 |
obj2.last_operational_success_timestamp = 'some date'
|
|
194 |
command.wait_operationals(2)
|
|
195 |
assert True
|
|
196 |
|
|
197 |
# not operational
|
|
198 |
obj2.last_operational_success_timestamp = None
|
|
199 |
with pytest.raises(CommandError) as e_info:
|
|
200 |
command.wait_operationals(.6)
|
|
201 |
assert str(e_info).find('CommandError: timeout waiting for url2') != -1
|
|
202 |
|
|
203 |
def test_set_variable(db):
|
|
204 |
command = Command()
|
|
205 |
|
|
206 |
command.set_variable('foo', 'bar')
|
|
207 |
value = Variable.objects.get(name='foo').value
|
|
208 |
label = Variable.objects.get(name='foo').label
|
|
209 |
assert value == 'bar'
|
|
210 |
assert label == 'foo'
|
|
211 |
|
|
212 |
command.set_variable('foo', 'bar', label='FOO')
|
|
213 |
value = Variable.objects.get(name='foo').value
|
|
214 |
label = Variable.objects.get(name='foo').label
|
|
215 |
assert value == 'bar'
|
|
216 |
assert label == 'FOO'
|
|
217 |
|
|
218 |
command.set_variable('foo', ['bar', 'baz'])
|
|
219 |
value = Variable.objects.get(name='foo').value
|
|
220 |
assert value == '["bar", "baz"]'
|
|
221 |
|
|
222 |
command.set_variable('foo', {'key1': 'bar', 'key2': 'baz'})
|
|
223 |
value = Variable.objects.get(name='foo').value
|
|
224 |
ordered_dump = json.dumps(json.loads(value), sort_keys=True)
|
|
225 |
assert ordered_dump == '{"key1": "bar", "key2": "baz"}'
|
|
226 |
|
|
227 |
def test_set_attribute(db):
|
|
228 |
command = Command()
|
|
229 |
command.set_attribute('foo_name', 'foo_label')
|
|
230 |
values = AttributeDefinition.objects.filter(name='foo_name')
|
|
231 |
assert values.count() == 1
|
|
232 |
assert values[0].label == 'foo_label'
|
|
233 |
assert values[0].disabled is False
|
|
234 |
|
|
235 |
command.set_attribute('foo_name', 'foo_label', disabled=True)
|
|
236 |
values = AttributeDefinition.objects.filter(name='foo_name')
|
|
237 |
assert values.count() == 1
|
|
238 |
assert values[0].label == 'foo_label'
|
|
239 |
assert values[0].disabled is True
|
|
240 |
|
|
241 |
def test_disable_attribute(db):
|
|
242 |
command = Command()
|
|
243 |
command.set_attribute('foo_name', 'foo_label')
|
|
244 |
values = AttributeDefinition.objects.filter(name='foo_name')
|
|
245 |
assert values.count() == 1
|
|
246 |
assert values[0].label == 'foo_label'
|
|
247 |
assert values[0].disabled is False
|
|
248 |
|
|
249 |
command.disable_attribute('foo_name')
|
|
250 |
values = AttributeDefinition.objects.filter(name='foo_name')
|
|
251 |
assert values[0].disabled is True
|
|
252 |
|
|
253 |
command.disable_attribute('not_defined')
|
|
254 |
values = AttributeDefinition.objects.filter(name='not_defined')
|
|
255 |
assert values.count() == 0
|
|
256 |
|
|
257 |
def test_enable_attribute(db):
|
|
258 |
command = Command()
|
|
259 |
command.set_attribute('foo_name', 'foo_label', disabled=True)
|
|
260 |
values = AttributeDefinition.objects.filter(name='foo_name')
|
|
261 |
assert values.count() == 1
|
|
262 |
assert values[0].label == 'foo_label'
|
|
263 |
assert values[0].disabled is True
|
|
264 |
|
|
265 |
command.enable_attribute('foo_name')
|
|
266 |
values = AttributeDefinition.objects.filter(name='foo_name')
|
|
267 |
assert values[0].disabled is False
|
|
268 |
|
|
269 |
command.enable_attribute('not_defined')
|
|
270 |
values = AttributeDefinition.objects.filter(name='not_defined')
|
|
271 |
assert values.count() == 0
|
|
272 |
|
|
273 |
def test_create_superuser(db):
|
|
274 |
command = Command()
|
|
275 |
command.create_superuser()
|
|
276 |
assert User.objects.count() == 1
|
|
277 |
user = User.objects.all()[0]
|
|
278 |
assert user.username == 'admin'
|
|
279 |
assert user.is_superuser is True
|
|
280 |
|
|
281 |
def test_create_site(db):
|
|
282 |
"""
|
|
283 |
code redondant ?
|
|
284 |
service_type=obj_type,
|
|
285 |
service_pk=obj.id,
|
|
286 |
"""
|
|
287 |
command = Command()
|
|
288 |
base_url = 'http://entrouvert.org'
|
|
289 |
title = 'site title'
|
|
290 |
slug = None
|
|
291 |
template_name = ''
|
|
292 |
variables = {'foo': {'label': 'FOO', 'value': {'key': 'bar'}}}
|
|
293 |
command.create_site(Combo, base_url, title, slug, template_name,
|
|
294 |
variables)
|
|
295 |
|
|
296 |
# Combo object
|
|
297 |
assert Combo.objects.count() == 1
|
|
298 |
combo = Combo.objects.all()[0]
|
|
299 |
assert combo.title == title
|
|
300 |
assert combo.base_url == base_url + '/'
|
|
301 |
assert combo.template_name == ''
|
|
302 |
|
|
303 |
# ContentType object
|
|
304 |
obj_type = ContentType.objects.get_for_model(Combo)
|
|
305 |
|
|
306 |
# Variables
|
|
307 |
variable = Variable.objects.get(name='foo')
|
|
308 |
assert variable.label == 'FOO'
|
|
309 |
assert variable.value == '{"key": "bar"}'
|
|
310 |
assert variable.service_type == obj_type
|
|
311 |
assert variable.service_pk == combo.id
|
|
312 |
|
|
313 |
with pytest.raises(CommandError) as e_info:
|
|
314 |
command.create_site(Combo, 'unvalid_url', 'site title', 'a slug', '', '')
|
|
315 |
assert 'Enter a valid URL.' in str(e_info.value)
|
|
316 |
|
|
317 |
@mock.patch('hobo.environment.management.commands.cook.connection')
|
|
318 |
@mock.patch('hobo.environment.management.commands.cook.call_command')
|
|
319 |
@mock.patch('hobo.environment.management.commands.cook.TenantMiddleware')
|
|
320 |
def test_create_hobo_primary(mocked_TenantMiddleware, mocked_call_command,
|
|
321 |
mocked_connection):
|
|
322 |
expected1 = '[]'
|
|
323 |
expected2 = "[call('create_hobo_tenant', 'entrouvert.org')]"
|
|
324 |
expected3 = "[call('/bof/base_url', 'w'),\n" + \
|
|
325 |
" call().write('http://entrouvert.org/and_much'),\n" + \
|
|
326 |
" call().close()]"
|
|
327 |
|
|
328 |
command = Command()
|
|
329 |
command.create_site = mock.MagicMock()
|
|
330 |
tenant = mock.Mock()
|
|
331 |
tenant.schema_name = 'public'
|
|
332 |
tenant.get_directory = mock.Mock(return_value='/bof')
|
|
333 |
mocked_connection.get_tenant = mock.Mock(return_value=tenant)
|
|
334 |
mocked_connection.set_tenant = mock.Mock()
|
|
335 |
mocked_TenantMiddleware.get_tenant_by_hostname = mock.Mock(return_value=tenant)
|
|
336 |
mocked_call_command.side_effect = CommandError
|
|
337 |
|
|
338 |
mocked_open = mock.mock_open()
|
|
339 |
with mock.patch('hobo.environment.management.commands.cook.open', mocked_open,
|
|
340 |
create=True):
|
|
341 |
command.create_hobo('http://entrouvert.org/and_much')
|
|
342 |
assert str(command.create_site.mock_calls) == expected1
|
|
343 |
assert str(mocked_call_command.mock_calls) == expected2
|
|
344 |
assert len(mocked_connection.set_tenant.mock_calls) == 1
|
|
345 |
assert str(mocked_open.mock_calls) == expected3
|
|
346 |
|
|
347 |
@mock.patch('hobo.environment.management.commands.cook.connection')
|
|
348 |
@mock.patch('hobo.environment.management.commands.cook.call_command')
|
|
349 |
@mock.patch('hobo.environment.management.commands.cook.TenantMiddleware')
|
|
350 |
def test_create_hobo_not_primary(mocked_TenantMiddleware, mocked_call_command,
|
|
351 |
mocked_connection):
|
|
352 |
command = Command()
|
|
353 |
command.create_site = mock.MagicMock()
|
|
354 |
tenant = mock.Mock()
|
|
355 |
tenant.schema_name = 'public'
|
|
356 |
tenant.get_directory = mock.Mock(return_value='/bof')
|
|
357 |
mocked_connection.get_tenant = mock.Mock(return_value=tenant)
|
|
358 |
mocked_connection.set_tenant = mock.Mock()
|
|
359 |
mocked_TenantMiddleware.get_tenant_by_hostname = mock.Mock(return_value=tenant)
|
|
360 |
|
|
361 |
expected1 = "[call(<class 'hobo.environment.models.Hobo'>, " + \
|
|
362 |
"'http://entrouvert.org/and_much', None, u'hobo-none', " + \
|
|
363 |
"template_name='', variables=None)]"
|
|
364 |
expected2 = "[]"
|
|
365 |
expected3 = "[]"
|
|
366 |
|
|
367 |
tenant.schema_name = 'other than public'
|
|
368 |
mocked_open = mock.mock_open()
|
|
369 |
with mock.patch('hobo.environment.management.commands.cook.open', mocked_open,
|
|
370 |
create=True):
|
|
371 |
command.create_hobo('http://entrouvert.org/and_much')
|
|
372 |
assert str(command.create_site.mock_calls) == expected1
|
|
373 |
assert str(mocked_call_command.mock_calls) == expected2
|
|
374 |
assert len(mocked_connection.set_tenant.mock_calls) == 1
|
|
375 |
assert str(mocked_open.mock_calls) == expected3
|
|
376 |
|
|
377 |
def test_create_services():
|
|
378 |
endings = ", 'url', 'title', None, '', None)"
|
|
379 |
expected = "[call(<class 'hobo.environment.models.Authentic'>" + endings
|
|
380 |
expected += ",\n call(<class 'hobo.environment.models.Combo'>" + endings
|
|
381 |
expected += ",\n call(<class 'hobo.environment.models.Wcs'>" + endings
|
|
382 |
expected += ",\n call(<class 'hobo.environment.models.Passerelle'>" + endings
|
|
383 |
expected += ",\n call(<class 'hobo.environment.models.Fargo'>" + endings
|
|
384 |
expected += ",\n call(<class 'hobo.environment.models.Welco'>" + endings
|
|
385 |
expected += ",\n call(<class 'hobo.environment.models.Chrono'>" + endings
|
|
386 |
expected += ",\n call(<class 'hobo.environment.models.Corbo'>" + endings
|
|
387 |
expected += ",\n call(<class 'hobo.environment.models.BiJoe'>" + endings
|
|
388 |
expected += "]"
|
|
389 |
|
|
390 |
command = Command()
|
|
391 |
command.create_site = mock.MagicMock()
|
|
392 |
command.create_authentic('url', 'title')
|
|
393 |
command.create_combo('url', 'title')
|
|
394 |
command.create_wcs('url', 'title')
|
|
395 |
command.create_passerelle('url', 'title')
|
|
396 |
command.create_fargo('url', 'title')
|
|
397 |
command.create_welco('url', 'title')
|
|
398 |
command.create_chrono('url', 'title')
|
|
399 |
command.create_corbo('url', 'title')
|
|
400 |
command.create_bijoe('url', 'title')
|
|
401 |
|
|
402 |
assert len(command.create_site.mock_calls) == 9
|
|
403 |
assert str(command.create_site.mock_calls) == expected
|
|
404 |
|
|
405 |
def test_set_idp(db):
|
|
406 |
command = Command()
|
|
407 |
|
|
408 |
# TODO: maybe we should handle this into cook.py ?
|
|
409 |
with pytest.raises(Authentic.DoesNotExist,
|
|
410 |
match='Authentic matching query does not exist'):
|
|
411 |
command.set_idp('url')
|
|
412 |
with pytest.raises(IndexError, match='list index out of range'):
|
|
413 |
command.set_idp()
|
|
414 |
|
|
415 |
# objects sorted on title: [obj1, obj2]
|
|
416 |
obj1, ignored = Authentic.objects.get_or_create(
|
|
417 |
slug='slug1', defaults={'title': 'bar'})
|
|
418 |
obj2, ignored = Authentic.objects.get_or_create(
|
|
419 |
slug='slug2', defaults={'title': 'foo', 'base_url': 'http://example.org'})
|
|
420 |
assert obj1.use_as_idp_for_self is False
|
|
421 |
assert obj2.use_as_idp_for_self is False
|
|
422 |
|
|
423 |
# set first
|
|
424 |
command.set_idp('')
|
|
425 |
obj = Authentic.objects.get(title='bar')
|
|
426 |
assert obj.use_as_idp_for_self is True
|
|
427 |
|
|
428 |
# set using url
|
|
429 |
command.set_idp('http://example.org/')
|
|
430 |
obj = Authentic.objects.get(title='foo')
|
|
431 |
assert obj.use_as_idp_for_self is True
|
|
432 |
|
|
433 |
@mock.patch('hobo.environment.management.commands.cook.set_theme')
|
|
434 |
@mock.patch('hobo.environment.management.commands.cook.connection')
|
|
435 |
@mock.patch('hobo.agent.common.management.commands.hobo_deploy.Command.configure_theme')
|
|
436 |
def test_set_theme(mocked_configure_theme, mocked_connection, mocked_set_theme):
|
|
437 |
expected1 = "[call('the theme')]"
|
|
438 |
expected2 = "[call({'variables': {'theme': 'the theme'}}, 'the tenant')]"
|
|
439 |
|
|
440 |
mocked_connection.get_tenant = mock.Mock(return_value='the tenant')
|
|
441 |
command = Command()
|
|
442 |
command.set_theme('the theme')
|
|
443 |
|
|
444 |
assert str(mocked_set_theme.mock_calls) == expected1
|
|
445 |
assert len(mocked_connection.get_tenant.mock_calls) == 1
|
|
446 |
assert str(mocked_configure_theme.mock_calls) == expected2
|
78 |
|
-
|