314 lines
11 KiB
Python
314 lines
11 KiB
Python
import cPickle
|
|
import email.header
|
|
import email.parser
|
|
import os
|
|
import tempfile
|
|
import random
|
|
import psycopg2
|
|
import pytest
|
|
import shutil
|
|
import threading
|
|
import urlparse
|
|
|
|
from wcs import sql
|
|
|
|
from webtest import TestApp
|
|
from quixote import cleanup, get_publisher
|
|
from django.conf import settings
|
|
|
|
import wcs
|
|
import wcs.wsgi
|
|
from wcs import publisher, compat
|
|
from wcs.qommon.http_request import HTTPRequest
|
|
from wcs.users import User
|
|
from wcs.tracking_code import TrackingCode
|
|
import wcs.qommon.sms
|
|
import qommon.sms
|
|
from qommon.errors import ConnectionError
|
|
|
|
class KnownElements(object):
|
|
pickle_app_dir = None
|
|
sql_app_dir = None
|
|
sql_db_name = None
|
|
|
|
known_elements = KnownElements()
|
|
|
|
def create_temporary_pub(sql_mode=False):
|
|
if sql_mode is True:
|
|
if pytest.config.getoption('without_postgresql_tests'):
|
|
pytest.skip("unsupported configuration")
|
|
return
|
|
if get_publisher():
|
|
get_publisher().cleanup()
|
|
cleanup()
|
|
if sql_mode is False and known_elements.pickle_app_dir:
|
|
APP_DIR = known_elements.pickle_app_dir
|
|
elif sql_mode is True and known_elements.sql_app_dir:
|
|
APP_DIR = known_elements.sql_app_dir
|
|
else:
|
|
APP_DIR = tempfile.mkdtemp()
|
|
if sql_mode is True:
|
|
known_elements.sql_app_dir = APP_DIR
|
|
elif sql_mode is False:
|
|
known_elements.pickle_app_dir = APP_DIR
|
|
|
|
compat.CompatWcsPublisher.APP_DIR = APP_DIR
|
|
compat.CompatWcsPublisher.DATA_DIR = os.path.abspath(
|
|
os.path.join(os.path.dirname(wcs.__file__), '..', 'data'))
|
|
compat.CompatWcsPublisher.cronjobs = None
|
|
pub = compat.CompatWcsPublisher.create_publisher()
|
|
# allow saving the user
|
|
pub.app_dir = os.path.join(APP_DIR, 'example.net')
|
|
pub.site_charset = 'utf-8'
|
|
|
|
if sql_mode:
|
|
pub.user_class = sql.SqlUser
|
|
pub.tracking_code_class = sql.TrackingCode
|
|
pub.is_using_postgresql = lambda: True
|
|
else:
|
|
pub.user_class = User
|
|
pub.tracking_code_class = TrackingCode
|
|
pub.is_using_postgresql = lambda: False
|
|
|
|
if os.path.exists(os.path.join(pub.app_dir, 'wcs.log')):
|
|
os.unlink(os.path.join(pub.app_dir, 'wcs.log'))
|
|
|
|
if os.path.exists(os.path.join(pub.APP_DIR, 'scripts')):
|
|
shutil.rmtree(os.path.join(pub.APP_DIR, 'scripts'))
|
|
if os.path.exists(os.path.join(pub.app_dir, 'scripts')):
|
|
shutil.rmtree(os.path.join(pub.app_dir, 'scripts'))
|
|
|
|
if os.path.exists(pub.app_dir):
|
|
pub.cfg = {}
|
|
if sql_mode:
|
|
pub.cfg['postgresql'] = {'database': known_elements.sql_db_name, 'user': os.environ['USER']}
|
|
pub.cfg['misc'] = {'charset': 'utf-8'}
|
|
pub.cfg['language'] = {'language': 'en'}
|
|
pub.write_cfg()
|
|
return pub
|
|
|
|
os.mkdir(pub.app_dir)
|
|
fd = file(os.path.join(pub.app_dir, 'site-options.cfg'), 'w')
|
|
fd.write('[wscall-secrets]\n')
|
|
fd.write('idp.example.net = BAR\n')
|
|
fd.write('\n')
|
|
fd.write('[options]\n')
|
|
fd.write('formdef-captcha-option = true\n')
|
|
fd.write('workflow-resubmit-action = true\n')
|
|
fd.write('workflow-global-actions = true\n')
|
|
fd.write('workflow-criticality-levels = true\n')
|
|
if sql_mode:
|
|
fd.write('postgresql = true\n')
|
|
conn = psycopg2.connect(user=os.environ['USER'])
|
|
conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
|
|
cur = conn.cursor()
|
|
dbname = 'wcstests%d' % random.randint(0, 100000)
|
|
known_elements.sql_db_name = dbname
|
|
cur.execute('CREATE DATABASE %s' % dbname)
|
|
cur.close()
|
|
|
|
pub.cfg['postgresql'] = {'database': dbname, 'user': os.environ['USER']}
|
|
pub.cfg['misc'] = {'charset': 'utf-8'}
|
|
pub.write_cfg()
|
|
|
|
sql.do_user_table()
|
|
sql.do_tracking_code_table()
|
|
|
|
conn.close()
|
|
|
|
fd.close()
|
|
|
|
return pub
|
|
|
|
def clean_temporary_pub():
|
|
if get_publisher():
|
|
get_publisher().cleanup()
|
|
if known_elements.pickle_app_dir and os.path.exists(known_elements.pickle_app_dir):
|
|
shutil.rmtree(known_elements.pickle_app_dir)
|
|
known_elements.pickle_app_dir = None
|
|
if known_elements.sql_app_dir and os.path.exists(known_elements.sql_app_dir):
|
|
shutil.rmtree(known_elements.sql_app_dir)
|
|
known_elements.sql_app_dir = None
|
|
if known_elements.sql_db_name:
|
|
conn = psycopg2.connect(user=os.environ['USER'])
|
|
conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
|
|
try:
|
|
cur = conn.cursor()
|
|
cur.execute('DROP DATABASE %s' % known_elements.sql_db_name)
|
|
cur.close()
|
|
except psycopg2.Error:
|
|
pass
|
|
known_elements.sql_db_name = None
|
|
|
|
def get_app(pub, https=False):
|
|
extra_environ = {'HTTP_HOST': 'example.net', 'REMOTE_ADDR': '127.0.0.1'}
|
|
if https:
|
|
settings.SECURE_PROXY_SSL_HEADER = ('HTTPS', 'on')
|
|
extra_environ['HTTPS'] = 'on'
|
|
else:
|
|
extra_environ['HTTPS'] = 'off'
|
|
return TestApp(wcs.wsgi.application, extra_environ=extra_environ)
|
|
|
|
def login(app, username='admin', password='admin'):
|
|
login_page = app.get('/login/')
|
|
login_form = login_page.forms['login-form']
|
|
login_form['username'] = username
|
|
login_form['password'] = password
|
|
resp = login_form.submit()
|
|
assert resp.status_int == 302
|
|
return app
|
|
|
|
|
|
class EmailsMocking(object):
|
|
def create_smtp_server(self, *args, **kwargs):
|
|
class MockSmtplibSMTP(object):
|
|
def __init__(self, emails):
|
|
self.emails = emails
|
|
|
|
def sendmail(self, msg_from, rcpts, msg):
|
|
msg = email.parser.Parser().parsestr(msg)
|
|
subject = email.header.decode_header(msg['Subject'])[0][0]
|
|
if msg.is_multipart():
|
|
payload = msg.get_payload()[0].get_payload(decode=True)
|
|
else:
|
|
payload = msg.get_payload(decode=True)
|
|
self.emails[subject] = {
|
|
'from': msg_from,
|
|
'to': email.header.decode_header(msg['To'])[0][0],
|
|
'payload': payload,
|
|
'msg': msg,
|
|
}
|
|
self.emails[subject]['email_rcpt'] = rcpts
|
|
|
|
def close(self):
|
|
pass
|
|
|
|
return MockSmtplibSMTP(self.emails)
|
|
|
|
def get(self, subject):
|
|
return self.emails.get(subject)
|
|
|
|
def empty(self):
|
|
self.emails.clear()
|
|
|
|
def count(self):
|
|
return len(self.emails)
|
|
|
|
def __enter__(self):
|
|
import wcs.qommon.emails
|
|
import qommon.emails
|
|
self.wcs_create_smtp_server = wcs.qommon.emails.create_smtp_server
|
|
self.qommon_create_smtp_server = qommon.emails.create_smtp_server
|
|
|
|
wcs.qommon.emails.create_smtp_server = self.create_smtp_server
|
|
qommon.emails.create_smtp_server = self.create_smtp_server
|
|
|
|
self.emails = {}
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_value, tb):
|
|
del self.emails
|
|
wcs.qommon.emails.create_smtp_server = self.wcs_create_smtp_server
|
|
qommon.emails.create_smtp_server = self.qommon_create_smtp_server
|
|
|
|
|
|
class MockSubstitutionVariables(object):
|
|
def get_substitution_variables(self):
|
|
return {'bar': 'Foobar', 'foo': '1 < 3', 'email': 'sub@localhost',
|
|
'empty': ''}
|
|
|
|
|
|
class HttpRequestsMocking(object):
|
|
def __init__(self):
|
|
self.requests = []
|
|
import wcs.qommon.misc
|
|
import qommon.misc
|
|
wcs.qommon.misc._http_request = self.http_request
|
|
qommon.misc._http_request = self.http_request
|
|
|
|
def http_request(self, url, method='GET', body=None, headers={}, timeout=None):
|
|
self.requests.append(
|
|
{'url': url,
|
|
'method': method,
|
|
'body': body,
|
|
'headers': headers,
|
|
'timeout': timeout})
|
|
|
|
scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)
|
|
base_url = urlparse.urlunparse((scheme, netloc, path, '', '', ''))
|
|
|
|
status, data, headers = {
|
|
'http://remote.example.net/204': (204, None, None),
|
|
'http://remote.example.net/400-json': (400, '{"err": 1, "err_desc": ":("}', None),
|
|
'http://remote.example.net/404': (404, 'page not found', None),
|
|
'http://remote.example.net/404-json': (404, '{"err": 1}', None),
|
|
'http://remote.example.net/500': (500, 'internal server error', None),
|
|
'http://remote.example.net/json': (200, '{"foo": "bar"}', None),
|
|
'http://remote.example.net/json-err0': (200, '{"data": "foo", "err": 0}', None),
|
|
'http://remote.example.net/json-err1': (200, '{"data": "", "err": 1}', None),
|
|
'http://remote.example.net/json-errstr': (200, '{"data": "", "err": "bug"}', None),
|
|
'http://remote.example.net/json-errheader0': (200, '{"foo": "bar"}',
|
|
{'x-error-code': '0'}),
|
|
'http://remote.example.net/json-errheader1': (200, '{"foo": "bar"}',
|
|
{'x-error-code': '1'}),
|
|
'http://remote.example.net/json-errheaderstr': (200, '{"foo": "bar"}',
|
|
{'x-error-code': 'bug'}),
|
|
'http://remote.example.net/xml': (200, '<?xml version="1.0"><foo/>',
|
|
{'content-type': 'text/xml'}),
|
|
'http://remote.example.net/xml-errheader': (200, '<?xml version="1.0"><foo/>',
|
|
{'content-type': 'text/xml', 'x-error-code': '1'}),
|
|
'http://remote.example.net/connection-error': (None, None, None),
|
|
}.get(base_url, (200, '', {}))
|
|
|
|
class FakeResponse(object):
|
|
def __init__(self, status, data, headers):
|
|
self.status = status
|
|
self.reason = 'whatever'
|
|
self.data = data
|
|
self.headers = headers or {}
|
|
self.length = len(data or '')
|
|
|
|
def getheader(self, header):
|
|
return self.headers.get(header, None)
|
|
|
|
if status is None:
|
|
raise ConnectionError('error')
|
|
return FakeResponse(status, data, headers), status, data, None
|
|
|
|
def get_last(self, attribute):
|
|
return self.requests[-1][attribute]
|
|
|
|
def empty(self):
|
|
self.requests = []
|
|
|
|
http_requests = HttpRequestsMocking()
|
|
|
|
|
|
class SMSMocking(wcs.qommon.sms.MobytSMS):
|
|
def get_sms_class(self, mode):
|
|
if mode == 'none':
|
|
return None
|
|
return self
|
|
|
|
def send(self, sender, destinations, text, quality=None):
|
|
self.sms.append({'sender': sender, 'destinations': destinations, 'text': text})
|
|
|
|
def get_sms_left(self, type='standard'):
|
|
raise NotImplementedError
|
|
|
|
def get_money_left(self):
|
|
raise NotImplementedError
|
|
|
|
def __enter__(self):
|
|
self.sms = []
|
|
self.wcs_get_sms_class = wcs.qommon.sms.SMS.get_sms_class
|
|
self.qommon_get_sms_class = qommon.sms.SMS.get_sms_class
|
|
wcs.qommon.sms.SMS.get_sms_class = self.get_sms_class
|
|
qommon.sms.SMS.get_sms_class = self.get_sms_class
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_value, tb):
|
|
del self.sms
|
|
wcs.qommon.sms.SMS.get_sms_class = self.wcs_get_sms_class
|
|
qommon.sms.SMS.get_sms_class = self.qommon_get_sms_class
|