~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to ivle/webapp/publisher/test_publisher.py

  • Committer: dcoles
  • Date: 2008-07-02 03:10:36 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:797
Setup: Addition of an automatic jail builder. This means we no longer are 
required to maintain an explicit list of files and libraries that can be easily 
broken by a single update to the system. It also goes a huge way to making IVLE 
not only more 'update maintainable' but portable to other Unix systems.  
(Should be fairly trivial if the system supports APT, should be able to be 
modified to support other package manager systems with a bit of work).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
from nose.tools import assert_equal, raises
2
 
 
3
 
from ivle.webapp.publisher import (INF, InsufficientPathSegments, NoPath,
4
 
                                   NotFound, RouteConflict, Publisher, ROOT)
5
 
 
6
 
class Root(object):
7
 
    def __init__(self):
8
 
        self.subjects = {}
9
 
        self.users = {}
10
 
 
11
 
    def add_subject(self, subject):
12
 
        self.subjects[subject.name] = subject
13
 
 
14
 
    def add_user(self, user):
15
 
        self.users[user.login] = user
16
 
 
17
 
class User(object):
18
 
    def __init__(self, login):
19
 
        self.login = login
20
 
 
21
 
class Subject(object):
22
 
    def __init__(self, name, code):
23
 
        self.name = name
24
 
        self.code = code
25
 
        self.offerings = {}
26
 
 
27
 
    def add_offering(self, offering):
28
 
        assert self.name == offering.subject.name
29
 
        self.offerings[(offering.year, offering.semester)] = offering
30
 
 
31
 
class Offering(object):
32
 
    def __init__(self, subject, year, semester):
33
 
        self.subject = subject
34
 
        self.year = year
35
 
        self.semester = semester
36
 
        self.projects = {}
37
 
 
38
 
    def add_project(self, project):
39
 
        assert project.offering is self
40
 
        self.projects[project.name] = project
41
 
 
42
 
class OfferingFiles(object):
43
 
    def __init__(self, offering):
44
 
        self.offering = offering
45
 
 
46
 
class OfferingFile(object):
47
 
    def __init__(self, offeringfiles, path):
48
 
        self.offering = offeringfiles.offering
49
 
        self.path = path
50
 
 
51
 
class Project(object):
52
 
    def __init__(self, offering, name):
53
 
        self.offering = offering
54
 
        self.name = name
55
 
 
56
 
 
57
 
class View(object):
58
 
    def __init__(self, context):
59
 
        self.context = context
60
 
 
61
 
class RootIndex(View):
62
 
    pass
63
 
 
64
 
class UserServeView(View):
65
 
    pass
66
 
 
67
 
class SubjectIndex(View):
68
 
    pass
69
 
 
70
 
class SubjectEdit(View):
71
 
    pass
72
 
 
73
 
class OfferingIndex(View):
74
 
    pass
75
 
 
76
 
class OfferingEdit(View):
77
 
    pass
78
 
 
79
 
class OfferingAPIIndex(View):
80
 
    pass
81
 
 
82
 
class OfferingFilesIndex(View):
83
 
    pass
84
 
 
85
 
class OfferingFileIndex(View):
86
 
    pass
87
 
 
88
 
class ProjectIndex(View):
89
 
    pass
90
 
 
91
 
class OfferingProjects(View):
92
 
    pass
93
 
 
94
 
class OfferingAddProject(View):
95
 
    pass
96
 
 
97
 
class OfferingWorksheets(View):
98
 
    pass
99
 
 
100
 
class OfferingWorksheetMarks(View):
101
 
    pass
102
 
 
103
 
class OfferingWorksheetCSVMarks(View):
104
 
    pass
105
 
 
106
 
def root_to_subject_or_user(root, name):
107
 
    if name.startswith('~'):
108
 
        return root.users.get(name[1:])
109
 
    return root.subjects.get(name)
110
 
 
111
 
def subject_to_offering(subject, year, semester):
112
 
    return subject.offerings.get((int(year), int(semester)))
113
 
 
114
 
def offering_to_files(offering):
115
 
    return OfferingFiles(offering)
116
 
 
117
 
def offering_files_to_file(offeringfiles, *path):
118
 
    return OfferingFile(offeringfiles, path)
119
 
 
120
 
def offering_to_project(offering, name):
121
 
    return offering.projects.get(name)
122
 
 
123
 
def subject_url(subject):
124
 
    return (ROOT, subject.name)
125
 
 
126
 
def offering_url(offering):
127
 
    return (offering.subject, (str(offering.year), str(offering.semester)))
128
 
 
129
 
def offering_files_url(offeringfiles):
130
 
    return (offeringfiles.offering, '+files')
131
 
 
132
 
def project_url(project):
133
 
    return (project.offering, ('+projects', project.name))
134
 
 
135
 
class BaseTest(object):
136
 
    def setUp(self):
137
 
        r = Root()
138
 
        self.r = r
139
 
 
140
 
        # A user would be nice.
141
 
        r.add_user(User('jsmith'))
142
 
 
143
 
        # Give us some subjects...
144
 
        r.add_subject(Subject('info1', '600151'))
145
 
        r.add_subject(Subject('info2', '600152'))
146
 
        r.add_subject(Subject('info3', '600251'))
147
 
 
148
 
        # ... and some offerings.
149
 
        r.subjects['info1'].add_offering(Offering(self.r.subjects['info1'],
150
 
                                         2008, 1))
151
 
        r.subjects['info1'].add_offering(Offering(self.r.subjects['info1'],
152
 
                                         2008, 2))
153
 
        r.subjects['info1'].add_offering(Offering(self.r.subjects['info1'],
154
 
                                         2009, 1))
155
 
        r.subjects['info2'].add_offering(Offering(self.r.subjects['info2'],
156
 
                                         2008, 2))
157
 
        r.subjects['info2'].add_offering(Offering(self.r.subjects['info2'],
158
 
                                         2009, 1))
159
 
        r.subjects['info3'].add_offering(Offering(self.r.subjects['info3'],
160
 
                                         2009, 1))
161
 
 
162
 
        # A normal project...
163
 
        r.subjects['info1'].offerings[(2009, 1)].add_project(
164
 
            Project(r.subjects['info1'].offerings[(2009, 1)], 'p1')
165
 
            )
166
 
 
167
 
        # And one conflicting with a deep view, just to be nasty.
168
 
        r.subjects['info1'].offerings[(2009, 1)].add_project(
169
 
            Project(r.subjects['info1'].offerings[(2009, 1)], '+new')
170
 
            )
171
 
 
172
 
class TestResolution(BaseTest):
173
 
    def setUp(self):
174
 
        super(TestResolution, self).setUp()
175
 
        self.rtr = Publisher(root=self.r, viewset='browser')
176
 
        self.rtr.add_set_switch('api', 'api')
177
 
        self.rtr.add_forward(Root, None, root_to_subject_or_user, 1)
178
 
        self.rtr.add_forward(Subject, None, subject_to_offering, 2)
179
 
        self.rtr.add_forward(Offering, '+files', offering_to_files, 0)
180
 
        self.rtr.add_forward(OfferingFiles, None, offering_files_to_file, INF)
181
 
        self.rtr.add_forward(Offering, '+projects', offering_to_project, 1)
182
 
        self.rtr.add_view(User, None, UserServeView, viewset='browser')
183
 
        self.rtr.add_view(Subject, '+index', SubjectIndex, viewset='browser')
184
 
        self.rtr.add_view(Subject, '+edit', SubjectEdit, viewset='browser')
185
 
        self.rtr.add_view(Offering, '+index', OfferingIndex, viewset='browser')
186
 
        self.rtr.add_view(Offering, '+index', OfferingAPIIndex, viewset='api')
187
 
        self.rtr.add_view(OfferingFiles, '+index', OfferingFilesIndex,
188
 
                          viewset='browser')
189
 
        self.rtr.add_view(OfferingFile, '+index', OfferingFileIndex,
190
 
                          viewset='browser')
191
 
        self.rtr.add_view(Project, '+index', ProjectIndex, viewset='browser')
192
 
        self.rtr.add_view(Offering, ('+projects', '+new'), OfferingAddProject,
193
 
                          viewset='browser')
194
 
        self.rtr.add_view(Offering, ('+projects', '+index'), OfferingProjects,
195
 
                          viewset='browser')
196
 
        self.rtr.add_view(Offering, ('+worksheets', '+index'),
197
 
                          OfferingWorksheets, viewset='browser')
198
 
        self.rtr.add_view(Offering, ('+worksheets', '+marks', '+index'),
199
 
                          OfferingWorksheetMarks, viewset='browser')
200
 
        self.rtr.add_view(Offering, ('+worksheets', '+marks', 'marks.csv'),
201
 
                          OfferingWorksheetCSVMarks, viewset='browser')
202
 
 
203
 
    def testOneRoute(self):
204
 
        assert_equal(self.rtr.resolve('/info1'),
205
 
                     (self.r.subjects['info1'], SubjectIndex, ())
206
 
                     )
207
 
        assert_equal(self.rtr.resolve('/info3'),
208
 
                     (self.r.subjects['info3'], SubjectIndex, ())
209
 
                     )
210
 
 
211
 
    def testTwoRoutes(self):
212
 
        assert_equal(self.rtr.resolve('/info1/2009/1'),
213
 
             (self.r.subjects['info1'].offerings[(2009, 1)], OfferingIndex, ())
214
 
             )
215
 
        assert_equal(self.rtr.resolve('/info2/2008/2'),
216
 
             (self.r.subjects['info2'].offerings[(2008, 2)], OfferingIndex, ())
217
 
             )
218
 
 
219
 
    def testNamedRoute(self):
220
 
        assert_equal(type(self.rtr.resolve('/info1/2009/1/+files')[0]),
221
 
                     OfferingFiles
222
 
                    )
223
 
        assert_equal(self.rtr.resolve('/info1/2009/1/+files')[0].offering,
224
 
                     self.r.subjects['info1'].offerings[(2009, 1)]
225
 
                    )
226
 
 
227
 
    def testNonDefaultView(self):
228
 
        assert_equal(self.rtr.resolve('/info1/+edit'),
229
 
                     (self.r.subjects['info1'], SubjectEdit, ())
230
 
                     )
231
 
 
232
 
    def testDefaultView(self):
233
 
        assert_equal(self.rtr.resolve('/info1'),
234
 
                     (self.r.subjects['info1'], SubjectIndex, ())
235
 
                     )
236
 
 
237
 
    def testViewWithSubpath(self):
238
 
        assert_equal(self.rtr.resolve('/info1/+edit/foo/bar'),
239
 
                     (self.r.subjects['info1'], SubjectEdit, ('foo', 'bar'))
240
 
                     )
241
 
 
242
 
    def testNoDefaultView(self):
243
 
        try:
244
 
            self.rtr.default = 'not+index'
245
 
            self.rtr.resolve('/info1')
246
 
        except NotFound, e:
247
 
            assert_equal(e.args, (self.r.subjects['info1'], '+index', ()))
248
 
        except:
249
 
            raise
250
 
        else:
251
 
            raise AssertionError('did not raise NotFound')
252
 
        finally:
253
 
            self.rtr.default = '+index'
254
 
 
255
 
    def testMissingView(self):
256
 
        try:
257
 
            self.rtr.resolve('/info1/+foo')
258
 
        except NotFound, e:
259
 
            assert_equal(e.args, (self.r.subjects['info1'], '+foo', ()))
260
 
        except:
261
 
            raise
262
 
        else:
263
 
            raise AssertionError('did not raise NotFound')
264
 
 
265
 
    def testViewSetSeparation(self):
266
 
        try:
267
 
            self.rtr.resolve('/api/info1/+edit')
268
 
        except NotFound, e:
269
 
            assert_equal(e.args, (self.r.subjects['info1'], '+edit', ()))
270
 
        except:
271
 
            raise
272
 
        else:
273
 
            raise AssertionError('did not raise NotFound')
274
 
 
275
 
    def testRouteReturningNone(self):
276
 
        try:
277
 
            self.rtr.resolve('/info9/+index')
278
 
        except NotFound, e:
279
 
            assert_equal(e.args, (self.r, 'info9', ('+index',)))
280
 
        except:
281
 
            raise
282
 
        else:
283
 
            raise AssertionError('did not raise NotFound')
284
 
 
285
 
    def testRouteWithInfinitelyManyArguments(self):
286
 
        o, v, sp = self.rtr.resolve('/info1/2009/1/+files/foo/bar/baz')
287
 
 
288
 
        assert_equal(type(o), OfferingFile)
289
 
        assert_equal(o.path, ('foo', 'bar', 'baz'))
290
 
        assert_equal(o.offering, self.r.subjects['info1'].offerings[(2009, 1)])
291
 
        assert_equal(v, OfferingFileIndex)
292
 
        assert_equal(sp, ())
293
 
 
294
 
    def testMissingRoute(self):
295
 
        try:
296
 
            self.rtr.resolve('/info1/2009/1/+foo')
297
 
        except NotFound, e:
298
 
            assert_equal(e.args, (
299
 
                self.r.subjects['info1'].offerings[(2009, 1)],
300
 
                '+foo',
301
 
                ()
302
 
                ))
303
 
        except:
304
 
            raise
305
 
        else:
306
 
            raise AssertionError('did not raise NotFound')
307
 
 
308
 
    def testAlternateViewSetWithDefault(self):
309
 
        assert_equal(self.rtr.resolve('/info1/2009/1'),
310
 
             (self.r.subjects['info1'].offerings[(2009, 1)], OfferingIndex, ())
311
 
             )
312
 
 
313
 
        assert_equal(self.rtr.resolve('/api/info1/2009/1'),
314
 
          (self.r.subjects['info1'].offerings[(2009, 1)], OfferingAPIIndex, ())
315
 
          )
316
 
 
317
 
    def testDeepView(self):
318
 
        assert_equal(self.rtr.resolve('/info1/2009/1/+projects/+new'),
319
 
             (self.r.subjects['info1'].offerings[(2009, 1)],
320
 
              OfferingAddProject, ())
321
 
             )
322
 
 
323
 
    def testDefaultDeepView(self):
324
 
        assert_equal(self.rtr.resolve('/info1/2009/1/+projects'),
325
 
             (self.r.subjects['info1'].offerings[(2009, 1)],
326
 
              OfferingProjects, ())
327
 
             )
328
 
 
329
 
    def testAnotherDefaultDeepView(self):
330
 
        assert_equal(self.rtr.resolve('/info1/2009/1/+worksheets'),
331
 
             (self.r.subjects['info1'].offerings[(2009, 1)],
332
 
              OfferingWorksheets, ())
333
 
             )
334
 
 
335
 
    def testReallyDeepView(self):
336
 
        assert_equal(
337
 
             self.rtr.resolve('/info1/2009/1/+worksheets/+marks/marks.csv'),
338
 
             (self.r.subjects['info1'].offerings[(2009, 1)],
339
 
              OfferingWorksheetCSVMarks, ())
340
 
             )
341
 
 
342
 
    def testDefaultReallyDeepView(self):
343
 
        assert_equal(self.rtr.resolve('/info1/2009/1/+worksheets/+marks'),
344
 
             (self.r.subjects['info1'].offerings[(2009, 1)],
345
 
              OfferingWorksheetMarks, ())
346
 
             )
347
 
 
348
 
    def testNamedRouteWithDeepView(self):
349
 
        assert_equal(self.rtr.resolve('/info1/2009/1/+projects/p1'),
350
 
             (self.r.subjects['info1'].offerings[(2009, 1)].projects['p1'],
351
 
              ProjectIndex, ())
352
 
             )
353
 
 
354
 
    def testNullPathView(self):
355
 
        """Verify that views can be placed immediately under an object.
356
 
 
357
 
        There are some cases in which it is useful for a view with a
358
 
        subpath to exist immediately under an object, with no name.
359
 
        """
360
 
        assert_equal(self.rtr.resolve('/~jsmith/foo/bar'),
361
 
             (self.r.users['jsmith'], UserServeView, ('foo', 'bar')))
362
 
 
363
 
    def testTrailingSlashResolvesToDefaultView(self):
364
 
        assert_equal(
365
 
             self.rtr.resolve('/info1/2009/1/'),
366
 
             (self.r.subjects['info1'].offerings[(2009, 1)],
367
 
              OfferingIndex, ())
368
 
             )
369
 
 
370
 
    def testTrailingSlashResolvesToDeepDefaultView(self):
371
 
        assert_equal(
372
 
             self.rtr.resolve('/info1/2009/1/+worksheets/+marks/'),
373
 
             (self.r.subjects['info1'].offerings[(2009, 1)],
374
 
              OfferingWorksheetMarks, ())
375
 
             )
376
 
 
377
 
    def testSubpathIndicatesTrailingSlash(self):
378
 
        assert_equal(
379
 
             self.rtr.resolve('/info1/2009/1/+index/'),
380
 
             (self.r.subjects['info1'].offerings[(2009, 1)],
381
 
              OfferingIndex, ('',))
382
 
             )
383
 
 
384
 
class TestGeneration(BaseTest):
385
 
    def setUp(self):
386
 
        super(TestGeneration, self).setUp()
387
 
        self.rtr = Publisher(root=self.r, viewset='browser')
388
 
        self.rtr.add_set_switch('api', 'api')
389
 
        self.rtr.add_reverse(Subject, subject_url)
390
 
        self.rtr.add_reverse(Offering, offering_url)
391
 
        self.rtr.add_reverse(OfferingFiles, offering_files_url)
392
 
        self.rtr.add_reverse(Project, project_url)
393
 
        self.rtr.add_view(Subject, '+index', SubjectIndex, viewset='browser')
394
 
        self.rtr.add_view(Subject, '+edit', SubjectEdit, viewset='browser')
395
 
        self.rtr.add_view(Offering, '+index', OfferingIndex, viewset='browser')
396
 
        self.rtr.add_view(Offering, '+index', OfferingAPIIndex, viewset='api')
397
 
        self.rtr.add_view(Project, '+index', ProjectIndex, viewset='browser')
398
 
        self.rtr.add_view(Offering, ('+projects', '+new'), OfferingAddProject,
399
 
                          viewset='browser')
400
 
        self.rtr.add_view(Offering, ('+projects', '+index'), OfferingProjects,
401
 
                          viewset='browser')
402
 
 
403
 
    def testOneLevel(self):
404
 
        assert_equal(self.rtr.generate(self.r.subjects['info1']), '/info1')
405
 
 
406
 
    def testTwoLevel(self):
407
 
        assert_equal(
408
 
            self.rtr.generate(self.r.subjects['info1'].offerings[(2009, 1)]),
409
 
            '/info1/2009/1'
410
 
            )
411
 
        assert_equal(
412
 
            self.rtr.generate(self.r.subjects['info2'].offerings[(2008, 2)]),
413
 
            '/info2/2008/2'
414
 
            )
415
 
 
416
 
    def testNamedRoute(self):
417
 
        assert_equal(self.rtr.generate(
418
 
                OfferingFiles(self.r.subjects['info1'].offerings[(2009, 1)])),
419
 
                '/info1/2009/1/+files'
420
 
            )
421
 
 
422
 
    def testView(self):
423
 
        assert_equal(self.rtr.generate(self.r.subjects['info1'], SubjectEdit),
424
 
                     '/info1/+edit'
425
 
                     )
426
 
 
427
 
    def testDefaultView(self):
428
 
        assert_equal(
429
 
            self.rtr.generate(self.r.subjects['info1'].offerings[(2009, 1)],
430
 
                              OfferingIndex
431
 
                              ),
432
 
            '/info1/2009/1'
433
 
            )
434
 
 
435
 
    def testViewWithSubpath(self):
436
 
        assert_equal(self.rtr.generate(self.r.subjects['info1'], SubjectEdit,
437
 
                                       ('foo', 'bar')),
438
 
                     '/info1/+edit/foo/bar'
439
 
                     )
440
 
 
441
 
    def testViewWithStringSubpath(self):
442
 
        assert_equal(self.rtr.generate(self.r.subjects['info1'], SubjectEdit,
443
 
                                       'foo/bar'),
444
 
                     '/info1/+edit/foo/bar'
445
 
                     )
446
 
 
447
 
    def testAlternateViewSetWithDefault(self):
448
 
        assert_equal(
449
 
            self.rtr.generate(self.r.subjects['info1'].offerings[(2009, 1)],
450
 
                              OfferingAPIIndex
451
 
                              ),
452
 
            '/api/info1/2009/1'
453
 
            )
454
 
 
455
 
    def testDeepView(self):
456
 
        assert_equal(
457
 
            self.rtr.generate(
458
 
                self.r.subjects['info1'].offerings[(2009, 1)],
459
 
                OfferingAddProject
460
 
                ),
461
 
        '/info1/2009/1/+projects/+new'
462
 
        )
463
 
 
464
 
    def testDefaultDeepView(self):
465
 
        assert_equal(
466
 
            self.rtr.generate(
467
 
                self.r.subjects['info1'].offerings[(2009, 1)],
468
 
                OfferingProjects
469
 
                ),
470
 
        '/info1/2009/1/+projects'
471
 
        )
472
 
 
473
 
    def testDefaultDeepViewWithSubpath(self):
474
 
        assert_equal(
475
 
            self.rtr.generate(
476
 
                self.r.subjects['info1'].offerings[(2009, 1)],
477
 
                OfferingProjects, ('foo', 'bar')
478
 
                ),
479
 
        '/info1/2009/1/+projects/+index/foo/bar'
480
 
        )
481
 
 
482
 
    def testNamedRouteWithDeepView(self):
483
 
        assert_equal(
484
 
            self.rtr.generate(
485
 
                self.r.subjects['info1'].offerings[(2009, 1)].projects['p1'],
486
 
                ProjectIndex
487
 
                ),
488
 
        '/info1/2009/1/+projects/p1'
489
 
        )
490
 
 
491
 
    def testRoot(self):
492
 
        assert_equal(self.rtr.generate(self.r), '/')
493
 
 
494
 
 
495
 
class TestErrors(BaseTest):
496
 
    def setUp(self):
497
 
        super(TestErrors, self).setUp()
498
 
        self.rtr = Publisher(root=self.r)
499
 
        self.rtr.add_forward(Root, None, root_to_subject_or_user, 1)
500
 
        self.rtr.add_forward(Subject, '+foo', lambda s: s.name + 'foo', 0)
501
 
        self.rtr.add_forward(Subject, None, subject_to_offering, 2)
502
 
        self.rtr.add_reverse(Subject, subject_url)
503
 
        self.rtr.add_reverse(Offering, offering_url)
504
 
        self.rtr.add_view(Offering, '+index', OfferingIndex)
505
 
        self.rtr.add_view(Offering, '+index', OfferingAPIIndex, viewset='api')
506
 
        self.rtr.add_set_switch('rest', 'rest')
507
 
 
508
 
    @raises(RouteConflict)
509
 
    def testForwardConflict(self):
510
 
        self.rtr.add_forward(Subject, '+foo', object(), 2)
511
 
 
512
 
    @raises(RouteConflict)
513
 
    def testReverseConflict(self):
514
 
        self.rtr.add_reverse(Subject, object())
515
 
 
516
 
    @raises(RouteConflict)
517
 
    def testViewConflict(self):
518
 
        self.rtr.add_view(Offering, '+index', object())
519
 
 
520
 
    @raises(RouteConflict)
521
 
    def testSetSwitchForwardConflict(self):
522
 
        self.rtr.add_set_switch('rest', 'foo')
523
 
 
524
 
    @raises(RouteConflict)
525
 
    def testSetSwitchReverseConflict(self):
526
 
        self.rtr.add_set_switch('bar', 'rest')
527
 
 
528
 
    @raises(NoPath)
529
 
    def testNoPath(self):
530
 
        self.rtr.generate(object())
531
 
 
532
 
    @raises(NoPath)
533
 
    def testNoSetSwitch(self):
534
 
        self.rtr.generate(self.r.subjects['info1'].offerings[(2009, 1)],
535
 
                          OfferingAPIIndex)
536
 
 
537
 
    @raises(NoPath)
538
 
    def testUnregisteredView(self):
539
 
        self.rtr.generate(self.r.subjects['info1'], SubjectIndex)
540
 
 
541
 
    @raises(NotFound)
542
 
    def testNotFound(self):
543
 
        self.rtr.resolve('/bar')
544
 
 
545
 
    @raises(InsufficientPathSegments)
546
 
    def testInsufficientPathSegments(self):
547
 
        self.rtr.resolve('/info1/foo')