Skip to content

Commit

Permalink
Add base cli setup and testing. Close #27.
Browse files Browse the repository at this point in the history
  • Loading branch information
chambridge committed Sep 21, 2017
1 parent 5c2a6a1 commit 7e6e6b4
Show file tree
Hide file tree
Showing 10 changed files with 366 additions and 4 deletions.
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,16 @@ install: build
$(PYTHON) setup.py install -f

test:
$(PYTHON) quipucords/manage.py test -v 2 quipucords
$(PYTHON) quipucords/manage.py test -v 2 quipucords/

test-coverage:
coverage run --source=quipucords/ quipucords/manage.py test -v 2 quipucords;coverage report -m
coverage run --source=quipucords/ quipucords/manage.py test -v 2 quipucords/;coverage report -m

lint-flake8:
flake8 . --ignore D203

lint-pylint:
$(PYTHON) -m pylint --load-plugins=pylint_django quipucords/*/*.py
find . -name "*.py" | xargs $(PYTHON) -m pylint --load-plugins=pylint_django --disable=duplicate-code

lint: lint-flake8 lint-pylint

Expand Down
52 changes: 52 additions & 0 deletions bin/qpc
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/usr/bin/python
#
# Copyright (c) 2017 Red Hat, Inc.
#
# This software is licensed to you under the GNU General Public License,
# version 3 (GPLv3). There is NO WARRANTY for this software, express or
# implied, including the implied warranties of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv3
# along with this software; if not, see
# https://www.gnu.org/licenses/gpl-3.0.txt.
#
"""Script for running qpc command line tool"""

import gettext
import os
import sys
import site
from distutils.sysconfig import get_python_lib


def get_path_from_site(pkg_path):
"""Find possible development location based on site package"""
link_path = os.path.join(pkg_path, 'quipucords.egg-link')
if os.path.isfile(link_path):
with open(link_path, 'r') as link_file:
result = link_file.read().splitlines()
for location in result:
code_path = os.path.join(location, 'quipucords')
sys.path.insert(0, os.path.join(code_path))


get_path_from_site(get_python_lib())

try:
for site_pkg in site.getsitepackages():
get_path_from_site(site_pkg)
except AttributeError:
pass

BASE_QPC_DIR = os.path.abspath(
os.path.normpath(
os.path.join(os.path.dirname(sys.argv[0]), '..')))

sys.path.insert(0, os.path.join(BASE_QPC_DIR, 'quipucords'))

# pylint: disable=wrong-import-position
from cli.cli import CLI # noqa

gettext.install('qpc')

if __name__ == "__main__":
CLI().main()
2 changes: 2 additions & 0 deletions quipucords/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# pylint: disable=missing-docstring
__version__ = '0.0.1'
16 changes: 16 additions & 0 deletions quipucords/cli/auth/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env python
#
# Copyright (c) 2017 Red Hat, Inc.
#
# This software is licensed to you under the GNU General Public License,
# version 3 (GPLv3). There is NO WARRANTY for this software, express or
# implied, including the implied warranties of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv3
# along with this software; if not, see
# https://www.gnu.org/licenses/gpl-3.0.txt.
#
""" Constants for the Auth commands
"""

SUBCOMMAND = 'auth'
ADD = 'add'
45 changes: 45 additions & 0 deletions quipucords/cli/auth/add.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env python
#
# Copyright (c) 2017 Red Hat, Inc.
#
# This software is licensed to you under the GNU General Public License,
# version 3 (GPLv3). There is NO WARRANTY for this software, express or
# implied, including the implied warranties of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv3
# along with this software; if not, see
# https://www.gnu.org/licenses/gpl-3.0.txt.
#
""" AuthAddCommand is used to add authentication credentials
for system access
"""

from __future__ import print_function
import sys
from cli.clicommand import CliCommand
import cli.auth as auth


# pylint: disable=too-few-public-methods
class AuthAddCommand(CliCommand):
"""
This command is for creating new auths which can be later associated with
profiles to gather facts.
"""
SUBCOMMAND = auth.SUBCOMMAND
ACTION = auth.ADD

def __init__(self, subparsers):
CliCommand.__init__(self, self.SUBCOMMAND, self.ACTION)
self.parser = subparsers.add_parser(self.ACTION)
self.parser.add_argument('--name', dest='name', metavar='NAME',
help='auth credential name')

def _validate_args(self):
CliCommand._validate_args(self)

if not self.args.name:
self.parser.print_help()
sys.exit(1)

def _do_command(self):
print('Auth "%s" was added' % self.args.name)
59 changes: 59 additions & 0 deletions quipucords/cli/auth/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#
# Copyright (c) 2017 Red Hat, Inc.
#
# This software is licensed to you under the GNU General Public License,
# version 3 (GPLv3). There is NO WARRANTY for this software, express or
# implied, including the implied warranties of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv3
# along with this software; if not, see
# https://www.gnu.org/licenses/gpl-3.0.txt.
#
"""Test the CLI module"""

import contextlib
import unittest
import sys
import six
from cli.cli import CLI


# pylint: disable=too-few-public-methods
class HushUpStderr(object):
"""Class used to quiet standard error output"""
def write(self, stream):
"""Ignore standard error output"""
pass


@contextlib.contextmanager
def redirect_stdout(stream):
"""Run a code block, capturing stdout to the given stream"""

old_stdout = sys.stdout
try:
sys.stdout = stream
yield
finally:
sys.stdout = old_stdout


class AuthCliTests(unittest.TestCase):
"""Class for testing the auth cli commands for qpc"""
def setUp(self):
# Temporarily disable stderr for these tests, CLI errors clutter up
# nosetests command.
self.orig_stderr = sys.stderr
sys.stderr = HushUpStderr()

def tearDown(self):
# Restore stderr
sys.stderr = self.orig_stderr

def test_add_auth(self):
"""Testing the add auth command"""
auth_out = six.StringIO()
with redirect_stdout(auth_out):
sys.argv = ['/bin/qpc', 'auth', 'add', '--name', 'auth1']
CLI().main()
self.assertEqual(auth_out.getvalue(),
'Auth "auth1" was added\n')
65 changes: 65 additions & 0 deletions quipucords/cli/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!/usr/bin/env python
#
# Copyright (c) 2017 Red Hat, Inc.
#
# This software is licensed to you under the GNU General Public License,
# version 3 (GPLv3). There is NO WARRANTY for this software, express or
# implied, including the implied warranties of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv3
# along with this software; if not, see
# https://www.gnu.org/licenses/gpl-3.0.txt.
#
""" Quipucords Command Line Interface """

from __future__ import print_function
from argparse import ArgumentParser
import cli.auth as auth
from cli.auth.add import AuthAddCommand
from . import __version__


# pylint: disable=too-few-public-methods
class CLI(object):
"""Class responsible for displaying ussage or matching inputs
to the valid set of commands supported by rho.
"""
def __init__(self, name="cli", usage=None, shortdesc=None,
description=None):
self.shortdesc = shortdesc
if shortdesc is not None and description is None:
description = shortdesc
self.parser = ArgumentParser(usage=usage, description=description)
self.parser.add_argument('--version', action='version',
version=__version__)

self.subparsers = self.parser.add_subparsers(dest='subcommand')
self.name = name
self.args = None
self.subcommands = {}
self._add_subcommand(auth.SUBCOMMAND, [AuthAddCommand])

def _add_subcommand(self, subcommand, actions):
subcommand_parser = self.subparsers.add_parser(subcommand)
action_subparsers = subcommand_parser.add_subparsers(dest='action')
self.subcommands[subcommand] = {}
for action in actions:
action_inst = action(action_subparsers)
action_dic = self.subcommands[action.SUBCOMMAND]
action_dic[action.ACTION] = action_inst

def main(self):
"""Method determine whether to display usage or pass input
to find the best command match. If no match is found the
usage is displayed
"""
self.args = self.parser.parse_args()

if self.args.subcommand in self.subcommands:
subcommand = self.subcommands[self.args.subcommand]
if self.args.action in subcommand:
action = subcommand[self.args.action]
action.main(self.args)
else:
self.parser.print_help()
else:
self.parser.print_help()
48 changes: 48 additions & 0 deletions quipucords/cli/clicommand.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/usr/bin/env python
#
# Copyright (c) 2017 Red Hat, Inc.
#
# This software is licensed to you under the GNU General Public License,
# version 3 (GPLv3). There is NO WARRANTY for this software, express or
# implied, including the implied warranties of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv3
# along with this software; if not, see
# https://www.gnu.org/licenses/gpl-3.0.txt.
#
""" Base CLI Command Class """

from __future__ import print_function


# pylint: disable=too-few-public-methods
class CliCommand(object):

""" Base class for all sub-commands. """
def __init__(self, subcommand, action):
self.subcommand = subcommand
self.action = action
self.args = None

def _validate_args(self):
"""
Sub-commands can override to do any argument validation they
require.
"""
pass

def _do_command(self):
"""
Sub-commands define this method to perform the
required action once all options have been verified.
"""
pass

def main(self, args):
"""
The method that does a basic check for command
validity and set's the process in motion.
"""
self.args = args
self._validate_args()

self._do_command()
59 changes: 59 additions & 0 deletions quipucords/cli/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#
# Copyright (c) 2017 Red Hat, Inc.
#
# This software is licensed to you under the GNU General Public License,
# version 3 (GPLv3). There is NO WARRANTY for this software, express or
# implied, including the implied warranties of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv3
# along with this software; if not, see
# https://www.gnu.org/licenses/gpl-3.0.txt.
#
"""Test the CLI module"""

import contextlib
import unittest
import sys
import six
from cli.cli import CLI


# pylint: disable=too-few-public-methods
class HushUpStderr(object):
"""Class used to quiet standard error output"""
def write(self, stream):
"""Ignore standard error output"""
pass


@contextlib.contextmanager
def redirect_stdout(stream):
"""Run a code block, capturing stdout to the given stream"""

old_stdout = sys.stdout
try:
sys.stdout = stream
yield
finally:
sys.stdout = old_stdout


class CliTests(unittest.TestCase):
"""Class for testing the base cli arguments for qpc"""
def setUp(self):
# Temporarily disable stderr for these tests, CLI errors clutter up
# nosetests command.
self.orig_stderr = sys.stderr
sys.stderr = HushUpStderr()

def tearDown(self):
# Restore stderr
sys.stderr = self.orig_stderr

def test_version(self):
"""Testing the verion argument"""
version_out = six.StringIO()
with self.assertRaises(SystemExit):
with redirect_stdout(version_out):
sys.argv = ['/bin/qpc', '--version']
CLI().main()
self.assertEqual(version_out.getvalue(), '0.0.1')
Loading

0 comments on commit 7e6e6b4

Please sign in to comment.