tests/ide_tests/sikuliberemiz.py
branchwxPython4
changeset 3424 7db96e011fe7
child 3430 c2171d87b587
equal deleted inserted replaced
3423:84afcc0ebadd 3424:7db96e011fe7
       
     1 "Commons definitions for sikuli based beremiz IDE GUI tests"
       
     2 
       
     3 import os
       
     4 import sys
       
     5 import subprocess
       
     6 from threading import Thread, Event
       
     7 from sikuli import *
       
     8 
       
     9 home = os.environ["HOME"]
       
    10 beremiz_path = os.environ["BEREMIZPATH"]
       
    11 
       
    12 opj = os.path.join
       
    13 
       
    14 
       
    15 def StartBeremizApp(projectpath=None, exemple=None):
       
    16     """
       
    17     Starts Beremiz IDE, waits for main window to appear, maximize it.
       
    18 
       
    19         Parameters: 
       
    20             projectpath (str): path to project to open
       
    21             exemple (str): path relative to exemples directory
       
    22 
       
    23         Returns:
       
    24             Sikuli App class instance
       
    25     """
       
    26 
       
    27     command = ["%s/beremizenv/bin/python"%home, opj(beremiz_path,"Beremiz.py"), "--log=/dev/stdout"]
       
    28 
       
    29     if exemple is not None:
       
    30         command.append(opj(beremiz_path,"exemples",exemple))
       
    31     elif projectpath is not None:
       
    32         command.append(projectpath)
       
    33 
       
    34     # App class is broken in Sikuli 2.0.5: can't start process with arguments.
       
    35     # 
       
    36     # Workaround : - use subprocess module to spawn IDE process,
       
    37     #              - use wmctrl to find IDE window details and maximize it
       
    38     #              - pass exact window title to App class constructor
       
    39 
       
    40     proc = subprocess.Popen(command, stdout=subprocess.PIPE, bufsize=0)
       
    41 
       
    42     # Window are macthed against process' PID
       
    43     ppid = proc.pid
       
    44 
       
    45     # Timeout 5s
       
    46     c = 50
       
    47     while c > 0:
       
    48         # equiv to "wmctrl -l -p | grep $pid"
       
    49         try:
       
    50             wlist = filter(lambda l:(len(l)>2 and l[2]==str(ppid)), map(lambda s:s.split(None,4), subprocess.check_output(["wmctrl", "-l", "-p"]).splitlines()))
       
    51         except subprocess.CalledProcessError:
       
    52             wlist = []
       
    53 
       
    54         # window with no title only has 4 fields do describe it
       
    55         # beremiz splashcreen has no title
       
    56         # we wity until main window is visible
       
    57         if len(wlist) == 1 and len(wlist[0]) == 5:
       
    58             windowID,_zero,wpid,_XID,wtitle = wlist[0] 
       
    59             break
       
    60 
       
    61         wait(0.1)
       
    62         c = c - 1
       
    63 
       
    64     if c == 0:
       
    65         raise Exception("Couldn't find Beremiz window")
       
    66 
       
    67     # Maximize window x and y
       
    68     subprocess.check_call(["wmctrl", "-i", "-r", windowID, "-b", "add,maximized_vert,maximized_horz"])
       
    69 
       
    70     # switchApp creates an App object by finding window by title, is not supposed to spawn a process
       
    71     return proc, switchApp(wtitle)
       
    72 
       
    73 class KBDShortcut:
       
    74     """Send shortut to app by calling corresponding methods:
       
    75           Stop   
       
    76           Run    
       
    77           Transfer
       
    78           Connect
       
    79           Clean  
       
    80           Build  
       
    81 
       
    82     example:
       
    83         k = KBDShortcut(app)
       
    84         k.Clean()
       
    85     """
       
    86 
       
    87     fkeys = {"Stop":     Key.F4,
       
    88              "Run":      Key.F5,
       
    89              "Transfer": Key.F6,
       
    90              "Connect":  Key.F7,
       
    91              "Clean":    Key.F9,
       
    92              "Build":    Key.F11}
       
    93 
       
    94     def __init__(self, app):
       
    95         self.app = app
       
    96     
       
    97     def __getattr__(self, name):
       
    98         fkey = self.fkeys[name]
       
    99         app = self.app
       
   100 
       
   101         def PressShortCut():
       
   102             app.focus()
       
   103             type(fkey)
       
   104 
       
   105         return PressShortCut
       
   106 
       
   107 
       
   108 class IDEIdleObserver:
       
   109     "Detects when IDE is idle. This is particularly handy when staring an operation and witing for the en of it."
       
   110 
       
   111     def __init__(self, app):
       
   112         """
       
   113         Parameters: 
       
   114             app (class App): Sikuli app given by StartBeremizApp
       
   115         """
       
   116         self.r = Region(app.window())
       
   117 
       
   118         self.idechanged = False
       
   119         
       
   120         # 200 was selected because default 50 was still catching cursor blinking in console
       
   121         # FIXME : remove blinking cursor in console
       
   122         self.r.onChange(200,self._OnIDEWindowChange)
       
   123         self.r.observeInBackground()
       
   124 
       
   125     def __del__(self):
       
   126         self.r.stopObserver()
       
   127 
       
   128     def _OnIDEWindowChange(self, event):
       
   129         print event
       
   130         self.idechanged = True
       
   131 
       
   132     def Wait(self, period, timeout):
       
   133         """
       
   134         Wait for IDE to stop changing
       
   135         Parameters: 
       
   136             period (int): how many seconds with no change to consider idle
       
   137             timeout (int): how long to wait for idle, in seconds
       
   138         """
       
   139         c = timeout/period
       
   140         while c > 0:
       
   141             self.idechanged = False
       
   142             wait(period)
       
   143             if not self.idechanged:
       
   144                 break
       
   145             c = c - 1
       
   146 
       
   147         if c == 0:
       
   148             raise Exception("Window did not idle before timeout")
       
   149 
       
   150  
       
   151 class stdoutIdleObserver:
       
   152     "Detects when IDE's stdout is idle. Can be more reliable than pixel based version (false changes ?)"
       
   153 
       
   154     def __init__(self, proc):
       
   155         """
       
   156         Parameters: 
       
   157             proc (subprocess.Popen): Beremiz process, given by StartBeremizApp
       
   158         """
       
   159         self.proc = proc
       
   160         self.stdoutchanged = False
       
   161 
       
   162         self.thread = Thread(target = self._waitStdoutProc).start()
       
   163 
       
   164     def _waitStdoutProc():
       
   165         while True:
       
   166             a = self.proc.stdout.read(1)
       
   167             if len(a) == 0 or a is None: 
       
   168                 break
       
   169             sys.stdout.write(a)
       
   170             self.idechanged = True
       
   171 
       
   172     def Wait(self, period, timeout):
       
   173         """
       
   174         Wait for IDE'stdout to stop changing
       
   175         Parameters: 
       
   176             period (int): how many seconds with no change to consider idle
       
   177             timeout (int): how long to wait for idle, in seconds
       
   178         """
       
   179         c = timeout/period
       
   180         while c > 0:
       
   181             self.idechanged = False
       
   182             wait(period)
       
   183             if not self.idechanged:
       
   184                 break
       
   185             c = c - 1
       
   186 
       
   187         if c == 0:
       
   188             raise Exception("Stdout did not idle before timeout")
       
   189 
       
   190 
       
   191 def waitPatternInStdout(proc, pattern, timeout, count=1):
       
   192     
       
   193     success_event = Event()
       
   194 
       
   195     def waitPatternInStdoutProc():
       
   196         found = 0
       
   197         while True:
       
   198             a = proc.stdout.readline()
       
   199             if len(a) == 0 or a is None: 
       
   200                 raise Exception("App finished before producing expected stdout pattern")
       
   201             sys.stdout.write(a)
       
   202             if a.find(pattern) >= 0:
       
   203                 found = found + 1
       
   204                 if found >= count:
       
   205                     success_event.set()
       
   206                     break
       
   207 
       
   208 
       
   209     Thread(target = waitPatternInStdoutProc).start()
       
   210 
       
   211     if not success_event.wait(timeout):
       
   212         # test timed out
       
   213         return False
       
   214     else:
       
   215         return True
       
   216 
       
   217 
       
   218