From 2a435965f97dd94dce9e4494c13286f0a39fd00f Mon Sep 17 00:00:00 2001 From: Julien Date: Mon, 22 Apr 2024 21:59:26 +0200 Subject: [PATCH] tests(usergroups): add unit tests against user groups module (#490) Following up #393 --- docs/jobs/profiles_downloader.md | 2 +- docs/jobs/profiles_manager.md | 2 +- docs/jobs/profiles_synchronizer.md | 3 +- tests/dev/dev_dulwich_remote.py | 2 +- tests/test_git_handler_remote.py | 36 ++++++++++------ tests/test_job_profiles_sync.py | 2 +- tests/test_utils_check_path.py | 50 +++++++++++----------- tests/test_utils_user_groups.py | 67 ++++++++++++++++++++++++++++++ 8 files changed, 120 insertions(+), 44 deletions(-) create mode 100644 tests/test_utils_user_groups.py diff --git a/docs/jobs/profiles_downloader.md b/docs/jobs/profiles_downloader.md index ef1ac7a6..a8d6def7 100644 --- a/docs/jobs/profiles_downloader.md +++ b/docs/jobs/profiles_downloader.md @@ -53,7 +53,7 @@ See this guide on [how to generate the qdt-files.json](../usage/profile.md#gener ### Profiles states -- `remote`: a profile stored outside the end-user computer, on a git repository, an HTTP server or a LAN drive. Typically: `https://gitlab.com/Oslandia/qgis/profils_qgis_fr_2022.git`. +- `remote`: a profile stored outside the end-user computer, on a git repository, an HTTP server or a LAN drive. Typically: `https://gitlab.com/Oslandia/qgis/profils_qgis_fr.git`. - `downloaded`: a profile downloaded into the QDT local working folder. Typically: `~/.cache/qgis-deployment-toolbelt/Oslandia/`. - `installed`: a profile's folder located into the QGIS profiles folder and so accessible to the end-user through the QGIS interface. Typically: `~/.local/share/QGIS/QGIS3/profiles/default` or `%APPDATA%/QGIS/QGIS3/profiles/default` diff --git a/docs/jobs/profiles_manager.md b/docs/jobs/profiles_manager.md index 13039f3f..d12972ee 100644 --- a/docs/jobs/profiles_manager.md +++ b/docs/jobs/profiles_manager.md @@ -66,7 +66,7 @@ If you use the HTTP procotol, a `qdt-files.json` must be downloadable at the URL ### Profiles states -- `remote`: a profile stored outside the end-user computer, on a git repository, an HTTP server or a LAN drive. Typically: `https://gitlab.com/Oslandia/qgis/profils_qgis_fr_2022.git`. +- `remote`: a profile stored outside the end-user computer, on a git repository, an HTTP server or a LAN drive. Typically: `https://gitlab.com/Oslandia/qgis/profils_qgis_fr.git`. - `downloaded`: a profile downloaded into the QDT local working folder. Typically: `~/.cache/qgis-deployment-toolbelt/Oslandia/`. - `installed`: a profile's folder located into the QGIS profiles folder and so accessible to the end-user through the QGIS interface. Typically: `~/.local/share/QGIS/QGIS3/profiles/default` or `%APPDATA%/QGIS/QGIS3/profiles/default` diff --git a/docs/jobs/profiles_synchronizer.md b/docs/jobs/profiles_synchronizer.md index a070edf5..acf5f166 100644 --- a/docs/jobs/profiles_synchronizer.md +++ b/docs/jobs/profiles_synchronizer.md @@ -26,14 +26,13 @@ Sample job configurations. sync_mode: overwrite ``` - ---- ## Vocabulary ### Profiles states -- `remote`: a profile stored outside the end-user computer, on a git repository, an HTTP server or a LAN drive. Typically: `https://gitlab.com/Oslandia/qgis/profils_qgis_fr_2022.git`. +- `remote`: a profile stored outside the end-user computer, on a git repository, an HTTP server or a LAN drive. Typically: `https://gitlab.com/Oslandia/qgis/profils_qgis_fr.git`. - `downloaded`: a profile downloaded into the QDT local working folder. Typically: `~/.cache/qgis-deployment-toolbelt/Oslandia/`. - `installed`: a profile's folder located into the QGIS profiles folder and so accessible to the end-user through the QGIS interface. Typically: `~/.local/share/QGIS/QGIS3/profiles/default` or `%APPDATA%/QGIS/QGIS3/profiles/default` diff --git a/tests/dev/dev_dulwich_remote.py b/tests/dev/dev_dulwich_remote.py index cf38c466..104e412c 100644 --- a/tests/dev/dev_dulwich_remote.py +++ b/tests/dev/dev_dulwich_remote.py @@ -70,7 +70,7 @@ remote_git_handler.download(destination_local_path=git_repository_local_dulwich) -# good_git_url = "https://gitlab.com/Oslandia/qgis/profils_qgis_fr_2022.git" +# good_git_url = "https://gitlab.com/Oslandia/qgis/profils_qgis_fr.git" # remote_git_handler = RemoteGitHandler(source_repository_url=good_git_url) # with tempfile.TemporaryDirectory(ignore_cleanup_errors=True) as tmpdirname: diff --git a/tests/test_git_handler_remote.py b/tests/test_git_handler_remote.py index 216548bc..53793022 100644 --- a/tests/test_git_handler_remote.py +++ b/tests/test_git_handler_remote.py @@ -21,6 +21,7 @@ # 3rd party from dulwich.errors import NotGitRepository +from git import Repo as GitPythonRepo from giturlparse import GitUrlParsed # package @@ -38,14 +39,14 @@ class TestGitHandlerRemote(unittest.TestCase): @classmethod def setUpClass(cls): """Executed when module is loaded before any test.""" - cls.good_git_url = "https://gitlab.com/Oslandia/qgis/profils_qgis_fr_2022.git" + cls.good_git_url = "https://gitlab.com/Oslandia/qgis/profils_qgis_fr.git" # -- TESTS --------------------------------------------------------- def test_initialization(self): """Test remote git repo identifier""" # OK - self.good_git_url = "https://gitlab.com/Oslandia/qgis/profils_qgis_fr_2022.git" - remote_git_handler = RemoteGitHandler(self.good_git_url) + self.good_git_url = "https://gitlab.com/Oslandia/qgis/profils_qgis_fr.git" + remote_git_handler = RemoteGitHandler(source_repository_url=self.good_git_url) self.assertEqual(remote_git_handler.SOURCE_REPOSITORY_TYPE, "git_remote") self.assertTrue(remote_git_handler.is_valid_git_repository()) @@ -57,18 +58,27 @@ def test_initialization(self): def test_is_local_git_repo(self): """Test local git repo identifier""" - self.good_git_url = "https://gitlab.com/Oslandia/qgis/profils_qgis_fr_2022.git" - git_handler = RemoteGitHandler(self.good_git_url) - - # OK - self.assertTrue(git_handler._is_local_path_git_repository(Path("."))) + good_git_url = "https://github.com/octocat/Hello-World" + git_handler = RemoteGitHandler(source_repository_url=self.good_git_url) + + with tempfile.TemporaryDirectory( + prefix="QDT_test_check_path", + ignore_cleanup_errors=True, + ) as tmpdirname: + GitPythonRepo.clone_from(url=good_git_url, to_path=Path(tmpdirname)) + # OK + self.assertTrue( + git_handler._is_local_path_git_repository( + local_path=Path(tmpdirname), raise_error=False + ) + ) # KO self.assertFalse(git_handler._is_local_path_git_repository(Path("./tests"))) def test_git_url_parsed(self): """Test git parsed URL""" - self.good_git_url = "https://gitlab.com/Oslandia/qgis/profils_qgis_fr_2022.git" - git_handler = RemoteGitHandler(self.good_git_url) + self.good_git_url = "https://gitlab.com/Oslandia/qgis/profils_qgis_fr.git" + git_handler = RemoteGitHandler(source_repository_url=self.good_git_url) git_url_parsed = git_handler.url_parsed(self.good_git_url) # type @@ -95,12 +105,12 @@ def test_git_url_parsed(self): self.assertEqual("qgis", git_url_parsed.groups_path) self.assertEqual("Oslandia", git_url_parsed.owner) self.assertEqual("gitlab", git_url_parsed.platform) - self.assertEqual("profils_qgis_fr_2022", git_url_parsed.repo) + self.assertEqual("profils_qgis_fr", git_url_parsed.repo) def test_git_clone_remote_url(self): """Test git parsed URL.""" - self.good_git_url = "https://gitlab.com/Oslandia/qgis/profils_qgis_fr_2022.git" - git_handler = RemoteGitHandler(self.good_git_url) + self.good_git_url = "https://gitlab.com/Oslandia/qgis/profils_qgis_fr.git" + git_handler = RemoteGitHandler(source_repository_url=self.good_git_url) with tempfile.TemporaryDirectory(ignore_cleanup_errors=True) as tmpdirname: local_dest = Path(tmpdirname) / "test_git_clone" diff --git a/tests/test_job_profiles_sync.py b/tests/test_job_profiles_sync.py index 95e0555a..d56b06d5 100644 --- a/tests/test_job_profiles_sync.py +++ b/tests/test_job_profiles_sync.py @@ -52,7 +52,7 @@ def tearDown(self): # # variables # fake_config = { # "action": "download", - # "source": "https://gitlab.com/Oslandia/qgis/profils_qgis_fr_2022.git", + # "source": "https://gitlab.com/Oslandia/qgis/profils_qgis_fr.git", # "protocol": "git", # "local_destination": "~/.cache/qgis-deployment-toolbelt/Oslandia/", # "sync_mode": "overwrite", diff --git a/tests/test_utils_check_path.py b/tests/test_utils_check_path.py index 578e19a3..137836bb 100644 --- a/tests/test_utils_check_path.py +++ b/tests/test_utils_check_path.py @@ -104,18 +104,17 @@ def test_check_path_readable_ko(self): def test_check_path_readable_ko_specific(self): """Test path is readable fail cases.""" # temporary fixture - new_file = Path("tests/fixtures/tmp_file_no_readable.txt") - new_file.touch(mode=0o333, exist_ok=True) - - # str not valid, an existing file but not readable - with self.assertRaises(IOError): - check_path_is_readable(input_path=new_file) - - # no exception but False - self.assertFalse(check_path_is_readable(input_path=new_file, raise_error=False)) + with tempfile.TemporaryDirectory( + prefix="QDT_test_check_path", + ignore_cleanup_errors=True, + ) as tmpdirname: + unreadable_file = Path(tmpdirname).joinpath("tmp_file_no_readable.txt") + unreadable_file.touch(mode=0o333, exist_ok=True) - # temporary fixture - new_file.unlink(missing_ok=True) + # no exception but False + self.assertFalse( + check_path_is_readable(input_path=unreadable_file, raise_error=False) + ) def test_check_path_writable_ok(self): """Test path is writable.""" @@ -131,25 +130,26 @@ def test_check_path_writable_ko(self): check_path_exists(input_path=1000) self.assertFalse(check_path_is_writable(input_path=1000, raise_error=False)) - @unittest.skipIf( - getenv("CI"), "Creating file on CI with specific rights is not working." - ) def test_check_path_writable_ko_specific(self): """Test path is writable fail cases (specific).""" - # temporary fixture - not_writable_file = Path("tests/fixtures/tmp_file_no_writable.txt") - not_writable_file.touch(mode=0o400, exist_ok=True) + with tempfile.TemporaryDirectory( + prefix="QDT_test_check_path", + ignore_cleanup_errors=True, + ) as tmpdirname: + unwritable_file = Path(tmpdirname).joinpath("tmp_file_no_writable.txt") + unwritable_file.touch(exist_ok=True) + unwritable_file.write_text("this content is the last to be written here") - # str not valid, an existing file but not writable - with self.assertRaises(IOError): - check_path_is_writable(input_path=not_writable_file) + chmod(unwritable_file, stat.S_IROTH) - # no exception but False - self.assertFalse( - check_path_is_writable(input_path=not_writable_file, raise_error=False) - ) + # str not valid, an existing file but not writable + with self.assertRaises(IOError): + check_path_is_writable(input_path=unwritable_file) - not_writable_file.unlink() + # no exception but False + self.assertFalse( + check_path_is_writable(input_path=unwritable_file, raise_error=False) + ) def test_check_path_meta_ok(self): """Test meta check path.""" diff --git a/tests/test_utils_user_groups.py b/tests/test_utils_user_groups.py new file mode 100644 index 00000000..7ab3baa6 --- /dev/null +++ b/tests/test_utils_user_groups.py @@ -0,0 +1,67 @@ +#! python3 # noqa E265 + +""" + Usage from the repo root folder: + + .. code-block:: bash + # for whole tests + python -m unittest tests.test_user_groups + # for specific test + python -m unittest tests.test_user_groups.TestUtilsUserGroups.test_win32_getenv +""" + +# standard library +import unittest +from getpass import getuser +from sys import platform as opersys + +# project +from qgis_deployment_toolbelt.utils.user_groups import ( + _is_computer_in_domain_powershell, + _is_computer_in_domain_pyad, + _is_computer_in_domain_win32, + get_user_local_groups, + is_computer_attached_to_a_domain, + is_user_in_group, +) + +# ############################################################################ +# ########## Classes ############# +# ################################ + + +class TestUtilsUserGroups(unittest.TestCase): + """Test package utilities.""" + + def test_computer_attached_to_domain(self): + """Test if the computer belongs to a domain.""" + # for now, domain link is only supported on Windows + if opersys != "win32": + self.assertFalse(is_computer_attached_to_a_domain()) + return + + # test different methods on Windows but for now, no domain mocked in tests + # TODO: mock domain link + domain_status = is_computer_attached_to_a_domain() + self.assertIsInstance(domain_status, bool) + + self.assertEqual(domain_status, _is_computer_in_domain_powershell()) + self.assertEqual(domain_status, _is_computer_in_domain_pyad()) + self.assertEqual(domain_status, _is_computer_in_domain_win32()) + + def test_user_in_group(self): + """Test function determining user's groups.""" + user_groups = get_user_local_groups() + + # test with existing group + self.assertTrue(is_user_in_group(user_groups[0])) + + # test with unisting group + self.assertFalse(is_user_in_group(group_name="fake_group", user_name=getuser())) + + +# ############################################################################ +# ####### Stand-alone run ######## +# ################################ +if __name__ == "__main__": + unittest.main()