PR_Tool / tests /test_max_api.py
Dink0's picture
Compare MAX channel handles without case changes affecting post identity
080564e verified
Raw History Blame Contribute Delete
5.33 kB
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()