File size: 5,332 Bytes
ff3c435
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
080564e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ff3c435
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import os
import time
import unittest
from unittest.mock import Mock, patch

import legacy_parser as app
import max_api


URL = "https://max.ru/vkontakte/AaE-viFyB3E"
MID = "mid.ffffc217ccd5157d01a13ebe21720771"
PAGE = '''<meta content="Public &amp; news" property="og:title">
<script>app.start(element, {
data: [null,{type:"data",data:{linkInfo:{channel:{
title:"Public & news",description:"a } and [ inside text",
participantsCount:5287,channelId:68067500157571},message:{text:"post"}}}}],
form:null});</script>'''


def page_response():
    return Mock(status_code=200, text=PAGE)


class MaxPublicPostTests(unittest.TestCase):
    def test_hydration_and_message_id(self):
        title, channel_id = max_api.parse_public_post(PAGE, "vkontakte")
        self.assertEqual(title, "Public & news")
        self.assertEqual(channel_id, 68067500157571)
        self.assertEqual(max_api.message_id_from_link(channel_id, "AaE-viFyB3E"), MID)

    def test_missing_hydration_preserves_meta_title(self):
        title, channel_id = max_api.parse_public_post(
            '<meta property="og:title" content="Public &amp; news">', "vkontakte",
        )
        self.assertEqual(title, "Public & news")
        self.assertIsNone(channel_id)

    def test_bad_post_id_is_rejected(self):
        with self.assertRaises(ValueError):
            max_api.message_id_from_link(68067500157571, "bad")

    @patch.dict(os.environ, {"MAX_ACCESS_TOKEN": "test-token"})
    def test_public_post_views_and_credentials(self):
        session = Mock()
        session.get.side_effect = [page_response(), Mock(status_code=200, json=lambda: {
            "body": {"mid": MID}, "stat": {"views": 1197}, "url": URL,
        })]
        self.assertEqual(max_api.get_public_post(
            session, "vkontakte", "AaE-viFyB3E", URL, (5, 8),
        ), ("Public & news", 1197))
        public_request, api_request = session.get.call_args_list
        self.assertNotIn("headers", public_request.kwargs)
        self.assertEqual(api_request.args[0], max_api.API_BASE_URL + "/messages/" + MID)
        self.assertEqual(api_request.kwargs["headers"], {"Authorization": "test-token"})
        self.assertEqual(api_request.kwargs["verify"], max_api.CA_FILE)
        self.assertFalse(api_request.kwargs["allow_redirects"])

    @patch.dict(os.environ, {"MAX_ACCESS_TOKEN": "test-token"})
    def test_denied_and_missing_counter_are_unknown_not_zero(self):
        for response in [Mock(status_code=403), Mock(status_code=200, json=lambda: {
            "body": {"mid": MID}, "stat": {},
        }), Mock(status_code=200, json=lambda: {
            "body": {"mid": "different"}, "stat": {"views": 9999},
        })]:
            with self.subTest(status=response.status_code):
                session = Mock()
                session.get.side_effect = [page_response(), response]
                self.assertEqual(max_api.get_public_post(
                    session, "vkontakte", "AaE-viFyB3E", URL, (5, 8),
                ), ("Public & news", None))

    @patch.dict(os.environ, {"MAX_ACCESS_TOKEN": "test-token"})
    def test_real_zero_is_preserved(self):
        session = Mock()
        session.get.side_effect = [page_response(), Mock(status_code=200, json=lambda: {
            "body": {"mid": MID}, "stat": {"views": 0},
        })]
        self.assertEqual(max_api.get_public_post(
            session, "vkontakte", "AaE-viFyB3E", URL, (5, 8),
        )[1], 0)

    @patch.dict(os.environ, {"MAX_ACCESS_TOKEN": "test-token"})
    def test_case_only_channel_difference_keeps_exact_message_check(self):
        session = Mock()
        session.get.side_effect = [page_response(), Mock(status_code=200, json=lambda: {
            "body": {"mid": MID}, "stat": {"views": 1197},
            "url": "https://max.ru/VKONTAKTE/AaE-viFyB3E/",
        })]
        self.assertEqual(max_api.get_public_post(session, "vkontakte", "AaE-viFyB3E", URL, (5, 8))[1], 1197)

    def test_url_comparison_rejects_other_posts_and_hosts(self):
        for url in ["https://max.ru/vkontakte/aaE-viFyB3E",
                    "https://max.ru/other/AaE-viFyB3E",
                    "https://evil.test/vkontakte/AaE-viFyB3E",
                    "https://user:pass@max.ru/vkontakte/AaE-viFyB3E",
                    "https://max.ru:8443/vkontakte/AaE-viFyB3E"]:
            with self.subTest(url=url):
                self.assertFalse(max_api.same_public_post_url(url, URL))
        self.assertTrue(max_api.same_public_post_url("https://max.ru/Vkontakte/AaE-viFyB3E?from=share", URL))

    def test_output_keeps_max_counters_and_partial_sum(self):
        lines = [("max", URL, "vkontakte", "AaE-viFyB3E"),
                 ("max", "https://max.ru/other/AaE-viFyB3E", "other", "AaE-viFyB3E")]
        with patch.object(app, "resolve_max", return_value={
            URL: ("Public & news", 1197), lines[1][1]: ("Other", None),
        }):
            html, text, _, _, errors, max_count = app.build_output(lines, time.monotonic() + 10)
        self.assertIn("<b>1,2K</b>", html)
        self.assertIn("Public &amp; news", html)
        self.assertIn("1,2K", text)
        self.assertIn("Постов без данных о просмотрах: 1.", text)
        self.assertEqual(len(errors), 1)
        self.assertEqual(max_count, 2)


if __name__ == "__main__":
    unittest.main()