Source code for tests.login_tests

#!/usr/bin/env python3
"""
Tests for LoginManager classes.

e.g. used to test password-file based login.
"""
#
# (C) Pywikibot team, 2012-2022
#
# Distributed under the terms of the MIT license.
#
from __future__ import annotations

from collections import defaultdict
from io import StringIO
from unittest import mock

from pywikibot.exceptions import NoUsernameError
from pywikibot.login import LoginManager
from tests.aspects import DefaultDrySiteTestCase, unittest


[docs] class FakeFamily: """Mock.""" name = '~FakeFamily'
[docs] class FakeSite: """Mock.""" code = '~FakeCode' family = FakeFamily
FakeUsername = '~FakeUsername'
[docs] class FakeConfig: """Mock.""" usernames = defaultdict(dict) usernames[FakeFamily.name] = {FakeSite.code: FakeUsername}
[docs] @mock.patch('pywikibot.Site', FakeSite) @mock.patch('pywikibot.login.config', FakeConfig) class TestOfflineLoginManager(DefaultDrySiteTestCase): """Test offline operation of login.LoginManager.""" dry = True
[docs] def test_default_init(self): """Test initialization of LoginManager without parameters.""" obj = LoginManager() self.assertIsInstance(obj.site, FakeSite) self.assertEqual(obj.username, FakeUsername) self.assertEqual(obj.login_name, FakeUsername) self.assertIsNone(obj.password)
[docs] @mock.patch.dict( FakeConfig.usernames, {'*': {'*': FakeUsername}}, clear=True ) def test_star_family(self): """Test LoginManager with '*' as family.""" lm = LoginManager() self.assertEqual(lm.username, FakeUsername) del FakeConfig.usernames['*'] FakeConfig.usernames['*']['en'] = FakeUsername error_undefined_username = 'ERROR: username for.*is undefined.\nIf' with self.assertRaisesRegex( NoUsernameError, error_undefined_username): LoginManager() FakeConfig.usernames['*']['*'] = FakeUsername lm = LoginManager() self.assertEqual(lm.username, FakeUsername)
[docs] @mock.patch('pywikibot.Site', FakeSite) class TestPasswordFile(DefaultDrySiteTestCase): """Test parsing password files."""
[docs] def patch(self, name): """Patch up <name> in self.setUp.""" patcher = mock.patch(name) self.addCleanup(patcher.stop) return patcher.start()
[docs] def setUp(self): """Patch a variety of dependencies.""" super().setUp() self.config = self.patch('pywikibot.login.config') self.config.usernames = FakeConfig.usernames self.config.password_file = '~FakeFile' self.config.private_files_permission = 0o600 self.config.base_dir = '' # ensure that no path modifies password_file self.stat = self.patch('os.stat') self.stat.return_value.st_mode = 0o100600 self.chmod = self.patch('os.chmod') self.open = self.patch('codecs.open') self.open.return_value = StringIO()
[docs] def test_auto_chmod_OK(self): """Do not chmod files that have mode private_files_permission.""" self.stat.return_value.st_mode = 0o100600 LoginManager() self.stat.assert_called_with(self.config.password_file) self.assertFalse(self.chmod.called)
[docs] def test_auto_chmod_not_OK(self): """Chmod files that do not have mode private_files_permission.""" self.stat.return_value.st_mode = 0o100644 LoginManager() self.stat.assert_called_with(self.config.password_file) self.chmod.assert_called_once_with( self.config.password_file, 0o600 )
def _test_pwfile(self, contents, password): self.open.return_value = StringIO(contents) obj = LoginManager() self.assertEqual(obj.password, password) return obj
[docs] def test_none_matching(self): """No matching passwords.""" self._test_pwfile(""" ('NotTheUsername', 'NotThePassword') """, None)
[docs] def test_match_global_username(self): """Test global username/password declaration.""" self._test_pwfile(""" ('~FakeUsername', '~FakePassword') """, '~FakePassword')
[docs] def test_match_family_username(self): """Test matching by family.""" self._test_pwfile(""" ('~FakeFamily', '~FakeUsername', '~FakePassword') """, '~FakePassword')
[docs] def test_match_code_username(self): """Test matching by full configuration.""" self._test_pwfile(""" ('~FakeCode', '~FakeFamily', '~FakeUsername', '~FakePassword') """, '~FakePassword')
[docs] def test_ordering(self): """Test that the last matching password is selected.""" self._test_pwfile(""" ('~FakeCode', '~FakeFamily', '~FakeUsername', '~FakePasswordA') ('~FakeUsername', '~FakePasswordB') """, '~FakePasswordB') self._test_pwfile(""" ('~FakeUsername', '~FakePasswordA') ('~FakeCode', '~FakeFamily', '~FakeUsername', '~FakePasswordB') """, '~FakePasswordB')
[docs] def test_BotPassword(self): """Test BotPassword entries. When a BotPassword is used, the login_name changes to contain a suffix, while the password is read from an object (instead of being read from the password file directly). """ obj = self._test_pwfile(""" ('~FakeUsername', BotPassword('~FakeSuffix', '~FakePassword')) """, '~FakePassword') self.assertEqual(obj.login_name, '~FakeUsername@~FakeSuffix')
if __name__ == '__main__': unittest.main()