def run(self, timeout=None): """\ Run the expectation loop on the testcase until all expectations pass or the timeout is exceeded. :param int timeout: (optional) maximum time to wait for all expectations to be met (defaults to :attr:`tcfl.expecter.expecter_c.timeout`) """ if timeout == None: timeout = self._timeout else: assert isinstance(timeout, int) # Fresh start self.buffers.clear() self.ts0 = time.time() _active_ts = self.ts0 functors_pending = self.functors while True: ts = time.time() td = ts - self.ts0 _functors_pending = list(functors_pending) for f, a, has_to_pass in _functors_pending: if a == None: args = (self, ) else: args = (self, ) + a try: self._log("running %s %s @%s" % (f.__name__, f.origin, args), dlevel=5) _ts0 = time.time() r = f(*args) _ts1 = time.time() except tc.pass_e as e: if has_to_pass: # Report pass information, including attachments tc.result_c.report_from_exception(self.testcase, e) r = True # Once it passes, we don't check it anymore if has_to_pass and r != None: self.remove(f, a) # if this returned normally or raised a tc.pass_e, # then it means the test passed; except if it # returns None, then ignore it (might have # been a poller) if self.have_to_pass == 0: raise tc.pass_e("all expectations found") # Check like this because we want to run the check # functions before determining a timeout as some of them # might also check on their own and offer better messages if td >= self.timeout: raise tc.error_e("Timed out (%.2fs)" % self.timeout) if ts - _active_ts > self.active_period: self.testcase._targets_active() _active_ts = ts time.sleep(self._poll_period)
def run(self, timeout = None): """\ Run the expectation loop on the testcase until all expectations pass or the timeout is exceeded. :param int timeout: (optional) maximum time to wait for all expectations to be met (defaults to :attr:`tcfl.expecter.expecter_c.timeout`) """ if timeout == None: timeout = self._timeout else: assert isinstance(timeout, int) # Fresh start self.buffers.clear() self.ts0 = time.time() _active_ts = self.ts0 functors_pending = self.functors while True: ts = time.time() td = ts - self.ts0 _functors_pending = list(functors_pending) for f, a, has_to_pass in _functors_pending: if a == None: args = (self,) else: args = (self, ) + a try: self._log( "running %s %s @%s" % (f.__name__, f.origin, args), dlevel = 5) _ts0 = time.time() r = f(*args) _ts1 = time.time() except tc.pass_e as e: if has_to_pass: # Report pass information, including attachments tc.result_c.report_from_exception(self.testcase, e) r = True # Once it passes, we don't check it anymore if has_to_pass and r != None: self.remove(f, a) # if this returned normally or raised a tc.pass_e, # then it means the test passed; except if it # returns None, then ignore it (might have # been a poller) if self.have_to_pass == 0: raise tc.pass_e("all expectations found") # Check like this because we want to run the check # functions before determining a timeout as some of them # might also check on their own and offer better messages if td >= self.timeout: raise tc.error_e("Timed out (%.2fs)" % self.timeout) if ts - _active_ts > self.active_period: self.testcase._targets_active() _active_ts = ts time.sleep(self._poll_period)
def console_rx_eval(expecter, target, regex, console=None, _timeout=None, result=None, uid=None): """ Check what came on a console and act on it :param str uid: (optional) identifier to use to store offset data """ if hasattr(regex, "pattern"): what = regex.pattern else: what = regex regex = re.compile(re.escape(regex)) if not uid: uid = console_mk_uid(target, what, console, _timeout, result) console_id_name, console_code = console_mk_code(target, console) # These were set by the poller of = expecter.buffers.get(console_code, None) if of == None: # FIXME: debug lof output here? expecter->tc backlink? return None ofd = of.fileno() ts = time.time() # Get the offset we saved before as the last part where we looked # at. If none, then get the last offset the poller has # recorded. Otherwise, just default to look from the start # Note the idea is each eval function has a different offset where # it is looking at. Likewise the poller for each console. offset_poller_code = "offset_" + console_code offset = expecter.buffers_persistent.get( uid, expecter.buffers_persistent.get(offset_poller_code, 0)) if _timeout != False: timeout = expecter.timeout if _timeout == None else _timeout # We can do timeout checks that provide better information # than a generic 'timeout' if ts - expecter.ts0 > timeout: of.seek(offset) # so we report console from where searched raise tc.error_e( "expected console output '%s' from console '%s:%s' " \ "NOT FOUND after %.1f s" \ % (what, target.id, console_id_name, ts - expecter.ts0), { 'target': target, "console output": of }) # mmap the whole file (which doesn't alter the file pointer) # # We have to mmap as the file might be getting huge and thus, # reading line by line might be dumb. # # However, we only search starting at @offset, which is set later # to the last success searching we had. So we shan't really map # the whole file, shall map on demand. stat_info = os.fstat(ofd) if stat_info.st_size == 0: # Nothing to read return None with contextlib.closing( mmap.mmap(of.fileno(), 0, mmap.MAP_PRIVATE, mmap.PROT_READ, 0)) as mapping: target.report_info("looking for `%s` in console %s:%s @%d-%d at " "%.2fs [%s]" % (what, target.fullid, console_id_name, offset, stat_info.st_size, ts - expecter.ts0, of.name), dlevel=3) m = regex.search(mapping[offset:]) if m: new_offset = offset + m.end() expecter.buffers_persistent[uid] = new_offset if result == None or result == "pass": # raising pass gets stopped at expecter.run(), so we # print instead, so we can see the console offset_tip = of.tell() # we report console from where searched of.seek(offset) # so we report console from where searched target.report_pass( "found expected `%s` in console `%s:%s` at %.2fs @%d" % (what, target.fullid, console_id_name, ts - expecter.ts0, offset + m.start()), {"console output": of}, dlevel=1, alevel=2) of.seek(offset_tip) raise tc.pass_e( "found expected `%s` in console `%s:%s` at %.2fs" % (what, target.fullid, console_id_name, ts - expecter.ts0), {'target': target}) elif result == "fail": of.seek(offset) # so we report console from where searched raise tc.failed_e( "found expected (for failure) `%s` in console " "`%s:%s` at %.2fs" % (what, target.fullid, console_id_name, ts - expecter.ts0), { 'target': target, "console output": of }) elif result == "error" or result == "errr": of.seek(offset) # so we report console from where searched raise tc.error_e( "found expected (for error) `%s` in console " "`%s:%s` at %.2fs" % (what, target.fullid, console_id_name, ts - expecter.ts0), { 'target': target, "console output": of }) elif result == "skip": of.seek(offset) # so we report console from where searched raise tc.skip_e( "found expected (for skip) `%s` in console " "'%s:%s' at %.2fs" % (what, target.fullid, console_id_name, ts - expecter.ts0), { 'target': target, "console output": of }) else: of.seek(offset) # so we report console from where searched raise tc.blocked_e("BUG: invalid result requested (%s)" % result) return None
def console_rx_eval(expecter, target, regex, console = None, _timeout = None, result = None, uid = None): """ Check what came on a console and act on it :param str uid: (optional) identifier to use to store offset data """ if hasattr(regex, "pattern"): what = regex.pattern else: what = regex regex = re.compile(re.escape(regex)) if not uid: uid = console_mk_uid(target, what, console, _timeout, result) console_id_name, console_code = console_mk_code(target, console) # These were set by the poller of = expecter.buffers.get(console_code, None) if of == None: # FIXME: debug lof output here? expecter->tc backlink? return None ofd = of.fileno() ts = time.time() # Get the offset we saved before as the last part where we looked # at. If none, then get the last offset the poller has # recorded. Otherwise, just default to look from the start # Note the idea is each eval function has a different offset where # it is looking at. Likewise the poller for each console. offset_poller_code = "offset_" + console_code offset = expecter.buffers_persistent.get( uid, expecter.buffers_persistent.get(offset_poller_code, 0)) if _timeout != False: timeout = expecter.timeout if _timeout == None else _timeout # We can do timeout checks that provide better information # than a generic 'timeout' if ts - expecter.ts0 > timeout: of.seek(offset) # so we report console from where searched raise tc.error_e( "expected console output '%s' from console '%s:%s' " \ "NOT FOUND after %.1f s" \ % (what, target.id, console_id_name, ts - expecter.ts0), { 'target': target, "console output": of }) # mmap the whole file (which doesn't alter the file pointer) # # We have to mmap as the file might be getting huge and thus, # reading line by line might be dumb. # # However, we only search starting at @offset, which is set later # to the last success searching we had. So we shan't really map # the whole file, shall map on demand. stat_info = os.fstat(ofd) if stat_info.st_size == 0: # Nothing to read return None with contextlib.closing(mmap.mmap(of.fileno(), 0, mmap.MAP_PRIVATE, mmap.PROT_READ, 0)) as mapping: target.report_info("looking for `%s` in console %s:%s @%d-%d at " "%.2fs [%s]" % (what, target.fullid, console_id_name, offset, stat_info.st_size, ts - expecter.ts0, of.name), dlevel = 3) m = regex.search(mapping[offset:]) if m: new_offset = offset + m.end() expecter.buffers_persistent[uid] = new_offset if result == None or result == "pass": # raising pass gets stopped at expecter.run(), so we # print instead, so we can see the console offset_tip = of.tell() # we report console from where searched of.seek(offset) # so we report console from where searched target.report_pass( "found expected `%s` in console `%s:%s` at %.2fs" % (what, target.fullid, console_id_name, ts - expecter.ts0), { "console output": of }, dlevel = 1, alevel = 2) of.seek(offset_tip) raise tc.pass_e( "found expected `%s` in console `%s:%s` at %.2fs" % (what, target.fullid, console_id_name, ts - expecter.ts0), {'target': target }) elif result == "fail": of.seek(offset) # so we report console from where searched raise tc.failed_e( "found expected (for failure) `%s` in console " "`%s:%s` at %.2fs" % (what, target.fullid, console_id_name, ts - expecter.ts0), { 'target': target, "console output": of }) elif result == "error" or result == "errr": of.seek(offset) # so we report console from where searched raise tc.error_e( "found expected (for error) `%s` in console " "`%s:%s` at %.2fs" % (what, target.fullid, console_id_name, ts - expecter.ts0), { 'target': target, "console output": of }) elif result == "skip": of.seek(offset) # so we report console from where searched raise tc.skip_e( "found expected (for skip) `%s` in console " "'%s:%s' at %.2fs" % (what, target.fullid, console_id_name, ts - expecter.ts0), { 'target': target, "console output": of }) else: of.seek(offset) # so we report console from where searched raise tc.blocked_e( "BUG: invalid result requested (%s)" % result) return None