| #!/usr/bin/env python |
| # |
| # Copyright (C) 2017 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. |
| # |
| |
| import unittest |
| |
| try: |
| from unittest import mock |
| except ImportError: |
| import mock |
| |
| from host_controller import invocation_thread |
| from host_controller.tfc import command_attempt |
| from host_controller.tradefed import remote_operation |
| |
| |
| class InvocationThreadTest(unittest.TestCase): |
| """A test for invocation_thread.InvocationThread. |
| |
| Attributes: |
| _remote_client: A mock remote_client.RemoteClient. |
| _tfc_client: A mock tfc_client.TfcClient. |
| _inv_thread: The InvocationThread being tested. |
| """ |
| |
| def setUp(self): |
| """Creates the InvocationThread.""" |
| self._remote_client = mock.Mock() |
| self._tfc_client = mock.Mock() |
| attempt = command_attempt.CommandAttempt( |
| task_id="321-0", |
| attempt_id="abcd-1234", |
| hostname="host0", |
| device_serial="ABCDEF") |
| command = ["vts", "-m", "SampleShellTest"] |
| serials = ["serial123", "serial456"] |
| self._inv_thread = invocation_thread.InvocationThread( |
| self._remote_client, self._tfc_client, |
| attempt, command, serials) |
| |
| def _GetSubmittedEventTypes(self): |
| """Gets the types of the events submitted by the mock TfcClient. |
| |
| Returns: |
| A list of strings, the event types. |
| """ |
| event_types = [] |
| for args, kwargs in self._tfc_client.SubmitCommandEvents.call_args_list: |
| event_types.extend(event["type"] for event in args[0]) |
| return event_types |
| |
| def _GetSentOperationTypes(self): |
| """Gets the types of the operations sent by the mock RemoteClient. |
| |
| Returns: |
| A list of strings, the operation types. |
| """ |
| operation_types = [args[0].type for args, kwargs in |
| self._remote_client.SendOperation.call_args_list] |
| return operation_types |
| |
| def testAllocationFailed(self): |
| """Tests AllocationFailed event.""" |
| self._remote_client.SendOperation.side_effect = ( |
| lambda op: _RaiseExceptionForOperation(op, "ALLOCATE_DEVICE")) |
| self._inv_thread.run() |
| self.assertEqual([command_attempt.EventType.ALLOCATION_FAILED], |
| self._GetSubmittedEventTypes()) |
| self.assertEqual(["ALLOCATE_DEVICE"], |
| self._GetSentOperationTypes()) |
| |
| def testExecuteFailed(self): |
| """Tests ExecuteFailed event.""" |
| self._remote_client.SendOperation.side_effect = ( |
| lambda op: _RaiseExceptionForOperation(op, "EXEC_COMMAND")) |
| self._inv_thread.run() |
| self.assertEqual([command_attempt.EventType.EXECUTE_FAILED], |
| self._GetSubmittedEventTypes()) |
| self.assertEqual(["ALLOCATE_DEVICE", |
| "ALLOCATE_DEVICE", |
| "EXEC_COMMAND", |
| "FREE_DEVICE", |
| "FREE_DEVICE"], |
| self._GetSentOperationTypes()) |
| |
| def testConfigurationError(self): |
| """Tests ConfigurationError event.""" |
| self._remote_client.SendOperation.side_effect = ( |
| lambda op: _RaiseExceptionForOperation(op, "EXEC_COMMAND", |
| "Config error: test")) |
| self._inv_thread.run() |
| self.assertEqual([command_attempt.EventType.CONFIGURATION_ERROR], |
| self._GetSubmittedEventTypes()) |
| self.assertEqual(["ALLOCATE_DEVICE", |
| "ALLOCATE_DEVICE", |
| "EXEC_COMMAND", |
| "FREE_DEVICE", |
| "FREE_DEVICE"], |
| self._GetSentOperationTypes()) |
| |
| def testInvocationCompleted(self): |
| """Tests InvocationCompleted event.""" |
| self._remote_client.WaitForCommandResult.side_effect = ( |
| None, {"status": "INVOCATION_SUCCESS"}) |
| self._inv_thread.run() |
| self.assertEqual([command_attempt.EventType.INVOCATION_STARTED, |
| command_attempt.EventType.TEST_RUN_IN_PROGRESS, |
| command_attempt.EventType.INVOCATION_COMPLETED], |
| self._GetSubmittedEventTypes()) |
| # GET_LAST_COMMAND_RESULT isn't called in mock WaitForCommandResult. |
| self.assertEqual(["ALLOCATE_DEVICE", |
| "ALLOCATE_DEVICE", |
| "EXEC_COMMAND", |
| "FREE_DEVICE", |
| "FREE_DEVICE"], |
| self._GetSentOperationTypes()) |
| |
| |
| def _RaiseExceptionForOperation(operation, op_type, error_msg="unit test"): |
| """Raises exception for specific operation type. |
| |
| Args: |
| operation: A remote_operation.RemoteOperation object. |
| op_type: A string, the expected type. |
| error_msg: The message in the exception. |
| |
| Raises: |
| RemoteOperationException if the operation's type matches op_type. |
| """ |
| if operation.type == op_type: |
| raise remote_operation.RemoteOperationException(error_msg) |
| |
| |
| if __name__ == "__main__": |
| unittest.main() |