def __init__(self, socket=None, wait=True): """ Spawns a node.js subprocess that listens on a TCP socket. A :class:`zombie.proxy.client.ZombieProxyClient` streams data to the server, which evaluates it as Javascript, passes it on to a zombie.js Browser object, and returns the results. :param socket: a (random, by default) filepath representing the intended TCP socket location :param wait: when True, wait until the node.js subprocess is responsive via the specified TCP socket. """ socket = socket or '/tmp/zombie-%s.sock' % random.randint(0, 10000) self.socket = socket # # Spawn the node proxy server in a subprocess. # This is a simple socket server that listens for data, # evaluates it as Javascript, and passes the eval'ed # input to a Zombie.js Browser object. # args = ['env', 'node', proxy_path, self.socket] self.child = subprocess.Popen( args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT ) self.child.stdin.close() if wait: # Wait until we can ping the node.js server client = ZombieProxyClient(socket) retries = 30 while True: retries -= 1 if retries < 0: # pragma: nocover raise RuntimeError( "The proxy server has not replied within 3 seconds." ) try: assert client.ping() == 'pong' except (SocketError, AssertionError): pass else: break time.sleep(.1) # # Start a thread to monitor and redirect the # subprocess stdout and stderr to the console. # PipeWorker(self.child.stdout).start()
def __init__(self, socket=None, wait=True): """ Spawns a node.js subprocess that listens on a TCP socket. A :class:`zombie.proxy.client.ZombieProxyClient` streams data to the server, which evaluates it as Javascript, passes it on to a zombie.js Browser object, and returns the results. :param socket: a (random, by default) filepath representing the intended TCP socket location :param wait: when True, wait until the node.js subprocess is responsive via the specified TCP socket. """ socket = socket or '/tmp/zombie-%s.sock' % random.randint(0, 10000) self.socket = socket # Kill the node process when finished atexit.register(__kill_node_processes__) # # Spawn the node proxy server in a subprocess. # This is a simple socket server that listens for data, # evaluates it as Javascript, and passes the eval'ed # input to a Zombie.js Browser object. # args = ['env', 'node', proxy_path, self.socket] self.child = subprocess.Popen( args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT ) self.child.stdin.close() PipeWorker(self.child.stdout).start() if wait: # Wait until we can ping the node.js server client = ZombieProxyClient(socket) retries = 30 while True: retries -= 1 if retries < 0: # pragma: nocover raise RuntimeError( "The proxy server has not replied within 3 seconds." ) try: assert client.ping() == 'pong' except (SocketError, AssertionError): pass else: break time.sleep(.1)
def __init__(self, socket=None, wait=True): """ Spawns a node.js subprocess that listens on a TCP socket. A :class:`zombie.proxy.client.ZombieProxyClient` streams data to the server, which evaluates it as Javascript, passes it on to a zombie.js Browser object, and returns the results. :param socket: a (random, by default) filepath representing the intended TCP socket location, or (on Windows) a tuple containing a host and a port name (defaults to ("127.0.0.1", 40140). :param wait: when True, wait until the node.js subprocess is responsive via the specified TCP socket. """ # no file based unix socket on windows if sys.platform == "win32": socket = socket or ("127.0.0.1", 40140) else: socket = socket or '/tmp/zombie-%s.sock' % random.randint(0, 10000) self.socket = socket # Kill the node process when finished atexit.register(__kill_node_processes__) # # Spawn the node proxy server in a subprocess. # This is a simple socket server that listens for data, # evaluates it as Javascript, and passes the eval'ed # input to a Zombie.js Browser object. # if sys.platform == "win32": # no env on windows, # just make sure that node is on the path # also no Unix file socket on windows, thus # only the port from the INET socket given as argument args = ['node', proxy_path, str(self.socket[1])] else: args = ['env', 'node', proxy_path, self.socket] self.child = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) self.child.stdin.close() PipeWorker(self.child.stdout).start() if wait: # Wait until we can ping the node.js server client = ZombieProxyClient(socket) retries = 30 while True: retries -= 1 if retries < 0: # pragma: nocover raise RuntimeError( "The proxy server has not replied within 3 seconds.") try: assert client.ping() == 'pong' except (SocketError, AssertionError): pass else: break time.sleep(.1)
class ZombieProxyClientTests(WebServerTestCase): def setUp(self): super(ZombieProxyClientTests, self).setUp() # Note, As a singleton so it will be created once, not in every test. self.server = ZombieProxyServer() self.client = ZombieProxyClient(self.server.socket) def tearDown(self): super(ZombieProxyClientTests, self).tearDown() def test_simple_json(self): obj = { 'foo': 'bar', 'test': 500 } self.assertEqual(obj, self.client.json(obj)) def test_malformed_command(self): with self.assertRaises(NodeError): self.client.json("banana") def test_nowait(self): self.assertEqual('Test', self.client.nowait("result = 'Test';")) def test_wait(self): self.client.wait('browser.visit', self.base_url) def test_wait_error(self): with self.assertRaises(NodeError): self.client.wait('browser.visit', self.base_url + 'notfound') def test_ping(self): self.assertEqual("pong", self.client.ping()) def test_cleanup(self): client = self.client self.assertEqual(1, client.json('browser.testing = 1')) client.cleanup() self.assertFalse(client.json('"testing" in browser')) def test_create_element(self): client = self.client client.wait('browser.visit', self.base_url) self.assertEqual( 0, client.create_element('browser.query', ('form',)).index) self.assertEqual( 1, client.create_element('browser.query', ('form',)).index) def test_create_element_attribute(self): client = self.client client.wait('browser.visit', self.base_url) self.assertEqual( 0, client.create_element('browser.html').index) def test_create_elements(self): client = self.client client.wait('browser.visit', self.base_url) res = client.create_elements('browser.queryAll', ('input', )) self.assertEqual(list(range(6)), [x.index for x in res])