"""Test Abacus State Bulk Query functional.""" import pytest from abacus_state.constants import error from tests.utils.factories import AbacusStateFactory pytestmark = [pytest.mark.db('mysql')] def test_bulk_query_no_filters(fixture_client): """Test bulk query without filters returns all states.""" state1 = AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=1, action_name='deliver_sales_files', action_status='complete', ) state2 = AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=2, action_name='approve_sales_files', action_status='init', ) state3 = AbacusStateFactory.create( parent_table_name='payment_group_payment', parent_table_id=1, action_name='generate_payments', action_status='running', ) res = fixture_client.post('/abacus-states/query', json={}) assert res.status_code == 200 assert res.json['total'] == 3 assert res.json['limit'] == 100 assert res.json['offset'] == 0 assert len(res.json['items']) == 3 def test_bulk_query_filter_by_parent_table_name(fixture_client): """Test bulk query filtering by parent_table_name.""" state1 = AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=1, action_name='deliver_sales_files', ) state2 = AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=2, action_name='approve_sales_files', ) state3 = AbacusStateFactory.create( parent_table_name='payment_group_payment', parent_table_id=1, action_name='generate_payments', ) res = fixture_client.post( '/abacus-states/query', json={'parent_table_name': 'accounting_period'} ) assert res.status_code == 200 assert res.json['total'] == 2 assert len(res.json['items']) == 2 for item in res.json['items']: assert item['parent_table_name'] == 'accounting_period' def test_bulk_query_filter_by_parent_table_ids(fixture_client): """Test bulk query filtering by parent_table_name and parent_table_ids.""" state1 = AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=1, action_name='deliver_sales_files', ) state2 = AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=2, action_name='deliver_sales_files', ) state3 = AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=3, action_name='deliver_sales_files', ) res = fixture_client.post( '/abacus-states/query', json={'parent_table_name': 'accounting_period', 'parent_table_ids': [1, 3]}, ) assert res.status_code == 200 assert res.json['total'] == 2 assert len(res.json['items']) == 2 parent_ids = [item['parent_table_id'] for item in res.json['items']] assert 1 in parent_ids assert 3 in parent_ids assert 2 not in parent_ids def test_bulk_query_filter_by_action_name(fixture_client): """Test bulk query filtering by action_name.""" state1 = AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=1, action_name='deliver_sales_files', ) state2 = AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=2, action_name='approve_sales_files', ) state3 = AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=3, action_name='deliver_sales_files', ) res = fixture_client.post( '/abacus-states/query', json={'action_name': 'deliver_sales_files'} ) assert res.status_code == 200 assert res.json['total'] == 2 assert len(res.json['items']) == 2 for item in res.json['items']: assert item['action_name'] == 'deliver_sales_files' def test_bulk_query_combined_filters(fixture_client): """Test bulk query with multiple filters combined.""" state1 = AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=1, action_name='deliver_sales_files', ) state2 = AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=2, action_name='deliver_sales_files', ) state3 = AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=3, action_name='approve_sales_files', ) state4 = AbacusStateFactory.create( parent_table_name='payment_group_payment', parent_table_id=1, action_name='deliver_sales_files', ) res = fixture_client.post( '/abacus-states/query', json={ 'parent_table_name': 'accounting_period', 'action_name': 'deliver_sales_files', 'parent_table_ids': [1, 2], }, ) assert res.status_code == 200 assert res.json['total'] == 2 assert len(res.json['items']) == 2 for item in res.json['items']: assert item['parent_table_name'] == 'accounting_period' assert item['action_name'] == 'deliver_sales_files' assert item['parent_table_id'] in [1, 2] def test_bulk_query_pagination_limit(fixture_client): """Test bulk query with limit parameter.""" for i in range(1, 6): AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=i, action_name='deliver_sales_files', ) res = fixture_client.post('/abacus-states/query?limit=3') assert res.status_code == 200 assert res.json['total'] == 5 assert res.json['limit'] == 3 assert res.json['offset'] == 0 assert len(res.json['items']) == 3 def test_bulk_query_pagination_offset(fixture_client): """Test bulk query with offset parameter.""" states = [] for i in range(1, 6): state = AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=i, action_name='deliver_sales_files', ) states.append(state) res = fixture_client.post('/abacus-states/query?limit=2&offset=2') assert res.status_code == 200 assert res.json['total'] == 5 assert res.json['limit'] == 2 assert res.json['offset'] == 2 assert len(res.json['items']) == 2 def test_bulk_query_pagination_limit_and_offset(fixture_client): """Test bulk query with both limit and offset parameters.""" for i in range(1, 11): AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=i, action_name='deliver_sales_files', ) res = fixture_client.post('/abacus-states/query?limit=3&offset=5') assert res.status_code == 200 assert res.json['total'] == 10 assert res.json['limit'] == 3 assert res.json['offset'] == 5 assert len(res.json['items']) == 3 def test_bulk_query_limit_max_cap(fixture_client): """Test that limit exceeding max returns 400 error.""" AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=1, action_name='deliver_sales_files', ) res = fixture_client.post('/abacus-states/query?limit=5000') assert res.status_code == 422 def test_bulk_query_limit_default(fixture_client): """Test that default limit is 100.""" AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=1, action_name='deliver_sales_files', ) res = fixture_client.post('/abacus-states/query', json={}) assert res.status_code == 200 assert res.json['limit'] == 100 def test_bulk_query_negative_limit(fixture_client): """Test that negative limit returns 400 error.""" AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=1, action_name='deliver_sales_files', ) res = fixture_client.post('/abacus-states/query?limit=-5') assert res.status_code == 422 def test_bulk_query_negative_offset(fixture_client): """Test that negative offset returns 400 error.""" AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=1, action_name='deliver_sales_files', ) res = fixture_client.post('/abacus-states/query?offset=-5') assert res.status_code == 422 def test_bulk_query_extremely_large_offset(fixture_client): """Test that extremely large offset returns 422 error.""" AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=1, action_name='deliver_sales_files', ) res = fixture_client.post('/abacus-states/query?offset=999999999999999999999') assert res.status_code == 422 def test_bulk_query_zero_limit(fixture_client): """Test that limit=0 is accepted and returns empty results.""" AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=1, action_name='deliver_sales_files', ) AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=2, action_name='deliver_sales_files', ) res = fixture_client.post('/abacus-states/query?limit=0') assert res.status_code == 200 assert res.json['total'] == 2 assert res.json['limit'] == 0 assert res.json['offset'] == 0 assert len(res.json['items']) == 0 def test_bulk_query_parent_table_ids_without_parent_table_name_error(fixture_client): """Test that parent_table_ids without parent_table_name returns error.""" AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=1, action_name='deliver_sales_files', ) res = fixture_client.post('/abacus-states/query', json={'parent_table_ids': [1]}) assert res.status_code == 400 assert res.json['code'] == 'error' assert error.ERROR_PARENT_TABLE_IDS_REQUIRE_PARENT_TABLE_NAME in res.json['message'] def test_bulk_query_invalid_parent_table_name_error(fixture_client): """Test that invalid parent_table_name returns error.""" AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=1, action_name='deliver_sales_files', ) res = fixture_client.post( '/abacus-states/query', json={'parent_table_name': 'invalid_table'} ) assert res.status_code == 400 assert res.json['code'] == 'error' assert error.ERROR_INVALID_PARENT_TABLE_NAME in res.json['message'] def test_bulk_query_empty_results(fixture_client): """Test bulk query returns empty list when no matches.""" AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=1, action_name='deliver_sales_files', ) res = fixture_client.post( '/abacus-states/query', json={'parent_table_name': 'payment_group_payment'} ) assert res.status_code == 200 assert res.json['total'] == 0 assert len(res.json['items']) == 0 def test_bulk_query_ordering(fixture_client): """Test that results are ordered by abacus_state_id ascending.""" state3 = AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=3, action_name='deliver_sales_files', ) state1 = AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=1, action_name='deliver_sales_files', ) state2 = AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=2, action_name='deliver_sales_files', ) res = fixture_client.post('/abacus-states/query', json={}) assert res.status_code == 200 assert len(res.json['items']) == 3 ids = [item['abacus_state_id'] for item in res.json['items']] assert ids == sorted(ids) def test_bulk_query_response_structure(fixture_client): """Test that response has correct structure.""" state = AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=1, action_name='deliver_sales_files', action_status='complete', ) res = fixture_client.post('/abacus-states/query', json={}) assert res.status_code == 200 assert 'items' in res.json assert 'total' in res.json assert 'limit' in res.json assert 'offset' in res.json assert isinstance(res.json['items'], list) assert len(res.json['items']) > 0 item = res.json['items'][0] assert 'abacus_state_id' in item assert 'parent_table_name' in item assert 'parent_table_id' in item assert 'action_name' in item assert 'action_status' in item assert 'created_at' in item assert 'created_by' in item assert 'last_modified' in item assert 'last_modified_by' in item def test_bulk_query_duplicate_parent_table_ids_error(fixture_client): """Test that duplicate parent_table_ids returns validation error.""" AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=1, action_name='deliver_sales_files', ) AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=2, action_name='deliver_sales_files', ) res = fixture_client.post( '/abacus-states/query', json={ 'parent_table_name': 'accounting_period', 'parent_table_ids': [1, 2, 1, 3], }, ) assert res.status_code == 422 assert res.json['code'] == 'error' def test_bulk_query_no_duplicate_parent_table_ids_success(fixture_client): """Test that unique parent_table_ids work correctly.""" state1 = AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=1, action_name='deliver_sales_files', ) state2 = AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=2, action_name='deliver_sales_files', ) state3 = AbacusStateFactory.create( parent_table_name='accounting_period', parent_table_id=3, action_name='deliver_sales_files', ) res = fixture_client.post( '/abacus-states/query', json={ 'parent_table_name': 'accounting_period', 'parent_table_ids': [1, 2, 3], }, ) assert res.status_code == 200 assert res.json['total'] == 3 assert len(res.json['items']) == 3 parent_ids = [item['parent_table_id'] for item in res.json['items']] assert set(parent_ids) == {1, 2, 3}