mochidriver.py
author Joel Maher <joel.maher@gmail.com>
Tue, 06 Oct 2009 13:54:42 -0400
changeset 8 7b4193f6c7101594740b5709d676568f868d77bb
parent 7 66b33bdac429170aeb3158671db60040e2b2fda6
child 10 a24ca1062300e71e2d0633ab9eedb3f88d91053f
permissions -rwxr-xr-x
removed xda for winmo and added test-agent for winmo

import os,re,maemkit
import ce

class MochiKit(maemkit.MaemKit):
  options = {}
  mochitestCommand = []
  directories = []
  testagent = ce.TestAgentCE()

  def __init__(self, mkit):
    self.dirtype = mkit.dirtype
    self.addOptions(mkit.config_options["mochitest"])

  def addOptions(self, input):
    for option in input:
      if (option == "split-directories"):
        self.options[option] = []
        for part in input[option].split(','): self.options[option].append(os.path.normpath(part.strip('\"')))
      else:
        self.options[option] = input[option]

  #originally written by harthur
  def getDirectories(self, aDir):
    testFilePattern = 'test_.*'
    testsDirPattern = ".*?" + self.dirtype + "tests" + self.dirtype + "(.*)"

    #returns the smallest possible directories containing tests (leaves of tests tree)
    dir = []
    relDirectories = []

    for split in self.options["split-directories"]: self.stitchDirectory(split)

    # get the smallest directories with test files in them
    for root, dirs, files in os.walk(aDir):
      p = re.compile(testFilePattern)
      for mFile in files:
        if(p.match(mFile)):
          dir.append(root)
          # don't search any further in this tree
          for directory in dirs:
            dirs.remove(directory)
          break

    # truncate path to path relative to tests directory
    testPatt = re.compile(testsDirPattern)
    for directory in dir:
      relDir = testPatt.match(directory)
      if relDir:
        relDirectories.append(relDir.group(1))

    relDirectories.sort()
    self.directories = relDirectories


  def getFiles(self, aDir):
    testFilePattern = 'test_.*'

    for split in self.options["split-directories"]: self.stitchDirectory(split)

    # get the smallest directories with test files in them
    p = re.compile(testFilePattern)
    for root, dirs, files in os.walk(aDir):
      for mFile in files:
        if(p.match(mFile)):
          #root will be self.options["testroot"]/tests/* and we want the *
          #assuming c:\\desktop\\mochitest\\tests\\*
          count = len(self.options["testroot"].split(self.dirtype)) + 1
          roots = root.split(self.dirtype, count)
          self.directories.append(os.path.join(roots[count],mFile))


  #Put directory back to normal; not necessary, but good to have
  def stitchDirectory(self, aDir):
    dirlist = []

    basedir = os.path.normpath(os.path.join(self.options["testroot"], "tests"))
    for root, dirs, files in os.walk(os.path.join(basedir, aDir)):
      dirlist = dirs
      break

    numtosplit = abs(100 / int(self.options["split-percentage"]))
    try:
      if (dirlist.index(str(numtosplit)) >= 0):
        try:
          if (dirlist.index(str(numtosplit + 1)) >= 0): stitch = True
        except: stitch = False
    except: stitch = True

    base_dir = os.path.normpath(os.path.join(basedir, aDir))

    if (stitch == True):
      myre = re.compile("^([0-9]+)$")
      for dir in dirlist:
        res = myre.match(dir)
        if (res):
          try:
            self.move(os.path.normpath(os.path.join(os.path.join(base_dir, res.group(1)), "*")), base_dir)
            self.rmdir(os.path.normpath(os.path.join(base_dir, res.group(1))))
          except:
            if (self.debug >= 1): print "couldn't find directory: " + res.group(1) + " in " + aDir
            pass

      try:
        self.move(os.path.normpath(os.path.join(os.path.join(base_dir, "tests"), "*")), base_dir)
        self.rmdir(os.path.normpath(os.path.join(base_dir, "tests")))
      except:
        if (self.debug >= 1): print "no directory tests in: " + aDir
        pass
    return

  def splitDirectory(self, aDir):

    num_files = 0
    for root,dirs,files in os.walk(os.path.normpath(os.path.join(os.path.join(self.options["testroot"], "tests"), aDir))):
      num_files = len(files)
      break

    bDir = os.path.normpath(os.path.join(os.path.join(self.options["testroot"], "tests"), aDir))

    dirlist = []
    for root, dirs, files in os.walk(bDir):
      dirlist = dirs
      break

    self.mkdir(os.path.join(bDir, "tests"))
    self.move(os.path.join(bDir, "test_*"), os.path.join(bDir, "tests"))

    num_files = 0
    testfiles = []
    for root,dirs,files in os.walk(os.path.join(bDir, "tests")):
      for file in files: testfiles.append(file)
      num_files = len(testfiles)
      break

    numtosplit = abs(100 / int(self.options["split-percentage"]))
    self.directories.remove(aDir)
    for num in range(numtosplit):
      newdir = os.path.normpath(os.path.join(aDir, str(num)))
      bnewdir = os.path.normpath(os.path.join(bDir, str(num)))
      self.directories.append(newdir)
      self.mkdir(bnewdir)
      self.copyfile(os.path.join(bDir, "*"), bnewdir)

      for dir in dirlist:
        if (dir != "tests"):
          self.mkdir(os.path.normpath(os.path.join(bnewdir, dir)))
          self.copyfile(os.path.normpath(os.path.join(os.path.join(bDir, dir), "*")), os.path.join(bnewdir, dir))

    num_copy = num_files / numtosplit
    count = 0
    round = 0
    for file in testfiles:
      self.copyfile(os.path.join(os.path.join(bDir, "tests"), file), os.path.join(bDir, str(round)))

      count = count + 1
      if (count >= num_copy):
        count = 0
        if (round < numtosplit - 1): round = round + 1

    self.rmdir(os.path.join(bDir, "tests"))


  def getTests(self):
      rootdir = os.path.normpath(os.path.join(self.options["testroot"], "tests"))
      if (self.options["test-path"] != None):
          rootdir = os.path.normpath(os.path.join(rootdir, self.options["test-path"]))
      if (self.singletest == True):
          self.getFiles(rootdir)
      else:
          self.getDirectories(rootdir)

  def ignoreTimeouts(self):
      ignore = []    
      temp = self.directories
      
      #build list of ignore files
      if (os.path.exists(self.options["timeout-log"])):
          f = open(self.options["timeout-log"], "r")
          lines = f.read().split("\n")
          f.close()
          for line in lines:
              if (line.strip() != ""):
                  ignore.append(line.strip())


          #remove ignore files
          self.directories = temp
          for dir in ignore:
              try:
                  temp.remove(dir)
              except:
                  pass
      if (self.debug >= 1): 
          print "new length: " + str(len(temp))
  
      self.directories = temp

  def ignorePartialRun(self):
      temp = self.directories
      for root, dirs, files in os.walk(self.options["logdir"]):
         for file in files:
             ref = file.strip()
             for dir in self.directories:
                 parts = dir.rsplit(self.dirtype, 1)
                 if (parts[1].strip() + ".log" == ref):
                     try: temp.remove(dir)
                     except: pass

      if (self.debug >=1 ):
          print "done preping tests: " + str(len(temp))
      self.directories = temp


  def prepTests(self):
    if (self.singletest == True):
      self.ignoreTimeouts()
      self.ignorePartialRun()
    else:
      # We need to copy to testdirs as self.splitDirectory modifies the self.directories variable
      testdirs = []
      for dir in self.directories: testdirs.append(dir)

      for dir in testdirs:
          try:
              if (self.options["split-directories"].index(dir) >= 0): self.splitDirectory(dir)
          except: continue

      self.directories = self.splitListParallel(self.directories, self.options)
  
  def setupRemoteProfile(self):
      self.mochitestCommand = ["python " + os.path.normpath(os.path.join(self.options["testroot"], "runtests.py")).replace("\\", "/") + " --setup-only "]
      self.mochitestCommand.append("--remote-webserver=" + os.path.normpath(self.options["remote-webserver"]))
      self.mochitestCommand.append("--appname=" + os.path.normpath(os.path.join(self.options["xre-path"], "xpcshell.exe")).replace("\\", "/"))
      mCommand = " ".join(self.mochitestCommand)
      self.addCommand(mCommand)

      remoteProfile = os.path.join(self.options["remote-logdir"], self.options["profiledir"])
      localProfile = os.path.normpath(os.path.join(self.options["testroot"], self.options["profiledir"]))
      self.testagent.pushDir(localProfile, remoteProfile)
  
  def setupLocalWebserver(self):
      pass

  def terminateWebserver(self):
      pass

  def runTests(self):
      self.mkLogDir(self.options["logdir"])

      #TODO: figure out a method for utilizing all the other config/cli options available
      self.mochitestCommand = ["python " + os.path.normpath(os.path.join(self.options["testroot"], "runtests.py")) + " --autorun --close-when-done"]
      for option in ["utility-path","appname","xre-path","certificate-path"]:
          self.mochitestCommand.append("--" + option + "=" + os.path.normpath(self.options[option]))
      mCommand = " ".join(self.mochitestCommand)

      singletest = [self.options["appname"], '--environ:NO_EM_RESTART=1', '-no-remote', '-profile', os.path.join(self.options["remote-logdir"], self.options["profiledir"]) ]
      if (self.singletest == True):
          self.setupRemoteProfile()
          self.setupLocalWebserver()

      for directory in self.directories:
          if (self.singletest == True):
              cmd = "http://" + self.options["remote-webserver"] + "/tests/"
              cmd += directory.replace("\\", "/") + "?logFile="
              remoteLog = os.path.join(self.options["remote-logdir"], self.options["log-file"]).replace("\\", "%5c")
              cmd += remoteLog

              self.testagent.removeFile(remoteLog)
              if (self.addCommandWinCE(" ".join(singletest) + " " + cmd + " > \\tests\\fennec.txt", timeout=2) == "*** TIMEOUT ***"):
                  self.cleanup()
                  f = open(self.options["timeout-log"], "a")
                  f.write(directory + "\n")
                  f.close()
                  if (self.debug >= 1): 
                      print "timed out: " + directory
              tests = directory.rsplit(self.dirtype, 1)
              log = os.path.join(self.options["logdir"], tests[1] + '.log')
              self.testagent.getFile(remoteLog, log)
              self.cleanup()
          else:
              mydir = directory.replace('\\', '/')
              logfile = os.path.join(self.options["logdir"],  self.getLogFileName(directory))
              self.addCommand(mCommand + " --test-path=" + mydir + " --log-file=" + logfile)
              if self.options['verbose'] and os.path.exists(logfile):
                  print ''.join(open(logfile).readlines())
              self.cleanup() #just for safety measures

      if (self.singletest == True):
          self.terminateWebserver()
  def parseLogs(self):
      self.stitchLogs()