1e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa#!/usr/bin/python
2e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa# Copyright 2017 The Chromium OS Authors. All rights reserved.
3e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa# Use of this source code is governed by a BSD-style license that can be
4e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa# found in the LICENSE file.
5e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
6e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwaimport os
7e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwaimport shutil
8e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwaimport socket
9e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwaimport tempfile
10e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwaimport unittest
11e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwafrom multiprocessing import connection
12e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
13e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwaimport common
14e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwafrom autotest_lib.client.common_lib import error
15e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwafrom autotest_lib.site_utils.lxc import unittest_setup
16e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwafrom autotest_lib.site_utils.lxc.container_pool import async_listener
17764c6d7451342e00768b9724badcc9514d31f626Ben Kwafrom autotest_lib.site_utils.lxc.container_pool import unittest_client
18e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
19e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
20e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa# Namespace object for parsing cmd line options.
21e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwaoptions = None
22e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
23e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
24e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwaclass AsyncListenerTests(unittest.TestCase):
25e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa    """Unit tests for the AsyncListener class."""
26e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
27e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa    def setUp(self):
28e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        self.tmpdir = tempfile.mkdtemp()
29e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        self.address = os.path.join(self.tmpdir, 'socket')
30e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        self.authkey = 'foo'
31764c6d7451342e00768b9724badcc9514d31f626Ben Kwa        self.listener = async_listener.AsyncListener(self.address)
32e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
33e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
34e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa    def tearDown(self):
35e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        self.listener.close()
36e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        shutil.rmtree(self.tmpdir)
37e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
38e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
39e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa    def testInvalidAddresses(self):
40e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        """Verifies that invalid socket paths raise errors."""
41e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        with self.assertRaises(socket.error):
42e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa            invalid_address = os.path.join(self.tmpdir, 'foo', 'socket')
43764c6d7451342e00768b9724badcc9514d31f626Ben Kwa            async_listener.AsyncListener(invalid_address)
44e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
45e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
46e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa    def testAddressConflict(self):
47e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        """Verifies that address conflicts raise errors."""
48e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        with self.assertRaises(socket.error):
49764c6d7451342e00768b9724badcc9514d31f626Ben Kwa            async_listener.AsyncListener(self.address)
50e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
51e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
52e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa    def testInetAddresses(self):
53e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        """Verifies that inet addresses raise errors."""
54e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        with self.assertRaises(TypeError):
55764c6d7451342e00768b9724badcc9514d31f626Ben Kwa            async_listener.AsyncListener(('127.0.0.1', 0))
56e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
57e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
58e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa    def testStartStop(self):
59e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        """Tests starting and stopping the async listener."""
60e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        try:
61e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa            self.assertFalse(self.listener.is_running())
62e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
63e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa            self.listener.start()
64e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa            self.assertTrue(self.listener.is_running())
65e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
66e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa            # Establish a connection to verify that the listener is actually
67e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa            # alive.
68e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa            host, client = self._make_connection()
69e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa            client.close()
70e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa            host.close()
71e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
72e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa            self.assertTrue(self.listener.stop())
73e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa            self.assertFalse(self.listener.is_running())
74e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        except:
75e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa            self.fail(error.format_error())
76e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
77e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
78e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa    def testStop_notRunning(self):
79e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        """Tests stopping the async listener when it's not running."""
80e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        try:
81e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa            self.assertFalse(self.listener.is_running())
82e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa            # Verify that calling stop just returns False when the listener
83e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa            # isn't running.
84e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa            self.assertFalse(self.listener.stop())
85e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        except:
86e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa            self.fail(error.format_error())
87e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
88e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
89e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa    def testConnection(self):
90e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        """Tests starting a connection."""
91e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        self.listener.start()
92e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
93e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        # Verify no pending connections.
94e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        self.assertIsNone(self.listener.get_connection(timeout=1))
95e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
96e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        # Start a client connection, verify that the listener now returns a
97e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        # pending connection.  Keep a reference to the client, so it doesn't get
98e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        # GC'd while the test is in progress.
99764c6d7451342e00768b9724badcc9514d31f626Ben Kwa        _unused = connection.Client(self.address)
100e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        self.assertIsNotNone(self.listener.get_connection(timeout=1))
101e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
102e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
103e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa    def testHostToClientComms(self):
104e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        """Tests that client/host connections can exchange data."""
105e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        self.listener.start()
106e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        host, client = self._make_connection()
107e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
108e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        # Send a message on the host side socket, check that the client receives
109e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        # it.
110e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        msg = 'quickly moving jedi zap a brown sith fox'
111e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        host.send(msg)
112e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        received_msg = client.recv()
113e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        self.assertEqual(msg, received_msg)
114e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
115e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
116e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa    def testMultipleConnections(self):
117e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        """Tests for correct pairing of multiple host/client connections."""
118e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        self.listener.start()
119e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
120e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        # Create two sets of host/client connections.  Verify that messages sent
121e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        # on each client are received by the correct respective host.
122e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        host0, client0 = self._make_connection()
123e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        host1, client1 = self._make_connection()
124e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
125e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        msg0 = 'a large fawn jumped quickly over white zinc boxes'
126e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        msg1 = 'six big devils from japan quickly forgot how to waltz'
127e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
128e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        client0.send(msg0)
129e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        client1.send(msg1)
130e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
131e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        received_msg0 = host0.recv()
132e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        received_msg1 = host1.recv()
133e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
134e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        self.assertEquals(msg0, received_msg0)
135e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        self.assertEquals(msg1, received_msg1)
136e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
137e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
138e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa    def _make_connection(self):
139e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        """Creates pairs of host/client connections.
140e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
141e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        @return: A host, client connection pair.
142e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        """
143764c6d7451342e00768b9724badcc9514d31f626Ben Kwa        client = unittest_client.connect(self.address)
144e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        host = self.listener.get_connection(timeout=1)
145e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa        return host, client
146e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
147e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
148e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa
149e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwaif __name__ == '__main__':
150e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa    unittest_setup.setup()
151e05b6e5b047d81087aa5ac9462f217de312ad0f3Ben Kwa    unittest.main()
152