Projet

Général

Profil

0001-cook-add-unit-tests-for-cook.py-32886.patch

Nicolas Roche, 07 mai 2019 19:36

Télécharger (15,5 ko)

Voir les différences:

Subject: [PATCH 1/2] cook: add unit tests for cook.py (#32886)

 tests/test_cook.py | 375 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 372 insertions(+), 3 deletions(-)
tests/test_cook.py
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
-