Add signal tests, add LearningMentor

This commit is contained in:
Christian Cueni 2024-06-26 07:46:31 +02:00
parent e6eae79171
commit eb931c86c8
3 changed files with 278 additions and 10 deletions

View File

@ -945,12 +945,10 @@ def create_or_update_student(data: Dict[str, Any]):
)
user.language = data["Sprache"]
update_user_json_data(user, data)
user.save()
# create user in intermediate sso i.e. Keycloak
sso_data = {"intermediate_sso_id": create_user(user)}
update_user_json_data(user, sso_data)
data["intermediate_sso_id"] = create_user(user)
user.update_additional_json_data(data)
user.save()
# general expert handling
import_id = data["Durchführungen"]

View File

@ -1,11 +1,12 @@
import structlog
from django.db.models.signals import m2m_changed, post_delete, pre_save
from django.db.models.signals import m2m_changed, post_delete, pre_delete, pre_save
from django.dispatch import receiver
from keycloak.exceptions import KeycloakDeleteError, KeycloakError, KeycloakPostError
from vbv_lernwelt.core.models import User
from vbv_lernwelt.course.models import CourseSessionUser
from vbv_lernwelt.course_session_group.models import CourseSessionGroup
from vbv_lernwelt.learning_mentor.models import LearningMentor
from vbv_lernwelt.sso.role_sync.services import (
add_roles_to_user,
remove_roles_from_user,
@ -18,7 +19,13 @@ logger = structlog.get_logger(__name__)
# CourseSessionUser
@receiver(post_delete, sender=CourseSessionUser, dispatch_uid="delete_sso_roles_in_cs")
def remove_sso_roles_in_cs(sender, instance, **kwargs):
_remove_sso_role(instance.user, instance.course_session.course.slug, instance.role)
# check if the user has any other roles in the course
if not CourseSessionUser.objects.filter(
user=instance.user, course_session__course=instance.course_session.course
).exists():
_remove_sso_role(
instance.user, instance.course_session.course.slug, instance.role
)
@receiver(pre_save, sender=CourseSessionUser, dispatch_uid="update_sso_roles_in_cs")
@ -44,9 +51,7 @@ def update_sso_roles_in_cs(sender, instance: CourseSessionUser, **kwargs):
# CourseSessionGroup
@receiver(
post_delete, sender=CourseSessionGroup, dispatch_uid="delete_sso_roles_in_csg"
)
@receiver(pre_delete, sender=CourseSessionGroup, dispatch_uid="delete_sso_roles_in_csg")
def remove_sso_roles_in_csg(sender, instance: CourseSessionGroup, **kwargs):
for user in instance.supervisor.all():
_remove_sso_role(user, instance.course.slug, "SUPERVISOR")
@ -69,6 +74,25 @@ def update_sso_roles_in_csg(sender, instance, action, reverse, model, pk_set, **
_remove_sso_role(user, instance.course.slug, "SUPERVISOR")
# LearningMentor
@receiver(post_delete, sender=LearningMentor, dispatch_uid="delete_sso_roles_in_lm")
def remove_sso_roles_in_lm(sender, instance: LearningMentor, **kwargs):
if not LearningMentor.objects.filter(
mentor=instance.mentor, course_session__course=instance.course_session.course
).exists():
_remove_sso_role(
instance.mentor, instance.course_session.course.slug, "LEARNING_MENTOR"
)
@receiver(pre_save, sender=LearningMentor, dispatch_uid="update_sso_roles_in_lm")
def update_sso_roles_in_lm(sender, instance: LearningMentor, **kwargs):
if not instance.pk:
_add_sso_role(
instance.mentor, instance.course_session.course.slug, "LEARNING_MENTOR"
)
def _remove_sso_role(user: User, course_slug: str, role: str):
try:
logger.debug(

View File

@ -0,0 +1,246 @@
from unittest.mock import call, patch
from django.db.models.signals import pre_save
from django.dispatch import Signal
from django.test import TestCase
from vbv_lernwelt.core.constants import (
TEST_COURSE_SESSION_BERN_ID,
TEST_COURSE_SESSION_ZURICH_ID,
TEST_STUDENT1_USER_ID,
TEST_STUDENT2_USER_ID,
TEST_SUPERVISOR1_USER_ID,
TEST_TRAINER1_USER_ID,
)
from vbv_lernwelt.core.create_default_users import create_default_users
from vbv_lernwelt.core.models import User
from vbv_lernwelt.course.consts import COURSE_TEST_ID
from vbv_lernwelt.course.creators.test_course import create_test_course
from vbv_lernwelt.course.creators.test_utils import (
add_course_session_user,
create_course,
create_course_session,
create_user,
)
from vbv_lernwelt.course.models import Course, CourseSessionUser
from vbv_lernwelt.course_session_group.models import CourseSessionGroup
from vbv_lernwelt.learning_mentor.models import LearningMentor
from vbv_lernwelt.sso.signals import update_sso_roles_in_cs
class CourseSessionUserTests(TestCase):
def setUp(self):
create_default_users()
create_test_course(include_uk=True, with_sessions=True)
self.student1 = User.objects.get(id=TEST_STUDENT1_USER_ID)
self.csu1_student1 = CourseSessionUser.objects.get(
user=self.student1, course_session__id=TEST_COURSE_SESSION_BERN_ID
)
self.student2 = User.objects.get(id=TEST_STUDENT2_USER_ID)
self.csu1_student2 = CourseSessionUser.objects.get(
user=self.student2, course_session__id=TEST_COURSE_SESSION_ZURICH_ID
)
# Disconnect the actual signal handler to avoid side effects during testing
pre_save.disconnect(receiver=update_sso_roles_in_cs, sender=CourseSessionUser)
# Connect a mock signal handler
self.mock_pre_save_signal = Signal()
self.mock_pre_save_signal.connect(
receiver=update_sso_roles_in_cs, sender=CourseSessionUser
)
@patch("vbv_lernwelt.sso.signals.remove_roles_from_user")
def test_remove_roles_for_single_role_in_cs(self, mock_remove_roles_from_user):
mock_remove_roles_from_user.return_value = None
self.csu1_student1.delete()
self.assertEqual(mock_remove_roles_from_user.call_count, 1)
mock_remove_roles_from_user.assert_called_with(
self.student1, [(self.csu1_student1.course_session.course.slug, "MEMBER")]
)
@patch("vbv_lernwelt.sso.signals.remove_roles_from_user")
def test_dont_remove_roles_for_multiple_roles_in_cs(
self, mock_remove_roles_from_user
):
mock_remove_roles_from_user.return_value = None
self.csu1_student2.delete()
self.assertFalse(mock_remove_roles_from_user.called)
@patch("vbv_lernwelt.sso.signals.add_roles_to_user")
def test_add_role_for_user_on_creation(self, mock_add_roles_from_user):
mock_add_roles_from_user.return_value = None
self.csu1_student1.delete()
csu = CourseSessionUser.objects.create(
user=self.student1,
course_session=self.csu1_student1.course_session,
role="MEMBER",
)
self.mock_pre_save_signal.send(sender=CourseSessionUser, instance=csu)
self.assertEqual(mock_add_roles_from_user.call_count, 1)
mock_add_roles_from_user.assert_called_with(
self.student1, [(self.csu1_student1.course_session.course.slug, "MEMBER")]
)
@patch("vbv_lernwelt.sso.signals.update_roles_for_user")
def test_update_role_for_user_on_creation(self, mock_update_roles_for_user):
mock_update_roles_for_user.return_value = None
self.csu1_student1.role = "TRAINER"
self.mock_pre_save_signal.send(
sender=CourseSessionUser, instance=self.csu1_student1
)
self.assertEqual(mock_update_roles_for_user.call_count, 1)
mock_update_roles_for_user.assert_called_with(
self.student1,
add_course_roles=[
(self.csu1_student1.course_session.course.slug, "TRAINER")
],
remove_course_roles=[
(self.csu1_student1.course_session.course.slug, "MEMBER")
],
)
@patch("vbv_lernwelt.sso.signals.update_roles_for_user")
def test_dont_update_role_for_user_on_creation(self, mock_update_roles_for_user):
mock_update_roles_for_user.return_value = None
self.csu1_student1.role = "MEMBER"
self.mock_pre_save_signal.send(
sender=CourseSessionUser, instance=self.csu1_student1
)
self.assertEqual(mock_update_roles_for_user.call_count, 0)
class CourseSessionGroupTests(TestCase):
def setUp(self):
create_default_users()
create_test_course(include_uk=True, with_sessions=True)
self.csg = CourseSessionGroup.objects.get(
name="Region 1",
)
course = Course.objects.get(id=COURSE_TEST_ID)
self.slug = course.slug
self.trainer = User.objects.get(id=TEST_TRAINER1_USER_ID)
self.supervisor = User.objects.get(id=TEST_SUPERVISOR1_USER_ID)
# m2m_changed.disconnect(receiver=update_sso_roles_in_csg, sender=CourseSessionGroup.supervisor.through)
#
# # Connect a mock signal handler
# self.mock_signal = Signal()
# self.mock_signal.connect(receiver=update_sso_roles_in_csg, sender=CourseSessionGroup.supervisor.through)
@patch("vbv_lernwelt.sso.signals.remove_roles_from_user")
def test_remove_roles_for_csg_supervisors(self, mock_remove_roles_from_user):
mock_remove_roles_from_user.return_value = None
self.csg.supervisor.set([self.trainer, self.supervisor])
self.csg.delete()
expected_calls = [
call(self.supervisor, [(self.slug, "SUPERVISOR")]),
call(self.trainer, [(self.slug, "SUPERVISOR")]),
]
mock_remove_roles_from_user.assert_has_calls(expected_calls, any_order=True)
self.assertEqual(mock_remove_roles_from_user.call_count, 2)
@patch("vbv_lernwelt.sso.signals.remove_roles_from_user")
@patch("vbv_lernwelt.sso.signals.add_roles_to_user")
def test_add_supervisors_to_csg(
self, mock_add_roles_to_user, mock_remove_roles_from_user
):
mock_remove_roles_from_user.return_value = None
mock_add_roles_to_user.return_value = None
self.csg.supervisor.add(self.trainer)
self.assertEqual(mock_add_roles_to_user.call_count, 1)
self.assertEqual(mock_remove_roles_from_user.call_count, 0)
mock_add_roles_to_user.assert_called_with(
self.trainer, [(self.slug, "SUPERVISOR")]
)
@patch("vbv_lernwelt.sso.signals.remove_roles_from_user")
@patch("vbv_lernwelt.sso.signals.add_roles_to_user")
def test_remove_supervisors_to_csg(
self, mock_add_roles_to_user, mock_remove_roles_from_user
):
mock_remove_roles_from_user.return_value = None
mock_add_roles_to_user.return_value = None
self.csg.supervisor.remove(self.supervisor)
self.assertEqual(mock_add_roles_to_user.call_count, 0)
self.assertEqual(mock_remove_roles_from_user.call_count, 1)
mock_remove_roles_from_user.assert_called_with(
self.supervisor, [(self.slug, "SUPERVISOR")]
)
class LearningMentorTests(TestCase):
def setUp(self):
self.course, self.course_page = create_course("Test Course")
self.course_session = create_course_session(course=self.course, title="Test VV")
self.user = create_user("mentor")
self.mentor = LearningMentor.objects.create(
mentor=self.user, course_session=self.course_session
)
@patch("vbv_lernwelt.sso.signals.remove_roles_from_user")
def test_remove_roles_for_learning_mentor_on_delete(
self, mock_remove_roles_from_user
):
mock_remove_roles_from_user.return_value = None
self.mentor.delete()
self.assertEqual(mock_remove_roles_from_user.call_count, 1)
mock_remove_roles_from_user.assert_called_with(
self.user, [(self.course.slug, "LEARNING_MENTOR")]
)
@patch("vbv_lernwelt.sso.signals.add_roles_to_user")
def test_add_roles_for_learning_mentor_on_create(self, mock_add_roles_from_user):
mock_add_roles_from_user.return_value = None
self.mentor.delete()
LearningMentor.objects.create(
mentor=self.user, course_session=self.course_session
)
self.assertEqual(mock_add_roles_from_user.call_count, 1)
mock_add_roles_from_user.assert_called_with(
self.user, [(self.course.slug, "LEARNING_MENTOR")]
)
@patch("vbv_lernwelt.sso.signals.add_roles_to_user")
def test_no_add_roles_for_learning_mentor_on_update(self, mock_add_roles_from_user):
mock_add_roles_from_user.return_value = None
participant_1 = add_course_session_user(
self.course_session,
create_user("participant_1"),
role=CourseSessionUser.Role.MEMBER,
)
mock_add_roles_from_user.reset_mock()
self.mentor.participants.set([participant_1])
self.assertEqual(mock_add_roles_from_user.call_count, 0)