def test_to_json_and_back(mock_client):
    test_watcher_file = "./test_subscription_watcher.json"
    if os.path.exists(test_watcher_file):
        os.remove(test_watcher_file)
    old_filename = SubscriptionWatcher.FILENAME
    SubscriptionWatcher.FILENAME = test_watcher_file
    api = MockExportAPI()
    latest_submissions = [
        SubmissionBuilder(submission_id="123243").build_short_submission(),
        SubmissionBuilder(submission_id="123242").build_short_submission(),
        SubmissionBuilder(submission_id="123240").build_short_submission()
    ]
    subscription1 = Subscription("query", 1234)
    subscription2 = Subscription("example", 5678)
    watcher = SubscriptionWatcher(api, mock_client)
    watcher._update_latest_ids(latest_submissions)
    watcher.subscriptions.add(subscription1)
    watcher.subscriptions.add(subscription2)
    watcher.blocklists[3452] = {"test", "example"}
    watcher.blocklists[1453] = {"ych"}

    try:
        watcher.save_to_json()
        new_watcher = SubscriptionWatcher.load_from_json(api, mock_client)

        assert len(new_watcher.latest_ids) == 3
        assert "123243" in new_watcher.latest_ids
        assert "123242" in new_watcher.latest_ids
        assert "123240" in new_watcher.latest_ids
        assert list(watcher.latest_ids) == list(new_watcher.latest_ids)
        assert len(new_watcher.subscriptions) == 2
        list_subs = list(new_watcher.subscriptions)
        if list_subs[0].query_str == "query":
            assert list_subs[0].destination == 1234
            assert list_subs[1].query_str == "example"
            assert list_subs[1].destination == 5678
        else:
            assert list_subs[0].query_str == "example"
            assert list_subs[0].destination == 5678
            assert list_subs[1].query_str == "query"
            assert list_subs[1].destination == 1234
        assert len(new_watcher.blocklists) == 2
        assert 3452 in new_watcher.blocklists
        assert len(new_watcher.blocklists[3452]) == 2
        assert isinstance(new_watcher.blocklists[3452], set)
        assert "test" in new_watcher.blocklists[3452]
        assert "example" in new_watcher.blocklists[3452]
        assert 1453 in new_watcher.blocklists
        assert len(new_watcher.blocklists[1453]) == 1
        assert isinstance(new_watcher.blocklists[1453], set)
        assert "ych" in new_watcher.blocklists[1453]
    finally:
        SubscriptionWatcher.FILENAME = old_filename
        os.remove(test_watcher_file)
示例#2
0
async def test_ignore_channel_post(mock_client):
    post_id = 23636984
    event = MockTelegramEvent.with_channel_post(
        text=f"https://www.furaffinity.net/view/{post_id}/")
    submission = MockSubmission(post_id)
    neaten = NeatenFunctionality(MockExportAPI())
    neaten.api.with_submission(submission)

    await neaten.call(event)

    submission._send_message.assert_not_called()
def test_remove_sub__non_existent_subscription(mock_client):
    api = MockExportAPI()
    watcher = SubscriptionWatcher(api, mock_client)
    watcher.subscriptions.add(Subscription("example", 18749))
    watcher.subscriptions.add(Subscription("test", 18747))
    func = SubscriptionFunctionality(watcher)

    resp = func._remove_sub(18749, "test")

    assert resp == "There is not a subscription for \"test\" in this chat."
    assert len(watcher.subscriptions) == 2
async def test_query_not_id_or_link():
    post_id = 12345
    sub = MockSubmission(post_id)
    event = MockTelegramEvent.with_inline_query(query="test")
    inline = InlineNeatenFunctionality(MockExportAPI().with_submissions(
        [MockSubmission(12344), sub,
         MockSubmission(12346)]))

    await inline.call(event)

    event.answer.assert_not_called()
示例#5
0
async def test_deleted_submission_group_chat(mock_client):
    post_id = 23636984
    event = MockTelegramEvent.with_message(
        text="furaffinity.net/view/{}".format(post_id),
        chat_type=ChatType.GROUP)
    neaten = NeatenFunctionality(MockExportAPI())

    with pytest.raises(StopPropagation):
        await neaten.call(event)

    event.reply.assert_called_with("⏳ Neatening image link")
    event.reply.return_value.delete.assert_called_once()
async def test_send_updates__deleted_pauses_subs(mock_client):
    api = MockExportAPI()
    watcher = SubscriptionWatcher(api, mock_client)
    subscription = Subscription("test", 12345)
    watcher.subscriptions.add(subscription)
    submission = SubmissionBuilder().build_mock_submission()
    submission.send_message = lambda *args, **kwargs: (_ for _ in ()).throw(
        InputUserDeactivatedError(None))

    await watcher._send_updates([subscription], submission)

    assert subscription.paused
def test_update_latest_ids(mock_client):
    api = MockExportAPI()
    watcher = SubscriptionWatcher(api, mock_client)
    id_list = ["1234", "1233", "1230", "1229"]
    submissions = [MockSubmission(x) for x in id_list]
    mock_save_json = MockMethod()
    watcher.save_to_json = mock_save_json.call

    watcher._update_latest_ids(submissions)

    assert list(watcher.latest_ids) == id_list
    assert mock_save_json.called
示例#8
0
async def test_submission_link_in_group_caption(mock_client):
    post_id = 23636984
    event = MockTelegramEvent.with_message(
        chat_type=ChatType.GROUP,
        text=f"https://www.furaffinity.net/view/{post_id}/").with_document()
    submission = MockSubmission(post_id)
    neaten = NeatenFunctionality(MockExportAPI())
    neaten.api.with_submission(submission)

    await neaten.call(event)

    submission._send_message.assert_not_called()
示例#9
0
async def test_deleted_submission(mock_client):
    post_id = 23636984
    event = MockTelegramEvent.with_message(
        text="furaffinity.net/view/{}".format(post_id))
    neaten = NeatenFunctionality(MockExportAPI())

    with pytest.raises(StopPropagation):
        await neaten.call(event)

    event.reply.assert_called_with(
        f"This doesn't seem to be a valid FA submission: https://www.furaffinity.net/view/{post_id}/"
    )
async def test_submission_direct_link__not_found():
    post_id = 12345
    username = "******"
    sub = MockSubmission(post_id, username=username)
    event = MockTelegramEvent.with_inline_query(query=sub.download_url)
    inline = InlineNeatenFunctionality(MockExportAPI().with_user_folder(
        username, "gallery",
        [MockSubmission(12344), MockSubmission(12346)]))

    await inline.call(event)

    event.answer.assert_not_called()
def test_save_to_json(mock_client):
    test_watcher_file = "./test_subscription_watcher.json"
    if os.path.exists(test_watcher_file):
        os.remove(test_watcher_file)
    api = MockExportAPI()
    latest_submissions = [
        SubmissionBuilder(submission_id="123243").build_short_submission(),
        SubmissionBuilder(submission_id="123242").build_short_submission(),
        SubmissionBuilder(submission_id="123240").build_short_submission()
    ]
    subscription1 = Subscription("query", 1234)
    subscription2 = Subscription("example", 5678)
    watcher = SubscriptionWatcher(api, mock_client)
    watcher._update_latest_ids(latest_submissions)
    watcher.subscriptions.add(subscription1)
    watcher.subscriptions.add(subscription2)
    watcher.blocklists[3452] = {"test", "example"}
    watcher.blocklists[1453] = {"ych"}
    watcher.FILENAME = test_watcher_file

    try:
        watcher.save_to_json()

        assert os.path.exists(test_watcher_file)
        with open(test_watcher_file, "r") as f:
            data = json.load(f)
        assert data is not None
        assert len(data['latest_ids']) == 3
        assert "123240" in data['latest_ids']
        assert "123242" in data['latest_ids']
        assert "123243" in data['latest_ids']
        assert len(data["destinations"]) == 4
        assert len(data["destinations"]["1234"]["subscriptions"]) == 1
        assert data["destinations"]["1234"]["subscriptions"][0][
            "query"] == "query"
        assert len(data["destinations"]["1234"]["blocks"]) == 0

        assert len(data["destinations"]["5678"]["subscriptions"]) == 1
        assert data["destinations"]["5678"]["subscriptions"][0][
            "query"] == "example"
        assert len(data["destinations"]["5678"]["blocks"]) == 0

        assert len(data["destinations"]["3452"]["subscriptions"]) == 0
        assert len(data["destinations"]["3452"]["blocks"]) == 2
        assert set([
            block["query"] for block in data["destinations"]["3452"]["blocks"]
        ]) == {"test", "example"}

        assert len(data["destinations"]["1453"]["subscriptions"]) == 0
        assert len(data["destinations"]["1453"]["blocks"]) == 1
        assert data["destinations"]["1453"]["blocks"][0]["query"] == "ych"
    finally:
        os.remove(test_watcher_file)
def test_list_subs__alphabetical_case_insensitive(mock_client):
    api = MockExportAPI()
    watcher = SubscriptionWatcher(api, mock_client)
    watcher.subscriptions.add(Subscription("Example", 18749))
    watcher.subscriptions.add(Subscription("test", 18749))
    watcher.subscriptions.add(Subscription("deer", 18749))
    func = SubscriptionFunctionality(watcher)

    resp = func._list_subs(18749)

    assert "Current subscriptions in this chat:" in resp
    assert "- deer\n- Example\n- test" in resp
def test_migrate_no_block_queries(mock_client):
    old_chat_id = 12345
    new_chat_id = 54321
    api = MockExportAPI()
    watcher = SubscriptionWatcher(api, mock_client)
    watcher.subscriptions.add(MockSubscription("ych", old_chat_id))

    watcher.migrate_chat(old_chat_id, new_chat_id)

    assert len(watcher.subscriptions) == 1
    sub = list(watcher.subscriptions)[0]
    assert sub.query_str == "ych"
    assert sub.destination == new_chat_id
def test_remove_from_blocklist__tag_not_in_blocklist(mock_client):
    api = MockExportAPI()
    watcher = SubscriptionWatcher(api, mock_client)
    watcher.blocklists[18749] = {"example"}
    watcher.blocklists[18747] = {"test"}
    func = BlocklistFunctionality(watcher)

    resp = func._remove_from_blocklist(18749, "test")

    assert resp == "The tag \"test\" is not on the blocklist for this chat."
    assert len(watcher.blocklists) == 2
    assert len(watcher.blocklists[18749]) == 1
    assert len(watcher.blocklists[18747]) == 1
def test_list_blocklisted_tags(mock_client):
    api = MockExportAPI()
    watcher = SubscriptionWatcher(api, mock_client)
    watcher.blocklists[18749] = {"example", "deer"}
    watcher.blocklists[18747] = {"test"}
    func = BlocklistFunctionality(watcher)

    resp = func._list_blocklisted_tags(18749)

    assert "Current blocklist for this chat:" in resp
    assert "- deer" in resp
    assert "- example" in resp
    assert "- test" not in resp
示例#16
0
def test_pause_subscription__one_matching_in_wrong_destination(mock_client):
    api = MockExportAPI()
    watcher = SubscriptionWatcher(api, mock_client)
    watcher.subscriptions.add(Subscription("example", 18749))
    watcher.subscriptions.add(Subscription("test", 12345))
    func = SubscriptionFunctionality(watcher)

    resp = func._pause_subscription(18749, "test")

    assert resp == "There is not a subscription for \"test\" in this chat."
    assert len(watcher.subscriptions) == 2
    for subscription in watcher.subscriptions:
        assert subscription.paused is False
async def test_run__is_stopped_by_running_false(mock_client):
    api = MockExportAPI()
    s = SubscriptionWatcher(api, mock_client)
    # Shorten the wait
    s.BACK_OFF = 1

    task = asyncio.get_event_loop().create_task(watcher_killer(s))

    # Run watcher
    await s.run()

    assert True
    await task
def test_list_subs__some_paused(mock_client):
    api = MockExportAPI()
    watcher = SubscriptionWatcher(api, mock_client)
    watcher.subscriptions.add(Subscription("example", 18749))
    sub_paused = Subscription("test", 18749)
    sub_paused.paused = True
    watcher.subscriptions.add(sub_paused)
    watcher.subscriptions.add(Subscription("deer", 18749))
    func = SubscriptionFunctionality(watcher)

    resp = func._list_subs(18749)

    assert "Current subscriptions in this chat:" in resp
    assert "- deer\n- example\n- ⏸<s>test</s>" in resp
async def test_run__calls_get_new_results(mock_client):
    api = MockExportAPI()
    watcher = SubscriptionWatcher(api, mock_client)
    method_called = MockMethod([])
    watcher._get_new_results = method_called.async_call
    # Shorten the wait
    watcher.BACK_OFF = 1

    task = asyncio.get_event_loop().create_task(watcher_killer(watcher))
    # Run watcher
    await watcher.run()
    await task

    assert method_called.called
def test_list_subs(mock_client):
    api = MockExportAPI()
    watcher = SubscriptionWatcher(api, mock_client)
    watcher.subscriptions.add(Subscription("example", 18749))
    watcher.subscriptions.add(Subscription("test", 18747))
    watcher.subscriptions.add(Subscription("deer", 18749))
    func = SubscriptionFunctionality(watcher)

    resp = func._list_subs(18749)

    assert "Current subscriptions in this chat:" in resp
    assert "- deer" in resp
    assert "- example" in resp
    assert "- test" not in resp
示例#21
0
async def test_unknown_type_submission_groupchat(mock_client):
    post_id = 23636984
    event = MockTelegramEvent.with_message(
        text="https://www.furaffinity.net/view/{}/".format(post_id),
        chat_type=ChatType.GROUP)
    submission = MockSubmission(post_id, file_ext="zzz")
    neaten = NeatenFunctionality(MockExportAPI())
    neaten.api.with_submission(submission)

    with pytest.raises(StopPropagation):
        await neaten.call(event)

    event.reply.assert_called_with("⏳ Neatening image link", )
    event.reply.return_value.delete.assert_called_once()
示例#22
0
async def test_inline_edit_functionality(mock_client):
    post_id = 1234
    event = MockTelegramEvent.with_inline_send(result_id=str(post_id))
    sub = MockSubmission(1234)
    api = MockExportAPI().with_submission(sub)
    func = InlineEditFunctionality(api, mock_client)

    await func.call(event)

    sub._send_message.assert_called_once()
    args, kwargs = sub._send_message.call_args
    assert args[0] == mock_client
    assert args[1] == event.msg_id
    assert kwargs['reply_to'] is None
    assert kwargs['edit'] is True
async def test_send_updates__sends_message(mock_client):
    api = MockExportAPI()
    watcher = SubscriptionWatcher(api, mock_client)
    subscription = Subscription("test", 12345)
    submission = SubmissionBuilder().build_mock_submission()

    await watcher._send_updates([subscription], submission)

    assert submission._send_message.asset_called_once()
    args, kwargs = submission._send_message.call_args
    assert args[0] == mock_client
    assert args[1] == 12345
    assert "update" in kwargs['prefix'].lower()
    assert "\"test\"" in kwargs['prefix']
    assert "subscription" in kwargs['prefix'].lower()
示例#24
0
async def test_inline_button_press(mock_client):
    callback = MockTelegramEvent.with_callback_query(
        data=b"neaten_me:1234",
        client=mock_client).with_inline_id(12345, 5431)
    sub = MockSubmission(1234)
    api = MockExportAPI().with_submission(sub)
    func = InlineEditButtonPress(api)

    await func.call(callback)

    sub._send_message.assert_called_once()
    args, kwargs = sub._send_message.call_args
    assert args[0] == mock_client
    assert args[1] == callback.original_update.msg_id
    assert kwargs['reply_to'] is None
    assert kwargs['edit'] is True
示例#25
0
async def test_call__route_pause_destination_with_handle(mock_client):
    event = MockTelegramEvent.with_message(chat_id=14358, text="/pause@FASearchBot")
    api = MockExportAPI()
    watcher = SubscriptionWatcher(api, mock_client)
    func = SubscriptionFunctionality(watcher)
    pause_dest = MockMethod("Paused all subscriptions")
    func._pause_destination = pause_dest.call

    with pytest.raises(StopPropagation):
        await func.call(event)

    assert pause_dest.called
    assert pause_dest.args is not None
    assert pause_dest.args[0] == event.chat_id
    event.reply.assert_called()
    assert event.reply.call_args[0][0] == "Paused all subscriptions"
async def test_run__can_exit_fast(mock_client):
    api = MockExportAPI()
    watcher = SubscriptionWatcher(api, mock_client)
    # Shorten the wait
    watcher.BACK_OFF = 3

    task = asyncio.get_event_loop().create_task(watcher_killer(watcher))

    # Run watcher
    start_time = datetime.datetime.now()
    await watcher.run()
    end_time = datetime.datetime.now()
    await task

    time_waited = end_time - start_time
    assert time_waited.seconds <= 1
示例#27
0
async def test_submission_link_in_caption(mock_client):
    post_id = 23636984
    event = MockTelegramEvent.with_message(client=mock_client).with_photo(
        caption=f"https://www.furaffinity.net/view/{post_id}/")
    submission = MockSubmission(post_id)
    neaten = NeatenFunctionality(MockExportAPI())
    neaten.api.with_submission(submission)

    with pytest.raises(StopPropagation):
        await neaten.call(event)

    submission._send_message.assert_called_once()
    args, kwargs = submission._send_message.call_args
    assert args[0] == mock_client
    assert args[1] == event.input_chat
    assert kwargs['reply_to'] == event.message.id
async def test_send_updates__blocked_pauses_other_subs(mock_client):
    api = MockExportAPI()
    watcher = SubscriptionWatcher(api, mock_client)
    subscription1 = Subscription("test", 12345)
    subscription2 = Subscription("other", 12345)
    subscription3 = Subscription("not me", 54321)
    watcher.subscriptions = {subscription1, subscription2, subscription3}
    submission = SubmissionBuilder().build_mock_submission()
    submission.send_message = lambda *args, **kwargs: (_ for _ in ()).throw(
        UserIsBlockedError(None))

    await watcher._send_updates([subscription1], submission)

    assert subscription1.paused
    assert subscription2.paused
    assert not subscription3.paused
示例#29
0
async def test_call__route_resume_destination(mock_client):
    event = MockTelegramEvent.with_message(chat_id=14358, text="/resume")
    api = MockExportAPI()
    watcher = SubscriptionWatcher(api, mock_client)
    func = SubscriptionFunctionality(watcher)
    resume_dest = MockMethod("Resumed all subscriptions")
    func._resume_destination = resume_dest.call

    with pytest.raises(StopPropagation):
        await func.call(event)

    assert resume_dest.called
    assert resume_dest.args is not None
    assert resume_dest.args[0] == event.chat_id
    event.reply.assert_called()
    assert event.reply.call_args[0][0] == "Resumed all subscriptions"
示例#30
0
def test_resume_subscription__no_matching(mock_client):
    api = MockExportAPI()
    watcher = SubscriptionWatcher(api, mock_client)
    sub1 = Subscription("example", 18749)
    sub1.paused = True
    watcher.subscriptions.add(sub1)
    sub2 = Subscription("deer", 18749)
    sub2.paused = True
    watcher.subscriptions.add(sub2)
    func = SubscriptionFunctionality(watcher)

    resp = func._resume_subscription(18749, "test")

    assert resp == "There is not a subscription for \"test\" in this chat."
    assert len(watcher.subscriptions) == 2
    for subscription in watcher.subscriptions:
        assert subscription.paused is True