7bfebfec3f9a5190ef40dac3dacbcb51dcd3bdd9
[htsworkflow.git] / htsworkflow / frontend / experiments / tests.py
1 import re
2 from BeautifulSoup import BeautifulSoup
3 try:
4     import json
5 except ImportError, e:
6     import simplejson as json
7 import os
8 import sys
9
10 from django.core import mail
11 from django.core.exceptions import ObjectDoesNotExist
12 from django.test import TestCase
13 from htsworkflow.frontend.experiments import models
14 from htsworkflow.frontend.experiments import experiments
15 from htsworkflow.frontend.auth import apidata
16
17 LANE_SET = range(1,9)
18
19 class ExperimentsTestCases(TestCase):
20     fixtures = ['test_flowcells.json']
21
22     def setUp(self):
23         pass
24
25     def test_flowcell_information(self):
26         """
27         Check the code that packs the django objects into simple types.
28         """
29         for fc_id in [u'303TUAAXX', u"42JTNAAXX", "42JU1AAXX"]:
30             fc_dict = experiments.flowcell_information(fc_id)
31             fc_django = models.FlowCell.objects.get(flowcell_id=fc_id)
32             self.failUnlessEqual(fc_dict['flowcell_id'], fc_id)
33             self.failUnlessEqual(fc_django.flowcell_id, fc_id)
34             self.failUnlessEqual(fc_dict['sequencer'], fc_django.sequencer.name)
35             self.failUnlessEqual(fc_dict['read_length'], fc_django.read_length)
36             self.failUnlessEqual(fc_dict['notes'], fc_django.notes)
37             self.failUnlessEqual(fc_dict['cluster_station'], fc_django.cluster_station.name)
38
39             for lane in fc_django.lane_set.all():
40                 lane_dict = fc_dict['lane_set'][lane.lane_number]
41                 self.failUnlessEqual(lane_dict['cluster_estimate'], lane.cluster_estimate)
42                 self.failUnlessEqual(lane_dict['comment'], lane.comment)
43                 self.failUnlessEqual(lane_dict['flowcell'], lane.flowcell.flowcell_id)
44                 self.failUnlessEqual(lane_dict['lane_number'], lane.lane_number)
45                 self.failUnlessEqual(lane_dict['library_name'], lane.library.library_name)
46                 self.failUnlessEqual(lane_dict['library_id'], lane.library.id)
47                 self.failUnlessAlmostEqual(float(lane_dict['pM']), float(lane.pM))
48                 self.failUnlessEqual(lane_dict['library_species'],
49                                      lane.library.library_species.scientific_name)
50                     
51             response = self.client.get('/experiments/config/%s/json' % (fc_id,), apidata)
52             # strptime isoformat string = '%Y-%m-%dT%H:%M:%S'
53             fc_json = json.loads(response.content)
54             self.failUnlessEqual(fc_json['flowcell_id'], fc_id)
55             self.failUnlessEqual(fc_json['sequencer'], fc_django.sequencer.name)
56             self.failUnlessEqual(fc_json['read_length'], fc_django.read_length)
57             self.failUnlessEqual(fc_json['notes'], fc_django.notes)
58             self.failUnlessEqual(fc_json['cluster_station'], fc_django.cluster_station.name)
59
60
61             for lane in fc_django.lane_set.all():
62                 lane_dict = fc_json['lane_set'][unicode(lane.lane_number)]
63                 self.failUnlessEqual(lane_dict['cluster_estimate'], lane.cluster_estimate)
64                 self.failUnlessEqual(lane_dict['comment'], lane.comment)
65                 self.failUnlessEqual(lane_dict['flowcell'], lane.flowcell.flowcell_id)
66                 self.failUnlessEqual(lane_dict['lane_number'], lane.lane_number)
67                 self.failUnlessEqual(lane_dict['library_name'], lane.library.library_name)
68                 self.failUnlessEqual(lane_dict['library_id'], lane.library.id)
69                 self.failUnlessAlmostEqual(float(lane_dict['pM']), float(lane.pM))
70                 self.failUnlessEqual(lane_dict['library_species'],
71                                      lane.library.library_species.scientific_name)
72
73     def test_invalid_flowcell(self):
74         """
75         Make sure we get a 404 if we request an invalid flowcell ID
76         """
77         response = self.client.get('/experiments/config/nottheone/json', apidata)
78         self.failUnlessEqual(response.status_code, 404)
79
80     def test_no_key(self):
81         """
82         Require logging in to retrieve meta data
83         """
84         response = self.client.get(u'/experiments/config/303TUAAXX/json')
85         self.failUnlessEqual(response.status_code, 403)
86
87     def test_library_id(self):
88         """
89         Library IDs should be flexible, so make sure we can retrive a non-numeric ID
90         """
91         response = self.client.get('/experiments/config/303TUAAXX/json', apidata)
92         self.failUnlessEqual(response.status_code, 200)
93         flowcell = json.loads(response.content)
94
95         self.failUnlessEqual(flowcell['lane_set']['3']['library_id'], 'SL039')
96
97         response = self.client.get('/samples/library/SL039/json', apidata)
98         self.failUnlessEqual(response.status_code, 200)
99         library_sl039 = json.loads(response.content)
100
101         self.failUnlessEqual(library_sl039['library_id'], 'SL039')
102
103     def test_raw_id_field(self):
104         """
105         Test ticket:147
106
107         Library's have IDs, libraries also have primary keys,
108         we eventually had enough libraries that the drop down combo box was too
109         hard to filter through, unfortnately we want a field that uses our library
110         id and not the internal primary key, and raw_id_field uses primary keys.
111
112         This tests to make sure that the value entered in the raw library id field matches
113         the library id looked up.
114         """
115         expected_ids = [u'10981',u'11016',u'SL039',u'11060',
116                         u'11061',u'11062',u'11063',u'11064']
117         self.client.login(username='supertest', password='BJOKL5kAj6aFZ6A5')
118         response = self.client.get('/admin/experiments/flowcell/153/')
119         soup = BeautifulSoup(response.content)
120         for i in range(0,8):
121             input_field = soup.find(id='id_lane_set-%d-library' % (i,))
122             library_field = input_field.findNext('strong')
123             library_id, library_name = library_field.string.split(':')
124             # strip leading '#' sign from name
125             library_id = library_id[1:]
126             self.failUnlessEqual(library_id, expected_ids[i])
127             self.failUnlessEqual(input_field['value'], library_id)
128
129     def test_lanes_for(self):
130         """
131         Check the code that packs the django objects into simple types.
132         """
133         user = 'test'
134         lanes = experiments.lanes_for(user)
135         self.failUnlessEqual(len(lanes), 5)
136
137         response = self.client.get('/experiments/lanes_for/%s/json' % (user,), apidata)
138         lanes_json = json.loads(response.content)
139         self.failUnlessEqual(len(lanes), len(lanes_json))
140         for i in range(len(lanes)):
141             self.failUnlessEqual(lanes[i]['comment'], lanes_json[i]['comment'])
142             self.failUnlessEqual(lanes[i]['lane_number'], lanes_json[i]['lane_number'])
143             self.failUnlessEqual(lanes[i]['flowcell'], lanes_json[i]['flowcell'])
144             self.failUnlessEqual(lanes[i]['run_date'], lanes_json[i]['run_date'])
145             
146     def test_lanes_for_no_lanes(self):
147         """
148         Do we get something meaningful back when the user isn't attached to anything?
149         """
150         user = 'supertest'
151         lanes = experiments.lanes_for(user)
152         self.failUnlessEqual(len(lanes), 0)
153
154         response = self.client.get('/experiments/lanes_for/%s/json' % (user,), apidata)
155         lanes_json = json.loads(response.content)
156
157     def test_lanes_for_no_user(self):
158         """
159         Do we get something meaningful back when its the wrong user
160         """
161         user = 'not a real user'
162         self.failUnlessRaises(ObjectDoesNotExist, experiments.lanes_for, user)
163
164         response = self.client.get('/experiments/lanes_for/%s/json' % (user,), apidata)
165         self.failUnlessEqual(response.status_code, 404)
166
167
168 class TestEmailNotify(TestCase):
169     fixtures = ['test_flowcells.json']
170
171     def test_started_email_not_logged_in(self):
172         response = self.client.get('/experiments/started/153/')
173         self.failUnlessEqual(response.status_code, 302)
174
175     def test_started_email_logged_in_user(self):
176         self.client.login(username='test', password='BJOKL5kAj6aFZ6A5')
177         response = self.client.get('/experiments/started/153/')
178         self.failUnlessEqual(response.status_code, 302)
179         
180     def test_started_email_logged_in_staff(self):
181         self.client.login(username='admintest', password='BJOKL5kAj6aFZ6A5') 
182         response = self.client.get('/experiments/started/153/')
183         self.failUnlessEqual(response.status_code, 200)
184
185     def test_started_email_send(self):
186         self.client.login(username='admintest', password='BJOKL5kAj6aFZ6A5') 
187         response = self.client.get('/experiments/started/153/')
188         self.failUnlessEqual(response.status_code, 200)
189         
190         self.failUnless('pk1@example.com' in response.content)
191         self.failUnless('Lane #8 : (11064) Paired ends 104' in response.content)
192
193         response = self.client.get('/experiments/started/153/', {'send':'1','bcc':'on'})
194         self.failUnlessEqual(response.status_code, 200)
195         self.failUnlessEqual(len(mail.outbox), 4)
196         for m in mail.outbox:
197             self.failUnless(len(m.body) > 0)
198
199     def test_email_navigation(self):
200         """
201         Can we navigate between the flowcell and email forms properly?
202         """
203         self.client.login(username='supertest', password='BJOKL5kAj6aFZ6A5') 
204         response = self.client.get('/experiments/started/153/')
205         self.failUnlessEqual(response.status_code, 200)
206         self.failUnless(re.search('Flowcell 303TUAAXX', response.content))
207         # require that navigation back to the admin page exists
208         self.failUnless(re.search('<a href="/admin/experiments/flowcell/153/">[^<]+</a>', response.content))
209         
210