Skip to content

Commit

Permalink
new cli publish command
Browse files Browse the repository at this point in the history
Signed-off-by: Sebastian Wojciechowski <s.wojciechowski89@gmail.com>
  • Loading branch information
sebwoj committed Aug 28, 2018
1 parent 54d704e commit 0fb9ba8
Show file tree
Hide file tree
Showing 2 changed files with 228 additions and 0 deletions.
47 changes: 47 additions & 0 deletions fedora_messaging/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,23 @@
"scheme://user:pass@host:port/virtual_host?key=value&key=value. Consult "
"the pika documentation for the supported query string parameters."
)
_topic_help = (
"The topic of the message. Can contain ASCII letters, digits, "
"hyphen, underscore, period, or colon."
)
_body_key_help = (
"The key of the first message body item. Can contain ASCII letters, digits, "
"hyphen, underscore, period, or colon."
)
_body_value_help = (
"The value of the first message body item. Can contain ASCII letters, digits, "
"hyphen, underscore, period, or colon."
)
_publish_exchange_help = (
"The name of the exchange to publish to. Can contain ASCII letters, "
"digits, hyphen, underscore, period, or colon. If one is not specified, the "
"default is the ``amq.topic`` exchange."
)


@click.group()
Expand Down Expand Up @@ -157,3 +174,33 @@ def consume(amqp_url, exchange, queue_name, routing_key, callback, app_name):
str(e.reason),
)
sys.exit(e.exit_code)


@cli.command()
@click.option("--publish-exchange", help=_publish_exchange_help)
@click.option("--body-key", help=_body_key_help)
@click.option("--body-value", help=_body_value_help)
@click.option("--topic", help=_topic_help)
def publish(topic, body_key, body_value, publish_exchange):
"""
Send a simple message to an AMQP queue.
"""
if (body_key and not body_value) or (not body_key and body_value):
raise click.ClickException(
"You must define both body_key or body_value"
"or none of them to omit message body"
)
_log.info("Sending message")
if topic:
_log.info("message topic: %s", topic)
if body_key:
_log.info("message body: %s", str({body_key: body_value}))
message = api.Message(topic=topic, body={body_key: body_value})
try:
return api.publish(message, publish_exchange)
except exceptions.PublishReturned as e:
_log.error("Unable to publish message: %s", str(e.reason))
sys.exit(1)
except exceptions.ConnectionException as e:
_log.error("Unable to connect to queue: %s", str(e.reason))
sys.exit(1)
181 changes: 181 additions & 0 deletions fedora_messaging/tests/unit/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,3 +346,184 @@ def test_consume_halt_without_exitcode(self, mock_consume, mock_importlib):
mock_importlib.import_module.called_once_with("mod")
mock_consume.assert_called_once_with(mock_mod_with_callable.callable, "b")
self.assertEqual(0, result.exit_code)


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

def setUp(self):
self.runner = CliRunner()

@mock.patch("fedora_messaging.cli.api.Message")
@mock.patch("fedora_messaging.cli.api.publish")
def test_no_conf(self, mock_publish, mock_message):
"""Assert not providing a configuration file via the CLI works."""
mock_message.return_value = mock_message
result = self.runner.invoke(cli.cli, ["publish"])
mock_message.assert_called_once_with(topic=None, body={None: None})
mock_publish.assert_called_once_with(mock_message, None)
self.assertEqual(0, result.exit_code)

@mock.patch("fedora_messaging.cli.api.Message")
@mock.patch("fedora_messaging.cli.api.publish")
def test_good_conf(self, mock_publish, mock_message):
"""Assert providing a configuration file via the CLI works."""
mock_message.return_value = mock_message
result = self.runner.invoke(cli.cli, ["--conf=" + GOOD_CONF, "publish"])
mock_message.assert_called_once_with(topic=None, body={None: None})
mock_publish.assert_called_once_with(mock_message, None)
self.assertEqual(0, result.exit_code)

@mock.patch("fedora_messaging.cli.api.Message")
@mock.patch("fedora_messaging.cli.api.publish")
def test_conf_env_support(self, mock_publish, mock_message):
"""Assert FEDORA_MESSAGING_CONF environment variable is supported."""
mock_message.return_value = mock_message
result = self.runner.invoke(
cli.cli, ["publish"], env={"FEDORA_MESSAGING_CONF": GOOD_CONF}
)
mock_message.assert_called_once_with(topic=None, body={None: None})
mock_publish.assert_called_with(mock_message, None)
self.assertEqual(0, result.exit_code)

@mock.patch("fedora_messaging.cli.api.publish")
def test_bad_conf(self, mock_publish):
"""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)
)
result = self.runner.invoke(cli.cli, ["--conf=" + BAD_CONF, "publish"])
self.assertEqual(2, result.exit_code)
self.assertIn(expected_err, result.output)

@mock.patch("fedora_messaging.cli.api.publish")
def test_missing_conf(self, mock_publish):
"""Assert a missing configuration file is reported."""
result = self.runner.invoke(cli.cli, ["--conf=thispathdoesnotexist", "publish"])
self.assertEqual(2, result.exit_code)
self.assertIn(
"Error: Invalid value: thispathdoesnotexist is not a file", result.output
)

@mock.patch("fedora_messaging.cli.api.Message")
@mock.patch("fedora_messaging.cli.api.publish")
def test_good_topic_and_body(self, mock_publish, mock_message):
"""Assert providing message topic and body via the CLI works."""
cli_options = {"topic": "t", "body-key": "bk", "body-value": "bv"}
mock_message.return_value = mock_message
result = self.runner.invoke(
cli.cli,
[
"--conf=" + GOOD_CONF,
"publish",
"--topic=" + cli_options["topic"],
"--body-key=" + cli_options["body-key"],
"--body-value=" + cli_options["body-value"],
],
)
mock_message.assert_called_once_with(
topic=cli_options["topic"],
body={cli_options["body-key"]: cli_options["body-value"]},
)
mock_publish.assert_called_once_with(mock_message, None)
self.assertEqual(0, result.exit_code)

@mock.patch("fedora_messaging.cli.api.Message")
@mock.patch("fedora_messaging.cli.api.publish")
def test_good_topic_and_improper_body(self, mock_publish, mock_message):
"""Assert a missing body option is reported."""
cli_options = {"topic": "t", "body-key": "bk", "body-value": "bv"}
mock_message.return_value = mock_message
# Missing cli option "body-value"
result = self.runner.invoke(
cli.cli,
[
"--conf=" + GOOD_CONF,
"publish",
"--topic=" + cli_options["topic"],
"--body-key=" + cli_options["body-key"],
],
)
self.assertIn(
"You must define both body_key or body_value"
"or none of them to omit message body",
result.output,
)
mock_message.assert_not_called()
mock_publish.assert_not_called()
self.assertEqual(1, result.exit_code)
# Missing cli option "body-value"
result = self.runner.invoke(
cli.cli,
[
"--conf=" + GOOD_CONF,
"publish",
"--topic=" + cli_options["topic"],
"--body-value=" + cli_options["body-value"],
],
)
self.assertIn(
"You must define both body_key or body_value"
"or none of them to omit message body",
result.output,
)
mock_message.assert_not_called()
mock_publish.assert_not_called()
self.assertEqual(1, result.exit_code)

@mock.patch("fedora_messaging.cli.api.Message")
@mock.patch("fedora_messaging.cli.api.publish")
def test_publish_rejected_message(self, mock_publish, mock_message):
"""Assert a rejected message is reported."""
cli_options = {"topic": "t", "body-key": "bk", "body-value": "bv"}
error_message = "Message rejected"
mock_message.return_value = mock_message
mock_publish.side_effect = exceptions.PublishReturned(error_message)
result = self.runner.invoke(
cli.cli,
[
"--conf=" + GOOD_CONF,
"publish",
"--topic=" + cli_options["topic"],
"--body-key=" + cli_options["body-key"],
"--body-value=" + cli_options["body-value"],
],
)
self.assertIn(
"Unable to publish message: {}".format(error_message), result.output
)
mock_message.assert_called_once_with(
topic=cli_options["topic"],
body={cli_options["body-key"]: cli_options["body-value"]},
)
mock_publish.assert_called_once_with(mock_message, None)
self.assertEqual(1, result.exit_code)

@mock.patch("fedora_messaging.cli.api.Message")
@mock.patch("fedora_messaging.cli.api.publish")
def test_publish_connection_failed(self, mock_publish, mock_message):
"""Assert a connection problem is reported."""
cli_options = {"topic": "t", "body-key": "bk", "body-value": "bv"}
error_message = "Connection failure"
mock_message.return_value = mock_message
mock_publish.side_effect = exceptions.ConnectionException(error_message)
result = self.runner.invoke(
cli.cli,
[
"--conf=" + GOOD_CONF,
"publish",
"--topic=" + cli_options["topic"],
"--body-key=" + cli_options["body-key"],
"--body-value=" + cli_options["body-value"],
],
)
self.assertIn(
"Unable to connect to queue: {}".format(error_message), result.output
)
mock_message.assert_called_once_with(
topic=cli_options["topic"],
body={cli_options["body-key"]: cli_options["body-value"]},
)
mock_publish.assert_called_once_with(mock_message, None)
self.assertEqual(1, result.exit_code)

0 comments on commit 0fb9ba8

Please sign in to comment.