# # All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or # its licensors. # # For complete copyright and license terms please see the LICENSE at the root of this # distribution (the "License"). All use of this software is governed by the License, # or, if provided, by the license below or the license accompanying this file. Do not # remove or modify any license notices. This file is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # import datetime import os import pathlib import platform import pytest import time from unittest.mock import patch, Mock from cmake.Tools.Platform.Android import android_deployment TEST_GAME_NAME = "Foo" TEST_DEV_ROOT = pathlib.Path("Foo") TEST_ASSET_MODE = 'LOOSE' TEST_ASSET_TYPE = 'android' TEST_ANDROID_SDK_PATH = pathlib.Path('c:\\AndroidSDK') TEST_BUILD_DIR = 'android_gradle_test' TEST_DEVICE_ID = '9A201FFAZ000ER' def match_arg_list(input_args, expected_args): if len(input_args) != len(expected_args): return False for index in range(len(input_args)): if input_args[index] != expected_args[index]: return False return True @patch('cmake.Tools.Platform.Android.android_deployment.AndroidDeployment.read_android_settings', return_value={}) @patch('cmake.Tools.Platform.Android.android_deployment.AndroidDeployment.resolve_adb_tool', return_value=pathlib.Path("Foo")) def test_Initialize(mock_resolve_adb_tool, mock_read_android_settings): attrs = {'glob.return_value': ["foo.bar"]} mock_local_asset_path = Mock(**attrs) inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', game_name=TEST_GAME_NAME, asset_mode=TEST_ASSET_MODE, asset_type=TEST_ASSET_TYPE, embedded_assets=True, android_device_filter=None, clean_deploy=False, android_sdk_path=TEST_ANDROID_SDK_PATH, deployment_type=android_deployment.AndroidDeployment.DEPLOY_BOTH) mock_resolve_adb_tool.assert_called_once_with(TEST_ANDROID_SDK_PATH) mock_read_android_settings.assert_called_once_with(TEST_DEV_ROOT, TEST_GAME_NAME) assert inst def test_read_android_settings(tmpdir): game_name = "Foo" tmpdir.ensure(f'dev_root/{game_name}/project.json') game_project_json_file = tmpdir.join(f'dev_root/{game_name}/project.json') game_project_json_file.write(f'{{"android_settings": {{"game_name": "{game_name.lower()}" }} }}') result = android_deployment.AndroidDeployment.read_android_settings(pathlib.Path(tmpdir.join('dev_root').realpath()), game_name) assert result['game_name'] == game_name.lower() def test_resolve_adb_tool(tmpdir): sdk_path = 'android_sdk' adb_target = 'adb.exe' if platform.system() == 'Windows' else 'adb' tmpdir.ensure(f'{sdk_path}/platform-tools/{adb_target}') dummy_adb_file = tmpdir.join(f'{sdk_path}/platform-tools/{adb_target}') dummy_adb_file.write('adb') result = android_deployment.AndroidDeployment.resolve_adb_tool(pathlib.Path(tmpdir.join(sdk_path).realpath())) assert pathlib.Path(dummy_adb_file.realpath()) == result @patch('subprocess.check_output', return_value=b'PASS') def test_adb_call(mock_check_output): with patch.object(android_deployment.AndroidDeployment, 'read_android_settings', return_value={}), \ patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', game_name=TEST_GAME_NAME, asset_mode=TEST_ASSET_MODE, asset_type=TEST_ASSET_TYPE, embedded_assets=True, android_device_filter=None, clean_deploy=False, android_sdk_path=TEST_ANDROID_SDK_PATH, deployment_type=android_deployment.AndroidDeployment.DEPLOY_BOTH) result = inst.adb_call(arg_list=['foo'], device_id='123') mock_check_output.assert_called_once() assert result == 'PASS' @patch('cmake.Tools.Platform.Android.android_deployment.AndroidDeployment.adb_call', return_value='PASS') def test_adb_shell(mock_adb_call): with patch.object(android_deployment.AndroidDeployment, 'read_android_settings', return_value={}), \ patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', game_name=TEST_GAME_NAME, asset_mode=TEST_ASSET_MODE, asset_type=TEST_ASSET_TYPE, embedded_assets=True, android_device_filter=None, clean_deploy=False, android_sdk_path=TEST_ANDROID_SDK_PATH, deployment_type=android_deployment.AndroidDeployment.DEPLOY_BOTH) result = inst.adb_shell(command='foo me', device_id='123') expected_args = ['shell', 'foo me'] mock_adb_call.assert_called_once_with(expected_args, device_id='123') assert result == 'PASS' @patch('cmake.Tools.Platform.Android.android_deployment.AndroidDeployment.adb_shell', return_value='output') def test_adb_ls_success(mock_adb_shell): with patch.object(android_deployment.AndroidDeployment, 'read_android_settings', return_value={}), \ patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', game_name=TEST_GAME_NAME, asset_mode=TEST_ASSET_MODE, asset_type=TEST_ASSET_TYPE, embedded_assets=True, android_device_filter=None, clean_deploy=False, android_sdk_path=TEST_ANDROID_SDK_PATH, deployment_type=android_deployment.AndroidDeployment.DEPLOY_BOTH) result, output = inst.adb_ls(path='/foo/bar', device_id='123') mock_adb_shell.assert_called_once_with(command='ls /foo/bar', device_id='123') assert result assert output == 'output' @patch('cmake.Tools.Platform.Android.android_deployment.AndroidDeployment.adb_shell', return_value='') def test_adb_ls_error_no_output(mock_adb_shell): with patch.object(android_deployment.AndroidDeployment, 'read_android_settings', return_value={}), \ patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', game_name=TEST_GAME_NAME, asset_mode=TEST_ASSET_MODE, asset_type=TEST_ASSET_TYPE, embedded_assets=True, android_device_filter=None, clean_deploy=False, android_sdk_path=TEST_ANDROID_SDK_PATH, deployment_type=android_deployment.AndroidDeployment.DEPLOY_BOTH) result, output = inst.adb_ls(path='/foo/bar', device_id='123') mock_adb_shell.assert_called_once_with(command='ls /foo/bar', device_id='123') assert not result assert output is None @patch('cmake.Tools.Platform.Android.android_deployment.AndroidDeployment.adb_shell', return_value='No such file or directory') def test_adb_ls_error_no_such_file(mock_adb_shell): with patch.object(android_deployment.AndroidDeployment, 'read_android_settings', return_value={}), \ patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', game_name=TEST_GAME_NAME, asset_mode=TEST_ASSET_MODE, asset_type=TEST_ASSET_TYPE, embedded_assets=True, android_device_filter=None, clean_deploy=False, android_sdk_path=TEST_ANDROID_SDK_PATH, deployment_type=android_deployment.AndroidDeployment.DEPLOY_BOTH) result, output = inst.adb_ls(path='/foo/bar', device_id='123') mock_adb_shell.assert_called_once_with(command='ls /foo/bar', device_id='123') assert not result assert output == 'No such file or directory' @patch('cmake.Tools.Platform.Android.android_deployment.AndroidDeployment.adb_shell', return_value='Permission denied') def test_adb_ls_error_permission_denied(mock_adb_shell): with patch.object(android_deployment.AndroidDeployment, 'read_android_settings', return_value={}), \ patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', game_name=TEST_GAME_NAME, asset_mode=TEST_ASSET_MODE, asset_type=TEST_ASSET_TYPE, embedded_assets=True, android_device_filter=None, clean_deploy=False, deployment_type=android_deployment.AndroidDeployment.DEPLOY_BOTH, android_sdk_path=TEST_ANDROID_SDK_PATH) result, output = inst.adb_ls(path='/foo/bar', device_id='123') mock_adb_shell.assert_called_once_with(command='ls /foo/bar', device_id='123') assert not result assert output == 'Permission denied' @patch('cmake.Tools.Platform.Android.android_deployment.AndroidDeployment.adb_call', return_value=f'List of devices attached{os.linesep}9A201FFAZ000ER device{os.linesep}1A201FFAZ000ER device{os.linesep}9A201FFAZ456ER unauthorized') def test_get_target_android_devices(mock_adb_call): with patch.object(android_deployment.AndroidDeployment, 'read_android_settings', return_value={}), \ patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', game_name=TEST_GAME_NAME, asset_mode=TEST_ASSET_MODE, asset_type=TEST_ASSET_TYPE, embedded_assets=True, android_device_filter=f'{TEST_DEVICE_ID},AAAAASDSFGG', clean_deploy=False, deployment_type=android_deployment.AndroidDeployment.DEPLOY_BOTH, android_sdk_path=TEST_ANDROID_SDK_PATH) result = inst.get_target_android_devices() mock_adb_call.assert_called_once_with("devices") assert len(result) == 1 assert result[0] == TEST_DEVICE_ID @patch('cmake.Tools.Platform.Android.android_deployment.AndroidDeployment.adb_ls', return_value=(True,"file")) def test_check_known_android_paths_success(mock_adb_ls): with patch.object(android_deployment.AndroidDeployment, 'read_android_settings', return_value={}), \ patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', game_name=TEST_GAME_NAME, asset_mode=TEST_ASSET_MODE, asset_type=TEST_ASSET_TYPE, embedded_assets=True, android_device_filter=None, clean_deploy=False, deployment_type=android_deployment.AndroidDeployment.DEPLOY_BOTH, android_sdk_path=TEST_ANDROID_SDK_PATH) result = inst.check_known_android_paths(device_id='123') mock_adb_ls.assert_called_once() assert result == android_deployment.KNOWN_ANDROID_EXTERNAL_STORAGE_PATHS[0][:-1] @patch('cmake.Tools.Platform.Android.android_deployment.AndroidDeployment.adb_ls', return_value=(False,None)) def test_check_known_android_paths_fail(mock_adb_ls): with patch.object(android_deployment.AndroidDeployment, 'read_android_settings', return_value={}), \ patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', game_name=TEST_GAME_NAME, asset_mode=TEST_ASSET_MODE, asset_type=TEST_ASSET_TYPE, embedded_assets=True, android_device_filter=None, clean_deploy=False, deployment_type=android_deployment.AndroidDeployment.DEPLOY_BOTH, android_sdk_path=TEST_ANDROID_SDK_PATH) result = inst.check_known_android_paths(device_id='123') assert not result assert mock_adb_ls.call_count == len(android_deployment.KNOWN_ANDROID_EXTERNAL_STORAGE_PATHS) @patch('cmake.Tools.Platform.Android.android_deployment.AndroidDeployment.adb_shell', return_value=None) @patch('cmake.Tools.Platform.Android.android_deployment.AndroidDeployment.check_known_android_paths', return_value="PATH") def test_detect_device_storage_path_no_external_storage_env(mock_check_known_android_paths, mock_adb_shell): with patch.object(android_deployment.AndroidDeployment, 'read_android_settings', return_value={}), \ patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")),\ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', game_name=TEST_GAME_NAME, asset_mode=TEST_ASSET_MODE, asset_type=TEST_ASSET_TYPE, embedded_assets=True, android_device_filter=None, clean_deploy=False, deployment_type=android_deployment.AndroidDeployment.DEPLOY_BOTH, android_sdk_path=TEST_ANDROID_SDK_PATH) result = inst.detect_device_storage_path(device_id=TEST_DEVICE_ID) assert result == "PATH" mock_adb_shell.assert_called_once() mock_check_known_android_paths.assert_called_once_with(TEST_DEVICE_ID) @patch('cmake.Tools.Platform.Android.android_deployment.AndroidDeployment.adb_shell', return_value="NotSet") @patch('cmake.Tools.Platform.Android.android_deployment.AndroidDeployment.check_known_android_paths', return_value="PATH") def test_detect_device_storage_path_invalid_external_storage_env(mock_check_known_android_paths, mock_adb_shell): with patch.object(android_deployment.AndroidDeployment, 'read_android_settings', return_value={}), \ patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")),\ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', game_name=TEST_GAME_NAME, asset_mode=TEST_ASSET_MODE, asset_type=TEST_ASSET_TYPE, embedded_assets=True, android_device_filter=None, clean_deploy=False, deployment_type=android_deployment.AndroidDeployment.DEPLOY_BOTH, android_sdk_path=TEST_ANDROID_SDK_PATH) result = inst.detect_device_storage_path(device_id=TEST_DEVICE_ID) assert result == "PATH" mock_adb_shell.assert_called_once() mock_check_known_android_paths.assert_called_once_with(TEST_DEVICE_ID) @patch('cmake.Tools.Platform.Android.android_deployment.AndroidDeployment.adb_shell', return_value="EXTERNAL_STORAGE=/foo/bar") @patch('cmake.Tools.Platform.Android.android_deployment.AndroidDeployment.adb_ls', return_value=(True, "foo.bar")) def test_detect_device_storage_path_valid_external_storage_env(mock_adb_ls, mock_adb_shell): with patch.object(android_deployment.AndroidDeployment, 'read_android_settings', return_value={}), \ patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")),\ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', game_name=TEST_GAME_NAME, asset_mode=TEST_ASSET_MODE, asset_type=TEST_ASSET_TYPE, embedded_assets=True, android_device_filter=None, clean_deploy=False, deployment_type=android_deployment.AndroidDeployment.DEPLOY_BOTH, android_sdk_path=TEST_ANDROID_SDK_PATH) result = inst.detect_device_storage_path(device_id=TEST_DEVICE_ID) assert result == "/foo/bar" mock_adb_shell.assert_called_once() mock_adb_ls.assert_called_once_with(path='/foo/bar', device_id=TEST_DEVICE_ID) def test_detect_device_storage_path_real_path(): def _mock_adb_shell(command, device_id): if command == "set | grep EXTERNAL_STORAGE": return "EXTERNAL_STORAGE=/foo/bar" elif command == f'realpath /foo/bar': return "/foo_reals" else: raise AssertionError def _mock_adb_ls(path, device_id, args=None): if path == "/foo/bar": return False, None elif path == '/foo_reals': return True, "foo.bar" else: raise AssertionError with patch.object(android_deployment.AndroidDeployment, 'read_android_settings', return_value={}), \ patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(android_deployment.AndroidDeployment, 'adb_shell', wraps=_mock_adb_shell), \ patch.object(android_deployment.AndroidDeployment, 'adb_ls', wraps=_mock_adb_ls), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', game_name=TEST_GAME_NAME, asset_mode=TEST_ASSET_MODE, asset_type=TEST_ASSET_TYPE, embedded_assets=True, android_device_filter=None, clean_deploy=False, deployment_type=android_deployment.AndroidDeployment.DEPLOY_BOTH, android_sdk_path=TEST_ANDROID_SDK_PATH) result = inst.detect_device_storage_path(device_id=TEST_DEVICE_ID) assert result == "/foo_reals" @patch('cmake.Tools.Platform.Android.android_deployment.AndroidDeployment.check_known_android_paths', return_value="PATH") def test_detect_device_storage_path_real_path_fail(mock_check_known_android_paths): def _mock_adb_shell(command, device_id): if command == "set | grep EXTERNAL_STORAGE": return "EXTERNAL_STORAGE=/foo/bar" elif command == f'realpath /foo/bar': return "/foo_reals" else: raise AssertionError def _mock_adb_ls(path, device_id, args=None): if path == "/foo/bar": return False, None elif path == '/foo_reals': return False, None else: raise AssertionError with patch.object(android_deployment.AndroidDeployment, 'read_android_settings', return_value={}), \ patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(android_deployment.AndroidDeployment, 'adb_shell', wraps=_mock_adb_shell), \ patch.object(android_deployment.AndroidDeployment, 'adb_ls', wraps=_mock_adb_ls), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', game_name=TEST_GAME_NAME, asset_mode=TEST_ASSET_MODE, asset_type=TEST_ASSET_TYPE, embedded_assets=True, android_device_filter=None, clean_deploy=False, deployment_type=android_deployment.AndroidDeployment.DEPLOY_BOTH, android_sdk_path=TEST_ANDROID_SDK_PATH) result = inst.detect_device_storage_path(device_id=TEST_DEVICE_ID) assert result == "PATH" mock_check_known_android_paths.assert_called_once_with(TEST_DEVICE_ID) @patch('cmake.Tools.Platform.Android.android_deployment.AndroidDeployment.adb_shell', return_value="2020-04-30 09:20:00.0000") def test_get_device_file_timestamp_success(mock_adb_shell): with patch.object(android_deployment.AndroidDeployment, 'read_android_settings', return_value={}), \ patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', game_name=TEST_GAME_NAME, asset_mode=TEST_ASSET_MODE, asset_type=TEST_ASSET_TYPE, embedded_assets=True, android_device_filter=None, clean_deploy=False, deployment_type=android_deployment.AndroidDeployment.DEPLOY_BOTH, android_sdk_path=TEST_ANDROID_SDK_PATH) remote_path = "/foo/bar/timestamp.txt" result = inst.get_device_file_timestamp(remote_file_path=remote_path, device_id=TEST_DEVICE_ID) assert result == time.mktime(time.strptime("2020-04-30 09:20:00.0000", '%Y-%m-%d %H:%M:%S.%f')) mock_adb_shell.assert_called_once_with(command=f'cat {remote_path}', device_id=TEST_DEVICE_ID) @patch('cmake.Tools.Platform.Android.android_deployment.AndroidDeployment.adb_shell', return_value=None) def test_get_device_file_timestamp_no_file(mock_adb_shell): with patch.object(android_deployment.AndroidDeployment, 'read_android_settings', return_value={}), \ patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', game_name=TEST_GAME_NAME, asset_mode=TEST_ASSET_MODE, asset_type=TEST_ASSET_TYPE, embedded_assets=True, android_device_filter=None, clean_deploy=False, deployment_type=android_deployment.AndroidDeployment.DEPLOY_BOTH, android_sdk_path=TEST_ANDROID_SDK_PATH) remote_path = "/foo/bar/timestamp.txt" result = inst.get_device_file_timestamp(remote_file_path=remote_path, device_id=TEST_DEVICE_ID) assert not result mock_adb_shell.assert_called_once_with(command=f'cat {remote_path}', device_id=TEST_DEVICE_ID) @patch('cmake.Tools.Platform.Android.android_deployment.AndroidDeployment.adb_shell', return_value="ZZZZXXXX") def test_get_device_file_timestamp_bad_timestamp_file(mock_adb_shell): with patch.object(android_deployment.AndroidDeployment, 'read_android_settings', return_value={}), \ patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): inst = android_deployment.AndroidDeployment(dev_root=TEST_DEV_ROOT, build_dir=TEST_BUILD_DIR, configuration='profile', game_name=TEST_GAME_NAME, asset_mode=TEST_ASSET_MODE, asset_type=TEST_ASSET_TYPE, embedded_assets=True, android_device_filter=None, clean_deploy=False, deployment_type=android_deployment.AndroidDeployment.DEPLOY_BOTH, android_sdk_path=TEST_ANDROID_SDK_PATH) remote_path = "/foo/bar/timestamp.txt" result = inst.get_device_file_timestamp(remote_file_path=remote_path, device_id=TEST_DEVICE_ID) assert not result mock_adb_shell.assert_called_once_with(command=f'cat {remote_path}', device_id=TEST_DEVICE_ID) def test_update_device_file_timestamp(tmpdir): cache_dir = f'{TEST_DEV_ROOT}/{TEST_GAME_NAME}/Cache/{TEST_ASSET_TYPE}' tmpdir.ensure(f'{cache_dir}/foo.txt') mock_dev_root = tmpdir.join(TEST_DEV_ROOT).realpath() with patch.object(android_deployment.AndroidDeployment, 'read_android_settings', return_value={}), \ patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(android_deployment.AndroidDeployment, 'adb_call', return_value="") as mock_adb_call: inst = android_deployment.AndroidDeployment(dev_root=mock_dev_root, build_dir=TEST_BUILD_DIR, configuration='profile', game_name=TEST_GAME_NAME, asset_mode=TEST_ASSET_MODE, asset_type=TEST_ASSET_TYPE, embedded_assets=True, android_device_filter=None, clean_deploy=False, deployment_type=android_deployment.AndroidDeployment.DEPLOY_ASSETS_ONLY, android_sdk_path=TEST_ANDROID_SDK_PATH) remote_path = "/foo/bar/timestamp.txt" inst.update_device_file_timestamp(relative_assets_path=remote_path, device_id=TEST_DEVICE_ID) mock_adb_call.assert_called() @pytest.mark.parametrize( "test_config, test_package_name, test_device_storage_path", [ pytest.param('profile', 'com.amazon.lumberyard.foo', '/data/fool_storage'), pytest.param('debug', 'com.amazon.lumberyard.foo', '/data/fool_storage'), pytest.param('profile', 'com.amazon.lumberyard.bar', '/data/fool_storage'), pytest.param('debug', 'com.amazon.lumberyard.bar', '/data/fool_storage'), pytest.param('profile', 'com.amazon.lumberyard.foo', '/data/fool_storage2'), pytest.param('debug', 'com.amazon.lumberyard.foo', '/data/fool_storage2'), pytest.param('profile', 'com.amazon.lumberyard.bar', '/data/fool_storage2'), pytest.param('debug', 'com.amazon.lumberyard.bar', '/data/fool_storage2') ] ) def test_execute_success(tmpdir, test_config, test_package_name, test_device_storage_path): mock_dev_root = tmpdir.join(TEST_DEV_ROOT).realpath() tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_BUILD_DIR}/app/build/outputs/apk/{test_config}/app-{test_config}.apk").ensure() expected_apk_path = str(tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_BUILD_DIR}/app/build/outputs/apk/{test_config}/app-{test_config}.apk").realpath()) tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_GAME_NAME}/Cache/{TEST_ASSET_TYPE}/dummy.txt").ensure() expected_asset_path = str(tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_GAME_NAME}/Cache/{TEST_ASSET_TYPE}").realpath()) tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_BUILD_DIR}/app/src/main/assets/Registry/dummy.txt").ensure() expected_registry_path = str(tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_BUILD_DIR}/app/src/main/assets/Registry").realpath()) expected_storage_registry_path = f'{test_device_storage_path}/Android/data/{test_package_name}/files/Registry' def _mock_adb_call(arg_list, device_id=None): if arg_list == "start-server": return "SUCCESS" if arg_list == "kill-server": return "SUCCESS" elif isinstance(arg_list, list): if match_arg_list(arg_list, ['install', '-r', expected_apk_path]): return "SUCCESS" elif match_arg_list(arg_list, ['install', '-t', '-r', expected_apk_path]): return "SUCCESS" elif match_arg_list(arg_list, ['push', expected_asset_path, f'{test_device_storage_path}/Android/data/{test_package_name}/files']): return "SUCCESS" elif match_arg_list(arg_list, ['push', expected_registry_path, expected_storage_registry_path]): return "SUCCESS" raise AssertionError with patch.object(android_deployment.AndroidDeployment, 'get_target_android_devices', return_value=[TEST_DEVICE_ID]), \ patch.object(android_deployment.AndroidDeployment, 'detect_device_storage_path', return_value=test_device_storage_path), \ patch.object(android_deployment.AndroidDeployment, 'get_device_file_timestamp', return_value=None), \ patch.object(android_deployment.AndroidDeployment, 'update_device_file_timestamp') as mock_update_device_file_timestamp, \ patch.object(android_deployment.AndroidDeployment, 'read_android_settings', return_value={'package_name': test_package_name}), \ patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(android_deployment.AndroidDeployment, 'adb_call', wraps=_mock_adb_call) as mock_adb_call, \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): inst = android_deployment.AndroidDeployment(dev_root=mock_dev_root, build_dir=TEST_BUILD_DIR, configuration=test_config, game_name=TEST_GAME_NAME, asset_mode=TEST_ASSET_MODE, asset_type=TEST_ASSET_TYPE, embedded_assets=False, android_device_filter=None, clean_deploy=False, deployment_type=android_deployment.AndroidDeployment.DEPLOY_BOTH, android_sdk_path=TEST_ANDROID_SDK_PATH) inst.execute() mock_update_device_file_timestamp.assert_called_once() assert mock_adb_call.call_count == 5 @pytest.mark.parametrize( "test_game_name, test_config, test_package_name, test_device_storage_path, test_asset_type", [ pytest.param('game1','profile', 'com.amazon.lumberyard.foo', '/data/fool_storage', 'android'), pytest.param('game1','debug', 'com.amazon.lumberyard.foo', '/data/fool_storage', 'android'), pytest.param('game2','profile', 'com.amazon.lumberyard.bar', '/data/fool_storage', 'android'), pytest.param('game2','debug', 'com.amazon.lumberyard.bar', '/data/fool_storage', 'android'), pytest.param('game3','profile', 'com.amazon.lumberyard.foo', '/data/fool_storage2', 'pc'), pytest.param('game3','debug', 'com.amazon.lumberyard.foo', '/data/fool_storage2', 'pc'), pytest.param('game4','profile', 'com.amazon.lumberyard.bar', '/data/fool_storage2', 'pc'), pytest.param('game4','debug', 'com.amazon.lumberyard.bar', '/data/fool_storage2', 'pc') ] ) def test_execute_clean_deploy_success(tmpdir, test_game_name, test_config, test_package_name, test_device_storage_path, test_asset_type): mock_dev_root = tmpdir.join(TEST_DEV_ROOT).realpath() tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_BUILD_DIR}/app/build/outputs/apk/{test_config}/app-{test_config}.apk").ensure() expected_apk_path = str(tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_BUILD_DIR}/app/build/outputs/apk/{test_config}/app-{test_config}.apk").realpath()) tmpdir.join(f"{TEST_DEV_ROOT}/{test_game_name}/Cache/{test_asset_type}/dummy.txt").ensure() expected_asset_path = str(tmpdir.join(f"{TEST_DEV_ROOT}/{test_game_name}/Cache/{test_asset_type}").realpath()) tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_BUILD_DIR}/app/src/main/assets/Registry/dummy.txt").ensure() expected_registry_path = str(tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_BUILD_DIR}/app/src/main/assets/Registry").realpath()) expected_storage_path = f'{test_device_storage_path}/Android/data/{test_package_name}/files' expected_storage_registry_path = f'{test_device_storage_path}/Android/data/{test_package_name}/files/Registry' def _mock_adb_call(arg_list, device_id=None): if arg_list == "start-server": return "SUCCESS" if arg_list == "kill-server": return "SUCCESS" elif isinstance(arg_list,list): if match_arg_list(arg_list, ['install', '-r', expected_apk_path]): return "SUCCESS" elif match_arg_list(arg_list, ['install', '-t', '-r', expected_apk_path]): return "SUCCESS" elif match_arg_list(arg_list, ['push', expected_asset_path, '-r', expected_apk_path, expected_storage_path]): return "SUCCESS" elif match_arg_list(arg_list, ['shell', 'cmd', 'package', 'list', 'packages', test_package_name]): return test_package_name elif match_arg_list(arg_list, ['uninstall', test_package_name]): return "SUCCESS" elif match_arg_list(arg_list, ['push', expected_asset_path, expected_storage_path]): return "SUCCESS" elif match_arg_list(arg_list, ['push', expected_registry_path, expected_storage_registry_path]): return "SUCCESS" raise AssertionError def _mock_adb_shell(command, device_id): assert command.startswith('rm -rf') def _mock_adb_ls(path, device_id, args=None): if path == "/foo/bar": return False, None elif path == '/foo_reals': return False, None else: raise AssertionError with patch.object(android_deployment.AndroidDeployment, 'get_target_android_devices', return_value=[TEST_DEVICE_ID]) as mock_get_target_android_devices, \ patch.object(android_deployment.AndroidDeployment, 'detect_device_storage_path', return_value=test_device_storage_path) as mock_detect_device_storage_path, \ patch.object(android_deployment.AndroidDeployment, 'get_device_file_timestamp', return_value=None) as mock_get_device_file_timestamp, \ patch.object(android_deployment.AndroidDeployment, 'update_device_file_timestamp') as mock_update_device_file_timestamp, \ patch.object(android_deployment.AndroidDeployment, 'read_android_settings', return_value={'package_name': test_package_name}), \ patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(android_deployment.AndroidDeployment, 'adb_call', wraps=_mock_adb_call) as mock_adb_call, \ patch.object(android_deployment.AndroidDeployment, 'adb_shell', wraps=_mock_adb_shell) as mock_adb_shell, \ patch.object(android_deployment.AndroidDeployment, 'adb_ls', wraps=_mock_adb_ls), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar"]): inst = android_deployment.AndroidDeployment(dev_root=mock_dev_root, build_dir=TEST_BUILD_DIR, configuration=test_config, game_name=test_game_name, asset_mode=TEST_ASSET_MODE, asset_type=test_asset_type, embedded_assets=False, android_device_filter=None, clean_deploy=True, deployment_type=android_deployment.AndroidDeployment.DEPLOY_BOTH, android_sdk_path=TEST_ANDROID_SDK_PATH) inst.execute() assert mock_adb_call.call_count == 7 mock_adb_shell.assert_called_once() mock_update_device_file_timestamp.assert_called_once() mock_get_device_file_timestamp.assert_called_once() mock_detect_device_storage_path.assert_called_once() mock_get_target_android_devices.assert_called_once() @pytest.mark.parametrize( "test_config, test_package_name, test_device_storage_path", [ pytest.param('profile', 'com.amazon.lumberyard.foo', '/data/fool_storage'), pytest.param('debug', 'com.amazon.lumberyard.foo', '/data/fool_storage'), pytest.param('profile', 'com.amazon.lumberyard.bar', '/data/fool_storage'), pytest.param('debug', 'com.amazon.lumberyard.bar', '/data/fool_storage'), pytest.param('profile', 'com.amazon.lumberyard.foo', '/data/fool_storage2'), pytest.param('debug', 'com.amazon.lumberyard.foo', '/data/fool_storage2'), pytest.param('profile', 'com.amazon.lumberyard.bar', '/data/fool_storage2'), pytest.param('debug', 'com.amazon.lumberyard.bar', '/data/fool_storage2') ] ) def test_execute_incremental_deploy_success(tmpdir, test_config, test_package_name, test_device_storage_path): mock_dev_root = tmpdir.join(TEST_DEV_ROOT).realpath() tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_BUILD_DIR}/app/build/outputs/apk/{test_config}/app-{test_config}.apk").ensure() expected_apk_path = str(tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_BUILD_DIR}/app/build/outputs/apk/{test_config}/app-{test_config}.apk").realpath()) tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_GAME_NAME}/Cache/{TEST_ASSET_TYPE}/dummy.txt").ensure() tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_BUILD_DIR}/app/src/main/assets/Registry/dummy.txt").ensure() expected_registry_path = str(tmpdir.join(f"{TEST_DEV_ROOT}/{TEST_BUILD_DIR}/app/src/main/assets/Registry").realpath()) expected_storage_registry_path = f'{test_device_storage_path}/Android/data/{test_package_name}/files/Registry' def _mock_adb_call(arg_list, device_id=None): if arg_list == "start-server": return "SUCCESS" if arg_list == "kill-server": return "SUCCESS" elif isinstance(arg_list,list): if match_arg_list(arg_list, ['install', '-r', expected_apk_path]): return "SUCCESS" elif match_arg_list(arg_list, ['install', '-t', '-r', expected_apk_path]): return "SUCCESS" elif match_arg_list(arg_list, ['push', expected_registry_path, expected_storage_registry_path]): return "SUCCESS" elif len(arg_list) == 3 and arg_list[0] == 'push' and arg_list[1] == 'foo.bar': return "SUCCESS" raise AssertionError def _mock_should_copy_file(check_path, check_time): return check_path == 'foo.bar' with patch.object(android_deployment.AndroidDeployment, 'get_target_android_devices', return_value=[TEST_DEVICE_ID]) as mock_get_target_android_devices, \ patch.object(android_deployment.AndroidDeployment, 'detect_device_storage_path', return_value=test_device_storage_path) as mock_detect_device_storage_path, \ patch.object(android_deployment.AndroidDeployment, 'get_device_file_timestamp', return_value=datetime.datetime.now()) as mock_get_device_file_timestamp, \ patch.object(android_deployment.AndroidDeployment, 'update_device_file_timestamp') as mock_update_device_file_timestamp, \ patch.object(android_deployment.AndroidDeployment, 'read_android_settings', return_value={'package_name': test_package_name}), \ patch.object(android_deployment.AndroidDeployment, 'resolve_adb_tool', return_value=pathlib.Path("Foo")), \ patch.object(android_deployment.AndroidDeployment, 'adb_call', wraps=_mock_adb_call) as mock_adb_call, \ patch.object(android_deployment.AndroidDeployment, 'should_copy_file', wraps=_mock_should_copy_file), \ patch.object(pathlib.Path, 'glob', return_value=["foo.bar", "no.bar"]): inst = android_deployment.AndroidDeployment(dev_root=mock_dev_root, build_dir=TEST_BUILD_DIR, configuration=test_config, game_name=TEST_GAME_NAME, asset_mode=TEST_ASSET_MODE, asset_type=TEST_ASSET_TYPE, embedded_assets=False, android_device_filter=None, clean_deploy=False, deployment_type=android_deployment.AndroidDeployment.DEPLOY_BOTH, android_sdk_path=TEST_ANDROID_SDK_PATH) inst.execute() assert mock_adb_call.call_count == 5 mock_update_device_file_timestamp.assert_called_once() mock_get_device_file_timestamp.assert_called_once() mock_detect_device_storage_path.assert_called_once() mock_get_target_android_devices.assert_called_once()