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