Projet

Général

Profil

0001-hobo_deploy-add-unit-tests-for-hobo_deploy.py-33224.patch

Nicolas Roche, 24 mai 2019 21:16

Télécharger (30,2 ko)

Voir les différences:

Subject: [PATCH] hobo_deploy: add unit tests for hobo_deploy.py (#33224)

 README                             |   6 +-
 tests/test_hobo_deploy.py          | 561 +++++++++++++++++++++++++++++
 tests_schemas/env.json             |  40 ++
 tests_schemas/settings.py          |   1 +
 tests_schemas/test_hobo_deploy.py  |  61 ++++
 tests_schemas/test_hobo_deploy2.py |  41 +++
 6 files changed, 707 insertions(+), 3 deletions(-)
 create mode 100644 tests/test_hobo_deploy.py
 create mode 100644 tests_schemas/env.json
 create mode 100644 tests_schemas/test_hobo_deploy.py
 create mode 100644 tests_schemas/test_hobo_deploy2.py
README
82 82
`BaseService`. For each service in the environment dictionary sent by the hobo
83 83
portal, it's instantiated with the key `base_url`, `title` and `secret_key` of
84 84
the service. If the `base_url` matches the `AGENT_HOST_PATTERNS` locally
85
defined, the `execute()` method of the instant is called, passing it the full
86
environment dictionary.
85
defined, the `execute()` method of the instance is called, passing it his
86
`base_url` and the full environment dictionary.
87 87

  
88 88
The environment dictionary contains services for this particular agent and all
89 89
other services defined on the portal. The `execute()` method should only create
......
152 152

  
153 153
authentic2 instances will be deployed using
154 154
"/usr/bin/authentic2-multitenant-manage" by default, this command can be
155
adapted in the AUTHENTIC_MANAGE_COMMAND setting.  It should be run with the
155
adapted in the AUTHENTIC_MANAGE_COMMAND setting. It should be run with the
156 156
same rights as the authentic2 process (redefine the command to use sudo if
157 157
necessary).
158 158

  
tests/test_hobo_deploy.py
1
""" unit tests (mainly for code coverage)
2
"""
3
import StringIO
4
import os
5
import sys
6

  
7
import json
8
import pytest
9
from mock import call, patch, Mock
10
from requests import Response, exceptions
11

  
12
from hobo.agent.combo.management.commands.hobo_deploy import Command as ComboCommand
13
from hobo.agent.common.management.commands.hobo_deploy import (
14
    replace_file, Command, CommandError)
15
from hobo.agent.hobo.management.commands.hobo_deploy import Command as HoboCommand
16
from hobo.environment.models import Variable, Combo, Hobo, Wcs
17
from hobo.multitenant.middleware import TenantNotFound
18

  
19

  
20
@pytest.fixture
21
def fake_themes(settings, tmpdir):
22
    THEMES="""
23
[
24
  {
25
    "id": "alfortville",
26
    "label": "Alfortville",
27
    "variables": {
28
      "css_variant": "alfortville",
29
      "no_extra_js": false,
30
      "theme_color": "#804697"
31
    },
32
    "overlay": "foobar"
33
  },
34
  {
35
    "id": "publik",
36
    "label": "Publik",
37
    "variables": {
38
      "css_variant": "publik",
39
      "no_extra_js": false,
40
      "theme_color": "#E80E89"
41
    }
42
  }
43
]
44
"""
45
    base_dir = str(tmpdir.mkdir('themes'))
46
    settings.THEMES_DIRECTORY = base_dir
47

  
48
    themes_dir = os.path.join(base_dir, 'publik-base')
49
    os.mkdir(themes_dir)
50
    with open(os.path.join(themes_dir, 'themes.json'), 'w') as handler:
51
        handler.write(THEMES)
52

  
53
    # populate 'foobar' overlay
54
    themes_dir = os.path.join(base_dir, 'foobar')
55
    os.mkdir(themes_dir)
56
    for part in ('static', 'templates'):
57
        os.mkdir(os.path.join(themes_dir, part))
58

  
59

  
60
def test_replace_file(tmpdir):
61
    path = str(tmpdir) + '/my_file.txt'
62

  
63
    content = 'content of my new file'
64
    replace_file(path, content)
65
    with open(path, 'r') as handler:
66
        assert handler.read() == content
67

  
68
    content = 'new content for my file'
69
    replace_file(path, content)
70
    with open(path, 'r') as handler:
71
        assert handler.read() == content
72

  
73

  
74
def test_handle_from_scratch():
75
    """API using JSON from file or from stdin"""
76
    command = Command()
77
    CONTENT = """
78
{
79
    "services": [{
80
        "service-id": "combo"
81
    }]
82
}
83
"""
84
    command.deploy = Mock()
85
    EXPECTED = [call('https://combo.dev.publik.love/',
86
                     {'services': [{'service-id': 'combo'}]}, None)]
87

  
88
    # handle from file
89
    command.deploy.reset_mock()
90
    with patch('hobo.agent.common.management.commands.hobo_deploy.file') as mocked_open:
91
        mocked_open.side_effect = [StringIO.StringIO(CONTENT)]
92
        command.handle('https://combo.dev.publik.love/', 'envbof.json')
93
    assert command.deploy.mock_calls == EXPECTED
94

  
95
    # handle using a pipe
96
    command.deploy.reset_mock()
97
    backup = sys.stdin
98
    sys.stdin = StringIO.StringIO(CONTENT)
99
    command.handle('https://combo.dev.publik.love/', '-')
100
    sys.stdin = backup
101
    assert command.deploy.mock_calls == EXPECTED
102

  
103
    # JSON having syntax error
104
    command.deploy.reset_mock()
105
    with patch('hobo.agent.common.management.commands.hobo_deploy.file') as mocked_open:
106
        mocked_open.side_effect = [StringIO.StringIO('malformated JSON')]
107
        with pytest.raises(ValueError, match='No JSON object could be decoded'):
108
            command.handle('https://combo.dev.publik.love/', 'env.json')
109
    assert command.deploy.mock_calls == []
110

  
111
    # missing args
112
    with pytest.raises(CommandError, match='missing args'):
113
        command.handle('https://combo.dev.publik.love/')
114
    with pytest.raises(CommandError, match='missing args'):
115
        command.handle(json_filename='env.json')
116

  
117

  
118
@patch('hobo.agent.common.management.commands.hobo_deploy.TenantMiddleware.get_tenants')
119
def test_handle_redeploy_case(mocked_get_tenants):
120
    """API using JSON from previous one we put on tenant"""
121
    command = Command()
122
    command.deploy = Mock()
123
    tenant = Mock()
124

  
125
    # redeploy
126
    command.deploy.reset_mock()
127
    ENVIRONMENT = {'services': [{'this': True,
128
                                 'base_url': 'https://combo.dev.publik.love/',
129
                                 'service-id': 'combo'}]}
130
    tenant.get_hobo_json = Mock(return_value=ENVIRONMENT)
131
    mocked_get_tenants.return_value = [tenant]
132
    command.handle(redeploy=True)
133
    assert command.deploy.mock_calls == [  # ignore_timestamp is set to True
134
          call('https://combo.dev.publik.love/', ENVIRONMENT, True)]
135

  
136
    # redeploy having wrong JSON content: no 'base_url' entry
137
    command.deploy.reset_mock()
138
    tenant.get_hobo_json = Mock(return_value=
139
                                {'services': [{'service-id': 'combo', 'this': True}]})
140
    mocked_get_tenants.return_value = [tenant]
141
    with pytest.raises(KeyError, match='base_url'):
142
        command.handle(redeploy=True)
143
    assert command.deploy.mock_calls == []
144

  
145
    # redeploy having wrong JSON content: 'this' entry not found
146
    command.deploy.reset_mock()
147
    tenant.get_hobo_json = Mock(return_value={'services': [{'service-id': 'combo'}]})
148
    mocked_get_tenants.return_value = [tenant]
149
    command.handle(redeploy=True)
150
    assert command.deploy.mock_calls == []
151

  
152
    # IOError
153
    command.deploy.reset_mock()
154
    tenant.get_hobo_json = Mock(side_effect=IOError)
155
    mocked_get_tenants.return_value = [tenant]
156
    command.handle(redeploy=True)
157
    assert command.deploy.mock_calls == []
158

  
159

  
160
@patch('hobo.agent.common.management.commands.hobo_deploy.TenantMiddleware.get_tenant_by_hostname')
161
def test_deploy(mocked_get_tenant_by_hostname, tmpdir):
162
    command = Command()
163
    command.deploy_specifics = Mock()
164
    tenant = Mock()
165
    tenant.get_directory = Mock(return_value=str(tmpdir))
166
    base_url = 'https://combo.dev.publik.love/'
167
    tenant_hobo_json = os.path.join(str(tmpdir), 'hobo.json')
168
    ENVIRONMENT = {'services': [{'service-id': 'combo', 'base_url': base_url}],
169
                   'timestamp': '001'}
170

  
171
    def assert_deployed():
172
        assert mocked_get_tenant_by_hostname.mock_calls[0] == call('combo.dev.publik.love')
173
        assert command.deploy_specifics.mock_calls == [
174
             call({'services': [{'base_url': 'https://combo.dev.publik.love/',
175
                                 'service-id': 'combo',
176
                                 'this': True,}],
177
                   'timestamp': '001'},
178
                  tenant)]
179
        with open(tenant_hobo_json, 'r') as handler:  # hobo.json file
180
            content = json.load(handler)
181
        assert ENVIRONMENT['services'][0]['this'] is True  # new entry added
182
        assert json.dumps(content, sort_keys=True), json.dumps(ENVIRONMENT, sort_keys=True)
183

  
184
    # create tenant first
185
    command.deploy_specifics.reset_mock()
186
    mocked_get_tenant_by_hostname.reset_mock()
187
    mocked_get_tenant_by_hostname.side_effect = [TenantNotFound, tenant]
188
    with patch('hobo.agent.common.management.commands.hobo_deploy.call_command'
189
              ) as mocked_call_command:
190
        command.deploy(base_url, ENVIRONMENT, None)
191
    assert mocked_call_command.mock_calls == [
192
        call('create_tenant', 'combo.dev.publik.love')]
193
    assert_deployed()
194

  
195
    # already there (timestamp do not change)
196
    command.deploy_specifics.reset_mock()
197
    mocked_get_tenant_by_hostname.side_effect = [tenant]
198
    command.deploy(base_url, ENVIRONMENT, None)
199
    assert command.deploy_specifics.mock_calls == []
200

  
201
    # force re-deploy
202
    command.deploy_specifics.reset_mock()
203
    mocked_get_tenant_by_hostname.reset_mock()
204
    mocked_get_tenant_by_hostname.side_effect = [tenant]
205
    command.deploy(base_url, ENVIRONMENT, True)
206
    assert_deployed()
207

  
208
    # early exit, we don't redeploy secondary services
209
    command.deploy_specifics.reset_mock()
210
    env = dict(ENVIRONMENT)
211
    env['services'][0]['secondary'] = True
212
    command.deploy(base_url, env, None)
213
    assert command.deploy_specifics.mock_calls == []
214

  
215

  
216
def test_deploy_specific():
217
    """stupid test"""
218
    command = Command()
219
    command.generate_saml_keys = Mock()
220
    command.configure_service_provider = Mock()
221
    command.configure_theme = Mock()
222
    command.configure_template = Mock()
223

  
224
    command.deploy_specifics('my_hobo_env', 'my_tenant')
225
    assert command.generate_saml_keys.mock_calls == [call('my_tenant', prefix='sp-')]
226
    assert command.configure_service_provider.mock_calls == [call('my_hobo_env', 'my_tenant')]
227
    assert command.configure_theme.mock_calls == [call('my_hobo_env', 'my_tenant')]
228
    assert command.configure_template.mock_calls == [call('my_hobo_env', 'my_tenant')]
229

  
230

  
231
def test_generate_saml_keys(tmpdir):
232
    """create an RSA key and its x509 certificate"""
233
    command = Command()
234
    tenant = Mock()
235
    tenant.get_directory = Mock(return_value=str(tmpdir))
236
    tenant.domain_url = 'combo.dev.publik.love'
237

  
238
    command.generate_saml_keys(tenant)
239
    with open('%s/saml.key' % str(tmpdir), 'r') as handler:
240
        key = handler.read()
241
    with open('%s/saml.crt' % str(tmpdir), 'r') as handler:
242
        crt = handler.read()
243

  
244
    # if files exist don't regenerate them
245
    command.generate_saml_keys(tenant)
246
    with open('%s/saml.key' % str(tmpdir), 'r') as handler:
247
        assert key == handler.read()
248
    with open('%s/saml.crt' % str(tmpdir), 'r') as handler:
249
        assert crt == handler.read()
250

  
251

  
252
@patch('hobo.agent.common.management.commands.hobo_deploy.requests.get')
253
def test_configure_service_provider(mocked_get, tmpdir):
254
    """create TENANT/idp-metadata-ID.xml file"""
255
    command = Command()
256
    tenant = Mock()
257
    tenant.get_directory = Mock(return_value=str(tmpdir))
258
    response1 = Response()
259
    response1._content = 'my saml idp metadata (1)'
260
    response1.status_code = 200
261
    response2 = Response()
262
    response2._content = 'my saml idp metadata (2)'
263
    response2.status_code = 200
264
    tenant_idp_metadata = '%s/idp-metadata-%s.xml' % (str(tmpdir), '1')
265

  
266
    ENVIRONMENT = {'services': [
267
        {'service-id': 'combo',
268
         'saml-idp-metadata-url': 'https://combo.dev.publik.love/accounts/mellon/metadata/',
269
         'id': 1},
270
        {'service-id': 'wcs',
271
         'saml-idp-metadata-url': 'https://wcs.dev.publik.love/saml/metadata',
272
         'id': 1},
273
    ]}
274

  
275
    # normal case (stop when configuration on a service success for this tenant)
276
    mocked_get.side_effect = [response1]
277
    command.configure_service_provider(ENVIRONMENT, tenant)
278
    with open(tenant_idp_metadata, 'r') as handler:
279
        assert handler.read() == 'my saml idp metadata (1)'
280

  
281
    # no 'idp_url' JSON entry
282
    env = {'services': [{'service-id': 'combo', 'id': 1}]}
283
    os.remove(tenant_idp_metadata)
284
    command.configure_service_provider(env, tenant)
285
    with pytest.raises(IOError, match='No such file or directory'):
286
        open(tenant_idp_metadata, 'r')
287

  
288
    # idp not available
289
    response1.status_code = 500
290
    mocked_get.side_effect = [exceptions.RequestException, response1]
291
    command.configure_service_provider(ENVIRONMENT, tenant)
292
    with pytest.raises(IOError, match='No such file or directory'):
293
        open(tenant_idp_metadata, 'r')
294

  
295
    # case when idp is becoming available
296
    mocked_get.side_effect = [response1, response2]
297
    command.configure_service_provider(ENVIRONMENT, tenant)
298
    with open(tenant_idp_metadata, 'r') as handler:
299
        assert handler.read() == 'my saml idp metadata (2)'
300

  
301

  
302
def test_get_theme(fake_themes):
303
    """return the service's theme"""
304
    COMBO = {'service-id': 'combo'}
305
    WCS = {'service-id': 'hobo', 'variables': {'theme': 'alfortville'}}
306
    HOBO = {'service-id': 'hobo', 'variables': {'theme': 'unknown_theme'}}
307
    ENVIRONMENT = {'services': [COMBO, WCS, HOBO], 'variables': {'theme': 'publik'}}
308
    command = Command()
309

  
310
    # main case
311
    command.me = COMBO
312
    assert command.get_theme(ENVIRONMENT)['id'] == 'publik'
313

  
314
    # service having theme overloaded
315
    command.me = WCS
316
    assert command.get_theme(ENVIRONMENT)['id'] == 'alfortville'
317

  
318
    # theme not specified
319
    command.me = COMBO
320
    assert command.get_theme({'services': [COMBO, WCS, HOBO]}) is None
321

  
322
    # unknown theme
323
    command.me = HOBO
324
    assert command.get_theme(ENVIRONMENT) is None
325

  
326
    # can't test last return case as it could never append
327
    # if not theme.get('module'):  # TODO: dead code to remove
328

  
329

  
330
def test_configure_theme(fake_themes, tmpdir):
331
    """make symlink for TENANT/theme
332
    and TENANT/static, TENANT/templates on overlay
333
    """
334
    COMBO = {'service-id': 'combo'}
335
    WCS = {'service-id': 'hobo', 'variables': {'theme': 'alfortville'}} # overlay on fixture
336
    HOBO = {'service-id': 'hobo', 'variables': {'theme': 'unknown_theme'}}
337
    ENVIRONMENT = {'services': [COMBO, WCS, HOBO], 'variables': {'theme': 'publik'}}
338
    command = Command()
339
    command.me = COMBO
340

  
341
    tenant = Mock()
342
    tenant.get_directory = Mock(return_value=str(tmpdir))
343
    theme_path = '%s/theme' % str(tmpdir)
344
    static_path = '%s/static' % str(tmpdir)
345
    templates_path = '%s/templates' % str(tmpdir)
346

  
347
    # main case: (remove 'static' and/or 'templates' links and empty directories too)
348
    os.mkdir(static_path)
349
    os.symlink(str(tmpdir), templates_path)
350
    command.configure_theme(ENVIRONMENT, tenant)
351
    assert os.path.islink(theme_path)
352
    assert os.path.exists(static_path) is False
353
    assert os.path.exists(templates_path) is False
354

  
355
    # overlay provided: build links to the 'overlay' directory
356
    os.symlink(str(tmpdir), static_path)
357
    os.mkdir(templates_path)
358
    command.me = WCS
359
    command.configure_theme(ENVIRONMENT, tenant)
360
    assert os.readlink(static_path) == '%s/themes/foobar/static' % str(tmpdir)
361
    assert os.readlink(templates_path) == '%s/themes/foobar/templates' % str(tmpdir)
362

  
363
    # retrieve on error (if server hangs during 'atomic_symlink')
364
    os.unlink(theme_path)
365
    os.symlink(str(tmpdir), theme_path + '.tmp')
366
    command.configure_theme(ENVIRONMENT, tenant)
367
    assert os.path.islink(theme_path)
368
    assert os.path.islink(static_path)  # to compare with result we get bellow
369

  
370
    # do not 'overlay' non-empty 'static' and/or 'templates' true directories
371
    os.unlink(static_path)
372
    os.mkdir(static_path)
373
    os.mkdir(os.path.join(static_path, 'some_dir'))
374
    command.configure_theme(ENVIRONMENT, tenant)
375
    assert os.path.isdir(static_path)
376

  
377
    # no theme provided
378
    os.unlink(theme_path)
379
    command.me = HOBO
380
    command.configure_theme(ENVIRONMENT, tenant)
381
    assert os.path.exists(theme_path) is False
382

  
383

  
384
@patch('hobo.agent.common.management.commands.hobo_deploy.get_commands')
385
@patch('hobo.agent.common.management.commands.hobo_deploy.call_command')
386
def test_configure_template(mocked_call_command, mocked_get_commands):
387
    command = Command()
388
    ENVIRONMENT = {'services': [{'service-id': 'combo',
389
                                 'template_name': 'my_template',
390
                                 'this': True}]}
391

  
392
    # import_template.py located into hobo/agent/common: always belongs to command object
393
    # TODO: dead condition
394
    mocked_get_commands.return_value = ['import_template', '...']
395

  
396
    # main case
397
    command.configure_template(ENVIRONMENT, 'unused')  # TODO: dead tenant parameter
398
    assert mocked_call_command.mock_calls == [call('import_template', 'my_template')]
399

  
400
    # no template_name entry provided
401
    mocked_call_command.reset_mock()
402
    del ENVIRONMENT['services'][0]['template_name']
403
    command.configure_template(ENVIRONMENT, 'unused')
404
    assert mocked_call_command.mock_calls == []
405

  
406

  
407
def test_combo_get_theme(fake_themes):
408
    # IMHO, JSON's 'this' entry can't miss
409
    # cf: hobo/agent/common/management/commands/hobo_deploy.py::configure_template
410
    # cf: hobo/agent/hobo/management/commands/hobo_deploy.py::deploy_specifics
411
    # TODO: dead file (I mean it should be removed)
412

  
413
    COMBO = {'service-id': 'combo', 'this': True}
414
    ENVIRONMENT = {'services': [COMBO], 'variables': {'theme': 'publik'}}
415
    command = ComboCommand()
416

  
417
    # main case
418
    assert command.get_theme(ENVIRONMENT)['id'] == 'publik'
419

  
420

  
421
@patch('hobo.agent.common.management.commands.hobo_deploy.Command.deploy_specifics')
422
@patch('hobo.agent.hobo.management.commands.hobo_deploy.tenant_context')
423
def test_hobo_deploy_specifics_alone(mocked_tenant_context, mocked_super, db):
424
    """build database content used later to generate hobo.json.
425
    tests using tenants are located into tests_multipublik/test_multipublik.py
426
    """
427
    command = HoboCommand()
428
    ENVIRONMENT = {'services': [{'service-id': 'hobo',
429
                                 'slug': 'hobo',
430
                                 'title': 'Hobo',
431
                                 'base_url': 'https://hobo.dev.publik.love/',
432
                                 'this': True},
433
                                {'service-id': 'combo',
434
                                 'slug': 'portal',
435
                                 'title': 'Compte citoyen',
436
                                 'base_url': 'https://combo.dev.publik.love/'},
437
                                {'service-id': 'wcs',
438
                                 'slug': 'eservices',
439
                                 'title': 'D\u00e9marches',
440
                                 'base_url': 'wcs.dev.publik.love'},
441
                                {'service-id': 'wrong id',
442
                                 'base_url': 'https://wrong.dev.publik.love/'}]}
443

  
444
    command.deploy_specifics(ENVIRONMENT, 'tenant')
445

  
446
    assert mocked_super.mock_calls == [call(ENVIRONMENT, 'tenant')]
447
    assert len(Hobo.objects.all()) == 0
448
    assert len(Combo.objects.all()) == 1
449
    assert len(Wcs.objects.all()) == 1
450
    combo = Combo.objects.all()[0]
451
    assert combo.base_url == 'https://combo.dev.publik.love/'
452
    assert combo.slug == '_interco_portal'
453

  
454
    # define global variables (twice)
455
    ou_label = Variable.objects.get(name='ou-label')
456
    ou_slug = Variable.objects.get(name='ou-slug')
457
    assert ou_label.value == 'Hobo'
458
    assert ou_slug.value == 'hobo'
459
    assert ou_label.service_pk is None
460
    assert ou_slug.service_pk is None
461

  
462

  
463
@patch('hobo.agent.common.management.commands.hobo_deploy.Command.deploy_specifics')
464
@patch('hobo.agent.hobo.management.commands.hobo_deploy.tenant_context')
465
def test_hobo_deploy_specifics_primary(mocked_tenant_context, mocked_super, db):
466
    """first deployement: do nothing for secondary hobo-services
467
    same behaviour as previous 'alone' test
468
    """
469
    command = HoboCommand()
470
    wcs_url = 'https://wcs.dev.publik.love/'
471
    ENVIRONMENT = {'services': [{'service-id': 'hobo',
472
                                 'slug': 'hobo',
473
                                 'title': 'Hobo primary',
474
                                 'base_url': 'https://hobo1.dev.publik.love/',
475
                                 'this': True},
476
                                {'service-id': 'combo',
477
                                 'slug': 'portal',
478
                                 'title': 'Compte citoyen',
479
                                 'base_url': 'https://combo.dev.publik.love/'},
480
                                {'service-id': 'wcs',
481
                                 'slug': 'eservices',
482
                                 'title': 'skipped as url already in use',
483
                                 'base_url': wcs_url},
484
                                {'service-id': 'hobo',
485
                                 'slug': 'hobo',
486
                                 'title': 'Hobo secondary',
487
                                 'base_url': 'https://hobo2.dev.publik.love/',
488
                                 'secondary': True}]}
489

  
490
    # make the wcs service already deployed
491
    Wcs.objects.get_or_create(base_url=wcs_url, secondary=False)
492

  
493
    command.deploy_specifics(ENVIRONMENT, 'tenant')
494

  
495
    assert mocked_super.mock_calls == [call(ENVIRONMENT, 'tenant')]
496
    assert len(Hobo.objects.all()) == 0
497
    assert len(Combo.objects.all()) == 1
498
    assert len(Wcs.objects.all()) == 1  # the wcs service already set upper
499
    combo = Combo.objects.all()[0]
500
    assert combo.base_url == 'https://combo.dev.publik.love/'
501
    assert combo.slug == '_interco_portal'
502

  
503
    # define global variables
504
    ou_label = Variable.objects.get(name='ou-label')
505
    ou_slug = Variable.objects.get(name='ou-slug')
506
    assert ou_label.value == 'Hobo primary'
507
    assert ou_slug.value == 'hobo'
508
    assert ou_label.service_pk is None
509
    assert ou_slug.service_pk is None
510

  
511

  
512
@patch('hobo.agent.common.management.commands.hobo_deploy.Command.deploy_specifics')
513
@patch('hobo.agent.hobo.management.commands.hobo_deploy.tenant_context')
514
def test_hobo_deploy_specifics_secondary(mocked_tenant_context, mocked_super, db):
515
    """next deployements: skip generic tasks and add 'ou' variables
516
    """
517
    command = HoboCommand()
518
    ENVIRONMENT = {'services': [{'service-id': 'hobo',
519
                                 'slug': 'hobo',
520
                                 'title': 'Hobo primary',
521
                                 'base_url': 'https://hobo1.dev.publik.love/'},
522
                                {'service-id': 'combo',
523
                                 'slug': 'portal',
524
                                 'title': 'Compte citoyen',
525
                                 'base_url': 'https://combo.dev.publik.love/'},
526
                                {'service-id': 'hobo',
527
                                 'slug': 'hobo',
528
                                 'title': 'Hobo secondary',
529
                                 'base_url': 'https://hobo2.dev.publik.love/',
530
                                 'secondary': True,
531
                                 'this': True}],
532
                   'variables': {'ou-label': 'my ou-label',
533
                                  'ou-slug': 'my ou-slug'}}
534

  
535
    # assert primary hobo is wanted
536
    command.deploy_specifics(ENVIRONMENT, 'tenant')
537
    assert len(Combo.objects.all()) == 0
538

  
539
    # make primary hobo already deployed
540
    Hobo.objects.get_or_create(base_url='hobo1.dev.publik.love', secondary=False)
541
    command.deploy_specifics(ENVIRONMENT, 'tenant')
542

  
543
    assert mocked_super.mock_calls == []
544
    assert len(Hobo.objects.all()) == 1  # primary hobo set upper
545
    assert len(Combo.objects.all()) == 1
546
    combo = Combo.objects.all()[0]
547
    assert combo.base_url == 'https://combo.dev.publik.love/'
548
    assert combo.slug == '_my ou-slug_portal'
549

  
550
    # variables are added to the services
551
    ou_label = Variable.objects.get(name='ou-label')
552
    ou_slug = Variable.objects.get(name='ou-slug')
553
    assert ou_label.value == 'my ou-label'
554
    assert ou_slug.value == 'my ou-slug'
555
    assert ou_label.service_pk == combo.id
556
    assert ou_slug.service_pk == combo.id
557

  
558

  
559
# Can't write test_authentic2_deploy_specifics as cannot import A2Command here:
560
#from hobo.agent.authentic2.management.commands.hobo_deploy import Command as A2Command
561
# -> tests_authentic/test_hobo_deploy.py
tests_schemas/env.json
1
{
2
    "services": [
3
	{
4
	    "service-id": "chrono",
5
	    "base_url": "https://chrono.dev.publik.love/",
6
	    "slug": "agendas",
7
	    "title": "CHRONO",
8
	    "secret_key": "123",
9
	    "template_name": "import_me.txt"
10
	},
11
	{
12
	    "service-id": "wcs",
13
	    "base_url": "https://wcs.dev.publik.love/",
14
	    "slug": "eservices",
15
	    "title": "WCS"
16
	},
17
	{
18
	    "service-id": "hobo",
19
	    "base_url": "https://hobo.dev.publik.love/",
20
	    "slug": "hobo",
21
	    "title": "HOBO",
22
	    "secret_key": "123"
23
	},
24
	{
25
	    "service-id": "combo",
26
	    "base_url": "https://combo.dev.publik.love/",
27
	    "slug": "portal",
28
	    "title": "COMBO",
29
	    "secret_key": "123",
30
	    "template_name": "import_me.txt"
31
	},
32
	{
33
	    "service-id": "authentic",
34
	    "base_url": "https://authentic.dev.publik.love/",
35
	    "slug": "idp",
36
	    "title": "A2",
37
	    "secret_key": "123"
38
	}
39
    ]
40
}
tests_schemas/settings.py
12 12
INSTALLED_APPS = ('hobo.multitenant', 'hobo') + INSTALLED_APPS
13 13
SHARED_APPS = ()
14 14
TENANT_APPS = INSTALLED_APPS
15
PROJECT_NAME = 'testing'
tests_schemas/test_hobo_deploy.py
1
import os
2

  
3
from django.core.management import load_command_class
4

  
5
from hobo.environment.models import Variable
6
from hobo.multitenant.middleware import TenantMiddleware
7
from tenant_schemas.utils import tenant_context
8

  
9

  
10
def assert_deployed(domain):
11
    tenant = TenantMiddleware.get_tenant_by_hostname(domain)
12
    tenant_hobo_json = os.path.join(tenant.get_directory(), 'hobo.json')
13
    assert os.path.exists(tenant_hobo_json)
14

  
15

  
16
def test_deploy_on_common_agent(db):
17
    """deploy basic case (for chrono here):
18
    $ chrono-manage hobo_deploy env.json  # simulate this bash query
19
    """
20
    command = load_command_class('hobo.agent.common', 'hobo_deploy')
21
    domain = 'chrono.dev.publik.love'
22
    command.handle('https://%s/' % domain, 'tests_schemas/env.json')
23
    assert_deployed(domain)
24

  
25

  
26
def test_deploy_specifics_on_hobo_agent(db):
27
    """overloaded case for hobo:
28
    $ hobo-manage hobo-deploy env.json  # simulate this bash query
29
    """
30
    command = load_command_class('hobo.agent.hobo', 'hobo_deploy')
31
    domain = 'hobo.dev.publik.love'
32

  
33
    command.handle('https://%s/' % domain, 'tests_schemas/env.json')
34
    assert_deployed(domain)
35

  
36
    # reach deploy_specifics() in hobo/agent/hobo/management/commands/hobo_deploy.py
37
    tenant = TenantMiddleware.get_tenant_by_hostname(domain)
38
    with tenant_context(tenant):
39
        assert Variable.objects.get(name='ou-label').value == 'HOBO'
40

  
41

  
42
# fails to simulate call from authentic2 agent, that overload deploy_specifics()
43
# $ authentic-multitenant-manage hobo-deploy
44
# here, because this agent need to import authentic2 modules
45

  
46

  
47
# fails to simulate call from bijoe agent, that overload deploy_specifics()
48
# $ bijoe-mange hobo-deploy
49
# here, because this code is not implemented here
50

  
51

  
52
def test_get_theme_on_combo_agent(db):
53
    """overloaded case for combo:
54
    $ combo-manage hobo-deploy env.json  # simulate this bash query
55
    """
56
    command = load_command_class('hobo.agent.combo', 'hobo_deploy')
57
    domain = 'combo.dev.publik.love'
58
    command.handle('https://%s/' % domain, 'tests_schemas/env.json')
59
    assert_deployed(domain)
60
    # lack an assert statement proving we do reach
61
    # get_theme() in hobo/agent/combo/management/commands/hobo_deploy.py
tests_schemas/test_hobo_deploy2.py
1
import mock
2
import os
3

  
4
from django.core.management import call_command, load_command_class
5

  
6
from hobo.multitenant.middleware import TenantMiddleware
7

  
8

  
9
def assert_deployed(domain):
10
    tenant = TenantMiddleware.get_tenant_by_hostname(domain)
11
    tenant_hobo_json = os.path.join(tenant.get_directory(), 'hobo.json')
12
    assert os.path.exists(tenant_hobo_json)
13

  
14

  
15
@mock.patch('hobo.agent.common.management.commands.hobo_deploy.call_command')
16
@mock.patch('hobo.agent.common.management.commands.hobo_deploy.get_commands')
17
def test_import_template(mocked_get_commands, mocked_call_command, db):
18
    """check 'hobo-deploy' result in '$ chrono-manage import_template' call
19
    $ chrono-manage hobo_deploy env.json  # simulate this bash query
20

  
21
    this test must be isolated from the others on test_deploy.py
22
    else 'get_commands' which is lru_cached fails to be mocked
23
    """
24
    command = load_command_class('hobo.agent.common', 'hobo_deploy')
25
    domain = 'chrono.dev.publik.love'
26

  
27
    def my_call_command(command, parameter):
28
        if command == 'import_template':
29
            my_call_command.import_template_was_called = True
30
            return
31
        call_command(command, parameter)
32

  
33
    mocked_get_commands.return_value = ['import_template']
34
    mocked_call_command.side_effect = my_call_command
35
    my_call_command.import_template_was_called = False
36

  
37
    command.handle('https://%s/' % domain, 'tests_schemas/env.json')
38
    assert_deployed(domain)
39

  
40
    # assert the 'import_template' command was called
41
    assert my_call_command.import_template_was_called is True
0
-