renovate-ci / validate-renovate (push) Skipped
ci / lint-compose (push) Successful in 14s
ci / lint-actionlint (push) Successful in 8s
ci / lint-shellcheck (push) Successful in 9s
ci / lint-prettier (push) Successful in 18s
ci / lint-ruff (push) Successful in 10s
ci / lint-yaml (push) Successful in 13s
ci / lint-dockerfiles (push) Successful in 6s
ci / validate (push) Successful in 6s
ci / build (push) Skipped
ci / lint-compose (pull_request) Successful in 9s
ci / lint-actionlint (pull_request) Successful in 4s
ci / lint-shellcheck (pull_request) Successful in 7s
ci / lint-prettier (pull_request) Successful in 16s
ci / lint-ruff (pull_request) Successful in 9s
ci / lint-yaml (pull_request) Successful in 10s
ci / lint-dockerfiles (pull_request) Successful in 4s
ci / validate (pull_request) Successful in 6s
ci / build (pull_request) Skipped
renovate-ci / validate-renovate (pull_request) Successful in 8s
75 lines
3.0 KiB
Python
75 lines
3.0 KiB
Python
"""Session publication checks without Redis, the EDU website, or credentials."""
|
|
|
|
import importlib.util
|
|
import sys
|
|
import unittest
|
|
from pathlib import Path
|
|
from unittest.mock import Mock, patch
|
|
|
|
SCRIPT = Path(__file__).resolve().parents[1] / 'edu_master/phpsessid-bot/bot.py'
|
|
spec = importlib.util.spec_from_file_location('session_keeper', SCRIPT)
|
|
bot = importlib.util.module_from_spec(spec)
|
|
with patch.dict(sys.modules, {'redis': Mock(), 'requests': Mock()}):
|
|
spec.loader.exec_module(bot)
|
|
|
|
|
|
class SessionKeeperTests(unittest.TestCase):
|
|
def setUp(self):
|
|
self.session = Mock()
|
|
self.session.get.return_value.status_code = 200
|
|
self.session.cookies.get.return_value = 'test-cookie'
|
|
self.redis = Mock()
|
|
self.touch = patch.object(bot, 'touch_success_file').start()
|
|
self.addCleanup(patch.stopall)
|
|
|
|
def test_verified_cookie_expires_and_is_not_logged(self):
|
|
with self.assertLogs(bot.logger, level='INFO') as logs:
|
|
self.assertTrue(bot.refresh_session(self.session, self.redis))
|
|
self.redis.set.assert_called_once_with('EDU_PHPSESSID', 'test-cookie', ex=bot.INTERVAL * 120)
|
|
self.touch.assert_called_once()
|
|
self.assertNotIn('test-cookie', '\n'.join(logs.output))
|
|
self.assertEqual(self.session.post.call_args.kwargs['timeout'], (10, 30))
|
|
self.assertEqual(self.session.get.call_args.kwargs['timeout'], (10, 30))
|
|
|
|
def test_redirect_does_not_publish(self):
|
|
self.session.get.return_value.status_code = 302
|
|
self.assertFalse(bot.refresh_session(self.session, self.redis))
|
|
self.redis.set.assert_not_called()
|
|
self.touch.assert_not_called()
|
|
|
|
def test_missing_cookie_does_not_mark_success(self):
|
|
self.session.cookies.get.return_value = None
|
|
self.assertFalse(bot.refresh_session(self.session, self.redis))
|
|
self.redis.set.assert_not_called()
|
|
self.touch.assert_not_called()
|
|
|
|
def test_redis_failure_does_not_mark_success(self):
|
|
self.redis.set.side_effect = OSError('redis unavailable')
|
|
with self.assertRaises(OSError):
|
|
bot.refresh_session(self.session, self.redis)
|
|
self.touch.assert_not_called()
|
|
|
|
def test_http_timeout_does_not_publish(self):
|
|
self.session.post.side_effect = TimeoutError('EDU unavailable')
|
|
with self.assertRaises(TimeoutError):
|
|
bot.refresh_session(self.session, self.redis)
|
|
self.redis.set.assert_not_called()
|
|
self.touch.assert_not_called()
|
|
|
|
def test_missing_credentials_fail_before_network_access(self):
|
|
with patch.object(bot, 'LOGIN', None), self.assertRaises(ValueError):
|
|
bot.main()
|
|
|
|
def test_nonpositive_interval_fails_before_network_access(self):
|
|
with (
|
|
patch.object(bot, 'LOGIN', 'test'),
|
|
patch.object(bot, 'PASSWORD', 'test'),
|
|
patch.object(bot, 'INTERVAL', 0),
|
|
self.assertRaises(ValueError),
|
|
):
|
|
bot.main()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|