blob: 80f53735dab4a6375e7404971e242b5e5b5fed1e [file] [log] [blame]
# Copyright 2016 Google Inc.
#
# 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
from future.tests.base import unittest
from mobly.controllers.android_device_lib import jsonrpc_client_base
from tests.lib import jsonrpc_client_test_base
class FakeRpcClient(jsonrpc_client_base.JsonRpcClientBase):
def __init__(self):
super().__init__(app_name='FakeRpcClient', ad=mock.Mock())
class JsonRpcClientBaseTest(jsonrpc_client_test_base.JsonRpcClientTestBase):
"""Unit tests for mobly.controllers.android_device_lib.jsonrpc_client_base.
"""
@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 client
will eventually exit with an IOError.
"""
mock_create_connection.side_effect = IOError()
with self.assertRaises(IOError):
client = FakeRpcClient()
client.connect()
@mock.patch('socket.create_connection')
def test_connect_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 = FakeRpcClient()
client.connect()
@mock.patch('socket.create_connection')
def test_handshake_error(self, mock_create_connection):
"""Test error in jsonrpc handshake
Test that if there is an error in the jsonrpc handshake then a protocol
error will be raised.
"""
self.setup_mock_socket_file(mock_create_connection, resp=None)
client = FakeRpcClient()
with self.assertRaisesRegex(
jsonrpc_client_base.ProtocolError,
jsonrpc_client_base.ProtocolError.NO_RESPONSE_FROM_HANDSHAKE):
client.connect()
@mock.patch('socket.create_connection')
def test_connect_handshake(self, mock_create_connection):
"""Test client handshake
Test that at the end of a handshake with no errors the client object
has the correct parameters.
"""
self.setup_mock_socket_file(mock_create_connection)
client = FakeRpcClient()
client.connect()
self.assertEqual(client.uid, 1)
@mock.patch('socket.create_connection')
def test_connect_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.
"""
self.setup_mock_socket_file(mock_create_connection,
resp=self.MOCK_RESP_UNKNOWN_STATUS)
client = FakeRpcClient()
client.connect()
self.assertEqual(client.uid, jsonrpc_client_base.UNKNOWN_UID)
@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 receives a response with an error will raised
an api error.
"""
fake_file = self.setup_mock_socket_file(mock_create_connection)
client = FakeRpcClient()
client.connect()
fake_file.resp = self.MOCK_RESP_WITH_ERROR
with self.assertRaisesRegex(jsonrpc_client_base.ApiError, '1'):
client.some_rpc(1, 2, 3)
@mock.patch('socket.create_connection')
def test_rpc_callback_response(self, mock_create_connection):
"""Test rpc that is given a callback response.
Test that when an rpc receives a callback response, a callback object is
created correctly.
"""
fake_file = self.setup_mock_socket_file(mock_create_connection)
client = FakeRpcClient()
client.connect()
fake_file.resp = self.MOCK_RESP_WITH_CALLBACK
client._event_client = mock.Mock()
callback = client.some_rpc(1, 2, 3)
self.assertEqual(callback.ret_value, 123)
self.assertEqual(callback._id, '1-0')
@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 = FakeRpcClient()
client.connect()
fake_file.resp = (self.MOCK_RESP_TEMPLATE % 52).encode('utf8')
with self.assertRaisesRegex(
jsonrpc_client_base.ProtocolError,
jsonrpc_client_base.ProtocolError.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 response
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 = FakeRpcClient()
client.connect()
fake_file.resp = None
with self.assertRaisesRegex(
jsonrpc_client_base.ProtocolError,
jsonrpc_client_base.ProtocolError.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 = FakeRpcClient()
client.connect()
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_send_to_socket_without_callback(self, mock_create_connection):
"""Test rpc sending and recieving with Rpc protocol before callback was
added to the resp message.
Logic is the same as test_rpc_send_to_socket.
"""
fake_file = self.setup_mock_socket_file(
mock_create_connection, resp=self.MOCK_RESP_WITHOUT_CALLBACK)
client = FakeRpcClient()
client.connect()
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 = FakeRpcClient()
client.connect()
for i in range(0, 10):
fake_file.resp = (self.MOCK_RESP_TEMPLATE % i).encode('utf-8')
client.some_rpc()
self.assertEqual(next(client._counter), 10)
@mock.patch('socket.create_connection')
def test_rpc_verbose_logging_with_long_string(self, mock_create_connection):
"""Test rpc response fully write into DEBUG level log."""
fake_file = self.setup_mock_socket_file(mock_create_connection)
testing_rpc_response = self.generate_rpc_response(4000)
fake_file.resp = testing_rpc_response
client = FakeRpcClient()
client.connect()
response = client._client_receive()
self.assertEqual(response, testing_rpc_response)
client.log.debug.assert_called_with('Snippet received: %s',
testing_rpc_response)
@mock.patch('socket.create_connection')
def test_rpc_truncated_logging_short_response(self, mock_create_connection):
"""Test rpc response will full logged when length is short."""
fake_file = self.setup_mock_socket_file(mock_create_connection)
testing_rpc_response = self.generate_rpc_response(
int(jsonrpc_client_base._MAX_RPC_RESP_LOGGING_LENGTH / 2))
fake_file.resp = testing_rpc_response
client = FakeRpcClient()
client.connect()
client.set_snippet_client_verbose_logging(False)
response = client._client_receive()
self.assertEqual(response, testing_rpc_response)
client.log.debug.assert_called_with('Snippet received: %s',
testing_rpc_response)
@mock.patch('socket.create_connection')
def test_rpc_truncated_logging_fit_size_response(self,
mock_create_connection):
"""Test rpc response will full logged when length is equal to threshold.
"""
fake_file = self.setup_mock_socket_file(mock_create_connection)
testing_rpc_response = self.generate_rpc_response(
jsonrpc_client_base._MAX_RPC_RESP_LOGGING_LENGTH)
fake_file.resp = testing_rpc_response
client = FakeRpcClient()
client.connect()
client.set_snippet_client_verbose_logging(False)
response = client._client_receive()
self.assertEqual(response, testing_rpc_response)
client.log.debug.assert_called_with('Snippet received: %s',
testing_rpc_response)
@mock.patch('socket.create_connection')
def test_rpc_truncated_logging_long_response(self, mock_create_connection):
"""Test rpc response truncated with given length in DEBUG level log."""
fake_file = self.setup_mock_socket_file(mock_create_connection)
resp_len = jsonrpc_client_base._MAX_RPC_RESP_LOGGING_LENGTH * 40
testing_rpc_response = self.generate_rpc_response(resp_len)
fake_file.resp = testing_rpc_response
client = FakeRpcClient()
client.connect()
client.set_snippet_client_verbose_logging(False)
response = client._client_receive()
self.assertEqual(response, testing_rpc_response)
# DEBUG level log should truncated by given length.
client.log.debug.assert_called_with(
'Snippet received: %s... %d chars are truncated',
testing_rpc_response[:jsonrpc_client_base._MAX_RPC_RESP_LOGGING_LENGTH],
resp_len - jsonrpc_client_base._MAX_RPC_RESP_LOGGING_LENGTH)
if __name__ == '__main__':
unittest.main()