1 from __future__ import absolute_import, print_function, unicode_literals
4 from lxml.html import fromstring
9 from six.moves.urllib.parse import urljoin
11 from django.conf import settings
12 from django.core import mail
13 from django.core.exceptions import ObjectDoesNotExist
14 from django.core.urlresolvers import reverse
15 from django.test import TestCase
16 from django.utils.encoding import smart_text, smart_bytes
18 from .models import SequencingRun, Sequencer, FlowCell, FileType
19 from samples.models import HTSUser
20 from .experiments import flowcell_information, lanes_for
21 from .experiments_factory import FlowCellFactory, LaneFactory
22 from samples.samples_factory import AffiliationFactory, HTSUserFactory, \
23 LibraryFactory, LibraryTypeFactory, MultiplexIndexFactory
24 from htsworkflow.auth import apidata
25 from htsworkflow.util.ethelp import validate_xhtml
27 from htsworkflow.pipelines.test.simulate_runfolder import TESTDATA_DIR
29 LANE_SET = range(1, 9)
31 NSMAP = {'libns': 'http://jumpgate.caltech.edu/wiki/LibraryOntology#'}
34 class ExperimentsTestCases(TestCase):
36 # Generate at least one fleshed out example flowcell
37 self.tempdir = tempfile.mkdtemp(prefix='htsw-test-experiments-')
38 settings.RESULT_HOME_DIR = self.tempdir
40 self.password = 'password'
41 self.user_odd = HTSUserFactory(username='user-odd')
42 self.user_odd.set_password(self.password)
43 self.affiliation_odd = AffiliationFactory(name='affiliation-odd', users=[self.user_odd])
44 self.user_even = HTSUserFactory(username='user-even')
45 self.user_even.set_password(self.password)
46 self.affiliation_even = AffiliationFactory(name='affiliation-even', users=[self.user_even])
47 self.admin = HTSUserFactory.create(username='admin', is_staff=True, is_superuser=True)
48 self.admin.set_password(self.password)
51 self.fc12150 = FlowCellFactory(flowcell_id='FC12150')
52 self.fc1_id = 'FC12150'
53 self.fc1_root = os.path.join(self.tempdir, self.fc1_id)
54 os.mkdir(self.fc1_root)
55 self.fc1_dir = os.path.join(self.fc1_root, 'C1-37')
56 os.mkdir(self.fc1_dir)
57 runxml = 'run_FC12150_2007-09-27.xml'
58 shutil.copy(os.path.join(TESTDATA_DIR, runxml),
59 os.path.join(self.fc1_dir, runxml))
61 affiliation = self.affiliation_odd if i % 2 == 1 else self.affiliation_even
62 library = LibraryFactory(id="1215" + str(i))
63 library.affiliations.add(affiliation)
64 lane = LaneFactory(flowcell=self.fc12150, lane_number=i, library=library)
66 os.path.join(TESTDATA_DIR,
67 'woldlab_070829_USI-EAS44_0017_FC11055_1.srf'),
68 os.path.join(self.fc1_dir,
69 'woldlab_070829_SERIAL_FC12150_%d.srf' %(i,))
73 self.fc42jtn = FlowCellFactory(flowcell_id='42JTNAAXX')
74 self.fc42jtn_lanes = []
76 affiliation = self.affiliation_odd if i % 2 == 1 else self.affiliation_even
77 library_type = LibraryTypeFactory(can_multiplex=True)
78 multiplex_index = MultiplexIndexFactory(adapter_type=library_type)
79 library = LibraryFactory(id="1300" + str(i),
80 library_type=library_type,
81 multiplex_id=multiplex_index.multiplex_id)
82 library.affiliations.add(affiliation)
83 lane = LaneFactory(flowcell=self.fc42jtn, lane_number=(i % 2) + 1, library=library)
84 self.fc42jtn_lanes.append(lane)
86 self.fc2_dir = os.path.join(self.tempdir, '42JTNAAXX')
87 os.mkdir(self.fc2_dir)
88 os.mkdir(os.path.join(self.fc2_dir, 'C1-25'))
89 os.mkdir(os.path.join(self.fc2_dir, 'C1-37'))
90 os.mkdir(os.path.join(self.fc2_dir, 'C1-37', 'Plots'))
93 shutil.rmtree(self.tempdir)
94 self.user_odd.delete()
95 self.user_even.delete()
98 def test_flowcell_information(self):
100 Check the code that packs the django objects into simple types.
102 fc12150 = self.fc12150
103 fc42jtn = self.fc42jtn
104 fc42ju1 = FlowCellFactory(flowcell_id='42JU1AAXX')
106 for fc_id in ['FC12150', '42JTNAAXX', '42JU1AAXX']:
107 fc_dict = flowcell_information(fc_id)
108 fc_django = FlowCell.objects.get(flowcell_id=fc_id)
109 self.assertEqual(fc_dict['flowcell_id'], fc_id)
110 self.assertEqual(fc_django.flowcell_id, fc_id)
111 self.assertEqual(fc_dict['sequencer'], fc_django.sequencer.name)
112 self.assertEqual(fc_dict['read_length'], fc_django.read_length)
113 self.assertEqual(fc_dict['notes'], fc_django.notes)
114 self.assertEqual(fc_dict['cluster_station'], fc_django.cluster_station.name)
116 for lane in fc_django.lane_set.all():
117 lane_contents = fc_dict['lane_set'][lane.lane_number]
118 lane_dict = multi_lane_to_dict(lane_contents)[lane.library_id]
119 self.assertEqual(lane_dict['cluster_estimate'], lane.cluster_estimate)
120 self.assertEqual(lane_dict['comment'], lane.comment)
121 self.assertEqual(lane_dict['flowcell'], lane.flowcell.flowcell_id)
122 self.assertEqual(lane_dict['lane_number'], lane.lane_number)
123 self.assertEqual(lane_dict['library_name'], lane.library.library_name)
124 self.assertEqual(lane_dict['library_id'], lane.library.id)
125 self.assertAlmostEqual(float(lane_dict['pM']), float(lane.pM))
126 self.assertEqual(lane_dict['library_species'],
127 lane.library.library_species.scientific_name)
129 response = self.client.get('/experiments/config/%s/json' % (fc_id,), apidata)
130 # strptime isoformat string = '%Y-%m-%dT%H:%M:%S'
131 fc_json = json.loads(smart_text(response.content))['result']
132 self.assertEqual(fc_json['flowcell_id'], fc_id)
133 self.assertEqual(fc_json['sequencer'], fc_django.sequencer.name)
134 self.assertEqual(fc_json['read_length'], fc_django.read_length)
135 self.assertEqual(fc_json['notes'], fc_django.notes)
136 self.assertEqual(fc_json['cluster_station'], fc_django.cluster_station.name)
139 for lane in fc_django.lane_set.all():
140 lane_contents = fc_json['lane_set'][str(lane.lane_number)]
141 lane_dict = multi_lane_to_dict(lane_contents)[lane.library_id]
143 self.assertEqual(lane_dict['cluster_estimate'], lane.cluster_estimate)
144 self.assertEqual(lane_dict['comment'], lane.comment)
145 self.assertEqual(lane_dict['flowcell'], lane.flowcell.flowcell_id)
146 self.assertEqual(lane_dict['lane_number'], lane.lane_number)
147 self.assertEqual(lane_dict['library_name'], lane.library.library_name)
148 self.assertEqual(lane_dict['library_id'], lane.library.id)
149 self.assertAlmostEqual(float(lane_dict['pM']), float(lane.pM))
150 self.assertEqual(lane_dict['library_species'],
151 lane.library.library_species.scientific_name)
153 def test_invalid_flowcell(self):
155 Make sure we get a 404 if we request an invalid flowcell ID
157 response = self.client.get('/experiments/config/nottheone/json', apidata)
158 self.assertEqual(response.status_code, 404)
160 def test_no_key(self):
162 Require logging in to retrieve meta data
164 response = self.client.get('/experiments/config/FC12150/json')
165 self.assertEqual(response.status_code, 403)
167 def test_library_id(self):
168 """make sure we can retrive a non-numeric library ID
170 response = self.client.get('/experiments/config/FC12150/json', apidata)
171 self.assertEqual(response.status_code, 200)
172 flowcell = json.loads(smart_text(response.content))['result']
174 # library id is 12150 + lane number (1-8), so 12153
175 lane_contents = flowcell['lane_set']['3']
176 lane_library = lane_contents[0]
177 self.assertEqual(lane_library['library_id'], '12153')
179 response = self.client.get('/samples/library/12153/json', apidata)
180 self.assertEqual(response.status_code, 200)
181 library_12153 = json.loads(smart_text(response.content))['result']
183 self.assertEqual(library_12153['library_id'], '12153')
185 def test_raw_id_field(self):
188 Library's have IDs, libraries also have primary keys,
189 we eventually had enough libraries that the drop down combo
190 box was too hard to filter through, unfortnately we want a
191 field that uses our library id and not the internal
192 primary key, and raw_id_field uses primary keys.
194 This tests to make sure that the value entered in the raw
195 library id field matches the library id looked up.
198 expected_ids = ['1215{}'.format(i) for i in range(1, 9)]
199 self.assertTrue(self.client.login(username=self.admin.username, password=self.password))
200 response = self.client.get(
201 '/admin/experiments/flowcell/{}/change/'.format(self.fc12150.id),
203 self.assertEquals(response.status_code, 200)
205 tree = fromstring(response.content)
206 for i in range(0, 8):
207 xpath_expression = '//input[@id="id_lane_set-%d-library"]'
208 input_field = tree.xpath(xpath_expression % (i,))[0]
209 library_field = input_field.find('../strong')
210 library_id, library_name = library_field.text.split(':')
211 # strip leading '#' sign from name
212 library_id = library_id[1:]
213 self.assertEqual(library_id, expected_ids[i])
214 self.assertEqual(input_field.attrib['value'], library_id)
216 def test_library_to_flowcell_link(self):
218 Make sure the library page includes links to the flowcell pages.
219 That work with flowcell IDs that have parenthetical comments.
221 self.assertTrue(self.client.login(username=self.admin.username, password=self.password))
222 response = self.client.get('/library/12151/')
223 self.assertEqual(response.status_code, 200)
224 status = validate_xhtml(response.content)
225 if status is not None:
226 self.assertTrue(status)
228 tree = fromstring(response.content)
229 flowcell_spans = tree.xpath('//span[@property="libns:flowcell_id"]',
231 self.assertEqual(flowcell_spans[1].text, 'FC12150')
232 failed_fc_span = flowcell_spans[1]
233 failed_fc_a = failed_fc_span.getparent()
234 # make sure some of our RDF made it.
235 self.assertEqual(failed_fc_a.get('typeof'), 'libns:IlluminaFlowcell')
236 self.assertEqual(failed_fc_a.get('href'), '/flowcell/FC12150/')
237 fc_response = self.client.get(failed_fc_a.get('href'))
238 self.assertEqual(fc_response.status_code, 200)
239 status = validate_xhtml(response.content)
240 if status is not None: self.assertTrue(status)
242 fc_lane_response = self.client.get('/flowcell/FC12150/8/')
243 self.assertEqual(fc_lane_response.status_code, 200)
244 status = validate_xhtml(response.content)
245 if status is not None: self.assertTrue(status)
247 def test_pooled_multiplex_id(self):
248 fc_dict = flowcell_information(self.fc42jtn.flowcell_id)
250 lane_contents = fc_dict['lane_set'][2]
251 self.assertEqual(len(lane_contents), len(self.fc42jtn_lanes) / 2)
252 lane_dict = multi_lane_to_dict(lane_contents)
254 self.assertTrue(self.fc42jtn_lanes[0].library.multiplex_id in \
255 lane_dict['13001']['index_sequence'])
256 self.assertTrue(self.fc42jtn_lanes[2].library.multiplex_id in \
257 lane_dict['13003']['index_sequence'])
260 def test_lanes_for_view_user_odd(self):
261 """Make sure lanes_for HTML UI works.
263 user = self.user_odd.username
264 lanes = lanes_for(user)
265 self.assertEqual(len(lanes), 8)
267 response = self.client.get(
268 reverse('lanes_for', kwargs={'username': user}))
269 self.assertEqual(response.status_code, 200)
270 tree = fromstring(response.content)
271 lane_trs = tree.xpath('//div[@id="changelist"]/table/tbody/tr')
272 self.assertEqual(len(lane_trs), len(lanes))
273 # lanes is in db order
274 # lane_trs is in newest to oldest order
275 for lane_tr, lane_db in zip(lane_trs, lanes):
276 library_id = lane_tr.xpath('td[6]/a')[0].text
277 self.assertEqual(library_id, lane_db['library'])
279 def test_lanes_for_view_invalid_user(self):
280 """Make sure we don't find anything with an invalid user
282 response = self.client.get(
283 reverse('lanes_for', kwargs={'username': 'doesntexist'}))
284 self.assertEqual(response.status_code, 404)
286 def test_lanes_for_json(self):
288 Check the code that packs the django objects into simple types.
290 user = self.user_odd.username
291 lanes = lanes_for(user)
292 self.assertEqual(len(lanes), 8)
294 response = self.client.get('/experiments/lanes_for/%s/json' % (user,), apidata)
295 lanes_json = json.loads(smart_text(response.content))['result']
296 self.assertEqual(len(lanes), len(lanes_json))
297 for i in range(len(lanes)):
298 self.assertEqual(lanes[i]['comment'], lanes_json[i]['comment'])
299 self.assertEqual(lanes[i]['lane_number'], lanes_json[i]['lane_number'])
300 self.assertEqual(lanes[i]['flowcell'], lanes_json[i]['flowcell'])
301 self.assertEqual(lanes[i]['run_date'], lanes_json[i]['run_date'])
303 def test_lanes_for_no_lanes(self):
305 Do we get something meaningful back when the user isn't attached to anything?
307 user = HTSUserFactory.create(username='supertest')
308 lanes = lanes_for(user.username)
309 self.assertEqual(len(lanes), 0)
311 response = self.client.get('/experiments/lanes_for/%s/json' % (user,), apidata)
312 self.assertEqual(response.status_code, 404)
314 def test_lanes_for_no_user(self):
316 Do we get something meaningful back when its the wrong user
318 user = 'not a real user'
319 self.assertRaises(ObjectDoesNotExist, lanes_for, user)
321 response = self.client.get('/experiments/lanes_for/%s/json' % (user,), apidata)
322 self.assertEqual(response.status_code, 404)
324 def test_raw_data_dir(self):
325 """Raw data path generator check"""
326 flowcell_id = self.fc1_id
327 raw_dir = os.path.join(settings.RESULT_HOME_DIR, flowcell_id)
329 fc = FlowCell.objects.get(flowcell_id=flowcell_id)
330 self.assertEqual(fc.get_raw_data_directory(), raw_dir)
332 fc.flowcell_id = flowcell_id + " (failed)"
333 self.assertEqual(fc.get_raw_data_directory(), raw_dir)
335 def test_sequencing_run_import(self):
336 srf_file_type = FileType.objects.get(name='SRF')
337 runxml_file_type = FileType.objects.get(name='run_xml')
338 flowcell_id = self.fc1_id
339 flowcell = FlowCell.objects.get(flowcell_id=flowcell_id)
340 flowcell.update_sequencing_runs()
341 self.assertEqual(len(flowcell.sequencingrun_set.all()), 1)
343 run = flowcell.sequencingrun_set.all()[0]
344 result_files = run.datafile_set.all()
345 result_dict = dict(((rf.relative_pathname, rf) for rf in result_files))
347 srf4 = result_dict['FC12150/C1-37/woldlab_070829_SERIAL_FC12150_4.srf']
348 self.assertEqual(srf4.file_type, srf_file_type)
349 self.assertEqual(srf4.library_id, '12154')
350 self.assertEqual(srf4.sequencing_run.flowcell.flowcell_id, 'FC12150')
352 srf4.sequencing_run.flowcell.lane_set.get(lane_number=4).library_id,
356 os.path.join(settings.RESULT_HOME_DIR, srf4.relative_pathname))
358 lane_files = run.lane_files()
359 self.assertEqual(lane_files[4]['srf'], srf4)
361 runxml= result_dict['FC12150/C1-37/run_FC12150_2007-09-27.xml']
362 self.assertEqual(runxml.file_type, runxml_file_type)
363 self.assertEqual(runxml.library_id, None)
365 import1 = len(SequencingRun.objects.filter(result_dir='FC12150/C1-37'))
366 # what happens if we import twice?
367 flowcell.import_sequencing_run('FC12150/C1-37',
368 'run_FC12150_2007-09-27.xml')
370 len(SequencingRun.objects.filter(result_dir='FC12150/C1-37')),
373 def test_read_result_file(self):
374 """make sure we can return a result file
376 flowcell_id = self.fc1_id
377 flowcell = FlowCell.objects.get(flowcell_id=flowcell_id)
378 flowcell.update_sequencing_runs()
380 #self.client.login(username='supertest', password='BJOKL5kAj6aFZ6A5')
382 result_files = flowcell.sequencingrun_set.all()[0].datafile_set.all()
383 for f in result_files:
384 url = '/experiments/file/%s' % ( f.random_key,)
385 response = self.client.get(url)
386 self.assertEqual(response.status_code, 200)
387 mimetype = f.file_type.mimetype
389 mimetype = 'application/octet-stream'
391 self.assertEqual(mimetype, response['content-type'])
393 def test_flowcell_rdf(self):
395 from htsworkflow.util.rdfhelp import get_model, \
397 load_string_into_model, \
404 expected = {'1': ['12151'],
412 url = '/flowcell/{}/'.format(self.fc12150.flowcell_id)
413 response = self.client.get(url)
414 self.assertEqual(response.status_code, 200)
415 status = validate_xhtml(response.content)
416 if status is not None: self.assertTrue(status)
418 ns = urljoin('http://localhost', url)
419 load_string_into_model(model, 'rdfa', smart_text(response.content), ns=ns)
420 body = """prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
421 prefix libns: <http://jumpgate.caltech.edu/wiki/LibraryOntology#>
423 select ?flowcell ?flowcell_id ?lane_id ?library_id
425 ?flowcell a libns:IlluminaFlowcell ;
426 libns:flowcell_id ?flowcell_id ;
427 libns:has_lane ?lane .
428 ?lane libns:lane_number ?lane_id ;
429 libns:library ?library .
430 ?library libns:library_id ?library_id .
432 query = RDF.SPARQLQuery(body)
434 for r in query.execute(model):
436 self.assertEqual(fromTypedNode(r['flowcell_id']), 'FC12150')
437 lane_id = fromTypedNode(r['lane_id'])
438 library_id = fromTypedNode(r['library_id'])
439 self.assertTrue(library_id in expected[lane_id])
440 self.assertEqual(count, 8)
442 class TestEmailNotify(TestCase):
444 self.password = 'foo27'
445 self.user = HTSUserFactory.create(username='test')
446 self.user.set_password(self.password)
448 self.admin = HTSUserFactory.create(username='admintest', is_staff=True)
449 self.admin.set_password(self.password)
451 self.superuser = HTSUserFactory.create(username='supertest', is_staff=True, is_superuser=True)
452 self.superuser.set_password(self.password)
453 self.superuser.save()
455 self.library = LibraryFactory.create()
456 self.affiliation = AffiliationFactory()
457 self.affiliation.users.add(self.user)
458 self.library.affiliations.add(self.affiliation)
459 self.fc = FlowCellFactory.create()
460 self.lane = LaneFactory(flowcell=self.fc, lane_number=1, library=self.library)
462 self.url = '/experiments/started/{}/'.format(self.fc.id)
465 # with django 1.10 running against postgresql I had to delete these
466 # test objects or else I get a constraint error
467 self.affiliation.delete()
470 self.superuser.delete()
472 def test_started_email_not_logged_in(self):
473 response = self.client.get(self.url)
474 self.assertEqual(response.status_code, 302)
476 def test_started_email_logged_in_user(self):
477 self.assertTrue(self.client.login(username=self.user.username, password=self.password))
478 response = self.client.get(self.url)
479 self.assertEqual(response.status_code, 302)
481 def test_started_email_logged_in_staff(self):
482 self.assertTrue(self.admin.is_staff)
483 admin = HTSUser.objects.get(username=self.admin.username)
484 self.assertTrue(admin.is_staff)
485 self.assertTrue(admin.check_password(self.password))
486 self.assertTrue(self.client.login(username=self.admin.username, password=self.password))
487 response = self.client.get(self.url)
488 self.assertEqual(response.status_code, 200)
490 def test_started_email_send(self):
491 self.assertTrue(self.client.login(username=self.admin.username, password=self.password))
492 response = self.client.get(self.url)
493 self.assertEqual(response.status_code, 200)
495 self.assertTrue(self.affiliation.email in smart_text(response.content))
496 self.assertTrue(self.library.library_name in smart_text(response.content))
498 response = self.client.get(self.url, {'send': '1', 'bcc': 'on'})
499 self.assertEqual(response.status_code, 200)
500 self.assertEqual(len(mail.outbox), 2)
501 bcc = set(settings.NOTIFICATION_BCC).copy()
502 bcc.update(set(settings.MANAGERS))
503 for m in mail.outbox:
504 self.assertTrue(len(m.body) > 0)
505 self.assertEqual(set(m.bcc), bcc)
507 def test_email_navigation(self):
509 Can we navigate between the flowcell and email forms properly?
511 admin_url = '/admin/experiments/flowcell/{}/change/'.format(self.fc.id)
512 self.client.login(username=self.admin.username, password=self.password)
513 response = self.client.get(self.url)
514 self.assertEqual(response.status_code, 200)
515 self.assertTrue(re.search(self.fc.flowcell_id, smart_text(response.content)))
516 # require that navigation back to the admin page exists
517 admin_a_tag = '<a href="{}">[^<]+</a>'.format(admin_url)
518 self.assertTrue(re.search(admin_a_tag, smart_text(response.content)))
520 def multi_lane_to_dict(lane):
521 """Convert a list of lane entries into a dictionary indexed by library ID
523 return dict( ((x['library_id'],x) for x in lane) )
525 class TestSequencer(TestCase):
527 self.fc12150 = FlowCellFactory(flowcell_id='FC12150')
528 self.library = LibraryFactory(id="12150")
529 self.lane = LaneFactory(flowcell=self.fc12150, lane_number=1, library=self.library)
531 def test_name_generation(self):
534 seq.instrument_name = "HWI-SEQ1"
535 seq.model = "Imaginary 5000"
537 self.assertEqual(str(seq), "Seq1 (HWI-SEQ1)")
539 def test_lookup(self):
541 self.assertEqual(fc.sequencer.model, 'HiSeq 1')
542 self.assertTrue(fc.sequencer.instrument_name.startswith('instrument name')),
543 # well actually we let the browser tack on the host name
544 url = fc.get_absolute_url()
545 self.assertEqual(url, '/flowcell/FC12150/')
548 response = self.client.get('/flowcell/FC12150/', apidata)
549 tree = fromstring(response.content)
550 seq_by = tree.xpath('//div[@rel="libns:sequenced_by"]',
552 self.assertEqual(len(seq_by), 1)
553 self.assertEqual(seq_by[0].attrib['rel'], 'libns:sequenced_by')
554 seq = seq_by[0].getchildren()
555 self.assertEqual(len(seq), 1)
556 sequencer = '/sequencer/' + str(self.fc12150.sequencer.id)
557 self.assertEqual(seq[0].attrib['about'], sequencer)
558 self.assertEqual(seq[0].attrib['typeof'], 'libns:Sequencer')
560 name = seq[0].xpath('./span[@property="libns:sequencer_name"]')
561 self.assertEqual(len(name), 1)
562 self.assertTrue(name[0].text.startswith('sequencer '))
563 instrument = seq[0].xpath(
564 './span[@property="libns:sequencer_instrument"]')
565 self.assertEqual(len(instrument), 1)
566 self.assertTrue(instrument[0].text.startswith('instrument name'))
567 model = seq[0].xpath(
568 './span[@property="libns:sequencer_model"]')
569 self.assertEqual(len(model), 1)
570 self.assertEqual(model[0].text, 'HiSeq 1')
572 def test_flowcell_with_rdf_validation(self):
573 from htsworkflow.util.rdfhelp import add_default_schemas, \
576 load_string_into_model
577 from htsworkflow.util.rdfinfer import Infer
580 add_default_schemas(model)
581 inference = Infer(model)
583 url ='/flowcell/FC12150/'
584 response = self.client.get(url)
585 self.assertEqual(response.status_code, 200)
586 status = validate_xhtml(response.content)
587 if status is not None:
588 self.assertTrue(status)
590 load_string_into_model(model, 'rdfa', smart_text(response.content))
592 errmsgs = list(inference.run_validation())
593 self.assertEqual(len(errmsgs), 0)
595 def test_lane_with_rdf_validation(self):
596 from htsworkflow.util.rdfhelp import add_default_schemas, \
599 load_string_into_model
600 from htsworkflow.util.rdfinfer import Infer
603 add_default_schemas(model)
604 inference = Infer(model)
606 url = '/lane/{}'.format(self.lane.id)
607 response = self.client.get(url)
608 self.assertEqual(response.status_code, 200)
609 status = validate_xhtml(smart_bytes(response.content))
610 if status is not None:
611 self.assertTrue(status)
613 load_string_into_model(model, 'rdfa', smart_text(response.content))
615 errmsgs = list(inference.run_validation())
616 self.assertEqual(len(errmsgs), 0)
619 from unittest import TestSuite, defaultTestLoader
621 for testcase in [ExerimentsTestCases,
624 suite.addTests(defaultTestLoader.loadTestsFromTestCase(testcase))
627 if __name__ == "__main__":
628 from unittest import main
629 main(defaultTest="suite")