2017-08-28 10:02:20 +00:00
|
|
|
import pytest
|
|
|
|
import sys
|
2017-10-05 19:41:17 +00:00
|
|
|
import re
|
|
|
|
import subprocess
|
2018-01-26 11:07:09 +00:00
|
|
|
import asyncio
|
2018-03-31 20:05:11 +00:00
|
|
|
|
2018-06-01 12:46:54 +00:00
|
|
|
from support.message_reliability_report import create_one_to_one_chat_report, create_public_chat_report
|
2018-06-07 15:13:37 +00:00
|
|
|
from support.api.network_api import NetworkApi
|
2018-01-26 11:07:09 +00:00
|
|
|
from os import environ
|
|
|
|
from appium import webdriver
|
|
|
|
from abc import ABCMeta, abstractmethod
|
2018-03-15 20:01:08 +00:00
|
|
|
from selenium.common.exceptions import WebDriverException
|
2018-05-25 17:29:07 +00:00
|
|
|
from tests import test_suite_data, start_threads
|
2018-03-15 20:01:08 +00:00
|
|
|
from views.base_view import BaseView
|
2017-08-28 10:02:20 +00:00
|
|
|
|
|
|
|
|
|
|
|
class AbstractTestCase:
|
|
|
|
__metaclass__ = ABCMeta
|
|
|
|
|
|
|
|
@property
|
|
|
|
def sauce_username(self):
|
|
|
|
return environ.get('SAUCE_USERNAME')
|
|
|
|
|
2018-01-26 11:07:09 +00:00
|
|
|
@property
|
|
|
|
def sauce_access_key(self):
|
|
|
|
return environ.get('SAUCE_ACCESS_KEY')
|
|
|
|
|
2017-08-28 10:02:20 +00:00
|
|
|
@property
|
|
|
|
def executor_sauce_lab(self):
|
|
|
|
return 'http://%s:%s@ondemand.saucelabs.com:80/wd/hub' % (self.sauce_username, self.sauce_access_key)
|
|
|
|
|
|
|
|
@property
|
2017-10-05 19:41:17 +00:00
|
|
|
def executor_local(self):
|
|
|
|
return 'http://localhost:4723/wd/hub'
|
2017-08-28 10:02:20 +00:00
|
|
|
|
|
|
|
def print_sauce_lab_info(self, driver):
|
|
|
|
sys.stdout = sys.stderr
|
|
|
|
print("SauceOnDemandSessionID=%s job-name=%s" % (driver.session_id,
|
|
|
|
pytest.config.getoption('build')))
|
|
|
|
|
2017-10-05 19:41:17 +00:00
|
|
|
def add_local_devices_to_capabilities(self):
|
|
|
|
updated_capabilities = list()
|
|
|
|
raw_out = re.split(r'[\r\\n]+', str(subprocess.check_output(['adb', 'devices'])).rstrip())
|
|
|
|
for line in raw_out[1:]:
|
2018-04-26 06:22:11 +00:00
|
|
|
serial = re.findall(r"(([\d.\d:]*\d+)|\bemulator-\d+)", line)
|
2017-10-05 19:41:17 +00:00
|
|
|
if serial:
|
|
|
|
capabilities = self.capabilities_local
|
2018-04-26 06:22:11 +00:00
|
|
|
capabilities['udid'] = serial[0][0]
|
2017-10-05 19:41:17 +00:00
|
|
|
updated_capabilities.append(capabilities)
|
|
|
|
return updated_capabilities
|
|
|
|
|
2017-08-28 10:02:20 +00:00
|
|
|
@property
|
2017-10-05 19:41:17 +00:00
|
|
|
def capabilities_sauce_lab(self):
|
|
|
|
desired_caps = dict()
|
2018-02-26 23:38:56 +00:00
|
|
|
desired_caps['app'] = 'sauce-storage:' + test_suite_data.apk_name
|
2017-11-13 10:49:45 +00:00
|
|
|
|
2017-10-05 19:41:17 +00:00
|
|
|
desired_caps['build'] = pytest.config.getoption('build')
|
2018-02-26 23:38:56 +00:00
|
|
|
desired_caps['name'] = test_suite_data.current_test.name
|
2017-10-05 19:41:17 +00:00
|
|
|
desired_caps['platformName'] = 'Android'
|
2018-03-15 20:01:08 +00:00
|
|
|
desired_caps['appiumVersion'] = '1.7.2'
|
2018-03-28 10:21:39 +00:00
|
|
|
desired_caps['platformVersion'] = '7.1'
|
2017-10-05 19:41:17 +00:00
|
|
|
desired_caps['deviceName'] = 'Android GoogleAPI Emulator'
|
|
|
|
desired_caps['deviceOrientation'] = "portrait"
|
|
|
|
desired_caps['commandTimeout'] = 600
|
|
|
|
desired_caps['idleTimeout'] = 1000
|
2018-02-14 13:48:18 +00:00
|
|
|
desired_caps['unicodeKeyboard'] = True
|
2018-03-28 10:21:39 +00:00
|
|
|
desired_caps['automationName'] = 'UiAutomator2'
|
|
|
|
desired_caps['setWebContentDebuggingEnabled'] = True
|
|
|
|
desired_caps['ignoreUnimportantViews'] = False
|
2018-06-14 10:57:04 +00:00
|
|
|
desired_caps['enableNotificationListener'] = True
|
2017-10-05 19:41:17 +00:00
|
|
|
return desired_caps
|
2017-08-28 10:02:20 +00:00
|
|
|
|
2018-03-31 20:05:11 +00:00
|
|
|
def update_capabilities_sauce_lab(self, new_capabilities: dict):
|
2018-05-16 19:59:36 +00:00
|
|
|
caps = self.capabilities_sauce_lab.copy()
|
2018-03-31 20:05:11 +00:00
|
|
|
caps.update(new_capabilities)
|
2018-05-16 19:59:36 +00:00
|
|
|
return caps
|
|
|
|
|
2017-08-28 10:02:20 +00:00
|
|
|
@property
|
|
|
|
def capabilities_local(self):
|
|
|
|
desired_caps = dict()
|
2017-10-05 19:41:17 +00:00
|
|
|
desired_caps['app'] = pytest.config.getoption('apk')
|
2017-09-21 17:01:04 +00:00
|
|
|
desired_caps['deviceName'] = 'nexus_5'
|
2017-08-28 10:02:20 +00:00
|
|
|
desired_caps['platformName'] = 'Android'
|
2018-03-15 20:01:08 +00:00
|
|
|
desired_caps['appiumVersion'] = '1.7.2'
|
2018-03-28 10:21:39 +00:00
|
|
|
desired_caps['platformVersion'] = '7.1'
|
2017-10-11 20:10:57 +00:00
|
|
|
desired_caps['newCommandTimeout'] = 600
|
2018-02-19 11:51:53 +00:00
|
|
|
desired_caps['fullReset'] = False
|
2018-02-14 13:48:18 +00:00
|
|
|
desired_caps['unicodeKeyboard'] = True
|
2018-03-28 10:21:39 +00:00
|
|
|
desired_caps['automationName'] = 'UiAutomator2'
|
|
|
|
desired_caps['setWebContentDebuggingEnabled'] = True
|
2017-08-28 10:02:20 +00:00
|
|
|
return desired_caps
|
|
|
|
|
|
|
|
@abstractmethod
|
|
|
|
def setup_method(self, method):
|
|
|
|
raise NotImplementedError('Should be overridden from a child class')
|
|
|
|
|
|
|
|
@abstractmethod
|
|
|
|
def teardown_method(self, method):
|
|
|
|
raise NotImplementedError('Should be overridden from a child class')
|
|
|
|
|
2017-10-05 19:41:17 +00:00
|
|
|
@property
|
|
|
|
def environment(self):
|
|
|
|
return pytest.config.getoption('env')
|
2017-08-28 10:02:20 +00:00
|
|
|
|
2018-01-03 09:34:40 +00:00
|
|
|
@property
|
|
|
|
def implicitly_wait(self):
|
2018-02-09 15:16:07 +00:00
|
|
|
return 8
|
2018-01-03 09:34:40 +00:00
|
|
|
|
2018-02-14 13:48:18 +00:00
|
|
|
errors = []
|
|
|
|
|
2018-05-25 17:29:07 +00:00
|
|
|
network_api = NetworkApi()
|
|
|
|
|
2018-02-14 13:48:18 +00:00
|
|
|
def verify_no_errors(self):
|
|
|
|
if self.errors:
|
|
|
|
pytest.fail('. '.join([self.errors.pop(0) for _ in range(len(self.errors))]))
|
|
|
|
|
2018-01-26 11:07:09 +00:00
|
|
|
|
|
|
|
class SingleDeviceTestCase(AbstractTestCase):
|
|
|
|
|
|
|
|
def setup_method(self, method):
|
|
|
|
capabilities = {'local': {'executor': self.executor_local,
|
|
|
|
'capabilities': self.capabilities_local},
|
|
|
|
'sauce': {'executor': self.executor_sauce_lab,
|
|
|
|
'capabilities': self.capabilities_sauce_lab}}
|
2018-02-19 11:51:53 +00:00
|
|
|
counter = 0
|
|
|
|
self.driver = None
|
|
|
|
while not self.driver and counter <= 3:
|
|
|
|
try:
|
|
|
|
self.driver = webdriver.Remote(capabilities[self.environment]['executor'],
|
|
|
|
capabilities[self.environment]['capabilities'])
|
|
|
|
self.driver.implicitly_wait(self.implicitly_wait)
|
2018-03-15 20:01:08 +00:00
|
|
|
BaseView(self.driver).accept_agreements()
|
2018-04-28 09:02:39 +00:00
|
|
|
test_suite_data.current_test.testruns[-1].jobs.append(self.driver.session_id)
|
2018-02-19 11:51:53 +00:00
|
|
|
break
|
|
|
|
except WebDriverException:
|
|
|
|
counter += 1
|
2018-01-26 11:07:09 +00:00
|
|
|
|
|
|
|
def teardown_method(self, method):
|
|
|
|
if self.environment == 'sauce':
|
|
|
|
self.print_sauce_lab_info(self.driver)
|
|
|
|
try:
|
|
|
|
self.driver.quit()
|
2018-02-19 11:51:53 +00:00
|
|
|
except (WebDriverException, AttributeError):
|
2018-01-26 11:07:09 +00:00
|
|
|
pass
|
|
|
|
|
2017-10-05 19:41:17 +00:00
|
|
|
|
2018-01-03 09:34:40 +00:00
|
|
|
class LocalMultipleDeviceTestCase(AbstractTestCase):
|
2017-08-28 10:02:20 +00:00
|
|
|
|
|
|
|
def setup_method(self, method):
|
2018-01-26 11:07:09 +00:00
|
|
|
self.drivers = dict()
|
|
|
|
|
|
|
|
def create_drivers(self, quantity):
|
2017-10-05 19:41:17 +00:00
|
|
|
capabilities = self.add_local_devices_to_capabilities()
|
2018-01-26 11:07:09 +00:00
|
|
|
for driver in range(quantity):
|
|
|
|
self.drivers[driver] = webdriver.Remote(self.executor_local, capabilities[driver])
|
|
|
|
self.drivers[driver].implicitly_wait(self.implicitly_wait)
|
2018-03-15 20:01:08 +00:00
|
|
|
BaseView(self.drivers[driver]).accept_agreements()
|
2018-04-28 09:02:39 +00:00
|
|
|
test_suite_data.current_test.testruns[-1].jobs.append(self.drivers[driver].session_id)
|
2017-08-28 10:02:20 +00:00
|
|
|
|
|
|
|
def teardown_method(self, method):
|
2018-01-26 11:07:09 +00:00
|
|
|
for driver in self.drivers:
|
2017-10-05 19:41:17 +00:00
|
|
|
try:
|
2018-01-26 11:07:09 +00:00
|
|
|
self.drivers[driver].quit()
|
2017-10-05 19:41:17 +00:00
|
|
|
except WebDriverException:
|
|
|
|
pass
|
2017-08-28 10:02:20 +00:00
|
|
|
|
|
|
|
|
2018-01-03 09:34:40 +00:00
|
|
|
class SauceMultipleDeviceTestCase(AbstractTestCase):
|
2017-08-28 10:02:20 +00:00
|
|
|
|
2017-09-13 14:34:42 +00:00
|
|
|
@classmethod
|
|
|
|
def setup_class(cls):
|
2018-02-09 15:16:07 +00:00
|
|
|
cls.loop = asyncio.new_event_loop()
|
|
|
|
asyncio.set_event_loop(cls.loop)
|
2017-09-13 14:34:42 +00:00
|
|
|
|
2017-08-28 10:02:20 +00:00
|
|
|
def setup_method(self, method):
|
2018-01-26 11:07:09 +00:00
|
|
|
self.drivers = dict()
|
|
|
|
|
2018-03-31 20:05:11 +00:00
|
|
|
def create_drivers(self, quantity=2, max_duration=1800, custom_implicitly_wait=None, offline_mode=False):
|
|
|
|
capabilities = {'maxDuration': max_duration}
|
|
|
|
if offline_mode:
|
|
|
|
capabilities['platformVersion'] = '6.0'
|
|
|
|
self.drivers = self.loop.run_until_complete(start_threads(quantity,
|
|
|
|
webdriver.Remote,
|
|
|
|
self.drivers,
|
|
|
|
self.executor_sauce_lab,
|
|
|
|
self.update_capabilities_sauce_lab(capabilities)))
|
2018-01-26 11:07:09 +00:00
|
|
|
for driver in range(quantity):
|
2018-03-31 20:05:11 +00:00
|
|
|
self.drivers[driver].implicitly_wait(
|
|
|
|
custom_implicitly_wait if custom_implicitly_wait else self.implicitly_wait)
|
2018-03-15 20:01:08 +00:00
|
|
|
BaseView(self.drivers[driver]).accept_agreements()
|
2018-04-28 09:02:39 +00:00
|
|
|
test_suite_data.current_test.testruns[-1].jobs.append(self.drivers[driver].session_id)
|
2017-08-28 10:02:20 +00:00
|
|
|
|
|
|
|
def teardown_method(self, method):
|
2018-01-26 11:07:09 +00:00
|
|
|
for driver in self.drivers:
|
2017-10-05 19:41:17 +00:00
|
|
|
try:
|
2018-02-19 11:51:53 +00:00
|
|
|
self.print_sauce_lab_info(self.drivers[driver])
|
2018-01-26 11:07:09 +00:00
|
|
|
self.drivers[driver].quit()
|
2018-02-19 11:51:53 +00:00
|
|
|
except (WebDriverException, AttributeError):
|
2017-10-05 19:41:17 +00:00
|
|
|
pass
|
2017-09-13 14:34:42 +00:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def teardown_class(cls):
|
|
|
|
cls.loop.close()
|
2017-10-05 19:41:17 +00:00
|
|
|
|
|
|
|
|
2018-06-07 15:13:37 +00:00
|
|
|
environment = LocalMultipleDeviceTestCase if pytest.config.getoption('env') == 'local' else SauceMultipleDeviceTestCase
|
2017-10-05 19:41:17 +00:00
|
|
|
|
|
|
|
|
2018-06-07 15:13:37 +00:00
|
|
|
class MultipleDeviceTestCase(environment):
|
2017-10-05 19:41:17 +00:00
|
|
|
|
2018-04-26 06:22:11 +00:00
|
|
|
def setup_method(self, method):
|
|
|
|
super(MultipleDeviceTestCase, self).setup_method(method)
|
|
|
|
self.senders = dict()
|
|
|
|
|
|
|
|
def teardown_method(self, method):
|
|
|
|
for user in self.senders:
|
2018-05-25 17:29:07 +00:00
|
|
|
self.network_api.faucet(address=self.senders[user]['address'])
|
2018-04-26 06:22:11 +00:00
|
|
|
super(MultipleDeviceTestCase, self).teardown_method(method)
|
|
|
|
|
2018-03-31 20:05:11 +00:00
|
|
|
|
|
|
|
class MessageReliabilityTestCase(MultipleDeviceTestCase):
|
|
|
|
|
|
|
|
def setup_method(self, method):
|
|
|
|
super(MessageReliabilityTestCase, self).setup_method(method)
|
|
|
|
self.one_to_one_chat_data = dict()
|
|
|
|
self.public_chat_data = dict()
|
|
|
|
|
|
|
|
def teardown_method(self, method):
|
|
|
|
if self.one_to_one_chat_data:
|
2018-06-01 12:46:54 +00:00
|
|
|
create_one_to_one_chat_report(self.one_to_one_chat_data)
|
2018-03-31 20:05:11 +00:00
|
|
|
if self.public_chat_data:
|
2018-06-01 12:46:54 +00:00
|
|
|
create_public_chat_report(self.public_chat_data)
|
|
|
|
super(MultipleDeviceTestCase, self).teardown_method(method)
|