예제 #1
0
  def start(self):
    '''Launch and wait for the process to initialize.'''
    print 'starting', self.cmd

    self.proc = Popen(self.cmd, shell=True, stderr=STDOUT, stdout=PIPE)
    self.socks = {}
    self._output_buffer = []
    self.waitForOutput('Starting BsonNetwork v')
    time.sleep(1.0)
예제 #2
0
class BsonNetworkProcess(object):
  '''Utility class in order to test BsoNetwork processes.'''

  def __init__(self, cmd, **kwargs):
    '''Initialize with the given command and arguments.'''
    self._parse_arguments(cmd, **kwargs)
    self.proc = None

  def _parse_arguments(self, cmd, port=None, clientid=None, **kwargs):
    '''Parse all the arguments and add them to the command.'''
    if isinstance(cmd, str):
      cmd = cmd.split(' ')

    if '-p' not in cmd and '--port' not in cmd:
      if port is None:
        port = process.randomPort()
      cmd.append('-p')
      cmd.append(str(port))
    self.port = int(cmd[cmd.index('-p') + 1])

    if '-i' not in cmd and '--client-id' not in cmd:
      if clientid is None:
        clientid = 'server'
      cmd.append('-i')
      cmd.append(clientid)
    self.clientid = cmd[cmd.index('-i') + 1]

    self.cmd = ' '.join(cmd)


  def start(self):
    '''Launch and wait for the process to initialize.'''
    print 'starting', self.cmd

    self.proc = Popen(self.cmd, shell=True, stderr=STDOUT, stdout=PIPE)
    self.socks = {}
    self._output_buffer = []
    self.waitForOutput('Starting BsonNetwork v')
    time.sleep(1.0)

  def stop(self):
    '''Stop the process, and print out all remaining output.'''
    for clientid in self.socks.keys():
      self.disconnect(clientid)
    self.socks = {}

    self.proc.terminate()
    if self.proc.poll() is None:
      self.proc.kill()

    self.proc = None

  def __enter__(self):
    '''This object can be used in a with clause. starts the process.'''
    self.start()
    return self

  def __exit__(self, type, value, traceback):
    '''This object can be used in a with clause. stops the process.'''
    self.stop()


  def waitForOutput(self, output):
    '''Waits for `output` to appear in the stdout or stderr of the process.'''
    print '=====> Waiting for: %s' % output

    # check backlog first.
    for line in self._output_buffer:
      if output in line:
        self._output_buffer.remove(line) # found it! remove it.
        return

    signal.signal(signal.SIGALRM, Alarm.handler)
    signal.alarm(10)
    tic = datetime.datetime.now()
    print 'TIC:', tic
    try:
      line = ''
      while output not in line:
        if len(line) > 1:
          self._output_buffer.append(line)
        line = self.proc.stdout.readline().strip()
        if len(line) > 1:
          print line
    except Alarm:
      toc = datetime.datetime.now()
      print 'RAISE TOC:', toc, ' :: ', (toc - tic)
      raise OutputTimeout('Timed out waiting for output: %s' % output)
    toc = datetime.datetime.now()
    print 'TOC:', toc, ' :: ', (toc - tic)
    signal.alarm(0)

  def _sendobj(self, clientid, doc):
    '''Sends bson document `doc` via socket with `clientid`.'''
    self.socks[clientid].send(bson.dumps(doc))

  def _recvobj(self, clientid, doc):
    '''Receives bson document `doc` via socket `clientid`.'''
    print len(bson.dumps(doc))
    res = self.socks[clientid].recvobj()
    #res = self.socks[clientid].recv(len(bson.dumps(doc)))
    print res
    return res


  def send(self, docs):
    '''Sends a collection of bson docs (with _src and _dst)'''
    print 'SENDING', docs
    if not isinstance(docs, list):
      docs = [docs]

    for doc in docs:
      self._sendobj(doc['_src'], doc)

  def receive(self, docs, printall=False):
    '''Receives a collection of bson docs (with _src and _dst)'''
    if not isinstance(docs, list):
      docs = [docs]

    for doc in docs:
      self.waitForOutput('[%(_dst)s] sending document' % doc)
      while printall:
        print self.proc.stdout.readline().strip()

      doc2 = self._recvobj(doc['_dst'], doc)
      if not dicts_equal(doc, doc2):
        raise DocumentMismatchError('Document mismatch:\n%s\n%s' % (doc, doc2))

  def send_and_receive(self, src, dst, docs):
    '''Sends and Receives a collection of bson docs (with _src and _dst)'''
    if not isinstance(docs, list):
      docs = [docs]

    for doc in docs:
      doc['_src'] = src
      doc['_dst'] = dst
      self.send(doc)
      self.receive(doc)

  def connect(self, clientid, trigger=True):
    '''Connects a socket with `clientid` to the process server.'''
    sock = None
    if trigger:
      print '=====> Connecting', clientid, 'to', self.port
      sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
      sock.connect(('', self.port))
      self.socks[clientid] = sock
    self.waitForOutput('connection made')
    return sock

  def disconnect(self, clientid, trigger=True):
    '''Disconnects the socket with `clientid` from the process server.'''
    if trigger:
      sock = self.socks[clientid]
      sock.close()
      del self.socks[clientid]
    self.waitForOutput('[%s] connection closed' % clientid)

  def identify(self, clientid, trigger=True):
    '''Identifies the socket with `clientid` with the process server.'''
    self.waitForOutput('sending identification message')
    if trigger:
      self._recvobj(clientid, { '_src' : self.clientid } )
      self._sendobj(clientid, { '_src' : clientid } )
    self.waitForOutput('[%s] connection identified' % clientid)

  def reidentify(self, oldid, newid, trigger=True):
    '''Re-identifies the socket with `oldid` with `newid`.'''
    if trigger:
      self.socks[newid] = self.socks[oldid]
      del self.socks[oldid]
      self._sendobj(newid, { '_src' : newid } )
    self.waitForOutput('[%s] connection identified' % newid)