def getDisplayInfo(self, machines, app):
     for machine in machines:
         displayName, pid, proc = self.createDisplay(machine, app)
         if displayName:
             return machine, displayName, pid, proc
         else:
             plugins.printWarning("Virtual display program Xvfb not available on " + machine, stdout=True)
 def createView(self):
     hbox = gtk.HBox()
     self.label = gtk.Label()
     self.label.set_name("GUI status")
     self.label.set_ellipsize(pango.ELLIPSIZE_END)
     # It seems difficult to say 'ellipsize when you'd otherwise need
     # to enlarge the window', so we'll have to settle for a fixed number
     # of max char's ... The current setting (90) is just a good choice
     # based on my preferred window size, on the test case I used to
     # develop this code. (since different chars have different widths,
     # the optimal number depends on the string to display) \ Mattias++
     self.label.set_max_width_chars(90)
     self.label.set_use_markup(True)
     self.label.set_markup(plugins.convertForMarkup("TextTest started at " + plugins.localtime() + "."))
     hbox.pack_start(self.label, expand=False, fill=False)
     imageDir = plugins.installationDir("images")
     try:
         staticIcon = os.path.join(imageDir, "throbber_inactive.png")
         temp = gtk.gdk.pixbuf_new_from_file(staticIcon)
         self.throbber = gtk.Image()
         self.throbber.set_from_pixbuf(temp)
         animationIcon = os.path.join(imageDir, "throbber_active.gif")
         self.animation = gtk.gdk.PixbufAnimation(animationIcon)
         hbox.pack_end(self.throbber, expand=False, fill=False)
     except Exception, e:
         plugins.printWarning("Failed to create icons for the status throbber:\n" + str(e) + \
                              "\nAs a result, the throbber will be disabled.", stdout=True)
         self.throbber = None
示例#3
0
 def notifyExtraTest(self, testPath, appName, versions):
     rootSuite = self.getRootSuite(appName, versions)
     if rootSuite:
         rootSuite.addTestCaseWithPath(testPath)
     else:
         message = "Couldn't add extra test for application: " + str(appName)
         plugins.printWarning(message)
    def startXvfb(self, startArgs, machine):
        for _ in range(5):
            self.diag.info("Starting Xvfb using args " + repr(startArgs))
            # Ignore job control signals for remote processes
            # Otherwise the ssh process gets killed, but the stuff it's started remotely doesn't, and we leak Xvfb processes
            preexec_fn = None if machine == "localhost" else self.ignoreSignals
            displayProc = subprocess.Popen(startArgs, preexec_fn=preexec_fn, stdin=open(os.devnull), stdout=subprocess.PIPE, stderr=open(os.devnull, "w"))
            line = plugins.retryOnInterrupt(displayProc.stdout.readline)
            if "Time Out!" in line:
                displayProc.wait()
                displayProc.stdout.close()
                self.diag.info("Timed out waiting for Xvfb to come up")
                # We try again and hope for a better process ID!
                continue
            try:
                displayNum, pid = map(int, line.strip().split(","))
                displayProc.stdout.close()
                return self.getDisplayName(machine, displayNum), pid, displayProc
            except ValueError: #pragma : no cover - should never happen, just a fail-safe
                sys.stderr.write("ERROR: Failed to parse startXvfb.py line :\n " + line + "\n")
                displayProc.stdout.close()
                return None, None, None

        messages = "Failed to start Xvfb in 5 attempts, giving up"
        plugins.printWarning(messages)
        return None, None, None
示例#5
0
 def notifyExtraTest(self, testPath, appName, versions):
     rootSuite = self.getRootSuite(appName, versions)
     if rootSuite:
         rootSuite.addTestCaseWithPath(testPath)
     else:
         message = "Couldn't add extra test for application: " + str(appName)
         plugins.printWarning(message)
示例#6
0
 def getDisplay(self, machines, app):
     for machine in machines:
         displayName, pid = self.createDisplay(machine, app)
         if displayName:
             return machine, displayName, pid
         else:
             plugins.printWarning("Virtual display program Xvfb not available on " + machine)
     return None, None, None
示例#7
0
 def getAccelerator(self, title):
     realAcc = guiConfig.getCompositeValue("gui_accelerators", title)
     if realAcc:
         key, mod = gtk.accelerator_parse(realAcc)
         if gtk.accelerator_valid(key, mod):
             return realAcc
         else:
             plugins.printWarning("Keyboard accelerator '" + realAcc + "' for action '" \
                                  + title + "' is not valid, ignoring ...")
示例#8
0
    def extract(self, test, sourceFile, targetFile, collationErrFile):
        stem = os.path.splitext(os.path.basename(targetFile))[0]
        scripts = test.getCompositeConfigValue("collate_script", stem)
        if len(scripts) == 0:
            return shutil.copyfile(sourceFile, targetFile)
            
        self.collationProc = None
        stdin = None
        for script in scripts:
            args = getScriptArgs(script)
            if self.collationProc:
                stdin = self.collationProc.stdout
            else:
                args.append(sourceFile)
            self.diag.info("Opening extract process with args " + repr(args))
            if script is scripts[-1]:
                stdout = open(targetFile, "w")
                stderr = open(collationErrFile, "w")
            else:
                stdout = subprocess.PIPE
                stderr = subprocess.STDOUT

            useShell = os.name == "nt" and len(scripts) == 1
            self.collationProc = self.runCollationScript(args, test, stdin, stdout, stderr, useShell)
            if not self.collationProc:
                if os.path.isfile(targetFile):
                    os.remove(targetFile)
                errorMsg = "Could not find extract script '" + script + "', not extracting file at\n" + sourceFile + "\n"
                stderr = open(collationErrFile, "w")
                stderr.write(errorMsg)
                plugins.printWarning(errorMsg.strip())
                stderr.close()
                return

        if self.collationProc:
            self.diag.info("Waiting for collation process to terminate...")
            self.collationProc.wait()
            if self.collationProc:
                self.collationProc = None
            else:
                procName = args[0]
                briefText = "KILLED (" + os.path.basename(procName) + ")"
                freeText = "Killed collation script '" + procName + "'\n while collating file at " + sourceFile + "\n"
                test.changeState(Killed(briefText, freeText, test.state))
            stdout.close()
            stderr.close()

        if os.path.getsize(sourceFile) > 0 and os.path.getsize(targetFile) == 0 and os.path.getsize(collationErrFile) == 0:
            # Collation scripts that don't write anything shouldn't produce empty files...
            # If they write errors though, we might want to pick those up
            os.remove(targetFile)

        collateErrMsg = test.app.filterErrorText(collationErrFile)
        if collateErrMsg:
            msg = "Errors occurred running collate_script(s) " + " and ".join(scripts) + \
                  "\nwhile trying to extract file at \n" + sourceFile + " : \n" + collateErrMsg
            plugins.printWarning(msg)
示例#9
0
 def addValuesToTotal(self, localName, valuesLine, totalValues):
     catValues = plugins.commasplit(valuesLine.strip())
     try:
         for value in catValues:
             catName, count = value.split("=")
             if not totalValues.has_key(catName):
                 totalValues[catName] = 0
             totalValues[catName] += int(count)
     except ValueError:
         plugins.printWarning("Found truncated or old format batch report (" + localName + ") - could not parse result correctly.")
示例#10
0
 def _getFromApps(self, method, *args, **kwargs):
     callables = [ plugins.Callable(method, app, *args) for app in self.apps ]
     aggregator = plugins.ResponseAggregator(callables)
     try:
         return aggregator(**kwargs)
     except plugins.AggregationError, e:
         app = self.apps[e.index]
         plugins.printWarning("GUI configuration '" + "::".join(args) +\
                              "' differs between applications, ignoring that from " + repr(app) + "\n" + \
                              "Value was " + repr(e.value2) + ", change from " + repr(e.value1), stdout=True)
         return e.value1
示例#11
0
 def __getitem__(self, key):
     if self.readingFile:
         msg = (
             "Bug file at "
             + self.readingFile
             + " has duplicated sections named '"
             + key
             + "', the later ones will be ignored"
         )
         plugins.printWarning(msg)
     return OrderedDict.__getitem__(self, key)
示例#12
0
 def saveToRepository(self, test):
     testRepository = self.repositories[test.app]
     targetFile = os.path.join(testRepository, test.app.name, getVersionName(test.app, self.allApps), \
                               test.getRelPath(), self.fileName)
     if os.path.isfile(targetFile):
         plugins.printWarning("File already exists at " + targetFile + " - not overwriting!")
     else:
         try:
             plugins.ensureDirExistsForFile(targetFile)
             shutil.copyfile(test.getStateFile(), targetFile)
         except IOError:
             plugins.printWarning("Could not write file at " + targetFile)
 def setUpVirtualDisplay(self, guiSuites):
     if len(guiSuites) == 0:
         return
     machines = self.findMachines(guiSuites)
     displayCount = max((suite.getConfigValue("virtual_display_count") for suite in guiSuites))
     for _ in range(displayCount):
         displayInfo = self.getDisplayInfo(machines, guiSuites[0].app)
         if displayInfo:
             self.displayInfo.append(displayInfo)
             self.guiSuites = guiSuites
         elif len(machines) > 0:
             plugins.printWarning("Failed to start virtual display on " + ",".join(machines) + " - using real display.")
示例#14
0
 def _getFromApps(self, method, *args, **kwargs):
     prevValue = None
     for app in self.apps:
         currValue = method(app, *args, **kwargs)
         toUse = self.chooseValueFrom(prevValue, currValue)
         if toUse is None and prevValue is not None:
             plugins.printWarning("GUI configuration '" + "::".join(args) +\
                                  "' differs between applications, ignoring that from " + repr(app) + "\n" + \
                                  "Value was " + repr(currValue) + ", change from " + repr(prevValue))
         else:
             prevValue = toUse
     return prevValue
示例#15
0
 def makeParser(fileName):
     parser = ConfigParser()
     # Default behaviour transforms to lower case: we want case-sensitive
     parser.optionxform = str
     # There isn't a nice way to change the behaviour on getting a duplicate section
     # so we use a nasty way :)
     parser._sections = ParserSectionDict(fileName)
     try:
         parser.read(fileName)
         parser._sections.readingFile = None
         return parser
     except Exception:
         plugins.printWarning("Bug file at " + fileName + " not understood, ignoring")
示例#16
0
 def setUpVirtualDisplay(self, guiSuites):
     if len(guiSuites) == 0:
         return
     machines = self.findMachines(guiSuites)
     machine, display, pid = self.getDisplay(machines, guiSuites[0].app)
     if display:
         self.displayName = display
         self.displayMachine = machine
         self.displayPid = pid
         self.guiSuites = guiSuites
         plugins.log.info("Tests will run with DISPLAY variable set to " + display)
     elif len(machines) > 0:
         plugins.printWarning("Failed to start virtual display on " + ",".join(machines) + " - using real display.")
示例#17
0
    def getRootSuite(self, appName, versions):
        for app, testSuite in self.appSuites.items():
            if app.name == appName and app.versions == versions:
                return testSuite

        dirCache = self.makeDirectoryCache(appName)
        if dirCache:
            newApp = self.addApplication(appName, dirCache, versions)[0]
            return self.createEmptySuite(newApp)
        else:
            message = "Couldn't create directory cache for application: " + str(appName)
            plugins.printWarning(message)
            return None
示例#18
0
    def getRootSuite(self, appName, versions):
        for app, testSuite in self.appSuites.items():
            if app.name == appName and app.versions == versions:
                return testSuite

        dirCache = self.makeDirectoryCache(appName)
        if dirCache:
            newApp = self.addApplication(appName, dirCache, versions)[0]
            return self.createEmptySuite(newApp)
        else:
            message = "Couldn't create directory cache for application: " + str(appName)
            plugins.printWarning(message)
            return None
示例#19
0
    def getAppRepositoryInfo(self):
        appInfo = seqdict()
        for app in self.appsToGenerate:
            repository = app.getCompositeConfigValue("batch_result_repository", self.batchSession)
            if not repository:
                continue
            repository = os.path.join(repository, app.name)
            if not os.path.isdir(repository):
                plugins.printWarning("Batch result repository " + repository + " does not exist - not creating pages for " + repr(app))
                continue

            pageTitle = app.getCompositeConfigValue("historical_report_page_name", self.batchSession)
            appInfo.setdefault(pageTitle, []).append((app, repository))
        return appInfo
示例#20
0
 def makeParser(self, fileName):
     parser = ConfigParser()
     # Default behaviour transforms to lower case: we want case-sensitive
     parser.optionxform = str
     parser._sections = seqdict()
     # There isn't a nice way to change the behaviour on getting a duplicate section
     # so we use a nasty way :)
     realLookup = parser._sections.__getitem__
     parser._sections.__getitem__ = plugins.Callable(self.lookupSection, fileName, realLookup)
     try:
         parser.read(fileName)
         parser._sections.__getitem__ = realLookup
         return parser
     except:
         plugins.printWarning("Bug file at " + fileName + " not understood, ignoring", stderr=True, stdout=False)
示例#21
0
 def createView(self):
     # Create toplevel window to show it all.
     self.topWindow = gtk.Window(gtk.WINDOW_TOPLEVEL)
     self.topWindow.set_name("Top Window")
     try:
         import stockitems
         stockitems.register(self.topWindow)
     except Exception: #pragma : no cover - should never happen
         plugins.printWarning("Failed to register texttest stock icons.")
         plugins.printException()
     iconFile = self.getIcon()
     try:
         self.topWindow.set_icon_from_file(iconFile)
     except Exception, e:
         plugins.printWarning("Failed to set texttest window icon.\n" + str(e), stdout=True)
示例#22
0
 def migrate(self, test):
     for bugFileName in test.findAllStdFiles("knownbugs"):
         parser = ConfigParser()
         # Default behaviour transforms to lower case: we want case-sensitive
         parser.optionxform = str
         try:
             parser.read(bugFileName)
         except Exception:
             plugins.printWarning("Bug file at " + bugFileName + " not understood, ignoring")
             continue
         if not parser.has_section("Migrated section 1"):
             self.describe(test, " - " + os.path.basename(bugFileName))
             sys.stdout.flush()
             self.updateFile(bugFileName, parser)
         else:
             self.describe(test, " (already migrated)")
示例#23
0
    def findDefinitionFileStems(self, test, tmpFiles, ignoreMissing):
        if ignoreMissing:
            return test.expandedDefFileStems()

        stems = test.expandedDefFileStems("regenerate")
        for defFile in test.defFileStems("builtin") + test.defFileStems("default"):
            if tmpFiles.has_key(defFile):
                stems.append(defFile)
                # On the whole, warn the user if unexpected things get generated
                # Make an exception for recording as usecase-related files may be recorded that
                # won't necessarily be re-recorded
                if not test.app.isRecording():
                    plugins.printWarning("A file was generated with stem '" + defFile + "'.\n" +
                                         "This stem is intended to indicate a definition file and hence should not be generated.\n" +
                                         "Please change the configuration so that the file is called something else,\n" +
                                         "or adjust the config file setting 'definition_file_stems' accordingly.")
        return stems
示例#24
0
    def createView(self):
        # Create toplevel window to show it all.
        self.topWindow = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.topWindow.set_name("Top Window")
        try:
            import stockitems
            stockitems.register(self.topWindow)
        except: #pragma : no cover - should never happen
            plugins.printWarning("Failed to register texttest stock icons.")
            plugins.printException()
        self.topWindow.set_icon_from_file(self.getIcon())
        self.setWindowTitle()

        self.topWindow.add(self.subguis[0].createView())
        self.adjustSize()
        self.topWindow.show()
        self.topWindow.set_default_size(-1, -1)

        self.notify("TopWindow", self.topWindow)
        self.topWindow.connect("delete-event", self.windowClosed)
        return self.topWindow
    def startXvfb(self, startArgs, machine):
        for i in range(5):
            self.diag.info("Starting Xvfb using args " + repr(startArgs))
            self.displayProc = subprocess.Popen(startArgs, stdin=open(os.devnull), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
            line = plugins.retryOnInterrupt(self.displayProc.stdout.readline)
            if "Time Out!" in line:
                self.displayProc.wait()
                self.displayProc.stdout.close()
                self.diag.info("Timed out waiting for Xvfb to come up")
                # We try again and hope for a better process ID!
                continue
            try:
                displayNum, pid = map(int, line.strip().split(","))
                self.displayProc.stdout.close()
                return self.getDisplayName(machine, displayNum), pid
            except ValueError: #pragma : no cover - should never happen, just a fail-safe
                plugins.log.info("Failed to parse line :\n " + line + self.displayProc.stdout.read())
                return None, None

        messages = "Failed to start Xvfb in 5 attempts, giving up"
        plugins.printWarning(messages)
        return None, None
示例#26
0
    def getAppRepositoryInfo(self):
        appInfo = OrderedDict()
        for suite in self.suitesToGenerate:
            repository = getBatchRepository(suite)
            if not repository:
                continue
            app = suite.app
            repository = os.path.join(repository, app.name)
            if not os.path.isdir(repository):
                plugins.printWarning(
                    "Batch result repository " + repository + " does not exist - not creating pages for " + repr(app)
                )
                continue

            pageTitle = app.getBatchConfigValue("historical_report_page_name")
            extraApps = []
            for extraApp in app.extras:
                extraPageTitle = extraApp.getBatchConfigValue("historical_report_page_name")
                if extraPageTitle != pageTitle and extraPageTitle != extraApp.getDefaultPageName():
                    appInfo.setdefault(extraPageTitle, []).append((extraApp, repository, []))
                else:
                    extraApps.append(extraApp)
            appInfo.setdefault(pageTitle, []).append((app, repository, extraApps))
        return appInfo
示例#27
0
 def lookupSection(self, name, fileName, realLookup):
     msg = "Bug file at " + fileName + " has duplicated sections named '" + name + "', the later ones will be ignored"
     plugins.printWarning(msg, stderr=True, stdout=False)
     return realLookup(name)
示例#28
0
 def checkRepository(self, repository, app):
     if not os.path.isdir(repository):
         plugins.printWarning("Batch result repository " + repository + " does not exist - not creating pages for " + repr(app))
         return False
     return True
示例#29
0
    def setActionSequence(self, actionSequence):
        self.actionSequence = []
        # Copy the action sequence, so we can edit it and mark progress
        for action in actionSequence:
            self.actionSequence.append(action)

    def handleExceptions(self, method, *args):
        try:
            method(*args)
            return True
        except plugins.TextTestError, e:
            self.failTest(str(e))
        except:
            exceptionText = plugins.getExceptionString()
            plugins.printWarning("Caught exception while running " + repr(self.test) +
                                 " changing state to UNRUNNABLE :\n" + exceptionText.rstrip(), stdout=True)
            self.failTest(exceptionText)
        return False
    
    def failTest(self, excString):
        execHosts = self.test.state.executionHosts
        failState = plugins.Unrunnable(freeText=excString, briefText="TEXTTEST EXCEPTION", executionHosts=execHosts)
        self.test.changeState(failState)

    def performActions(self, previousTestRunner):
        tearDownSuites, setUpSuites = self.findSuitesToChange(previousTestRunner)
        for suite in tearDownSuites:
            self.handleExceptions(previousTestRunner.appRunner.tearDownSuite, suite)
        for suite in setUpSuites:
            self.appRunner.markForSetUp(suite)
        abandon = self.test.state.shouldAbandon()