Home | History | Annotate | Download | only in tcp_server
      1 #
      2 # Copyright (C) 2016 The Android Open Source Project
      3 #
      4 # Licensed under the Apache License, Version 2.0 (the "License");
      5 # you may not use this file except in compliance with the License.
      6 # You may obtain a copy of the License at
      7 #
      8 #      http://www.apache.org/licenses/LICENSE-2.0
      9 #
     10 # Unless required by applicable law or agreed to in writing, software
     11 # distributed under the License is distributed on an "AS IS" BASIS,
     12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 # See the License for the specific language governing permissions and
     14 # limitations under the License.
     15 #
     16 
     17 import socket
     18 import unittest
     19 import logging
     20 import errno
     21 from socket import error as socket_error
     22 
     23 from vts.runners.host import errors
     24 from vts.proto import AndroidSystemControlMessage_pb2 as SysMsg_pb2
     25 from vts.runners.host.tcp_server import callback_server
     26 
     27 HOST, PORT = "localhost", 0
     28 ERROR_PORT = 380  # port at which we test the error case.
     29 
     30 
     31 class TestMethods(unittest.TestCase):
     32     """This class defines unit test methods.
     33 
     34     The common scenarios are when we wish to test the whether we are able to
     35     receive the expected data from the server; and whether we receive the
     36     correct error when we try to connect to server from a wrong port.
     37 
     38     Attributes:
     39         _callback_server: an instance of CallbackServer that is used to
     40                          start and stop the TCP server.
     41         _counter: This is used to keep track of number of calls made to the
     42                   callback function.
     43     """
     44     _callback_server = None
     45     _counter = 0
     46 
     47     def setUp(self):
     48         """This function initiates starting the server in CallbackServer."""
     49         self._callback_server = callback_server.CallbackServer()
     50         self._callback_server.Start()
     51 
     52     def tearDown(self):
     53         """To initiate shutdown of the server.
     54 
     55         This function calls the callback_server.CallbackServer.Stop which
     56         shutdowns the server.
     57         """
     58         self._callback_server.Stop()
     59 
     60     def DoErrorCase(self):
     61         """Unit test for Error case.
     62 
     63         This function tests the cases that throw exception.
     64         e.g sending requests to port 25.
     65 
     66         Raises:
     67             ConnectionRefusedError: ConnectionRefusedError occurred in
     68             test_ErrorCase().
     69         """
     70         host = self._callback_server.ip
     71 
     72         # Create a socket (SOCK_STREAM means a TCP socket)
     73         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     74 
     75         try:
     76             # Connect to server; this should result in Connection refused error
     77             sock.connect((host, ERROR_PORT))
     78         except socket_error as e:
     79             # We are comparing the error number of the error we expect and
     80             # the error that we get.
     81             # Test fails if ConnectionRefusedError is not raised at this step.
     82             if e.errno == errno.ECONNREFUSED:
     83                 raise errors.ConnectionRefusedError  # Test is a success here
     84             else:
     85                 raise e  # Test fails, since ConnectionRefusedError was expected
     86         finally:
     87             sock.close()
     88 
     89     def ConnectToServer(self, func_id):
     90         """This function creates a connection to TCP server and sends/receives
     91             message.
     92 
     93         Args:
     94             func_id: This is the unique key corresponding to a function and
     95                 also the id field of the request_message that we send to the
     96                 server.
     97 
     98         Returns:
     99             response_message: The object that the TCP host returns.
    100 
    101         Raises:
    102             TcpServerConnectionError: Exception occurred while stopping server.
    103         """
    104         # This object is sent to the TCP host
    105         request_message = SysMsg_pb2.AndroidSystemCallbackRequestMessage()
    106         request_message.id = func_id
    107 
    108         #  The response in string format that we receive from host
    109         received_message = ""
    110 
    111         # The final object that this function returns
    112         response_message = SysMsg_pb2.AndroidSystemCallbackResponseMessage()
    113 
    114         # Create a socket (SOCK_STREAM means a TCP socket)
    115         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    116         sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    117         host = self._callback_server.ip
    118         port = self._callback_server.port
    119         logging.info('Sending Request to host %s using port %s', host, port)
    120 
    121         try:
    122             # Connect to server and send request_message
    123             sock.connect((host, port))
    124 
    125             message = request_message.SerializeToString()
    126             sock.sendall(str(len(message)) + "\n" + message)
    127             logging.info("Sent: %s", message)
    128 
    129             # Receive request_message from the server and shut down
    130             received_message = sock.recv(1024)
    131             response_message.ParseFromString(received_message)
    132             logging.info('Received: %s', received_message)
    133         except socket_error as e:
    134             logging.error(e)
    135             raise errors.TcpServerConnectionError('Exception occurred.')
    136         finally:
    137             sock.close()
    138 
    139         return response_message
    140 
    141     def testDoErrorCase(self):
    142         """Unit test for error cases."""
    143         with self.assertRaises(errors.ConnectionRefusedError):
    144             self.DoErrorCase()
    145 
    146     def testCallback(self):
    147         """Tests two callback use cases."""
    148         self.TestNormalCase()
    149         self.TestDoRegisterCallback()
    150 
    151     def TestNormalCase(self):
    152         """Tests the normal request to TCPServer.
    153 
    154         This function sends the request to the Tcp server where the request
    155         should be a success.
    156 
    157         This function also checks the register callback feature by ensuring that
    158         callback_func() is called and the value of the global counter is
    159         increased by one.
    160         """
    161         func_id = "1"  # to maintain the key for function pointer
    162 
    163         def callback_func():
    164             self._counter += 1
    165 
    166         # Function should be registered with RegisterCallback
    167         self._callback_server.RegisterCallback(func_id, callback_func)
    168 
    169         # Capture the previous value of global counter
    170         prev_value = self._counter
    171 
    172         # Connect to server
    173         response_message = self.ConnectToServer(func_id)
    174 
    175         # Confirm whether the callback_func() was called thereby increasing
    176         # value of global counter by 1
    177         self.assertEqual(self._counter, prev_value + 1)
    178 
    179         # Also confirm if query resulted in a success
    180         self.assertEqual(response_message.response_code, SysMsg_pb2.SUCCESS)
    181 
    182     def TestDoRegisterCallback(self):
    183         """Checks the register callback functionality of the Server.
    184 
    185         This function checks whether the value of global counter remains same
    186         if function is not registered. It also checks whether it's incremented
    187         by 1 when the function is registered.
    188         """
    189         func_id = "11"  # to maintain the key for function pointer
    190 
    191         def callback_func():
    192             self._counter += 1
    193 
    194         # Capture the previous value of global counter
    195         prev_value = self._counter
    196 
    197         # Function should be registered with RegisterCallback
    198         self._callback_server.RegisterCallback(func_id, callback_func)
    199 
    200         # Connect to server
    201         response_message = self.ConnectToServer(func_id)
    202 
    203         # Confirm whether the callback_func() was not called.
    204         self.assertEqual(self._counter, prev_value + 1)
    205 
    206         # also confirm the error message
    207         self.assertEqual(response_message.response_code, SysMsg_pb2.SUCCESS)
    208 
    209         # Now unregister the function and check again
    210         # Function should be unregistered with UnegisterCallback
    211         # and the key should also be present
    212         self._callback_server.UnregisterCallback(func_id)
    213 
    214         # Capture the previous value of global counter
    215         prev_value = self._counter
    216 
    217         # Connect to server
    218         response_message = self.ConnectToServer(func_id)
    219 
    220         # Confirm whether the callback_func() was not called.
    221         self.assertEqual(self._counter, prev_value)
    222 
    223         # also confirm the error message
    224         self.assertEqual(response_message.response_code, SysMsg_pb2.FAIL)
    225 
    226 if __name__ == '__main__':
    227     unittest.main()
    228