~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-08-21 03:11:19 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:1037
Console: More clean up work to try and prevent coding errors from getting cmdQ 
and lineQ out of sync (that's very bad!). We now use functions to handle each 
request and the top level loop does the queue management. In short, don't mess 
directly with the queues unless you know what you're doing!

Also added in a ExistingConsole class (extends Console) which can be used to 
connect up an existing console process rather than a new one with most of the 
functionality of the Console class. (Basically you can't start a new console)

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
 
def root_to_subject_or_user(root, name):
98
 
    if name.startswith('~'):
99
 
        return root.users.get(name[1:])
100
 
    return root.subjects.get(name)
101
 
 
102
 
def subject_to_offering(subject, year, semester):
103
 
    return subject.offerings.get((int(year), int(semester)))
104
 
 
105
 
def offering_to_files(offering):
106
 
    return OfferingFiles(offering)
107
 
 
108
 
def offering_files_to_file(offeringfiles, *path):
109
 
    return OfferingFile(offeringfiles, path)
110
 
 
111
 
def offering_to_project(offering, name):
112
 
    return offering.projects.get(name)
113
 
 
114
 
def subject_url(subject):
115
 
    return (ROOT, subject.name)
116
 
 
117
 
def offering_url(offering):
118
 
    return (offering.subject, (str(offering.year), str(offering.semester)))
119
 
 
120
 
def offering_files_url(offeringfiles):
121
 
    return (offeringfiles.offering, '+files')
122
 
 
123
 
def project_url(project):
124
 
    return (project.offering, ('+projects', project.name))
125
 
 
126
 
class BaseTest(object):
127
 
    def setUp(self):
128
 
        r = Root()
129
 
        self.r = r
130
 
 
131
 
        # A user would be nice.
132
 
        r.add_user(User('jsmith'))
133
 
 
134
 
        # Give us some subjects...
135
 
        r.add_subject(Subject('info1', '600151'))
136
 
        r.add_subject(Subject('info2', '600152'))
137
 
        r.add_subject(Subject('info3', '600251'))
138
 
 
139
 
        # ... and some offerings.
140
 
        r.subjects['info1'].add_offering(Offering(self.r.subjects['info1'],
141
 
                                         2008, 1))
142
 
        r.subjects['info1'].add_offering(Offering(self.r.subjects['info1'],
143
 
                                         2008, 2))
144
 
        r.subjects['info1'].add_offering(Offering(self.r.subjects['info1'],
145
 
                                         2009, 1))
146
 
        r.subjects['info2'].add_offering(Offering(self.r.subjects['info2'],
147
 
                                         2008, 2))
148
 
        r.subjects['info2'].add_offering(Offering(self.r.subjects['info2'],
149
 
                                         2009, 1))
150
 
        r.subjects['info3'].add_offering(Offering(self.r.subjects['info3'],
151
 
                                         2009, 1))
152
 
 
153
 
        # A normal project...
154
 
        r.subjects['info1'].offerings[(2009, 1)].add_project(
155
 
            Project(r.subjects['info1'].offerings[(2009, 1)], 'p1')
156
 
            )
157
 
 
158
 
        # And one conflicting with a deep view, just to be nasty.
159
 
        r.subjects['info1'].offerings[(2009, 1)].add_project(
160
 
            Project(r.subjects['info1'].offerings[(2009, 1)], '+new')
161
 
            )
162
 
 
163
 
class TestResolution(BaseTest):
164
 
    def setUp(self):
165
 
        super(TestResolution, self).setUp()
166
 
        self.rtr = Publisher(root=self.r, viewset='browser')
167
 
        self.rtr.add_set_switch('api', 'api')
168
 
        self.rtr.add_forward(Root, None, root_to_subject_or_user, 1)
169
 
        self.rtr.add_forward(Subject, None, subject_to_offering, 2)
170
 
        self.rtr.add_forward(Offering, '+files', offering_to_files, 0)
171
 
        self.rtr.add_forward(OfferingFiles, None, offering_files_to_file, INF)
172
 
        self.rtr.add_forward(Offering, '+projects', offering_to_project, 1)
173
 
        self.rtr.add_view(User, None, UserServeView, viewset='browser')
174
 
        self.rtr.add_view(Subject, '+index', SubjectIndex, viewset='browser')
175
 
        self.rtr.add_view(Subject, '+edit', SubjectEdit, viewset='browser')
176
 
        self.rtr.add_view(Offering, '+index', OfferingIndex, viewset='browser')
177
 
        self.rtr.add_view(Offering, '+index', OfferingAPIIndex, viewset='api')
178
 
        self.rtr.add_view(OfferingFiles, '+index', OfferingFilesIndex,
179
 
                          viewset='browser')
180
 
        self.rtr.add_view(OfferingFile, '+index', OfferingFileIndex,
181
 
                          viewset='browser')
182
 
        self.rtr.add_view(Project, '+index', ProjectIndex, viewset='browser')
183
 
        self.rtr.add_view(Offering, ('+projects', '+new'), OfferingAddProject,
184
 
                          viewset='browser')
185
 
        self.rtr.add_view(Offering, ('+projects', '+index'), OfferingProjects,
186
 
                          viewset='browser')
187
 
 
188
 
    def testOneRoute(self):
189
 
        assert_equal(self.rtr.resolve('/info1'),
190
 
                     (self.r.subjects['info1'], SubjectIndex, ())
191
 
                     )
192
 
        assert_equal(self.rtr.resolve('/info3'),
193
 
                     (self.r.subjects['info3'], SubjectIndex, ())
194
 
                     )
195
 
 
196
 
    def testTwoRoutes(self):
197
 
        assert_equal(self.rtr.resolve('/info1/2009/1'),
198
 
             (self.r.subjects['info1'].offerings[(2009, 1)], OfferingIndex, ())
199
 
             )
200
 
        assert_equal(self.rtr.resolve('/info2/2008/2'),
201
 
             (self.r.subjects['info2'].offerings[(2008, 2)], OfferingIndex, ())
202
 
             )
203
 
 
204
 
    def testNamedRoute(self):
205
 
        assert_equal(type(self.rtr.resolve('/info1/2009/1/+files')[0]),
206
 
                     OfferingFiles
207
 
                    )
208
 
        assert_equal(self.rtr.resolve('/info1/2009/1/+files')[0].offering,
209
 
                     self.r.subjects['info1'].offerings[(2009, 1)]
210
 
                    )
211
 
 
212
 
    def testNonDefaultView(self):
213
 
        assert_equal(self.rtr.resolve('/info1/+edit'),
214
 
                     (self.r.subjects['info1'], SubjectEdit, ())
215
 
                     )
216
 
 
217
 
    def testDefaultView(self):
218
 
        assert_equal(self.rtr.resolve('/info1'),
219
 
                     (self.r.subjects['info1'], SubjectIndex, ())
220
 
                     )
221
 
 
222
 
    def testViewWithSubpath(self):
223
 
        assert_equal(self.rtr.resolve('/info1/+edit/foo/bar'),
224
 
                     (self.r.subjects['info1'], SubjectEdit, ('foo', 'bar'))
225
 
                     )
226
 
 
227
 
    def testNoDefaultView(self):
228
 
        try:
229
 
            self.rtr.default = 'not+index'
230
 
            self.rtr.resolve('/info1')
231
 
        except NotFound, e:
232
 
            assert_equal(e.args, (self.r.subjects['info1'], '+index', ()))
233
 
        except:
234
 
            raise
235
 
        else:
236
 
            raise AssertionError('did not raise NotFound')
237
 
        finally:
238
 
            self.rtr.default = '+index'
239
 
 
240
 
    def testMissingView(self):
241
 
        try:
242
 
            self.rtr.resolve('/info1/+foo')
243
 
        except NotFound, e:
244
 
            assert_equal(e.args, (self.r.subjects['info1'], '+foo', ()))
245
 
        except:
246
 
            raise
247
 
        else:
248
 
            raise AssertionError('did not raise NotFound')
249
 
 
250
 
    def testViewSetSeparation(self):
251
 
        try:
252
 
            self.rtr.resolve('/api/info1/+edit')
253
 
        except NotFound, e:
254
 
            assert_equal(e.args, (self.r.subjects['info1'], '+edit', ()))
255
 
        except:
256
 
            raise
257
 
        else:
258
 
            raise AssertionError('did not raise NotFound')
259
 
 
260
 
    def testRouteReturningNone(self):
261
 
        try:
262
 
            self.rtr.resolve('/info9/+index')
263
 
        except NotFound, e:
264
 
            assert_equal(e.args, (self.r, 'info9', ('+index',)))
265
 
        except:
266
 
            raise
267
 
        else:
268
 
            raise AssertionError('did not raise NotFound')
269
 
 
270
 
    def testRouteWithInfinitelyManyArguments(self):
271
 
        o, v, sp = self.rtr.resolve('/info1/2009/1/+files/foo/bar/baz')
272
 
 
273
 
        assert_equal(type(o), OfferingFile)
274
 
        assert_equal(o.path, ('foo', 'bar', 'baz'))
275
 
        assert_equal(o.offering, self.r.subjects['info1'].offerings[(2009, 1)])
276
 
        assert_equal(v, OfferingFileIndex)
277
 
        assert_equal(sp, ())
278
 
 
279
 
    def testMissingRoute(self):
280
 
        try:
281
 
            self.rtr.resolve('/info1/2009/1/+foo')
282
 
        except NotFound, e:
283
 
            assert_equal(e.args, (
284
 
                self.r.subjects['info1'].offerings[(2009, 1)],
285
 
                '+foo',
286
 
                ()
287
 
                ))
288
 
        except:
289
 
            raise
290
 
        else:
291
 
            raise AssertionError('did not raise NotFound')
292
 
 
293
 
    def testAlternateViewSetWithDefault(self):
294
 
        assert_equal(self.rtr.resolve('/info1/2009/1'),
295
 
             (self.r.subjects['info1'].offerings[(2009, 1)], OfferingIndex, ())
296
 
             )
297
 
 
298
 
        assert_equal(self.rtr.resolve('/api/info1/2009/1'),
299
 
          (self.r.subjects['info1'].offerings[(2009, 1)], OfferingAPIIndex, ())
300
 
          )
301
 
 
302
 
    def testDeepView(self):
303
 
        assert_equal(self.rtr.resolve('/info1/2009/1/+projects/+new'),
304
 
             (self.r.subjects['info1'].offerings[(2009, 1)],
305
 
              OfferingAddProject, ())
306
 
             )
307
 
 
308
 
    def testDefaultDeepView(self):
309
 
        assert_equal(self.rtr.resolve('/info1/2009/1/+projects'),
310
 
             (self.r.subjects['info1'].offerings[(2009, 1)],
311
 
              OfferingProjects, ())
312
 
             )
313
 
 
314
 
    def testNamedRouteWithDeepView(self):
315
 
        assert_equal(self.rtr.resolve('/info1/2009/1/+projects/p1'),
316
 
             (self.r.subjects['info1'].offerings[(2009, 1)].projects['p1'],
317
 
              ProjectIndex, ())
318
 
             )
319
 
 
320
 
    def testNullPathView(self):
321
 
        """Verify that views can be placed immediately under an object.
322
 
 
323
 
        There are some cases in which it is useful for a view with a
324
 
        subpath to exist immediately under an object, with no name.
325
 
        """
326
 
        assert_equal(self.rtr.resolve('/~jsmith/foo/bar'),
327
 
             (self.r.users['jsmith'], UserServeView, ('foo', 'bar')))
328
 
 
329
 
 
330
 
class TestGeneration(BaseTest):
331
 
    def setUp(self):
332
 
        super(TestGeneration, self).setUp()
333
 
        self.rtr = Publisher(root=self.r, viewset='browser')
334
 
        self.rtr.add_set_switch('api', 'api')
335
 
        self.rtr.add_reverse(Subject, subject_url)
336
 
        self.rtr.add_reverse(Offering, offering_url)
337
 
        self.rtr.add_reverse(OfferingFiles, offering_files_url)
338
 
        self.rtr.add_reverse(Project, project_url)
339
 
        self.rtr.add_view(Subject, '+index', SubjectIndex, viewset='browser')
340
 
        self.rtr.add_view(Subject, '+edit', SubjectEdit, viewset='browser')
341
 
        self.rtr.add_view(Offering, '+index', OfferingIndex, viewset='browser')
342
 
        self.rtr.add_view(Offering, '+index', OfferingAPIIndex, viewset='api')
343
 
        self.rtr.add_view(Project, '+index', ProjectIndex, viewset='browser')
344
 
        self.rtr.add_view(Offering, ('+projects', '+new'), OfferingAddProject,
345
 
                          viewset='browser')
346
 
        self.rtr.add_view(Offering, ('+projects', '+index'), OfferingProjects,
347
 
                          viewset='browser')
348
 
 
349
 
    def testOneLevel(self):
350
 
        assert_equal(self.rtr.generate(self.r.subjects['info1']), '/info1')
351
 
 
352
 
    def testTwoLevel(self):
353
 
        assert_equal(
354
 
            self.rtr.generate(self.r.subjects['info1'].offerings[(2009, 1)]),
355
 
            '/info1/2009/1'
356
 
            )
357
 
        assert_equal(
358
 
            self.rtr.generate(self.r.subjects['info2'].offerings[(2008, 2)]),
359
 
            '/info2/2008/2'
360
 
            )
361
 
 
362
 
    def testNamedRoute(self):
363
 
        assert_equal(self.rtr.generate(
364
 
                OfferingFiles(self.r.subjects['info1'].offerings[(2009, 1)])),
365
 
                '/info1/2009/1/+files'
366
 
            )
367
 
 
368
 
    def testView(self):
369
 
        assert_equal(self.rtr.generate(self.r.subjects['info1'], SubjectEdit),
370
 
                     '/info1/+edit'
371
 
                     )
372
 
 
373
 
    def testDefaultView(self):
374
 
        assert_equal(
375
 
            self.rtr.generate(self.r.subjects['info1'].offerings[(2009, 1)],
376
 
                              OfferingIndex
377
 
                              ),
378
 
            '/info1/2009/1'
379
 
            )
380
 
 
381
 
    def testViewWithSubpath(self):
382
 
        assert_equal(self.rtr.generate(self.r.subjects['info1'], SubjectEdit,
383
 
                                       ('foo', 'bar')),
384
 
                     '/info1/+edit/foo/bar'
385
 
                     )
386
 
 
387
 
    def testViewWithStringSubpath(self):
388
 
        assert_equal(self.rtr.generate(self.r.subjects['info1'], SubjectEdit,
389
 
                                       'foo/bar'),
390
 
                     '/info1/+edit/foo/bar'
391
 
                     )
392
 
 
393
 
    def testAlternateViewSetWithDefault(self):
394
 
        assert_equal(
395
 
            self.rtr.generate(self.r.subjects['info1'].offerings[(2009, 1)],
396
 
                              OfferingAPIIndex
397
 
                              ),
398
 
            '/api/info1/2009/1'
399
 
            )
400
 
 
401
 
    def testDeepView(self):
402
 
        assert_equal(
403
 
            self.rtr.generate(
404
 
                self.r.subjects['info1'].offerings[(2009, 1)],
405
 
                OfferingAddProject
406
 
                ),
407
 
        '/info1/2009/1/+projects/+new'
408
 
        )
409
 
 
410
 
    def testDefaultDeepView(self):
411
 
        assert_equal(
412
 
            self.rtr.generate(
413
 
                self.r.subjects['info1'].offerings[(2009, 1)],
414
 
                OfferingProjects
415
 
                ),
416
 
        '/info1/2009/1/+projects'
417
 
        )
418
 
 
419
 
    def testDefaultDeepViewWithSubpath(self):
420
 
        assert_equal(
421
 
            self.rtr.generate(
422
 
                self.r.subjects['info1'].offerings[(2009, 1)],
423
 
                OfferingProjects, ('foo', 'bar')
424
 
                ),
425
 
        '/info1/2009/1/+projects/+index/foo/bar'
426
 
        )
427
 
 
428
 
    def testNamedRouteWithDeepView(self):
429
 
        assert_equal(
430
 
            self.rtr.generate(
431
 
                self.r.subjects['info1'].offerings[(2009, 1)].projects['p1'],
432
 
                ProjectIndex
433
 
                ),
434
 
        '/info1/2009/1/+projects/p1'
435
 
        )
436
 
 
437
 
    def testRoot(self):
438
 
        assert_equal(self.rtr.generate(self.r), '/')
439
 
 
440
 
 
441
 
class TestErrors(BaseTest):
442
 
    def setUp(self):
443
 
        super(TestErrors, self).setUp()
444
 
        self.rtr = Publisher(root=self.r)
445
 
        self.rtr.add_forward(Root, None, root_to_subject_or_user, 1)
446
 
        self.rtr.add_forward(Subject, '+foo', lambda s: s.name + 'foo', 0)
447
 
        self.rtr.add_forward(Subject, None, subject_to_offering, 2)
448
 
        self.rtr.add_reverse(Subject, subject_url)
449
 
        self.rtr.add_reverse(Offering, offering_url)
450
 
        self.rtr.add_view(Offering, '+index', OfferingIndex)
451
 
        self.rtr.add_view(Offering, '+index', OfferingAPIIndex, viewset='api')
452
 
        self.rtr.add_set_switch('rest', 'rest')
453
 
 
454
 
    @raises(RouteConflict)
455
 
    def testForwardConflict(self):
456
 
        self.rtr.add_forward(Subject, '+foo', object(), 2)
457
 
 
458
 
    @raises(RouteConflict)
459
 
    def testReverseConflict(self):
460
 
        self.rtr.add_reverse(Subject, object())
461
 
 
462
 
    @raises(RouteConflict)
463
 
    def testViewConflict(self):
464
 
        self.rtr.add_view(Offering, '+index', object())
465
 
 
466
 
    @raises(RouteConflict)
467
 
    def testSetSwitchForwardConflict(self):
468
 
        self.rtr.add_set_switch('rest', 'foo')
469
 
 
470
 
    @raises(RouteConflict)
471
 
    def testSetSwitchReverseConflict(self):
472
 
        self.rtr.add_set_switch('bar', 'rest')
473
 
 
474
 
    @raises(NoPath)
475
 
    def testNoPath(self):
476
 
        self.rtr.generate(object())
477
 
 
478
 
    @raises(NoPath)
479
 
    def testNoSetSwitch(self):
480
 
        self.rtr.generate(self.r.subjects['info1'].offerings[(2009, 1)],
481
 
                          OfferingAPIIndex)
482
 
 
483
 
    @raises(NoPath)
484
 
    def testUnregisteredView(self):
485
 
        self.rtr.generate(self.r.subjects['info1'], SubjectIndex)
486
 
 
487
 
    @raises(NotFound)
488
 
    def testNotFound(self):
489
 
        self.rtr.resolve('/bar')
490
 
 
491
 
    @raises(InsufficientPathSegments)
492
 
    def testInsufficientPathSegments(self):
493
 
        self.rtr.resolve('/info1/foo')