MiniApp / tests /test_max_api.py
Dink0
Read public MAX post views through Bot API
72f0375
Raw History Blame Contribute Delete
4.22 kB
import os
import time
import unittest
from unittest.mock import Mock, patch
import 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)
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()