def filterdefs(text=None): """Add the given text into the environment used for filtering. With no arguments, clear defined list. """ global _filterwith if text is None: log('filterdefs: erasing definitions') _filterwith = [] else: try: d = {} for f in _filterwith: exec(f, d) exec(text, d) except SyntaxError as e: raise AtsError(e) except KeyboardInterrupt: raise except Exception as e: pass if debug(): log('filterdefs:') log.indent() log(text) log.dedent() _filterwith.append(text)
def logStart(self, test, result): "Make appropriate log entries about the test that was started" if result: m1 = "Start" elif configuration.options.skip: m1 = "SKIP " else: m1 = "" if self.verbose or debug(): m1 = "Failed attempting to start" n = len(test.group) my_nn = 0 my_nt = 0 my_ngpu = 0 msgHosts = "" if hasattr(test, 'rs_nodesToUse'): if len(test.rs_nodesToUse) > 0: msgHosts = "Hosts = [ " for host in test.rs_nodesToUse: msgHosts += str(host) + " " msgHosts += "]" if hasattr(test, 'num_nodes'): my_nn = test.num_nodes if hasattr(test, 'nt'): my_nt = test.nt if hasattr(test, 'ngpu'): my_ngpu = test.ngpu if n == 1: if (test.srunRelativeNode >= 0): msg = '%s #%4d r=%d, N=%d-%d, np=%s, %s, %s' % \ (m1, test.serialNumber, test.srunRelativeNode, test.numberOfNodesNeeded, test.numNodesToUse, test.np, time.asctime(), test.name) else: msg = '%s #%4d %s, %s nn=%i, np=%i, nt=%i, ngpu=%i %s' % \ (m1, test.serialNumber, test.name, msgHosts, my_nn, test.np, my_nt, my_ngpu, time.asctime()) else: if (test.srunRelativeNode >= 0): msg = '%s #%4d r=%d, N=%d-%d, np=%s, %s, (Group %d #%d) %s' % \ (m1, test.serialNumber, test.srunRelativeNode, test.numberOfNodesNeeded, test.numNodesToUse, test.np, test.groupNumber, time.asctime(), test.groupSerialNumber, test.name) else: msg = '%s #%4d (Group %d #%d) %s, %s nn=%i, np=%i, nt=%i, ngpu=%i %s' % \ (m1, test.serialNumber, test.groupNumber, test.groupSerialNumber, test.name, msgHosts, my_nn, test.np, my_nt, my_ngpu, time.asctime()) if configuration.options.showGroupStartOnly: echo = (not result) or self.verbose or (test.groupSerialNumber == 1) or test.options.get( 'record', False) else: echo = (result) or self.verbose or test.options.get( 'record', False) log(msg, echo=echo) self.schedule(msg) if self.verbose or debug(): log.indent() log("Executing", test.commandLine) log("in directory", test.directory) #log("with timelimit", test.timelimit) log.dedent()
def recordOutput(self, groupFailure): """Standard recorder for test. Some tests have a very large amount of output, so this does direct output rather than keep it in the test object. groupFailure is used if one member of a group died. """ failures = [FAILED, TIMEDOUT, HALTED] # What we're going to do with the output file: checkit = self.options.get('check', False) keep = self.options.get('keep') magic = self.options.get('magic', '#ATS:') if checkit: self.notes.append( 'Please check the results of this test manually.') log('Please check the results of this test manually.', echo=True) if configuration.options.skip: return if self.testStdout != 'terminal': try: f = open(self.outname, 'r') except IOError as e: self.notes = ['Missing output file.'] log('Missing output file', self.outname, e) return if magic is not None: # Check for output that starts with magic phrase n = 0 M = len(magic) for line in f: n += 1 if line.startswith(magic): self.output.append(line[M:-1]) f.close() failed = self.status in failures lookatit = checkit or failed keepit = (keep > 0) or lookatit or groupFailure hideIt = self.options.get('hideOutput') if keepit and (self.testStdout != 'terminal'): log.indent() if magic is not None: log('%d lines of output in %s' % (n, self.shortoutname), echo=lookatit) else: log('Output in %s' % self.shortoutname, echo=lookatit) log.dedent() else: self.fileOutDelete() if not hideIt and self.output: log("Captured output:", echo=False, logging=True) log.indent() for line in self.output: log(line, echo=False, logging=True) log.dedent()
def documentConfiguration(): """Write the configuration to the log.""" log('Configuration:') log.indent() log('Input files:', inputFiles) log('Python path:', sys.executable) log('ATS from ', os.path.dirname(__file__)) log('ATS version:', version.version) log('Options:') log.indent() olist = list(options.keys()) olist.sort() for k in olist: log(k + ":", repr(getattr(options, k))) log.dedent() log.dedent()
def logDefinitions(self, *words, **options): """Log the current definitions of words; if none given show all. options passed to log (echo, logging) """ logging = options.get('logging', True) echo = options.get('echo', True) log("Test environment symbols:", logging=logging, echo=echo) log.indent() if not words: words = list(testEnvironment.keys()) words.sort() for key in words: try: log(key, ":", testEnvironment[key], logging=logging, echo=echo) except KeyError: log("Not defined:", key, logging=logging, echo=echo) log.dedent()
def report(self): "Log a report, showing each test." doAll = debug() or \ configuration.options.skip or \ configuration.options.verbose outputCaptured = False for test in self.testlist: if test.output: outputCaptured = True if outputCaptured and not configuration.options.hideOutput: log("NOTICE:", "Captured output, see log.", echo=True, logging=False) for test in self.testlist: if doAll or test.notes or test.groupSerialNumber ==1 or \ test.group.echoStatus() or test.options.get('record', False): echo = True else: echo = False log("#%d %s %s %s (Group %d #%d)" % \ (test.serialNumber, test.status, test.name, test.message, test.group.number, test.groupSerialNumber), echo=echo) for line in test.notes: log("NOTE:", line, echo=echo) log.indent() if debug() or configuration.options.skip: log([t.serialNumber for t in test.waitUntil], echo=False) log.dedent()
def __init__(self, *fixedargs, **options): "Must not throw an exception -- object must always get created." super(AtsTest, self).__init__() AtsTest.serialNumber += 1 AtsTest.waitUntilAccumulator.append(self) # populate attributes self.serialNumber = AtsTest.serialNumber if AtsTest.group is None: AtsTest.groupCounter += 1 self.group = AtsTestGroup(AtsTest.groupCounter) else: self.group = AtsTest.group self.group.append(self) self.groupNumber = self.group.number self.groupSerialNumber = len(self.group) self.waitUntil = AtsTest.waitUntil #never modify this, it may be shared. self.runOrder = 0 # to aid in diagnosis of wait, priority self.depends_on = None self.dependents = [] self.expectedResult = PASSED self.setName("uninitialized") self.set(INVALID, "New test, unitialized") self.srunRelativeNode = -1 self.numNodesToUse = -1 self.priority = -1 self.totalPriority = -1 self.startDateTime = curDateTime() self.endDateTime = curDateTime() self.output = [] #magic output, newlines and magic removed. self.notes = [] #note from the run self.block = '' # these will all get changed below but want them set to something for getResults self.level = 0 self.independent = False self.np = 1 self.priority = 1 self.totalPriority = 1 self.directory = '' self.batch = False self.clas = '' self.combineOutput = False self.outname = '' self.shortoutname = '' self.errname = '' self.outhandle = None self.errhandle = None self.commandList = ['not run'] # this is just used for documentation self.commandLine = 'not run' rootdict = dict(ATSROOT=configuration.ATSROOT) # Combine the options: first the defaults, then the glued, then the tacked, # then the stuck, then the test options. self.options = AttributeDict( script='', clas=[], executable='', directory='', ) try: self.options.update(configuration.options.testDefaults) self.options.update(AtsTest.glued) self.options.update(AtsTest.tacked) self.options.update(AtsTest.stuck) self.options.update(AtsTest.grouped) self.options.update(options) except Exception as e: self.set(INVALID, 'Bad options: ' + e) return self.level = self.options['level'] self.np = self.options['np'] self.priority = self.options.get('priority', max(1, self.np)) self.totalPriority = self.priority self.testStdout = self.options['testStdout'] outOpts = ['file', 'terminal', 'both'] if not self.testStdout in outOpts: msg = 'Invalid setting for option testStdout: ' + self.testStdout raise AtsError(msg) if configuration.options.allInteractive: self.batch = False else: self.batch = self.options['batch'] if configuration.options.combineOutErr: self.combineOutput = True else: self.combineOutput = False # process the arguments # Note: old interface was script, clas='', **options # Now allow for possibility of no script, or clas as unnamed second # positional lc = len(fixedargs) if lc > 2: self.set(INVALID, 'Too many positional arguments to test command.') return elif lc == 2: self.options['script'] = fixedargs[0] self.options['clas'] = fixedargs[1] elif lc == 1: self.options['script'] = fixedargs[0] script = self.options['script'] clas = self.options['clas'] if isinstance(clas, str): clas = configuration.machine.split(clas) self.clas = [c % self.options for c in clas] executable = str(self.options.get('executable')) self.directory = self.options['directory'] if executable == '1': if not script: self.set(INVALID, "executable = 1 requires a first argument.") return script = script.replace('$ATSROOT', configuration.ATSROOT) if len(configuration.ATSROOT) == 0: script = script[1:] # remove leading "/" or "\" script = script % rootdict self.executable = Executable(script) if self.directory == '': self.directory = os.getcwd() path = self.executable.path junk, filename = os.path.split(path) else: if executable: executable = executable.replace('$ATSROOT', configuration.ATSROOT) self.executable = Executable(executable % rootdict) else: self.executable = configuration.defaultExecutable if script: script = abspath(script) % self.options self.clas.insert(0, script) if self.directory == '': self.directory, filename = os.path.split(script) else: if self.directory == '': self.directory = os.getcwd() junk, filename = os.path.split(self.executable.path) name, junk = os.path.splitext(filename) self.setName(self.options.get('name', name)) label = self.options.get('label', '') if label: label = str(label).strip() self.setName(self.name + '(' + label + ')') if debug(): log("Results of parsing test arguments", echo=False) log.indent() log("Name:", self.name, echo=False) log("Options:", echo=False) log.indent() for k in self.options: log(k, ": ", self.options[k], echo=False) log.dedent() log("Executable path:", self.executable.path, echo=False) log("Directory:", self.directory, echo=False) log.dedent() self.independent = self.options.get('independent', False) if not self.independent: # the lower() is due to peculiarities on at least the Mac # where os.chdir() seems to change case partially. self.block = self.directory.lower() if not self.executable.is_valid(): self.set(INVALID, 'Executable "%s" not valid.' % self.executable) return if not os.path.isdir(self.directory): self.set(INVALID, 'Directory not valid: %s' % self.directory) if script and not is_valid_file(script): self.set(INVALID, "Script %s does not exist." % script) return self.fileOutNamesSet() #set the timelimit try: tl = options.get('timelimit', None) if tl is None: self.timelimit = configuration.timelimit else: self.timelimit = Duration(tl) except AtsError as msg: self.set(INVALID, msg) return if self.priority <= 0: self.set(SKIPPED, 'Test has priority <= zero.') return # if the test ends up BATCHED, such jobs are legal. if self.batch and configuration.options.nobatch: self.set(SKIPPED, "Batch not available") elif self.batch: problem = configuration.batchmachine.canRun(self) if not problem: if configuration.options.skip: self.set(SKIPPED, "BACH skipped due to skip flag") else: self.set(BATCHED, "Ready to run in batch.") else: self.set(SKIPPED, problem) else: problem = configuration.machine.canRun(self) if not problem: self.set(CREATED, "Ready to run interactively.") elif configuration.options.allInteractive or \ configuration.options.nobatch or \ self.groupNumber: self.set(SKIPPED, problem) else: self.set(BATCHED, problem) self.notes.append(\ "Changed to batch since unable to run interactively on this machine.")
def collectTests(self): """Process the input and collect the tests to be executed. We immediately make sure each input file exists and is readable. (If we don't we might not find out until many tests have run.) """ # It is worth settling this now. if debug(): log("Checking that input files exist.") files = [] for input_file in self.inputFiles: t = abspath(input_file) dir, filename = os.path.split(t) name, e = os.path.splitext(filename) if e: namelist = [t] else: namelist = [t, t + '.ats', t + '.py'] for t1 in namelist: try: f = open(t1, 'r') break except IOError: pass else: log.fatal_error('Cannot open %s.' % t) f.close() files.append(t1) log("Input ok. Now collect the tests.") # Now collect the tests. for t in files: self.source(t) # Stop the execution of ats when the first INVALID test is found unless option --okInvalid. log.indent() found = False for item in self.badlist: found = True log('Bad file:', item, echo=True) for test in self.testlist: if test.status is INVALID: found = True log(test.status, "#%d" % test.serialNumber, test.name, echo=True) log.dedent() if found: log('************************************************', echo=True) log('NOTE: Invalid tests or files', echo=True) if not configuration.options.okInvalid: log.fatal_error("Fix invalid tests or rerun with --okInvalid.") # Make sure that every test has distinct name testnames = [t.name.lower() for t in self.testlist] for i in range(len(testnames)): name = testnames[i] while testnames.count(name) > 1: count = 1 for j in range(i + 1, len(testnames)): if testnames[j] == name: count += 1 t = self.testlist[j] t.name += ("#%d" % count) testnames[j] = t.name.lower() # Add parents to each test's waitlist. for t in self.testlist: if t.status is CREATED: for d in t.dependents: if t not in d.waitUntil: d.waitUntil = d.waitUntil + [t] log.leading = '' log("------------------ Input complete --------", echo=True) echo = configuration.options.verbose or \ debug() or \ configuration.options.skip for t in self.testlist: log(repr(t), echo=echo)
def _source(self, path, introspector, vocabulary): "Process source file. Returns true if successful" here = os.getcwd() t = abspath(path) directory, filename = os.path.split(t) name, e = os.path.splitext(filename) if e: namelist = [t] else: namelist = [t, t + '.ats', t + '.py'] for t1 in namelist: if t1 in AtsManager.alreadysourced: log("Already sourced:", t1) return try: f = open(t1) break except IOError as e: pass else: log("Error opening input file:", t1, echo=True) self.badlist.append(t1) raise AtsError("Could not open input file %s" % path) t = abspath(t1) directory, filename = os.path.split(t1) name, e = os.path.splitext(filename) AtsManager.alreadysourced.append(t1) # save to restore after this file is read savestuck = dict(AtsTest.stuck) savetacked = dict(AtsTest.tacked) unstick() #clear sticky list at the start of a file. AtsTest.waitNewSource() testenv = dict(testEnvironment) testenv.update(vocabulary) testenv['SELF'] = t1 atstext = [] for line1 in f: if not line1: continue if line1.startswith('#!'): continue magic = introspector(line1[:-1]) if magic is not None: atstext.append(magic) f.close() if atstext: log('-> Executing statements in', t1, echo=False) log.indent() code = '\n'.join(atstext) if debug(): for line in atstext: log(line, echo=False) os.chdir(directory) try: exec(code, testenv) if debug(): log('Finished ', t1, datestamp()) except KeyboardInterrupt: raise except Exception as details: self.badlist.append(t1) log('Error while processing statements in', t1, ':', echo=True) log(details, echo=True) log.dedent() else: log('-> Sourcing', t1, echo=False) log.indent() os.chdir(directory) try: exec(compile(open(t1, "rb").read(), t1, 'exec'), testenv) if debug(): log('Finished ', t1, datestamp()) result = 1 except KeyboardInterrupt: raise except Exception as details: self.badlist.append(t1) log('Error in input file', t1, ':', echo=True) log(details, echo=True) log('------------------------------------------', echo=True) log.dedent() AtsTest.endGroup() unstick() stick(**savestuck) untack() tack(**savetacked) AtsTest.waitEndSource() os.chdir(here)