[IMP] maintenance_service_http_monitoring: rework maintenance.request creation

Previously, a single ``maintenance.request`` was created per equipment,
regardless of how many services were down on that equipment. The name
was ``[HTTP KO] {equipment.name}`` and deduplication relied on a
name+date+equipment search that was fragile (manual clear of the field
would lose the reference to an existing open request).

This commit reworks the whole creation logic:

- **1 request per KO service** instead of 1 per equipment. Each failing
  ``service.instance`` gets its own ``maintenance.request``, allowing
  fine-grained tracking and independent resolution.

- **Request name** is now ``[HTTP KO] {service_url}``, making it
  immediately identifiable without opening the record.

- **Description** includes the error detail: ``HTTP {status_code}`` for
  HTTP errors, or a human-readable network error label when
  ``last_http_status_code == -1`` (timeout / DNS / SSL failures).

- **Deduplication** is now based solely on whether an open (non-done)
  ``maintenance.request`` already exists on the ``service.instance``
  via the new ``http_maintenance_request`` field. No date boundary —
  as long as the request is open, no new one is created.

- **``http_maintenance_request``** field moved from
  ``maintenance.equipment`` to ``service.instance``, where it belongs
  given the 1-request-per-service model. It is exposed as an optional
  hidden column in the service instance list view.

- ``_build_ko_services_description()`` is removed (no longer needed).

- ``create_http_maintenance_request()`` now receives a single
  ``service.instance`` recordset instead of a list.

Tests updated accordingly (14 tests total):
- Tests 2, 4, 9, 10, 12, 13 now assert on
  ``service_instance.http_maintenance_request``.
- Test 2 also verifies the request name contains the service URL and
  the description contains the HTTP status code.
- New test 14 asserts that two KO services on the same equipment
  produce two distinct requests with the correct names.
This commit is contained in:
Stéphan Sainléger
2026-06-15 17:31:57 +02:00
parent 2724d29f25
commit c238e54808
6 changed files with 76 additions and 48 deletions

View File

@@ -55,7 +55,7 @@ class TestHttpMonitoring(TransactionCase):
self.assertIsNotNone(self.service_instance.last_http_check_date)
# ------------------------------------------------------------------
# Test 2 -- Two KO passes -> maintenance.request created
# Test 2 -- Two KO passes -> maintenance.request created on the service
# ------------------------------------------------------------------
def test_http_500_creates_maintenance_request(self):
with (
@@ -69,11 +69,13 @@ class TestHttpMonitoring(TransactionCase):
self.assertFalse(self.service_instance.http_status_ok)
self.assertEqual(self.service_instance.last_http_status_code, 500)
request = self.equipment.http_maintenance_request
request = self.service_instance.http_maintenance_request
self.assertTrue(request)
self.assertEqual(request.name, f"[HTTP KO] {self.equipment.name}")
self.assertEqual(request.name, f"[HTTP KO] {self.service_instance.service_url}")
self.assertEqual(request.priority, "2")
self.assertEqual(request.maintenance_type, "corrective")
self.assertIn("HTTP 500", request.description)
self.assertIn(self.service_instance.service_url, request.description)
# ------------------------------------------------------------------
# Test 3 -- Network error -> KO with code -1
@@ -99,7 +101,7 @@ class TestHttpMonitoring(TransactionCase):
mock_requests.exceptions.RequestException = Exception
self.env["service.instance"].cron_check_http_services()
request_1 = self.equipment.http_maintenance_request
request_1 = self.service_instance.http_maintenance_request
self.assertTrue(request_1)
with (
@@ -110,7 +112,7 @@ class TestHttpMonitoring(TransactionCase):
mock_requests.exceptions.RequestException = Exception
self.env["service.instance"].cron_check_http_services()
self.assertEqual(self.equipment.http_maintenance_request, request_1)
self.assertEqual(self.service_instance.http_maintenance_request, request_1)
self.assertEqual(
self.env["maintenance.request"].search_count(
[("equipment_id", "=", self.equipment.id)]
@@ -247,11 +249,9 @@ class TestHttpMonitoring(TransactionCase):
mock_requests.exceptions.RequestException = Exception
self.env["service.instance"].cron_check_http_services()
# Final status reflects pass 2 result
self.assertTrue(self.service_instance.http_status_ok)
self.assertEqual(self.service_instance.last_http_status_code, 200)
# No maintenance.request must have been created
self.assertFalse(self.equipment.http_maintenance_request)
self.assertFalse(self.service_instance.http_maintenance_request)
self.assertEqual(
self.env["maintenance.request"].search_count(
[("equipment_id", "=", self.equipment.id)]
@@ -271,12 +271,44 @@ class TestHttpMonitoring(TransactionCase):
mock_requests.exceptions.RequestException = Exception
self.env["service.instance"].cron_check_http_services()
# sleep must have been called between the two passes
mock_sleep.assert_called_once_with(2)
# requests.get must have been called twice (pass 1 + pass 2)
self.assertEqual(mock_requests.get.call_count, 2)
# Final status is KO
self.assertFalse(self.service_instance.http_status_ok)
self.assertEqual(self.service_instance.last_http_status_code, 503)
# maintenance.request created
self.assertTrue(self.equipment.http_maintenance_request)
self.assertTrue(self.service_instance.http_maintenance_request)
# ------------------------------------------------------------------
# Test 14 -- 2 KO services on same equipment -> 2 distinct requests
# ------------------------------------------------------------------
def test_two_ko_services_same_equipment_create_two_requests(self):
service2 = self.env["service"].create({"name": "Test Service 2"})
service_instance2 = self.env["service.instance"].create(
{
"equipment_id": self.equipment.id,
"service_id": service2.id,
"service_url": "https://other.example.com",
}
)
with (
patch(SERVICE_INSTANCE_REQUESTS) as mock_requests,
patch(SERVICE_INSTANCE_SLEEP),
):
mock_requests.get.return_value = _mock_response(500)
mock_requests.exceptions.RequestException = Exception
self.env["service.instance"].cron_check_http_services()
req1 = self.service_instance.http_maintenance_request
req2 = service_instance2.http_maintenance_request
self.assertTrue(req1)
self.assertTrue(req2)
self.assertNotEqual(req1, req2)
self.assertEqual(req1.name, f"[HTTP KO] {self.service_instance.service_url}")
self.assertEqual(req2.name, f"[HTTP KO] {service_instance2.service_url}")
self.assertEqual(
self.env["maintenance.request"].search_count(
[("equipment_id", "=", self.equipment.id)]
),
2,
)