Mobilizon-Reshare-condividi.../tests/commands/test_start.py

323 lines
10 KiB
Python

from logging import DEBUG, INFO
import pytest
from mobilizon_reshare.config.command import CommandConfig
from mobilizon_reshare.dataclasses import EventPublicationStatus
from mobilizon_reshare.dataclasses import MobilizonEvent
from mobilizon_reshare.dataclasses.event import get_all_mobilizon_events
from mobilizon_reshare.main.start import start
from mobilizon_reshare.models.event import Event
from mobilizon_reshare.models.publication import PublicationStatus
from tests.commands.conftest import simple_event_element, second_event_element
one_published_event_specification = {
"event": 1,
"publications": [
{"event_idx": 0, "publisher_idx": 0, "status": PublicationStatus.COMPLETED}
],
"publisher": ["telegram", "twitter", "mastodon", "zulip"],
}
@pytest.mark.asyncio
@pytest.mark.parametrize(
"dry_run", [True, False]
) # the behavior should be identical with and without dry-run
@pytest.mark.parametrize(
"elements", [[]],
)
async def test_start_no_event(
mock_mobilizon_success_answer, mobilizon_answer, caplog, elements, dry_run
):
with caplog.at_level(DEBUG):
assert await start(CommandConfig(dry_run=dry_run)) is None
assert "No event to publish found" in caplog.text
@pytest.mark.parametrize(
"publisher_class", [pytest.lazy_fixture("mock_publisher_class")]
)
@pytest.mark.asyncio
@pytest.mark.parametrize(
"elements",
[[simple_event_element()], [simple_event_element(), simple_event_element()]],
)
async def test_start_new_event(
mock_mobilizon_success_answer,
mobilizon_answer,
caplog,
mock_publisher_config,
message_collector,
elements,
command_config,
):
with caplog.at_level(DEBUG):
# calling the start command
assert await start(command_config) is not None
# since the mobilizon_answer contains at least one result, one event to publish must be found and published
# by the publisher coordinator
assert "Event to publish found" in caplog.text
assert message_collector == [
"test event|Some description",
]
all_events = (
await Event.all()
.prefetch_related("publications")
.prefetch_related("publications__publisher")
)
# the start command should save all the events in the database
assert len(all_events) == len(elements), all_events
# it should create a publication for each publisher
publications = all_events[0].publications
assert len(publications) == 1, publications
# all the other events should have no publication
for e in all_events[1:]:
assert len(e.publications) == 0, e.publications
# all the publications for the first event should be saved as COMPLETED
for p in publications[1:]:
assert p.status == PublicationStatus.COMPLETED
# the derived status for the event should be COMPLETED
assert (
MobilizonEvent.from_model(all_events[0]).status
== EventPublicationStatus.COMPLETED
)
@pytest.mark.asyncio
@pytest.mark.parametrize(
"publisher_class", [pytest.lazy_fixture("mock_publisher_class")]
)
@pytest.mark.parametrize(
"elements", [[]],
)
async def test_start_event_from_db(
mock_mobilizon_success_answer,
mobilizon_answer,
caplog,
mock_publisher_config,
message_collector,
event_generator,
command_config,
):
event = event_generator()
event_model = event.to_model()
await event_model.save()
with caplog.at_level(DEBUG):
# calling the start command
result = await start(command_config)
assert result.successful
assert len(result.reports) == 1
assert (
result.reports[0].published_content == "test event|description of the event"
)
# since the db contains at least one event, this has to be picked and published
assert "Event to publish found" in caplog.text
assert message_collector == [
"test event|description of the event",
]
await event_model.fetch_related("publications", "publications__publisher")
# it should create a publication for each publisher
publications = event_model.publications
assert len(publications) == 1, publications
# all the publications for the first event should be saved as COMPLETED
for p in publications:
assert p.status == PublicationStatus.COMPLETED
# the derived status for the event should be COMPLETED
assert (
MobilizonEvent.from_model(event_model).status
== EventPublicationStatus.COMPLETED
)
@pytest.mark.asyncio
@pytest.mark.parametrize(
"publisher_class", [pytest.lazy_fixture("mock_publisher_invalid_class")]
)
@pytest.mark.parametrize(
"elements", [[]],
)
async def test_start_publisher_failure(
mock_mobilizon_success_answer,
mobilizon_answer,
caplog,
mock_publisher_config,
message_collector,
event_generator,
mock_notifier_config,
command_config,
):
event = event_generator()
event_model = event.to_model()
await event_model.save()
with caplog.at_level(DEBUG):
# calling the start command
result = await start(command_config)
assert not result.successful
assert len(result.reports) == 1
assert result.reports[0].published_content is None
# since the db contains at least one event, this has to be picked and published
await event_model.fetch_related("publications", "publications__publisher")
# it should create a publication for each publisher
publications = event_model.publications
assert len(publications) == 1, publications
# all the publications for event should be saved as FAILED
for p in publications:
assert p.status == PublicationStatus.FAILED
assert p.reason == "credentials error"
assert "Event to publish found" in caplog.text
assert message_collector == [
f"Publication {p.id} failed with status: FAILED."
f"\nReason: credentials error\nPublisher: mock\nEvent: test event"
for p in publications
for _ in range(2)
] # 2 publications failed * 2 notifiers
# the derived status for the event should be FAILED
assert (
MobilizonEvent.from_model(event_model).status
== EventPublicationStatus.FAILED
)
@pytest.mark.asyncio
@pytest.mark.parametrize(
"publisher_class", [pytest.lazy_fixture("mock_publisher_class")]
)
@pytest.mark.parametrize(
"elements", [[second_event_element()]],
)
async def test_start_second_execution(
mock_mobilizon_success_answer,
mobilizon_answer,
caplog,
mock_publisher_config,
message_collector,
generate_models,
command_config,
):
await generate_models(one_published_event_specification)
# I clean the message collector
message_collector.data = []
with caplog.at_level(INFO):
# calling the start command
assert await start(command_config) is not None
# verify that the second event gets published
assert "Event to publish found" in caplog.text
assert message_collector == [
"event_1|desc_1",
]
# I verify that the db event and the new event coming from mobilizon are both in the db
assert len(list(await get_all_mobilizon_events())) == 2
@pytest.mark.parametrize(
"publisher_class", [pytest.lazy_fixture("mock_publisher_class")]
)
@pytest.mark.asyncio
@pytest.mark.parametrize(
"elements",
[[simple_event_element()], [simple_event_element(), simple_event_element()]],
)
async def test_start_dry_run(
mock_mobilizon_success_answer,
mobilizon_answer,
caplog,
mock_publisher_config,
message_collector,
elements,
):
with caplog.at_level(DEBUG):
# calling the start command
result = await start(CommandConfig(dry_run=True))
assert result.successful
assert len(result.reports) == 1
assert result.reports[0].published_content == "test event|Some description"
assert "Event to publish found" in caplog.text
assert (
"Executing in dry run mode. No event is going to be published."
in caplog.text
)
assert (
message_collector == []
) # the configured publisher shouldn't be called if in dry run mode
all_events = (
await Event.all()
.prefetch_related("publications")
.prefetch_related("publications__publisher")
)
# the start command should save all the events in the database
assert len(all_events) == len(elements), all_events
# it should create no publication
publications = all_events[0].publications
assert len(publications) == 0, publications
@pytest.mark.parametrize(
"publisher_class", [pytest.lazy_fixture("mock_publisher_class")]
)
@pytest.mark.asyncio
@pytest.mark.parametrize(
"elements",
[[simple_event_element()], [simple_event_element(), simple_event_element()]],
)
async def test_start_dry_run_second_execution(
mock_mobilizon_success_answer,
mobilizon_answer,
caplog,
mock_publisher_config,
message_collector,
elements,
):
with caplog.at_level(DEBUG):
# calling the start command in dry_run
assert await start(CommandConfig(dry_run=True)) is not None
assert "Event to publish found" in caplog.text
assert (
"Executing in dry run mode. No event is going to be published."
in caplog.text
)
assert (
message_collector == []
) # the configured publisher shouldn't be called if in dry run mode
# calling the start command in normal mode
assert await start(CommandConfig(dry_run=False)) is not None
assert message_collector == [
"test event|Some description"
] # the publisher should now have published one message
all_events = (
await Event.all()
.prefetch_related("publications")
.prefetch_related("publications__publisher")
)
# verify that the dry run doesn't mistakenly does double saves
assert len(all_events) == len(elements), all_events