From 21c7ef9a5549c7699acf2724e625f6261e5017ef Mon Sep 17 00:00:00 2001 From: Girik1105 Date: Mon, 15 Jun 2026 16:33:47 -0700 Subject: [PATCH] [HOP-71] fix kb sync and tests --- hospexplorer/ask/tests.py | 52 +++++++++++++++++++++++++++++++++++++++ hospexplorer/ask/views.py | 9 +++++++ 2 files changed, 61 insertions(+) diff --git a/hospexplorer/ask/tests.py b/hospexplorer/ask/tests.py index c51517a..8246e7c 100644 --- a/hospexplorer/ask/tests.py +++ b/hospexplorer/ask/tests.py @@ -160,6 +160,58 @@ def test_response_payload_powers_the_dom_injection(self, mock_download): self.assertIn("id", body) +class KBAddPdfToMcpViewTests(TestCase): + """The re-ingest endpoint that pushes a stored PDF back into the KB. + + A PDFResource can legitimately exist with no local file (tracking-only + rows created when the KB doc's bytes were never downloaded). Re-ingesting + such a row has no bytes to send, so it must fail cleanly instead of + raising ValueError from the empty FileField. + """ + + URL = "/hopper/ask/kb/add-pdf-to-kb/" + + def setUp(self): + media_root = tempfile.mkdtemp() + self.addCleanup(shutil.rmtree, media_root, ignore_errors=True) + override = override_settings(MEDIA_ROOT=media_root) + override.enable() + self.addCleanup(override.disable) + + self.user = User.objects.create_user("curator", password="pw") + self.user.user_permissions.add( + Permission.objects.get(codename="change_pdfresource") + ) + TermsAcceptance.objects.create( + user=self.user, terms_version=settings.TERMS_VERSION + ) + self.client.force_login(self.user) + + def _post(self, body): + return self.client.post( + self.URL, data=json.dumps(body), content_type="application/json" + ) + + @patch("ask.views.add_pdf_to_kb") + def test_resource_without_file_fails_cleanly(self, mock_add): + pdf = PDFResource.objects.create(title="Tracking only", creator=self.user) + resp = self._post({"id": pdf.id}) + self.assertEqual(resp.status_code, 400) + self.assertFalse(resp.json()["success"]) + mock_add.assert_not_called() + + @patch("ask.views.add_pdf_to_kb") + def test_resource_with_file_is_reingested(self, mock_add): + mock_add.return_value = {"doc_id": 321} + pdf = PDFResource(title="Real report", creator=self.user) + pdf.file.save("report.pdf", ContentFile(b"%PDF-1.4 real"), save=True) + resp = self._post({"id": pdf.id}) + self.assertEqual(resp.status_code, 200) + self.assertTrue(resp.json()["success"]) + pdf.refresh_from_db() + self.assertEqual(pdf.mcp_kb_document_id, 321) + + class DownloadKBPdfHelperTests(TestCase): """Unit tests for the new kb_connector.download_kb_pdf helper.""" diff --git a/hospexplorer/ask/views.py b/hospexplorer/ask/views.py index 6135717..a30e174 100644 --- a/hospexplorer/ask/views.py +++ b/hospexplorer/ask/views.py @@ -547,6 +547,15 @@ def kb_add_pdf_to_mcp(request): except PDFResource.DoesNotExist: return JsonResponse({"success": False, "error": "Resource not found."}, status=404) + # Tracking-only resources (created without downloading the KB bytes) have no + # local file, so there is nothing to re-ingest — fail cleanly instead of + # letting the empty FileField raise ValueError. + if not resource.file: + return JsonResponse( + {"success": False, "error": "No local file is stored for this resource, so it can't be re-added to the Knowledge Base. Re-upload the PDF instead."}, + status=400, + ) + try: resource.file.open("rb") file_bytes = resource.file.read()