|
31 |
# <http://www.gnu.org/licenses/>. |
31 |
# <http://www.gnu.org/licenses/>. |
32 |
|
32 |
|
33 |
|
33 |
|
34 |
from BaseTest import BaseCase, TestError, ProcessFailedError |
34 |
from BaseTest import BaseCase, TestError |
35 |
|
35 |
|
36 |
|
36 |
|
37 |
class ObjectNotFoundError(TestError): |
37 |
class ObjectNotFoundError(TestError): |
Lines 47-52
class ObjectNotFoundError(TestError):
|
Link Here
|
---|
|
47 |
% (test.name, helper, test.modname) |
47 |
% (test.name, helper, test.modname) |
48 |
TestError.__init__(self, error, test) |
48 |
TestError.__init__(self, error, test) |
49 |
|
49 |
|
|
|
50 |
|
50 |
class LeftoverObjectFound(TestError): |
51 |
class LeftoverObjectFound(TestError): |
51 |
'''Assertion error in the Univention Admin test suite. |
52 |
'''Assertion error in the Univention Admin test suite. |
52 |
|
53 |
|
Lines 60-65
class LeftoverObjectFound(TestError):
|
Link Here
|
---|
|
60 |
% (test.name, helper, test.modname) |
61 |
% (test.name, helper, test.modname) |
61 |
TestError.__init__(self, error, test) |
62 |
TestError.__init__(self, error, test) |
62 |
|
63 |
|
|
|
64 |
|
63 |
class ObjectNotIdentifiedError(TestError): |
65 |
class ObjectNotIdentifiedError(TestError): |
64 |
'''Assertion error in the Univention Admin test suite. |
66 |
'''Assertion error in the Univention Admin test suite. |
65 |
|
67 |
|
Lines 70-75
class ObjectNotIdentifiedError(TestError):
|
Link Here
|
---|
|
70 |
% (test.name, dn, test.modname) |
72 |
% (test.name, dn, test.modname) |
71 |
TestError.__init__(self, error, test) |
73 |
TestError.__init__(self, error, test) |
72 |
|
74 |
|
|
|
75 |
|
73 |
class PropertyInvalidError(TestError): |
76 |
class PropertyInvalidError(TestError): |
74 |
'''Assertion error in the Univention Admin test suite. |
77 |
'''Assertion error in the Univention Admin test suite. |
75 |
|
78 |
|
Lines 81-90
class PropertyInvalidError(TestError):
|
Link Here
|
---|
|
81 |
e1 = 'Incorrect property %s (%s)' % (property, description) |
84 |
e1 = 'Incorrect property %s (%s)' % (property, description) |
82 |
e2 = 'of object %s at DN %s (module %s).' \ |
85 |
e2 = 'of object %s at DN %s (module %s).' \ |
83 |
% (test.name, dn, test.modname) |
86 |
% (test.name, dn, test.modname) |
84 |
e3= 'Expected: "%s" Actual: "%s"' % (expected, actual) |
87 |
e3 = 'Expected: "%s" Actual: "%s"' % (expected, actual) |
85 |
error = '%s %s %s' % (e1, e2, e3) |
88 |
error = '%s %s %s' % (e1, e2, e3) |
86 |
TestError.__init__(self, error, test) |
89 |
TestError.__init__(self, error, test) |
87 |
|
90 |
|
|
|
91 |
|
88 |
class ObjectClassNotPresentError(TestError): |
92 |
class ObjectClassNotPresentError(TestError): |
89 |
'''Assertion error in the Univention Admin test suite. |
93 |
'''Assertion error in the Univention Admin test suite. |
90 |
|
94 |
|
Lines 97-103
class ObjectClassNotPresentError(TestError):
|
Link Here
|
---|
|
97 |
% (option, description) |
101 |
% (option, description) |
98 |
e2 = 'of object %s at DN %s (module %s).' \ |
102 |
e2 = 'of object %s at DN %s (module %s).' \ |
99 |
% (test.name, dn, test.modname) |
103 |
% (test.name, dn, test.modname) |
100 |
e3= 'Expected: "%s" Actual: "%s"' % (expected, actual) |
104 |
e3 = 'Expected: "%s" Actual: "%s"' % (expected, actual) |
101 |
error = '%s %s %s' % (e1, e2, e3) |
105 |
error = '%s %s %s' % (e1, e2, e3) |
102 |
TestError.__init__(self, error, test) |
106 |
TestError.__init__(self, error, test) |
103 |
|
107 |
|
Lines 157-171
class GenericTestCase(BaseCase):
|
Link Here
|
---|
|
157 |
# NOTE: this filter might be a little fragile... |
161 |
# NOTE: this filter might be a little fragile... |
158 |
cmd.filter('%s="%s"' % (self.identifier, self.name)) |
162 |
cmd.filter('%s="%s"' % (self.identifier, self.name)) |
159 |
|
163 |
|
160 |
def __setupCommandUpdate(self, cmd, name, properties, options = None): |
164 |
def __setupCommandUpdate(self, cmd, name, properties, options=None): |
161 |
descriptions = self.module.property_descriptions |
165 |
descriptions = self.module.property_descriptions |
162 |
special = set(('position',)) |
166 |
special = set(('position',)) |
163 |
single = (p for p in properties |
167 |
single = ( |
164 |
if not p in special |
168 |
p for p in properties |
165 |
if not descriptions[p].multivalue) |
169 |
if p not in special |
166 |
multi = (p for p in properties |
170 |
if not descriptions[p].multivalue) |
167 |
if not p in special |
171 |
multi = ( |
168 |
if descriptions[p].multivalue) |
172 |
p for p in properties |
|
|
173 |
if p not in special |
174 |
if descriptions[p].multivalue) |
169 |
# set identifying property |
175 |
# set identifying property |
170 |
if name is not None: |
176 |
if name is not None: |
171 |
cmd.set(self.identifier, name) |
177 |
cmd.set(self.identifier, name) |
Lines 276-301
class GenericTestCase(BaseCase):
|
Link Here
|
---|
|
276 |
self.dn = dn |
282 |
self.dn = dn |
277 |
self.__leftover_dns.add(dn) |
283 |
self.__leftover_dns.add(dn) |
278 |
|
284 |
|
279 |
def testObjectExists(self, dn = None): |
285 |
def testObjectExists(self, dn=None): |
280 |
'''Check that the object exists. |
286 |
'''Check that the object exists. |
281 |
|
287 |
|
282 |
"DN", if given, indicates the DN of the object to test. |
288 |
"DN", if given, indicates the DN of the object to test. |
283 |
|
289 |
|
284 |
Raise "ObjectNotFoundError" if it does not exists. |
290 |
Raise "ObjectNotFoundError" if it does not exists. |
285 |
''' |
291 |
''' |
286 |
dn, attr = self.search(dn = dn) |
292 |
dn, attr = self.search(dn=dn) |
287 |
if attr is None: |
293 |
if attr is None: |
288 |
raise ObjectNotFoundError(self, dn) |
294 |
raise ObjectNotFoundError(self, dn) |
289 |
self.useDN(dn) |
295 |
self.useDN(dn) |
290 |
|
296 |
|
291 |
def testObjectExistsNot(self, dn = None): |
297 |
def testObjectExistsNot(self, dn=None): |
292 |
'''Check that the object does not exists. |
298 |
'''Check that the object does not exists. |
293 |
|
299 |
|
294 |
"DN", if given, indicates the DN of the object to test. |
300 |
"DN", if given, indicates the DN of the object to test. |
295 |
|
301 |
|
296 |
Raise "LeftoverObjectFound" if it does exists. |
302 |
Raise "LeftoverObjectFound" if it does exists. |
297 |
''' |
303 |
''' |
298 |
dn, attr = self.search(dn = dn) |
304 |
dn, attr = self.search(dn=dn) |
299 |
if bool(attr): |
305 |
if bool(attr): |
300 |
self.useDN(dn) |
306 |
self.useDN(dn) |
301 |
raise LeftoverObjectFound(self, dn) |
307 |
raise LeftoverObjectFound(self, dn) |
Lines 306-312
class GenericTestCase(BaseCase):
|
Link Here
|
---|
|
306 |
Raise "ObjectNotIdentifiedError" if the module cannot identify |
312 |
Raise "ObjectNotIdentifiedError" if the module cannot identify |
307 |
the current object. |
313 |
the current object. |
308 |
''' |
314 |
''' |
309 |
_, attr = self.search(dn = self.dn) |
315 |
_, attr = self.search(dn=self.dn) |
310 |
if not self.module.identify(self.dn, attr): |
316 |
if not self.module.identify(self.dn, attr): |
311 |
raise ObjectNotIdentifiedError(self, self.dn) |
317 |
raise ObjectNotIdentifiedError(self, self.dn) |
312 |
|
318 |
|
Lines 317-323
class GenericTestCase(BaseCase):
|
Link Here
|
---|
|
317 |
|
323 |
|
318 |
Raise "ObjectClassNotPresentError" if an option is not present. |
324 |
Raise "ObjectClassNotPresentError" if an option is not present. |
319 |
''' |
325 |
''' |
320 |
attr = self.ldap.get(dn = self.dn, attr = ['objectClass']) |
326 |
attr = self.ldap.get(dn=self.dn, attr=['objectClass']) |
321 |
for o in options: |
327 |
for o in options: |
322 |
classes = self.module.options[o].objectClasses |
328 |
classes = self.module.options[o].objectClasses |
323 |
if not classes: |
329 |
if not classes: |
Lines 336-349
class GenericTestCase(BaseCase):
|
Link Here
|
---|
|
336 |
values. |
342 |
values. |
337 |
''' |
343 |
''' |
338 |
special = set(('position',)) |
344 |
special = set(('position',)) |
339 |
props = (p for p in properties |
345 |
props = ( |
340 |
if not p in special |
346 |
p for p in properties |
341 |
if not p in self.uncheckedProperties) |
347 |
if p not in special |
342 |
obj = self.open(dn = self.dn) |
348 |
if p not in self.uncheckedProperties) |
|
|
349 |
obj = self.open(dn=self.dn) |
343 |
for prop in props: |
350 |
for prop in props: |
344 |
self._testProperty(prop, obj, properties) |
351 |
self._testProperty(prop, obj, properties) |
345 |
|
352 |
|
346 |
def create(self, properties, options = None, name = None): |
353 |
def create(self, properties, options=None, name=None): |
347 |
'''Create an object of the current module. |
354 |
'''Create an object of the current module. |
348 |
|
355 |
|
349 |
"Properties" is a mapping from property names to values. |
356 |
"Properties" is a mapping from property names to values. |
Lines 357-365
class GenericTestCase(BaseCase):
|
Link Here
|
---|
|
357 |
self.__setupCommandUpdate(cmd, name, properties, options) |
364 |
self.__setupCommandUpdate(cmd, name, properties, options) |
358 |
return cmd.run() |
365 |
return cmd.run() |
359 |
|
366 |
|
360 |
def modify(self, properties, dn = None, name = None, newName = None): |
367 |
def modify(self, properties, dn=None, name=None, newName=None): |
361 |
'''Modify an object of the current module. |
368 |
'''Modify an object of the current module. |
362 |
|
369 |
|
363 |
"Properties" is a mapping from property names to values; |
370 |
"Properties" is a mapping from property names to values; |
364 |
only values that should be changed need to be included. |
371 |
only values that should be changed need to be included. |
365 |
"DN", if given, is the DN of the object to modify. |
372 |
"DN", if given, is the DN of the object to modify. |
Lines 376-384
class GenericTestCase(BaseCase):
|
Link Here
|
---|
|
376 |
self.__setupCommandUpdate(cmd, newName, properties) |
383 |
self.__setupCommandUpdate(cmd, newName, properties) |
377 |
return cmd.run() |
384 |
return cmd.run() |
378 |
|
385 |
|
379 |
def remove(self, name = None, dn = None, recursive = False): |
386 |
def remove(self, name=None, dn=None, recursive=False): |
380 |
'''Remove an object of the current module. |
387 |
'''Remove an object of the current module. |
381 |
|
388 |
|
382 |
"Name" is the name of the object to remove (defaults to the current objects name). |
389 |
"Name" is the name of the object to remove (defaults to the current objects name). |
383 |
"DN", if given, is the DN of the object to remove. |
390 |
"DN", if given, is the DN of the object to remove. |
384 |
"Recursive" should be True to remove the object recursively. |
391 |
"Recursive" should be True to remove the object recursively. |
Lines 391-397
class GenericTestCase(BaseCase):
|
Link Here
|
---|
|
391 |
if recursive: |
398 |
if recursive: |
392 |
cmd.recursive() |
399 |
cmd.recursive() |
393 |
return cmd.run() |
400 |
return cmd.run() |
394 |
|
401 |
|
395 |
def hookAfterCreated(self, dn): |
402 |
def hookAfterCreated(self, dn): |
396 |
'''Perform additional actions after creating an object. |
403 |
'''Perform additional actions after creating an object. |
397 |
|
404 |
|
Lines 418-424
class GenericTestCase(BaseCase):
|
Link Here
|
---|
|
418 |
|
425 |
|
419 |
def setUp(self): |
426 |
def setUp(self): |
420 |
'''Hook method for setting up the test fixture before exercising it. |
427 |
'''Hook method for setting up the test fixture before exercising it. |
421 |
|
428 |
|
422 |
Override this method to set up values for these properties: |
429 |
Override this method to set up values for these properties: |
423 |
"name": The name of the object that will be tested. |
430 |
"name": The name of the object that will be tested. |
424 |
You most definitely want to set this one. |
431 |
You most definitely want to set this one. |
Lines 460-466
class GenericTestCase(BaseCase):
|
Link Here
|
---|
|
460 |
self.createOptions = set() |
467 |
self.createOptions = set() |
461 |
self.dn = None |
468 |
self.dn = None |
462 |
self.superordinate() |
469 |
self.superordinate() |
463 |
self.arg() |
|
|
464 |
self.__leftover_dns = set() |
470 |
self.__leftover_dns = set() |
465 |
|
471 |
|
466 |
def runTest(self): |
472 |
def runTest(self): |
Lines 484-491
class GenericTestCase(BaseCase):
|
Link Here
|
---|
|
484 |
is identified by the module and has the correct options and |
490 |
is identified by the module and has the correct options and |
485 |
property values set. |
491 |
property values set. |
486 |
''' |
492 |
''' |
487 |
proc = self.create(self.createProperties, |
493 |
proc = self.create(self.createProperties, self.createOptions) |
488 |
self.createOptions) |
|
|
489 |
self._checkProcess(proc, 'create') |
494 |
self._checkProcess(proc, 'create') |
490 |
self.testObjectExists(self.dn) |
495 |
self.testObjectExists(self.dn) |
491 |
self.testObjectIdentify() |
496 |
self.testObjectIdentify() |
Lines 500-506
class GenericTestCase(BaseCase):
|
Link Here
|
---|
|
500 |
exists, is identified by the module and has the correct property |
505 |
exists, is identified by the module and has the correct property |
501 |
values set. |
506 |
values set. |
502 |
''' |
507 |
''' |
503 |
proc = self.modify(self.modifyProperties, dn = self.dn) |
508 |
proc = self.modify(self.modifyProperties, dn=self.dn) |
504 |
self._checkProcess(proc, 'modify') |
509 |
self._checkProcess(proc, 'modify') |
505 |
if self.newName is not None: |
510 |
if self.newName is not None: |
506 |
self.dn = None |
511 |
self.dn = None |
Lines 516-522
class GenericTestCase(BaseCase):
|
Link Here
|
---|
|
516 |
This test removes the current object and then checks that it |
521 |
This test removes the current object and then checks that it |
517 |
does not exist any more. |
522 |
does not exist any more. |
518 |
''' |
523 |
''' |
519 |
proc = self.remove(dn = self.dn) |
524 |
proc = self.remove(dn=self.dn) |
520 |
self._checkProcess(proc, 'remove') |
525 |
self._checkProcess(proc, 'remove') |
521 |
self.testObjectExistsNot(self.dn) |
526 |
self.testObjectExistsNot(self.dn) |
522 |
self.hookAfterRemoved(self.dn) |
527 |
self.hookAfterRemoved(self.dn) |
Lines 529-535
class GenericTestCase(BaseCase):
|
Link Here
|
---|
|
529 |
When overriding this method, make sure you call to your superclass first! |
534 |
When overriding this method, make sure you call to your superclass first! |
530 |
''' |
535 |
''' |
531 |
for dn in self.__leftover_dns: |
536 |
for dn in self.__leftover_dns: |
532 |
self.remove(dn = dn, recursive = True) |
537 |
self.remove(dn=dn, recursive=True) |
533 |
|
538 |
|
534 |
def shortDescription(self): |
539 |
def shortDescription(self): |
535 |
return 'testing module %s' % self.modname |
540 |
return 'testing module %s' % self.modname |