Package pysys :: Package process :: Module commonwrapper
[hide private]
[frames] | no frames]

Source Code for Module pysys.process.commonwrapper

  1  #!/usr/bin/env python 
  2  # PySys System Test Framework, Copyright (C) 2006-2016  M.B.Grieve 
  3   
  4  # This library is free software; you can redistribute it and/or 
  5  # modify it under the terms of the GNU Lesser General Public 
  6  # License as published by the Free Software Foundation; either 
  7  # version 2.1 of the License, or (at your option) any later version. 
  8   
  9  # This library is distributed in the hope that it will be useful, 
 10  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 11  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 12  # Lesser General Public License for more details. 
 13   
 14  # You should have received a copy of the GNU Lesser General Public 
 15  # License along with this library; if not, write to the Free Software 
 16  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 
 17   
 18  # Contact: moraygrieve@users.sourceforge.net 
 19   
 20  import string, os.path, time, thread, logging, Queue 
 21   
 22  from pysys import log 
 23  from pysys import process_lock 
 24  from pysys.constants import * 
 25  from pysys.exceptions import * 
 26   
 27  # check for new lines on end of a string 
 28  EXPR = re.compile(".*\n$") 
 29   
30 -def _stringToUnicode(s):
31 """ Converts a unicode string or a utf-8 bit string into a unicode string. 32 33 """ 34 if isinstance(s, unicode): 35 return s 36 else: 37 return unicode(s, "utf8")
38
39 -class CommonProcessWrapper(object):
40 """Abstract base process wrapper class for process execution and management. 41 42 A base implementation of common process related operations, which should be extended 43 by the OS specific wrapper classes. 44 45 @ivar pid: The process id for a running or complete process (as set by the OS) 46 @type pid: integer 47 @ivar exitStatus: The process exit status for a completed process 48 @type exitStatus: integer 49 50 """ 51
52 - def __init__(self, command, arguments, environs, workingDir, state, timeout, stdout=None, stderr=None, displayName=None):
53 """Create an instance of the process wrapper. 54 55 @param command: The full path to the command to execute 56 @param arguments: A list of arguments to the command 57 @param environs: A dictionary of environment variables (key, value) for the process context execution 58 @param workingDir: The working directory for the process 59 @param state: The state of the process (L{pysys.constants.FOREGROUND} or L{pysys.constants.BACKGROUND} 60 @param timeout: The timeout in seconds to be applied to the process 61 @param stdout: The full path to the filename to write the stdout of the process 62 @param stderr: The full path to the filename to write the sdterr of the process 63 @param displayName: Display name for this process 64 65 """ 66 self.displayName = displayName if displayName else os.path.basename(command) 67 self.command = command 68 self.arguments = arguments 69 self.environs = {} 70 for key in environs: self.environs[_stringToUnicode(key)] = _stringToUnicode(environs[key]) 71 self.workingDir = workingDir 72 self.state = state 73 self.timeout = timeout 74 75 # 'publicly' available data attributes set on execution 76 self.pid = None 77 self.exitStatus = None 78 79 # print process debug information 80 log.debug("Process parameters for executable %s" % os.path.basename(self.command)) 81 log.debug(" command : %s", self.command) 82 for a in self.arguments: log.debug(" argument : %s", a) 83 log.debug(" working dir : %s", self.workingDir) 84 log.debug(" stdout : %s", stdout) 85 log.debug(" stderr : %s", stderr) 86 keys=self.environs.keys() 87 keys.sort() 88 for e in keys: log.debug(" environment : %s=%s", e, self.environs[e]) 89 90 # private 91 self._outQueue = None
92 93
94 - def __str__(self): return self.displayName
95 - def __repr__(self): return '%s (pid %s)'%(self.displayName, self.pid)
96 97 # these abstract methods must be implemented by subclasses
98 - def setExitStatus(self): raise Exception('Not implemented')
99 - def startBackgroundProcess(self): raise Exception('Not implemented')
100 - def writeStdin(self): raise Exception('Not implemented')
101 - def stop(self): raise Exception('Not implemented')
102 - def signal(self): raise Exception('Not implemented')
103
104 - def write(self, data, addNewLine=True):
105 """Write data to the stdin of the process. 106 107 Note that when the addNewLine argument is set to true, if a new line does not 108 terminate the input data string, a newline character will be added. If one 109 already exists a new line character will not be added. Should you explicitly 110 require to add data without the method appending a new line charater set 111 addNewLine to false. 112 113 @param data: The data to write to the process stdout 114 @param addNewLine: True if a new line character is to be added to the end of 115 the data string 116 117 """ 118 if not self.running(): raise Exception('Cannot write to process stdin when it is not running') 119 if addNewLine and not EXPR.search(data): data = "%s\n" % data 120 121 if self._outQueue == None: 122 # start thread on demand 123 self._outQueue = Queue.Queue() 124 thread.start_new_thread(self.writeStdin, ()) 125 126 self._outQueue.put(data)
127
128 - def running(self):
129 """Check to see if a process is running, returning true if running. 130 131 @return: The running status (True / False) 132 @rtype: integer 133 134 """ 135 return self.setExitStatus() is None
136 137
138 - def wait(self, timeout):
139 """Wait for a process to complete execution. 140 141 The method will block until either the process is no longer running, or the timeout 142 is exceeded. Note that the method will not terminate the process if the timeout is 143 exceeded. 144 145 @param timeout: The timeout to wait in seconds. Always provide a 146 timeout, otherwise your test may block indefinitely! 147 @raise ProcessTimeout: Raised if the timeout is exceeded. 148 149 """ 150 startTime = time.time() 151 while self.running(): 152 if timeout: 153 currentTime = time.time() 154 if currentTime > startTime + timeout: 155 raise ProcessTimeout, "Process timedout" 156 time.sleep(0.05)
157 158 159
160 - def start(self):
161 """Start a process using the runtime parameters set at instantiation. 162 163 @raise ProcessError: Raised if there is an error creating the process 164 @raise ProcessTimeout: Raised in the process timed out (foreground process only) 165 166 """ 167 self._outQueue = None # always reset 168 169 if self.workingDir and not os.path.isdir(self.workingDir): 170 raise Exception('Cannot start process %s as workingDir "%s" does not exist'% (self, self.workingDir)) 171 172 if self.state == FOREGROUND: 173 self.startBackgroundProcess() 174 self.wait(self.timeout) 175 else: 176 self.startBackgroundProcess()
177