From a29e1a58a4ffc0970ae54f65c794d5d17077187f Mon Sep 17 00:00:00 2001 From: Vaibhav Rathore Date: Tue, 3 Mar 2026 17:34:34 +0530 Subject: [PATCH] fix: resolve server test failures for Google Meet integration - Mock get_google_calendar_object in live class tests to prevent real Google API calls in CI (no OAuth tokens available) - Fix on_trash to clear event link before deleting Event to avoid LinkExistsError - Fix test query to avoid PostgreSQL-incompatible integer filter - Add Google Settings setup to Google Meet Settings integration tests --- .../test_lms_google_meet_settings.py | 17 ++++++++ .../doctype/lms_live_class/lms_live_class.py | 4 +- .../lms_live_class/test_lms_live_class.py | 39 +++++++++++++++---- 3 files changed, 52 insertions(+), 8 deletions(-) diff --git a/lms/lms/doctype/lms_google_meet_settings/test_lms_google_meet_settings.py b/lms/lms/doctype/lms_google_meet_settings/test_lms_google_meet_settings.py index 2f3a794f..b9d218cb 100644 --- a/lms/lms/doctype/lms_google_meet_settings/test_lms_google_meet_settings.py +++ b/lms/lms/doctype/lms_google_meet_settings/test_lms_google_meet_settings.py @@ -22,6 +22,16 @@ class IntegrationTestLMSGoogleMeetSettings(IntegrationTestCase): def setUp(self): self.cleanup_items = [] + google_settings = frappe.get_doc("Google Settings") + self._original_google_settings = { + "enable": google_settings.enable, + "client_id": google_settings.client_id, + } + google_settings.enable = 1 + google_settings.client_id = "test-client-id" + google_settings.client_secret = "test-client-secret" + google_settings.save(ignore_permissions=True) + def tearDown(self): for item_type, item_name in reversed(self.cleanup_items): if frappe.db.exists(item_type, item_name): @@ -30,6 +40,13 @@ class IntegrationTestLMSGoogleMeetSettings(IntegrationTestCase): except Exception: pass + if hasattr(self, "_original_google_settings"): + google_settings = frappe.get_doc("Google Settings") + google_settings.enable = self._original_google_settings["enable"] + google_settings.client_id = self._original_google_settings["client_id"] + google_settings.client_secret = "" + google_settings.save(ignore_permissions=True) + def _create_google_calendar(self, name="Test Google Calendar"): if frappe.db.exists("Google Calendar", name): return frappe.get_doc("Google Calendar", name) diff --git a/lms/lms/doctype/lms_live_class/lms_live_class.py b/lms/lms/doctype/lms_live_class/lms_live_class.py index d690a010..6d1554ac 100644 --- a/lms/lms/doctype/lms_live_class/lms_live_class.py +++ b/lms/lms/doctype/lms_live_class/lms_live_class.py @@ -35,7 +35,9 @@ class LMSLiveClass(Document): def on_trash(self): if self.event and frappe.db.exists("Event", self.event): - frappe.delete_doc("Event", self.event, ignore_permissions=True) + event_name = self.event + frappe.db.set_value("LMS Live Class", self.name, "event", "") + frappe.delete_doc("Event", event_name, ignore_permissions=True) def _get_participants(self): participants = frappe.get_all("LMS Batch Enrollment", {"batch": self.batch_name}, pluck="member") diff --git a/lms/lms/doctype/lms_live_class/test_lms_live_class.py b/lms/lms/doctype/lms_live_class/test_lms_live_class.py index 2e37c640..5351db79 100644 --- a/lms/lms/doctype/lms_live_class/test_lms_live_class.py +++ b/lms/lms/doctype/lms_live_class/test_lms_live_class.py @@ -1,23 +1,50 @@ # Copyright (c) 2023, Frappe and Contributors # See license.txt +from unittest.mock import MagicMock, patch + import frappe from frappe.utils import add_days, nowdate from lms.lms.test_helpers import BaseTestUtils +GOOGLE_CALENDAR_MODULE = "frappe.integrations.doctype.google_calendar.google_calendar" + class TestLMSLiveClass(BaseTestUtils): """Tests for LMS Live Class including Google Meet integration.""" def setUp(self): super().setUp() + + # Mock get_google_calendar_object to prevent Frappe's Event hooks + # from calling the real Google Calendar API (no OAuth tokens in CI). + mock_api = MagicMock() + mock_api.events.return_value.insert.return_value.execute.return_value = { + "id": "test-gcal-event-id", + "hangoutLink": "https://meet.google.com/test-link", + "status": "confirmed", + } + mock_api.events.return_value.update.return_value.execute.return_value = { + "id": "test-gcal-event-id", + "hangoutLink": "https://meet.google.com/test-link", + } + mock_api.events.return_value.patch.return_value.execute.return_value = {} + mock_api.events.return_value.delete.return_value.execute.return_value = None + + self._gcal_patcher = patch( + f"{GOOGLE_CALENDAR_MODULE}.get_google_calendar_object", + return_value=(mock_api, MagicMock()), + ) + self._gcal_patcher.start() + self._setup_course_flow() self._setup_batch_flow() self._setup_google_meet() def tearDown(self): super().tearDown() + self._gcal_patcher.stop() if hasattr(self, "_original_google_settings"): google_settings = frappe.get_doc("Google Settings") google_settings.enable = self._original_google_settings["enable"] @@ -139,7 +166,8 @@ class TestLMSLiveClass(BaseTestUtils): old_calendar = self.google_meet_settings.google_calendar self.google_meet_settings.google_calendar = "" - self.google_meet_settings.save(ignore_mandatory=True) + self.google_meet_settings.flags.ignore_mandatory = True + self.google_meet_settings.save() with self.assertRaises(frappe.exceptions.ValidationError): create_google_meet_live_class( @@ -313,18 +341,15 @@ class TestLMSLiveClass(BaseTestUtils): def test_update_attendance_skips_google_meet(self): """The Zoom attendance scheduler should skip Google Meet classes.""" - from lms.lms.doctype.lms_live_class.lms_live_class import update_attendance - live_class = self._create_live_class() live_class.reload() - # The update_attendance function filters out Google Meet classes - # It should not raise an error or attempt to call Zoom API for Google Meet classes + # The update_attendance function uses conferencing_provider != "Google Meet" + # to filter out Google Meet classes from Zoom attendance processing. + # Verify a Google Meet class is excluded by that filter. past_classes = frappe.get_all( "LMS Live Class", { - "uuid": ["is", "set"], - "attendees": ["is", "not set"], "conferencing_provider": ["!=", "Google Meet"], }, pluck="name",