mirror of
https://github.com/status-im/status-react.git
synced 2025-01-09 18:46:19 +00:00
Allow to measure battery and network consumption on real device
This commit is contained in:
parent
50200404ce
commit
eed610c46e
110
test/appium/docker/Dockerfile
Normal file
110
test/appium/docker/Dockerfile
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
FROM ubuntu:16.04
|
||||||
|
|
||||||
|
LABEL maintainer "Lukasz Fryc <lukasz@status.im>"
|
||||||
|
|
||||||
|
WORKDIR /root
|
||||||
|
|
||||||
|
#==================
|
||||||
|
# General Packages
|
||||||
|
#------------------
|
||||||
|
# openjdk-8-jdk
|
||||||
|
# Java
|
||||||
|
# ca-certificates
|
||||||
|
# SSL client
|
||||||
|
# tzdata
|
||||||
|
# Timezone
|
||||||
|
# zip
|
||||||
|
# Make a zip file
|
||||||
|
# unzip
|
||||||
|
# Unzip zip file
|
||||||
|
# curl
|
||||||
|
# Transfer data from or to a server
|
||||||
|
# wget
|
||||||
|
# Network downloader
|
||||||
|
# libqt5webkit5
|
||||||
|
# Web content engine (Fix issue in Android)
|
||||||
|
# libgconf-2-4
|
||||||
|
# Required package for chrome and chromedriver to run on Linux
|
||||||
|
# xvfb
|
||||||
|
# X virtual framebuffer
|
||||||
|
#==================
|
||||||
|
RUN apt-get -qqy update && \
|
||||||
|
apt-get -qqy --no-install-recommends install \
|
||||||
|
openjdk-8-jdk \
|
||||||
|
ca-certificates \
|
||||||
|
tzdata \
|
||||||
|
zip \
|
||||||
|
unzip \
|
||||||
|
curl \
|
||||||
|
wget \
|
||||||
|
libqt5webkit5 \
|
||||||
|
libgconf-2-4 \
|
||||||
|
xvfb \
|
||||||
|
build-essential \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
#===============
|
||||||
|
# Set JAVA_HOME
|
||||||
|
#===============
|
||||||
|
ENV JAVA_HOME="/usr/lib/jvm/java-8-openjdk-amd64/jre" \
|
||||||
|
PATH=$PATH:$JAVA_HOME/bin
|
||||||
|
|
||||||
|
#=====================
|
||||||
|
# Install Android SDK
|
||||||
|
#=====================
|
||||||
|
ARG SDK_VERSION=sdk-tools-linux-4333796
|
||||||
|
ARG ANDROID_BUILD_TOOLS_VERSION=28.0.1
|
||||||
|
ARG ANDROID_PLATFORM_VERSION="android-27"
|
||||||
|
|
||||||
|
ENV SDK_VERSION=$SDK_VERSION \
|
||||||
|
ANDROID_BUILD_TOOLS_VERSION=$ANDROID_BUILD_TOOLS_VERSION \
|
||||||
|
ANDROID_HOME=/root
|
||||||
|
|
||||||
|
RUN wget -O tools.zip https://dl.google.com/android/repository/${SDK_VERSION}.zip && \
|
||||||
|
unzip tools.zip && rm tools.zip && \
|
||||||
|
chmod a+x -R $ANDROID_HOME && \
|
||||||
|
chown -R root:root $ANDROID_HOME
|
||||||
|
|
||||||
|
ENV PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/tools/bin
|
||||||
|
|
||||||
|
# https://askubuntu.com/questions/885658/android-sdk-repositories-cfg-could-not-be-loaded
|
||||||
|
RUN mkdir -p ~/.android && \
|
||||||
|
touch ~/.android/repositories.cfg && \
|
||||||
|
echo y | sdkmanager "platform-tools" && \
|
||||||
|
echo y | sdkmanager "build-tools;$ANDROID_BUILD_TOOLS_VERSION" && \
|
||||||
|
echo y | sdkmanager "platforms;$ANDROID_PLATFORM_VERSION"
|
||||||
|
|
||||||
|
ENV PATH=$PATH:$ANDROID_HOME/platform-tools:$ANDROID_HOME/build-tools
|
||||||
|
|
||||||
|
#====================================
|
||||||
|
# Install latest nodejs, npm, appiuma
|
||||||
|
#====================================
|
||||||
|
# ARG APPIUM_VERSION=1.7.2
|
||||||
|
# ENV APPIUM_VERSION=$APPIUM_VERSION
|
||||||
|
|
||||||
|
RUN curl -sL https://deb.nodesource.com/setup_9.x | bash -
|
||||||
|
RUN apt-get -qqy install nodejs
|
||||||
|
RUN npm set maxsockets 3 && \
|
||||||
|
npm install -g appium@1.7.2 --unsafe-perm=true --allow-root
|
||||||
|
RUN apt-get remove --purge -y npm && \
|
||||||
|
apt-get autoremove --purge -y && \
|
||||||
|
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \
|
||||||
|
apt-get clean
|
||||||
|
|
||||||
|
#==================================
|
||||||
|
# Fix Issue with timezone mismatch
|
||||||
|
#==================================
|
||||||
|
# ENV TZ="US/Pacific"
|
||||||
|
# RUN echo "${TZ}" > /etc/timezone
|
||||||
|
|
||||||
|
#===============
|
||||||
|
# Expose Ports
|
||||||
|
#---------------
|
||||||
|
# 4723
|
||||||
|
# Appium port
|
||||||
|
#===============
|
||||||
|
EXPOSE 4723
|
||||||
|
|
||||||
|
COPY entry_point.sh /root/
|
||||||
|
RUN chmod +x /root/entry_point.sh
|
||||||
|
ENTRYPOINT /root/entry_point.sh
|
66
test/appium/docker/HOWTO.md
Normal file
66
test/appium/docker/HOWTO.md
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
## Instructions
|
||||||
|
|
||||||
|
Use device with Android 7.1 or newer.
|
||||||
|
|
||||||
|
1. Install needed tools
|
||||||
|
|
||||||
|
- Install Docker https://docs.docker.com/install/
|
||||||
|
- Install Python 3
|
||||||
|
|
||||||
|
Go to https://realpython.com/installing-python and follow the instructions. For macOS with Homebrew, you can run `brew install python3` to install it.
|
||||||
|
|
||||||
|
2. Build Appium docker image
|
||||||
|
|
||||||
|
- Make sure Docker app is running
|
||||||
|
- Build Appium image to have environment in which tests will be executed
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cd appium/docker
|
||||||
|
$ docker build -t "appium/appium:local" .
|
||||||
|
```
|
||||||
|
|
||||||
|
Make sure all build steps were successful. You should see:
|
||||||
|
```
|
||||||
|
Successfully tagged appium/appium:local
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Find out IP address of the device
|
||||||
|
|
||||||
|
On device, open wifi settings and click on the current network. Write down the IP address as it will be needed for running the battery test wirelessly.
|
||||||
|
|
||||||
|
4. Run the battery test
|
||||||
|
|
||||||
|
- Make sure the device is sufficiently charged
|
||||||
|
- Disconnect the device USB cable
|
||||||
|
- Create a directory that will be shared with the docker container. E.g. `mkdir /Users/lukas/Desktop/shared`
|
||||||
|
- Put .apk to test into the shared directory. E.g. `mv StatusIm-181109-092655-009d97-e2e.apk /Users/lukas/Desktop/shared`
|
||||||
|
- Run a test with using appium container
|
||||||
|
- `--device_ip` - IP address of the device (see 3.)
|
||||||
|
- `--apk=StatusIm-181109-092655-009d97-e2e.apk` - name of the apk file
|
||||||
|
- `--docker=True` - run the tests using appium docker container
|
||||||
|
- `--docker_shared_volume=/Users/lukas/Desktop/shared` - path to the shared directory
|
||||||
|
- `--bugreport=True` - generate bugreport file
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cd status-react/test/appium
|
||||||
|
$ python3 -m pytest --apk=StatusIm-181109-092655-009d97-e2e.apk --device_ip=192.168.0.104 --bugreport=True --docker=true --docker_shared_volume=/Users/lukas/Desktop/shared tests/atomic/transactions/test_wallet.py::TestTransactionWalletSingleDevice::test_send_eth_from_wallet_to_contact
|
||||||
|
```
|
||||||
|
- Follow the instructions shown in the command line
|
||||||
|
|
||||||
|
**In case of issues:**
|
||||||
|
|
||||||
|
Find out the Appium container id: `docker ps` and get the latest logs: `docker logs ebdf1761f51f` where `ebdf1761f51f` is the container id.
|
||||||
|
|
||||||
|
5. Analyse test results
|
||||||
|
|
||||||
|
The test generates Android bugreport that is saved in shared directory. It contains data about battery, cpu, memory, network usage, and more. See [energy-efficient-bok](https://github.com/status-im/energy-efficient-bok/blob/master/QA_Android.md) or [Battery Historian](https://developer.android.com/studio/profile/battery-historian) to learn how to analyse it.
|
||||||
|
|
||||||
|
|
||||||
|
## Issues with adb connect
|
||||||
|
|
||||||
|
To run the battery test without charging the device, adb needs to connect to it wirelessly. To avoid wifi connection issues, you can connect to the device via bluetooth.
|
||||||
|
|
||||||
|
macOS instructions:
|
||||||
|
- On device, enable bluetooth on your device in Android settings -> connections -> bluetooth
|
||||||
|
- On device, go to mobile hotspots and tethering and enable bluetooth tethering
|
||||||
|
- On macOS, go to the bluetooth settings and connect with the device (click "Connect to Network")
|
6
test/appium/docker/entry_point.sh
Normal file
6
test/appium/docker/entry_point.sh
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
APPIUM_LOG="/var/log/appium.log"
|
||||||
|
CMD="appium --log $APPIUM_LOG"
|
||||||
|
|
||||||
|
$CMD
|
@ -47,3 +47,5 @@ toolz==0.9.0
|
|||||||
urllib3==1.22
|
urllib3==1.22
|
||||||
yarl==0.12.0
|
yarl==0.12.0
|
||||||
zbarlight==1.2
|
zbarlight==1.2
|
||||||
|
docker
|
||||||
|
influxdb
|
111
test/appium/support/appium_container.py
Normal file
111
test/appium/support/appium_container.py
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
import datetime
|
||||||
|
import logging
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
|
||||||
|
import docker
|
||||||
|
from docker.errors import NotFound
|
||||||
|
|
||||||
|
|
||||||
|
DOCKER_SHARED_VOLUME_PATH = '/root/shared_volume'
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceStats(object):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.total_battery_capacity_mah = None
|
||||||
|
# Est power used (mAh) by the app
|
||||||
|
self.estimated_power_usage_mah = None
|
||||||
|
|
||||||
|
|
||||||
|
class AppiumContainer:
|
||||||
|
|
||||||
|
def start_appium_container(self, shared_volume):
|
||||||
|
docker_client = docker.from_env()
|
||||||
|
try:
|
||||||
|
self.container = docker_client.containers.get("appium")
|
||||||
|
self.container.restart()
|
||||||
|
except NotFound:
|
||||||
|
self.container = docker_client.containers.run("appium/appium:local", detach=True, name="appium",
|
||||||
|
ports={'4723/tcp': 4723},
|
||||||
|
volumes={shared_volume: {
|
||||||
|
'bind': DOCKER_SHARED_VOLUME_PATH, 'mode': 'rw'}})
|
||||||
|
logging.info("Running Appium container. ID: %s" % self.container.short_id)
|
||||||
|
|
||||||
|
def exec_run(self, cmd):
|
||||||
|
return self.container.exec_run(cmd, stdout=True, stderr=True, stdin=True)
|
||||||
|
|
||||||
|
def connect_device(self, device_ip):
|
||||||
|
device_address = device_ip + ':5555'
|
||||||
|
connected_state = "connected to %s" % device_address
|
||||||
|
|
||||||
|
cmd = self.exec_run(['adb', 'connect', device_address])
|
||||||
|
if connected_state in cmd.output.decode("utf-8"):
|
||||||
|
logging.info("adb is already connected with the device")
|
||||||
|
else:
|
||||||
|
logging.info("Connecting the device with adb..")
|
||||||
|
# Restart adb on host machine
|
||||||
|
subprocess.call(['adb', 'kill-server'])
|
||||||
|
input("Connect USB cable to the device and press ENTER..")
|
||||||
|
# Reset USB on host machine
|
||||||
|
subprocess.call(['adb', 'usb'])
|
||||||
|
time.sleep(5) # wait until adb usb is restarted
|
||||||
|
# Set the target device to listen for a TCP/IP connection on port 5555 on host machine
|
||||||
|
subprocess.call(['adb', 'tcpip', '5555'])
|
||||||
|
# restarting in TCP mode port: 5555
|
||||||
|
input("Now, disconnect the USB cable and press ENTER..")
|
||||||
|
# Connect to the device in docker container
|
||||||
|
self.exec_run(['adb', 'connect', device_address])
|
||||||
|
input("Please check your device and allow for USB debugging if necessary. Then press ENTER to continue "
|
||||||
|
"the test..\n")
|
||||||
|
|
||||||
|
def reset_battery_stats(self):
|
||||||
|
logging.info("Resetting device stats..")
|
||||||
|
self.exec_run(['adb', 'shell', 'dumpsys', 'batterystats', '--reset'])
|
||||||
|
|
||||||
|
def generate_bugreport(self, report_name):
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
bugreport_name = "bugreport_%s_%s" % (report_name, now.strftime("%Y-%m-%d_%H-%M-%S"))
|
||||||
|
|
||||||
|
print("\nGenerating device report from the test..")
|
||||||
|
self.exec_run(['adb', 'bugreport', "/%s/%s" % (DOCKER_SHARED_VOLUME_PATH, bugreport_name)])
|
||||||
|
print("Device report saved in the shared volume as %s.zip" % bugreport_name)
|
||||||
|
|
||||||
|
def get_device_stats(self):
|
||||||
|
stats = DeviceStats()
|
||||||
|
|
||||||
|
# Find process uid
|
||||||
|
uid_line = self.exec_run(['adb', 'shell', 'ps', '|', 'grep', 'im.status.ethereum']).output \
|
||||||
|
.decode('utf-8')
|
||||||
|
# Match first word which is the uid
|
||||||
|
match = re.match(r'(?:^|(?:[.!?]\s))(\w+)', uid_line, re.M | re.I)
|
||||||
|
uid = match.group(1).replace('_', '')
|
||||||
|
|
||||||
|
# Battery stats
|
||||||
|
batterystats = self.exec_run(['adb', 'shell', 'dumpsys', 'batterystats', 'im.status.ethereum']).output \
|
||||||
|
.decode('utf-8').splitlines()
|
||||||
|
battery_usage_line = [s for s in batterystats if "Uid %s" % uid in s][0]
|
||||||
|
match = re.match(r'.* Uid %s: ([^\s]+)' % uid, battery_usage_line, re.M | re.I)
|
||||||
|
stats.estimated_power_usage_mah = float(match.group(1))
|
||||||
|
capacity_line = [s for s in batterystats if "Capacity" in s][0]
|
||||||
|
match = re.match(r'.* Capacity: (.*), Computed drain: (.*), .*', capacity_line, re.M | re.I)
|
||||||
|
stats.total_battery_capacity_mah = float(match.group(1))
|
||||||
|
stats.total_computed_drain_mah = float(match.group(2))
|
||||||
|
|
||||||
|
# Wi-Fi stats
|
||||||
|
wifi_stats = self.exec_run(['adb', 'shell', 'dumpsys', 'batterystats', 'im.status.ethereum', '|', 'grep',
|
||||||
|
'Wi-Fi\ total']).output.decode('utf-8')
|
||||||
|
stats.wifi_received = wifi_stats.split()[3].replace(',', '')
|
||||||
|
stats.wifi_sent = wifi_stats.split()[5]
|
||||||
|
|
||||||
|
# OS stats
|
||||||
|
stats.os_version = self.exec_run(['adb', 'shell', 'getprop', 'ro.build.version.release'])\
|
||||||
|
.output.decode('utf-8').rstrip("\n")
|
||||||
|
stats.device_model = self.exec_run(['adb', 'shell', 'getprop', 'ro.product.model'])\
|
||||||
|
.output.decode('utf-8').rstrip("\n")
|
||||||
|
|
||||||
|
return stats
|
||||||
|
|
||||||
|
def stop_container(self):
|
||||||
|
self.container.stop()
|
39
test/appium/support/device_stats_db.py
Normal file
39
test/appium/support/device_stats_db.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import datetime
|
||||||
|
|
||||||
|
from influxdb import InfluxDBClient
|
||||||
|
|
||||||
|
|
||||||
|
def convert_to_mb(value):
|
||||||
|
number = float(value[:-2])
|
||||||
|
unit = value[-2:]
|
||||||
|
if unit == 'KB':
|
||||||
|
number = number / 1000
|
||||||
|
return number
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceStatsDB:
|
||||||
|
|
||||||
|
def __init__(self, host, port, username, password, database):
|
||||||
|
self.client = InfluxDBClient(host, port, username, password, database)
|
||||||
|
|
||||||
|
def save_stats(self, build_name, test_name, test_group, test_passed, device_stats):
|
||||||
|
json_body = [
|
||||||
|
{
|
||||||
|
"measurement": "device",
|
||||||
|
"time": datetime.datetime.utcnow().isoformat(),
|
||||||
|
"fields": {
|
||||||
|
"battery_used_mah": device_stats.estimated_power_usage_mah,
|
||||||
|
"wifi_sent": convert_to_mb(device_stats.wifi_sent),
|
||||||
|
"wifi_received": convert_to_mb(device_stats.wifi_received),
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"test_name": test_name,
|
||||||
|
"test_group": test_group,
|
||||||
|
"build_name": build_name,
|
||||||
|
"device_model": device_stats.device_model,
|
||||||
|
"device_os_version": device_stats.os_version,
|
||||||
|
"test_passed": test_passed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
self.client.write_points(json_body)
|
@ -2,6 +2,7 @@ import asyncio
|
|||||||
import logging
|
import logging
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
from support.appium_container import AppiumContainer
|
||||||
from support.test_data import TestSuiteData
|
from support.test_data import TestSuiteData
|
||||||
|
|
||||||
|
|
||||||
@ -24,6 +25,7 @@ def debug(text: str):
|
|||||||
|
|
||||||
|
|
||||||
test_suite_data = TestSuiteData()
|
test_suite_data = TestSuiteData()
|
||||||
|
appium_container = AppiumContainer()
|
||||||
|
|
||||||
common_password = 'qwerty'
|
common_password = 'qwerty'
|
||||||
unique_password = 'unique' + get_current_time()
|
unique_password = 'unique' + get_current_time()
|
||||||
|
@ -10,6 +10,7 @@ class TestCreateAccount(SingleDeviceTestCase):
|
|||||||
|
|
||||||
@marks.testrail_id(5300)
|
@marks.testrail_id(5300)
|
||||||
@marks.critical
|
@marks.critical
|
||||||
|
@marks.battery_consumption
|
||||||
def test_create_account(self):
|
def test_create_account(self):
|
||||||
sign_in = SignInView(self.driver, skip_popups=False)
|
sign_in = SignInView(self.driver, skip_popups=False)
|
||||||
sign_in.accept_agreements()
|
sign_in.accept_agreements()
|
||||||
|
@ -201,6 +201,7 @@ class TestProfileSingleDevice(SingleDeviceTestCase):
|
|||||||
|
|
||||||
@marks.testrail_id(5382)
|
@marks.testrail_id(5382)
|
||||||
@marks.high
|
@marks.high
|
||||||
|
@marks.battery_consumption
|
||||||
def test_contact_profile_view(self):
|
def test_contact_profile_view(self):
|
||||||
sign_in_view = SignInView(self.driver)
|
sign_in_view = SignInView(self.driver)
|
||||||
sign_in_view.create_user()
|
sign_in_view.create_user()
|
||||||
|
@ -13,6 +13,7 @@ class TestRecoverAccountSingleDevice(SingleDeviceTestCase):
|
|||||||
|
|
||||||
@marks.testrail_id(5301)
|
@marks.testrail_id(5301)
|
||||||
@marks.critical
|
@marks.critical
|
||||||
|
@marks.battery_consumption
|
||||||
def test_recover_account(self):
|
def test_recover_account(self):
|
||||||
sign_in = SignInView(self.driver)
|
sign_in = SignInView(self.driver)
|
||||||
home = sign_in.create_user()
|
home = sign_in.create_user()
|
||||||
|
@ -474,6 +474,7 @@ class TestMessagesOneToOneChatSingle(SingleDeviceTestCase):
|
|||||||
|
|
||||||
@marks.testrail_id(5328)
|
@marks.testrail_id(5328)
|
||||||
@marks.critical
|
@marks.critical
|
||||||
|
@marks.battery_consumption
|
||||||
def test_send_emoji(self):
|
def test_send_emoji(self):
|
||||||
sign_in = SignInView(self.driver)
|
sign_in = SignInView(self.driver)
|
||||||
home = sign_in.create_user()
|
home = sign_in.create_user()
|
||||||
|
@ -1,20 +1,21 @@
|
|||||||
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
import pytest
|
|
||||||
import sys
|
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import asyncio
|
import sys
|
||||||
|
|
||||||
from support.message_reliability_report import create_one_to_one_chat_report, create_public_chat_report
|
|
||||||
from support.api.network_api import NetworkApi
|
|
||||||
from os import environ
|
|
||||||
from appium import webdriver
|
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
from selenium.common.exceptions import WebDriverException
|
from os import environ
|
||||||
from tests import test_suite_data, start_threads
|
|
||||||
|
import pytest
|
||||||
|
from appium import webdriver
|
||||||
from appium.webdriver.common.mobileby import MobileBy
|
from appium.webdriver.common.mobileby import MobileBy
|
||||||
from selenium.common.exceptions import NoSuchElementException
|
from selenium.common.exceptions import NoSuchElementException
|
||||||
|
from selenium.common.exceptions import WebDriverException
|
||||||
|
|
||||||
|
from support.api.network_api import NetworkApi
|
||||||
from support.github_report import GithubHtmlReport
|
from support.github_report import GithubHtmlReport
|
||||||
|
from support.message_reliability_report import create_one_to_one_chat_report, create_public_chat_report
|
||||||
|
from tests import test_suite_data, start_threads, appium_container
|
||||||
|
|
||||||
|
|
||||||
class AbstractTestCase:
|
class AbstractTestCase:
|
||||||
@ -81,11 +82,16 @@ class AbstractTestCase:
|
|||||||
@property
|
@property
|
||||||
def capabilities_local(self):
|
def capabilities_local(self):
|
||||||
desired_caps = dict()
|
desired_caps = dict()
|
||||||
desired_caps['app'] = pytest.config.getoption('apk')
|
if pytest.config.getoption('docker'):
|
||||||
|
# apk is in shared volume directory
|
||||||
|
apk = '/root/shared_volume/%s' % pytest.config.getoption('apk')
|
||||||
|
else:
|
||||||
|
apk = pytest.config.getoption('apk')
|
||||||
|
desired_caps['app'] = apk
|
||||||
desired_caps['deviceName'] = 'nexus_5'
|
desired_caps['deviceName'] = 'nexus_5'
|
||||||
desired_caps['platformName'] = 'Android'
|
desired_caps['platformName'] = 'Android'
|
||||||
desired_caps['appiumVersion'] = '1.7.2'
|
desired_caps['appiumVersion'] = '1.7.2'
|
||||||
desired_caps['platformVersion'] = '7.1'
|
desired_caps['platformVersion'] = pytest.config.getoption('platform_version')
|
||||||
desired_caps['newCommandTimeout'] = 600
|
desired_caps['newCommandTimeout'] = 600
|
||||||
desired_caps['fullReset'] = False
|
desired_caps['fullReset'] = False
|
||||||
desired_caps['unicodeKeyboard'] = True
|
desired_caps['unicodeKeyboard'] = True
|
||||||
@ -152,21 +158,28 @@ class Driver(webdriver.Remote):
|
|||||||
class SingleDeviceTestCase(AbstractTestCase):
|
class SingleDeviceTestCase(AbstractTestCase):
|
||||||
|
|
||||||
def setup_method(self, method, max_duration=1800):
|
def setup_method(self, method, max_duration=1800):
|
||||||
|
if pytest.config.getoption('docker'):
|
||||||
|
appium_container.start_appium_container(pytest.config.getoption('docker_shared_volume'))
|
||||||
|
appium_container.connect_device(pytest.config.getoption('device_ip'))
|
||||||
|
|
||||||
(executor, capabilities) = (self.executor_sauce_lab, self.capabilities_sauce_lab) if \
|
(executor, capabilities) = (self.executor_sauce_lab, self.capabilities_sauce_lab) if \
|
||||||
self.environment == 'sauce' else (self.executor_local, self.capabilities_local)
|
self.environment == 'sauce' else (self.executor_local, self.capabilities_local)
|
||||||
capabilities['maxDuration'] = max_duration
|
capabilities['maxDuration'] = max_duration
|
||||||
self.driver = Driver(executor, capabilities)
|
self.driver = Driver(executor, capabilities)
|
||||||
|
|
||||||
test_suite_data.current_test.testruns[-1].jobs[self.driver.session_id] = 1
|
test_suite_data.current_test.testruns[-1].jobs[self.driver.session_id] = 1
|
||||||
self.driver.implicitly_wait(self.implicitly_wait)
|
self.driver.implicitly_wait(self.implicitly_wait)
|
||||||
|
|
||||||
|
if pytest.config.getoption('docker'):
|
||||||
|
appium_container.reset_battery_stats()
|
||||||
|
|
||||||
def teardown_method(self, method):
|
def teardown_method(self, method):
|
||||||
if self.environment == 'sauce':
|
if self.environment == 'sauce':
|
||||||
self.print_sauce_lab_info(self.driver)
|
self.print_sauce_lab_info(self.driver)
|
||||||
try:
|
try:
|
||||||
self.add_alert_text_to_report(self.driver)
|
self.add_alert_text_to_report(self.driver)
|
||||||
self.driver.quit()
|
self.driver.quit()
|
||||||
|
if pytest.config.getoption('docker'):
|
||||||
|
appium_container.stop_container()
|
||||||
except (WebDriverException, AttributeError):
|
except (WebDriverException, AttributeError):
|
||||||
pass
|
pass
|
||||||
finally:
|
finally:
|
||||||
|
@ -2,8 +2,10 @@ import requests
|
|||||||
import pytest
|
import pytest
|
||||||
import re
|
import re
|
||||||
from _pytest.runner import runtestprotocol
|
from _pytest.runner import runtestprotocol
|
||||||
|
|
||||||
|
from support.device_stats_db import DeviceStatsDB
|
||||||
from support.test_rerun import should_rerun_test
|
from support.test_rerun import should_rerun_test
|
||||||
from tests import test_suite_data
|
from tests import test_suite_data, appium_container
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from os import environ
|
from os import environ
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
@ -35,6 +37,10 @@ def pytest_addoption(parser):
|
|||||||
action='store',
|
action='store',
|
||||||
default='sauce',
|
default='sauce',
|
||||||
help='Specify environment: local/sauce/api')
|
help='Specify environment: local/sauce/api')
|
||||||
|
parser.addoption('--platform_version',
|
||||||
|
action='store',
|
||||||
|
default='7.1',
|
||||||
|
help='Android device platform version')
|
||||||
parser.addoption('--log',
|
parser.addoption('--log',
|
||||||
action='store',
|
action='store',
|
||||||
default=False,
|
default=False,
|
||||||
@ -90,6 +96,45 @@ def pytest_addoption(parser):
|
|||||||
default=600,
|
default=600,
|
||||||
help='Running time in seconds')
|
help='Running time in seconds')
|
||||||
|
|
||||||
|
# running tests using appium docker instance
|
||||||
|
|
||||||
|
parser.addoption('--docker',
|
||||||
|
action='store',
|
||||||
|
default=False,
|
||||||
|
help='Are you using the appium docker container to run the tests?')
|
||||||
|
parser.addoption('--docker_shared_volume',
|
||||||
|
action='store',
|
||||||
|
default=None,
|
||||||
|
help='Path to a directory with .apk that will be shared with docker instance. Test reports will be also saved there')
|
||||||
|
parser.addoption('--device_ip',
|
||||||
|
action='store',
|
||||||
|
default=None,
|
||||||
|
help='Android device IP address used for battery tests')
|
||||||
|
parser.addoption('--bugreport',
|
||||||
|
action='store',
|
||||||
|
default=False,
|
||||||
|
help='Should generate bugreport for each test?')
|
||||||
|
parser.addoption('--stats_db_host',
|
||||||
|
action='store',
|
||||||
|
default=None,
|
||||||
|
help='Host address for device stats database')
|
||||||
|
parser.addoption('--stats_db_port',
|
||||||
|
action='store',
|
||||||
|
default=8086,
|
||||||
|
help='Port for device stats db')
|
||||||
|
parser.addoption('--stats_db_username',
|
||||||
|
action='store',
|
||||||
|
default=None,
|
||||||
|
help='Username for device stats db')
|
||||||
|
parser.addoption('--stats_db_password',
|
||||||
|
action='store',
|
||||||
|
default=None,
|
||||||
|
help='Password for device stats db')
|
||||||
|
parser.addoption('--stats_db_database',
|
||||||
|
action='store',
|
||||||
|
default='example9',
|
||||||
|
help='Database name for device stats db')
|
||||||
|
|
||||||
|
|
||||||
def is_master(config):
|
def is_master(config):
|
||||||
return not hasattr(config, 'slaveinput')
|
return not hasattr(config, 'slaveinput')
|
||||||
@ -160,6 +205,26 @@ def pytest_runtest_makereport(item, call):
|
|||||||
current_test.testruns[-1].error = error
|
current_test.testruns[-1].error = error
|
||||||
if is_sauce_env:
|
if is_sauce_env:
|
||||||
update_sauce_jobs(current_test.name, current_test.testruns[-1].jobs, report.passed)
|
update_sauce_jobs(current_test.name, current_test.testruns[-1].jobs, report.passed)
|
||||||
|
if pytest.config.getoption('docker'):
|
||||||
|
device_stats = appium_container.get_device_stats()
|
||||||
|
if pytest.config.getoption('bugreport'):
|
||||||
|
appium_container.generate_bugreport(item.name)
|
||||||
|
|
||||||
|
build_name = pytest.config.getoption('apk')
|
||||||
|
# Find type of tests that are run on the device
|
||||||
|
if 'battery_consumption' in item.keywords._markers:
|
||||||
|
test_group = 'battery_consumption'
|
||||||
|
else:
|
||||||
|
test_group = None
|
||||||
|
|
||||||
|
device_stats_db = DeviceStatsDB(
|
||||||
|
item.config.getoption('stats_db_host'),
|
||||||
|
item.config.getoption('stats_db_port'),
|
||||||
|
item.config.getoption('stats_db_username'),
|
||||||
|
item.config.getoption('stats_db_password'),
|
||||||
|
item.config.getoption('stats_db_database'),
|
||||||
|
)
|
||||||
|
device_stats_db.save_stats(build_name, item.name, test_group, not report.failed, device_stats)
|
||||||
|
|
||||||
|
|
||||||
def update_sauce_jobs(test_name, job_ids, passed):
|
def update_sauce_jobs(test_name, job_ids, passed):
|
||||||
|
@ -21,3 +21,5 @@ wallet_modal = pytest.mark.wallet_modal
|
|||||||
sign_in = pytest.mark.sign_in
|
sign_in = pytest.mark.sign_in
|
||||||
skip = pytest.mark.skip
|
skip = pytest.mark.skip
|
||||||
logcat = pytest.mark.logcat
|
logcat = pytest.mark.logcat
|
||||||
|
|
||||||
|
battery_consumption = pytest.mark.battery_consumption
|
||||||
|
Loading…
x
Reference in New Issue
Block a user