Projet

Général

Profil

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

Nicolas Roche, 09 mai 2019 16:40

Télécharger (16,2 ko)

Voir les différences:

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

 tests/test_cook.py | 391 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 388 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
12
from hobo.profile.models import AttributeDefinition
9 13

  
10 14

  
11 15
def test_check_action(monkeypatch):
......
55 59
        command.check_action(action, action_args)
56 60
    assert 'has no valid certificate' in str(e_info.value)
57 61

  
62
def test_handle():
63
    expected = "[call('recipe_me.json')]"
64

  
65
    kwargs = {'verbosity': 'verbosity value',
66
              'timeout': 'timeout value',
67
              'permissive': 'permissive value'}
68
    command = Command()
69
    command.run_cook = mock.Mock()
70

  
71
    command.handle('recipe_me.json', **kwargs)
72
    assert command.verbosity == 'verbosity value'
73
    assert command.timeout == 'timeout value'
74
    assert command.permissive == 'permissive value'
75
    assert str(command.run_cook.mock_calls) == expected
76

  
77
@mock.patch('hobo.environment.management.commands.cook.open')
78
@mock.patch('hobo.environment.management.commands.cook.notify_agents')
79
def test_run_cook(mocked_notify_agents, mocked_open):
80
    receipe = """{
81
  "steps": [
82
    {"create-hobo": {
83
      "url": "https://entrouvert.org/"
84
    }}
85
  ]
86
}"""
87
    expected1 = "[call(u'create-hobo', {u'url': u'https://entrouvert.org/'})]"
88
    expected2 = "[call(url=u'https://entrouvert.org/')]"
89
    expected3 = "[]"
90
    expected4 = "[call(timeout=42)]"
91

  
92
    command = Command()
93
    command.permissive = False
94
    command.must_notify = True
95
    command.timeout = 42
96
    command.check_action = mock.Mock()
97
    command.create_hobo = mock.Mock()
98
    mocked_notify_agents = mock.Mock()
99
    command.wait_operationals = mock.Mock()
100

  
101
    mocked_open.side_effect = [StringIO.StringIO(receipe)]
102
    command.run_cook('recipe_me.json')
103
    assert str(command.check_action.mock_calls) == expected1
104
    assert str(command.create_hobo.mock_calls) == expected2
105
    assert str(mocked_notify_agents.mock_calls) == expected3
106
    assert str(command.wait_operationals.mock_calls) == expected4
107

  
58 108
@mock.patch('hobo.environment.management.commands.cook.open')
59 109
def test_having_several_action_args(mocked_open):
60
    """load variables from a file"""
61 110
    receipe = """{
62 111
  "steps": [
63 112
    {"create-authentic": {
......
70 119

  
71 120
    command = Command()
72 121
    command.permissive = True
73
    command.create_authentic = mock.MagicMock()
122
    command.create_authentic = mock.Mock()
74 123

  
75 124
    mocked_open.side_effect = [StringIO.StringIO(receipe)]
76 125
    command.run_cook('recipe_me.json')
77 126
    assert str(command.create_authentic.mock_calls) == expected_a2
127

  
128
@mock.patch('hobo.environment.management.commands.cook.open')
129
def test_load_variables_from(mocked_open):
130
    """load variables from a file"""
131
    receipe = """{
132
  "load-variables-from": "variables.json",
133
  "variables": {
134
    "domain": "entrouvert.org",
135
    "bar": "bar2"
136
  },
137
  "steps": [
138
    {"create-hobo": {
139
      "url": "https://${domain}/"
140
    }},
141
    {"create-authentic": {
142
      "url": "https://${foo}/"
143
    }},
144
    {"create-combo": {
145
      "url": "https://${bar}/",
146
      "not_a_string": []
147
    }}
148
  ]
149
}"""
150
    variables = """{
151
  "foo": "foo1",
152
  "bar": "bar1"
153
}"""
154
    expected_hobo = "[call(url=u'https://entrouvert.org/')]"
155
    expected_a2 = "[call(url=u'https://foo1/')]"
156
    expected_combo = "[call(not_a_string=[], url=u'https://bar2/')]"
157

  
158
    command = Command()
159
    command.permissive = True
160
    command.create_hobo = mock.Mock()
161
    command.create_authentic = mock.Mock()
162
    command.create_combo = mock.Mock()
163

  
164
    mocked_open.side_effect = [StringIO.StringIO(receipe),
165
                               StringIO.StringIO(variables)]
166
    command.run_cook('recipe_me.json')
167
    assert str(command.create_hobo.mock_calls) == expected_hobo
168
    assert str(command.create_authentic.mock_calls) == expected_a2
169
    assert str(command.create_combo.mock_calls) == expected_combo
170

  
171
def test_wait_operationals(db, monkeypatch):
172
    service1 = mock.Mock()
173
    service2 = mock.Mock()
174
    obj1 = mock.Mock()
175
    obj2 = mock.Mock()
176

  
177
    def do_nothing(*args, **kwargs):
178
        pass
179

  
180
    obj1.check_operational = do_nothing
181
    obj2.check_operational = do_nothing
182
    obj1.base_url = 'url1'
183
    obj2.base_url = 'url2'
184

  
185
    service1.objects.all = mock.Mock(return_value = [obj1])
186
    service2.objects.all = mock.Mock(return_value = [obj2])
187
    monkeypatch.setattr(
188
        'hobo.environment.management.commands.cook.AVAILABLE_SERVICES',
189
        [service1, service2])
190
    command = Command()
191

  
192
    # already operational
193
    obj1.last_operational_success_timestamp = 'some date'
194
    obj2.last_operational_success_timestamp = 'some date'
195
    command.wait_operationals(2)
196
    assert True
197

  
198
    # not operational
199
    obj2.last_operational_success_timestamp = None
200
    with pytest.raises(CommandError) as e_info:
201
        command.wait_operationals(.6)
202
    assert str(e_info).find('CommandError: timeout waiting for url2') != -1
203

  
204
def test_set_variable(db):
205
    command = Command()
206

  
207
    command.set_variable('foo', 'bar')
208
    value = Variable.objects.get(name='foo').value
209
    label = Variable.objects.get(name='foo').label
210
    assert value == 'bar'
211
    assert label == 'foo'
212

  
213
    command.set_variable('foo', 'bar', label='FOO')
214
    value = Variable.objects.get(name='foo').value
215
    label = Variable.objects.get(name='foo').label
216
    assert value == 'bar'
217
    assert label == 'FOO'
218

  
219
    command.set_variable('foo', ['bar', 'baz'])
220
    value = Variable.objects.get(name='foo').value
221
    assert value == '["bar", "baz"]'
222

  
223
    command.set_variable('foo', {'key1': 'bar', 'key2': 'baz'})
224
    value = Variable.objects.get(name='foo').value
225
    ordered_dump = json.dumps(json.loads(value), sort_keys=True)
226
    assert  ordered_dump == '{"key1": "bar", "key2": "baz"}'
227

  
228
def test_set_attribute(db):
229
    command = Command()
230
    command.set_attribute('foo_name', 'foo_label')
231
    values = AttributeDefinition.objects.filter(name='foo_name')
232
    assert values.count() == 1
233
    assert values[0].label == 'foo_label'
234
    assert values[0].disabled is False
235

  
236
    command.set_attribute('foo_name', 'foo_label', disabled=True)
237
    values = AttributeDefinition.objects.filter(name='foo_name')
238
    assert values.count() == 1
239
    assert values[0].label == 'foo_label'
240
    assert values[0].disabled is True
241

  
242
def test_disable_attribute(db):
243
    command = Command()
244
    command.set_attribute('foo_name', 'foo_label')
245
    values = AttributeDefinition.objects.filter(name='foo_name')
246
    assert values.count() == 1
247
    assert values[0].label == 'foo_label'
248
    assert values[0].disabled is False
249

  
250
    command.disable_attribute('foo_name')
251
    values = AttributeDefinition.objects.filter(name='foo_name')
252
    assert values[0].disabled is True
253

  
254
    command.disable_attribute('not_defined')
255
    values = AttributeDefinition.objects.filter(name='not_defined')
256
    assert values.count() == 0
257

  
258
def test_enable_attribute(db):
259
    command = Command()
260
    command.set_attribute('foo_name', 'foo_label', disabled=True)
261
    values = AttributeDefinition.objects.filter(name='foo_name')
262
    assert values.count() == 1
263
    assert values[0].label == 'foo_label'
264
    assert values[0].disabled is True
265

  
266
    command.enable_attribute('foo_name')
267
    values = AttributeDefinition.objects.filter(name='foo_name')
268
    assert values[0].disabled is False
269

  
270
    command.enable_attribute('not_defined')
271
    values = AttributeDefinition.objects.filter(name='not_defined')
272
    assert values.count() == 0
273

  
274
def test_create_superuser(db):
275
    command = Command()
276
    command.create_superuser()
277
    assert User.objects.count() == 1
278
    user = User.objects.all()[0]
279
    assert user.username == 'admin'
280
    assert user.is_superuser is True
281

  
282
def test_create_site(db):
283
    """
284
    code redondant ?
285
      service_type=obj_type,
286
      service_pk=obj.id,
287
    """
288
    command = Command()
289
    base_url = 'http://entrouvert.org'
290
    title = 'site title'
291
    slug = None
292
    template_name = ''
293
    variables = {'foo': {'label': 'FOO', 'value': {'key': 'bar'}}}
294
    command.create_site(Combo, base_url, title, slug, template_name,
295
                        variables)
296

  
297
    # Combo object
298
    assert Combo.objects.count() == 1
299
    combo = Combo.objects.all()[0]
300
    assert combo.title == title
301
    assert combo.base_url == base_url + '/'
302
    assert combo.template_name == ''
303

  
304
    # ContentType object
305
    obj_type = ContentType.objects.get_for_model(Combo)
306

  
307
    # Variables
308
    variable = Variable.objects.get(name='foo')
309
    assert variable.label == 'FOO'
310
    assert variable.value == '{"key": "bar"}'
311
    assert variable.service_type == obj_type
312
    assert variable.service_pk == combo.id
313

  
314
    with pytest.raises(CommandError) as e_info:
315
        command.create_site(Combo, 'unvalid_url', 'site title', 'a slug', '', '')
316
    assert 'Enter a valid URL.' in str(e_info.value)
317

  
318
@mock.patch('hobo.environment.management.commands.cook.connection')
319
@mock.patch('hobo.environment.management.commands.cook.call_command')
320
@mock.patch('hobo.environment.management.commands.cook.TenantMiddleware')
321
def test_create_hobo_primary(mocked_TenantMiddleware, mocked_call_command,
322
                             mocked_connection):
323
    expected1 = '[]'
324
    expected2 = "[call('create_hobo_tenant', 'entrouvert.org')]"
325
    expected3 = "[call('/bof/base_url', 'w'),\n" + \
326
      " call().write('http://entrouvert.org/and_much'),\n" + \
327
      " call().close()]"
328

  
329
    command = Command()
330
    command.create_site = mock.Mock()
331
    tenant = mock.Mock()
332
    tenant.schema_name = 'public'
333
    tenant.get_directory = mock.Mock(return_value='/bof')
334
    mocked_connection.get_tenant = mock.Mock(return_value=tenant)
335
    mocked_connection.set_tenant = mock.Mock()
336
    mocked_TenantMiddleware.get_tenant_by_hostname = mock.Mock(return_value=tenant)
337
    mocked_call_command.side_effect = CommandError
338

  
339
    mocked_open = mock.mock_open()
340
    with mock.patch('hobo.environment.management.commands.cook.open', mocked_open,
341
                    create=True):
342
        command.create_hobo('http://entrouvert.org/and_much')
343
    assert str(command.create_site.mock_calls) == expected1
344
    assert str(mocked_call_command.mock_calls) == expected2
345
    assert len(mocked_connection.set_tenant.mock_calls) == 1
346
    assert str(mocked_open.mock_calls) == expected3
347

  
348
@mock.patch('hobo.environment.management.commands.cook.connection')
349
@mock.patch('hobo.environment.management.commands.cook.call_command')
350
@mock.patch('hobo.environment.management.commands.cook.TenantMiddleware')
351
def test_create_hobo_not_primary(mocked_TenantMiddleware, mocked_call_command,
352
                     mocked_connection):
353
    command = Command()
354
    command.create_site = mock.Mock()
355
    tenant = mock.Mock()
356
    tenant.schema_name = 'public'
357
    tenant.get_directory = mock.Mock(return_value='/bof')
358
    mocked_connection.get_tenant = mock.Mock(return_value=tenant)
359
    mocked_connection.set_tenant = mock.Mock()
360
    mocked_TenantMiddleware.get_tenant_by_hostname = mock.Mock(return_value=tenant)
361

  
362
    expected1 = "[call(<class 'hobo.environment.models.Hobo'>, " + \
363
      "'http://entrouvert.org/and_much', None, u'hobo-none', " + \
364
      "template_name='', variables=None)]"
365
    expected2 = "[]"
366
    expected3 = "[]"
367

  
368
    tenant.schema_name = 'other than public'
369
    mocked_open = mock.mock_open()
370
    with mock.patch('hobo.environment.management.commands.cook.open', mocked_open,
371
                    create=True):
372
        command.create_hobo('http://entrouvert.org/and_much')
373
    assert str(command.create_site.mock_calls) == expected1
374
    assert str(mocked_call_command.mock_calls) == expected2
375
    assert len(mocked_connection.set_tenant.mock_calls) == 1
376
    assert str(mocked_open.mock_calls) == expected3
377

  
378
def test_create_services():
379
    endings = ", 'url', 'title', None, '', None)"
380
    expected = "[call(<class 'hobo.environment.models.Authentic'>" + endings
381
    expected += ",\n call(<class 'hobo.environment.models.Combo'>" + endings
382
    expected += ",\n call(<class 'hobo.environment.models.Wcs'>" + endings
383
    expected += ",\n call(<class 'hobo.environment.models.Passerelle'>" + endings
384
    expected += ",\n call(<class 'hobo.environment.models.Fargo'>" + endings
385
    expected += ",\n call(<class 'hobo.environment.models.Welco'>" + endings
386
    expected += ",\n call(<class 'hobo.environment.models.Chrono'>" + endings
387
    expected += ",\n call(<class 'hobo.environment.models.Corbo'>" + endings
388
    expected += ",\n call(<class 'hobo.environment.models.BiJoe'>" + endings
389
    expected += "]"
390

  
391
    command = Command()
392
    command.create_site = mock.Mock()
393
    command.create_authentic('url', 'title')
394
    command.create_combo('url', 'title')
395
    command.create_wcs('url', 'title')
396
    command.create_passerelle('url', 'title')
397
    command.create_fargo('url', 'title')
398
    command.create_welco('url', 'title')
399
    command.create_chrono('url', 'title')
400
    command.create_corbo('url', 'title')
401
    command.create_bijoe('url', 'title')
402

  
403
    assert len(command.create_site.mock_calls) == 9
404
    assert str(command.create_site.mock_calls) == expected
405

  
406
def test_set_idp(db):
407
    command = Command()
408

  
409
    # TODO: maybe we should handle this into cook.py ?
410
    with pytest.raises(Authentic.DoesNotExist,
411
                       match='Authentic matching query does not exist'):
412
        command.set_idp('url')
413
    with pytest.raises(IndexError, match='list index out of range'):
414
        command.set_idp()
415

  
416
    # objects sorted on title: [obj1, obj2]
417
    obj1, ignored = Authentic.objects.get_or_create(
418
        slug='slug1', defaults={'title': 'bar'})
419
    obj2, ignored = Authentic.objects.get_or_create(
420
        slug='slug2', defaults={'title': 'foo', 'base_url': 'http://example.org'})
421
    assert obj1.use_as_idp_for_self is False
422
    assert obj2.use_as_idp_for_self is False
423

  
424
    # set first
425
    command.set_idp('')
426
    obj = Authentic.objects.get(title='bar')
427
    assert obj.use_as_idp_for_self is True
428

  
429
    # set using url
430
    command.set_idp('http://example.org/')
431
    obj = Authentic.objects.get(title='foo')
432
    assert obj.use_as_idp_for_self is True
433

  
434
@mock.patch('hobo.environment.management.commands.cook.set_theme')
435
@mock.patch('hobo.environment.management.commands.cook.connection')
436
@mock.patch('hobo.agent.common.management.commands.hobo_deploy.Command.configure_theme')
437
def test_set_theme(mocked_configure_theme, mocked_connection, mocked_set_theme):
438
    expected1 = "[call('the theme')]"
439
    expected2 = "[call({'variables': {'theme': 'the theme'}}, 'the tenant')]"
440

  
441
    mocked_connection.get_tenant = mock.Mock(return_value='the tenant')
442
    command = Command()
443
    command.set_theme('the theme')
444

  
445
    assert str(mocked_set_theme.mock_calls) == expected1
446
    assert len(mocked_connection.get_tenant.mock_calls) == 1
447
    assert str(mocked_configure_theme.mock_calls) == expected2
448

  
449
@mock.patch('hobo.environment.management.commands.cook.connection')
450
def test_cook(mocked_connection):
451
    expected1 = "[call('a-recipe-file.json')]"
452
    expected2 = "[call('the tenant')]"
453

  
454
    mocked_connection.get_tenant = mock.Mock(return_value='the tenant')
455
    mocked_connection.set_tenant = mock.Mock()
456
    command = Command()
457
    command.run_cook = mock.Mock()
458
    command.cook('a-recipe-file.json')
459

  
460
    assert len(mocked_connection.get_tenant.mock_calls) == 1
461
    assert str(command.run_cook.mock_calls) == expected1
462
    assert str(mocked_connection.set_tenant.mock_calls) == expected2
78
-