source: main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_webservices.py @ 13316

Last change on this file since 13316 was 12110, checked in by Henrik Bettermann, 10 years ago

svn propset svn:keywords "Id"

  • Property svn:keywords set to Id
File size: 17.5 KB
Line 
1# Tests for webservices
2import xmlrpclib
3import os
4from cStringIO import StringIO
5from zope.app.testing.xmlrpc import ServerProxy
6from zope.component import getUtility
7from waeup.kofa.interfaces import IExtFileStore, IFileStoreNameChooser
8from waeup.kofa.testing import FunctionalLayer
9from waeup.kofa.students.payments import StudentOnlinePayment
10from waeup.kofa.students.tests.test_browser import StudentsFullSetup
11from waeup.kofa.students.studylevel import StudentStudyLevel, CourseTicket
12
13
14class XMLRPCTests(StudentsFullSetup):
15    # check XMLRPC services for university portal
16
17    layer = FunctionalLayer
18
19    def setup_student(self, student):
20        study_level = StudentStudyLevel()
21        study_level.level_session = 2012
22        study_level.level_verdict = "A"
23        study_level.level = 100
24        study_level.validated_by = u"my adviser"
25        student['studycourse'].addStudentStudyLevel(
26            self.certificate, study_level)
27
28        ticket = CourseTicket()
29        ticket.automatic = True
30        ticket.carry_over = True
31        ticket.code = u'CRS1'
32        ticket.title = u'Course 1'
33        ticket.fcode = u'FAC1'
34        ticket.dcode = u'DEP1'
35        ticket.credits = 100
36        ticket.passmark = 100
37        ticket.semester = 2
38        study_level[ticket.code] = ticket
39
40    def create_passport_img(self, student):
41        # create some passport file for `student`
42        storage = getUtility(IExtFileStore)
43        image_path = os.path.join(os.path.dirname(__file__), 'test_image.jpg')
44        self.image_contents = open(image_path, 'rb').read()
45        file_id = IFileStoreNameChooser(student).chooseName(
46            attr='passport.jpg')
47        storage.createFile(file_id, StringIO(self.image_contents))
48
49    def create_fpm_file(self, student, finger_num):
50        # create some .fpm file for `student` finger `finger_num`
51        storage = getUtility(IExtFileStore)
52        file_id = IFileStoreNameChooser(student).chooseName(
53            attr='%s.fpm' % finger_num)
54        storage.createFile(file_id, StringIO('FP1FakedMintiaeFile1'))
55
56    def XMLRPC_post(self, body):
57        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
58        self.browser.addHeader('Content-Length', len(body))
59        self.browser.post('http://localhost/app', body,
60            'text/xml; charset=utf-8')
61        return self.browser.contents
62
63    def test_get_student_id_no_match(self):
64        # w/o any students we get none
65        server = ServerProxy('http://mgr:mgrpw@localhost/app')
66        result = server.get_student_id('Nonsense')
67        self.assertTrue(result is None)
68        return
69
70    def test_get_student_id_regno_exists(self):
71        # we can get the id of an existing student with matching reg_no
72        server = ServerProxy('http://mgr:mgrpw@localhost/app')
73        result = server.get_student_id('123')
74        self.assertEqual(result, 'K1000000')
75        self.assertEqual(self.student_id, result)
76        REQUEST_XML = """\
77<?xml version="1.0"?>
78<methodCall>
79<methodName>get_student_id</methodName>
80<params>
81<param>
82<value><string>123</string></value>
83</param>
84</params>
85</methodCall>"""
86        RESPONSE_XML = """\
87<?xml version='1.0'?>
88<methodResponse>
89<params>
90<param>
91<value><string>K1000000</string></value>
92</param>
93</params>
94</methodResponse>
95"""
96        xmlout = self.XMLRPC_post(REQUEST_XML)
97        self.assertEqual(xmlout, RESPONSE_XML)
98        return
99
100    def test_get_student_id_block_unauthorized(self):
101        # requests from unauthorized users are blocked
102        # no username nor password
103        server = ServerProxy('http://localhost/app')
104        self.assertRaises(
105            xmlrpclib.ProtocolError, server.get_student_id, '123')
106        # wrong password
107        server = ServerProxy('http://mgr:WRONGPW@localhost/app')
108        self.assertRaises(
109            xmlrpclib.ProtocolError, server.get_student_id, '123')
110        # wrong username
111        server = ServerProxy('http://WRONGUSER:mgrpw@localhost/app')
112        self.assertRaises(
113            xmlrpclib.ProtocolError, server.get_student_id, '123')
114        return
115
116    def test_get_courses_by_session(self):
117        server = ServerProxy('http://mgr:mgrpw@localhost/app')
118        result = server.get_courses_by_session('K1000000')
119        self.assertEqual(result, None)
120        self.setup_student(self.student)
121        result = server.get_courses_by_session('K1000000', '2010')
122        self.assertEqual(result, None)
123        result = server.get_courses_by_session('K1000000', '2012')
124        self.assertEqual(result,
125            {'100|CRS1': 'Course 1', '100|COURSE1': 'Unnamed Course'})
126        result = server.get_courses_by_session('K1000000')
127        self.assertEqual(result,
128            {'100|CRS1': 'Course 1', '100|COURSE1': 'Unnamed Course'})
129        # Also matric_number ...
130        result = server.get_courses_by_session('234')
131        self.assertEqual(result,
132            {'100|CRS1': 'Course 1', '100|COURSE1': 'Unnamed Course'})
133        # ... or reg_number can be used.
134        result = server.get_courses_by_session('123')
135        self.assertEqual(result,
136            {'100|CRS1': 'Course 1', '100|COURSE1': 'Unnamed Course'})
137        result = server.get_courses_by_session('Nonsense')
138        self.assertEqual(result, None)
139        REQUEST_XML = """\
140<?xml version="1.0"?>
141<methodCall>
142<methodName>get_courses_by_session</methodName>
143<params>
144<param>
145<value><string>K1000000</string></value>
146</param>
147</params>
148</methodCall>"""
149        RESPONSE_XML = """\
150<?xml version='1.0'?>
151<methodResponse>
152<params>
153<param>
154<value><struct>
155<member>
156<name>100|CRS1</name>
157<value><string>Course 1</string></value>
158</member>
159<member>
160<name>100|COURSE1</name>
161<value><string>Unnamed Course</string></value>
162</member>
163</struct></value>
164</param>
165</params>
166</methodResponse>
167"""
168        xmlout = self.XMLRPC_post(REQUEST_XML)
169        self.assertEqual(xmlout, RESPONSE_XML)
170        return
171
172    def test_get_students_by_course(self):
173        self.setup_student(self.student)
174        server = ServerProxy('http://mgr:mgrpw@localhost/app')
175        result = server.get_students_by_course('CRS1', '2010')
176        self.assertEqual(result, None)
177        result = server.get_students_by_course('CRS1', '2012')
178        self.assertEqual(result, [['K1000000', '234', 'my adviser', 0], ])
179        result = server.get_students_by_course('CRS1')
180        self.assertEqual(result, [['K1000000', '234', 'my adviser', 0], ])
181        payment = StudentOnlinePayment()
182        payment.p_id = 'my-id'
183        payment.p_session = 2012
184        payment.amount_auth = 12.12
185        payment.p_state = u'paid'
186        payment.p_category = u'schoolfee'
187        self.student['payments']['my-payment'] = payment
188        result = server.get_students_by_course('CRS1')
189        self.assertEqual(result, [['K1000000', '234', 'my adviser', 12.12], ])
190        REQUEST_XML = """\
191<?xml version="1.0"?>
192<methodCall>
193<methodName>get_students_by_course</methodName>
194<params>
195<param>
196<value><string>CRS1</string></value>
197<value><string>2012</string></value>
198</param>
199</params>
200</methodCall>"""
201        RESPONSE_XML = """\
202<?xml version='1.0'?>
203<methodResponse>
204<params>
205<param>
206<value><array><data>
207<value><array><data>
208<value><string>K1000000</string></value>
209<value><string>234</string></value>
210<value><string>my adviser</string></value>
211<value><double>12.12</double></value>
212</data></array></value>
213</data></array></value>
214</param>
215</params>
216</methodResponse>
217"""
218        xmlout = self.XMLRPC_post(REQUEST_XML)
219        self.assertEqual(xmlout, RESPONSE_XML)
220        return
221
222    def test_get_student_info(self):
223        server = ServerProxy('http://mgr:mgrpw@localhost/app')
224        self.setup_student(self.student)
225        result = server.get_student_info('123')
226        self.assertEqual(result,
227            ['Anna Tester', 'CERT1', '1234', 'aa@aa.ng'])
228        REQUEST_XML = """\
229<?xml version="1.0"?>
230<methodCall>
231<methodName>get_student_info</methodName>
232<params>
233<param>
234<value><string>K1000000</string></value>
235</param>
236</params>
237</methodCall>"""
238        RESPONSE_XML = """\
239<?xml version='1.0'?>
240<methodResponse>
241<params>
242<param>
243<value><array><data>
244<value><string>Anna Tester</string></value>
245<value><string>CERT1</string></value>
246<value><string>1234</string></value>
247<value><string>aa@aa.ng</string></value>
248</data></array></value>
249</param>
250</params>
251</methodResponse>
252"""
253        xmlout = self.XMLRPC_post(REQUEST_XML)
254        self.assertEqual(xmlout, RESPONSE_XML)
255        return
256
257    def test_get_student_passport(self):
258        server = ServerProxy('http://mgr:mgrpw@localhost/app')
259        self.setup_student(self.student)
260        self.create_passport_img(self.student)
261        result = server.get_student_passport('123')
262        img = getUtility(IExtFileStore).getFileByContext(
263            self.student, attr='passport.jpg')
264        binary = img.read()
265        self.assertEqual(binary, result)
266        REQUEST_XML = """\
267<?xml version="1.0"?>
268<methodCall>
269<methodName>get_student_passport</methodName>
270<params>
271<param>
272<value><string>K1000000</string></value>
273</param>
274</params>
275</methodCall>"""
276        RESPONSE_XML = """\
277<?xml version='1.0'?>
278<methodResponse>
279<params>
280<param>
281<value><base64>
282/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b
283"""
284        xmlout = self.XMLRPC_post(REQUEST_XML)
285        self.assertTrue(xmlout.startswith(RESPONSE_XML))
286
287    def test_get_paid_sessions(self):
288        server = ServerProxy('http://mgr:mgrpw@localhost/app')
289        self.setup_student(self.student)
290        payment = StudentOnlinePayment()
291        payment.p_id = 'my-id'
292        payment.p_session = 2009
293        payment.amount_auth = 12.12
294        payment.p_state = u'paid'
295        payment.p_category = u'schoolfee'
296        self.student['payments']['my-payment'] = payment
297        result = server.get_paid_sessions('123')
298        self.assertEqual(result, {'2009': 12.12})
299        REQUEST_XML = """\
300<?xml version="1.0"?>
301<methodCall>
302<methodName>get_paid_sessions</methodName>
303<params>
304<param>
305<value><string>K1000000</string></value>
306</param>
307</params>
308</methodCall>"""
309        RESPONSE_XML = """\
310<?xml version='1.0'?>
311<methodResponse>
312<params>
313<param>
314<value><struct>
315<member>
316<name>2009</name>
317<value><double>12.12</double></value>
318</member>
319</struct></value>
320</param>
321</params>
322</methodResponse>
323"""
324        xmlout = self.XMLRPC_post(REQUEST_XML)
325        self.assertEqual(xmlout, RESPONSE_XML)
326        return
327
328    def test_check_student_credentials(self):
329        # make sure we can get student infos providing valid creds
330        server = ServerProxy('http://mgr:mgrpw@localhost/app')
331        self.setup_student(self.student)
332        stud_id = self.student.student_id
333        result = server.check_student_credentials(stud_id, 'spwd')
334        self.assertEqual(
335            result, {
336                'description': 'Anna Tester',
337                'email': 'aa@aa.ng',
338                'id': 'K1000000',
339                'type': 'student'}
340            )
341        return
342
343    def test_get_student_moodle_data(self):
344        server = ServerProxy('http://mgr:mgrpw@localhost/app')
345        self.setup_student(self.student)
346        result = server.get_student_moodle_data(self.student.student_id)
347        self.assertEqual(result,
348            {'lastname': 'Tester', 'email': 'aa@aa.ng', 'firstname': 'Anna'})
349        REQUEST_XML = """\
350<?xml version="1.0"?>
351<methodCall>
352<methodName>get_student_moodle_data</methodName>
353<params>
354<param>
355<value><string>K1000000</string></value>
356</param>
357</params>
358</methodCall>"""
359        RESPONSE_XML = """\
360<?xml version='1.0'?>
361<methodResponse>
362<params>
363<param>
364<value><struct>
365<member>
366<name>lastname</name>
367<value><string>Tester</string></value>
368</member>
369<member>
370<name>email</name>
371<value><string>aa@aa.ng</string></value>
372</member>
373<member>
374<name>firstname</name>
375<value><string>Anna</string></value>
376</member>
377</struct></value>
378</param>
379</params>
380</methodResponse>
381"""
382        xmlout = self.XMLRPC_post(REQUEST_XML)
383        self.assertEqual(xmlout, RESPONSE_XML)
384        return
385
386    def test_put_student_fingerprints_no_stud(self):
387        # invalid student ids will result in `False`
388        server = ServerProxy('http://mgr:mgrpw@localhost/app')
389        self.assertRaises(
390            xmlrpclib.Fault, server.put_student_fingerprints,
391            'invalid id', {})
392
393    def test_put_student_fingerprints_non_dict(self):
394        # fingerprints must be passed in in a dict
395        server = ServerProxy('http://mgr:mgrpw@localhost/app')
396        self.setup_student(self.student)
397        self.assertRaises(
398            xmlrpclib.Fault, server.put_student_fingerprints,
399            self.student.student_id, 'not-a-dict')
400
401    def test_put_student_fingerprints_non_num_keys_ignored(self):
402        # non-numeric keys in fingerprint dict are ignored
403        server = ServerProxy('http://mgr:mgrpw@localhost/app')
404        self.setup_student(self.student)
405        result = server.put_student_fingerprints(
406            self.student.student_id, {'not-a-num': 'foo',
407                                      '12.2': 'bar',
408                                      '123': 'baz'})
409        self.assertEqual(result, False)
410
411    def test_put_student_fingerprints_non_fpm_data(self):
412        # we cannot pass non-.fpm files as values
413        server = ServerProxy('http://mgr:mgrpw@localhost/app')
414        self.setup_student(self.student)
415        self.assertRaises(
416            xmlrpclib.Fault, server.put_student_fingerprints,
417            self.student.student_id, {'1': 'not-a-fingerprint'})
418
419    def test_put_student_fingerprints_invalid_file_format(self):
420        # invalid files will result in `False`
421        server = ServerProxy('http://mgr:mgrpw@localhost/app')
422        self.setup_student(self.student)
423        invalid_fpm = xmlrpclib.Binary('invalid file')
424        self.assertRaises(
425            xmlrpclib.Fault, server.put_student_fingerprints,
426            self.student.student_id, {'1': invalid_fpm})
427
428    def test_put_student_fingerprints(self):
429        # we can store fingerprints
430        server = ServerProxy('http://mgr:mgrpw@localhost/app')
431        self.setup_student(self.student)
432        fpm = xmlrpclib.Binary('FP1faked_fpm')
433        result = server.put_student_fingerprints(
434            self.student.student_id, {'1': fpm})
435        self.assertEqual(result, True)
436        stored_file = getUtility(IExtFileStore).getFileByContext(
437            self.student, attr="1.fpm")
438        self.assertEqual(stored_file.read(), 'FP1faked_fpm')
439
440    def test_put_student_fingerprints_existing(self):
441        # existing fingerprints are overwritten
442        server = ServerProxy('http://mgr:mgrpw@localhost/app')
443        self.setup_student(self.student)
444        self.create_fpm_file(self.student, '1')
445        fpm1 = xmlrpclib.Binary('FP1faked_fpm1')
446        fpm2 = xmlrpclib.Binary('FP1faked_fpm2')
447        result = server.put_student_fingerprints(
448            self.student.student_id, {'1': fpm1, '3': fpm2})
449        self.assertEqual(result, True)
450        stored_file1 = getUtility(IExtFileStore).getFileByContext(
451            self.student, attr="1.fpm")
452        stored_file2 = getUtility(IExtFileStore).getFileByContext(
453            self.student, attr="3.fpm")
454        self.assertEqual(stored_file1.read(), 'FP1faked_fpm1')
455        self.assertEqual(stored_file2.read(), 'FP1faked_fpm2')
456
457    def test_get_student_fingerprints_no_stud(self):
458        # invalid student ids result in empty dict
459        server = ServerProxy('http://mgr:mgrpw@localhost/app')
460        result = server.get_student_fingerprints('invalid id')
461        self.assertEqual(result, {})
462
463    def test_get_student_fingerprints_no_files(self):
464        # we get student data, but no fingerprints if not stored before
465        server = ServerProxy('http://mgr:mgrpw@localhost/app')
466        self.setup_student(self.student)
467        result = server.get_student_fingerprints(self.student.student_id)
468        self.assertEqual(
469            result,
470            {'lastname': 'Tester',
471             'email': 'aa@aa.ng',
472             'firstname': 'Anna',
473             'fingerprints': {},
474             'img': None,
475             'img_name': None,
476             })
477
478    def test_get_student_fingerprints_passport(self):
479        # we get a photograph of the student if avail.
480        server = ServerProxy('http://mgr:mgrpw@localhost/app')
481        self.setup_student(self.student)
482        self.create_passport_img(self.student)
483        result = server.get_student_fingerprints(self.student.student_id)
484        self.assertTrue(
485            isinstance(result['img'], xmlrpclib.Binary))
486        self.assertEqual(result['img_name'], 'passport_K1000000.jpg')
487
488    def test_get_student_fingerprints_fpm(self):
489        # we get minutiae files if any are avail.
490        server = ServerProxy('http://mgr:mgrpw@localhost/app')
491        self.setup_student(self.student)
492        self.create_fpm_file(self.student, '1')
493        result = server.get_student_fingerprints(self.student.student_id)
494        self.assertTrue('1' in result['fingerprints'].keys())
495        self.assertTrue(
496            isinstance(result['fingerprints']['1'], xmlrpclib.Binary))
497
498    def test_get_student_fingerprints_block_unauthorized(self):
499        # requests from unauthorized users are blocked
500        # no username nor password
501        server = ServerProxy('http://localhost/app')
502        self.setup_student(self.student)
503        stud_id = self.student.student_id
504        self.assertRaises(
505            xmlrpclib.ProtocolError, server.get_student_id, stud_id)
506        # wrong password
507        server = ServerProxy('http://mgr:WRONGPW@localhost/app')
508        self.assertRaises(
509            xmlrpclib.ProtocolError, server.get_student_id, stud_id)
510        # wrong username
511        server = ServerProxy('http://WRONGUSER:mgrpw@localhost/app')
512        self.assertRaises(
513            xmlrpclib.ProtocolError, server.get_student_id, stud_id)
514        return
Note: See TracBrowser for help on using the repository browser.