2018-11-03 19:33:19 +03:00
|
|
|
#!/usr/bin/python3
|
2019-06-05 22:57:55 +03:00
|
|
|
#
|
|
|
|
# Copyright 2019 Daniel Silverstone <dsilvers@digital-scurf.org>
|
|
|
|
#
|
|
|
|
# This file is part of NetSurf, http://www.netsurf-browser.org/
|
|
|
|
#
|
|
|
|
# NetSurf is free software; you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation; version 2 of the License.
|
|
|
|
#
|
|
|
|
# NetSurf is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
"""
|
|
|
|
runs tests in monkey as defined in a yaml file
|
|
|
|
"""
|
2018-11-03 19:33:19 +03:00
|
|
|
|
2019-07-05 00:44:58 +03:00
|
|
|
# pylint: disable=locally-disabled, missing-docstring
|
|
|
|
|
2020-03-19 23:57:37 +03:00
|
|
|
import os
|
2019-07-05 00:44:58 +03:00
|
|
|
import sys
|
|
|
|
import getopt
|
|
|
|
import time
|
|
|
|
import yaml
|
2018-11-03 19:33:19 +03:00
|
|
|
|
2018-11-03 20:14:43 +03:00
|
|
|
from monkeyfarmer import Browser
|
|
|
|
|
2019-07-05 00:44:58 +03:00
|
|
|
|
2019-02-16 13:56:28 +03:00
|
|
|
class DriverBrowser(Browser):
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
super(DriverBrowser, self).__init__(*args, **kwargs)
|
|
|
|
self.auth = []
|
|
|
|
|
|
|
|
def add_auth(self, url, realm, username, password):
|
|
|
|
self.auth.append((url, realm, username, password))
|
|
|
|
|
|
|
|
def remove_auth(self, url, realm, username, password):
|
|
|
|
keep = []
|
2019-07-05 00:44:58 +03:00
|
|
|
|
|
|
|
def matches(first, second):
|
|
|
|
if first is None or second is None:
|
2019-02-16 13:56:28 +03:00
|
|
|
return True
|
2019-07-05 00:44:58 +03:00
|
|
|
return first == second
|
|
|
|
|
2019-02-16 13:56:28 +03:00
|
|
|
for (iurl, irealm, iusername, ipassword) in self.auth:
|
|
|
|
if not (matches(url, iurl) or
|
|
|
|
matches(realm, irealm) or
|
|
|
|
matches(username, iusername) or
|
|
|
|
matches(password, ipassword)):
|
|
|
|
keep.append((iurl, irealm, iusername, ipassword))
|
|
|
|
self.auth = keep
|
|
|
|
|
|
|
|
def handle_ready_login(self, logwin):
|
|
|
|
# We have logwin.{url,username,password,realm}
|
|
|
|
# We must logwin.send_{username,password}(xxx)
|
|
|
|
# We may logwin.go()
|
|
|
|
# We may logwin.destroy()
|
2019-07-05 00:44:58 +03:00
|
|
|
def matches(first, second):
|
|
|
|
if first is None or second is None:
|
2019-02-16 13:56:28 +03:00
|
|
|
return True
|
2019-07-05 00:44:58 +03:00
|
|
|
return first == second
|
2019-02-16 13:56:28 +03:00
|
|
|
candidates = []
|
|
|
|
for (url, realm, username, password) in self.auth:
|
|
|
|
score = 0
|
|
|
|
if matches(url, logwin.url):
|
|
|
|
score += 1
|
|
|
|
if matches(realm, logwin.realm):
|
|
|
|
score += 1
|
|
|
|
if matches(username, logwin.username):
|
|
|
|
score += 1
|
|
|
|
if score > 0:
|
|
|
|
candidates.append((score, username, password))
|
|
|
|
if candidates:
|
|
|
|
candidates.sort()
|
|
|
|
(score, username, password) = candidates[-1]
|
|
|
|
print("401: Found candidate {}/{} with score {}".format(username, password, score))
|
|
|
|
logwin.send_username(username)
|
|
|
|
logwin.send_password(password)
|
|
|
|
logwin.go()
|
|
|
|
else:
|
|
|
|
print("401: No candidate found, cancelling login box")
|
|
|
|
logwin.destroy()
|
|
|
|
|
2019-07-05 00:44:58 +03:00
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
def print_usage():
|
|
|
|
print('Usage:')
|
2019-07-05 00:44:58 +03:00
|
|
|
print(' ' + sys.argv[0] + ' -m <path to monkey> -t <path to test> [-w <wrapper arguments>]')
|
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
|
|
|
|
def parse_argv(argv):
|
2019-07-05 00:44:58 +03:00
|
|
|
|
|
|
|
# pylint: disable=locally-disabled, unused-variable
|
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
path_monkey = ''
|
|
|
|
path_test = ''
|
2019-06-15 22:01:08 +03:00
|
|
|
wrapper = None
|
2018-11-03 19:33:19 +03:00
|
|
|
try:
|
2019-07-05 00:44:58 +03:00
|
|
|
opts, args = getopt.getopt(argv, "hm:t:w:", ["monkey=", "test=", "wrapper="])
|
2018-11-03 19:33:19 +03:00
|
|
|
except getopt.GetoptError:
|
|
|
|
print_usage()
|
|
|
|
sys.exit(2)
|
|
|
|
for opt, arg in opts:
|
|
|
|
if opt == '-h':
|
|
|
|
print_usage()
|
|
|
|
sys.exit()
|
|
|
|
elif opt in ("-m", "--monkey"):
|
|
|
|
path_monkey = arg
|
|
|
|
elif opt in ("-t", "--test"):
|
|
|
|
path_test = arg
|
2019-06-15 22:01:08 +03:00
|
|
|
elif opt in ("-w", "--wrapper"):
|
|
|
|
if wrapper is None:
|
|
|
|
wrapper = []
|
|
|
|
wrapper.extend(arg.split())
|
2018-11-03 19:33:19 +03:00
|
|
|
|
|
|
|
if path_monkey == '':
|
|
|
|
print_usage()
|
|
|
|
sys.exit()
|
|
|
|
if path_test == '':
|
|
|
|
print_usage()
|
|
|
|
sys.exit()
|
|
|
|
|
2019-06-15 22:01:08 +03:00
|
|
|
return path_monkey, path_test, wrapper
|
2018-11-03 19:33:19 +03:00
|
|
|
|
2019-07-05 00:44:58 +03:00
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
def load_test_plan(path):
|
2019-07-05 00:44:58 +03:00
|
|
|
|
|
|
|
# pylint: disable=locally-disabled, broad-except
|
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
plan = []
|
|
|
|
with open(path, 'r') as stream:
|
|
|
|
try:
|
2019-11-30 18:40:37 +03:00
|
|
|
plan = (yaml.load(stream, Loader=yaml.CSafeLoader))
|
2019-07-05 00:44:58 +03:00
|
|
|
except Exception as exc:
|
|
|
|
print(exc)
|
2018-11-03 19:33:19 +03:00
|
|
|
return plan
|
|
|
|
|
2019-07-05 00:44:58 +03:00
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
def get_indent(ctx):
|
2019-07-05 00:44:58 +03:00
|
|
|
return ' ' * ctx["depth"]
|
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
|
|
|
|
def print_test_plan_info(ctx, plan):
|
2019-07-05 00:44:58 +03:00
|
|
|
|
|
|
|
# pylint: disable=locally-disabled, unused-argument
|
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
print('Running test: [' + plan["group"] + '] ' + plan["title"])
|
|
|
|
|
2019-07-05 00:44:58 +03:00
|
|
|
|
2018-11-03 20:14:43 +03:00
|
|
|
def assert_browser(ctx):
|
2019-07-05 00:44:58 +03:00
|
|
|
assert ctx['browser'].started
|
|
|
|
assert not ctx['browser'].stopped
|
|
|
|
|
2018-11-04 16:13:23 +03:00
|
|
|
|
|
|
|
def conds_met(ctx, conds):
|
2019-05-20 12:07:53 +03:00
|
|
|
# for each condition listed determine if they have been met
|
|
|
|
# efectively this is condition1 | condition2
|
2018-11-04 16:13:23 +03:00
|
|
|
for cond in conds:
|
2019-05-20 12:07:53 +03:00
|
|
|
if 'timer' in cond.keys():
|
|
|
|
timer = cond['timer']
|
|
|
|
elapsed = cond['elapsed']
|
|
|
|
assert_browser(ctx)
|
2019-07-05 00:44:58 +03:00
|
|
|
assert ctx['timers'].get(timer) is not None
|
2019-05-20 12:07:53 +03:00
|
|
|
taken = time.time() - ctx['timers'][timer]["start"]
|
2019-07-05 00:44:58 +03:00
|
|
|
if taken >= elapsed:
|
2019-05-20 12:07:53 +03:00
|
|
|
return True
|
|
|
|
elif 'window' in cond.keys():
|
2019-05-19 01:45:52 +03:00
|
|
|
status = cond['status']
|
|
|
|
window = cond['window']
|
2020-05-22 11:15:27 +03:00
|
|
|
assert status == "complete" or status == "loading" # TODO: Add more status support?
|
2019-05-19 01:45:52 +03:00
|
|
|
if window == "*all*":
|
2020-05-23 21:50:29 +03:00
|
|
|
# all windows must be complete, or any still loading
|
2019-05-20 12:07:53 +03:00
|
|
|
throbbing = False
|
2019-05-19 01:45:52 +03:00
|
|
|
for win in ctx['windows'].items():
|
|
|
|
if win[1].throbbing:
|
2019-05-20 12:07:53 +03:00
|
|
|
throbbing = True
|
2020-05-22 11:15:27 +03:00
|
|
|
# throbbing and want loading => true
|
|
|
|
# not throbbing and want complete => true
|
2020-05-23 21:50:29 +03:00
|
|
|
if (status == "loading") == throbbing:
|
|
|
|
return True
|
2019-05-19 01:45:52 +03:00
|
|
|
else:
|
|
|
|
win = ctx['windows'][window]
|
2020-05-23 21:50:29 +03:00
|
|
|
if win.throbbing == (status == "loading"):
|
|
|
|
return True
|
2018-11-04 16:13:23 +03:00
|
|
|
else:
|
2019-05-19 01:45:52 +03:00
|
|
|
raise AssertionError("Unknown condition: {}".format(repr(cond)))
|
|
|
|
|
2019-05-20 12:07:53 +03:00
|
|
|
return False
|
2018-11-04 16:13:23 +03:00
|
|
|
|
2019-07-05 00:44:58 +03:00
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
def run_test_step_action_launch(ctx, step):
|
|
|
|
print(get_indent(ctx) + "Action: " + step["action"])
|
2020-03-19 23:57:37 +03:00
|
|
|
|
|
|
|
# ensure browser is not already launched
|
2019-07-05 00:44:58 +03:00
|
|
|
assert ctx.get('browser') is None
|
|
|
|
assert ctx.get('windows') is None
|
2020-03-19 23:57:37 +03:00
|
|
|
|
|
|
|
# build command line switches list
|
2020-02-24 18:35:56 +03:00
|
|
|
monkey_cmd = [ctx["monkey"]]
|
|
|
|
for option in step.get('launch-options', []):
|
|
|
|
monkey_cmd.append("--{}".format(option))
|
|
|
|
print(get_indent(ctx) + " " + "Command line: " + repr(monkey_cmd))
|
2020-03-19 23:57:37 +03:00
|
|
|
|
|
|
|
# build command environment
|
|
|
|
monkey_env = os.environ.copy()
|
|
|
|
for envkey, envvalue in step.get('environment', {}).items():
|
|
|
|
monkey_env[envkey] = envvalue
|
|
|
|
print(get_indent(ctx) + " " + envkey + "=" + envvalue)
|
|
|
|
if 'language' in step.keys():
|
|
|
|
monkey_env['LANGUAGE'] = step['language']
|
|
|
|
|
|
|
|
# create browser object
|
2019-07-05 00:44:58 +03:00
|
|
|
ctx['browser'] = DriverBrowser(
|
2020-02-24 18:35:56 +03:00
|
|
|
monkey_cmd=monkey_cmd,
|
2020-03-19 23:57:37 +03:00
|
|
|
monkey_env=monkey_env,
|
2021-02-08 11:44:54 +03:00
|
|
|
quiet=True,
|
2019-07-05 00:44:58 +03:00
|
|
|
wrapper=ctx.get("wrapper"))
|
2018-11-03 20:14:43 +03:00
|
|
|
assert_browser(ctx)
|
|
|
|
ctx['windows'] = dict()
|
2020-03-19 23:57:37 +03:00
|
|
|
|
|
|
|
# set user options
|
2019-07-02 01:27:45 +03:00
|
|
|
for option in step.get('options', []):
|
|
|
|
print(get_indent(ctx) + " " + option)
|
|
|
|
ctx['browser'].pass_options(option)
|
2019-05-06 13:00:39 +03:00
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
|
|
|
|
def run_test_step_action_window_new(ctx, step):
|
2019-07-05 00:44:58 +03:00
|
|
|
|
|
|
|
# pylint: disable=locally-disabled, invalid-name
|
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
print(get_indent(ctx) + "Action: " + step["action"])
|
2018-11-03 20:14:43 +03:00
|
|
|
tag = step['tag']
|
|
|
|
assert_browser(ctx)
|
2019-07-05 00:44:58 +03:00
|
|
|
assert ctx['windows'].get(tag) is None
|
2018-11-03 20:14:43 +03:00
|
|
|
ctx['windows'][tag] = ctx['browser'].new_window(url=step.get('url'))
|
2018-11-03 19:33:19 +03:00
|
|
|
|
2019-07-05 00:44:58 +03:00
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
def run_test_step_action_window_close(ctx, step):
|
2019-07-05 00:44:58 +03:00
|
|
|
|
|
|
|
# pylint: disable=locally-disabled, invalid-name
|
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
print(get_indent(ctx) + "Action: " + step["action"])
|
2018-11-03 20:14:43 +03:00
|
|
|
assert_browser(ctx)
|
|
|
|
tag = step['window']
|
2019-07-05 00:44:58 +03:00
|
|
|
assert ctx['windows'].get(tag) is not None
|
2018-11-03 20:14:43 +03:00
|
|
|
win = ctx['windows'].pop(tag)
|
2020-02-22 20:51:07 +03:00
|
|
|
timeout = int(step.get('timeout', 30))
|
2018-11-03 20:14:43 +03:00
|
|
|
win.kill()
|
2019-09-07 16:53:18 +03:00
|
|
|
win.wait_until_dead(timeout=timeout)
|
2019-07-05 00:44:58 +03:00
|
|
|
assert not win.alive
|
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
|
|
|
|
def run_test_step_action_navigate(ctx, step):
|
|
|
|
print(get_indent(ctx) + "Action: " + step["action"])
|
2018-11-03 20:14:43 +03:00
|
|
|
assert_browser(ctx)
|
2019-06-13 01:55:54 +03:00
|
|
|
if 'url' in step.keys():
|
|
|
|
url = step['url']
|
|
|
|
elif 'repeaturl' in step.keys():
|
|
|
|
repeat = ctx['repeats'].get(step['repeaturl'])
|
2019-07-05 00:44:58 +03:00
|
|
|
assert repeat is not None
|
|
|
|
assert repeat.get('values') is not None
|
2019-06-13 01:55:54 +03:00
|
|
|
url = repeat['values'][repeat['i']]
|
|
|
|
else:
|
|
|
|
url = None
|
2019-07-05 00:44:58 +03:00
|
|
|
assert url is not None
|
2018-11-03 20:14:43 +03:00
|
|
|
tag = step['window']
|
2019-06-13 01:55:54 +03:00
|
|
|
print(get_indent(ctx) + " " + tag + " --> " + url)
|
2018-11-03 20:14:43 +03:00
|
|
|
win = ctx['windows'].get(tag)
|
2019-07-05 00:44:58 +03:00
|
|
|
assert win is not None
|
2019-06-13 01:55:54 +03:00
|
|
|
win.go(url)
|
2018-11-03 19:33:19 +03:00
|
|
|
|
2019-07-05 00:44:58 +03:00
|
|
|
|
2019-06-06 19:16:23 +03:00
|
|
|
def run_test_step_action_stop(ctx, step):
|
|
|
|
print(get_indent(ctx) + "Action: " + step["action"])
|
|
|
|
assert_browser(ctx)
|
|
|
|
tag = step['window']
|
|
|
|
win = ctx['windows'].get(tag)
|
2019-07-05 00:44:58 +03:00
|
|
|
assert win is not None
|
2019-06-06 19:16:23 +03:00
|
|
|
win.stop()
|
|
|
|
|
2019-07-05 00:44:58 +03:00
|
|
|
|
2019-08-02 14:24:14 +03:00
|
|
|
def run_test_step_action_reload(ctx, step):
|
|
|
|
print(get_indent(ctx) + "Action: " + step["action"])
|
|
|
|
assert_browser(ctx)
|
|
|
|
tag = step['window']
|
|
|
|
win = ctx['windows'].get(tag)
|
|
|
|
assert win is not None
|
|
|
|
win.reload()
|
|
|
|
|
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
def run_test_step_action_sleep_ms(ctx, step):
|
|
|
|
print(get_indent(ctx) + "Action: " + step["action"])
|
2020-03-22 16:09:45 +03:00
|
|
|
conds = step.get('conditions', {})
|
2018-11-04 17:34:31 +03:00
|
|
|
sleep_time = step['time']
|
|
|
|
sleep = 0
|
|
|
|
have_repeat = False
|
|
|
|
if isinstance(sleep_time, str):
|
2019-07-05 00:44:58 +03:00
|
|
|
assert ctx['repeats'].get(sleep_time) is not None
|
2018-11-04 17:34:31 +03:00
|
|
|
repeat = ctx['repeats'].get(sleep_time)
|
|
|
|
sleep = repeat["i"] / 1000
|
|
|
|
start = repeat["start"]
|
|
|
|
have_repeat = True
|
|
|
|
else:
|
2019-08-03 19:28:35 +03:00
|
|
|
sleep = sleep_time / 1000
|
2018-11-04 17:34:31 +03:00
|
|
|
start = time.time()
|
|
|
|
|
|
|
|
while True:
|
|
|
|
slept = time.time() - start
|
|
|
|
if conds_met(ctx, conds):
|
|
|
|
if have_repeat:
|
|
|
|
ctx['repeats'][sleep_time]["loop"] = False
|
|
|
|
print(get_indent(ctx) + " Condition met after {}s".format(slept))
|
|
|
|
break
|
|
|
|
elif slept > sleep:
|
|
|
|
print(get_indent(ctx) + " Condition not met after {}s".format(sleep))
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
ctx['browser'].farmer.loop(once=True)
|
2018-11-03 19:33:19 +03:00
|
|
|
|
2019-07-05 00:44:58 +03:00
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
def run_test_step_action_block(ctx, step):
|
|
|
|
print(get_indent(ctx) + "Action: " + step["action"])
|
2018-11-03 20:14:43 +03:00
|
|
|
conds = step['conditions']
|
|
|
|
assert_browser(ctx)
|
2019-07-05 00:44:58 +03:00
|
|
|
|
2018-11-04 16:13:23 +03:00
|
|
|
while not conds_met(ctx, conds):
|
2018-11-03 20:14:43 +03:00
|
|
|
ctx['browser'].farmer.loop(once=True)
|
2018-11-03 19:33:19 +03:00
|
|
|
|
2019-07-05 00:44:58 +03:00
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
def run_test_step_action_repeat(ctx, step):
|
|
|
|
print(get_indent(ctx) + "Action: " + step["action"])
|
2018-11-04 17:34:31 +03:00
|
|
|
tag = step['tag']
|
2019-07-05 00:44:58 +03:00
|
|
|
assert ctx['repeats'].get(tag) is None
|
2020-03-23 01:45:19 +03:00
|
|
|
# initialise the loop continue conditional
|
2019-07-05 00:44:58 +03:00
|
|
|
ctx['repeats'][tag] = {"loop": True, }
|
2019-06-13 01:55:54 +03:00
|
|
|
|
|
|
|
if 'values' in step.keys():
|
2020-03-23 01:45:19 +03:00
|
|
|
# value iterator
|
2019-06-13 01:55:54 +03:00
|
|
|
ctx['repeats'][tag]['values'] = step["values"]
|
2020-03-23 01:45:19 +03:00
|
|
|
ctx['repeats'][tag]["max"] = len(step["values"])
|
|
|
|
ctx['repeats'][tag]["i"] = 0
|
|
|
|
ctx['repeats'][tag]["step"] = 1
|
2019-06-13 01:55:54 +03:00
|
|
|
else:
|
2020-03-23 01:45:19 +03:00
|
|
|
# numeric iterator
|
2019-06-13 01:55:54 +03:00
|
|
|
ctx['repeats'][tag]['values'] = None
|
|
|
|
|
2020-03-23 01:45:19 +03:00
|
|
|
if 'min' in step.keys():
|
|
|
|
ctx['repeats'][tag]["i"] = step["min"]
|
|
|
|
else:
|
|
|
|
ctx['repeats'][tag]["i"] = 0
|
|
|
|
|
|
|
|
if 'step' in step.keys():
|
|
|
|
ctx['repeats'][tag]["step"] = step["step"]
|
|
|
|
else:
|
|
|
|
ctx['repeats'][tag]["step"] = 1
|
|
|
|
|
|
|
|
if 'max' in step.keys():
|
|
|
|
ctx['repeats'][tag]["max"] = step["max"]
|
|
|
|
else:
|
|
|
|
ctx['repeats'][tag]["max"] = None
|
|
|
|
|
2018-11-04 17:34:31 +03:00
|
|
|
while ctx['repeats'][tag]["loop"]:
|
|
|
|
ctx['repeats'][tag]["start"] = time.time()
|
|
|
|
ctx["depth"] += 1
|
2020-03-23 01:45:19 +03:00
|
|
|
|
|
|
|
# run through steps for this iteration
|
2019-07-05 00:44:58 +03:00
|
|
|
for stp in step["steps"]:
|
|
|
|
run_test_step(ctx, stp)
|
2020-03-23 01:45:19 +03:00
|
|
|
|
|
|
|
# increment iterator
|
2018-11-04 17:34:31 +03:00
|
|
|
ctx['repeats'][tag]["i"] += ctx['repeats'][tag]["step"]
|
2020-03-23 01:45:19 +03:00
|
|
|
|
|
|
|
# check for end condition
|
|
|
|
if ctx['repeats'][tag]["max"] is not None:
|
|
|
|
if ctx['repeats'][tag]["i"] >= ctx['repeats'][tag]["max"]:
|
2019-06-13 01:55:54 +03:00
|
|
|
ctx['repeats'][tag]["loop"] = False
|
2020-03-23 01:45:19 +03:00
|
|
|
|
2018-11-04 17:34:31 +03:00
|
|
|
ctx["depth"] -= 1
|
2018-11-03 19:33:19 +03:00
|
|
|
|
2019-07-05 00:44:58 +03:00
|
|
|
|
2019-08-03 14:31:43 +03:00
|
|
|
def run_test_step_action_click(ctx, step):
|
|
|
|
print(get_indent(ctx) + "Action: " + step["action"])
|
|
|
|
assert_browser(ctx)
|
|
|
|
win = ctx['windows'][step['window']]
|
|
|
|
targets = step['target']
|
|
|
|
if type(targets) == dict:
|
|
|
|
targets = [targets]
|
|
|
|
button = step.get('button', 'left').upper()
|
|
|
|
kind = step.get('kind', 'single').upper()
|
|
|
|
all_text_list = []
|
|
|
|
bitmaps = []
|
|
|
|
for plot in win.redraw():
|
|
|
|
if plot[0] == 'TEXT':
|
|
|
|
all_text_list.append((int(plot[2]), int(plot[4]), " ".join(plot[6:])))
|
|
|
|
if plot[0] == 'BITMAP':
|
|
|
|
bitmaps.append((int(plot[2]), int(plot[4]), int(plot[6]), int(plot[8])))
|
|
|
|
|
|
|
|
x = None
|
|
|
|
y = None
|
|
|
|
|
|
|
|
for target in targets:
|
|
|
|
if 'bitmap' in target:
|
|
|
|
if x is not None:
|
|
|
|
assert False, "Found more than one thing to click on, oh well"
|
|
|
|
bmap = int(target['bitmap'])
|
|
|
|
assert bmap < 0 or bmap >= len(bitmaps)
|
|
|
|
x = bitmaps[bmap][0] + bitmaps[bmap][2] / 2
|
|
|
|
y = bitmaps[bmap][1] + bitmaps[bmap][3] / 2
|
|
|
|
elif 'text' in target:
|
|
|
|
if x is not None:
|
|
|
|
assert False, "Found more than one thing to click on, oh well"
|
|
|
|
text = target['text']
|
|
|
|
for textentry in all_text_list:
|
|
|
|
if text in textentry[2]:
|
|
|
|
if x is not None:
|
|
|
|
assert False, "Text {} found more than once".format(text)
|
|
|
|
x = textentry[0] + 2
|
|
|
|
y = textentry[1] + 2
|
|
|
|
|
|
|
|
# Now we want to click on the x/y coordinate given
|
|
|
|
print(get_indent(ctx) + " Clicking at {}, {} (button={} kind={})".format(x, y, button, kind))
|
|
|
|
win.click(x, y, button, kind)
|
|
|
|
|
|
|
|
|
|
|
|
def run_test_step_action_wait_loading(ctx, step):
|
|
|
|
print(get_indent(ctx) + "Action: " + step["action"])
|
|
|
|
assert_browser(ctx)
|
|
|
|
win = ctx['windows'][step['window']]
|
|
|
|
win.wait_start_loading()
|
|
|
|
|
2018-11-03 20:14:43 +03:00
|
|
|
def run_test_step_action_plot_check(ctx, step):
|
|
|
|
print(get_indent(ctx) + "Action: " + step["action"])
|
|
|
|
assert_browser(ctx)
|
|
|
|
win = ctx['windows'][step['window']]
|
2021-02-08 01:57:27 +03:00
|
|
|
|
|
|
|
if 'area' in step.keys():
|
|
|
|
if step["area"] == "extent":
|
|
|
|
# ought to capture the extent updates and use that, instead use a
|
|
|
|
# big area and have the browser clip it
|
|
|
|
area=["0","0","1000","1000000"]
|
|
|
|
else:
|
|
|
|
area = [step["area"]]
|
|
|
|
else:
|
|
|
|
area = None
|
|
|
|
|
|
|
|
# get the list of checks
|
2019-06-13 00:45:07 +03:00
|
|
|
if 'checks' in step.keys():
|
|
|
|
checks = step['checks']
|
|
|
|
else:
|
|
|
|
checks = {}
|
2021-02-08 01:57:27 +03:00
|
|
|
|
2019-07-05 00:44:58 +03:00
|
|
|
all_text_list = []
|
2018-11-03 20:14:43 +03:00
|
|
|
bitmaps = []
|
2021-02-08 01:57:27 +03:00
|
|
|
for plot in win.redraw(coords=area):
|
2018-11-03 20:14:43 +03:00
|
|
|
if plot[0] == 'TEXT':
|
2019-07-05 00:44:58 +03:00
|
|
|
all_text_list.extend(plot[6:])
|
2018-11-03 20:14:43 +03:00
|
|
|
if plot[0] == 'BITMAP':
|
|
|
|
bitmaps.append(plot[1:])
|
2019-07-05 00:44:58 +03:00
|
|
|
all_text = " ".join(all_text_list)
|
2019-06-13 00:45:07 +03:00
|
|
|
for check in checks:
|
|
|
|
if 'text-contains' in check.keys():
|
2019-08-03 14:31:43 +03:00
|
|
|
print(" Check {} in {}".format(repr(check['text-contains']), repr(all_text)))
|
2019-07-05 00:44:58 +03:00
|
|
|
assert check['text-contains'] in all_text
|
2019-06-13 00:45:07 +03:00
|
|
|
elif 'text-not-contains' in check.keys():
|
2019-08-03 14:31:43 +03:00
|
|
|
print(" Check {} NOT in {}".format(repr(check['text-not-contains']), repr(all_text)))
|
2019-07-05 00:44:58 +03:00
|
|
|
assert check['text-not-contains'] not in all_text
|
2019-06-13 00:45:07 +03:00
|
|
|
elif 'bitmap-count' in check.keys():
|
2019-08-03 14:31:43 +03:00
|
|
|
print(" Check bitmap count is {}".format(int(check['bitmap-count'])))
|
2019-07-05 00:44:58 +03:00
|
|
|
assert len(bitmaps) == int(check['bitmap-count'])
|
2019-06-13 00:45:07 +03:00
|
|
|
else:
|
|
|
|
raise AssertionError("Unknown check: {}".format(repr(check)))
|
2018-11-03 20:14:43 +03:00
|
|
|
|
2019-07-05 00:44:58 +03:00
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
def run_test_step_action_timer_start(ctx, step):
|
2019-07-05 00:44:58 +03:00
|
|
|
|
|
|
|
# pylint: disable=locally-disabled, invalid-name
|
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
print(get_indent(ctx) + "Action: " + step["action"])
|
2019-06-13 00:45:07 +03:00
|
|
|
tag = step['timer']
|
2018-11-04 13:57:14 +03:00
|
|
|
assert_browser(ctx)
|
2019-07-05 00:44:58 +03:00
|
|
|
assert ctx['timers'].get(tag) is None
|
2018-11-04 13:57:14 +03:00
|
|
|
ctx['timers'][tag] = {}
|
|
|
|
ctx['timers'][tag]["start"] = time.time()
|
2018-11-03 19:33:19 +03:00
|
|
|
|
2019-07-05 00:44:58 +03:00
|
|
|
|
2019-05-19 01:45:52 +03:00
|
|
|
def run_test_step_action_timer_restart(ctx, step):
|
2019-07-05 00:44:58 +03:00
|
|
|
|
|
|
|
# pylint: disable=locally-disabled, invalid-name
|
|
|
|
|
2019-05-19 01:45:52 +03:00
|
|
|
print(get_indent(ctx) + "Action: " + step["action"])
|
|
|
|
timer = step['timer']
|
|
|
|
assert_browser(ctx)
|
2019-07-05 00:44:58 +03:00
|
|
|
assert ctx['timers'].get(timer) is not None
|
2019-05-20 12:07:53 +03:00
|
|
|
taken = time.time() - ctx['timers'][timer]["start"]
|
2019-06-13 01:55:54 +03:00
|
|
|
print("{} {} restarted at: {:.2f}s".format(get_indent(ctx), timer, taken))
|
2019-05-20 12:07:53 +03:00
|
|
|
ctx['timers'][timer]["taken"] = taken
|
2019-05-19 01:45:52 +03:00
|
|
|
ctx['timers'][timer]["start"] = time.time()
|
|
|
|
|
2019-07-05 00:44:58 +03:00
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
def run_test_step_action_timer_stop(ctx, step):
|
|
|
|
print(get_indent(ctx) + "Action: " + step["action"])
|
2018-11-04 13:57:14 +03:00
|
|
|
timer = step['timer']
|
|
|
|
assert_browser(ctx)
|
2019-07-05 00:44:58 +03:00
|
|
|
assert ctx['timers'].get(timer) is not None
|
2018-11-04 13:57:14 +03:00
|
|
|
taken = time.time() - ctx['timers'][timer]["start"]
|
2019-06-13 01:55:54 +03:00
|
|
|
print("{} {} took: {:.2f}s".format(get_indent(ctx), timer, taken))
|
2018-11-04 13:57:14 +03:00
|
|
|
ctx['timers'][timer]["taken"] = taken
|
2018-11-03 19:33:19 +03:00
|
|
|
|
2019-07-05 00:44:58 +03:00
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
def run_test_step_action_timer_check(ctx, step):
|
2019-07-05 00:44:58 +03:00
|
|
|
|
|
|
|
# pylint: disable=locally-disabled, invalid-name
|
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
print(get_indent(ctx) + "Action: " + step["action"])
|
2018-11-04 13:57:14 +03:00
|
|
|
condition = step["condition"].split()
|
2019-07-05 00:44:58 +03:00
|
|
|
assert len(condition) == 3
|
2018-11-04 13:57:14 +03:00
|
|
|
timer1 = ctx['timers'].get(condition[0])
|
|
|
|
timer2 = ctx['timers'].get(condition[2])
|
2019-07-05 00:44:58 +03:00
|
|
|
assert timer1 is not None
|
|
|
|
assert timer2 is not None
|
|
|
|
assert timer1["taken"] is not None
|
|
|
|
assert timer2["taken"] is not None
|
|
|
|
assert condition[1] in ('<', '>')
|
2018-11-04 13:57:14 +03:00
|
|
|
if condition[1] == '<':
|
2019-07-05 00:44:58 +03:00
|
|
|
assert timer1["taken"] < timer2["taken"]
|
2018-11-04 13:57:14 +03:00
|
|
|
elif condition[1] == '>':
|
2019-07-05 00:44:58 +03:00
|
|
|
assert timer1["taken"] > timer2["taken"]
|
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
|
2019-02-16 13:56:28 +03:00
|
|
|
def run_test_step_action_add_auth(ctx, step):
|
|
|
|
print(get_indent(ctx) + "Action:" + step["action"])
|
|
|
|
assert_browser(ctx)
|
|
|
|
browser = ctx['browser']
|
|
|
|
browser.add_auth(step.get("url"), step.get("realm"),
|
|
|
|
step.get("username"), step.get("password"))
|
|
|
|
|
|
|
|
|
|
|
|
def run_test_step_action_remove_auth(ctx, step):
|
2019-07-05 00:44:58 +03:00
|
|
|
|
|
|
|
# pylint: disable=locally-disabled, invalid-name
|
|
|
|
|
2019-02-16 13:56:28 +03:00
|
|
|
print(get_indent(ctx) + "Action:" + step["action"])
|
|
|
|
assert_browser(ctx)
|
|
|
|
browser = ctx['browser']
|
|
|
|
browser.remove_auth(step.get("url"), step.get("realm"),
|
|
|
|
step.get("username"), step.get("password"))
|
|
|
|
|
2019-07-05 00:44:58 +03:00
|
|
|
|
2019-05-06 13:00:39 +03:00
|
|
|
def run_test_step_action_clear_log(ctx, step):
|
|
|
|
print(get_indent(ctx) + "Action: " + step["action"])
|
|
|
|
assert_browser(ctx)
|
|
|
|
tag = step['window']
|
|
|
|
print(get_indent(ctx) + " " + tag + " Log cleared")
|
|
|
|
win = ctx['windows'].get(tag)
|
2019-07-05 00:44:58 +03:00
|
|
|
assert win is not None
|
2019-05-06 13:00:39 +03:00
|
|
|
win.clear_log()
|
|
|
|
|
|
|
|
|
|
|
|
def run_test_step_action_wait_log(ctx, step):
|
|
|
|
print(get_indent(ctx) + "Action: " + step["action"])
|
|
|
|
assert_browser(ctx)
|
|
|
|
tag = step['window']
|
|
|
|
source = step.get('source')
|
|
|
|
foldable = step.get('foldable')
|
|
|
|
level = step.get('level')
|
|
|
|
substr = step.get('substring')
|
|
|
|
print(get_indent(ctx) + " " + tag + " Wait for logging")
|
|
|
|
win = ctx['windows'].get(tag)
|
2019-07-05 00:44:58 +03:00
|
|
|
assert win is not None
|
2019-05-06 13:00:39 +03:00
|
|
|
win.wait_for_log(source=source, foldable=foldable, level=level, substr=substr)
|
|
|
|
|
|
|
|
|
2019-05-06 21:20:15 +03:00
|
|
|
def run_test_step_action_js_exec(ctx, step):
|
|
|
|
print(get_indent(ctx) + "Action: " + step["action"])
|
|
|
|
assert_browser(ctx)
|
|
|
|
tag = step['window']
|
|
|
|
cmd = step['cmd']
|
|
|
|
print(get_indent(ctx) + " " + tag + " Run " + cmd)
|
|
|
|
win = ctx['windows'].get(tag)
|
2019-07-05 00:44:58 +03:00
|
|
|
assert win is not None
|
2019-05-06 21:20:15 +03:00
|
|
|
win.js_exec(cmd)
|
|
|
|
|
|
|
|
|
2019-12-01 21:23:39 +03:00
|
|
|
def run_test_step_action_page_info_state(ctx, step):
|
|
|
|
print(get_indent(ctx) + "Action: " + step["action"])
|
|
|
|
assert_browser(ctx)
|
|
|
|
tag = step['window']
|
|
|
|
win = ctx['windows'].get(tag)
|
|
|
|
assert win is not None
|
|
|
|
match = step['match']
|
|
|
|
assert win.page_info_state == match
|
|
|
|
|
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
def run_test_step_action_quit(ctx, step):
|
|
|
|
print(get_indent(ctx) + "Action: " + step["action"])
|
2018-11-03 20:14:43 +03:00
|
|
|
assert_browser(ctx)
|
|
|
|
browser = ctx.pop('browser')
|
2019-07-05 00:44:58 +03:00
|
|
|
assert browser.quit_and_wait()
|
2020-03-23 01:47:17 +03:00
|
|
|
# clean up context as all windows have gone away after browser quit
|
|
|
|
ctx.pop('windows')
|
2019-07-05 00:44:58 +03:00
|
|
|
|
|
|
|
|
|
|
|
STEP_HANDLERS = {
|
|
|
|
"launch": run_test_step_action_launch,
|
|
|
|
"window-new": run_test_step_action_window_new,
|
|
|
|
"window-close": run_test_step_action_window_close,
|
|
|
|
"navigate": run_test_step_action_navigate,
|
2019-08-02 14:24:14 +03:00
|
|
|
"reload": run_test_step_action_reload,
|
2019-07-05 00:44:58 +03:00
|
|
|
"stop": run_test_step_action_stop,
|
|
|
|
"sleep-ms": run_test_step_action_sleep_ms,
|
|
|
|
"block": run_test_step_action_block,
|
|
|
|
"repeat": run_test_step_action_repeat,
|
|
|
|
"timer-start": run_test_step_action_timer_start,
|
|
|
|
"timer-restart": run_test_step_action_timer_restart,
|
|
|
|
"timer-stop": run_test_step_action_timer_stop,
|
|
|
|
"timer-check": run_test_step_action_timer_check,
|
|
|
|
"plot-check": run_test_step_action_plot_check,
|
2019-08-03 14:31:43 +03:00
|
|
|
"click": run_test_step_action_click,
|
|
|
|
"wait-loading": run_test_step_action_wait_loading,
|
2019-07-05 00:44:58 +03:00
|
|
|
"add-auth": run_test_step_action_add_auth,
|
|
|
|
"remove-auth": run_test_step_action_remove_auth,
|
|
|
|
"clear-log": run_test_step_action_clear_log,
|
|
|
|
"wait-log": run_test_step_action_wait_log,
|
|
|
|
"js-exec": run_test_step_action_js_exec,
|
2019-12-01 21:23:39 +03:00
|
|
|
"page-info-state":
|
|
|
|
run_test_step_action_page_info_state,
|
2019-07-05 00:44:58 +03:00
|
|
|
"quit": run_test_step_action_quit,
|
2018-11-03 19:33:19 +03:00
|
|
|
}
|
|
|
|
|
2019-07-05 00:44:58 +03:00
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
def run_test_step(ctx, step):
|
2019-07-05 00:44:58 +03:00
|
|
|
STEP_HANDLERS[step["action"]](ctx, step)
|
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
|
|
|
|
def walk_test_plan(ctx, plan):
|
|
|
|
ctx["depth"] = 0
|
2018-11-04 16:10:27 +03:00
|
|
|
ctx["timers"] = dict()
|
2018-11-04 17:34:31 +03:00
|
|
|
ctx['repeats'] = dict()
|
2018-11-03 19:33:19 +03:00
|
|
|
for step in plan["steps"]:
|
|
|
|
run_test_step(ctx, step)
|
|
|
|
|
2019-07-05 00:44:58 +03:00
|
|
|
|
2019-02-16 17:57:11 +03:00
|
|
|
def run_test_plan(ctx, plan):
|
|
|
|
print_test_plan_info(ctx, plan)
|
|
|
|
walk_test_plan(ctx, plan)
|
|
|
|
|
2019-07-05 00:44:58 +03:00
|
|
|
|
2019-02-16 17:57:11 +03:00
|
|
|
def run_preloaded_test(path_monkey, plan):
|
|
|
|
ctx = {
|
|
|
|
"monkey": path_monkey,
|
|
|
|
}
|
|
|
|
run_test_plan(ctx, plan)
|
2018-11-03 19:33:19 +03:00
|
|
|
|
2019-07-05 00:44:58 +03:00
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
def main(argv):
|
|
|
|
ctx = {}
|
2019-06-15 22:01:08 +03:00
|
|
|
path_monkey, path_test, wrapper = parse_argv(argv)
|
2018-11-03 19:33:19 +03:00
|
|
|
plan = load_test_plan(path_test)
|
2018-11-03 20:14:43 +03:00
|
|
|
ctx["monkey"] = path_monkey
|
2019-06-15 22:01:08 +03:00
|
|
|
ctx["wrapper"] = wrapper
|
2019-02-16 18:34:18 +03:00
|
|
|
run_test_plan(ctx, plan)
|
2018-11-03 19:33:19 +03:00
|
|
|
|
2019-07-05 00:44:58 +03:00
|
|
|
|
2018-11-03 19:33:19 +03:00
|
|
|
# Some python weirdness to get to main().
|
|
|
|
if __name__ == "__main__":
|
2018-11-03 20:14:43 +03:00
|
|
|
main(sys.argv[1:])
|