2019-01-17 17:46:55 +01:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
import sys
|
|
|
|
import time
|
|
|
|
import os
|
|
|
|
import shutil
|
|
|
|
import random
|
|
|
|
import socket
|
|
|
|
from contextlib import closing
|
|
|
|
from collections import namedtuple
|
|
|
|
|
|
|
|
import psycopg2
|
|
|
|
import pytest
|
|
|
|
|
2019-03-01 14:11:15 +01:00
|
|
|
import utils
|
|
|
|
|
|
|
|
|
2019-01-17 17:46:55 +01:00
|
|
|
Wcs = namedtuple('Wcs', ['url', 'appdir', 'pid'])
|
|
|
|
|
|
|
|
|
|
|
|
class Database(object):
|
|
|
|
def __init__(self):
|
|
|
|
self.db_name = 'db%s' % random.getrandbits(20)
|
|
|
|
self.dsn = 'dbname=%s' % self.db_name
|
|
|
|
with closing(psycopg2.connect('')) as conn:
|
|
|
|
conn.set_isolation_level(0)
|
|
|
|
with conn.cursor() as cursor:
|
|
|
|
cursor.execute('CREATE DATABASE %s' % self.db_name)
|
|
|
|
|
|
|
|
def conn(self):
|
|
|
|
return closing(psycopg2.connect(self.dsn))
|
|
|
|
|
|
|
|
def delete(self):
|
|
|
|
with closing(psycopg2.connect('')) as conn:
|
|
|
|
conn.set_isolation_level(0)
|
|
|
|
with conn.cursor() as cursor:
|
|
|
|
cursor.execute('DROP DATABASE IF EXISTS %s' % self.db_name)
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return '<Postgres Database %r>' % self.db_name
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def postgres_db():
|
|
|
|
db = Database()
|
|
|
|
try:
|
|
|
|
yield db
|
|
|
|
finally:
|
|
|
|
db.delete()
|
|
|
|
|
|
|
|
|
|
|
|
WCS_SCRIPTS = {
|
|
|
|
'setup-auth': u"""
|
|
|
|
from quixote import get_publisher
|
|
|
|
|
|
|
|
get_publisher().cfg['identification'] = {'methods': ['password']}
|
|
|
|
get_publisher().cfg['debug'] = {'display_exceptions': 'text'}
|
|
|
|
get_publisher().write_cfg()
|
|
|
|
""",
|
|
|
|
'create-user': u"""
|
|
|
|
from quixote import get_publisher
|
|
|
|
from qommon.ident.password_accounts import PasswordAccount
|
|
|
|
|
|
|
|
user = get_publisher().user_class()
|
|
|
|
user.name = 'foo bar'
|
|
|
|
user.email = 'foo@example.net'
|
|
|
|
user.store()
|
|
|
|
account = PasswordAccount(id='user')
|
|
|
|
account.set_password('user')
|
|
|
|
account.user_id = user.id
|
|
|
|
account.store()
|
|
|
|
""",
|
|
|
|
'create-data': u"""
|
|
|
|
import datetime
|
|
|
|
import random
|
|
|
|
from quixote import get_publisher
|
|
|
|
|
|
|
|
from wcs.categories import Category
|
|
|
|
from wcs.formdef import FormDef
|
|
|
|
from wcs.roles import Role
|
|
|
|
from wcs import fields
|
|
|
|
|
|
|
|
cat = Category()
|
|
|
|
cat.name = 'Catégorie'
|
|
|
|
cat.description = ''
|
|
|
|
cat.store()
|
|
|
|
|
|
|
|
formdef = FormDef()
|
|
|
|
formdef.name = 'Demande'
|
|
|
|
formdef.category_id = cat.id
|
|
|
|
formdef.fields = [
|
2019-02-07 23:30:18 +01:00
|
|
|
fields.StringField(id='1', label='1st field', type='string', anonymise=False, varname='string'),
|
2019-01-17 17:46:55 +01:00
|
|
|
fields.ItemField(id='2', label='2nd field', type='item',
|
2019-02-07 23:30:18 +01:00
|
|
|
items=['foo', 'bar', 'baz'], varname='item'),
|
|
|
|
fields.BoolField(id='3', label='3rd field', type='bool', varname='bool'),
|
2019-03-01 14:11:15 +01:00
|
|
|
fields.ItemField(id='4', label='4rth field', type='item', varname='item_open'),
|
2019-01-17 17:46:55 +01:00
|
|
|
]
|
|
|
|
formdef.store()
|
|
|
|
|
|
|
|
user = get_publisher().user_class.select()[0]
|
|
|
|
|
|
|
|
for i in range(50):
|
|
|
|
formdata = formdef.data_class()()
|
|
|
|
formdata.just_created()
|
|
|
|
formdata.receipt_time = datetime.datetime(2018, random.randrange(1, 13), random.randrange(1, 29)).timetuple()
|
|
|
|
formdata.data = {'1': 'FOO BAR %d' % i}
|
|
|
|
if i%4 == 0:
|
|
|
|
formdata.data['2'] = 'foo'
|
|
|
|
formdata.data['2_display'] = 'foo'
|
2019-03-01 14:11:15 +01:00
|
|
|
formdata.data['4'] = 'open_one'
|
|
|
|
formdata.data['4_display'] = 'open_one'
|
2019-01-17 17:46:55 +01:00
|
|
|
elif i%4 == 1:
|
|
|
|
formdata.data['2'] = 'bar'
|
|
|
|
formdata.data['2_display'] = 'bar'
|
2019-03-01 14:11:15 +01:00
|
|
|
formdata.data['4'] = 'open_two'
|
|
|
|
formdata.data['4_display'] = 'open_two'
|
2019-01-17 17:46:55 +01:00
|
|
|
else:
|
|
|
|
formdata.data['2'] = 'baz'
|
|
|
|
formdata.data['2_display'] = 'baz'
|
2019-03-01 14:11:15 +01:00
|
|
|
formdata.data['4'] = "open'three"
|
|
|
|
formdata.data['4_display'] = "open'three"
|
|
|
|
|
2019-01-14 10:57:16 +01:00
|
|
|
formdata.data['3'] = bool(i % 2)
|
2019-01-17 17:46:55 +01:00
|
|
|
if i%3 == 0:
|
|
|
|
formdata.jump_status('new')
|
|
|
|
else:
|
|
|
|
formdata.jump_status('finished')
|
|
|
|
if i%7 == 0:
|
|
|
|
formdata.user_id = user.id
|
|
|
|
formdata.store()
|
|
|
|
""",
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-03-01 14:11:15 +01:00
|
|
|
@pytest.fixture
|
|
|
|
def wcs_dir(tmp_path_factory):
|
|
|
|
return tmp_path_factory.mktemp('wcs')
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def wcs(tmp_path_factory, wcs_dir):
|
2019-01-17 17:46:55 +01:00
|
|
|
'''Session scoped wcs fixture, so read-only.'''
|
|
|
|
PORT = 8899
|
|
|
|
ADDRESS = '0.0.0.0'
|
|
|
|
WCS_PID = None
|
|
|
|
|
2019-03-01 14:11:15 +01:00
|
|
|
tenant_dir = wcs_dir / utils.HOSTNAME
|
2019-01-17 17:46:55 +01:00
|
|
|
tenant_dir.mkdir()
|
|
|
|
|
2019-03-01 14:11:15 +01:00
|
|
|
utils.run_wcs_script(wcs_dir, WCS_SCRIPTS['setup-auth'], 'setup-auth')
|
|
|
|
utils.run_wcs_script(wcs_dir, WCS_SCRIPTS['create-user'], 'create-user')
|
|
|
|
utils.run_wcs_script(wcs_dir, WCS_SCRIPTS['create-data'], 'create-data')
|
2019-01-17 17:46:55 +01:00
|
|
|
|
|
|
|
with (tenant_dir / 'site-options.cfg').open('w') as fd:
|
|
|
|
fd.write(u'''[api-secrets]
|
|
|
|
olap = olap
|
|
|
|
''')
|
|
|
|
|
2019-03-01 14:11:15 +01:00
|
|
|
with (wcs_dir / 'wcs.cfg').open('w') as fd:
|
2019-01-17 17:46:55 +01:00
|
|
|
fd.write(u'''[main]
|
2019-03-01 14:11:15 +01:00
|
|
|
app_dir = %s\n''' % wcs_dir)
|
2019-01-17 17:46:55 +01:00
|
|
|
|
2019-03-01 14:11:15 +01:00
|
|
|
with (wcs_dir / 'local_settings.py').open('w') as fd:
|
2019-01-17 17:46:55 +01:00
|
|
|
fd.write(u'''
|
|
|
|
WCS_LEGACY_CONFIG_FILE = '%s/wcs.cfg'
|
|
|
|
THEMES_DIRECTORY = '/'
|
|
|
|
ALLOWED_HOSTS = ['%s']
|
2019-03-01 14:11:15 +01:00
|
|
|
''' % (wcs_dir, utils.HOSTNAME))
|
2019-01-17 17:46:55 +01:00
|
|
|
|
|
|
|
# launch a Django worker for running w.c.s.
|
|
|
|
WCS_PID = os.fork()
|
|
|
|
if not WCS_PID:
|
2019-03-01 14:11:15 +01:00
|
|
|
os.chdir(os.path.dirname(utils.WCSCTL))
|
2019-01-17 17:46:55 +01:00
|
|
|
os.environ['DJANGO_SETTINGS_MODULE'] = 'wcs.settings'
|
2019-03-01 14:11:15 +01:00
|
|
|
os.environ['WCS_SETTINGS_FILE'] = str(wcs_dir / 'local_settings.py')
|
2019-01-17 17:46:55 +01:00
|
|
|
os.execvp('python', ['python', 'manage.py', 'runserver', '--noreload', '%s:%s' % (ADDRESS, PORT)])
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
# verify w.c.s. is launched
|
|
|
|
s = socket.socket()
|
|
|
|
i = 0
|
|
|
|
while True:
|
|
|
|
i += 1
|
|
|
|
try:
|
|
|
|
s.connect((ADDRESS, PORT))
|
|
|
|
except Exception:
|
|
|
|
time.sleep(0.1)
|
|
|
|
else:
|
|
|
|
s.close()
|
|
|
|
break
|
|
|
|
assert i < 50, 'no connection found after 5 seconds'
|
|
|
|
|
|
|
|
# verify w.c.s. is still running
|
|
|
|
pid, exit_code = os.waitpid(WCS_PID, os.WNOHANG)
|
|
|
|
if pid:
|
|
|
|
assert False, 'w.c.s. stopped with exit-code %s' % exit_code
|
|
|
|
|
2019-03-01 14:11:15 +01:00
|
|
|
yield Wcs(url='http://%s:%s/' % (utils.HOSTNAME, PORT), appdir=wcs_dir, pid=WCS_PID)
|
2019-01-17 17:46:55 +01:00
|
|
|
os.kill(WCS_PID, 9)
|
2019-03-01 14:11:15 +01:00
|
|
|
shutil.rmtree(str(wcs_dir))
|
2019-01-18 14:11:59 +01:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def olap_cmd(wcs, tmpdir, postgres_db):
|
|
|
|
config_ini = tmpdir / 'config.ini'
|
|
|
|
model_dir = tmpdir / 'model_dir'
|
|
|
|
model_dir.mkdir()
|
|
|
|
with config_ini.open('w') as fd:
|
|
|
|
fd.write(u'''
|
|
|
|
[wcs-olap]
|
|
|
|
cubes_model_dirs = {model_dir}
|
|
|
|
pg_dsn = {dsn}
|
|
|
|
|
|
|
|
[{wcs.url}]
|
|
|
|
orig = olap
|
|
|
|
key = olap
|
|
|
|
schema = olap
|
|
|
|
'''.format(wcs=wcs, model_dir=model_dir, dsn=postgres_db.dsn))
|
|
|
|
|
|
|
|
from wcs_olap import cmd
|
|
|
|
import sys
|
|
|
|
|
|
|
|
def f(no_log_errors=True):
|
|
|
|
old_argv = sys.argv
|
|
|
|
try:
|
|
|
|
sys.argv = ['', str(config_ini)]
|
|
|
|
if no_log_errors:
|
|
|
|
sys.argv.insert(1, '--no-log-errors')
|
|
|
|
cmd.main2()
|
|
|
|
finally:
|
|
|
|
sys.argv = old_argv
|
|
|
|
f.model_dir = model_dir
|
|
|
|
return f
|