mgw / tests /test_app.py
alessandro trinca tornidor
ci: add docker and docker compose support
d7027f5
raw
history blame
9.12 kB
import asyncio
import unittest
from unittest.mock import patch, MagicMock
from fastapi import Request
from fastapi.testclient import TestClient
from my_ghost_writer.app import app, mongo_health_check_background_task, lifespan
class TestAppEndpoints(unittest.TestCase):
def setUp(self):
self.client = TestClient(app)
def tearDown(self) -> None:
self.client.close()
return super().tearDown()
def test_health(self):
response = self.client.get("/health")
self.assertEqual(response.status_code, 200)
self.assertIn("Still alive", response.text)
@patch("my_ghost_writer.app.mongodb_health_check")
@patch("my_ghost_writer.app.pymongo_version", "8.0.0")
def test_health_mongo_ok(self, mock_health_check):
mock_health_check.return_value = True
response = self.client.get("/health-mongo")
self.assertEqual(response.status_code, 200)
self.assertIn("Mongodb: still alive", response.text)
@patch("my_ghost_writer.app.mongodb_health_check", side_effect=Exception("mongo error"))
def test_health_mongo_fail(self, mock_health_check):
mock_health_check.side_effect = Exception("mongo error")
response = self.client.get("/health-mongo")
self.assertNotEqual(response.status_code, 200)
self.assertEqual(response.status_code, 500)
@patch("my_ghost_writer.app.text_stemming")
def test_words_frequency(self, mock_stemming):
mock_stemming.return_value = (1, {"word": 2})
body = '{"text": "test test"}'
response = self.client.post("/words-frequency", json=body)
self.assertEqual(response.status_code, 200)
self.assertIn("words_frequency", response.json())
def test_words_frequency_fail_request(self):
body = '{}'
response = self.client.post("/words-frequency", json=body)
self.assertEqual(response.status_code, 500)
@patch("my_ghost_writer.app.text_stemming")
def test_words_frequency_fail2(self, mock_stemming):
mock_stemming.side_effect = ValueError("stemming error")
body = '{"text": "test test"}'
response = self.client.post("/words-frequency", json=body)
self.assertEqual(response.status_code, 500)
@patch("my_ghost_writer.app.pymongo_operations_rw.get_document_by_word")
def test_thesaurus_wordsapi_local(self, mock_get_doc):
mock_get_doc.return_value = {"word": "test"}
with patch("my_ghost_writer.app.db_ok", {"mongo_ok": True}):
body = '{"query": "test"}'
response = self.client.post("/thesaurus-wordsapi", json=body)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json()["source"], "local")
@patch("my_ghost_writer.app.WORDSAPI_URL", "http://mocked-url.com")
@patch("my_ghost_writer.app.RAPIDAPI_HOST", "mocked-rapidapi-host.com")
@patch("my_ghost_writer.app.WORDSAPI_KEY", "WORDSAPI_KEY")
@patch("my_ghost_writer.app.requests.get")
@patch("my_ghost_writer.app.pymongo_operations_rw.get_document_by_word", side_effect=AssertionError)
@patch("my_ghost_writer.app.pymongo_operations_rw.insert_document")
def test_thesaurus_wordsapi_remote_mongo_ok(self, mock_insert, mock_get_doc, mock_requests_get):
mock_get_doc.return_value = None
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {"word": "test", "_id": "_id"}
mock_requests_get.return_value = mock_response
with patch("my_ghost_writer.app.db_ok", {"mongo_ok": True}):
body = '{"query": "test"}'
response = self.client.post("/thesaurus-wordsapi", json=body)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json()["source"], "wordsapi")
@patch("my_ghost_writer.app.requests.get")
def test_thesaurus_wordsapi_remote_404(self, mock_requests_get):
mock_response = MagicMock()
mock_response.status_code = 404
mock_response.json.return_value = {"error": "not found"}
mock_requests_get.return_value = mock_response
with patch("my_ghost_writer.app.db_ok", {"mongo_ok": True}):
body = '{"query": "test"}'
response = self.client.post("/thesaurus-wordsapi", json=body)
self.assertEqual(response.status_code, 404)
response_json = response.json()
self.assertDictEqual({'msg': {'error': 'not found'}}, response_json)
@patch("my_ghost_writer.app.requests.get")
def test_thesaurus_wordsapi_remote_500(self, mock_requests_get):
mock_response = MagicMock()
mock_response.status_code = 500
mock_requests_get.side_effect = Exception("test exception")
with patch("my_ghost_writer.app.db_ok", {"mongo_ok": True}):
body = '{"query": "test"}'
response = self.client.post("/thesaurus-wordsapi", json=body)
self.assertEqual(response.status_code, 500)
response_text = response.text
self.assertEqual("", response_text)
@patch("my_ghost_writer.app.WORDSAPI_URL", "http://mocked-url.com")
@patch("my_ghost_writer.app.RAPIDAPI_HOST", "mocked-rapidapi-host.com")
@patch("my_ghost_writer.app.WORDSAPI_KEY", "WORDSAPI_KEY")
@patch("my_ghost_writer.app.requests.get")
def test_thesaurus_wordsapi_remote_mongo_disabled(self, mock_requests_get):
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {"word": "test", "_id": "_id"}
mock_requests_get.return_value = mock_response
with patch("my_ghost_writer.app.db_ok", {"mongo_ok": False}):
body = '{"query": "test"}'
response = self.client.post("/thesaurus-wordsapi", json=body)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json()["source"], "wordsapi")
@patch("my_ghost_writer.app.WORDSAPI_URL", "http://mocked-url.com")
@patch("my_ghost_writer.app.RAPIDAPI_HOST", "mocked-rapidapi-host.com")
@patch("my_ghost_writer.app.WORDSAPI_KEY", "WORDSAPI_KEY")
@patch("my_ghost_writer.app.requests.get")
def test_thesaurus_wordsapi_remote_mongo_disabled_fail(self, mock_requests_get):
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {"word": "test", "_id": "_id"}
mock_requests_get.side_effect = IOError("io error")
with patch("my_ghost_writer.app.db_ok", {"mongo_ok": False}):
body = '{"query": "test"}'
response = self.client.post("/thesaurus-wordsapi", json=body)
self.assertEqual(response.status_code, 500)
self.assertEqual(response.text, "")
def test_lifespan(self):
# Test that lifespan yields and cancels the task
async def run_lifespan():
gen = lifespan(app)
await gen.asend(None)
await gen.aclose()
asyncio.run(run_lifespan())
def test_mongo_health_check_background_task(self):
# Patch sleep and health_mongo to exit after one loop
with patch("my_ghost_writer.app.ME_CONFIG_MONGODB_USE_OK", True), \
patch("my_ghost_writer.app.health_mongo", return_value="Mongodb: still alive..."), \
patch("my_ghost_writer.app.asyncio.sleep", side_effect=Exception("stop")):
with self.assertRaises(Exception):
asyncio.run(mongo_health_check_background_task())
def test_index_route(self):
from pathlib import Path
import tempfile
with tempfile.TemporaryDirectory() as tmpdir:
index_path = Path(tmpdir) / "index.html"
index_path.write_text("<html>Test</html>")
with patch("my_ghost_writer.app.STATIC_FOLDER", Path(tmpdir)):
response = self.client.get("/")
self.assertEqual(response.status_code, 200)
self.assertIn("Test", response.text)
def test_static_route(self):
with patch("my_ghost_writer.app.STATIC_FOLDER") as mock_static:
mock_static.__truediv__.return_value = "index.html"
response = self.client.get("/static/")
self.assertEqual(response.status_code, 200)
@patch("my_ghost_writer.app.exception_handlers.request_validation_exception_handler")
def test_request_validation_exception_handler(self, mock_handler):
req = MagicMock(spec=Request)
exc = MagicMock()
from my_ghost_writer.app import request_validation_exception_handler
request_validation_exception_handler(req, exc)
mock_handler.assert_called_once_with(req, exc)
@patch("my_ghost_writer.app.exception_handlers.http_exception_handler")
def test_http_exception_handler(self, mock_handler):
req = MagicMock(spec=Request)
exc = MagicMock()
from my_ghost_writer.app import http_exception_handler
http_exception_handler(req, exc)
mock_handler.assert_called_once_with(req, exc)
if __name__ == "__main__":
unittest.main()