From 7785e56a2ab26a55e2d25d5c37b0c74fef03d22b Mon Sep 17 00:00:00 2001 From: butomo1989 Date: Sun, 8 Jan 2017 17:24:14 +0100 Subject: [PATCH] support noVNC --- Dockerfile | 71 +++++++++++++------ service/start.py | 68 ++++++++++-------- service/tests/__init__.py | 19 +++-- ...ndroid_emulator.py => test_get_command.py} | 17 ++--- 4 files changed, 111 insertions(+), 64 deletions(-) rename service/tests/{test_android_emulator.py => test_get_command.py} (70%) diff --git a/Dockerfile b/Dockerfile index 82fe920..87c599c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,24 +1,44 @@ -FROM ubuntu:16.04 +FROM ubuntu:14.04 #======================= # General Configuration #======================= +ENV DEBIAN_FRONTEND noninteractive RUN apt-get update && apt-get upgrade -y -RUN apt-get install wget -y + +#===================================== +# Install virtual display framebuffer +#===================================== +RUN apt-get install Xvfb x11vnc -y + +#================================================ +# Install Windows Manager, Debian Menu and Numpy +# https://github.com/novnc/websockify/issues/77 +#================================================ +RUN apt-get install openbox menu python-numpy -y + +#====================== +# Clone noVNC projects +#====================== +RUN apt-get install git -y +WORKDIR /root +RUN git clone https://github.com/kanaka/noVNC.git && \ + cd noVNC/utils && git clone https://github.com/kanaka/websockify websockify #============== # Install Java #============== -RUN apt-get install openjdk-8-jdk -y -ENV JAVA_HOME="/usr/lib/jvm/java-8-openjdk-amd64/jre" +RUN apt-get install openjdk-7-jdk -y +ENV JAVA_HOME="/usr/lib/jvm/java-7-openjdk-amd64/jre" ENV PATH="${PATH}:${JAVA_HOME}/bin" #===================== # Install Android SDK #===================== +RUN apt-get install wget -y RUN wget http://dl.google.com/android/android-sdk_r24.4.1-linux.tgz -RUN tar -xvzf android-sdk_r24.4.1-linux.tgz -ENV ANDROID_HOME="/android-sdk-linux" +RUN tar -xvzf android-sdk_r24.4.1-linux.tgz && rm android-sdk_r24.4.1-linux.tgz +ENV ANDROID_HOME="/root/android-sdk-linux" ENV PATH="${PATH}:${ANDROID_HOME}/tools" #===================================================== @@ -28,26 +48,33 @@ ENV PATH="${PATH}:${ANDROID_HOME}/tools" RUN echo y | android update sdk --no-ui --filter 2,3 ENV PATH="${PATH}:${ANDROID_HOME}/platform-tools" ENV PATH="${PATH}:${ANDROID_HOME}/build-tools" +RUN mv ${ANDROID_HOME}/tools/emulator ${ANDROID_HOME}/tools/emulator.backup +RUN ln -s ${ANDROID_HOME}/tools/emulator64-arm ${ANDROID_HOME}/tools/emulator -#================================================== -# Fix issue regarding 64bit while running emulator -#================================================== -RUN dpkg --add-architecture i386 -RUN apt-get update -RUN apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 -y -ENV ANDROID_EMULATOR_FORCE_32BIT=true -RUN adb start-server - -#============================================ -# Install nodejs, npm, appium, appium-doctor -#============================================ -RUN apt-get install npm nodejs-legacy -y +#==================================== +# Install latest nodejs, npm, appium +#==================================== +RUN apt-get install curl -y +RUN curl -sL https://deb.nodesource.com/setup_7.x | sudo -E bash - +RUN apt-get install nodejs -y ENV APPIUM_VERSION 1.6.3 RUN npm install -g appium@$APPIUM_VERSION +#====================== +# noVNC Configurations +#====================== +ENV DISPLAY=:0 \ + SCREEN=0 \ + SCREEN_WIDTH=1600 \ + SCREEN_HEIGHT=900 \ + SCREEN_DEPTH=16 \ + LOCAL_PORT=5900 \ + TARGET_PORT=6080 \ + TIMEOUT=1 +RUN ln -s noVNC/vnc_auto.html noVNC/index.html + #=================== # Run docker-appium #=================== -COPY service /service -WORKDIR /service -CMD python start.py +COPY service /root/service +CMD python -m service.start diff --git a/service/start.py b/service/start.py index 4bf7545..33da529 100644 --- a/service/start.py +++ b/service/start.py @@ -9,18 +9,27 @@ logger = logging.getLogger('android_appium') def run(): """ - Run Android emulator and Appium server. + Start noVNC, installation of needed android SDK packages and Appium server. """ android_version = os.getenv('ANDROID_VERSION', '4.2.2') - create_android_emulator(android_version) + os.environ['emulator_name'] = 'emulator_{version}'.format(version=android_version) - emulator_name = 'emulator_{version}'.format(version=android_version) + # Start Xvfb + subprocess.check_call('Xvfb ${DISPLAY} -screen ${SCREEN} ${SCREEN_WIDTH}x${SCREEN_HEIGHT}x${SCREEN_DEPTH} & ' + 'sleep ${TIMEOUT}', shell=True) - logger.info('android emulator name: {name} '.format(name=emulator_name)) - # TODO: check android emulator is ready to use - cmd_run = 'emulator -avd {name} -no-audio -no-window & appium'.format(name=emulator_name) - subprocess.check_call(cmd_run, shell=True) + # Start noVNC, installation of packages and appium + vnc_cmd = 'openbox-session & x11vnc -display ${DISPLAY} -nopw -ncache 10 -forever & ' \ + './noVNC/utils/launch.sh --vnc localhost:${LOCAL_PORT} --listen ${TARGET_PORT}' + android_cmd = get_android_bash_commands(android_version) + if android_cmd: + cmd = '({vnc}) & (xterm -T "Android-Appium" -n "Android-Appium" -e \"{android} && ' \ + '/bin/echo $emulator_name && appium\")'.format(vnc=vnc_cmd, android=android_cmd) + else: + logger.warning('There is no android packages installed!') + cmd = '({vnc}) & (xterm -e \"appium\")'.format(vnc=vnc_cmd) + subprocess.check_call(cmd, shell=True) def get_available_sdk_packages(): @@ -30,12 +39,10 @@ def get_available_sdk_packages(): :return: List of available packages. :rtype: bytearray """ - logger.info('List of Android SDK: ') cmd = ['android', 'list', 'sdk'] - output_str = subprocess.check_output(cmd) + logger.info('List of Android SDK: ') logger.info(output_str) - return [output.strip() for output in output_str.split('\n')] if output_str else None @@ -54,17 +61,20 @@ def get_item_position(keyword, items): return pos -def create_android_emulator(android_version): +def get_android_bash_commands(android_version): """ - Create android emulator based on given android version. + Get bash commands to install given android version and to create android emulator. - It include installation of sdk package and its armeabi v7a. To see list of available targets: android list targets To see list to avd: android list avd :param android_version: android version :type android_version: str + :return: bash commands + :rtype: bytearray """ + bash_command = None + try: packages = get_available_sdk_packages() @@ -79,31 +89,29 @@ def create_android_emulator(android_version): logger.info( 'Package number: {number}, API version: {version}'.format(number=package_number, version=api_version)) - # Install SDK package - logger.info('Installing SDK package...') - cmd_sdk = 'echo y | android update sdk --no-ui --filter {number}'.format(number=package_number) - subprocess.check_call(cmd_sdk, shell=True) - logger.info('Installation completed') + commands = [] + # Command to install SDK package + commands.append('echo y | android update sdk --no-ui --filter {number}'.format(number=package_number)) - # Install armeabi v7a - logger.info('Installing its armeabi...') - cmd_arm = 'echo y | android update sdk --no-ui -a --filter sys-img-armeabi-v7a-android-{api}'.format( - api=api_version) - subprocess.check_call(cmd_arm, shell=True) - logger.info('Installation completed') + # Command to install armeabi v7a + commands.append('echo y | android update sdk --no-ui -a --filter sys-img-armeabi-v7a-android-{api}'.format( + api=api_version)) - # Create android emulator - logger.info('Creating android emulator...') - cmd_emu = 'echo no | android create avd -f -n emulator_{version} -t android-{api} --abi armeabi-v7a'.format( - version=android_version, api=api_version) - subprocess.check_call(cmd_emu, shell=True) - logger.info('Android emulator is created') + # Command to create android emulator + commands.append( + 'echo no | android create avd -f -n emulator_{version} -t android-{api} --abi armeabi-v7a'.format( + version=android_version, api=api_version)) + + # Join all commands in one str for xterm + bash_command = ' && '.join(commands) else: raise RuntimeError('Packages is empty!') except IndexError as i_err: logger.error(i_err) + return bash_command + if __name__ == '__main__': logger.setLevel(logging.INFO) diff --git a/service/tests/__init__.py b/service/tests/__init__.py index fbc8d7c..57c9215 100644 --- a/service/tests/__init__.py +++ b/service/tests/__init__.py @@ -9,11 +9,22 @@ from service import start class TestService(TestCase): """Unit test class to test method run.""" - @mock.patch('service.start.create_android_emulator') + @mock.patch('service.start.get_android_bash_commands') @mock.patch('subprocess.check_call') - def test_service(self, mocked_creation, mocked_subprocess): - self.assertFalse(mocked_creation.called) + def test_service(self, mocked_bash_cmd, mocked_subprocess): + self.assertFalse(mocked_bash_cmd.called) self.assertFalse(mocked_subprocess.called) start.run() - self.assertTrue(mocked_creation.called) + self.assertTrue(mocked_bash_cmd.called) self.assertTrue(mocked_subprocess.called) + + @mock.patch('service.start.get_android_bash_commands') + @mock.patch('subprocess.check_call') + @mock.patch('service.start.logger.warning') + def test_empty_android_cmd(self, mocked_bash_cmd, mocked_subprocess, mocked_logger_warning): + mocked_bash_cmd.return_value = None + self.assertFalse(mocked_subprocess.called) + self.assertFalse(mocked_logger_warning.called) + start.run() + self.assertTrue(mocked_subprocess.called) + self.assertTrue(mocked_logger_warning.called) diff --git a/service/tests/test_android_emulator.py b/service/tests/test_get_command.py similarity index 70% rename from service/tests/test_android_emulator.py rename to service/tests/test_get_command.py index 831b5b6..ecf6547 100644 --- a/service/tests/test_android_emulator.py +++ b/service/tests/test_get_command.py @@ -8,27 +8,28 @@ from service import start @mock.patch('service.start.get_available_sdk_packages') class TestRunService(TestCase): - """Unit test class to test method create_android_emulator.""" + """Unit test class to test method get_android_bash_commands.""" def test_create_emulator(self, mocked_packages): mocked_packages.return_value = ['9- SDK Platform Android 4.4.2, API 19, revision 4', '10- SDK Platform Android 4.3.1, API 18, revision 3', '11- SDK Platform Android 4.2.2, API 17, revision 3'] - with mock.patch('subprocess.check_call') as mocked_subprocess: - self.assertFalse(mocked_subprocess.called) - android_version = '4.2.2' - start.create_android_emulator(android_version) - self.assertTrue(mocked_subprocess.called) + + android_version = '4.2.2' + cmd = start.get_android_bash_commands(android_version) + self.assertIsNotNone(cmd) + self.assertTrue('android update sdk' in cmd) + self.assertTrue('android create avd' in cmd) def test_empty_packages(self, mocked_packages): mocked_packages.return_value = None with self.assertRaises(RuntimeError): - start.create_android_emulator('4.2.2') + start.get_android_bash_commands('4.2.2') def test_index_error(self, mocked_packages): mocked_packages.return_value = ['9 SDK Platform Android 4.4.2, API 19, revision 4', '10 SDK Platform Android 4.3.1, API 18, revision 3', '11 SDK Platform Android 4.2.2, API 17, revision 3'] android_version = '4.2.2' - start.create_android_emulator(android_version) + start.get_android_bash_commands(android_version) self.assertRaises(IndexError)