Projet

Général

Profil

0001-add-tests-13612.patch

Benjamin Dauvergne, 16 janvier 2019 17:19

Télécharger (11,1 ko)

Voir les différences:

Subject: [PATCH 1/2] add tests (#13612)

 get_wcs.sh        |   4 +
 tests/conftest.py | 197 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/test_wcs.py |  91 +++++++++++++++++++++
 tox.ini           |   9 ++-
 wcs_olap/cmd.py   |   4 +
 5 files changed, 304 insertions(+), 1 deletion(-)
 create mode 100755 get_wcs.sh
 create mode 100644 tests/conftest.py
 create mode 100644 tests/test_wcs.py
get_wcs.sh
1
#!/bin/sh -xue
2

  
3
test -d wcs || git clone http://git.entrouvert.org/wcs.git
4
(cd wcs && git pull)
tests/conftest.py
1
# -*- coding: utf-8 -*-
2

  
3
import sys
4
import subprocess
5
import time
6
import os
7
import shutil
8
import random
9
import socket
10
from contextlib import closing
11
from collections import namedtuple
12

  
13
import psycopg2
14

  
15
import pytest
16

  
17
Wcs = namedtuple('Wcs', ['url', 'appdir', 'pid'])
18

  
19

  
20
class Database(object):
21
    def __init__(self):
22
        self.db_name = 'db%s' % random.getrandbits(20)
23
        self.dsn = 'dbname=%s' % self.db_name
24
        with closing(psycopg2.connect('')) as conn:
25
            conn.set_isolation_level(0)
26
            with conn.cursor() as cursor:
27
                cursor.execute('CREATE DATABASE %s' % self.db_name)
28

  
29
    def conn(self):
30
        return closing(psycopg2.connect(self.dsn))
31

  
32
    def delete(self):
33
        with closing(psycopg2.connect('')) as conn:
34
            conn.set_isolation_level(0)
35
            with conn.cursor() as cursor:
36
                cursor.execute('DROP DATABASE IF EXISTS %s' % self.db_name)
37

  
38

  
39
@pytest.fixture
40
def postgres_db():
41
    db = Database()
42
    try:
43
        yield db
44
    finally:
45
        db.delete()
46

  
47

  
48
WCS_SCRIPTS = {
49
    'setup-auth': u"""
50
from quixote import get_publisher
51

  
52
get_publisher().cfg['identification'] = {'methods': ['password']}
53
get_publisher().cfg['debug'] = {'display_exceptions': 'text'}
54
get_publisher().write_cfg()
55
""",
56
    'create-user': u"""
57
from quixote import get_publisher
58
from qommon.ident.password_accounts import PasswordAccount
59

  
60
user = get_publisher().user_class()
61
user.name = 'foo bar'
62
user.email = 'foo@example.net'
63
user.store()
64
account = PasswordAccount(id='user')
65
account.set_password('user')
66
account.user_id = user.id
67
account.store()
68
""",
69
    'create-data': u"""
70
import datetime
71
import random
72
from quixote import get_publisher
73

  
74
from wcs.categories import Category
75
from wcs.formdef import FormDef
76
from wcs.roles import Role
77
from wcs import fields
78

  
79
cat = Category()
80
cat.name = 'Catégorie'
81
cat.description = ''
82
cat.store()
83

  
84
formdef = FormDef()
85
formdef.name = 'Demande'
86
formdef.category_id = cat.id
87
formdef.fields = [
88
    fields.StringField(id='1', label='1st field', type='string', anonymise=False, varname='field_string'),
89
    fields.ItemField(id='2', label='2nd field', type='item',
90
                     items=['foo', 'bar', 'baz'], varname='field_item'),
91
]
92
formdef.store()
93

  
94
user = get_publisher().user_class.select()[0]
95

  
96
for i in range(50):
97
    formdata = formdef.data_class()()
98
    formdata.just_created()
99
    formdata.receipt_time = datetime.datetime(2018, random.randrange(1, 13), random.randrange(1, 29)).timetuple()
100
    formdata.data = {'1': 'FOO BAR %d' % i}
101
    if i%4 == 0:
102
        formdata.data['2'] = 'foo'
103
        formdata.data['2_display'] = 'foo'
104
    elif i%4 == 1:
105
        formdata.data['2'] = 'bar'
106
        formdata.data['2_display'] = 'bar'
107
    else:
108
        formdata.data['2'] = 'baz'
109
        formdata.data['2_display'] = 'baz'
110
    if i%3 == 0:
111
        formdata.jump_status('new')
112
    else:
113
        formdata.jump_status('finished')
114
    if i%7 == 0:
115
        formdata.user_id = user.id
116
    formdata.store()
117
""",
118
}
119

  
120

  
121
@pytest.fixture(scope='session')
122
def wcs(tmp_path_factory):
123
    '''Session scoped wcs fixture, so read-only.'''
124
    if 'WCSCTL' not in os.environ or not os.path.exists(os.environ['WCSCTL']):
125
        pytest.skip('WCSCTL not defined in environment')
126
    WCSCTL = os.environ.get('WCSCTL')
127
    WCS_DIR = tmp_path_factory.mktemp('wcs')
128
    HOSTNAME = '127.0.0.1'
129
    PORT = 8899
130
    ADDRESS = '0.0.0.0'
131
    WCS_PID = None
132

  
133
    def run_wcs_script(script, hostname):
134
        '''Run python script inside w.c.s. environment'''
135

  
136
        script_path = WCS_DIR / (script + '.py')
137
        with script_path.open('w') as fd:
138
            fd.write(WCS_SCRIPTS[script])
139

  
140
        subprocess.check_call(
141
            [WCSCTL, 'runscript', '--app-dir', str(WCS_DIR), '--vhost', hostname,
142
             str(script_path)])
143

  
144
    tenant_dir = WCS_DIR / HOSTNAME
145
    tenant_dir.mkdir()
146

  
147
    run_wcs_script('setup-auth', HOSTNAME)
148
    run_wcs_script('create-user', HOSTNAME)
149
    run_wcs_script('create-data', HOSTNAME)
150

  
151
    with (tenant_dir / 'site-options.cfg').open('w') as fd:
152
        fd.write(u'''[api-secrets]
153
olap = olap
154
''')
155

  
156
    with (WCS_DIR / 'wcs.cfg').open('w') as fd:
157
        fd.write(u'''[main]
158
app_dir = %s\n''' % WCS_DIR)
159

  
160
    with (WCS_DIR / 'local_settings.py').open('w') as fd:
161
        fd.write(u'''
162
WCS_LEGACY_CONFIG_FILE = '%s/wcs.cfg'
163
THEMES_DIRECTORY = '/'
164
ALLOWED_HOSTS = ['%s']
165
''' % (WCS_DIR, HOSTNAME))
166

  
167
    # launch a Django worker for running w.c.s.
168
    WCS_PID = os.fork()
169
    if not WCS_PID:
170
        os.chdir(os.path.dirname(WCSCTL))
171
        os.environ['DJANGO_SETTINGS_MODULE'] = 'wcs.settings'
172
        os.environ['WCS_SETTINGS_FILE'] = str(WCS_DIR / 'local_settings.py')
173
        os.execvp('python', ['python', 'manage.py', 'runserver', '--noreload', '%s:%s' % (ADDRESS, PORT)])
174
        sys.exit(0)
175

  
176
    # verify w.c.s. is launched
177
    s = socket.socket()
178
    i = 0
179
    while True:
180
        i += 1
181
        try:
182
            s.connect((ADDRESS, PORT))
183
        except Exception:
184
            time.sleep(0.1)
185
        else:
186
            s.close()
187
            break
188
        assert i < 50, 'no connection found after 5 seconds'
189

  
190
    # verify w.c.s. is still running
191
    pid, exit_code = os.waitpid(WCS_PID, os.WNOHANG)
192
    if pid:
193
        assert False, 'w.c.s. stopped with exit-code %s' % exit_code
194

  
195
    yield Wcs(url='http://%s:%s/' % (HOSTNAME, PORT), appdir=WCS_DIR, pid=WCS_PID)
196
    os.kill(WCS_PID, 9)
197
    shutil.rmtree(str(WCS_DIR))
tests/test_wcs.py
1
import subprocess
2

  
3

  
4
def test_wcs_fixture(wcs, postgres_db, tmpdir, caplog):
5
    config_ini = tmpdir / 'config.ini'
6
    model_dir = tmpdir / 'model_dir'
7
    model_dir.mkdir()
8
    with config_ini.open('w') as fd:
9
        fd.write(u'''
10
[wcs-olap]
11
cubes_model_dirs = {model_dir}
12
pg_dsn = {dsn}
13

  
14
[{wcs.url}]
15
orig = olap
16
key = olap
17
schema = public
18
'''.format(wcs=wcs, model_dir=model_dir, dsn=postgres_db.dsn))
19

  
20
    from wcs_olap import cmd
21
    import sys
22

  
23
    sys.argv = ['', '--no-log-errors', str(config_ini)]
24
    cmd.main2()
25

  
26
    expected_schema = [
27
        ('agent', 'id'),
28
        ('agent', 'label'),
29
        ('category', 'id'),
30
        ('category', 'label'),
31
        ('channel', 'id'),
32
        ('channel', 'label'),
33
        ('evolution', 'id'),
34
        ('evolution', 'generic_status_id'),
35
        ('evolution', 'formdata_id'),
36
        ('evolution', 'time'),
37
        ('evolution', 'date'),
38
        ('evolution', 'hour_id'),
39
        ('evolution_demande', 'id'),
40
        ('evolution_demande', 'status_id'),
41
        ('evolution_demande', 'formdata_id'),
42
        ('evolution_demande', 'time'),
43
        ('evolution_demande', 'date'),
44
        ('evolution_demande', 'hour_id'),
45
        ('formdata', 'id'),
46
        ('formdata', 'formdef_id'),
47
        ('formdata', 'receipt_time'),
48
        ('formdata', 'hour_id'),
49
        ('formdata', 'channel_id'),
50
        ('formdata', 'backoffice'),
51
        ('formdata', 'generic_status_id'),
52
        ('formdata', 'endpoint_delay'),
53
        ('formdata', 'first_agent_id'),
54
        ('formdata', 'geolocation_base'),
55
        ('formdata', 'json_data'),
56
        ('formdata_demande', 'id'),
57
        ('formdata_demande', 'formdef_id'),
58
        ('formdata_demande', 'receipt_time'),
59
        ('formdata_demande', 'hour_id'),
60
        ('formdata_demande', 'channel_id'),
61
        ('formdata_demande', 'backoffice'),
62
        ('formdata_demande', 'generic_status_id'),
63
        ('formdata_demande', 'endpoint_delay'),
64
        ('formdata_demande', 'first_agent_id'),
65
        ('formdata_demande', 'geolocation_base'),
66
        ('formdata_demande', 'json_data'),
67
        ('formdata_demande', 'status_id'),
68
        ('formdata_demande', 'field_field_item'),
69
        ('formdata_demande', 'function__receiver'),
70
        ('formdata_demande_field_field_item', 'id'),
71
        ('formdata_demande_field_field_item', 'label'),
72
        ('formdef', 'id'),
73
        ('formdef', 'category_id'),
74
        ('formdef', 'label'),
75
        ('hour', 'id'),
76
        ('hour', 'label'),
77
        ('role', 'id'),
78
        ('role', 'label'),
79
        ('status', 'id'),
80
        ('status', 'label'),
81
        ('status_demande', 'id'),
82
        ('status_demande', 'label')
83
    ]
84

  
85
    with postgres_db.conn() as conn:
86
        with conn.cursor() as c:
87
            c.execute('SELECT table_name, column_name '
88
                      'FROM information_schema.columns '
89
                      'WHERE table_schema = \'public\' ORDER BY table_name, ordinal_position')
90

  
91
            assert list(c.fetchall()) == expected_schema
tox.ini
9 9
[testenv]
10 10
usedevelop = true
11 11
setenv =
12
	WCSCTL=wcs/wcsctl.py
12 13
	coverage: COVERAGE=--junit-xml=junit.xml --cov=src --cov-report xml 
13 14
deps =
14 15
	coverage
15 16
	pytest
16 17
	pytest-cov
17 18
	pytest-random
19
	quixote<3.0
20
	psycopg2-binary
21
	vobject
22
	gadjo
23
	django>=1.11,<1.12
18 24
commands =
19
	py.test {env:COVERAGE:} {posargs:--random tests}
25
	./get_wcs.sh
26
	py.test {env:COVERAGE:} {posargs:--random-group tests}
wcs_olap/cmd.py
49 49
    group = parser.add_mutually_exclusive_group()
50 50
    parser.add_argument('--no-feed', dest='feed', help='only produce the model',
51 51
                        action='store_false', default=True)
52
    parser.add_argument('--no-log-errors', dest='no_log_errors',
53
                        action='store_true', default=False)
52 54
    parser.add_argument('--fake', action='store_true', default=False)
53 55
    group.add_argument("-a", "--all", help="synchronize all wcs", action='store_true',
54 56
                       default=False)
......
111 113
                logger.info('finished')
112 114
                feed_result = False
113 115
            except:
116
                if args.no_log_errors:
117
                    raise
114 118
                feed_result = True
115 119
                logger.exception('failed to synchronize with %s', url)
116 120
            failure = failure or feed_result
117
-