Skip to content
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
22 changes: 20 additions & 2 deletions postman/collections/ros2-medkit-gateway.postman_collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"name": "Discovery",
"item": [
{
"name": "GET Gateway Info",
"name": "GET Server Capabilities",
"request": {
"method": "GET",
"header": [],
Expand All @@ -22,7 +22,25 @@
""
]
},
"description": "Get gateway status and version information"
"description": "Get server capabilities and entry points (REQ_INTEROP_010). Returns server name, version, available endpoints, and capabilities."
},
"response": []
},
{
"name": "GET Version Info",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/version-info",
"host": [
"{{base_url}}"
],
"path": [
"version-info"
]
},
"description": "Get gateway status and version information (REQ_INTEROP_001). Returns status, version, and timestamp."
},
"response": []
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class RESTServer {
// Route handlers
void handle_health(const httplib::Request& req, httplib::Response& res);
void handle_root(const httplib::Request& req, httplib::Response& res);
void handle_version_info(const httplib::Request& req, httplib::Response& res);
void handle_list_areas(const httplib::Request& req, httplib::Response& res);
void handle_list_components(const httplib::Request& req, httplib::Response& res);
void handle_area_components(const httplib::Request& req, httplib::Response& res);
Expand Down
46 changes: 44 additions & 2 deletions src/ros2_medkit_gateway/src/rest_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,16 @@ void RESTServer::setup_routes() {
handle_health(req, res);
});

// Root
// Root - server capabilities and entry points (REQ_INTEROP_010)
server_->Get("/", [this](const httplib::Request& req, httplib::Response& res) {
handle_root(req, res);
});

// Version info (REQ_INTEROP_001)
server_->Get("/version-info", [this](const httplib::Request& req, httplib::Response& res) {
handle_version_info(req, res);
});

// Areas
server_->Get("/areas", [this](const httplib::Request& req, httplib::Response& res) {
handle_list_areas(req, res);
Expand Down Expand Up @@ -160,6 +165,39 @@ void RESTServer::handle_health(const httplib::Request& req, httplib::Response& r
void RESTServer::handle_root(const httplib::Request& req, httplib::Response& res) {
(void)req; // Unused parameter

try {
json response = {
{"name", "ROS 2 Medkit Gateway"},
{"version", "0.1.0"},
{"endpoints", json::array({
"/health",
"/version-info",
"/areas",
"/components",
"/areas/{area_id}/components",
"/components/{component_id}/data",
"/components/{component_id}/data/{topic_name}"
})},
{"capabilities", {
{"discovery", true},
{"data_access", true}
}}
};

res.set_content(response.dump(2), "application/json");
} catch (const std::exception& e) {
res.status = StatusCode::InternalServerError_500;
res.set_content(
json{{"error", "Internal server error"}}.dump(),
"application/json"
);
RCLCPP_ERROR(rclcpp::get_logger("rest_server"), "Error in handle_root: %s", e.what());
}
}
Comment thread
mfaferek93 marked this conversation as resolved.

void RESTServer::handle_version_info(const httplib::Request& req, httplib::Response& res) {
(void)req; // Unused parameter

try {
json response = {
{"status", "ROS 2 Medkit Gateway running"},
Expand All @@ -174,7 +212,11 @@ void RESTServer::handle_root(const httplib::Request& req, httplib::Response& res
json{{"error", "Internal server error"}}.dump(),
"application/json"
);
RCLCPP_ERROR(rclcpp::get_logger("rest_server"), "Error in handle_root: %s", e.what());
RCLCPP_ERROR(
rclcpp::get_logger("rest_server"),
"Error in handle_version_info: %s",
e.what()
);
}
}

Expand Down
24 changes: 20 additions & 4 deletions src/ros2_medkit_gateway/test/test_gateway_node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,22 @@ class GatewayNode : public rclcpp::Node {
(void)req;

nlohmann::json info_json = {
{"service", "ros2_medkit_gateway"},
{"name", "ROS 2 Medkit Gateway"},
{"version", VERSION},
{"endpoints", nlohmann::json::array({"/health", "/"})}};
{"endpoints", nlohmann::json::array({
"/health",
"/version-info",
"/areas",
"/components",
"/areas/{area_id}/components",
"/components/{component_id}/data",
"/components/{component_id}/data/{topic_name}"
})},
{"capabilities", {
{"discovery", true},
{"data_access", true}
}}
};

res.set_content(info_json.dump(), "application/json");
res.status = 200;
Expand Down Expand Up @@ -155,11 +168,14 @@ TEST_F(TestGatewayNode, test_root_endpoint) {

// Parse and verify JSON
auto json_response = nlohmann::json::parse(res->body);
EXPECT_EQ(json_response["service"], "ros2_medkit_gateway");
EXPECT_EQ(json_response["name"], "ROS 2 Medkit Gateway");
EXPECT_EQ(json_response["version"], "0.1.0");
EXPECT_TRUE(json_response.contains("endpoints"));
EXPECT_TRUE(json_response["endpoints"].is_array());
EXPECT_EQ(json_response["endpoints"].size(), 2);
EXPECT_EQ(json_response["endpoints"].size(), 7);
EXPECT_TRUE(json_response.contains("capabilities"));
EXPECT_TRUE(json_response["capabilities"]["discovery"]);
EXPECT_TRUE(json_response["capabilities"]["data_access"]);
}

int main(int argc, char **argv) {
Expand Down
35 changes: 33 additions & 2 deletions src/ros2_medkit_gateway/test/test_integration.test.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,16 +167,47 @@ def _get_json(self, endpoint: str):

def test_01_root_endpoint(self):
"""
Test GET / returns gateway status and version.
Test GET / returns server capabilities and entry points.

@verifies REQ_INTEROP_010
"""
data = self._get_json('/')
self.assertIn('name', data)
self.assertIn('version', data)
self.assertIn('endpoints', data)
self.assertIn('capabilities', data)

self.assertEqual(data['name'], 'ROS 2 Medkit Gateway')
self.assertEqual(data['version'], '0.1.0')

# Verify endpoints list
self.assertIsInstance(data['endpoints'], list)
self.assertIn('/health', data['endpoints'])
self.assertIn('/version-info', data['endpoints'])
self.assertIn('/areas', data['endpoints'])
self.assertIn('/components', data['endpoints'])
Comment thread
mfaferek93 marked this conversation as resolved.

# Verify capabilities
self.assertIn('discovery', data['capabilities'])
self.assertIn('data_access', data['capabilities'])
self.assertTrue(data['capabilities']['discovery'])
self.assertTrue(data['capabilities']['data_access'])
print('✓ Root endpoint test passed')

def test_01b_version_info_endpoint(self):
"""
Test GET /version-info returns gateway status and version.

@verifies REQ_INTEROP_001
"""
data = self._get_json('/version-info')
self.assertIn('status', data)
self.assertIn('version', data)
self.assertIn('timestamp', data)
self.assertEqual(data['status'], 'ROS 2 Medkit Gateway running')
self.assertEqual(data['version'], '0.1.0')
print('✓ Root endpoint test passed')
self.assertIsInstance(data['timestamp'], int)
print('✓ Version info endpoint test passed')

def test_02_list_areas(self):
"""
Expand Down