Merge pull request #179 from rbaron/master

Fixed issue #170
This commit is contained in:
Budi Utomo 2019-07-25 12:57:01 +02:00 committed by GitHub
commit 34fa736916
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 50 additions and 19 deletions

View file

@ -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`

View file

@ -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())

View file

@ -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)

View file

@ -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)