diff --git a/README_CUSTOM_CONFIG.md b/README_CUSTOM_CONFIG.md index 02ebc71..0d69701 100644 --- a/README_CUSTOM_CONFIG.md +++ b/README_CUSTOM_CONFIG.md @@ -51,7 +51,7 @@ If you want to backup/reuse the avds created with furture upgrades or for replic - -v local_backup/android_emulator:/root/android_emulator ```bash -docker run --privileged -d -p 6080:6080 -p 4723:4723 -p 5554:5554 -p 5555:5555 -v local_backup/.android:/root/.android -v local_backup/android_emulator:local_backup/android_emulator -e DEVICE="Nexus 5" --name android-container budtmo/docker-android-x86-8.1 +docker run --privileged -d -p 6080:6080 -p 4723:4723 -p 5554:5554 -p 5555:5555 -v local_backup/.android:/root/.android -v local_backup/android_emulator:/root/android_emulator -e DEVICE="Nexus 5" --name android-container budtmo/docker-android-x86-8.1 ``` For the first run, this will create a new avd and all the changes will be accessible in the `local_backup` directory. Now for all future runs, it will reuse the avds. Even this should work with new releases of `docker-android` diff --git a/src/app.py b/src/app.py index ed767be..1b0ae8a 100644 --- a/src/app.py +++ b/src/app.py @@ -50,8 +50,22 @@ def convert_str_to_bool(str: str) -> bool: logger.error(err) -def is_initialized() -> bool: - return os.path.exists(os.path.join(ROOT, '.android', 'devices.xml')) +def is_initialized(device_name) -> bool: + config_path = os.path.join(ROOT, 'android_emulator', 'config.ini') + + if os.path.exists(config_path): + logger.info('Found existing config file at {}.'.format(config_path)) + with open(config_path, 'r') as f: + if any('hw.device.name={}'.format(device_name) in line for line in f): + logger.info('Existing config file references {}. Assuming device was previously initialized.'.format(device_name)) + return True + else: + logger.info('Existing config file does not reference {}. Assuming new device.'.format(device_name)) + return False + + logger.info('No config file file was found at {}. Assuming new device.'.format(config_path)) + return False + ANDROID_HOME = get_or_raise('ANDROID_HOME') ANDROID_VERSION = get_or_raise('ANDROID_VERSION') @@ -68,7 +82,7 @@ logger.info('Android version: {version} \n' img=SYS_IMG, img_type=IMG_TYPE)) -def prepare_avd(device: str, avd_name: str): +def prepare_avd(device: str, avd_name: str, dp_size: str): """ Create and run android virtual device. @@ -101,6 +115,8 @@ def prepare_avd(device: str, avd_name: str): config_path = '/'.join([avd_path, 'config.ini']) with open(config_path, 'a') as file: file.write('skin.path={sp}'.format(sp=skin_path)) + file.write('\ndisk.dataPartition.size={dp}'.format(dp=dp_size)) + logger.info('Skin was added in config.ini') @@ -192,21 +208,23 @@ def run(): avd_name = '{device}_{version}'.format(device=device.replace(' ', '_').lower(), version=ANDROID_VERSION) logger.info('AVD name: {avd}'.format(avd=avd_name)) - is_first_run = not is_initialized() + is_first_run = not is_initialized(device) + + dp_size = os.getenv('DATAPARTITION', '550m') if is_first_run: logger.info('Preparing emulator...') - prepare_avd(device, avd_name) + prepare_avd(device, avd_name, dp_size) logger.info('Run emulator...') - dp_size = os.getenv('DATAPARTITION', '550m') - with open("/root/android_emulator/config.ini", "a") as cfg: - cfg.write('\ndisk.dataPartition.size={dp}'.format(dp=dp_size)) if is_first_run: + logger.info('Emulator was not previously initialized. Preparing a new one...') cmd = 'emulator/emulator @{name} -gpu swiftshader_indirect -accel on -wipe-data -writable-system -verbose {custom_args}'.format(name=avd_name, custom_args=custom_args) else: + logger.info('Using previously initialized AVD...') cmd = 'emulator/emulator @{name} -gpu swiftshader_indirect -accel on -verbose -writable-system {custom_args}'.format(name=avd_name, custom_args=custom_args) + appium = convert_str_to_bool(str(os.getenv('APPIUM', False))) if appium: subprocess.Popen(cmd.split()) diff --git a/src/tests/unit/test_app.py b/src/tests/unit/test_app.py index f8e2c2f..e626793 100644 --- a/src/tests/unit/test_app.py +++ b/src/tests/unit/test_app.py @@ -7,6 +7,13 @@ import mock from src import app +# https://bugs.python.org/issue21258 +def mock_open(*args, **kargs): + f_open = mock.mock_open(*args, **kargs) + f_open.return_value.__iter__ = lambda self : iter(self.readline, '') + return f_open + + class TestApp(TestCase): """Unit test class to test other methods in the app.""" @@ -60,7 +67,6 @@ class TestApp(TestCase): os.environ['APPIUM'] = str(True) app.run() self.assertTrue(mocked_avd.called) - self.assertTrue(mocked_open.called) self.assertTrue(mocked_subprocess.called) self.assertTrue(mocked_appium.called) @@ -73,7 +79,6 @@ class TestApp(TestCase): os.environ['RELAXED_SECURITY'] = str(True) app.run() self.assertTrue(mocked_avd.called) - self.assertTrue(mocked_open.called) self.assertTrue(mocked_subprocess.called) self.assertTrue(mocked_appium.called) @@ -85,24 +90,32 @@ class TestApp(TestCase): os.environ['APPIUM'] = str(False) app.run() self.assertTrue(mocked_avd.called) - self.assertTrue(mocked_open.called) self.assertTrue(mocked_subprocess.called) self.assertFalse(mocked_appium.called) @mock.patch('builtins.open') @mock.patch('subprocess.Popen') @mock.patch('os.path.exists', mock.MagicMock(return_value=False)) - def test_run_first_run(self, mocked_open, mocked_subprocess): + def test_it_prepares_avd_on_first_run(self, mocked_open, mocked_subprocess): with mock.patch('src.app.prepare_avd') as mocked_prepare_avd: app.run() - self.assertFalse(app.is_initialized()) + self.assertFalse(app.is_initialized('Nexus 5')) self.assertTrue(mocked_prepare_avd.called) - @mock.patch('builtins.open') @mock.patch('subprocess.Popen') @mock.patch('os.path.exists', mock.MagicMock(return_value=True)) - def test_run_next_run(self, mocked_open, mocked_subprocess): + @mock.patch('builtins.open', mock_open(read_data="\nhw.device.name=Nexus 5\n")) + def test_it_doesnt_prepare_avd_if_config_exists(self, mocked_subprocess): with mock.patch('src.app.prepare_avd') as mocked_prepare_avd: app.run() - self.assertTrue(app.is_initialized()) + self.assertTrue(app.is_initialized('Nexus 5')) self.assertFalse(mocked_prepare_avd.called) + + @mock.patch('subprocess.Popen') + @mock.patch('os.path.exists', mock.MagicMock(return_value=True)) + @mock.patch('builtins.open', mock_open(read_data="\nhw.device.name=Samsung S7\n")) + def test_it_prepares_avd_if_config_is_for_another_device(self, mocked_subprocess): + with mock.patch('src.app.prepare_avd') as mocked_prepare_avd: + app.run() + self.assertFalse(app.is_initialized('Nexus 5')) + self.assertTrue(mocked_prepare_avd.called) diff --git a/src/tests/unit/test_avd.py b/src/tests/unit/test_avd.py index c6ca33b..2512da9 100644 --- a/src/tests/unit/test_avd.py +++ b/src/tests/unit/test_avd.py @@ -18,7 +18,7 @@ class TestAvd(TestCase): def test_nexus_avd_as_default(self, mocked_suprocess, mocked_open): self.assertFalse(mocked_suprocess.called) self.assertFalse(mocked_open.called) - app.prepare_avd('Nexus 5', self.avd_name) + app.prepare_avd('Nexus 5', self.avd_name, '550m') self.assertTrue(mocked_suprocess.called) self.assertTrue(mocked_open.called) @@ -28,7 +28,7 @@ class TestAvd(TestCase): self.assertFalse(mocked_sys_link.called) self.assertFalse(mocked_suprocess.called) self.assertFalse(mocked_open.called) - app.prepare_avd('Samsung Galaxy S6', self.avd_name) + app.prepare_avd('Samsung Galaxy S6', self.avd_name, '550m') self.assertTrue(mocked_sys_link.called) self.assertTrue(mocked_suprocess.called) self.assertTrue(mocked_open.called)