#!/usr/bin/env python # Any copyright is dedicated to the Public Domain. # http://creativecommons.org/publicdomain/zero/1.0/ import datetime import socket import time from threading import Thread class MockAgent(object): MAX_WAIT_TIME_SECONDS = 10 SOCKET_TIMEOUT_SECONDS = 5 def __init__(self, tester, start_commands=None, commands=[]): if start_commands: self.commands = start_commands else: self.commands = [("ver", "SUTAgentAndroid Version 1.14")] self.commands = self.commands + commands self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self._sock.bind(("127.0.0.1", 0)) self._sock.listen(1) self.tester = tester self.thread = Thread(target=self._serve_thread) self.thread.start() self.should_stop = False @property def port(self): return self._sock.getsockname()[1] def _serve_thread(self): conn = None while self.commands: if not conn: conn, addr = self._sock.accept() conn.settimeout(self.SOCKET_TIMEOUT_SECONDS) conn.send("$>\x00") (command, response) = self.commands.pop(0) data = '' timeout = datetime.datetime.now() + datetime.timedelta( seconds=self.MAX_WAIT_TIME_SECONDS) # The data might come in chunks, particularly if we are expecting # multiple lines, as with push commands. while (len(data) < len(command) and datetime.datetime.now() < timeout): try: data += conn.recv(1024) except socket.timeout: # We handle timeouts in the main loop. pass self.tester.assertEqual(data.strip(), command) # send response and prompt separately to test for bug 789496 # FIXME: Improve the mock agent, since overloading the meaning # of 'response' is getting confusing. if response is None: # code for "shut down" conn.shutdown(socket.SHUT_RDWR) conn.close() conn = None elif type(response) is int: # code for "time out" max_timeout = 15.0 timeout = 0.0 interval = 0.1 while not self.should_stop and timeout < max_timeout: time.sleep(interval) timeout += interval if timeout >= max_timeout: raise Exception("Maximum timeout reached! This should not " "happen") return else: # pull is handled specially, as we just pass back the full # command line if "pull" in command: conn.send(response) else: conn.send("%s\n" % response) conn.send("$>\x00") def wait(self): self.thread.join()