Skip to content

refactor: run command #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Dec 6, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 28 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,41 @@

Project with test for NativeScript tooling.

## Install Requirements
## Requirements

**Posix:**
- Python 2.7 or Python 3.2+

**Windows**
- Python 3.2+

Install Python 2.*:
```
brew install python
```

## Before Running Tests

**Install Required Packages**

Update `pip` and install project requirements:
```
python -m pip install --upgrade pip
pip install -r requirements.txt --user
```

## Before Running Tests
Install packages on macOS:
```bash
pip install --upgrade -r requirements_darwin.txt --user
```
Install packages on Windows on Linux:
```bash
pip install --upgrade -r requirements.txt --user
```

Set `PYTHONUNBUFFERED` and `PYTHONIOENCODING` environment variables:
```bash
export PYTHONUNBUFFERED=1
export PYTHONIOENCODING=utf-8
```
Notes:
- `PYTHONUNBUFFERED` is required to get logging on Jenkins CI working properly.
- `PYTHONIOENCODING` helps to get command execution more stable.

**Setup Machine**

Expand Down
10 changes: 9 additions & 1 deletion SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Install Tesseract

In order to get OCR features workign you need to install `tesseract`.
In order to get OCR features working you need to install `tesseract`.

**macOS**
```bash
Expand All @@ -20,6 +20,14 @@ Download [installer](https://github.com/UB-Mannheim/tesseract/wiki) and install
Notes:
Installation of python wrapper around `tesseract` is handled in `requirements.txt`.

## OpenCV

OpenCV has some known installation issues on Windows when Python 3.7 is used.

Please read those articles:
- [import-cv2-doesnt-give-error-on-command-prompt-but-error-on-idle-on-windows-10ó](https://stackoverflow.com/questions/49516989/import-cv2-doesnt-give-error-on-command-prompt-but-error-on-idle-on-windows-10)
- [opencv-for-python-3-x-under-windows](https://stackoverflow.com/questions/26489867/opencv-for-python-3-x-under-windows)
- [pythonlibs](https://www.lfd.uci.edu/~gohlke/pythonlibs/#opencv)

## (macOS Only) Allow apps to control your computer

Expand Down
22 changes: 9 additions & 13 deletions core/base_test/tns_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ def setUpClass(cls):
Tns.kill()
Gradle.kill()
TnsTest.kill_emulators()
cls.kill_processes()

# Ensure log folders are create
Folder.create(Settings.TEST_OUT_HOME)
Expand All @@ -50,10 +49,16 @@ def setUp(self):
def tearDown(self):
# Kill processes
Tns.kill()
self.kill_processes()
Process.kill_all_in_context()

# Analise test result
result = self._resultForDoCleanups
if Settings.PYTHON_VERSION < 3:
# noinspection PyUnresolvedReferences
result = self._resultForDoCleanups
else:
# noinspection PyUnresolvedReferences
result = self._outcome.result

outcome = 'FAILED'
if result.errors == [] and result.failures == []:
outcome = 'PASSED'
Expand All @@ -69,18 +74,9 @@ def tearDownClass(cls):
"""
Tns.kill()
TnsTest.kill_emulators()
for process in TestContext.STARTED_PROCESSES:
Log.info("Kill Process: " + os.linesep + process.commandline)
Process.kill_pid(process.pid)
Process.kill_all_in_context()
Log.test_class_end(class_name=cls.__name__)

@staticmethod
def kill_processes():
for process in TestContext.STARTED_PROCESSES:
if Process.is_running(process.pid):
Log.info("Kill Process: " + os.linesep + process.commandline)
Process.kill_pid(process.pid)

@staticmethod
def kill_emulators():
DeviceManager.Emulator.stop()
Expand Down
6 changes: 4 additions & 2 deletions core/log/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
class Log(object):

@staticmethod
def log(level, message):
def log(level, msg):
if level != logging.DEBUG:
date = datetime.datetime.now().strftime('%H:%M:%S')
print '{0} {1}'.format(date, message)
print('{0} {1}'.format(date, msg))

@staticmethod
def debug(message):
Expand Down Expand Up @@ -51,12 +51,14 @@ def test_end(test_name, outcome):
Log.info('TEST COMPLETE: {0}'.format(test_name))
Log.info('OUTCOME: {0}'.format(outcome))
Log.info('=============================================================')
Log.info('')

@staticmethod
def test_class_end(class_name):
Log.info('')
Log.info('END CLASS: {0}'.format(class_name))
Log.info('=============================================================')
Log.info('')

@staticmethod
def test_step(message):
Expand Down
13 changes: 9 additions & 4 deletions core/settings/Settings.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging
import os
import platform
import sys

from core.enums.env import EnvironmentType
from core.enums.os_type import OSType
Expand All @@ -17,6 +18,10 @@ def get_os():
return OSType.LINUX


def get_python_version():
return sys.version_info[0]


def get_env():
env = os.environ.get('TEST_ENV', 'next')
if 'next' in env:
Expand All @@ -34,14 +39,14 @@ def get_project_home():
return home


HOST_OS = get_os()
PYTHON_VERSION = get_python_version()
ENV = get_env()

LOG_LEVEL = logging.DEBUG

NS_GIT_ORG = 'NativeScript'

HOST_OS = get_os()

ENV = get_env()

TEST_RUN_HOME = get_project_home()
TEST_SUT_HOME = os.path.join(TEST_RUN_HOME, 'sut')

Expand Down
13 changes: 6 additions & 7 deletions core/utils/device/adb.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
from core.enums.os_type import OSType
from core.settings import Settings
from core.utils.file_utils import File
from core.utils.process import Run, Process
from core.utils.process import Process
from core.utils.run import run

ANDROID_HOME = os.environ.get('ANDROID_HOME')
ADB_PATH = os.path.join(ANDROID_HOME, 'platform-tools', 'adb')
Expand All @@ -19,7 +20,7 @@ def __run_adb_command(command, id=None, wait=True, timeout=60, fail_safe=False,
command = '{0} {1}'.format(ADB_PATH, command)
else:
command = '{0} -s {1} {2}'.format(ADB_PATH, id, command)
return Run.command(cmd=command, wait=wait, timeout=timeout, fail_safe=fail_safe, log_level=log_level)
return run(cmd=command, wait=wait, timeout=timeout, fail_safe=fail_safe, log_level=log_level)

@staticmethod
def __get_ids(include_emulator=False):
Expand Down Expand Up @@ -145,12 +146,10 @@ def is_text_visible(id, text, case_sensitive=False):
@staticmethod
def get_screen(id, file_path):
File.clean(path=file_path)
if Settings.OSType == OSType.WINDOWS:
Adb.__run_adb_command(command='exec-out screencap -p > ' + file_path, id=id, log_level=logging.INFO)
if Settings.HOST_OS == OSType.WINDOWS:
Adb.__run_adb_command(command='exec-out screencap -p > ' + file_path, id=id, log_level=logging.DEBUG)
else:
Adb.__run_adb_command(command='shell rm /sdcard/screen.png', id=id)
Adb.__run_adb_command(command='shell screencap -p /sdcard/screen.png', id=id)
Adb.pull(id=id, source='/sdcard/screen.png', target=file_path)
Adb.__run_adb_command(command="shell screencap -p | perl -pe 's/\\x0D\\x0A/\\x0A/g' > " + file_path, id=id)
if File.exists(file_path):
return
else:
Expand Down
14 changes: 9 additions & 5 deletions core/utils/device/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from core.utils.device.simctl import Simctl
from core.utils.file_utils import File, Folder
from core.utils.image_utils import ImageUtils
from core.utils.process import Run
from core.utils.run import run
from core.utils.wait import Wait

if Settings.HOST_OS is OSType.OSX:
Expand All @@ -26,7 +26,7 @@ def __init__(self, id, name, type, version):
self.version = version

if type is DeviceType.IOS:
type = Run.command(cmd="ideviceinfo | grep ProductType")
type = run(cmd="ideviceinfo | grep ProductType")
type = type.replace(',', '')
type = type.replace('ProductType:', '').strip(' ')
self.name = type
Expand Down Expand Up @@ -57,7 +57,7 @@ def is_text_visible(self, text):

# Retry find with ORC if macOS automation fails
if not is_visible:
actual_text = self.get_text().encode('utf-8').strip()
actual_text = self.get_text()
if text in actual_text:
is_visible = True
else:
Expand All @@ -70,7 +70,11 @@ def get_text(self):
actual_image_path = os.path.join(Settings.TEST_OUT_IMAGES, img_name)
File.clean(actual_image_path)
self.get_screen(path=actual_image_path, log_level=logging.DEBUG)
return ImageUtils.get_text(image_path=actual_image_path)
text = ImageUtils.get_text(image_path=actual_image_path)
if Settings.PYTHON_VERSION < 3:
return text.encode('utf-8').strip()
else:
return text.encode('utf-8').strip().decode('utf-8')

def wait_for_text(self, text, timeout=30, retry_delay=1):
t_end = time.time() + timeout
Expand Down Expand Up @@ -114,7 +118,7 @@ def get_screen(self, path, log_level=logging.INFO):
image_saved = True
if image_saved:
message = "Image of {0} saved at {1}".format(self.id, path)
Log.log(level=log_level, message=message)
Log.log(level=log_level, msg=message)
else:
message = "Failed to save image of {0} saved at {1}".format(self.id, path)
Log.error(message)
Expand Down
13 changes: 7 additions & 6 deletions core/utils/device/device_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
from core.utils.device.device import Device
from core.utils.device.idevice import IDevice
from core.utils.device.simctl import Simctl
from core.utils.process import Run, Process
from core.utils.process import Process
from core.utils.run import run


class DeviceManager(object):
Expand Down Expand Up @@ -59,7 +60,7 @@ def start(emulator, wipe_data=True):
command = '{0} @{1} {2}'.format(emulator_path, emulator.avd, options)
Log.info('Booting {0} with cmd:'.format(emulator.avd))
Log.info(command)
Run.command(cmd=command, wait=False, register_for_cleanup=False)
run(cmd=command, wait=False, register=False)
booted = Adb.wait_until_boot(id=emulator.id)
if booted:
Log.info('{0} is up and running!'.format(emulator.avd))
Expand Down Expand Up @@ -102,7 +103,7 @@ class Simulator(object):
def create(simulator_info):
cmd = 'xcrun simctl create {0} "{1}" com.apple.CoreSimulator.SimRuntime.iOS-{2}' \
.format(simulator_info.name, simulator_info.device_type, str(simulator_info.sdk).replace('.', '-'))
result = Run.command(cmd=cmd, timeout=60)
result = run(cmd=cmd, timeout=60)
assert result.exit_code == 0, 'Failed to create iOS Simulator with name {0}'.format(simulator_info.name)
assert '-' in result.output, 'Failed to create iOS Simulator with name {0}'.format(simulator_info.name)
simulator_info.id = result.output.splitlines()[0]
Expand All @@ -121,8 +122,8 @@ def stop(id='booted'):
Process.kill('launchd_sim')
Process.kill_by_commandline('CoreSimulator')
else:
print 'Stop simulator with id ' + id
Run.command(cmd='xcrun simctl shutdown {0}'.format(id), timeout=60)
Log.info('Stop simulator with id ' + id)
run(cmd='xcrun simctl shutdown {0}'.format(id), timeout=60)

@staticmethod
def start(simulator_info):
Expand All @@ -135,7 +136,7 @@ def start(simulator_info):
Log.debug('Simulator GUI is already running.')
else:
Log.info('Start simulator GUI.')
Run.command(cmd='open -a Simulator')
run(cmd='open -a Simulator')

# Return result
device = Device(id=simulator_info.id, name=simulator_info.name, type=DeviceType.SIM,
Expand Down
27 changes: 9 additions & 18 deletions core/utils/device/simctl.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,26 @@

from core.log.log import Log
from core.utils.file_utils import File
from core.utils.process import Run, Process
from core.utils.wait import Wait
from core.utils.run import run


# noinspection PyShadowingBuiltins
class Simctl(object):

@staticmethod
def __run_simctl_command(command, wait=True, timeout=30):
def __run_simctl_command(command, wait=True, timeout=60):
command = '{0} {1}'.format('xcrun simctl', command)
return Run.command(cmd=command, wait=wait, timeout=timeout)
return run(cmd=command, wait=wait, timeout=timeout)

# noinspection PyBroadException
@staticmethod
def __get_simulators():
result = Simctl.__run_simctl_command(command='list --json devices', wait=False)
logs = result.log_file
found = Wait.until(lambda: 'iPhone' in File.read(logs), timeout=30)
Process.kill_pid(result.pid)
if found:
json_content = '{' + File.read(logs).split('{', 1)[-1]
try:
return json.loads(json_content)
except ValueError:
Log.error('Failed to parse json ' + os.linesep + json_content)
return json.loads('{}')
else:
Log.error(File.read(logs))
raise Exception('Failed to list iOS Devices!')
result = Simctl.__run_simctl_command(command='list --json devices')
try:
return json.loads(result.output)
except ValueError:
Log.error('Failed to parse json ' + os.linesep + result.output)
return json.loads('{}')

@staticmethod
def start(simulator_info):
Expand Down
4 changes: 2 additions & 2 deletions core/utils/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""
from core.settings import Settings
from core.utils.file_utils import Folder
from core.utils.process import Run
from core.utils.run import run


def get_repo_url(repo_url, ssh_clone=False):
Expand All @@ -29,6 +29,6 @@ def clone(repo_url, local_folder, branch=None):
command = 'git clone {0} "{1}"'.format(repo_url, str(local_folder))
if branch is not None:
command = command + ' -b ' + branch
result = Run.command(cmd=command)
result = run(cmd=command)
assert "fatal" not in result.output, "Failed to clone: " + repo_url
assert result.exit_code is 0, "Failed to clone: " + repo_url
Loading