From 031fe2b4bd6219183ebd50c108ee47c6ccdee768 Mon Sep 17 00:00:00 2001 From: Julian Lobbes Date: Wed, 16 Nov 2022 00:22:39 +0100 Subject: [PATCH] tests(ldap, usermodel): add unit tests --- lumi2/ldap.py | 8 +- tests/test_ldap.py | 129 +++++++++++++++++++++++++++++ tests/test_usermodel.py | 179 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 310 insertions(+), 6 deletions(-) diff --git a/lumi2/ldap.py b/lumi2/ldap.py index c8373f1..9f13a0a 100644 --- a/lumi2/ldap.py +++ b/lumi2/ldap.py @@ -565,11 +565,6 @@ def user_exists(connection: Connection, user_dn: str) -> bool: Bound Connection object to an LDAP server. user_dn : str DN of a user entry (uid) directly below the LDAP_USERS_OU entry. - - Raises - ------ - MissingParentEntryException - If the specified user DN's direct parent entry is not present in the DIT. """ _assert_is_valid_connection(connection) @@ -761,6 +756,9 @@ def update_user(connection: Connection, user: User) -> None: def delete_user(connection: Connection, uid: str) -> None: """Deletes the user with the specified uid (username) from the LDAP server. + + If any groups exists in which the specified User is the only member, the + respective Group is also silently deleted. Parameters ---------- diff --git a/tests/test_ldap.py b/tests/test_ldap.py index 0e88fc5..c7f41a9 100644 --- a/tests/test_ldap.py +++ b/tests/test_ldap.py @@ -3,6 +3,7 @@ import pytest import lumi2.ldap as ll +import lumi2.usermodel as lu import lumi2.exceptions as le @@ -161,6 +162,7 @@ def test_ou_exists_unpopulated(app, connection_empty_dit): assert not ll.ou_exists(connection_empty_dit, "ou=users,dc=example,dc=com") assert not ll.ou_exists(connection_empty_dit, "ou=groups,dc=example,dc=com") + def test_create_ou(app, connection): with app.app_context(): with pytest.raises(ll.EntryExistsException): @@ -169,3 +171,130 @@ def test_create_ou(app, connection): assert not ll.ou_exists(connection, "ou=foo,dc=example,dc=com") ll.create_ou(connection, "ou=foo,dc=example,dc=com") assert ll.ou_exists(connection, "ou=foo,dc=example,dc=com") + + +def test_user_exists(app, connection): + with app.app_context(): + assert ll.user_exists(connection, "uid=alice,ou=users,dc=example,dc=com") + assert not ll.user_exists(connection, "uid=nonexistent,ou=users,dc=example,dc=com") + + +def test_get_user(app, connection): + with app.app_context(): + for invalid_type in [1, True, None]: + with pytest.raises(TypeError): + ll.get_user(connection, invalid_type) + + with pytest.raises(ll.EntryNotFoundException): + ll.get_user(connection, "nonexistent") + + assert ll.get_user(connection, "alice").username == "alice" + + +def test_create_user(app, connection): + with app.app_context(): + user0 = lu.User( + username="user0", + password_hash=lu.User.generate_password_hash("password"), + email="valid@example.com", + first_name="Test", + last_name="User", + ) + alice_duplicate = lu.User( + username="alice", + password_hash=lu.User.generate_password_hash("password"), + email="valid@example.com", + first_name="Test", + last_name="User", + ) + + with pytest.raises(ll.EntryExistsException): + ll.create_user(connection, alice_duplicate) + + assert ll.create_user(connection, user0) == None + + +def test_update_user(app, connection): + with app.app_context(): + user0 = lu.User( + username="user0", + password_hash=lu.User.generate_password_hash("password"), + email="valid@example.com", + first_name="Test", + last_name="User", + ) + + with pytest.raises(TypeError): + ll.update_user(connection, None) + with pytest.raises(ll.EntryNotFoundException): + ll.update_user(connection, user0) + + ll.create_user(connection, user0) + assert ll.get_user(connection, "user0").email == "valid@example.com" + user0.email = "other@example.com" + ll.update_user(connection, user0) + assert ll.get_user(connection, "user0").email == "other@example.com" + + +def test_delete_user(app, connection): + with app.app_context(): + user0 = lu.User( + username="user0", + password_hash=lu.User.generate_password_hash("password"), + email="valid@example.com", + first_name="Test", + last_name="User", + ) + + with pytest.raises(ll.EntryNotFoundException): + ll.delete_user(connection, "user0") + + ll.create_user(connection, user0) + assert ll.user_exists(connection, user0.get_dn()) + ll.delete_user(connection, "user0") + assert not ll.user_exists(connection, user0.get_dn()) + + # TODO check that group deletion works + + +def test_get_users(app, connection): + with app.app_context(): + assert len(ll.get_users(connection)) == 2 + for user in ll.get_users(connection): + assert user.username in ["alice", "bobbuilder"] + + +def test_group_exists(app, connection): + with app.app_context(): + # TODO implement + pass + + +def test_create_group(app, connection): + with app.app_context(): + # TODO implement + pass + + +def test_delete_group(app, connection): + with app.app_context(): + # TODO implement + pass + + +def test_get_group(app, connection): + with app.app_context(): + # TODO implement + pass + + +def test_get_groups(app, connection): + with app.app_context(): + # TODO implement + pass + + +def test_get_groups_of_user(app, connection): + with app.app_context(): + # TODO implement + pass diff --git a/tests/test_usermodel.py b/tests/test_usermodel.py index 40b8661..487e646 100644 --- a/tests/test_usermodel.py +++ b/tests/test_usermodel.py @@ -1,8 +1,9 @@ """Unit tests for the lumi2.usermodel module.""" import pytest +from PIL import Image, JpegImagePlugin -from lumi2.usermodel import User +from lumi2.usermodel import User, Group def test_is_valid_username(): @@ -91,3 +92,179 @@ def test_is_valid_person_name(): def test_is_valid_picture(): # TODO implement pass + + +def test_generate_password_hash(): + for invalid_type in [None, 0, True, ("x",), ["x"]]: + with pytest.raises(TypeError): + User.generate_password_hash(invalid_type) + + with pytest.raises(ValueError): + User.generate_password_hash("") + + assert User.generate_password_hash("Password") == "5sg7KCrrLgIoRFlXIcwAu9pHyyRTfBd5+buE8EA54Wdua6hXPliNoQUlEOOqCjKp5Vh5riKwwtYhNvwKPoX4uw==" + + +def test_get_default_picture(app): + with app.app_context(): + assert isinstance(User._get_default_picture(), Image.Image) + assert isinstance(User._get_default_picture(), JpegImagePlugin.JpegImageFile) + + +def test_User(app): + with app.app_context(): + with pytest.raises(ValueError): + User( + username="=invalid", + password_hash=User.generate_password_hash("password"), + email="valid@example.com", + first_name="Test", + last_name="User", + ) + User( + username="test", + password_hash="=invalid", + email="invalid", + first_name="Test", + last_name="User", + ) + User( + username="test", + password_hash=User.generate_password_hash("password"), + email="invalid", + first_name="Test", + last_name="User", + ) + User( + username="test", + password_hash=User.generate_password_hash("password"), + email="invalid", + first_name="Test", + last_name="User", + ) + User( + username="test", + password_hash=User.generate_password_hash("password"), + email="valid@example.com", + first_name="=invalid", + last_name="User", + ) + User( + username="test", + password_hash=User.generate_password_hash("password"), + email="valid@example.com", + first_name="Test", + last_name="=invalid", + ) + User( + username="=invalid", + password_hash="=invalid", + email="=invalid", + first_name="=invalid", + last_name="=invalid", + ) + + User( + username="test", + password_hash=User.generate_password_hash("password"), + email="valid@example.com", + first_name="Test", + last_name="User", + ) + + +def test_User_get_dn(app): + with app.app_context(): + user = User( + username="test", + password_hash=User.generate_password_hash("password"), + email="valid@example.com", + first_name="Test", + last_name="User", + ) + + assert user.get_dn() == "uid=test," + app.config['LDAP_USERS_OU'] + + +def test_User_eq(app): + with app.app_context(): + user0 = User( + username="user0", + password_hash=User.generate_password_hash("password"), + email="valid@example.com", + first_name="Test", + last_name="User", + ) + user0_copy = User( + username="user0", + password_hash=User.generate_password_hash("password"), + email="valid@example.com", + first_name="Test", + last_name="User", + ) + user1 = User( + username="user1", + password_hash=User.generate_password_hash("password"), + email="valid@example.com", + first_name="Test", + last_name="User", + ) + + assert user0 == user0_copy + assert user0 != user1 + assert user0 < user1 + + +def test_is_valid_groupname(): + for invalid_type in [None, 0, True, ("x",), ["x"]]: + with pytest.raises(TypeError): + Group.is_valid_groupname(invalid_type) + + for invalid_input in [ + "", " ", "foo ", " foo", + "1foo", "foo_", "Foo=" + ]: + assert not Group.is_valid_groupname(invalid_input) + + for valid_input in [ + "foo", "foo123", "F1oFoFo", "o2FoFo", + ]: + assert Group.is_valid_groupname(valid_input) + + +def test_Group(app): + with app.app_context(): + user0 = User( + username="user0", + password_hash=User.generate_password_hash("password"), + email="valid@example.com", + first_name="Test", + last_name="User", + ) + user1 = User( + username="user1", + password_hash=User.generate_password_hash("password"), + email="valid@example.com", + first_name="Test", + last_name="User", + ) + user2 = User( + username="user2", + password_hash=User.generate_password_hash("password"), + email="valid@example.com", + first_name="Test", + last_name="User", + ) + + with pytest.raises(ValueError): + Group("foo_", {user0}) + Group("foo", set()) + + group0 = Group("group0", {user0}) + group0_copy = Group("group0", {user0, user1}) + group1 = Group("group1", {user1, user2}) + + assert group0.get_dn() == "cn=group0," + app.config['LDAP_GROUPS_OU'] + assert group0 == group0_copy + assert group0 != group1 + assert group0 < group1