def __unicode__(self): """ Display items as a list for printing """ if self._items: # List of identifiers try: return listed(sorted([item.identifier for item in self._items])) # If no identifiers, just join strings except AttributeError: return listed(self._items, quote="'") else: return "[None]"
def clear(self, classes=None): """ Completely wipe out cache of all (or selected) classes Accepts class or a list of classes. Clears all given classes and their subclasses. For example Cache().clear(Mutable) will empty cache of all mutable objects. """ # Wipe everything if classes == None: log.cache("Wiping out all objects memory cache") classes = self._classes # Wipe selected classes only else: # Convert single class into a list if isinstance(classes, type): classes = [classes] # Prepare the list of given classes and their subclasses classes = [cls for cls in self._classes if any([issubclass(cls, klass) for klass in classes])] log.cache("Wiping out {0} memory cache".format( listed([klass.__name__ for klass in classes]))) # For each class re-initialize objects and remove from index for current_class in classes: for current_object in current_class._cache.itervalues(): # Reset the object to the initial state current_object._init() current_class._cache = {}
def _remove(self, plans): """ Remove self as parent of given test plans """ log.info("Removing {1} as parent of {0}".format(self._identifier, listed([plan.identifier for plan in plans]))) for plan in plans: plan.parent = None plan.update()
def _add(self, testcases): """ Add given test cases to the test run """ # Short info about the action identifiers = [testcase.identifier for testcase in testcases] log.info("Adding {0} to {1}".format( listed(identifiers, "testcase", max=3), self._object.identifier)) # Prepare data and push data = [testcase.id for testcase in testcases] log.data(pretty(data)) try: self._server.TestRun.add_cases(self.id, data) # Handle duplicate entry errors by adding test cases one by one except xmlrpclib.Fault as error: if not "Duplicate entry" in unicode(error): raise log.warn(error) for id in data: try: self._server.TestRun.add_cases(self.id, id) except xmlrpclib.Fault: pass # RunCaseRuns will need update ---> erase current data self._object.caseruns._init()
def _add(self, plans): """ Set self as parent of given test plans """ log.info("Setting {1} as parent of {0}".format(self._identifier, listed([plan.identifier for plan in plans]))) for plan in plans: plan.parent = TestPlan(self.id) plan.update()
def _remove(self, bugs): """ Detach provided bugs from the test case """ log.info(u"Detaching {0} from {1}".format( listed(bugs), self._identifier)) data = [bug.bug for bug in bugs] log.data(pretty(data)) self._server.TestCaseRun.detach_bug(self.id, data)
def _add(self, components): """ Link provided components to the test plan """ log.info(u"Linking {1} to {0}".format(self._identifier, listed([component.name for component in components]))) data = [component.id for component in components] log.data(data) self._server.TestPlan.add_component(self.id, data)
def update(self): """ Update all modified mutable objects in the cache This method uses MultiCall to perform the update which can significantly speed up things when compared to updating each individual object separately. Note: The update is done in batches. The maximum number of objects updated at once is controlled by the global variable MULTICALL_MAX, by default set to 10 object per session.""" for klass in self._mutable + self._containers: modified = [mutable for mutable in klass._cache.itervalues() if mutable._modified] if not modified: continue log.info("Found {0} in the {1} cache, updating...".format( listed(modified, "modified object"), klass.__name__)) for slice in sliced(modified, config.MULTICALL_MAX): multicall_start() for mutable in slice: mutable.update() multicall_end()
def _fetch(self, inset=None): """ Fetch currently linked test cases from the server """ # If data initialized from the inset ---> we're done if Container._fetch(self, inset): return # Initialize all plan-case tags (skip when caching persistently # as this an additional/unnecessary call in that case) if config.get_cache_level() == config.CACHE_OBJECTS: log.info("Fetching tags for all {0}'s test cases".format(self._object.identifier)) for tag in self._server.TestPlan.get_all_cases_tags(self.id): Tag(tag) # Fetch test cases from the server log.info("Fetching {0}'s cases".format(self._identifier)) injects = self._server.TestPlan.get_test_cases(self.id) log.data("Fetched {0}".format(listed(injects, "inject"))) self._current = set([TestCase(inject) for inject in injects]) self._original = set(self._current) # Initialize case plans if not already cached if not PlanCasePlans._is_cached(self._object.caseplans): inset = [ CasePlan( { # Fake our own internal id from testplan & testcase "id": _idify([self._object.id, inject["case_id"]]), "case_id": inject["case_id"], "plan_id": self._object.id, "sortkey": inject["sortkey"], } ) for inject in injects ] self._object.caseplans._fetch(inset)
def _fetch(self, inset=None): """ Fetch currently linked test cases from the server """ # If data initialized from the inset ---> we're done if Container._fetch(self, inset): return # Initialize all plan-case tags (skip when caching persistently # as this an additional/unnecessary call in that case) if config.get_cache_level() == config.CACHE_OBJECTS: log.info("Fetching tags for all {0}'s test cases".format( self._object.identifier)) for tag in self._server.TestPlan.get_all_cases_tags(self.id): Tag(tag) # Fetch test cases from the server log.info("Fetching {0}'s cases".format(self._identifier)) injects = self._server.TestPlan.get_test_cases(self.id) log.data("Fetched {0}".format(listed(injects, "inject"))) self._current = set([TestCase(inject) for inject in injects]) self._original = set(self._current) # Initialize case plans if not already cached if not PlanCasePlans._is_cached(self._object.caseplans): inset = [ CasePlan({ # Fake our own internal id from testplan & testcase "id": _idify([self._object.id, inject["case_id"]]), "case_id": inject["case_id"], "plan_id": self._object.id, "sortkey": inject["sortkey"] }) for inject in injects ] self._object.caseplans._fetch(inset)
def _remove(self, bugs): """ Detach provided bugs from the test case """ log.info(u"Detaching {0} from {1}".format(listed(bugs), self._identifier)) data = [bug.bug for bug in bugs] log.data(pretty(data)) self._server.TestCaseRun.detach_bug(self.id, data)
def _remove(self, plans): """ Remove self as parent of given test plans """ log.info("Removing {1} as parent of {0}".format( self._identifier, listed([plan.identifier for plan in plans]))) for plan in plans: plan.parent = None plan.update()
def _add(self, plans): """ Set self as parent of given test plans """ log.info("Setting {1} as parent of {0}".format( self._identifier, listed([plan.identifier for plan in plans]))) for plan in plans: plan.parent = TestPlan(self.id) plan.update()
def update(self): """ Update all modified mutable objects in the cache This method uses MultiCall to perform the update which can significantly speed up things when compared to updating each individual object separately. Note: The update is done in batches. The maximum number of objects updated at once is controlled by the global variable MULTICALL_MAX, by default set to 10 object per session.""" for klass in self._mutable + self._containers: modified = [mutable for mutable in klass._cache.values() if mutable._modified] if not modified: continue log.info("Found {0} in the {1} cache, updating...".format( listed(modified, "modified object"), klass.__name__)) for slice in sliced(modified, config.MULTICALL_MAX): multicall_start() for mutable in slice: mutable.update() multicall_end()
def clear(self, classes=None): """ Completely wipe out cache of all (or selected) classes Accepts class or a list of classes. Clears all given classes and their subclasses. For example Cache().clear(Mutable) will empty cache of all mutable objects. """ # Wipe everything if classes == None: log.cache("Wiping out all objects memory cache") classes = self._classes # Wipe selected classes only else: # Convert single class into a list if isinstance(classes, type): classes = [classes] # Prepare the list of given classes and their subclasses classes = [cls for cls in self._classes if any([issubclass(cls, klass) for klass in classes])] log.cache("Wiping out {0} memory cache".format( listed([klass.__name__ for klass in classes]))) # For each class re-initialize objects and remove from index for current_class in classes: for current_object in list(current_class._cache.values()): # Reset the object to the initial state current_object._init() current_class._cache = {}
def _add(self, cases): """ Link provided cases to the test plan """ # Link provided cases on the server log.info("Linking {1} to {0}".format(self._identifier, listed([case.identifier for case in cases]))) self._server.TestCase.link_plan([case.id for case in cases], self.id) # Add corresponding CasePlan objects to the PlanCasePlans container if PlanCasePlans._is_cached(self._object.caseplans): self._object.caseplans.add([CasePlan(testcase=case, testplan=self._object) for case in cases])
def _add(self, components): """ Link provided components to the test plan """ log.info(u"Linking {1} to {0}".format( self._identifier, listed([component.name for component in components]))) data = [component.id for component in components] log.data(data) self._server.TestPlan.add_component(self.id, data)
def _add(self, bugs): """ Attach provided bugs to the test case """ log.info(u"Attaching {0} to {1}".format(listed(bugs), self._identifier)) data = [{"bug_id": bug.bug, "bug_system_id": bug.system, "case_run_id": self.id} for bug in bugs] log.data(pretty(data)) self._server.TestCaseRun.attach_bug(data) # Fetch again the whole bug list (to get the internal id) self._fetch()
def _remove(self, testcases): """ Remove given test cases from the test run """ # Short info about the action identifiers = [testcase.identifier for testcase in testcases] log.info("Removing {0} from {1}".format(listed(identifiers, "testcase", max=3), self._object.identifier)) data = [testcase.id for testcase in testcases] log.data(pretty(data)) self._server.TestRun.remove_cases(self.id, data) # RunCaseRuns will need update ---> erase current data self._object.caseruns._init()
def expire(self): """ Remove all out-of-date objects from the cache All expired objects are wiped out as well as those mutable objects which are in modified state (hold different information from what is on the server a thus could cause inconsistencies). Also all uninitialized objects are removed from the cache. """ for current_class in self._classes: expired = [] for id, current_object in current_class._cache.items(): expire = False # Check if object is uninitialized if (current_object._id is NitrateNone or current_object._fetched is None): log.all("Wiping uninitialized {0} {1} from cache".format( current_object.__class__.__name__, current_object.identifier)) expire = True # Check if object is expired elif current_object._is_expired: log.all("Wiping expired {0} {1} from cache".format( current_object.__class__.__name__, current_object.identifier)) expire = True # Check if object is modified elif (isinstance(current_object, mutable.Mutable) and current_object._modified): log.all("Wiping modified {0} {1} from cache".format( current_object.__class__.__name__, current_object.identifier)) expire = True # Expire containers with uncached items elif (isinstance(current_object, containers.Container) and not current_object._class._is_cached( current_object._current)): log.all("Wiping {0} {1} with uncached items".format( current_object.__class__.__name__, current_object.identifier)) expire = True if expire: # Reset the object to the initial state current_object._init() expired.append(id) before = len(current_class._cache) for id in expired: del current_class._cache[id] after = len(current_class._cache) if before != after: log.cache("Wiped {0} from the {1} cache".format( listed(before - after, "expired object"), current_class.__name__))
def expire(self): """ Remove all out-of-date objects from the cache All expired objects are wiped out as well as those mutable objects which are in modified state (hold different information from what is on the server a thus could cause inconsistencies). Also all uninitialized objects are removed from the cache. """ for current_class in self._classes: expired = [] for id, current_object in current_class._cache.iteritems(): expire = False # Check if object is uninitialized if (current_object._id is NitrateNone or current_object._fetched is None): log.all("Wiping uninitialized {0} {1} from cache".format( current_object.__class__.__name__, current_object.identifier)) expire = True # Check if object is expired elif current_object._is_expired: log.all("Wiping expired {0} {1} from cache".format( current_object.__class__.__name__, current_object.identifier)) expire = True # Check if object is modified elif (isinstance(current_object, mutable.Mutable) and current_object._modified): log.all("Wiping modified {0} {1} from cache".format( current_object.__class__.__name__, current_object.identifier)) expire = True # Expire containers with uncached items elif (isinstance(current_object, containers.Container) and not current_object._class._is_cached( current_object._current)): log.all("Wiping {0} {1} with uncached items".format( current_object.__class__.__name__, current_object.identifier)) expire = True if expire: # Reset the object to the initial state current_object._init() expired.append(id) before = len(current_class._cache) for id in expired: del current_class._cache[id] after = len(current_class._cache) if before != after: log.cache("Wiped {0} from the {1} cache".format( listed(before - after, "expired object"), current_class.__name__))
def _remove(self, testcases): """ Remove given test cases from the test run """ # Short info about the action identifiers = [testcase.identifier for testcase in testcases] log.info("Removing {0} from {1}".format( listed(identifiers, "testcase", max=3), self._object.identifier)) data = [testcase.id for testcase in testcases] log.data(pretty(data)) self._server.TestRun.remove_cases(self.id, data) # RunCaseRuns will need update ---> erase current data self._object.caseruns._init()
def _add(self, bugs): """ Attach provided bugs to the test case """ log.info(u"Attaching {0} to {1}".format(listed(bugs), self._identifier)) data = [{ "bug_id": bug.bug, "bug_system_id": bug.system, "case_run_id": self.id } for bug in bugs] log.data(pretty(data)) self._server.TestCaseRun.attach_bug(data) # Fetch again the whole bug list (to get the internal id) self._fetch()
def multicall_end(): """ Execute xmlrpc call queue and exit MultiCall mode """ log.info("Ending multicall session, sending to the server...") response = Nitrate._multicall_proxy() log.data("Server response:") entries = 0 for entry in response: log.data(pretty(entry)) entries += 1 Nitrate._multicall_proxy = None Nitrate._requests += 1 log.info("Multicall session finished, {0} completed".format( listed(entries, "update"))) return response
def remove(self, items): """ Remove an item or a list of items from the container """ # Convert to set representation if isinstance(items, list): items = set(items) else: items = set([items]) # If there are any items to be removed remove_items = items.intersection(self._items) if remove_items: log.info("Removing {0} from {1}'s {2}".format( listed([item.identifier for item in remove_items], self._class.__name__, max=10), self._object.identifier, self.__class__.__name__)) self._items.difference_update(items) if config.get_cache_level() != config.CACHE_NONE: self._modified = True else: self._update()
def add(self, items): """ Add an item or a list of items to the container """ # Convert to set representation if isinstance(items, list): items = set(items) else: items = set([items]) # If there are any new items add_items = items - self._items if add_items: log.info("Adding {0} to {1}'s {2}".format( listed([item.identifier for item in add_items], self._class.__name__, max=10), self._object.identifier, self.__class__.__name__)) self._items.update(items) if config.get_cache_level() != config.CACHE_NONE: self._modified = True else: self._update()
def _add(self, testcases): """ Add given test cases to the test run """ # Short info about the action identifiers = [testcase.identifier for testcase in testcases] log.info("Adding {0} to {1}".format( listed(identifiers, "testcase", max=3), self._object.identifier)) # Prepare data and push data = [testcase.id for testcase in testcases] log.data(pretty(data)) try: self._server.TestRun.add_cases(self.id, data) # Handle duplicate entry errors by adding test cases one by one except xmlrpclib.Fault as error: if not "Duplicate entry" in six.u(error): raise log.warn(error) for id in data: try: self._server.TestRun.add_cases(self.id, id) except xmlrpclib.Fault: pass # RunCaseRuns will need update ---> erase current data self._object.caseruns._init()
def __unicode__(self): return listed(self._items, quote="'")
def _remove(self, tags): """ Detach provided tags from the test case """ log.info(u"Untagging {0} of {1}".format(self._identifier, listed(tags, quote="'"))) self._server.TestCase.remove_tag(self.id, list(tag.name for tag in tags))
def _add(self, tags): """ Attach provided tags to the test case """ log.info(u"Tagging {0} with {1}".format(self._identifier, listed(tags, quote="'"))) self._server.TestCase.add_tag(self.id, list(tag.name for tag in tags))
def __unicode__(self): return listed(self._items)
def __unicode__(self): """ The list of linked components' names """ if self._items: return listed(sorted([component.name for component in self])) else: return "[None]"
def _add(self, plans): """ Link provided plans to the test case """ log.info("Linking {1} to {0}".format( self._identifier, listed([plan.identifier for plan in plans]))) self._server.TestCase.link_plan(self.id, [plan.id for plan in plans])
def _add(self, plans): """ Link provided plans to the test case """ log.info("Linking {1} to {0}".format(self._identifier, listed([plan.identifier for plan in plans]))) self._server.TestCase.link_plan(self.id, [plan.id for plan in plans])