mission17-ai / test_chatbot_model_serialization.py
GitHub Action
sync: feat: harden BrgyLink auth and app flows
c8af596
Raw History Blame Contribute Delete
2.44 kB
"""Regression tests for safe on-disk chatbot model loading."""
import os
import pickle
import json
import tempfile
import unittest
from unittest.mock import patch
from chatbot_runtime import smart_classifier
_PICKLE_REDUCER_CALLED = False
def _pickle_reducer_marker():
global _PICKLE_REDUCER_CALLED
_PICKLE_REDUCER_CALLED = True
return {}
class _ExecutablePicklePayload:
def __reduce__(self):
return _pickle_reducer_marker, ()
class ChatbotModelSerializationTests(unittest.TestCase):
def test_model_training_round_trips_through_json(self):
with tempfile.TemporaryDirectory(dir=os.path.dirname(__file__)) as directory:
model_path = os.path.join(directory, "synthetic-model.json")
with patch.object(smart_classifier, "MODEL_FILE", model_path):
trained = smart_classifier.train()
loaded = smart_classifier.load_model()
with open(model_path, "r", encoding="utf-8") as model_file:
serialized = json.load(model_file)
self.assertEqual(loaded["version"], smart_classifier.MODEL_VERSION)
self.assertEqual(loaded["training_sha256"], serialized["training_sha256"])
self.assertEqual(loaded["centroids"], trained["centroids"])
before = smart_classifier.handle_message("How do I request a barangay clearance?", model=trained)
after = smart_classifier.handle_message("How do I request a barangay clearance?", model=loaded)
self.assertEqual(after["intent"], before["intent"])
self.assertEqual(after["response"], before["response"])
def test_model_loader_does_not_execute_pickle_payloads(self):
global _PICKLE_REDUCER_CALLED
_PICKLE_REDUCER_CALLED = False
with tempfile.TemporaryDirectory() as directory:
model_path = os.path.join(directory, "synthetic-model.json")
with open(model_path, "wb") as model_file:
model_file.write(pickle.dumps(_ExecutablePicklePayload()))
with patch.object(smart_classifier, "MODEL_FILE", model_path), \
patch.object(smart_classifier, "train", return_value={"safe": True}) as train:
self.assertEqual(smart_classifier.load_model(), {"safe": True})
self.assertFalse(_PICKLE_REDUCER_CALLED)
train.assert_called_once_with()
if __name__ == "__main__":
unittest.main()