Skip to content

Api updates for spa work #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ services:
environment:
MONGO_CONNECTION_STRING: mongodb://mongodb:27017/?replicaSet=rs0
MONGO_DB_NAME: test_database
MONGODB_API_PORT: 8081
AUTO_PROCESS: True
LOAD_TEST_DATA: True
depends_on:
Expand Down
8 changes: 0 additions & 8 deletions docs/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -366,14 +366,6 @@ components:
- default
- file
- environment
versions:
type: array
description: List of version information
items:
type: object
enumerators:
type: object
description: Dictionary of enumerations
token:
type: object
properties:
Expand Down
4 changes: 2 additions & 2 deletions stage0_mongodb_api/routes/collection_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def process_collections():
"message": str(e)
}]), 500

@blueprint.route('/<collection_name>', methods=['GET'])
@blueprint.route('/<collection_name>/', methods=['GET'])
def get_collection(collection_name):
"""Get a specific collection configuration"""
token = create_flask_token()
Expand All @@ -74,7 +74,7 @@ def get_collection(collection_name):
"message": str(e)
}]), 500

@blueprint.route('/<collection_name>', methods=['POST'])
@blueprint.route('/<collection_name>/', methods=['POST'])
def process_collection(collection_name):
"""Process a specific collection"""
token = create_flask_token()
Expand Down
3 changes: 3 additions & 0 deletions stage0_mongodb_api/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ def handle_exit(signum, frame):
app = Flask(__name__)
app.json = MongoJSONEncoder(app)

# Configure Flask to be strict about trailing slashes
app.url_map.strict_slashes = False

# Auto-processing logic - runs when module is imported (including by Gunicorn)
if config.AUTO_PROCESS:
logger.info(f"============= Auto Processing is Enabled ===============")
Expand Down
13 changes: 8 additions & 5 deletions stage0_mongodb_api/services/collection_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ class CollectionService:
"""

@staticmethod
def list_collections(token: Dict = None) -> Dict:
def list_collections(token: Dict = None) -> List[Dict]:
"""List all configured collections.

Args:
token: Authentication token for RBAC enforcement

Returns:
Dictionary of collection name: version string
List of dictionaries with collection_name and version

Raises:
CollectionProcessingError: If there are load or validation errors
Expand All @@ -49,10 +49,13 @@ def list_collections(token: Dict = None) -> Dict:
if validation_errors:
raise CollectionProcessingError("collections", validation_errors)

# Create a dict of collection name: version string
collections = {}
# Create a list of collection objects matching the OpenAPI schema
collections = []
for collection_name, collection in config_manager.collection_configs.items():
collections[collection_name] = VersionManager.get_current_version(collection_name)
collections.append({
"collection_name": collection_name,
"version": VersionManager.get_current_version(collection_name)
})
return collections

@staticmethod
Expand Down
26 changes: 13 additions & 13 deletions tests/routes/test_collection_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ def setUp(self):
def test_list_collections_success(self, mock_collection_service):
"""Test listing all collections successfully"""
# Arrange
mock_collections = {
"users": "1.0.0.1",
"organizations": "1.0.0.1"
}
mock_collections = [
{"collection_name": "users", "version": "1.0.0.1"},
{"collection_name": "organizations", "version": "1.0.0.1"}
]
mock_collection_service.list_collections.return_value = mock_collections

# Act
Expand Down Expand Up @@ -98,12 +98,12 @@ def test_get_collection_success(self, mock_collection_service):
mock_collection_service.get_collection.return_value = mock_collection

# Act
response = self.client.get(f'/api/collections/users')
response = self.client.get(f'/api/collections/{collection_name}/')

# Assert
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json, mock_collection)
mock_collection_service.get_collection.assert_called_once()
mock_collection_service.get_collection.assert_called_once_with(collection_name, mock_collection_service.get_collection.call_args[0][1])

@patch('stage0_mongodb_api.routes.collection_routes.CollectionService')
def test_get_collection_not_found(self, mock_collection_service):
Expand All @@ -113,7 +113,7 @@ def test_get_collection_not_found(self, mock_collection_service):
mock_collection_service.get_collection.side_effect = CollectionNotFoundError(collection_name)

# Act
response = self.client.get(f'/api/collections/{collection_name}')
response = self.client.get(f'/api/collections/{collection_name}/')

# Assert
self.assertEqual(response.status_code, 404)
Expand All @@ -128,7 +128,7 @@ def test_get_collection_processing_error(self, mock_collection_service):
mock_collection_service.get_collection.side_effect = CollectionProcessingError(collection_name, errors)

# Act
response = self.client.get(f'/api/collections/{collection_name}')
response = self.client.get(f'/api/collections/{collection_name}/')

# Assert
self.assertEqual(response.status_code, 500)
Expand All @@ -147,12 +147,12 @@ def test_process_specific_collection_success(self, mock_collection_service):
mock_collection_service.process_collection.return_value = mock_result

# Act
response = self.client.post(f'/api/collections/{collection_name}')
response = self.client.post(f'/api/collections/{collection_name}/')

# Assert
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json, mock_result)
mock_collection_service.process_collection.assert_called_once()
mock_collection_service.process_collection.assert_called_once_with(collection_name, mock_collection_service.process_collection.call_args[0][1])

@patch('stage0_mongodb_api.routes.collection_routes.CollectionService')
def test_process_specific_collection_not_found(self, mock_collection_service):
Expand All @@ -162,7 +162,7 @@ def test_process_specific_collection_not_found(self, mock_collection_service):
mock_collection_service.process_collection.side_effect = CollectionNotFoundError(collection_name)

# Act
response = self.client.post(f'/api/collections/{collection_name}')
response = self.client.post(f'/api/collections/{collection_name}/')

# Assert
self.assertEqual(response.status_code, 404)
Expand All @@ -177,7 +177,7 @@ def test_process_specific_collection_processing_error(self, mock_collection_serv
mock_collection_service.process_collection.side_effect = CollectionProcessingError(collection_name, errors)

# Act
response = self.client.post(f'/api/collections/{collection_name}')
response = self.client.post(f'/api/collections/{collection_name}/')

# Assert
self.assertEqual(response.status_code, 500)
Expand All @@ -191,7 +191,7 @@ def test_process_specific_collection_unexpected_error(self, mock_collection_serv
mock_collection_service.process_collection.side_effect = Exception("Unexpected error")

# Act
response = self.client.post(f'/api/collections/{collection_name}')
response = self.client.post(f'/api/collections/{collection_name}/')

# Assert
self.assertEqual(response.status_code, 500)
Expand Down
7 changes: 4 additions & 3 deletions tests/services/test_collection_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ def test_list_collections_success(self, mock_config_manager):
mock_config_manager.return_value.load_errors = None
mock_config_manager.return_value.validate_configs.return_value = []
with patch('stage0_mongodb_api.services.collection_service.VersionManager') as mock_version_manager:
mock_version_manager.get_version_string.return_value = "simple.1.0.0.1"
mock_version_manager.get_current_version.return_value = "simple.1.0.0.1"
result = CollectionService.list_collections()
self.assertEqual(len(result), 1)
self.assertIsInstance(result, dict)
self.assertIn("simple", result)
self.assertIsInstance(result, list)
self.assertEqual(result[0]["collection_name"], "simple")
self.assertEqual(result[0]["version"], "simple.1.0.0.1")

@patch('stage0_mongodb_api.services.collection_service.ConfigManager')
def test_list_collections_load_error(self, mock_config_manager):
Expand Down
15 changes: 11 additions & 4 deletions tests/stepci/small_sample.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,17 @@ tests:
check:
status: /200/
schema:
type: "object"
properties:
simple:
type: "string"
type: "array"
items:
type: "object"
properties:
collection_name:
type: "string"
version:
type: "string"
required:
- collection_name
- version
- name: GET A Collection
http:
url: http://${{env.host}}/api/collections/simple
Expand Down
14 changes: 9 additions & 5 deletions tests/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ class TestServer(unittest.TestCase):
def setUp(self):
"""Set up test fixtures."""
self.app = app.test_client()
# Patch MongoIO for every test to ensure no real DB connection
patcher = patch('stage0_py_utils.MongoIO.get_instance', return_value=MagicMock())
self.addCleanup(patcher.stop)
self.mock_mongo = patcher.start()

def test_app_initialization(self):
"""Test Flask app initialization."""
Expand All @@ -47,11 +51,11 @@ def test_config_routes_registered(self):

def test_collection_routes_registered(self):
"""Test collection routes are registered."""
# Act
response = self.app.get('/api/collections')

# Assert
self.assertNotEqual(response.status_code, 404)
with patch('stage0_mongodb_api.routes.collection_routes.CollectionService.list_collections', return_value=[{"collection_name": "dummy", "version": "1.0.0"}]):
# Act
response = self.app.get('/api/collections/')
# Assert
self.assertEqual(response.status_code, 200)

def test_render_routes_registered(self):
"""Test render routes are registered."""
Expand Down
Loading