Skip to content

Commit

Permalink
Add GUI call functionality to scauto CLI
Browse files Browse the repository at this point in the history
Add CLI GUI commands to make direct calls to the GUI model library
functions necessary for some manual and remotely executed test steps.

As a part of the change to run GUI functions from the CLI, we also need
to move the initialization of the screen object in __init__ instead of
__enter__.

resolves #146
  • Loading branch information
spoore1 committed Nov 27, 2024
1 parent 67004e0 commit ec4d04b
Show file tree
Hide file tree
Showing 2 changed files with 169 additions and 36 deletions.
201 changes: 166 additions & 35 deletions SCAutolib/cli_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,50 @@
from pathlib import Path
from sys import exit

from collections import OrderedDict

from SCAutolib import logger, exceptions, schema_user
from SCAutolib.controller import Controller
from SCAutolib.enums import ReturnCode


@click.group()
def check_conf_path(conf):
return click.Path(exists=True, resolve_path=True)(conf)


class NaturalOrderGroup(click.Group):
"""
Command group trying to list subcommands in the order they were added.
Example use::
@click.group(cls=NaturalOrderGroup)
If passing dict of commands from other sources, ensure they are of type
OrderedDict and properly ordered, otherwise order of them will be random
and newly added will come to the end.
"""
def __init__(self, name=None, commands=None, **attrs):
if commands is None:
commands = OrderedDict()
elif not isinstance(commands, OrderedDict):
commands = OrderedDict(commands)
click.Group.__init__(self, name=name,
commands=commands,
**attrs)

def list_commands(self, ctx):
"""
List command names as they are in commands dict.
If the dict is OrderedDict, it will preserve the order commands
were added.
"""
return self.commands.keys()


@click.group(cls=NaturalOrderGroup)
@click.option("--conf", "-c",
default="./conf.json",
type=click.Path(exists=True, resolve_path=True),
show_default=True,
help="Path to JSON configuration file.")
@click.option('--force', "-f", is_flag=True, default=False, show_default=True,
Expand All @@ -29,35 +64,11 @@ def cli(ctx, force, verbose, conf):
logger.setLevel(verbose)
ctx.ensure_object(dict) # Create a dict to store the context
ctx.obj["FORCE"] = force # Store the force option in the context
ctx.obj["CONTROLLER"] = Controller(conf)
if ctx.invoked_subcommand and not gui:
ctx.obj["CONTROLLER"] = Controller(check_conf_path(conf))


@click.command()
@click.option("--ca-type", "-t",
required=False,
default='all',
type=click.Choice(['all', 'local', 'ipa'], case_sensitive=False),
show_default=True,
help="Type of the CA to be configured. If not set, all CA's "
"from the config file would be configured")
@click.pass_context
def setup_ca(ctx, ca_type):
"""
Configure the CA's in the config file. If more than one CA is
specified, specified CA type would be configured.
"""
cnt = ctx.obj["CONTROLLER"]
if ca_type == 'all':
cnt.setup_local_ca(force=ctx.obj["FORCE"])
cnt.setup_ipa_client(force=ctx.obj["FORCE"])
elif ca_type == 'local':
cnt.setup_local_ca(force=ctx.obj["FORCE"])
elif ca_type == 'ipa':
cnt.setup_ipa_client(force=ctx.obj["FORCE"])
exit(ReturnCode.SUCCESS.value)


@click.command()
@cli.command()
@click.option("--gdm", "-g",
required=False,
default=False,
Expand Down Expand Up @@ -85,7 +96,32 @@ def prepare(ctx, gdm, install_missing, graphical):
exit(ReturnCode.SUCCESS.value)


@click.command()
@cli.command()
@click.option("--ca-type", "-t",
required=False,
default='all',
type=click.Choice(['all', 'local', 'ipa'], case_sensitive=False),
show_default=True,
help="Type of the CA to be configured. If not set, all CA's "
"from the config file would be configured")
@click.pass_context
def setup_ca(ctx, ca_type):
"""
Configure the CA's in the config file. If more than one CA is
specified, specified CA type would be configured.
"""
cnt = ctx.obj["CONTROLLER"]
if ca_type == 'all':
cnt.setup_local_ca(force=ctx.obj["FORCE"])
cnt.setup_ipa_client(force=ctx.obj["FORCE"])
elif ca_type == 'local':
cnt.setup_local_ca(force=ctx.obj["FORCE"])
elif ca_type == 'ipa':
cnt.setup_ipa_client(force=ctx.obj["FORCE"])
exit(ReturnCode.SUCCESS.value)


@cli.command()
@click.argument("name",
required=True,
default=None)
Expand Down Expand Up @@ -154,7 +190,7 @@ def setup_user(ctx, name, card_dir, card_type, passwd, pin, user_type):
exit(ReturnCode.SUCCESS.value)


@click.command()
@cli.command()
@click.pass_context
def cleanup(ctx):
"""
Expand All @@ -165,7 +201,102 @@ def cleanup(ctx):
exit(ReturnCode.SUCCESS.value)


cli.add_command(setup_ca)
cli.add_command(prepare)
cli.add_command(setup_user)
cli.add_command(cleanup)
@cli.group(cls=NaturalOrderGroup, chain=True)
@click.pass_context
def gui(ctx):
""" Run GUI Test commands """
pass


@gui.command()
def init():
""" Initialize GUI for testing """
return "init"


@gui.command()
@click.argument("name")
def assert_text(name):
""" Check if a word is found on the screen """
return f"assert_text:{name}"


@gui.command()
@click.argument("name")
def assert_no_text(name):
""" Check that a word is not found on the screen """
return f"assert_no_text:{name}"


@gui.command()
@click.argument("name")
def click_on(name):
""" Click on object containing word """
return f"click_on:{name}"


@gui.command()
def check_home_screen():
""" Check if screen appears to be the home screen """
return f"check_home_screen"


@gui.command()
@click.argument("keys")
def kb_send(keys):
""" Send key(s) to keyboard """
return f"kb_send:{keys}"


@gui.command()
@click.argument("keys")
def kb_write(keys):
""" Send string to keyboard """
return f"kb_write:{keys}"


@gui.command()
def done():
""" cleanup after testing """
return "done"


@gui.result_callback()
@click.pass_context
def run_all(ctx, actions):
click.echo(actions)

from SCAutolib.models.gui import GUI
gui = GUI()
for action in actions:
if "init" in action:
gui.__enter__()
if "assert_text" in action:
assert_text = action.split(":")[1]
click.echo(f"CLICK: assert_text:{assert_text}")
gui.assert_text(assert_text)
if "assert_no_text" in action:
assert_text = action.split(":")[1]
click.echo(f"CLICK: assert_text:{assert_text}")
gui.assert_text(assert_text)
if "click_on" in action:
click_on = action.split(":")[1]
click.echo(f"CLICK: click_on:{click_on}")
gui.click_on(click_on)
if "check_home_screen" in action:
click.echo("CLICK: check_home_screen")
gui.check_home_screen()
if "kb_send" in action:
params = action.split(":")[1].split()
click.echo(f"CLICK: kb_send:{params}")
gui.kb_send(*params)
if "kb_write" in action:
params = action.split(":")[1].split()
click.echo(f"CLICK: kb_write:{params}")
gui.kb_write(*params)
if "done" in action:
gui.__exit__(None, None, None)


if __name__ == "__main__":
cli()
4 changes: 3 additions & 1 deletion SCAutolib/models/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,8 +290,10 @@ def __init__(self, wait_time: float = 5, res_dir_name: str = None):
# otherwise the first character is not sent
keyboard.send('enter')

def __enter__(self):
# create screen object to use from calls
self.screen = Screen(self.screenshot_directory, self.html_file)

def __enter__(self):
# By restarting gdm, the system gets into defined state
run(['systemctl', 'restart', 'gdm'], check=True)
# Cannot screenshot before gdm starts displaying
Expand Down

0 comments on commit ec4d04b

Please sign in to comment.