source: main/waeup.kofa/branches/uli-rm-bootstrap/src/waeup/kofa/students/tests/test_webservices.py @ 17463

Last change on this file since 17463 was 14681, checked in by Henrik Bettermann, 8 years ago

Add logging message.

  • Property svn:keywords set to Id
File size: 17.8 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="finger1.fpm")
438        self.assertEqual(stored_file.read(), 'FP1faked_fpm')
439        # storing is logged
440        logfile = os.path.join(
441            self.app['datacenter'].storage, 'logs', 'students.log')
442        logcontent = open(logfile).read()
443        self.assertTrue(
444            'zope.mgr - grok.meta.StudentsXMLRPC '
445            '- K1000000 - fingerprint stored' in logcontent)
446
447    def test_put_student_fingerprints_existing(self):
448        # existing fingerprints are overwritten
449        server = ServerProxy('http://mgr:mgrpw@localhost/app')
450        self.setup_student(self.student)
451        self.create_fpm_file(self.student, '1')
452        fpm1 = xmlrpclib.Binary('FP1faked_fpm1')
453        fpm2 = xmlrpclib.Binary('FP1faked_fpm2')
454        result = server.put_student_fingerprints(
455            self.student.student_id, {'1': fpm1, '3': fpm2})
456        self.assertEqual(result, True)
457        stored_file1 = getUtility(IExtFileStore).getFileByContext(
458            self.student, attr="finger1.fpm")
459        stored_file2 = getUtility(IExtFileStore).getFileByContext(
460            self.student, attr="finger3.fpm")
461        self.assertEqual(stored_file1.read(), 'FP1faked_fpm1')
462        self.assertEqual(stored_file2.read(), 'FP1faked_fpm2')
463
464    def test_get_student_fingerprints_no_stud(self):
465        # invalid student ids result in empty dict
466        server = ServerProxy('http://mgr:mgrpw@localhost/app')
467        result = server.get_student_fingerprints('invalid id')
468        self.assertEqual(result, {})
469
470    def test_get_student_fingerprints_no_files(self):
471        # we get student data, but no fingerprints if not stored before
472        server = ServerProxy('http://mgr:mgrpw@localhost/app')
473        self.setup_student(self.student)
474        result = server.get_student_fingerprints(self.student.student_id)
475        self.assertEqual(
476            result,
477            {'lastname': 'Tester',
478             'email': 'aa@aa.ng',
479             'firstname': 'Anna',
480             'fingerprints': {},
481             'img': None,
482             'img_name': None,
483             })
484
485    def test_get_student_fingerprints_passport(self):
486        # we get a photograph of the student if avail.
487        server = ServerProxy('http://mgr:mgrpw@localhost/app')
488        self.setup_student(self.student)
489        self.create_passport_img(self.student)
490        result = server.get_student_fingerprints(self.student.student_id)
491        self.assertTrue(
492            isinstance(result['img'], xmlrpclib.Binary))
493        self.assertEqual(result['img_name'], 'passport_K1000000.jpg')
494
495    def test_get_student_fingerprints_fpm(self):
496        # we get minutiae files if any are avail.
497        server = ServerProxy('http://mgr:mgrpw@localhost/app')
498        self.setup_student(self.student)
499        self.create_fpm_file(self.student, 'finger1')
500        result = server.get_student_fingerprints(self.student.student_id)
501        self.assertTrue('1' in result['fingerprints'].keys())
502        self.assertTrue(
503            isinstance(result['fingerprints']['1'], xmlrpclib.Binary))
504
505    def test_get_student_fingerprints_block_unauthorized(self):
506        # requests from unauthorized users are blocked
507        # no username nor password
508        server = ServerProxy('http://localhost/app')
509        self.setup_student(self.student)
510        stud_id = self.student.student_id
511        self.assertRaises(
512            xmlrpclib.ProtocolError, server.get_student_id, stud_id)
513        # wrong password
514        server = ServerProxy('http://mgr:WRONGPW@localhost/app')
515        self.assertRaises(
516            xmlrpclib.ProtocolError, server.get_student_id, stud_id)
517        # wrong username
518        server = ServerProxy('http://WRONGUSER:mgrpw@localhost/app')
519        self.assertRaises(
520            xmlrpclib.ProtocolError, server.get_student_id, stud_id)
521        return
Note: See TracBrowser for help on using the repository browser.