示例#1
0
def test_retries_temporary_email_failures(_):
    class FailOnceMail:
        def __init__(self):
            self.call_count = 0

        def send(self, _):
            self.call_count += 1
            if self.call_count == 1:
                return SendEmailResult(SendEmailState.TEMPORARY_FAILURE,
                                       "oops")
            return SendEmailResult(SendEmailState.SUCCESS)

    mail = FailOnceMail()
    _send_emails(
        mail,
        Mock(),
        logging.create_dev_logger(),
        [OutgoingEmail("", "", "", 0, "", "")],
        0,
    )
    _send_emails(
        mail,
        Mock(),
        logging.create_dev_logger(),
        [OutgoingEmail("", "", "", 1, "", "")],
        0,
    )
    assert mail.call_count == 3
示例#2
0
def test_service_keeps_css_classes_if_writing_to_fs(mock_template_store,
                                                    tmp_path):
    mail = FsMail("", logging.create_dev_logger(), tmp_path)
    db = MockDB(is_initialized=True)
    settings = MockSettings(worker=MockWorker(), mail=mail, db=db)
    service(settings, Mock())
    assert mock_template_store.call_args.kwargs["keep_css_classes"] is True
示例#3
0
def test_processes_with_minimal_context_if_full_context_error():
    event = {
        "isSecure": True,
        "timestamp": 0,
        "context": {
            "thisContextIsMissingProperties": True,
        },
        "minimalContext": {
            "revision": {
                "revisionId": 1,
                "link": "link",
            },
            "recipients": [{
                "username": "******",
                "email": "2@mail",
                "timezoneOffset": 0,
                "isActor": False,
            }],
        },
    }
    mail = MockMail()
    render = Render(JinjaTemplateStore("", "", False))
    logger = logging.create_dev_logger()
    with spy_on(mail.send) as spy:
        process_event(event, render, MockThreadStore(), logger, 0, Mock(),
                      mail)
        assert len(spy.calls) == 1
        assert spy.calls[0].args[0].template_path == "minimal"
def test_ses():
    client = Mock()
    mail = SesMail(client, "from@mail", logging.create_dev_logger(), None)
    mail.send([MOCK_EMAIL])
    ses_kwargs = client.send_raw_email.call_args.kwargs
    assert ses_kwargs["Destinations"] == ["to@mail"]
    assert ses_kwargs["Source"] == "from@mail"
    assert "phabricator subject" in ses_kwargs["RawMessage"]["Data"]
    assert "summary in html" in ses_kwargs["RawMessage"]["Data"]
    assert "summary in text" in ses_kwargs["RawMessage"]["Data"]
示例#5
0
def test_parse_fs_mail(tmp_path):
    config = _config_parser("""
    [email]
    from_address=from@mail
    implementation=fs
    [email-fs]
    "output_path={tmp_path}
    """)
    mail = _parse_mail(config, logging.create_dev_logger())
    assert isinstance(mail, FsMail)
示例#6
0
def _parse_logger(config: ConfigParser):
    """Provides a logger set up according to our configuration.

    The regular logger is noisy and implements the MozLog JSON format, so we also
    have a "dev" logger that simply prints out each log without any annotations.
    The correct logger is chosen based on the provided configuration file.
    """
    if config.has_section("dev"):
        return create_dev_logger()
    else:
        return create_logger()
def test_smtp():
    smtp_server = Mock()
    mail = SmtpMail(smtp_server, "from@mail", logging.create_dev_logger(), None)
    mail.send([MOCK_EMAIL])
    smtp_server.sendmail.assert_called_with(
        "from@mail", "to@mail", mock.ANY,
    )
    mime_message = smtp_server.sendmail.call_args.args[2]
    assert "phabricator subject" in mime_message
    assert "summary in html" in mime_message
    assert "summary in text" in mime_message
示例#8
0
def test_poll_caught_up():
    position = QueryPosition()
    position.up_to_key = 10

    def pipeline(*unused):
        return 10

    worker = PhabricatorWorker(create_dev_logger(), 60, False)
    caught_up = worker._poll(MockQueryPositionStore(position=position),
                             MockThreadStore(), pipeline)
    assert caught_up is True
示例#9
0
def test_poll_fresh_events():
    position = QueryPosition()
    position.up_to_key = 10

    def pipeline(*unused):
        return 20

    worker = PhabricatorWorker(create_dev_logger(), 60)
    caught_up = worker._poll(
        MockQueryPositionStore(position=position), MockThreadStore(), pipeline
    )
    assert caught_up is False
    assert position.up_to_key == 20
示例#10
0
def test_pipeline_updates_position_even_if_no_new_events():
    # Sometimes, a feed event may happen that isn't relevant to emails. Phabricator
    # will report a newer feed position while returning an empty event list.
    source = MockSource(next_result={
        "data": {
            "events": [],
            "storyErrors": 0
        },
        "cursor": {
            "after": 20
        }
    })
    logger = logging.create_dev_logger()
    pipeline = Pipeline(source, Mock(), MockMail(), logger, 0, Mock(), False)
    new_position = pipeline.run(MockThreadStore(), 10)
    assert new_position == 20
示例#11
0
def test_integration_pipeline():
    source = MockSource(
        next_result={
            "data": {
                "storyErrors":
                0,
                "events": [
                    {
                        "isSecure": True,
                        "timestamp": 0,
                        "context": {
                            "eventKind": "revision-reclaimed",
                            "actor": {
                                "userName": "******",
                                "realName": "1"
                            },
                            "body": {
                                "reviewers": [
                                    {
                                        "name":
                                        "2",
                                        "isActionable":
                                        False,
                                        "status":
                                        "accepted",
                                        "recipients": [{
                                            "timezoneOffset": 0,
                                            "username": "******",
                                            "email": "2@mail",
                                            "isActor": False,
                                        }],
                                    },
                                    {
                                        "name":
                                        "3",
                                        "isActionable":
                                        True,
                                        "status":
                                        "requested-changes",
                                        "recipients": [{
                                            "timezoneOffset": 0,
                                            "username": "******",
                                            "email": "3@mail",
                                            "isActor": False,
                                        }],
                                    },
                                ],
                                "subscribers": [{
                                    "email": "3@mail",
                                    "username": "******",
                                    "timezoneOffset": 0,
                                    "isActor": False,
                                }],
                                "commentCount":
                                1,
                                "transactionLink":
                                "link",
                            },
                            "revision": {
                                "revisionId": 1,
                                "repositoryName": "repo",
                                "link": "link",
                                "bug": {
                                    "bugId": 1,
                                    "link": "link"
                                },
                            },
                        },
                    },
                    {
                        "isSecure": False,
                        "timestamp": 1,
                        "context": {
                            "eventKind": "revision-abandoned",
                            "actor": {
                                "userName": "******",
                                "realName": "4"
                            },
                            "body": {
                                "reviewers": [{
                                    "username": "******",
                                    "email": "5@mail",
                                    "timezoneOffset": 0,
                                    "isActor": False,
                                }],
                                "subscribers": [],
                                "mainCommentMessage": {
                                    "asText": "Main comment",
                                    "asHtml": "<p>Main comment</p>",
                                },
                                "inlineComments": [{
                                    "contextKind": "code",
                                    "context": {
                                        "diff": [{
                                            "lineNumber": 10,
                                            "type": "added",
                                            "rawContent": "hello world",
                                        }]
                                    },
                                    "fileContext": "/README:20",
                                    "link": "link",
                                    "message": {
                                        "asText": "great content here.",
                                        "asHtml":
                                        "<em>great content here.</em>",
                                    },
                                }],
                                "transactionLink":
                                "link",
                            },
                            "revision": {
                                "revisionId": 2,
                                "name": "name 2",
                                "repositoryName": "repo",
                                "link": "link",
                            },
                        },
                    },
                ],
            },
            "cursor": {
                "after": 20
            },
        })
    mail = MockMail()
    render = Render(JinjaTemplateStore("", "", False))
    logger = logging.create_dev_logger()
    pipeline = Pipeline(source, render, mail, logger, 0, Mock(), False)
    with spy_on(mail.send) as send_spy, spy_on(source.fetch_next) as fetch_spy:
        new_position = pipeline.run(MockThreadStore(), 10)
        assert new_position == 20
        assert fetch_spy.calls[0].args[0] == 10

        emails = []
        for call in send_spy.calls:
            emails.append(call.args[0])

    _assert_mail(
        emails[0],
        "D1: (secure bug 1)",
        "2@mail",
        "1 reclaimed this revision that you've accepted and submitted a comment.",
    )
    _assert_mail(
        emails[1],
        "D1: (secure bug 1)",
        "3@mail",
        "1 reclaimed this revision and submitted a comment.",
    )
    _assert_mail(
        emails[2],
        "D2: name 2",
        "5@mail",
        "4 abandoned this revision and submitted comments.",
    )
示例#12
0
def test_retries_failed_full_sends_with_minimal_emails(send_emails_fn):
    event = {
        "timestamp": 0,
        "isSecure": True,
        "context": {
            "eventKind": "revision-reclaimed",
            "actor": {
                "userName": "******",
                "realName": "1"
            },
            "body": {
                "reviewers": [{
                    "name":
                    "2",
                    "isActionable":
                    False,
                    "status":
                    "unreviewed",
                    "recipients": [
                        {
                            "username": "******",
                            "email": "2@mail",
                            "timezoneOffset": 0,
                            "isActor": False,
                        },
                        {
                            "username": "******",
                            "email": "3@mail",
                            "timezoneOffset": 0,
                            "isActor": False,
                        },
                    ],
                }],
                "subscribers": [],
                "commentCount":
                1,
                "transactionLink":
                "link",
            },
            "revision": {
                "revisionId": 1,
                "link": "link",
                "bug": {
                    "bugId": 1,
                    "link": "link"
                },
            },
        },
        "minimalContext": {
            "revision": {
                "revisionId": 1,
                "link": "link",
            },
            "recipients": [
                {
                    "username": "******",
                    "email": "2@mail",
                    "timezoneOffset": 0,
                    "isActor": False,
                },
                {
                    "username": "******",
                    "email": "3@mail",
                    "timezoneOffset": 0,
                    "isActor": False,
                },
            ],
        },
    }

    send_emails_fn.side_effect = [["2@mail"], []]
    render = Render(JinjaTemplateStore("", "", False))
    logger = logging.create_dev_logger()
    process_event(event, render, MockThreadStore(), logger, 0, Mock(), None)
    assert len(send_emails_fn.call_args_list) == 2
    assert len(send_emails_fn.call_args_list[1][0][3]) == 1
    _assert_mail(
        send_emails_fn.call_args_list[1][0][3][0],
        "D1",
        "2@mail",
        "An (unknown) action occurred",
    )
示例#13
0
def test_pipeline_returns_same_position_if_fetch_fails():
    source = MockSource(fail_on_fetch_next=True)
    pipeline = Pipeline(source, Mock(), Mock(), logging.create_dev_logger(), 0,
                        Mock(), False)
    assert pipeline.run(MockThreadStore(), 10) == 10