Skip to content

Commit

Permalink
Merge pull request #21 from jeremycline/cli-tests
Browse files Browse the repository at this point in the history
Add tests for the CLI
  • Loading branch information
jeremycline committed Aug 17, 2018
2 parents 7a99a24 + 3bbb12c commit a2783c8
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 13 deletions.
9 changes: 6 additions & 3 deletions fedora_messaging/cli.py
Expand Up @@ -24,6 +24,7 @@
import importlib
import logging
import logging.config
import os
import sys

import click
Expand Down Expand Up @@ -72,10 +73,12 @@
def cli(conf):
"""The fedora-messaging command line interface."""
if conf:
if not os.path.isfile(conf):
raise click.exceptions.BadParameter('{} is not a file'.format(conf))
try:
config.conf.load_config(config_path=conf)
except ValueError as e:
raise click.exceptions.BadParameter(e)
except exceptions.ConfigurationException as e:
raise click.exceptions.BadParameter(str(e))
config.conf.setup_logging()


Expand All @@ -87,7 +90,7 @@ def cli(conf):
@click.option('--exchange', help=_exchange_help)
@click.option('--amqp-url', help=_amqp_url_help)
def consume(amqp_url, exchange, queue_name, routing_key, callback, app_name):

"""Consume messages from an AMQP queue using a Python callback."""
amqp_url = amqp_url or config.conf['amqp_url']
if exchange and queue_name and routing_key:
bindings = [{
Expand Down
5 changes: 3 additions & 2 deletions fedora_messaging/config.py
Expand Up @@ -404,8 +404,9 @@ def load_config(self, config_path=None):
for key in file_config:
config[key.lower()] = file_config[key]
except pytoml.core.TomlError as e:
_log.error('Failed to parse {}: {}'.format(config_path, str(e)))
raise exceptions.ConfigurationException(e)
msg = 'Failed to parse {}: error at line {}, column {}'.format(
config_path, e.line, e.col)
raise exceptions.ConfigurationException(msg)
else:
_log.info('The configuration file, {}, does not exist.'.format(config_path))

Expand Down
14 changes: 13 additions & 1 deletion fedora_messaging/exceptions.py
Expand Up @@ -6,7 +6,19 @@ class BaseException(Exception):


class ConfigurationException(BaseException):
"""Raised when there's an invalid configuration setting"""
"""
Raised when there's an invalid configuration setting
Args:
message (str): A detailed description of the configuration problem
which is presented to the user.
"""

def __init__(self, message):
self.message = message

def __str__(self):
return 'Configuration error: ' + self.message


class PublishException(BaseException):
Expand Down
1 change: 1 addition & 0 deletions fedora_messaging/tests/fixtures/bad_conf.toml
@@ -0,0 +1 @@
publish_exchange = I forgot quotes here
6 changes: 6 additions & 0 deletions fedora_messaging/tests/fixtures/good_conf.toml
@@ -0,0 +1,6 @@
callback = "fedora_messaging.tests.unit.test_cli:echo"

[[bindings]]
exchange = "e"
queue_name = "q"
routing_key = "#"
87 changes: 87 additions & 0 deletions fedora_messaging/tests/unit/test_cli.py
@@ -0,0 +1,87 @@
# This file is part of fedora_messaging.
# Copyright (C) 2018 Red Hat, Inc.
#
# This program 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; either version 2 of the License, or
# (at your option) any later version.
#
# This program 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, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""Tests for the :module:`fedora_messaging.cli` module."""

import os
import unittest

from click.testing import CliRunner
import mock

from fedora_messaging import cli

FIXTURES_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '../fixtures/'))
GOOD_CONF = os.path.join(FIXTURES_DIR, 'good_conf.toml')
BAD_CONF = os.path.join(FIXTURES_DIR, 'bad_conf.toml')


def echo(message):
"""Echo the message received to standard output."""
print(str(message))


class BaseCliTests(unittest.TestCase):
"""Unit tests for the base command of the CLI."""

def test_no_conf(self):
"""Assert the CLI runs without exploding."""
runner = CliRunner()
result = runner.invoke(cli.cli)
assert result.exit_code == 0


class ConsumeCliTests(unittest.TestCase):
"""Unit tests for the 'consume' command of the CLI."""

@mock.patch('fedora_messaging.cli.api.consume')
def test_good_conf(self, mock_consume):
"""Assert providing a configuration file via the CLI works."""
runner = CliRunner()
result = runner.invoke(cli.cli, ['--conf=' + GOOD_CONF, 'consume'])
mock_consume.assert_called_with(
echo,
[{'exchange': 'e', 'queue_name': 'q', 'routing_key': '#'}])
self.assertEqual(0, result.exit_code)

@mock.patch('fedora_messaging.cli.api.consume')
def test_conf_env_support(self, mock_consume):
"""Assert FEDORA_MESSAGING_CONF environment variable is supported."""
runner = CliRunner()
result = runner.invoke(
cli.cli, ['consume'], env={'FEDORA_MESSAGING_CONF': GOOD_CONF})
mock_consume.assert_called_with(
echo,
[{'exchange': 'e', 'queue_name': 'q', 'routing_key': '#'}])
self.assertEqual(0, result.exit_code)

@mock.patch('fedora_messaging.cli.api.consume')
def test_bad_conf(self, mock_consume):
"""Assert a bad configuration file is reported."""
expected_err = ('Error: Invalid value: Configuration error: Failed to parse'
' {}: error at line 1, column 1'.format(BAD_CONF))
runner = CliRunner()
result = runner.invoke(cli.cli, ['--conf=' + BAD_CONF, 'consume'])
self.assertEqual(2, result.exit_code)
self.assertIn(expected_err, result.output)

@mock.patch('fedora_messaging.cli.api.consume')
def test_missing_conf(self, mock_consume):
"""Assert a missing configuration file is reported."""
runner = CliRunner()
result = runner.invoke(cli.cli, ['--conf=thispathdoesnotexist', 'consume'])
self.assertEqual(2, result.exit_code)
self.assertIn('Error: Invalid value: thispathdoesnotexist is not a file', result.output)
12 changes: 5 additions & 7 deletions fedora_messaging/tests/unit/test_config.py
Expand Up @@ -120,15 +120,13 @@ def test_invalid_key(self, mock_exists):
self.assertRaises(ConfigurationException, config.load_config)

@mock.patch('fedora_messaging.config.open', mock.mock_open(read_data='Ni!'))
@mock.patch('fedora_messaging.config._log', autospec=True)
@mock.patch('fedora_messaging.config.os.path.exists', return_value=True)
def test_bad_config_file(self, mock_exists, mock_log):
def test_bad_config_file(self, mock_exists):
"""Assert an invalid TOML file raises a ConfigurationException."""
self.assertRaises(ConfigurationException, msg_config.LazyConfig().load_config)
mock_log.info.assert_called_once_with(
'Loading configuration from /etc/fedora-messaging/config.toml')
error = 'Failed to parse /etc/fedora-messaging/config.toml: <string>(1, 1): msg'
self.assertEqual(error, mock_log.error.call_args_list[0][0][0])
with self.assertRaises(ConfigurationException) as cm:
msg_config.LazyConfig().load_config()
error = 'Failed to parse /etc/fedora-messaging/config.toml: error at line 1, column 1'
self.assertEqual(error, cm.exception.message)

@mock.patch('fedora_messaging.config.open', mock.mock_open(read_data=partial_config))
@mock.patch('fedora_messaging.config._log', autospec=True)
Expand Down

0 comments on commit a2783c8

Please sign in to comment.