def populate(self, app, dbsession): import transaction from occams import models from datetime import date # Any view-dependent data goes here # Webtests will use a different scope for its transaction with transaction.manager: user = models.User(key=USERID) dbsession.info['blame'] = user dbsession.add(user) dbsession.flush() site = models.Site(name=u'UCSD', title=u'UCSD', description=u'UCSD Campus', create_date=date.today()) patient = models.Patient(initials=u'ian', nurse=u'*****@*****.**', site=site, pid=u'123') study = models.Study( name=u'test_study', code=u'test_code', consent_date=date(2014, 12, 23), is_randomized=False, title=u'test_title', short_title=u'test_short', ) dbsession.add( models.Enrollment(patient=patient, study=study, consent_date=date(2014, 12, 22)))
def test_delete(self, req, dbsession, config, check_csrf_token): """ It should allow the owner of the export to cancel/delete the export """ import mock from pyramid.httpexceptions import HTTPOk from occams import models blame = models.User(key=u'joe') dbsession.add(blame) dbsession.flush() dbsession.info['blame'] = blame export = models.Export( owner_user=( dbsession.query(models.User) .filter_by(key='joe') .one()), contents=[], status='complete') dbsession.add(export) dbsession.flush() export_id = export.id export_name = export.name dbsession.expunge_all() config.testing_securitypolicy(userid='joe') with mock.patch('occams.tasks.app.control.revoke') as revoke: res = self._call_fut(export, req) check_csrf_token.assert_called_with(req) assert isinstance(res, HTTPOk) assert dbsession.query(models.Export).get(export_id) is None revoke.assert_called_with(export_name)
def dbsession(config): """ (Integartion Testing) Instantiates a database session. :param config: The pyramid testing configuartion :returns: An instantiated sqalchemy database session """ from occams import models import occams.models.events import zope.sqlalchemy dbsession = config.registry['dbsession_factory']() occams.models.events.register(dbsession) zope.sqlalchemy.register(dbsession) # Pre-configure with a blame user blame = models.User(key=USERID) dbsession.add(blame) dbsession.flush() dbsession.info['blame'] = blame # Other expected settings dbsession.info['settings'] = config.registry.settings # Hardcoded workflow dbsession.add_all([ models.State(name=u'pending-entry', title=u'Pending Entry'), models.State(name=u'pending-review', title=u'Pending Review'), models.State(name=u'pending-correction', title=u'Pending Correction'), models.State(name=u'complete', title=u'Complete') ]) return dbsession
def test_not_owner(self, app, dbsession): import transaction from occams import models with transaction.manager: dbsession.add(models.User(key='somebody_else')) environ = make_environ(userid='somebody_else') app.get(self.url, extra_environ=environ, status=403)
def populate(self, app, dbsession): import transaction from occams import models from datetime import date # Any view-dependent data goes here # Webtests will use a different scope for its transaction with transaction.manager: user = models.User(key=USERID) dbsession.info['blame'] = user dbsession.add(user) dbsession.flush() site = models.Site(name=u'UCSD', title=u'UCSD', description=u'UCSD Campus', create_date=date.today()) dbsession.add( models.Site(name=u'UCLA', title=u'UCLA', description=u'UCLA Campus', create_date=date.today())) dbsession.add( models.Patient(initials=u'ian', nurse=u'*****@*****.**', site=site, pid=u'123')) dbsession.flush()
def test_get_not_found_status(self, req, dbsession, status): """ It should return 404 if the record is not ready """ from pyramid.httpexceptions import HTTPBadRequest from occams import models blame = models.User(key=u'joe') dbsession.add(blame) dbsession.flush() dbsession.info['blame'] = blame export = models.Export( id=123, owner_user=( dbsession.query(models.User) .filter_by(key='joe') .one()), contents=[], status=status) dbsession.add(export) dbsession.flush() with pytest.raises(HTTPBadRequest): self._call_fut(export, req)
def test_zip(self): """ It should generate a zip file containing the specified contents """ from zipfile import ZipFile from occams.celery import Session from occams import models as datastore from occams import models, tasks from occams.exports.pid import PidPlan owner = datastore.User(key=u'joe') Session.info['blame'] = owner Session.add(owner) Session.flush() export = models.Export(owner_user=owner, contents=[{ 'name': 'pid', 'title': 'PID', 'versions': [] }], status='complete') Session.add(export) Session.flush() tasks.app.settings['studies.export.plans'] = [PidPlan] tasks.make_export(export.name) # @in_transaction removes the session metadata, so we gotta do this export = Session.merge(export) with ZipFile(export.path, 'r') as zfp: file_names = zfp.namelist() assert sorted(['pid.csv', 'codebook.csv']) == sorted(file_names)
def populate(self, app, dbsession): import transaction from occams import models # Any view-dependent data goes here # Webtests will use a different scope for its transaction with transaction.manager: dbsession.add(models.User(key=USERID))
def test_not_owner(self, app, dbsession): import transaction from occams import models with transaction.manager: dbsession.add(models.User(key='somebody_else')) environ = make_environ(userid='somebody_else') csrf_token = get_csrf_token(app, environ) app.delete(self.url, extra_environ=environ, headers={'X-CSRF-Token': csrf_token}, xhr=True, status=403)
def test_get_current_user(self, req, dbsession, config): """ It should return the authenticated user's exports """ import mock from occams import models req.registry.settings['studies.export.dir'] = '/tmp' blame = models.User(key=u'joe') dbsession.add(blame) dbsession.add(models.User(key='jane')) dbsession.flush() dbsession.info['blame'] = blame export1 = models.Export( owner_user=( dbsession.query(models.User) .filter_by(key='joe') .one()), contents=[], status='pending') export2 = models.Export( owner_user=( dbsession.query(models.User) .filter_by(key='jane') .one()), contents=[], status='pending') dbsession.add_all([export1, export2]) dbsession.flush() config.testing_securitypolicy(userid='joe') req.redis = mock.Mock() context = models.ExportFactory(req) export1.__parent__ = context export2.__parent__ = context res = self._call_fut(models.ExportFactory(req), req) exports = res['exports'] assert len(exports) == 1
def populate(self, app, dbsession): import transaction from occams import models from datetime import date # Any view-dependent data goes here # Webtests will use a different scope for its transaction with transaction.manager: user = models.User(key=USERID) dbsession.info['blame'] = user dbsession.add(user) dbsession.flush() site = models.Site(name=u'UCSD', title=u'UCSD', description=u'UCSD Campus', create_date=date.today()) patient = models.Patient(initials=u'ian', nurse=u'*****@*****.**', site=site, pid=u'123') form = models.Schema(name=u'test_schema', title=u'test_title', publish_date=date(2015, 1, 1)) study = models.Study(name=u'test_study', code=u'test_code', consent_date=date(2014, 12, 23), is_randomized=False, title=u'test_title', short_title=u'test_short', schemata=set([form])) cycle = models.Cycle(name=u'TestCycle', title=u'TestCycle', week=39, study=study) visit = models.Visit(patient=patient, cycles=[cycle], visit_date='2015-01-01') entity = models.Entity(schema=form, collect_date=date(2015, 1, 1)) dbsession.add(study) dbsession.add(patient) dbsession.add(visit) dbsession.add(entity) patient.entities.add(entity)
def populate(self, app, dbsession): import transaction from occams import models # Any view-dependent data goes here # Webtests will use a different scope for its transaction with transaction.manager: user = models.User(key=USERID) dbsession.info['blame'] = user dbsession.add(user) export = models.Export(owner_user=user) dbsession.add(export) dbsession.flush() self.url = self.url_fmt.format(export=export.id)
def populate(self, app, dbsession): import transaction from occams import models # Any view-dependent data goes here # Webtests will use a different scope for its transaction with transaction.manager: blame = models.User(key=USERID) dbsession.info['blame'] = blame dbsession.add(blame) dbsession.flush() dbsession.add(models.Site(name=u'ucsd', title=u'UCSD')) dbsession.add(models.Site(name=u'ucla', title=u'UCSD'))
def app(request, wsgi, dbsession): """ (Functional Testing) Initiates a user request against a WSGI stack :param request: The pytest context :param wsgi: An initialized WSGI stack :param dbsession: A database session for seting up pre-existing data :returns: a test app request against the WSGI instance """ import transaction from webtest import TestApp from zope.sqlalchemy import mark_changed from occams import models as models # Save all changes up tho this point (dbsession does some configuration) with transaction.manager: blame = models.User(key='workflow@localhost') dbsession.add(blame) dbsession.flush() dbsession.info['blame'] = blame dbsession.add_all([ models.State(name=u'pending-entry', title=u'Pending Entry'), models.State(name=u'pending-review', title=u'Pending Review'), models.State(name=u'pending-correction', title=u'Pending Correction'), models.State(name=u'complete', title=u'Complete') ]) app = TestApp(wsgi) yield app with transaction.manager: # DELETE is dramatically faster than TRUNCATE # http://stackoverflow.com/a/11423886/148781 # We also have to do this as a raw query becuase SA does # not have a way to invoke server-side cascade dbsession.execute('DELETE FROM "rostersite" CASCADE') dbsession.execute('DELETE FROM "study" CASCADE') dbsession.execute('DELETE FROM "patient" CASCADE') dbsession.execute('DELETE FROM "site" CASCADE') dbsession.execute('DELETE FROM "schema" CASCADE') dbsession.execute('DELETE FROM "export" CASCADE') dbsession.execute('DELETE FROM "state" CASCADE') dbsession.execute('DELETE FROM "user" CASCADE') mark_changed(dbsession)
def test_ignore_expired(self, req, dbsession, config): """ It should not render expired exports. """ from datetime import datetime, timedelta import mock from occams import models EXPIRE_DAYS = 10 req.registry.settings['studies.export.expire'] = EXPIRE_DAYS req.registry.settings['studies.export.dir'] = '/tmp' blame = models.User(key=u'joe') dbsession.add(blame) dbsession.flush() dbsession.info['blame'] = blame now = datetime.now() export = models.Export( owner_user=( dbsession.query(models.User) .filter_by(key='joe') .one()), contents=[], status='pending', create_date=now, modify_date=now) dbsession.add(export) dbsession.flush() config.testing_securitypolicy(userid='joe') req.redis = mock.Mock() context = models.ExportFactory(req) export.__parent__ = context res = self._call_fut(context, req) exports = res['exports'] assert len(exports) == 1 export.create_date = export.modify_date = \ now - timedelta(EXPIRE_DAYS + 1) dbsession.flush() context = models.ExportFactory(req) export.__parent__ = context res = self._call_fut(context, req) exports = res['exports'] assert len(exports) == 0
def populate(self, app, dbsession): import transaction from occams import models from datetime import date # Any view-dependent data goes here # Webtests will use a different scope for its transaction with transaction.manager: user = models.User(key=USERID) dbsession.info['blame'] = user dbsession.add(user) dbsession.flush() site = models.Site(name=u'UCSD', title=u'UCSD', description=u'UCSD Campus', create_date=date.today()) patient = models.Patient(initials=u'ian', nurse=u'*****@*****.**', site=site, pid=u'123') form = models.Schema(name=u'test_schema', title=u'test_title', publish_date=date(2015, 1, 1)) study = models.Study(name=u'test_study', code=u'test_code', consent_date=date(2014, 12, 23), is_randomized=False, title=u'test_title', short_title=u'test_short', schemata=set([form])) state = (dbsession.query( models.State).filter_by(name=u'pending-entry').one()) dbsession.add( models.Entity(state=state, schema=form, collect_date=date(2015, 2, 1))) dbsession.add( models.Enrollment(patient=patient, study=study, consent_date=date(2014, 12, 22)))
def populate(self, app, dbsession): from datetime import date import transaction from occams import models # Any view-dependent data goes here # Webtests will use a different scope for its transaction with transaction.manager: user = models.User(key=USERID) dbsession.info['blame'] = user dbsession.add(user) dbsession.flush() dbsession.add( models.Site(name=u'UCSD', title=u'UCSD', description=u'UCSD Campus', create_date=date.today())) dbsession.flush()
def populate(self, app, dbsession): import transaction from occams import models from datetime import date # Any view-dependent data goes here # Webtests will use a different scope for its transaction with transaction.manager: user = models.User(key=USERID) dbsession.info['blame'] = user dbsession.add(user) dbsession.flush() dbsession.add( models.Study(name=u'test', title=u'test', short_title=u'test', code=u'test', consent_date=date.today(), is_randomized=False))
def populate(self, request, app, dbsession): import os import transaction from occams import models # Any view-dependent data goes here # Webtests will use a different scope for its transaction with transaction.manager: dbsession.add(models.User(key=USERID)) # XXX: need to somehow get the settings so we can consitently # get the correct directory with open('/tmp/codebook.csv', 'w+') as fp: self.codebook_file_name = fp.name def rm(): os.unlink(self.codebook_file_name) request.addfinalizer(rm)
def celery(request): """ (Function Testing) Sets up a celery application for testing :param request: The pytest context """ import shutil import tempfile import mock from redis import StrictRedis from sqlalchemy import create_engine from occams.celery import Session from occams import models as models from occams import tasks settings = { 'studies.export.dir': tempfile.mkdtemp(), 'celery.blame': USERID } tasks.app.userid = settings['celery.blame'] tasks.app.redis = StrictRedis.from_url(REDIS_URL) tasks.app.settings = settings db_url = request.config.getoption('--db') engine = create_engine(db_url) Session.configure(bind=engine, info={'settings': settings}) Session.add(models.User(key=settings['celery.blame'])) Session.flush() commitmock = mock.patch('occams.tasks.Session.commit') commitmock.start() def cleanup(): commitmock.stop() shutil.rmtree(settings['studies.export.dir']) Session.remove() request.addfinalizer(cleanup)
def test_exceed_limit(self, req, dbsession, config): """ It should not let the user exceed their allocated export limit """ from datetime import date from webob.multidict import MultiDict from occams import models from occams.exports.schema import SchemaPlan config.registry.settings['app.export.limit'] = 0 req.registry.settings['studies.export.plans'] = [SchemaPlan.list_all] blame = models.User(key=u'joe') dbsession.add(blame) dbsession.flush() dbsession.info['blame'] = blame previous_export = models.Export( owner_user=( dbsession.query(models.User) .filter_by(key='joe') .one()), contents=[{ u'name': u'vitals', u'title': u'Vitals', u'versions': [str(date.today())]}]) dbsession.add(previous_export) dbsession.flush() # The renderer should know about it config.testing_securitypolicy(userid='joe') res = self._call_fut(models.ExportFactory(req), req) assert res['exceeded'] # If the user insists, they'll get a validation error as well config.testing_securitypolicy(userid='joe') req.method = 'POST' req.POST = MultiDict([('contents', 'vitals')]) assert res['exceeded']
def test_valid(self, req, dbsession, config, check_csrf_token): """ It should add an export record and initiate an async task """ from datetime import date import mock from pyramid.httpexceptions import HTTPFound from webob.multidict import MultiDict from occams import models from occams.exports.schema import SchemaPlan req.registry.settings['app.export.dir'] = '/tmp' req.registry.settings['studies.export.plans'] = [SchemaPlan.list_all] blame = models.User(key=u'joe') dbsession.add(blame) dbsession.flush() dbsession.info['blame'] = blame schema = models.Schema( name=u'vitals', title=u'Vitals', publish_date=date.today()) dbsession.add(schema) dbsession.flush() config.testing_securitypolicy(userid='joe') req.method = 'POST' req.POST = MultiDict([('contents', str('vitals'))]) # Don't invoke subtasks with mock.patch('occams.tasks.make_export'): res = self._call_fut(models.ExportFactory(req), req) check_csrf_token.assert_called_with(req) assert isinstance(res, HTTPFound) assert res.location == req.route_path('studies.exports_status') export = dbsession.query(models.Export).one() assert export.owner_user.key == 'joe'
def populate(self, request, dbsession): import os import transaction from occams import models # Any view-dependent data goes here # Webtests will use a different scope for its transaction with transaction.manager: user = models.User(key=USERID) dbsession.info['blame'] = user dbsession.add(user) export = models.Export(name='myexport', status='complete', owner_user=user) dbsession.add(export) dbsession.flush() self.url = self.url_fmt.format(export=export.id) with open('/tmp/myexport', 'w+') as fp: self.export_file_name = fp.name def rm(): os.unlink(self.export_file_name) request.addfinalizer(rm)