1 from __future__ import absolute_import, print_function, unicode_literals
4 from lxml.html import fromstring
10 from six.moves.urllib.parse import urljoin
12 from django.conf import settings
13 from django.core import mail
14 from django.core.exceptions import ObjectDoesNotExist
15 from django.test import TestCase
16 from django.test.utils import setup_test_environment, teardown_test_environment
17 from django.db import connection
18 from django.conf import settings
19 from django.utils.encoding import smart_text
21 from .models import ClusterStation, cluster_station_default, \
22 DataRun, Sequencer, FlowCell, FileType
23 from samples.models import HTSUser
24 from .experiments import flowcell_information, lanes_for
25 from .experiments_factory import ClusterStationFactory, FlowCellFactory, LaneFactory
26 from samples.samples_factory import AffiliationFactory, HTSUserFactory, \
27 LibraryFactory, LibraryTypeFactory, MultiplexIndexFactory
28 from htsworkflow.auth import apidata
29 from htsworkflow.util.ethelp import validate_xhtml
31 from htsworkflow.pipelines.test.simulate_runfolder import TESTDATA_DIR
33 LANE_SET = range(1, 9)
35 NSMAP = {'libns': 'http://jumpgate.caltech.edu/wiki/LibraryOntology#'}
37 from django.db import connection
40 class ExperimentsTestCases(TestCase):
42 # Generate at least one fleshed out example flowcell
43 self.tempdir = tempfile.mkdtemp(prefix='htsw-test-experiments-')
44 settings.RESULT_HOME_DIR = self.tempdir
46 self.password = 'password'
47 self.user_odd = HTSUserFactory(username='user-odd')
48 self.user_odd.set_password(self.password)
49 self.affiliation_odd = AffiliationFactory(name='affiliation-odd', users=[self.user_odd])
50 self.user_even = HTSUserFactory(username='user-even')
51 self.user_even.set_password(self.password)
52 self.affiliation_even = AffiliationFactory(name='affiliation-even', users=[self.user_even])
53 self.admin = HTSUserFactory.create(username='admin', is_staff=True, is_superuser=True)
54 self.admin.set_password(self.password)
57 self.fc12150 = FlowCellFactory(flowcell_id='FC12150')
58 self.fc1_id = 'FC12150'
59 self.fc1_root = os.path.join(self.tempdir, self.fc1_id)
60 os.mkdir(self.fc1_root)
61 self.fc1_dir = os.path.join(self.fc1_root, 'C1-37')
62 os.mkdir(self.fc1_dir)
63 runxml = 'run_FC12150_2007-09-27.xml'
64 shutil.copy(os.path.join(TESTDATA_DIR, runxml),
65 os.path.join(self.fc1_dir, runxml))
67 affiliation = self.affiliation_odd if i % 2 == 1 else self.affiliation_even
68 library = LibraryFactory(id="1215" + str(i))
69 library.affiliations.add(affiliation)
70 lane = LaneFactory(flowcell=self.fc12150, lane_number=i, library=library)
72 os.path.join(TESTDATA_DIR,
73 'woldlab_070829_USI-EAS44_0017_FC11055_1.srf'),
74 os.path.join(self.fc1_dir,
75 'woldlab_070829_SERIAL_FC12150_%d.srf' %(i,))
79 self.fc42jtn = FlowCellFactory(flowcell_id='42JTNAAXX')
80 self.fc42jtn_lanes = []
82 affiliation = self.affiliation_odd if i % 2 == 1 else self.affiliation_even
83 library_type = LibraryTypeFactory(can_multiplex=True)
84 multiplex_index = MultiplexIndexFactory(adapter_type=library_type)
85 library = LibraryFactory(id="1300" + str(i),
86 library_type=library_type,
87 multiplex_id=multiplex_index.multiplex_id)
88 library.affiliations.add(affiliation)
89 lane = LaneFactory(flowcell=self.fc42jtn, lane_number=(i % 2) + 1, library=library)
90 self.fc42jtn_lanes.append(lane)
92 self.fc2_dir = os.path.join(self.tempdir, '42JTNAAXX')
93 os.mkdir(self.fc2_dir)
94 os.mkdir(os.path.join(self.fc2_dir, 'C1-25'))
95 os.mkdir(os.path.join(self.fc2_dir, 'C1-37'))
96 os.mkdir(os.path.join(self.fc2_dir, 'C1-37', 'Plots'))
99 shutil.rmtree(self.tempdir)
101 def test_flowcell_information(self):
103 Check the code that packs the django objects into simple types.
105 fc12150 = self.fc12150
106 fc42jtn = self.fc42jtn
107 fc42ju1 = FlowCellFactory(flowcell_id='42JU1AAXX')
109 for fc_id in ['FC12150', '42JTNAAXX', '42JU1AAXX']:
110 fc_dict = flowcell_information(fc_id)
111 fc_django = FlowCell.objects.get(flowcell_id=fc_id)
112 self.assertEqual(fc_dict['flowcell_id'], fc_id)
113 self.assertEqual(fc_django.flowcell_id, fc_id)
114 self.assertEqual(fc_dict['sequencer'], fc_django.sequencer.name)
115 self.assertEqual(fc_dict['read_length'], fc_django.read_length)
116 self.assertEqual(fc_dict['notes'], fc_django.notes)
117 self.assertEqual(fc_dict['cluster_station'], fc_django.cluster_station.name)
119 for lane in fc_django.lane_set.all():
120 lane_contents = fc_dict['lane_set'][lane.lane_number]
121 lane_dict = multi_lane_to_dict(lane_contents)[lane.library_id]
122 self.assertEqual(lane_dict['cluster_estimate'], lane.cluster_estimate)
123 self.assertEqual(lane_dict['comment'], lane.comment)
124 self.assertEqual(lane_dict['flowcell'], lane.flowcell.flowcell_id)
125 self.assertEqual(lane_dict['lane_number'], lane.lane_number)
126 self.assertEqual(lane_dict['library_name'], lane.library.library_name)
127 self.assertEqual(lane_dict['library_id'], lane.library.id)
128 self.assertAlmostEqual(float(lane_dict['pM']), float(lane.pM))
129 self.assertEqual(lane_dict['library_species'],
130 lane.library.library_species.scientific_name)
132 response = self.client.get('/experiments/config/%s/json' % (fc_id,), apidata)
133 # strptime isoformat string = '%Y-%m-%dT%H:%M:%S'
134 fc_json = json.loads(smart_text(response.content))['result']
135 self.assertEqual(fc_json['flowcell_id'], fc_id)
136 self.assertEqual(fc_json['sequencer'], fc_django.sequencer.name)
137 self.assertEqual(fc_json['read_length'], fc_django.read_length)
138 self.assertEqual(fc_json['notes'], fc_django.notes)
139 self.assertEqual(fc_json['cluster_station'], fc_django.cluster_station.name)
142 for lane in fc_django.lane_set.all():
143 lane_contents = fc_json['lane_set'][str(lane.lane_number)]
144 lane_dict = multi_lane_to_dict(lane_contents)[lane.library_id]
146 self.assertEqual(lane_dict['cluster_estimate'], lane.cluster_estimate)
147 self.assertEqual(lane_dict['comment'], lane.comment)
148 self.assertEqual(lane_dict['flowcell'], lane.flowcell.flowcell_id)
149 self.assertEqual(lane_dict['lane_number'], lane.lane_number)
150 self.assertEqual(lane_dict['library_name'], lane.library.library_name)
151 self.assertEqual(lane_dict['library_id'], lane.library.id)
152 self.assertAlmostEqual(float(lane_dict['pM']), float(lane.pM))
153 self.assertEqual(lane_dict['library_species'],
154 lane.library.library_species.scientific_name)
156 def test_invalid_flowcell(self):
158 Make sure we get a 404 if we request an invalid flowcell ID
160 response = self.client.get('/experiments/config/nottheone/json', apidata)
161 self.assertEqual(response.status_code, 404)
163 def test_no_key(self):
165 Require logging in to retrieve meta data
167 response = self.client.get('/experiments/config/FC12150/json')
168 self.assertEqual(response.status_code, 403)
170 def test_library_id(self):
172 Library IDs should be flexible, so make sure we can retrive a non-numeric ID
174 response = self.client.get('/experiments/config/FC12150/json', apidata)
175 self.assertEqual(response.status_code, 200)
176 flowcell = json.loads(smart_text(response.content))['result']
178 # library id is 12150 + lane number (1-8), so 12153
179 lane_contents = flowcell['lane_set']['3']
180 lane_library = lane_contents[0]
181 self.assertEqual(lane_library['library_id'], '12153')
183 response = self.client.get('/samples/library/12153/json', apidata)
184 self.assertEqual(response.status_code, 200)
185 library_12153 = json.loads(smart_text(response.content))['result']
187 self.assertEqual(library_12153['library_id'], '12153')
189 def test_raw_id_field(self):
192 Library's have IDs, libraries also have primary keys,
193 we eventually had enough libraries that the drop down combo
194 box was too hard to filter through, unfortnately we want a
195 field that uses our library id and not the internal
196 primary key, and raw_id_field uses primary keys.
198 This tests to make sure that the value entered in the raw
199 library id field matches the library id looked up.
202 expected_ids = [ '1215{}'.format(i) for i in range(1,9) ]
203 self.assertTrue(self.client.login(username=self.admin.username, password=self.password))
204 response = self.client.get('/admin/experiments/flowcell/{}/'.format(self.fc12150.id))
206 tree = fromstring(response.content)
208 xpath_expression = '//input[@id="id_lane_set-%d-library"]'
209 input_field = tree.xpath(xpath_expression % (i,))[0]
210 library_field = input_field.find('../strong')
211 library_id, library_name = library_field.text.split(':')
212 # strip leading '#' sign from name
213 library_id = library_id[1:]
214 self.assertEqual(library_id, expected_ids[i])
215 self.assertEqual(input_field.attrib['value'], library_id)
217 def test_library_to_flowcell_link(self):
219 Make sure the library page includes links to the flowcell pages.
220 That work with flowcell IDs that have parenthetical comments.
222 self.assertTrue(self.client.login(username=self.admin.username, password=self.password))
223 response = self.client.get('/library/12151/')
224 self.assertEqual(response.status_code, 200)
225 status = validate_xhtml(response.content)
226 if status is not None: 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('experiments.views.lanes_for',
270 self.assertEqual(response.status_code, 200)
271 tree = fromstring(response.content)
272 lane_trs = tree.xpath('//div[@id="changelist"]/table/tbody/tr')
273 self.assertEqual(len(lane_trs), len(lanes))
274 # lanes is in db order
275 # lane_trs is in newest to oldest order
276 for lane_tr, lane_db in zip(lane_trs, reversed(lanes)):
277 library_id = lane_tr.xpath('td[6]/a')[0].text
278 self.assertEqual(library_id, lane_db['library'])
280 def test_lanes_for_view_invalid_user(self):
281 """Make sure we don't find anything with an invalid user
283 response = self.client.get(
284 reverse('experiments.views.lanes_for',
285 args=["doesntexist"]))
286 self.assertEqual(response.status_code, 404)
288 def test_lanes_for_json(self):
290 Check the code that packs the django objects into simple types.
292 user = self.user_odd.username
293 lanes = lanes_for(user)
294 self.assertEqual(len(lanes), 8)
296 response = self.client.get('/experiments/lanes_for/%s/json' % (user,), apidata)
297 lanes_json = json.loads(smart_text(response.content))['result']
298 self.assertEqual(len(lanes), len(lanes_json))
299 for i in range(len(lanes)):
300 self.assertEqual(lanes[i]['comment'], lanes_json[i]['comment'])
301 self.assertEqual(lanes[i]['lane_number'], lanes_json[i]['lane_number'])
302 self.assertEqual(lanes[i]['flowcell'], lanes_json[i]['flowcell'])
303 self.assertEqual(lanes[i]['run_date'], lanes_json[i]['run_date'])
305 def test_lanes_for_no_lanes(self):
307 Do we get something meaningful back when the user isn't attached to anything?
309 user = HTSUserFactory.create(username='supertest')
310 lanes = lanes_for(user.username)
311 self.assertEqual(len(lanes), 0)
313 response = self.client.get('/experiments/lanes_for/%s/json' % (user,), apidata)
314 self.assertEqual(response.status_code, 404)
316 def test_lanes_for_no_user(self):
318 Do we get something meaningful back when its the wrong user
320 user = 'not a real user'
321 self.assertRaises(ObjectDoesNotExist, lanes_for, user)
323 response = self.client.get('/experiments/lanes_for/%s/json' % (user,), apidata)
324 self.assertEqual(response.status_code, 404)
326 def test_raw_data_dir(self):
327 """Raw data path generator check"""
328 flowcell_id = self.fc1_id
329 raw_dir = os.path.join(settings.RESULT_HOME_DIR, flowcell_id)
331 fc = FlowCell.objects.get(flowcell_id=flowcell_id)
332 self.assertEqual(fc.get_raw_data_directory(), raw_dir)
334 fc.flowcell_id = flowcell_id + " (failed)"
335 self.assertEqual(fc.get_raw_data_directory(), raw_dir)
337 def test_data_run_import(self):
338 srf_file_type = FileType.objects.get(name='SRF')
339 runxml_file_type = FileType.objects.get(name='run_xml')
340 flowcell_id = self.fc1_id
341 flowcell = FlowCell.objects.get(flowcell_id=flowcell_id)
342 flowcell.update_data_runs()
343 self.assertEqual(len(flowcell.datarun_set.all()), 1)
345 run = flowcell.datarun_set.all()[0]
346 result_files = run.datafile_set.all()
347 result_dict = dict(((rf.relative_pathname, rf) for rf in result_files))
349 srf4 = result_dict['FC12150/C1-37/woldlab_070829_SERIAL_FC12150_4.srf']
350 self.assertEqual(srf4.file_type, srf_file_type)
351 self.assertEqual(srf4.library_id, '12154')
352 self.assertEqual(srf4.data_run.flowcell.flowcell_id, 'FC12150')
354 srf4.data_run.flowcell.lane_set.get(lane_number=4).library_id,
358 os.path.join(settings.RESULT_HOME_DIR, srf4.relative_pathname))
360 lane_files = run.lane_files()
361 self.assertEqual(lane_files[4]['srf'], srf4)
363 runxml= result_dict['FC12150/C1-37/run_FC12150_2007-09-27.xml']
364 self.assertEqual(runxml.file_type, runxml_file_type)
365 self.assertEqual(runxml.library_id, None)
367 import1 = len(DataRun.objects.filter(result_dir='FC12150/C1-37'))
368 # what happens if we import twice?
369 flowcell.import_data_run('FC12150/C1-37',
370 'run_FC12150_2007-09-27.xml')
372 len(DataRun.objects.filter(result_dir='FC12150/C1-37')),
375 def test_read_result_file(self):
376 """make sure we can return a result file
378 flowcell_id = self.fc1_id
379 flowcell = FlowCell.objects.get(flowcell_id=flowcell_id)
380 flowcell.update_data_runs()
382 #self.client.login(username='supertest', password='BJOKL5kAj6aFZ6A5')
384 result_files = flowcell.datarun_set.all()[0].datafile_set.all()
385 for f in result_files:
386 url = '/experiments/file/%s' % ( f.random_key,)
387 response = self.client.get(url)
388 self.assertEqual(response.status_code, 200)
389 mimetype = f.file_type.mimetype
391 mimetype = 'application/octet-stream'
393 self.assertEqual(mimetype, response['content-type'])
395 def test_flowcell_rdf(self):
397 from htsworkflow.util.rdfhelp import get_model, \
399 load_string_into_model, \
406 expected = {'1': ['12151'],
414 url = '/flowcell/{}/'.format(self.fc12150.flowcell_id)
415 response = self.client.get(url)
416 self.assertEqual(response.status_code, 200)
417 status = validate_xhtml(response.content)
418 if status is not None: self.assertTrue(status)
420 ns = urljoin('http://localhost', url)
421 load_string_into_model(model, 'rdfa', smart_text(response.content), ns=ns)
422 body = """prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
423 prefix libns: <http://jumpgate.caltech.edu/wiki/LibraryOntology#>
425 select ?flowcell ?flowcell_id ?lane_id ?library_id
427 ?flowcell a libns:IlluminaFlowcell ;
428 libns:flowcell_id ?flowcell_id ;
429 libns:has_lane ?lane .
430 ?lane libns:lane_number ?lane_id ;
431 libns:library ?library .
432 ?library libns:library_id ?library_id .
434 query = RDF.SPARQLQuery(body)
436 for r in query.execute(model):
438 self.assertEqual(fromTypedNode(r['flowcell_id']), 'FC12150')
439 lane_id = fromTypedNode(r['lane_id'])
440 library_id = fromTypedNode(r['library_id'])
441 self.assertTrue(library_id in expected[lane_id])
442 self.assertEqual(count, 8)
444 class TestEmailNotify(TestCase):
446 self.password = 'foo27'
447 self.user = HTSUserFactory.create(username='test')
448 self.user.set_password(self.password)
450 self.admin = HTSUserFactory.create(username='admintest', is_staff=True)
451 self.admin.set_password(self.password)
453 self.super = HTSUserFactory.create(username='supertest', is_staff=True, is_superuser=True)
454 self.super.set_password(self.password)
457 self.library = LibraryFactory.create()
458 self.affiliation = AffiliationFactory()
459 self.affiliation.users.add(self.user)
460 self.library.affiliations.add(self.affiliation)
461 self.fc = FlowCellFactory.create()
462 self.lane = LaneFactory(flowcell=self.fc, lane_number=1, library=self.library)
464 self.url = '/experiments/started/{}/'.format(self.fc.id)
466 def test_started_email_not_logged_in(self):
467 response = self.client.get(self.url)
468 self.assertEqual(response.status_code, 302)
470 def test_started_email_logged_in_user(self):
471 self.assertTrue(self.client.login(username=self.user.username, password=self.password))
472 response = self.client.get(self.url)
473 self.assertEqual(response.status_code, 302)
475 def test_started_email_logged_in_staff(self):
476 self.assertTrue(self.admin.is_staff)
477 admin = HTSUser.objects.get(username=self.admin.username)
478 self.assertTrue(admin.is_staff)
479 self.assertTrue(admin.check_password(self.password))
480 self.assertTrue(self.client.login(username=self.admin.username, password=self.password))
481 response = self.client.get(self.url)
482 self.assertEqual(response.status_code, 200)
484 def test_started_email_send(self):
485 self.assertTrue(self.client.login(username=self.admin.username, password=self.password))
486 response = self.client.get(self.url)
487 self.assertEqual(response.status_code, 200)
489 self.assertTrue(self.affiliation.email in smart_text(response.content))
490 self.assertTrue(self.library.library_name in smart_text(response.content))
492 response = self.client.get(self.url, {'send':'1','bcc':'on'})
493 self.assertEqual(response.status_code, 200)
494 self.assertEqual(len(mail.outbox), 2)
495 bcc = set(settings.NOTIFICATION_BCC).copy()
496 bcc.update(set(settings.MANAGERS))
497 for m in mail.outbox:
498 self.assertTrue(len(m.body) > 0)
499 self.assertEqual(set(m.bcc), bcc)
501 def test_email_navigation(self):
503 Can we navigate between the flowcell and email forms properly?
505 admin_url = '/admin/experiments/flowcell/{}/'.format(self.fc.id)
506 self.client.login(username=self.admin.username, password=self.password)
507 response = self.client.get(self.url)
508 self.assertEqual(response.status_code, 200)
509 #print("email navigation content:", response.content)
510 self.assertTrue(re.search(self.fc.flowcell_id, smart_text(response.content)))
511 # require that navigation back to the admin page exists
512 self.assertTrue(re.search('<a href="{}">[^<]+</a>'.format(admin_url),
513 smart_text(response.content)))
515 def multi_lane_to_dict(lane):
516 """Convert a list of lane entries into a dictionary indexed by library ID
518 return dict( ((x['library_id'],x) for x in lane) )
520 class TestSequencer(TestCase):
522 self.fc12150 = FlowCellFactory(flowcell_id='FC12150')
523 self.library = LibraryFactory(id="12150")
524 self.lane = LaneFactory(flowcell=self.fc12150, lane_number=1, library=self.library)
526 def test_name_generation(self):
529 seq.instrument_name = "HWI-SEQ1"
530 seq.model = "Imaginary 5000"
532 self.assertEqual(str(seq), "Seq1 (HWI-SEQ1)")
534 def test_lookup(self):
536 self.assertEqual(fc.sequencer.model, 'HiSeq 1')
537 self.assertTrue(fc.sequencer.instrument_name.startswith('instrument name')),
538 # well actually we let the browser tack on the host name
539 url = fc.get_absolute_url()
540 self.assertEqual(url, '/flowcell/FC12150/')
543 response = self.client.get('/flowcell/FC12150/', apidata)
544 tree = fromstring(response.content)
545 seq_by = tree.xpath('//div[@rel="libns:sequenced_by"]',
547 self.assertEqual(len(seq_by), 1)
548 self.assertEqual(seq_by[0].attrib['rel'], 'libns:sequenced_by')
549 seq = seq_by[0].getchildren()
550 self.assertEqual(len(seq), 1)
551 sequencer = '/sequencer/' + str(self.fc12150.sequencer.id)
552 self.assertEqual(seq[0].attrib['about'], sequencer)
553 self.assertEqual(seq[0].attrib['typeof'], 'libns:Sequencer')
555 name = seq[0].xpath('./span[@property="libns:sequencer_name"]')
556 self.assertEqual(len(name), 1)
557 self.assertTrue(name[0].text.startswith('sequencer '))
558 instrument = seq[0].xpath(
559 './span[@property="libns:sequencer_instrument"]')
560 self.assertEqual(len(instrument), 1)
561 self.assertTrue(instrument[0].text.startswith('instrument name'))
562 model = seq[0].xpath(
563 './span[@property="libns:sequencer_model"]')
564 self.assertEqual(len(model), 1)
565 self.assertEqual(model[0].text, 'HiSeq 1')
567 def test_flowcell_with_rdf_validation(self):
568 from htsworkflow.util.rdfhelp import add_default_schemas, \
571 load_string_into_model
572 from htsworkflow.util.rdfinfer import Infer
575 add_default_schemas(model)
576 inference = Infer(model)
578 url ='/flowcell/FC12150/'
579 response = self.client.get(url)
580 self.assertEqual(response.status_code, 200)
581 status = validate_xhtml(response.content)
582 if status is not None: self.assertTrue(status)
584 load_string_into_model(model, 'rdfa', smart_text(response.content))
586 errmsgs = list(inference.run_validation())
587 self.assertEqual(len(errmsgs), 0)
589 def test_lane_with_rdf_validation(self):
590 from htsworkflow.util.rdfhelp import add_default_schemas, \
593 load_string_into_model
594 from htsworkflow.util.rdfinfer import Infer
597 add_default_schemas(model)
598 inference = Infer(model)
600 url = '/lane/{}'.format(self.lane.id)
601 response = self.client.get(url)
602 rdfbody = smart_text(response.content)
603 self.assertEqual(response.status_code, 200)
604 status = validate_xhtml(rdfbody)
605 if status is not None: self.assertTrue(status)
607 load_string_into_model(model, 'rdfa', rdfbody)
609 errmsgs = list(inference.run_validation())
610 self.assertEqual(len(errmsgs), 0)
613 from unittest import TestSuite, defaultTestLoader
615 for testcase in [ExerimentsTestCases,
618 suite.addTests(defaultTestLoader.loadTestsFromTestCase(testcase))
621 if __name__ == "__main__":
622 from unittest import main
623 main(defaultTest="suite")