def test_by_ids(self, req, dbsession,): """ It should allow search via direct ids (for pre-entered values) """ from datetime import date from occams import models from webob.multidict import MultiDict study = models.Study( name=u'somestudy', title=u'Some Study', short_title=u'sstudy', code=u'000', consent_date=date.today()) cycle1 = models.Cycle(name='week-1', title=u'Foo Week 1', week=1) cycle2 = models.Cycle(name='week-2', title=u'Bar Week 2', week=2) patient = models.Patient( site=models.Site(name=u'ucsd', title=u'UCSD'), pid=u'12345') study.cycles.append(cycle1) study.cycles.append(cycle2) dbsession.add_all([patient, study]) dbsession.flush() req.GET = MultiDict([('ids', cycle1.id)]) res = self._call_fut(patient['visits'], req) assert cycle1.id == res['cycles'][0]['id']
def test_call_success(self, req, dbsession,): """ It should be able to validate cycles via GET (for AJAX req) """ from datetime import date from occams import models from webob.multidict import MultiDict study = models.Study( name=u'somestudy', title=u'Some Study', short_title=u'sstudy', code=u'000', consent_date=date.today()) cycle1 = models.Cycle(name='week-1', title=u'Foo Week 1', week=1) cycle2 = models.Cycle(name='week-2', title=u'Bar Week 2', week=2) patient = models.Patient( site=models.Site(name=u'ucsd', title=u'UCSD'), pid=u'12345') study.cycles.append(cycle1) study.cycles.append(cycle2) dbsession.add_all([patient, study]) dbsession.flush() req.GET = MultiDict([ ('cycles', ','.join(map(str, [cycle1.id, cycle2.id])))]) res = self._call_fut(patient['visits'], req) assert res
def test_update_cycles(self, req, dbsession, check_csrf_token): """ It should also update cycle versions """ from datetime import date, timedelta from occams import models as datastore from occams import models today = date.today() tomorrow = today + timedelta(days=1) v1 = datastore.Schema(name=u'test', title=u'', publish_date=today) v2 = datastore.Schema(name=u'test', title=u'', publish_date=tomorrow) cycle = models.Cycle(name=u'wk-001', title=u'WK-001', schemata=set([v1])) study = models.Study(name=u'somestudy', title=u'Some Study', short_title=u'sstudy', code=u'000', cycles=[cycle], schemata=set([v1]), consent_date=date.today()) dbsession.add_all([study, v1, v2]) dbsession.flush() req.json_body = {'schema': v1.name, 'versions': [v2.id]} self._call_fut(study, req) assert v2 in study.schemata # v2 should have been passed on to the cycle using it as well assert v2 in cycle.schemata
def test_success(self, req, dbsession, check_csrf_token): """ It should remove the schema from the study and cascade to its cycles """ from datetime import date from occams import models as datastore from occams import models schema = datastore.Schema(name='test', title=u'', publish_date=date.today()) cycle = models.Cycle(name='week-1', title=u'Week 1', week=1, schemata=set([schema])) study = models.Study(name=u'somestudy', title=u'Some Study', short_title=u'sstudy', code=u'000', consent_date=date.today(), cycles=[cycle], schemata=set([schema])) dbsession.add_all([study, schema]) dbsession.flush() req.matchdict = {'schema': schema.name} self._call_fut(study, req) assert schema not in study.schemata assert schema not in cycle.schemata
def test_edit_unique_name(self, req, dbsession): """ It should allow the cycle to be able to change its unique name """ from datetime import date from occams import models cycle = models.Cycle(name='week-1', title=u'Week 1', week=1) study = models.Study(name=u'somestudy', title=u'Some Study', short_title=u'sstudy', code=u'000', consent_date=date.today(), cycles=[cycle]) dbsession.add_all([study]) dbsession.flush() req.json_body = { 'name': 'somestudy', 'title': cycle.title, 'week': cycle.week } res = self._call_fut(cycle, req) assert res is not None
def test_enforce_unique_name(self, req, dbsession): """ It should make sure the name stays unique when adding new cycles """ from datetime import date from pyramid.httpexceptions import HTTPBadRequest from occams import models cycle = models.Cycle(name='week-1', title=u'Week 1', week=1) study = models.Study(name=u'some-study', title=u'Some Study', short_title=u'sstudy', code=u'000', consent_date=date.today(), cycles=[cycle]) dbsession.add_all([study]) dbsession.flush() req.json_body = {'title': u'Week 1', 'week': 2} with pytest.raises(HTTPBadRequest) as excinfo: self._call_fut(study['cycles'], req) assert 'not yield a unique' in \ excinfo.value.json['errors']['title'].lower()
def test_update_patient(self, req, dbsession, check_csrf_token): """ It should also mark the patient as modified """ from datetime import date from occams import models study = models.Study( name=u'somestudy', title=u'Some Study', short_title=u'sstudy', code=u'000', consent_date=date.today()) cycle1 = models.Cycle(study=study, name='week-1', title=u'', week=1) patient = models.Patient( site=models.Site(name=u'ucsd', title=u'UCSD'), pid=u'12345') dbsession.add_all([patient, study]) dbsession.flush() old_modify_date = patient.modify_date req.json_body = { 'cycles': [str(cycle1.id)], 'visit_date': str(date.today()) } self._call_fut(patient['visits'], req) assert old_modify_date < patient.modify_date
def test_enable(self, req, dbsession, check_csrf_token): """ It should successfully add a schema to a cycle """ from datetime import date from occams import models as datastore from occams import models schema = datastore.Schema(name='test', title=u'Test', publish_date=date.today()) cycle = models.Cycle(name='week-1', title=u'Week 1', week=1) study = models.Study(name=u'somestudy', title=u'Some Study', short_title=u'sstudy', code=u'000', consent_date=date.today(), cycles=[cycle], schemata=set([schema])) dbsession.add_all([study, schema]) dbsession.flush() req.json_body = { 'schema': schema.name, 'cycle': cycle.id, 'enabled': True } self._call_fut(study, req) assert schema in cycle.schemata
def test_unique_visit_date(self, req, dbsession, check_csrf_token): """ It should not allow duplicate visit dates """ from datetime import date from pyramid.httpexceptions import HTTPBadRequest from occams import models study = models.Study( name=u'somestudy', title=u'Some Study', short_title=u'sstudy', code=u'000', consent_date=date.today()) cycle1 = models.Cycle(name='week-1', title=u'', week=1) cycle2 = models.Cycle(name='week-2', title=u'', week=2) study.cycles.append(cycle1) study.cycles.append(cycle2) patient = models.Patient( site=models.Site(name=u'ucsd', title=u'UCSD'), pid=u'12345') visit = models.Visit( patient=patient, cycles=[cycle1], visit_date=date.today()) dbsession.add_all([patient, study, visit]) dbsession.flush() req.json_body = { 'cycles': [cycle2.id], 'visit_date': str(date.today()) } # Update the visit, should allow to update the date self._call_fut(visit, req) # New visits cannot share dates with pytest.raises(HTTPBadRequest) as excinfo: self._call_fut(patient['visits'], req) assert 'already exists' in \ excinfo.value.json['errors']['visit_date']
def test_success(self, req, dbsession, check_csrf_token): """ It should allow removal of entities from a visit. """ from datetime import date, timedelta from pyramid.httpexceptions import HTTPOk from occams import models as datastore from occams import models cycle = models.Cycle(name='week-1', title=u'', week=1) schema = datastore.Schema( name=u'sample', title=u'', publish_date=date.today()) study = models.Study( name=u'somestudy', title=u'Some Study', short_title=u'sstudy', code=u'000', consent_date=date.today(), cycles=[cycle], schemata=set([schema])) site = models.Site(name=u'ucsd', title=u'UCSD') default_state = ( dbsession.query(datastore.State) .filter_by(name=u'pending-entry') .one()) t_a = date.today() + timedelta(days=5) patient_a = models.Patient(site=site, pid=u'12345') visit_a = models.Visit( patient=patient_a, cycles=[cycle], visit_date=t_a) entity_a_1 = datastore.Entity( schema=schema, collect_date=t_a, state=default_state) entity_a_2 = datastore.Entity( schema=schema, collect_date=t_a, state=default_state) entity_a_3 = datastore.Entity( schema=schema, collect_date=t_a, state=default_state) list(map(visit_a.entities.add, [entity_a_1, entity_a_2, entity_a_3])) dbsession.add_all([visit_a, study]) dbsession.flush() req.json_body = { 'forms': [entity_a_2.id, entity_a_3.id] } res = self._call_fut(visit_a['forms'], req) # refresh the session so we can get a correct listing dbsession.expunge_all() visit_a = dbsession.query(models.Visit).get(visit_a.id) assert isinstance(res, HTTPOk) assert sorted([e.id for e in [entity_a_1]]) == \ sorted([e.id for e in visit_a.entities])
def test_cascade_forms(self, req, dbsession, check_csrf_token): """ It should remove all visit-associated forms. """ from datetime import date from occams import models as datastore from occams import models schema = datastore.Schema( name=u'sample', title=u'Some Sample', publish_date=date.today()) study = models.Study( name=u'somestudy', title=u'Some Study', short_title=u'sstudy', code=u'000', consent_date=date.today()) cycle = models.Cycle( name=u'week-10', title=u'Week 10', week=10) study.cycles.append(cycle) patient = models.Patient( site=models.Site(name=u'ucsd', title=u'UCSD'), pid=u'12345') enrollment = models.Enrollment( study=study, patient=patient, consent_date=date.today()) visit = models.Visit( patient=patient, cycles=[cycle], visit_date=date.today()) visit.entities.add(datastore.Entity( schema=schema, collect_date=date.today())) dbsession.add_all([patient, enrollment, study, visit]) dbsession.flush() visit_id = visit.id self._call_fut(visit, req) assert dbsession.query(models.Visit).get(visit_id) is None assert 0 == dbsession.query(datastore.Entity).count()
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 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', ) cycle = models.Cycle( name=u'TestView', title=u'TestView', week=39, study=study ) dbsession.add(study) dbsession.add(patient) dbsession.add(cycle)
def test_unique_cycle(self, req, dbsession, check_csrf_token): """ It should not allow repeat cycles (unless it's interim) """ from datetime import date, timedelta from pyramid.httpexceptions import HTTPBadRequest from occams import models study = models.Study( name=u'somestudy', title=u'Some Study', short_title=u'sstudy', code=u'000', consent_date=date.today()) cycle = models.Cycle(name='week-1', title=u'', week=1) study.cycles.append(cycle) patient = models.Patient( site=models.Site(name=u'ucsd', title=u'UCSD'), pid=u'12345') visit = models.Visit( patient=patient, cycles=[cycle], visit_date=date.today()) dbsession.add_all([patient, study, visit]) dbsession.flush() req.json_body = { 'cycles': [cycle.id], 'visit_date': str(date.today() + timedelta(days=1)) } with pytest.raises(HTTPBadRequest) as excinfo: self._call_fut(patient['visits'], req) assert 'already in use' in \ excinfo.value.json['errors']['cycles-0'].lower() # The exception is interims cycle.is_interim = True dbsession.flush() res = self._call_fut(patient['visits'], req) assert res is not None
def test_include_not_retracted_form( self, req, dbsession, check_csrf_token): """ It should not use retracted forms, even if there are the most recent """ from datetime import date, timedelta from occams import models as datastore from occams import models t0 = date.today() t1 = t0 + timedelta(days=1) t2 = t1 + timedelta(days=1) study = models.Study( name=u'somestudy', title=u'Some Study', short_title=u'sstudy', code=u'000', consent_date=date.today()) cycle1 = models.Cycle(name='week-1', title=u'', week=1) cycle1.schemata.update([ datastore.Schema(name='form1', title=u'', publish_date=t0), datastore.Schema(name='form1', title=u'', publish_date=t2, retract_date=t2)]) study.cycles.append(cycle1) patient = models.Patient( site=models.Site(name=u'ucsd', title=u'UCSD'), pid=u'12345') dbsession.add_all([patient, study]) dbsession.flush() req.json_body = { 'cycles': [cycle1.id], 'visit_date': str(t2), 'include_forms': True } res = self._call_fut(patient['visits'], req) assert 1 == len(res['entities']) assert str(t0) == res['entities'][0]['schema']['publish_date']
def test_cycle_in_study(self, req, dbsession, check_csrf_token): """ It should fail if the cycle is not part of the study """ from datetime import date from pyramid.httpexceptions import HTTPBadRequest from occams import models as datastore from occams import models schema = datastore.Schema(name='test', title=u'Test', publish_date=date.today()) other_cycle = models.Cycle(name=u'week-1', title=u'Title', week=1) other_study = models.Study(name=u'otherstudy', title=u'Other Study', short_title=u'ostudy', code=u'111', consent_date=date.today(), cycles=[other_cycle]) study = models.Study(name=u'somestudy', title=u'Some Study', short_title=u'sstudy', code=u'000', consent_date=date.today(), schemata=set([schema])) dbsession.add_all([study, schema, other_study]) dbsession.flush() req.json_body = { 'schema': schema.name, 'cycle': other_cycle.id, 'enabled': True } with pytest.raises(HTTPBadRequest) as excinfo: self._call_fut(study, req) assert 'not a valid choice' in \ excinfo.value.json['errors']['cycle'].lower()
def test_add_to_visit(self, req, dbsession): from datetime import date from occams import models schema = models.Schema(name=u'schema', title=u'Schema', publish_date=date.today()) study = models.Study(name='some-study', title=u'Some Study', short_title=u'sstudy', code=u'000', consent_date=date.today(), schemata=set([schema])) cycle = models.Cycle(study=study, name=u'cycle-1', title=u'Cycle') site = models.Site(name=u'somewhere', title=u'Somewhere') patient = models.Patient(pid=u'12345', site=site) visit = models.Visit(patient=patient, visit_date=date.today(), cycles=[cycle]) dbsession.add_all([study, patient, visit]) dbsession.flush() req.matchdict = {'patient': patient, 'visit': visit} req.json_body = { 'schema': schema.id, 'collect_date': str(date.today()), } factory = models.FormFactory(req) factory.__parent__ = visit self._call_fut(factory, req) contexts = dbsession.query(models.Context).all() assert len(contexts) == 2 assert sorted(['patient', 'visit']) == \ sorted([c.external for c in contexts])
def test_not_in_study(self, req, dbsession): """ It should fail if the form is not part of the study """ from datetime import date, timedelta from pyramid.httpexceptions import HTTPBadRequest from occams import models cycle = models.Cycle(name='week-1', title=u'', week=1) schema = models.Schema(name=u'sample', title=u'', publish_date=date.today()) study = models.Study(name=u'somestudy', title=u'Some Study', short_title=u'sstudy', code=u'000', consent_date=date.today(), cycles=[cycle]) site = models.Site(name=u'ucsd', title=u'UCSD') t_a = date.today() + timedelta(days=5) patient_a = models.Patient(site=site, pid=u'12345') visit_a = models.Visit(patient=patient_a, cycles=[cycle], visit_date=t_a) dbsession.add_all([schema, visit_a, study]) dbsession.flush() req.json_body = { 'schema': schema.id, } with pytest.raises(HTTPBadRequest) as excinfo: self._call_fut(visit_a['forms'], req) assert 'is not part of the studies' in \ excinfo.value.json['errors']['schema']
def test_has_visits(self, req, dbsession, config): """ It should not allow deletion of a cycle if it has visit (unless administrator) """ from datetime import date from pyramid.httpexceptions import HTTPForbidden from occams import models cycle = models.Cycle(name='week-1', title=u'Week 1', week=1) study = models.Study(name=u'somestudy', title=u'Some Study', short_title=u'sstudy', code=u'000', consent_date=date.today(), cycles=[cycle]) patient = models.Patient(site=models.Site(name='ucsd', title=u'UCSD'), pid=u'12345') enrollment = models.Enrollment(study=study, consent_date=date.today(), patient=patient) visit = models.Visit(patient=patient, visit_date=date.today(), cycles=[cycle]) dbsession.add_all([study, enrollment, visit]) dbsession.flush() # Should not be able to delete if not an admin config.testing_securitypolicy(permissive=False) with pytest.raises(HTTPForbidden): self._call_fut(cycle, req) config.testing_securitypolicy(permissive=True) self._call_fut(cycle, req) assert 0 == study.cycles.count()
def test_no_visit(self, req, dbsession): """ It should allow deleting of a cycle if it has no visits """ from datetime import date from occams import models cycle = models.Cycle(name='week-1', title=u'Week 1', week=1) study = models.Study(name=u'somestudy', title=u'Some Study', short_title=u'sstudy', code=u'000', consent_date=date.today(), cycles=[cycle]) dbsession.add_all([study]) dbsession.flush() self._call_fut(cycle, req) assert 0 == study.cycles.count()
def test_visit(self, dbsession): """ It should add visit-specific metadata to the report """ from datetime import date, timedelta from occams import models as datastore from occams import models from occams.exports.schema import SchemaPlan schema = datastore.Schema(name=u'vitals', title=u'Vitals', publish_date=date.today(), attributes={ 'foo': datastore.Attribute( name='foo', title=u'', type='string', order=0, ) }) entity = datastore.Entity(collect_date=date.today(), schema=schema) patient = models.Patient(site=models.Site(name='ucsd', title=u'UCSD'), pid=u'12345', entities=[entity]) visit = models.Visit( visit_date=date.today(), patient=patient, cycles=[ models.Cycle(name=u'study1-scr', title=u'Study 1 Screening', week=123, study=models.Study(name=u'study1', short_title=u'S1', code=u'001', consent_date=date.today() - timedelta(365), title=u'Study 1')), models.Cycle(name=u'study2-wk1', title=u'Study 2 Week 1', week=5858, study=models.Study(name=u'study21', short_title=u'S2', code=u'002', consent_date=date.today() - timedelta(365), title=u'Study 2')) ], entities=[entity]) dbsession.add_all([schema, entity, patient, visit]) dbsession.flush() plan = SchemaPlan.from_schema(dbsession, schema.name) codebook = list(plan.codebook()) query = plan.data() codebook_columns = [c['field'] for c in codebook] data_columns = [c['name'] for c in query.column_descriptions] record = query.one() assert sorted(codebook_columns) == sorted(data_columns) assert record.site == patient.site.name assert record.pid == patient.pid assert record.enrollment is None cyclefmt = '{cycle.study.title}({cycle.week})' assert sorted(record.visit_cycles.split(';')) == \ sorted([cyclefmt.format(cycle=c) for c in visit.cycles]) assert str(record.visit_id) == str(visit.id) assert record.collect_date == entity.collect_date
def test_include_forms(self, req, dbsession, check_csrf_token): """ It should allow the user to create cycle forms """ from datetime import date, timedelta from occams import models as datastore from occams import models form1 = datastore.Schema( name='form1', title=u'', publish_date=date.today()) form2 = datastore.Schema( name='form2', title=u'', publish_date=date.today()) study = models.Study( name=u'somestudy', title=u'Some Study', short_title=u'sstudy', code=u'000', consent_date=date.today()) cycle1 = models.Cycle(name='week-1', title=u'', week=1) cycle1.schemata.add(form1) cycle2 = models.Cycle(name='week-2', title=u'', week=2) cycle2.schemata.add(form2) study.cycles.append(cycle1) study.cycles.append(cycle2) patient = models.Patient( site=models.Site(name=u'ucsd', title=u'UCSD'), pid=u'12345') dbsession.add_all([patient, study]) dbsession.flush() req.json_body = { 'cycles': [cycle1.id], 'visit_date': str(date.today() + timedelta(days=1)), 'include_forms': True } res = self._call_fut(patient['visits'], req) assert ['form1'] == \ [e['schema']['name'] for e in res['entities']] contexts = dbsession.query(datastore.Context).all() assert sorted(['patient', 'visit']) == \ sorted([c.external for c in contexts]) visit = dbsession.query(models.Visit).get(res['id']) # Update to demonstrate forms can still be added on edit req.json_body = { 'cycles': [cycle1.id, cycle2.id], 'visit_date': str(date.today() + timedelta(days=1)), 'include_forms': True } res = self._call_fut(visit, req) assert sorted(['form1', 'form2']) == \ sorted([e['schema']['name'] for e in res['entities']]) contexts = dbsession.query(datastore.Context).all() assert sorted([(x, e['id']) for e in res['entities'] for x in ('patient', 'visit')]) == \ sorted([(c.external, c.entity_id) for c in contexts])