home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / pyshared / checkbox / traverser.py < prev    next >
Encoding:
Python Source  |  2009-04-27  |  7.1 KB  |  199 lines

  1. #
  2. # This file is part of Checkbox.
  3. #
  4. # Copyright 2008 Canonical Ltd.
  5. #
  6. # Checkbox is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # Checkbox is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with Checkbox.  If not, see <http://www.gnu.org/licenses/>.
  18. #
  19. """
  20. The traverser exposes a simple iterator interface for accessing the graph
  21. of tests as expressed by the dependency tree. The constructor provides an
  22. additional callbacks instance for processing tests which might be skipped.
  23. """
  24.  
  25. import logging
  26.  
  27. from checkbox.lib.iterator import (Iterator, IteratorContain,
  28.     IteratorExclude, IteratorPostRepeat, IteratorPreRepeat)
  29.  
  30. from checkbox.resolver import Resolver
  31. from checkbox.test import FAIL, SKIP
  32.  
  33.  
  34. class TraverserCallbacks(object):
  35.  
  36.     def get_architecture(self):
  37.         return None
  38.  
  39.     def get_category(self):
  40.         return None
  41.  
  42.     def get_priorities(self):
  43.         return []
  44.  
  45.     def skipped_dependent(self, test, result):
  46.         logging.info("Test '%s' dependent on skipped test",
  47.             test.name)
  48.  
  49.     def failed_dependent(self, test, result):
  50.         logging.info("Test '%s' dependent on failed test",
  51.             test.name)
  52.  
  53.     def unsupported_requires(self, test, result):
  54.         logging.info("Test '%s' does not support requires field: %s",
  55.             test.name, test.requires)
  56.  
  57.     def undefined_architecture(self, test, result):
  58.         logging.info("No system architecture defined, skipping test: %s",
  59.             test.name)
  60.  
  61.     def unsupported_architecture(self, test, result):
  62.         logging.info("System architecture not supported, skipping test: %s",
  63.             test.name)
  64.  
  65.     def undefined_category(self, test, result):
  66.         logging.info("No system category defined, skipping test: %s",
  67.             test.name)
  68.  
  69.     def unsupported_category(self, test, result):
  70.         logging.info("System category not supported, skipping test: %s",
  71.             test.name)
  72.  
  73.  
  74. class Traverser(IteratorContain):
  75.  
  76.     def __init__(self, tests=[], callbacks=TraverserCallbacks, *args, **kwargs):
  77.         self._callbacks = callbacks(*args, **kwargs)
  78.  
  79.         self._dependent_next = []
  80.         self._dependent_prev = []
  81.         self._dependent_status = None
  82.  
  83.         # Express dependents as objects rather than string names
  84.         resolver = Resolver(self._compare_func)
  85.         test_dict = dict(((t.suite, t.name), t) for t in tests)
  86.         for test in tests:
  87.             test_depends = [test_dict[(test.suite, d)] for d in test.depends]
  88.             resolver.add(test, *test_depends)
  89.  
  90.         tests = resolver.get_dependents()
  91.         iterator = Iterator(tests)
  92.         iterator = IteratorExclude(iterator,
  93.             self._requires_exclude_func,
  94.             self._requires_exclude_func)
  95.         iterator = IteratorExclude(iterator,
  96.             self._architecture_exclude_func,
  97.             self._architecture_exclude_func)
  98.         iterator = IteratorExclude(iterator,
  99.             self._category_exclude_func,
  100.             self._category_exclude_func)
  101.         iterator = IteratorExclude(iterator,
  102.             self._dependent_exclude_next_func,
  103.             self._dependent_exclude_prev_func)
  104.         iterator = IteratorPreRepeat(iterator,
  105.             lambda test, result, resolver=resolver: \
  106.                    self._dependent_prerepeat_next_func(test, result, resolver))
  107.         iterator = IteratorPostRepeat(iterator,
  108.             prev_func=lambda test, result, resolver=resolver: \
  109.                    self._dependent_prerepeat_prev_func(test, result, resolver))
  110.  
  111.         super(Traverser, self).__init__(iterator)
  112.  
  113.     def _compare_func(self, a, b):
  114.         priorities = self._callbacks.get_priorities()
  115.         if a.plugin in priorities:
  116.             if b.plugin in priorities:
  117.                 ia = priorities.index(a.plugin)
  118.                 ib = priorities.index(b.plugin)
  119.                 if ia != ib:
  120.                     return cmp(ia, ib)
  121.             else:
  122.                 return -1
  123.         elif b.plugin in priorities:
  124.             return 1
  125.  
  126.         return cmp((a.suite, a.name), (b.suite, b.name))
  127.  
  128.     def _dependent_prerepeat_next_func(self, test, result, resolver):
  129.         """IteratorPreRepeat function which completely skips dependents
  130.            of tests which either have a status of FAIL or SKIP."""
  131.         if result and result.test == test:
  132.             if result.status == FAIL or result.status == SKIP:
  133.                 self._dependent_next = resolver.get_dependents(test)
  134.                 self._dependent_status = result.status
  135.             else:
  136.                 self._dependent_next = []
  137.  
  138.         self._dependent_prev.append(test)
  139.  
  140.     def _dependent_prerepeat_prev_func(self, test, result, resolver):
  141.         """IteratorPreRepeat function which supplements the above by
  142.            keeping track of a stack of previously run tests."""
  143.         self._dependent_prev.pop()
  144.  
  145.     def _dependent_exclude_next_func(self, test, result):
  146.         if test in self._dependent_next:
  147.             if self._dependent_status == FAIL:
  148.                 self._callbacks.failed_dependent(test, result)
  149.             elif self._dependent_status == SKIP:
  150.                 self._callbacks.skipped_dependent(test, result)
  151.             return True
  152.  
  153.         return False
  154.  
  155.     def _dependent_exclude_prev_func(self, test, result):
  156.         if self._dependent_prev[-1] != test:
  157.             return True
  158.  
  159.         return False
  160.  
  161.     def _requires_exclude_func(self, test, result):
  162.         """IteratorExclude function which removes test when the
  163.            requires field contains a False value."""
  164.         if False in test.requires.get_mask():
  165.             self._callbacks.unsupported_requires(test, result)
  166.             return True
  167.  
  168.         return False
  169.  
  170.     def _architecture_exclude_func(self, test, result):
  171.         """IteratorExclude function which removes test when the
  172.            architectures field exists and doesn't meet the given
  173.            requirements."""
  174.         if test.architectures:
  175.             architecture = self._callbacks.get_architecture()
  176.             if architecture is None:
  177.                 self._callbacks.undefined_architecture(test, result)
  178.                 return True
  179.             elif architecture not in test.architectures:
  180.                 self._callbacks.unsupported_architecture(test, result)
  181.                 return True
  182.  
  183.         return False
  184.  
  185.     def _category_exclude_func(self, test, result):
  186.         """IteratorExclude function which removes test when
  187.            the categories field exists and doesn't meet the given
  188.            requirements."""
  189.         if test.categories:
  190.             category = self._callbacks.get_category()
  191.             if category is None:
  192.                 self._callbacks.undefined_category(test, result)
  193.                 return True
  194.             elif category not in test.categories:
  195.                 self._callbacks.unsupported_category(test, result)
  196.                 return True
  197.  
  198.         return False
  199.