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