Skip to content

Commit 7e72f58

Browse files
rochacbrunoelyezer
authored andcommitted
Added "manage ui browse" command (SatelliteQE#3721)
1 parent 82556d6 commit 7e72f58

14 files changed

+403
-7
lines changed

.coveragerc

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
[run]
2+
omit =
3+
robottelo/commands/*.py
24
include =
35
robottelo/*.py
46
robottelo/api

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ env:
44
- TOXENV=py27
55
- TOXENV=py34
66
install:
7-
- pip install -r requirements.txt coveralls flake8 sphinx testimony tox
7+
- pip install -r requirements.txt coveralls flake8 sphinx testimony tox manage
88
script:
99
- flake8 .
1010
- make test-docstrings

docs/api/robottelo.commands.rst

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
:mod:`robottelo.commands`
2+
===========================
3+
4+
.. automodule:: robottelo.commands
5+
6+
:mod:`robottelo.commands.ui`
7+
--------------------------------
8+
9+
.. automodule:: robottelo.commands.ui

docs/api/robottelo.rst

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Submodules:
66
.. toctree::
77
robottelo.api
88
robottelo.cli
9+
robottelo.commands
910
robottelo.performance
1011
robottelo.ui
1112
robottelo.decorators

docs/features/commands.rst

+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
Commands
2+
========
3+
4+
This section explains Robottelo Management Commands.
5+
6+
.. contents::
7+
8+
Modules
9+
-------
10+
11+
Robottelo uses `manage` and `click` for its management commands, the commands
12+
are accessible via console using the :code:`$ manage`. To see a list of all available
13+
commands run :code:`$ manage --help`.
14+
15+
The command manager specification is located at `robottelo/manage.yml` and
16+
it is easy to add new commands to framework by creating new functions or
17+
click commands and referring on `manage.yml` file.
18+
19+
Existing commands are located at
20+
:doc:`commands package </api/robottelo.commands>`. There are commands to
21+
open an interactive shell, interact with UI browser, API and other utilities.
22+
23+
requisites
24+
----------
25+
26+
To play with the management commands you need to install robottelo's
27+
additional requirements which includes the `manage` library and also
28+
is recommended to have iPython installed::
29+
30+
$ cd robottelo
31+
$ make pyc-clean
32+
$ pip install ipython
33+
$ pip install -r -U requirements-optional.txt
34+
35+
shell
36+
-----
37+
38+
The Interactive Shell is useful to test robottelo's functions and entities,
39+
you can change code and all changes are automatically reloaded into shell so
40+
no need to restart the shell or reload the modules.
41+
42+
If ipython is installed your shell will be opened using ipython but it is also
43+
possible to use `--bpython`, `--ptpython` or bare `--python` as console.
44+
45+
To check the shell options run::
46+
47+
$ manage shell --help
48+
49+
And to open the shell::
50+
51+
$ manage shell
52+
53+
Assuming you have ipython installed you will see a console like:
54+
55+
.. code-block:: console
56+
57+
(robottelo_env)[you@host robottelo]$ manage shell
58+
Python 2.7.11 (default, Jul 8 2016, 19:45:00)
59+
Type "copyright", "credits" or "license" for more information.
60+
61+
IPython 5.0.0 -- An enhanced Interactive Python.
62+
? -> Introduction and overview of IPython's features.
63+
%quickref -> Quick reference.
64+
help -> Python's own help system.
65+
object? -> Details about 'object', use 'object??' for extra details.
66+
67+
Welcome to Robottelo Interactive shell
68+
Auto imported: ['rt', 'nailgun', 'settings', 'robottelo', 'ng', 'entities', 'locators']
69+
70+
In [1]: rt.ssh.command('uname -r')
71+
2016-09-16 13:54:57 - robottelo.ssh - DEBUG - Connected to [foreman-server.com]
72+
Out[1]: SSHCommandResult(stdout=[u'3.10.0-327.el7.x86_64', u''], stderr='', return_code=0, output_format=None)
73+
In [2]: exit
74+
75+
This is the Robottelo's interactive shell welcome screen and you can see some
76+
most commonly used objects are `auto_imported` saving you time.
77+
78+
Also the `settings` object is loaded and configured, so you have a ready to use
79+
environment to play with robottelo features.
80+
81+
ui browse
82+
---------
83+
84+
In the subgroup `ui` you can find the `browse` command which opens the same
85+
interactive shell but it also opens a new browser instance and gives you
86+
the context to play with this.
87+
88+
The interaction with the `ui` browser is done trough the `session` object, and
89+
the opened browser uses the configuration from your `robottelo.properties` file.
90+
91+
Open a new REPL connected to a browser session:
92+
93+
.. code-block:: console
94+
95+
(robottelo_env)[you@host robottelo]$ manage ui browse
96+
2016-09-16 14:00:42 - robottelo.ui.browser - DEBUG - newSession: {'desiredCapabilities': {'platform': 'ANY', 'browserName': 'chrome', 'version': '', 'chromeOptions': {'args': [], 'extensions': []}, 'javascriptEnabled': True}}
97+
98+
Welcome to Robottelo Interactive shell
99+
Auto imported: ['rt', 'nailgun', 'settings', 'robottelo', 'ng', 'entities', 'host', 'session', 'current_browser', 'locators', 'ui_factory', 'api_factory', 'browser']
100+
101+
In [1]: session.browser
102+
Out[1]: <robottelo.ui.browser.Chrome (session="0968e34f29e2c3208554ada58023fa4f")>
103+
104+
In [2]: session.nav.go_to_users()
105+
2016-09-16 14:01:15 - robottelo.ui.browser - DEBUG - mouseMoveTo: {'element': u'0.8036987570003233-1'}
106+
107+
In [3]: session.ui.user.click(locators.locators.users.new)
108+
2016-09-16 14:01:46 - robottelo.ui.browser - DEBUG - clickElement: {'id': u'0.12969267888817115-2'}
109+
110+
In [4]: session.ui.user.assign_value(locators.locators.users.username, "my_username")
111+
2016-09-16 14:02:13 - robottelo.ui.browser - DEBUG - sendKeysToElement: {'id': u'0.12969267888817115-3', 'value': 'my_username'}
112+
113+
In [5]: exit
114+
2016-09-16 14:05:46 - robottelo.ui.browser - DEBUG - logout
115+
2016-09-16 14:05:46 - robottelo.ui.browser - DEBUG - Close Browser
116+
117+
While you interact wth the UI using the helpers as the ones in the exemple above
118+
you see your browser window changing interactively, if you prefer to use a docker browser
119+
it is possible to connect via VNC or get screenshots calling :code:`session.browser.save_screenshot()`
120+
121+
It is also possible to open the `browse` session in specific page if you specify the entity name
122+
123+
.. code-block:: console
124+
125+
# opens the session with browser already in users page
126+
(robottelo_env)[you@host robottelo]$ manage ui browse user
127+
128+
# create user using factory
129+
In [1]: session.ui.make_user(username="my_username")
130+
131+

docs/features/index.rst

+1-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ about its capabilities.
77
.. toctree::
88
:maxdepth: 1
99

10+
commands
1011
decorators
1112
ssh
12-
13-

manage.yml

+12-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ help_text: This is the {project_name} interactive shell
33

44
# interactive shell
55
shell:
6+
ipython_auto_reload: true
67
auto_import:
78
display: true
89
objects:
@@ -28,6 +29,15 @@ shell:
2829
readline_enabled: false
2930

3031
# commands
31-
click_commands: []
32-
function_commands: []
32+
33+
groups:
34+
- ui:
35+
short_help: Commands to interactively browse UI
36+
help_text: |
37+
Commands to interactively browse UI.
38+
39+
click_commands:
40+
- module: robottelo.commands.ui
41+
group: ui
42+
3343
inline_commands: []

requirements-optional.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@ docker-py
2020
sauceclient
2121

2222
# For 'manage' interactive shell
23-
manage>=0.1.12
23+
manage>=0.1.13

robottelo/commands/__init__.py

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
"""
2+
This module stores all commands for robottelo management console.
3+
4+
The commands are written using `click` library and loaded using `manage`
5+
6+
Simply create a new module containing a new `click` commands or a `function`
7+
and reference this new module in `robottelo/manage.yml` file and the new
8+
command will be available trough :code:`$ manage command_name`
9+
10+
Please take a look at :doc:`commands package </features/commands>` page
11+
in documentation for more details.
12+
"""

robottelo/commands/ui.py

+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
# coding: utf-8
2+
"""
3+
This module contains commands to interact with UI via console
4+
5+
Commands included:
6+
7+
Browse
8+
------
9+
10+
A command to open a browser session using the configured preferences from
11+
`robottelo.properties` file and provide an interactive shell to play with
12+
browser session::
13+
14+
$ manage ui browse <entity>
15+
>>> session.nav.go_to_entity()
16+
>>> session.ui.make_user(username='my_username')
17+
18+
Please take a look at :doc:`commands package </features/commands>` page
19+
in documentation for more details.
20+
21+
"""
22+
import click
23+
import import_string
24+
25+
from functools import partial
26+
from inspect import getmembers
27+
from manage.cli import create_shell
28+
from nailgun import entities
29+
from robottelo.config import settings
30+
from robottelo.constants import UI_CRUD
31+
from robottelo.helpers import Storage
32+
from robottelo.ui.browser import browser as selenium_browser
33+
from robottelo.ui.browser import DockerBrowser
34+
from robottelo.ui import factory as ui_factory
35+
from robottelo.ui.session import Session
36+
37+
38+
def _get_browser(browser=None):
39+
"""Gets a new instance of a browser to interact"""
40+
41+
browser = browser or settings.browser
42+
if browser == 'docker':
43+
_docker_browser = DockerBrowser()
44+
_docker_browser.start()
45+
_browser = _docker_browser.webdriver
46+
elif browser == "selenium":
47+
_browser = selenium_browser()
48+
else:
49+
raise NotImplementedError(
50+
"this shell only supports docker and selenium")
51+
52+
_browser.maximize_window()
53+
_browser.get(settings.server.get_url())
54+
return _browser
55+
56+
57+
def _import_ui_crud():
58+
"""Imports all UI crud related classes to shell scope"""
59+
# FIXME: get all subclasses of robotello.ui.base.Base automatically
60+
base_module = "robottelo.ui.{0}"
61+
return {
62+
name.split('.')[-1]: import_string(base_module.format(name))
63+
for name in UI_CRUD
64+
}
65+
66+
67+
@click.command()
68+
@click.option('--host', required=False, default=None,
69+
help="satellite host name e.g:'foo.bar.com'")
70+
@click.option('--browser', required=False, default=None,
71+
help='selenium or docker (defaults to properties file)')
72+
@click.argument('entity', required=False, default=None)
73+
def browse(entity, browser, host):
74+
"""Opens a page in defined browser for interaction:\n
75+
All parameters defaults to what is in robottelo.properties file.\n
76+
example: $ manage ui browse activationkey\n
77+
Opens a browser in ActivationKey scope and gives you
78+
interactive shell to play with the page\n
79+
"""
80+
settings.configure()
81+
if host:
82+
settings.server.hostname = host
83+
current_browser = _get_browser(browser)
84+
with Session(current_browser) as session: # noqa
85+
86+
ui_crud = _import_ui_crud()
87+
# Make all UI CRUD entities available in a dict
88+
# each entity initialized with current_browser instance
89+
ui_entities = {
90+
name.lower(): crud_class(current_browser)
91+
for name, crud_class in ui_crud.items()
92+
}
93+
if entity:
94+
# if entity name specified navigate to the page
95+
# example: manage ui browse user
96+
ui_entities[entity.lower()].navigate_to_entity()
97+
98+
# gets all functions from ui.factory module which starts with 'make_'
99+
ui_factory_members = getmembers(
100+
ui_factory,
101+
lambda i: callable(i) and i.__name__.startswith('make')
102+
)
103+
# Usually we need to pass the `session` as 1st argument
104+
# e.g `make_user(session, username='...')`
105+
# using `partial` we make session the default 1st argument
106+
# it allows the use as: `make_user(username='...')
107+
# and `session` is implicit there.
108+
ui_factory_functions = {
109+
name: partial(function, session=session)
110+
for name, function in ui_factory_members
111+
}
112+
113+
# now we "inject" the factories and entities under `session.ui`
114+
session.ui = Storage(ui_entities, ui_factory_functions)
115+
116+
# The same for nailgun.entities.* under `session.api`
117+
session.api = Storage(dict(getmembers(entities)))
118+
119+
def close():
120+
"""Hook to close the session and browser atexit it also flushes
121+
the session history content to the specified file
122+
"""
123+
session.close()
124+
# FIXME: if --out=/path/to/file should save session history
125+
# see ipython.readthedocs.io/en/stable/config/options/terminal.html
126+
127+
extra_vars = {
128+
'session': session,
129+
'browser': current_browser,
130+
'current_browser': current_browser,
131+
'host': settings.server.hostname,
132+
'api_factory': entities,
133+
'ui_factory': ui_factory
134+
}
135+
136+
create_shell('ipython', extra_vars=extra_vars, exit_hooks=[close])

0 commit comments

Comments
 (0)