Skip to content

Commit 1ae9375

Browse files
committed
Merge pull request avocado-framework#446 from clebergnu/rest-client-v4
REST Client: introduce API and avocado-rest-client application [v4]
2 parents 0aad3cc + 90b897b commit 1ae9375

24 files changed

+1026
-4
lines changed

Makefile

+2
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,14 @@ clean:
5050
rm -rf build/ MANIFEST BUILD BUILDROOT SPECS RPMS SRPMS SOURCES
5151
find . -name '*.pyc' -delete
5252
rm -f man/avocado.1
53+
rm -f man/avocado-rest-client.1
5354
rm -rf docs/build
5455

5556
check:
5657
selftests/checkall
5758

5859
man:
5960
rst2man man/avocado.rst man/avocado.1
61+
rst2man man/avocado-rest-client.rst man/avocado-rest-client.1
6062

6163
.PHONY: source install clean check man

avocado.spec

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Summary: Avocado Test Framework
22
Name: avocado
33
Version: 0.20.1
4-
Release: 1%{?dist}
4+
Release: 2%{?dist}
55
License: GPLv2
66
Group: Development/Tools
77
URL: http://avocado-framework.github.io/
@@ -20,11 +20,13 @@ these days a framework) to perform automated testing.
2020
%build
2121
%{__python} setup.py build
2222
%{__python2} /usr/bin/rst2man man/avocado.rst man/avocado.1
23+
%{__python2} /usr/bin/rst2man man/avocado-rest-client.rst man/avocado-rest-client.1
2324

2425
%install
2526
%{__python} setup.py install --root %{buildroot} --skip-build
2627
%{__mkdir} -p %{buildroot}%{_mandir}/man1
2728
%{__install} -m 0644 man/avocado.1 %{buildroot}%{_mandir}/man1/avocado.1
29+
%{__install} -m 0644 man/avocado-rest-client.1 %{buildroot}%{_mandir}/man1/avocado-rest-client.1
2830

2931
%files
3032
%defattr(-,root,root,-)
@@ -34,10 +36,12 @@ these days a framework) to perform automated testing.
3436
%config(noreplace)/etc/avocado/avocado.conf
3537
%config(noreplace)/etc/avocado/conf.d/README
3638
%{_bindir}/avocado
39+
%{_bindir}/avocado-rest-client
3740
%exclude %{python_sitelib}/avocado/plugins/htmlresult.py*
3841
%exclude %{python_sitelib}/avocado/plugins/resources/htmlresult/*
3942
%{python_sitelib}/avocado*
4043
%{_mandir}/man1/avocado.1.gz
44+
%{_mandir}/man1/avocado-rest-client.1.gz
4145

4246
%package plugins-output-html
4347
Summary: Avocado HTML report plugin
@@ -64,8 +68,12 @@ examples of how to write tests on your own.
6468
%files examples
6569
%{_datadir}/avocado/tests
6670
%{_datadir}/avocado/wrappers
71+
%{_datadir}/avocado/api
6772

6873
%changelog
74+
* Mon Feb 23 2015 Cleber Rosa <[email protected]> - 0.20.1-2
75+
- Added avocado-rest-client modules, script, man page and API examples
76+
6977
* Fri Feb 6 2015 Lucas Meneghel Rodrigues <[email protected]> - 0.20.1-1
7078
- Update to upstream version 0.20.1
7179

avocado/restclient/__init__.py

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# This program is free software; you can redistribute it and/or modify
2+
# it under the terms of the GNU General Public License as published by
3+
# the Free Software Foundation; either version 2 of the License, or
4+
# (at your option) any later version.
5+
#
6+
# This program is distributed in the hope that it will be useful,
7+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
8+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9+
#
10+
# See LICENSE for more details.
11+
#
12+
# Copyright: Red Hat Inc. 2015
13+
# Author: Cleber Rosa <[email protected]>

avocado/restclient/cli/__init__.py

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# This program is free software; you can redistribute it and/or modify
2+
# it under the terms of the GNU General Public License as published by
3+
# the Free Software Foundation; either version 2 of the License, or
4+
# (at your option) any later version.
5+
#
6+
# This program is distributed in the hope that it will be useful,
7+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
8+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9+
#
10+
# See LICENSE for more details.
11+
#
12+
# Copyright: Red Hat Inc. 2015
13+
# Author: Cleber Rosa <[email protected]>
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# This program is free software; you can redistribute it and/or modify
2+
# it under the terms of the GNU General Public License as published by
3+
# the Free Software Foundation; either version 2 of the License, or
4+
# (at your option) any later version.
5+
#
6+
# This program is distributed in the hope that it will be useful,
7+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
8+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9+
#
10+
# See LICENSE for more details.
11+
#
12+
# Copyright: Red Hat Inc. 2015
13+
# Author: Cleber Rosa <[email protected]>
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Copyright: Red Hat Inc. 2015
2+
# Author: Cleber Rosa <[email protected]>
3+
4+
5+
def action(function):
6+
"""
7+
Simple function that marks functions as CLI actions
8+
9+
:param function: the function that will receive the CLI action mark
10+
"""
11+
function.is_action = True
12+
return function
+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Copyright: Red Hat Inc. 2015
2+
# Author: Cleber Rosa <[email protected]>
3+
4+
"""
5+
Module that implements the actions for the CLI App when the job toplevel
6+
command is used
7+
"""
8+
9+
from avocado.restclient import connection
10+
from avocado.restclient.cli.actions import base
11+
12+
13+
@base.action
14+
def status(app):
15+
"""
16+
Shows the server status
17+
"""
18+
data = app.connection.request("version/")
19+
app.view.notify(event="message",
20+
msg="Server version: %s" % data.get('version'))
21+
22+
23+
@base.action
24+
def list_brief(app):
25+
"""
26+
Shows the server API list
27+
"""
28+
try:
29+
data = app.connection.get_api_list()
30+
except connection.UnexpectedHttpStatusCode, e:
31+
if e.received == 403:
32+
app.view.notify(event="error",
33+
msg="Error: Access Forbidden")
34+
return False
35+
36+
app.view.notify(event="message",
37+
msg="Available APIs:")
38+
for name in data:
39+
app.view.notify(event="message",
40+
msg=" * %s" % name)

avocado/restclient/cli/app.py

+134
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# This program is free software; you can redistribute it and/or modify
2+
# it under the terms of the GNU General Public License as published by
3+
# the Free Software Foundation; either version 2 of the License, or
4+
# (at your option) any later version.
5+
#
6+
# This program is distributed in the hope that it will be useful,
7+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
8+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9+
#
10+
# See LICENSE for more details.
11+
#
12+
# Copyright: Red Hat Inc. 2015
13+
# Author: Cleber Rosa <[email protected]>
14+
15+
"""
16+
This is the main entry point for the rest client cli application
17+
"""
18+
19+
20+
import sys
21+
import types
22+
import importlib
23+
import functools
24+
25+
from avocado import settings
26+
from avocado.core import output
27+
from avocado.core import exit_codes
28+
from avocado.restclient import connection
29+
from avocado.restclient.cli import parser
30+
31+
__all__ = ['App']
32+
33+
34+
class App(object):
35+
36+
"""
37+
Base class for CLI application
38+
"""
39+
40+
def __init__(self):
41+
"""
42+
Initializes a new app instance.
43+
44+
This class is intended both to be used by the stock client application
45+
and also to be reused by custom applications. If you want, say, to
46+
limit the amount of command line actions and its arguments, you can
47+
simply supply another argument parser class to this constructor. Of
48+
course another way to customize it is to inherit from this and modify
49+
its members at will.
50+
"""
51+
self.connection = None
52+
self.parser = parser.Parser()
53+
self.parser.add_arguments_on_all_modules()
54+
self.view = output.View()
55+
56+
def initialize_connection(self):
57+
"""
58+
Initialize the connection instance
59+
"""
60+
try:
61+
self.connection = connection.Connection(
62+
hostname=self.args.hostname,
63+
port=self.args.port,
64+
username=self.args.username,
65+
password=self.args.password)
66+
except connection.InvalidConnectionError:
67+
self.view.notify(event="error",
68+
msg="Error: could not connect to the server")
69+
sys.exit(exit_codes.AVOCADO_JOB_FAIL)
70+
except connection.InvalidServerVersionError:
71+
self.view.notify(event="error",
72+
msg=("REST server version is higher than "
73+
"than this client can support."))
74+
self.view.notify(event="error",
75+
msg=("Please use a more recent version "
76+
"of the REST client application."))
77+
sys.exit(exit_codes.AVOCADO_JOB_FAIL)
78+
79+
def dispatch_action(self):
80+
"""
81+
Calls the actions that was specified via command line arguments.
82+
83+
This involves loading the relevant module file.
84+
"""
85+
module_name = "%s.%s" % ('avocado.restclient.cli.actions',
86+
self.args.top_level_action)
87+
88+
try:
89+
module = importlib.import_module(module_name)
90+
except ImportError:
91+
return
92+
93+
# Filter out the attributes out of the loaded module that look
94+
# like command line actions, based on type and 'is_action' attribute
95+
module_actions = {}
96+
for attribute_name in module.__dict__:
97+
attribute = module.__dict__[attribute_name]
98+
if (isinstance(attribute, types.FunctionType) and
99+
hasattr(attribute, 'is_action')):
100+
if attribute.is_action:
101+
module_actions[attribute_name] = attribute
102+
103+
chosen_action = None
104+
for action in module_actions.keys():
105+
if getattr(self.args, action, False):
106+
chosen_action = action
107+
break
108+
109+
kallable = module_actions.get(chosen_action, None)
110+
if kallable is not None:
111+
self.initialize_connection()
112+
return kallable(self)
113+
else:
114+
self.view.notify(event="error",
115+
msg="Action specified is not implemented")
116+
117+
def run(self):
118+
"""
119+
Main entry point for application
120+
"""
121+
action_result = None
122+
try:
123+
self.args = self.parser.parse_args()
124+
action_result = self.dispatch_action()
125+
except KeyboardInterrupt:
126+
print 'Interrupted'
127+
128+
if isinstance(action_result, int):
129+
sys.exit(action_result)
130+
elif isinstance(action_result, bool):
131+
if action_result is True:
132+
sys.exit(0)
133+
else:
134+
sys.exit(1)
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# This program is free software; you can redistribute it and/or modify
2+
# it under the terms of the GNU General Public License as published by
3+
# the Free Software Foundation; either version 2 of the License, or
4+
# (at your option) any later version.
5+
#
6+
# This program is distributed in the hope that it will be useful,
7+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
8+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9+
#
10+
# See LICENSE for more details.
11+
#
12+
# Copyright: Red Hat Inc. 2015
13+
# Author: Cleber Rosa <[email protected]>

avocado/restclient/cli/args/base.py

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# This program is free software; you can redistribute it and/or modify
2+
# it under the terms of the GNU General Public License as published by
3+
# the Free Software Foundation; either version 2 of the License, or
4+
# (at your option) any later version.
5+
#
6+
# This program is distributed in the hope that it will be useful,
7+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
8+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9+
#
10+
# See LICENSE for more details.
11+
#
12+
# Copyright: Red Hat Inc. 2015
13+
# Author: Cleber Rosa <[email protected]>
14+
15+
"""
16+
This module has base action arguments that are used on other top level commands
17+
18+
These top level commands import these definitions for uniformity and
19+
consistency sake
20+
"""
21+
22+
__all__ = ['ADD', 'LIST_BRIEF', 'LIST_FULL', 'DELETE', 'NAME', 'ID']
23+
24+
25+
#
26+
# Arguments that are treated as actions
27+
#
28+
ADD = (('-a', '--add',),
29+
{'help': 'add a new entry',
30+
'action': 'store_true',
31+
'default': False})
32+
33+
34+
LIST_BRIEF = (('-l', '--list-brief',),
35+
{'help': 'list all records briefly',
36+
'action': 'store_true',
37+
'default': False})
38+
39+
40+
LIST_FULL = (('-L', '--list-full',),
41+
{'help': 'list all records with all information',
42+
'action': 'store_true',
43+
'default': False})
44+
45+
46+
DELETE = (('-d', '--delete',),
47+
{'help': 'delete an existing object',
48+
'action': 'store_true',
49+
'default': False})
50+
51+
52+
#
53+
# Other arguments that will influence action behaviour
54+
#
55+
NAME = (('-n', '--name'),
56+
{'help': 'name of the object'})
57+
58+
59+
ID = (('-i', '--id'),
60+
{'help': 'numeric identification of the object',
61+
'type': int})

0 commit comments

Comments
 (0)