blob: 1754d4f36ae76caf881b0d416c26a3aa235c03be [file] [log] [blame]
#!/usr/bin/env python3.4
#
# Copyright 2016 - The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from builtins import str
import json
import mock
import socket
import unittest
from acts.controllers import sl4a_client
MOCK_RESP = b'{"id": 0, "result": 123, "error": null, "status": 1, "uid": 1}'
MOCK_RESP_TEMPLATE = '{"id": %d, "result": 123, "error": null, "status": 1, "uid": 1}'
MOCK_RESP_UNKWN_STATUS = b'{"id": 0, "result": 123, "error": null, "status": 0}'
MOCK_RESP_WITH_ERROR = b'{"id": 0, "error": 1, "status": 1, "uid": 1}'
class MockSocketFile(object):
def __init__(self, resp):
self.resp = resp
self.last_write = None
def write(self, msg):
self.last_write = msg
def readline(self):
return self.resp
def flush(self):
pass
class ActsSl4aClientTest(unittest.TestCase):
"""This test class has unit tests for the implementation of everything
under acts.controllers.android, which is the RPC client module for sl4a.
"""
def setup_mock_socket_file(self, mock_create_connection):
"""Sets up a fake socket file from the mock connection.
Args:
mock_create_connection: The mock method for creating a method.
Returns:
The mock file that will be injected into the code.
"""
fake_file = MockSocketFile(MOCK_RESP)
fake_conn = mock.MagicMock()
fake_conn.makefile.return_value = fake_file
mock_create_connection.return_value = fake_conn
return fake_file
@mock.patch('socket.create_connection')
def test_open_timeout_io_error(self, mock_create_connection):
"""Test socket timeout with io error
Test that if the net socket gives an io error, then the sl4a client
will eventually exit with an IOError.
"""
mock_create_connection.side_effect = IOError()
with self.assertRaises(IOError):
client = sl4a_client.Sl4aClient()
client.open(connection_timeout=0.1)
@mock.patch('socket.create_connection')
def test_open_timeout(self, mock_create_connection):
"""Test socket timeout
Test that a timeout exception will be raised if the socket gives a
timeout.
"""
mock_create_connection.side_effect = socket.timeout
with self.assertRaises(socket.timeout):
client = sl4a_client.Sl4aClient()
client.open(connection_timeout=0.1)
@mock.patch('socket.create_connection')
def test_handshake_error(self, mock_create_connection):
"""Test error in sl4a handshake
Test that if there is an error in the sl4a handshake then a protocol
error will be raised.
"""
fake_conn = mock.MagicMock()
fake_conn.makefile.return_value = MockSocketFile(None)
mock_create_connection.return_value = fake_conn
with self.assertRaises(sl4a_client.Sl4aProtocolError):
client = sl4a_client.Sl4aClient()
client.open()
@mock.patch('socket.create_connection')
def test_open_handshake(self, mock_create_connection):
"""Test sl4a client handshake
Test that at the end of a handshake with no errors the client object
has the correct parameters.
"""
fake_conn = mock.MagicMock()
fake_conn.makefile.return_value = MockSocketFile(MOCK_RESP)
mock_create_connection.return_value = fake_conn
client = sl4a_client.Sl4aClient()
client.open()
self.assertEqual(client.uid, 1)
@mock.patch('socket.create_connection')
def test_open_handshake_unknown_status(self, mock_create_connection):
"""Test handshake with unknown status response
Test that when the handshake is given an unknown status then the client
will not be given a uid.
"""
fake_conn = mock.MagicMock()
fake_conn.makefile.return_value = MockSocketFile(
MOCK_RESP_UNKWN_STATUS)
mock_create_connection.return_value = fake_conn
client = sl4a_client.Sl4aClient()
client.open()
self.assertEqual(client.uid, sl4a_client.UNKNOWN_UID)
@mock.patch('socket.create_connection')
def test_open_no_response(self, mock_create_connection):
"""Test handshake no response
Test that if a handshake recieves no response then it will give a
protocol error.
"""
fake_file = self.setup_mock_socket_file(mock_create_connection)
client = sl4a_client.Sl4aClient()
client.open()
fake_file.resp = None
with self.assertRaises(
sl4a_client.Sl4aProtocolError,
msg=sl4a_client.Sl4aProtocolError.NO_RESPONSE_FROM_HANDSHAKE):
client.some_rpc(1, 2, 3)
@mock.patch('socket.create_connection')
def test_rpc_error_response(self, mock_create_connection):
"""Test rpc that is given an error response
Test that when an rpc recieves a reponse with an error will raised
an api error.
"""
fake_file = self.setup_mock_socket_file(mock_create_connection)
client = sl4a_client.Sl4aClient()
client.open()
fake_file.resp = MOCK_RESP_WITH_ERROR
with self.assertRaises(sl4a_client.Sl4aApiError, msg=1):
client.some_rpc(1, 2, 3)
@mock.patch('socket.create_connection')
def test_rpc_id_mismatch(self, mock_create_connection):
"""Test rpc that returns a different id than expected
Test that if an rpc returns with an id that is different than what
is expected will give a protocl error.
"""
fake_file = self.setup_mock_socket_file(mock_create_connection)
client = sl4a_client.Sl4aClient()
client.open()
fake_file.resp = (MOCK_RESP_TEMPLATE % 52).encode('utf8')
with self.assertRaises(
sl4a_client.Sl4aProtocolError,
msg=sl4a_client.Sl4aProtocolError.MISMATCHED_API_ID):
client.some_rpc(1, 2, 3)
@mock.patch('socket.create_connection')
def test_rpc_no_response(self, mock_create_connection):
"""Test rpc that does not get a reponse
Test that when an rpc does not get a response it throws a protocol
error.
"""
fake_file = self.setup_mock_socket_file(mock_create_connection)
client = sl4a_client.Sl4aClient()
client.open()
fake_file.resp = None
with self.assertRaises(
sl4a_client.Sl4aProtocolError,
msg=sl4a_client.Sl4aProtocolError.NO_RESPONSE_FROM_SERVER):
client.some_rpc(1, 2, 3)
@mock.patch('socket.create_connection')
def test_rpc_send_to_socket(self, mock_create_connection):
"""Test rpc sending and recieving
Tests that when an rpc is sent and received the corrent data
is used.
"""
fake_file = self.setup_mock_socket_file(mock_create_connection)
client = sl4a_client.Sl4aClient()
client.open()
result = client.some_rpc(1, 2, 3)
self.assertEqual(result, 123)
expected = {'id': 0, 'method': 'some_rpc', 'params': [1, 2, 3]}
actual = json.loads(fake_file.last_write.decode('utf-8'))
self.assertEqual(expected, actual)
@mock.patch('socket.create_connection')
def test_rpc_call_increment_counter(self, mock_create_connection):
"""Test rpc counter
Test that with each rpc call the counter is incremented by 1.
"""
fake_file = self.setup_mock_socket_file(mock_create_connection)
client = sl4a_client.Sl4aClient()
client.open()
for i in range(0, 10):
fake_file.resp = (MOCK_RESP_TEMPLATE % i).encode('utf-8')
client.some_rpc()
self.assertEqual(next(client._counter), 10)
if __name__ == "__main__":
unittest.main()