Skip to content

integration tests for webhook #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions action_triggers/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""

import json
import logging
import typing as _t
from functools import partial

Expand All @@ -19,6 +20,8 @@
from action_triggers.models import Config
from action_triggers.webhooks import WebhookProcessor

logger = logging.getLogger(__name__)


def signal_callback(
instance: _t.Type[Model],
Expand All @@ -44,18 +47,19 @@ def signal_callback(
)

for config in configs:
print("Signal triggered for config:", config)
logger.debug(f"Signal triggered for config: {config}")
payload = json.dumps(config.payload)

for webhook in config.webhooks.all():
WebhookProcessor(webhook, instance).process()
WebhookProcessor(webhook, payload).process()

for broker in config.message_broker_queues.all():
broker_class = get_broker_class(broker.name)
broker_class(
broker.name,
broker.conn_details,
broker.parameters,
).send_message(json.dumps(config.payload))
).send_message(payload)


def setup() -> None:
Expand Down
14 changes: 14 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,17 @@ def customer_kafka_post_save_signal(
customer_post_save_signal,
kafka_1_trigger,
)


@pytest.fixture
def customer_webhook_post_save_signal(
config,
config_add_customer_ct,
customer_post_save_signal,
webhook,
):
return namedtuple("ConfigContext", ["config", "signal", "trigger"])(
config,
customer_post_save_signal,
webhook,
)
66 changes: 65 additions & 1 deletion tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,23 @@

from unittest.mock import patch

import pytest
import responses
from model_bakery import baker

from action_triggers.registry import add_to_registry
from tests.models import CustomerModel
from tests.utils import get_rabbitmq_conn
from tests.utils import (
can_connect_to_kafka,
can_connect_to_rabbitmq,
get_rabbitmq_conn,
)


@pytest.mark.skipif(
not can_connect_to_rabbitmq(),
reason="Cannot connect to RabbitMQ",
)
class TestIntegrationMessageBrokerRabbitMQ:
"""Integration tests where the action to be triggered is sending a payload
to a RabbitMQ message broker.
Expand Down Expand Up @@ -51,6 +61,10 @@ def test_simple_basic_plain_message(
assert body.decode() == '"Hello World!"'


@pytest.mark.skipif(
not can_connect_to_kafka(),
reason="Cannot connect to Kafka",
)
class TestIntegrationMessageBrokerKafka:
"""Integration tests where the action to be triggered is sending a payload
to a Kafka message broker.
Expand All @@ -70,3 +84,53 @@ def test_simple_basic_json_message(
add_to_registry(CustomerModel)
baker.make(CustomerModel)
mock_send_message_impl.assert_called_once()


class TestIntegrationWebhook:
"""Integration tests where the action to be triggered is sending a payload
to a webhook.
"""

@responses.activate
def test_simple_basic_json_message(
self,
customer_webhook_post_save_signal,
):
add_to_registry(CustomerModel)

responses.add(
responses.POST,
"https://example.com/",
json={"success": "True"},
)

baker.make(CustomerModel)

assert len(responses.calls) == 1
assert responses.calls[0].request.url == "https://example.com/"
assert (
responses.calls[0].request.body == '{"message": "Hello, World!"}'
)

@responses.activate
def test_simple_basic_plain_message(
self,
customer_webhook_post_save_signal,
):
config = customer_webhook_post_save_signal.config
config.payload = "Hello World!"
config.save()

add_to_registry(CustomerModel)

responses.add(
responses.POST,
"https://example.com/",
json={"success": "True"},
)

baker.make(CustomerModel)

assert len(responses.calls) == 1
assert responses.calls[0].request.url == "https://example.com/"
assert responses.calls[0].request.body == '"Hello World!"'
16 changes: 5 additions & 11 deletions tests/test_message_broker_kafka.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,7 @@

from action_triggers.message_broker.exceptions import ConnectionValidationError
from action_triggers.message_broker.kafka import KafkaBroker, KafkaConnection
from tests.utils import get_kafka_conn


def conn_test() -> bool:
"""Verify that a connection can be made to Kafka."""
try:
get_kafka_conn()
return True
except Exception:
return False
from tests.utils import can_connect_to_kafka


class TestKafkaConnection:
Expand Down Expand Up @@ -51,7 +42,10 @@ def test_requires_topic(self):
params={},
)

@pytest.mark.skipif(not conn_test(), reason="Kafka is not running.")
@pytest.mark.skipif(
not can_connect_to_kafka(),
reason="Kafka is not running.",
)
def test_message_can_be_sent(self):
"""It should be able to send a message to Kafka."""
broker = KafkaBroker(
Expand Down
30 changes: 14 additions & 16 deletions tests/test_signals.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""Tests for the `signals` module."""

import logging

import pytest
from django.contrib.contenttypes.models import ContentType
from model_bakery import baker
Expand All @@ -13,45 +15,42 @@
class TestSignal:
"""Tests that the signals are connected to the callback function."""

def test_signal_callback_prints_message(self, capsys):
def test_signal_callback_prints_message(self, caplog):
caplog.set_level(logging.DEBUG)
add_to_registry(CustomerModel)
add_to_registry(CustomerOrderModel)
config = baker.make(Config)
config.content_types.add(
ContentType.objects.get_for_model(CustomerModel)
)
baker.make(ConfigSignal, config=config, signal=SignalChoices.POST_SAVE)

CustomerModel.create_record()

captured = capsys.readouterr()
assert "Signal triggered for config:" in captured.out
assert "Signal triggered for config:" in caplog.text

def test_action_does_not_run_for_inactive_message(self, capsys):
def test_action_does_not_run_for_inactive_message(self, caplog):
caplog.set_level(logging.DEBUG)
add_to_registry(CustomerModel)
add_to_registry(CustomerOrderModel)
config = baker.make(Config, active=False)
config.content_types.add(
ContentType.objects.get_for_model(CustomerModel)
)
baker.make(ConfigSignal, config=config, signal=SignalChoices.POST_SAVE)

CustomerModel.create_record()

captured = capsys.readouterr()
assert captured.out == ""
assert "Signal triggered for config:" not in caplog.text

def test_does_not_trigger_action_for_unregistered_model(self, capsys):
def test_does_not_trigger_action_for_unregistered_model(self, caplog):
caplog.set_level(logging.DEBUG)
config = baker.make(Config)
config.content_types.add(
ContentType.objects.get_for_model(CustomerOrderModel)
)
baker.make(ConfigSignal, config=config, signal=SignalChoices.POST_SAVE)

CustomerModel.create_record()

captured = capsys.readouterr()
assert captured.out == ""
assert "Signal triggered for config:" not in caplog.text

@pytest.mark.parametrize(
"signal_choice",
Expand All @@ -63,16 +62,15 @@ def test_does_not_trigger_action_for_unregistered_model(self, capsys):
def test_action_not_triggered_for_unassociated_signals(
self,
signal_choice,
capsys,
caplog,
):
caplog.set_level(logging.DEBUG)
add_to_registry(CustomerModel)
config = baker.make(Config)
config.content_types.add(
ContentType.objects.get_for_model(CustomerModel)
)
baker.make(ConfigSignal, config=config, signal=signal_choice)

CustomerModel.create_record()

captured = capsys.readouterr()
assert captured.out == ""
assert "Signal triggered for config:" not in caplog.text
28 changes: 28 additions & 0 deletions tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,31 @@ def get_kafka_producer(key: str = "kafka_1"):
yield producer

producer.close()


def can_connect_to_rabbitmq() -> bool:
"""Check if the service can connect to RabbitMQ.

Returns:
bool: True if the service can connect to RabbitMQ, False otherwise
"""

try:
with get_rabbitmq_conn():
return True
except pika.exceptions.ProbableAuthenticationError:
return False


def can_connect_to_kafka() -> bool:
"""Check if the service can connect to Kafka.

Returns:
bool: True if the service can connect to Kafka, False otherwise
"""

try:
with get_kafka_conn():
return True
except Exception:
return False