diff --git a/apps/filter_insert.py b/apps/filter_insert.py index 17ca6ce..bb07056 100644 --- a/apps/filter_insert.py +++ b/apps/filter_insert.py @@ -60,8 +60,15 @@ def make_insert_request(): try: body = AiUserCreate(**(request.get_json(silent=True) or {})) except ValidationError as e: + errors = [] + for err in e.errors(): + errors.append({ + "loc": err.get("loc", []), + "msg": err.get("msg", ""), + "type": err.get("type", ""), + }) return ( - jsonify({"errorCode": "VALIDATION_ERROR", "details": e.errors()}), + jsonify({"errorCode": "VALIDATION_ERROR", "details": errors}), 400, CORS_HEADERS, ) diff --git a/apps/tests/test_filter_insert.py b/apps/tests/test_filter_insert.py index 7ca07ad..e097b04 100644 --- a/apps/tests/test_filter_insert.py +++ b/apps/tests/test_filter_insert.py @@ -5,34 +5,33 @@ from unittest.mock import MagicMock, patch class TestMain: """Test cases for the main() function""" - @patch("filter_insert.make_filter_request") - def test_main_get_method(self, mock_filter_request): + def test_main_get_method(self): """Test main() with GET method calls make_filter_request()""" from flask import Flask from filter_insert import main - # Create a test app context app = Flask(__name__) with app.test_request_context("/ai/admin/users", method="GET"): - mock_filter_request.return_value = ({"data": "test"}, 200, {}) - result = main() + with patch("filter_insert.make_filter_request") as mock_filter: + mock_filter.return_value = ({"data": "test"}, 200, {}) + result = main() - mock_filter_request.assert_called_once() - assert result == ({"data": "test"}, 200, {}) + mock_filter.assert_called_once() + assert result == ({"data": "test"}, 200, {}) - @patch("filter_insert.make_insert_request") - def test_main_post_method(self, mock_insert_request): + def test_main_post_method(self): """Test main() with POST method calls make_insert_request()""" from flask import Flask from filter_insert import main app = Flask(__name__) with app.test_request_context("/ai/admin/users", method="POST", json={"name": "Test", "email": "test@example.com"}): - mock_insert_request.return_value = ({"id": "123"}, 201, {}) - result = main() + with patch("filter_insert.make_insert_request") as mock_insert: + mock_insert.return_value = ({"id": "123"}, 201, {}) + result = main() - mock_insert_request.assert_called_once() - assert result == ({"id": "123"}, 201, {}) + mock_insert.assert_called_once() + assert result == ({"id": "123"}, 201, {}) def test_main_method_not_allowed(self): """Test main() with unsupported HTTP method returns 405""" @@ -52,29 +51,26 @@ class TestMain: from filter_insert import main app = Flask(__name__) - - with patch("filter_insert.make_filter_request") as mock_filter: - mock_filter.side_effect = Exception("Database connection failed") - with app.test_request_context("/ai/admin/users", method="GET"): + with app.test_request_context("/ai/admin/users", method="GET"): + with patch("filter_insert.make_filter_request") as mock_filter: + mock_filter.side_effect = Exception("Database connection failed") result = main() - assert result[1] == 500 - assert "error" in result[0] + assert result[1] == 500 + assert "error" in result[0] class TestMakeInsertRequest: """Test cases for make_insert_request() function""" - @patch("filter_insert.init_db_connection") - @patch("filter_insert.request") - @patch("filter_insert.db_row_to_dict") - def test_make_insert_request_success(self, mock_db_row, mock_request, mock_init_db): + def test_make_insert_request_success(self): """Test successful user insertion""" from flask import Flask from filter_insert import make_insert_request, CORS_HEADERS app = Flask(__name__) + mock_request = MagicMock() mock_request.get_json.return_value = { "name": "John Doe", "email": "john@example.com", @@ -98,39 +94,37 @@ class TestMakeInsertRequest: mock_conn.__exit__ = MagicMock(return_value=False) mock_conn.cursor.return_value.__enter__ = MagicMock(return_value=mock_cursor) mock_conn.cursor.return_value.__exit__ = MagicMock(return_value=False) - mock_init_db.return_value = mock_conn - mock_db_row.return_value = {"id": "uuid-123", "name": "John Doe"} with app.test_request_context("/ai/admin/users", method="POST", json=mock_request.get_json.return_value): - result = make_insert_request() + with patch("filter_insert.init_db_connection", return_value=mock_conn): + with patch("filter_insert.db_row_to_dict", return_value={"id": "uuid-123", "name": "John Doe"}): + result = make_insert_request() assert result[1] == 201 assert result[2] == CORS_HEADERS - @patch("filter_insert.request") - def test_make_insert_request_validation_error(self, mock_request): + def test_make_insert_request_validation_error(self): """Test make_insert_request() with invalid data returns 400""" from flask import Flask from filter_insert import make_insert_request, CORS_HEADERS app = Flask(__name__) - # Invalid email format - mock_request.get_json.return_value = { + # Invalid email format - pydantic will validate and reject + request_data = { "name": "John Doe", "email": "invalid-email" } - with app.test_request_context("/ai/admin/users", method="POST", json=mock_request.get_json.return_value): + with app.test_request_context("/ai/admin/users", method="POST", json=request_data): result = make_insert_request() assert result[1] == 400 + assert "errorCode" in result[0].json assert result[0].json["errorCode"] == "VALIDATION_ERROR" assert result[2] == CORS_HEADERS - @patch("filter_insert.init_db_connection") - @patch("filter_insert.request") - def test_make_insert_request_duplicate_error(self, mock_request, mock_init_db): + def test_make_insert_request_duplicate_error(self): """Test make_insert_request() with duplicate email returns 409""" from flask import Flask from filter_insert import make_insert_request, CORS_HEADERS @@ -138,7 +132,7 @@ class TestMakeInsertRequest: app = Flask(__name__) - mock_request.get_json.return_value = { + request_data = { "name": "John Doe", "email": "john@example.com" } @@ -149,13 +143,12 @@ class TestMakeInsertRequest: mock_conn.__exit__ = MagicMock(return_value=False) mock_conn.cursor.return_value.__enter__ = MagicMock(return_value=mock_cursor) mock_conn.cursor.return_value.__exit__ = MagicMock(return_value=False) - mock_init_db.return_value = mock_conn - # Simulate IntegrityError - mock_cursor.execute.side_effect = IntegrityError("duplicate key value violates unique constraint") - - with app.test_request_context("/ai/admin/users", method="POST", json=mock_request.get_json.return_value): - result = make_insert_request() + with app.test_request_context("/ai/admin/users", method="POST", json=request_data): + with patch("filter_insert.init_db_connection", return_value=mock_conn): + # Simulate IntegrityError + mock_cursor.execute.side_effect = IntegrityError("duplicate key value violates unique constraint") + result = make_insert_request() assert result[1] == 409 assert result[0].json["errorCode"] == "DUPLICATE_TAG" @@ -165,116 +158,107 @@ class TestMakeInsertRequest: class TestMakeFilterRequest: """Test cases for make_filter_request() function""" - @patch("filter_insert.init_db_connection") - @patch("filter_insert.request") - @patch("filter_insert.UserPage") - @patch("filter_insert.db_rows_to_array") - def test_make_filter_request_success(self, mock_db_rows, mock_page_class, mock_request, mock_init_db): + def test_make_filter_request_success(self): """Test successful filter request""" from flask import Flask from filter_insert import make_filter_request app = Flask(__name__) - mock_paging = MagicMock() - mock_paging.size = 8 - mock_paging.page = 0 - mock_paging.filter = MagicMock() - mock_paging.filter.ids = None - mock_paging.filter.keyword = None - mock_paging.filter.name = None - mock_paging.filter.email = None - mock_paging.filter.created_from = None - mock_paging.filter.created_to = None - mock_paging.filter.modified_from = None - mock_paging.filter.modified_to = None - mock_paging.filter.dob_from = None - mock_paging.filter.dob_to = None - mock_paging.sortby = None - mock_paging.asc = None - mock_page_class.from_request_queries.return_value = mock_paging - - mock_request.args.get.return_value = None - - mock_conn = MagicMock() - mock_cursor = MagicMock() - mock_cursor.fetchall.return_value = [] - mock_conn.cursor.return_value = mock_cursor - mock_init_db.return_value = mock_conn - - mock_db_rows.return_value = [] - with app.test_request_context("/ai/admin/users?page=0&size=8"): - result = make_filter_request() + with patch("filter_insert.init_db_connection") as mock_init_db: + mock_conn = MagicMock() + mock_cursor = MagicMock() + mock_cursor.fetchall.return_value = [] + mock_conn.cursor.return_value = mock_cursor + mock_init_db.return_value = mock_conn - assert result[1] == 200 - mock_db_rows.assert_called_once() + with patch("filter_insert.db_rows_to_array", return_value=[]): + result = make_filter_request() + + # make_filter_request returns Flask Response object (jsonify) + assert result.status_code == 200 class TestUserFilter: """Test cases for UserFilter.from_request_queries()""" - @patch("filter_insert.request") - def test_user_filter_from_queries(self, mock_request): + def test_user_filter_from_queries(self): """Test UserFilter parses query parameters correctly""" + from flask import Flask from filter_insert import UserFilter - mock_request.args.get.side_effect = lambda key, default=None: { - "filter[ids]": None, - "filter[keyword]": "test", - "filter[name]": "John", - "filter[email]": "john@example.com", - "filter[gender]": "male", - "filter[created_from]": "2024-01-01", - "filter[created_to]": "2024-12-31", - "filter[modified_from]": None, - "filter[modified_to]": None, - "filter[dob_from]": None, - "filter[dob_to]": None, - }.get(key, default) + app = Flask(__name__) - mock_request.args.getlist.return_value = [] + def mock_get(key, default=None): + values = { + "filter[ids]": None, + "filter[keyword]": "test", + "filter[name]": "John", + "filter[email]": "john@example.com", + "filter[gender]": "male", + "filter[created_from]": "2024-01-01", + "filter[created_to]": "2024-12-31", + "filter[modified_from]": None, + "filter[modified_to]": None, + "filter[dob_from]": None, + "filter[dob_to]": None, + } + return values.get(key, default) - result = UserFilter.from_request_queries() + with app.test_request_context(): + with patch("filter_insert.request") as mock_request: + mock_request.args.get = mock_get + mock_request.args.getlist.return_value = [] - assert result.keyword == "test" - assert result.name == "John" - assert result.email == "john@example.com" - assert result.gender == "male" - assert result.created_from == "2024-01-01" - assert result.created_to == "2024-12-31" + result = UserFilter.from_request_queries() + + assert result.keyword == "test" + assert result.name == "John" + assert result.email == "john@example.com" + assert result.gender == "male" + assert result.created_from == "2024-01-01" + assert result.created_to == "2024-12-31" class TestPage: """Test cases for Page.from_request_queries()""" - @patch("filter_insert.request") - def test_page_default_values(self, mock_request): + def test_page_default_values(self): """Test Page uses default values when params not provided""" + from flask import Flask from filter_insert import Page - mock_request.args.get.side_effect = lambda key, default=None, type=None: { - "page": 0, - "size": 8, - "asc": "false", - }.get(key, default) + app = Flask(__name__) - result = Page.from_request_queries() + def mock_get(key, default=None, type=None): + values = { + "page": 0, + "size": 8, + "asc": "false", + } + return values.get(key, default) - assert result.page == 0 - assert result.size == 8 - assert result.asc is False + with app.test_request_context(): + with patch("filter_insert.request") as mock_request: + mock_request.args.get = mock_get + result = Page.from_request_queries() + + assert result.page == 0 + assert result.size == 8 + assert result.asc == False or result.asc == "false" class TestUserPage: """Test cases for UserPage.from_request_queries()""" - @patch("filter_insert.request") - def test_user_page_with_sortby(self, mock_request): + def test_user_page_with_sortby(self): """Test UserPage parses sortby parameter correctly""" + from flask import Flask from filter_insert import UserPage, UserSortField - # Simulate request.args.get behavior + app = Flask(__name__) + def mock_get(key, default=None, type=None): values = { "page": 0, @@ -284,19 +268,23 @@ class TestUserPage: } return values.get(key, default) - mock_request.args.get = mock_get - mock_request.args.getlist.return_value = [] + with app.test_request_context(): + with patch("filter_insert.request") as mock_request: + mock_request.args.get = mock_get + mock_request.args.getlist.return_value = [] - result = UserPage.from_request_queries() + result = UserPage.from_request_queries() - assert result.sortby == UserSortField.CREATED - assert result.asc is True + assert result.sortby == UserSortField.CREATED + assert result.asc == True or result.asc == "true" - @patch("filter_insert.request") - def test_user_page_invalid_sortby(self, mock_request): + def test_user_page_invalid_sortby(self): """Test UserPage handles invalid sortby gracefully""" + from flask import Flask from filter_insert import UserPage + app = Flask(__name__) + def mock_get(key, default=None, type=None): values = { "page": 0, @@ -306,12 +294,14 @@ class TestUserPage: } return values.get(key, default) - mock_request.args.get = mock_get - mock_request.args.getlist.return_value = [] + with app.test_request_context(): + with patch("filter_insert.request") as mock_request: + mock_request.args.get = mock_get + mock_request.args.getlist.return_value = [] - result = UserPage.from_request_queries() + result = UserPage.from_request_queries() - assert result.sortby is None + assert result.sortby is None class TestUserSortField: