robosystems-client 0.1.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of robosystems-client might be problematic. Click here for more details.
- robosystems_client/__init__.py +14 -0
- robosystems_client/api/__init__.py +1 -0
- robosystems_client/api/agent/__init__.py +1 -0
- robosystems_client/api/agent/query_financial_agent.py +423 -0
- robosystems_client/api/auth/__init__.py +1 -0
- robosystems_client/api/auth/check_password_strength.py +172 -0
- robosystems_client/api/auth/complete_sso_auth.py +177 -0
- robosystems_client/api/auth/generate_sso_token.py +174 -0
- robosystems_client/api/auth/get_captcha_config.py +87 -0
- robosystems_client/api/auth/get_current_auth_user.py +220 -0
- robosystems_client/api/auth/get_password_policy.py +134 -0
- robosystems_client/api/auth/login_user.py +181 -0
- robosystems_client/api/auth/logout_user.py +169 -0
- robosystems_client/api/auth/refresh_session.py +174 -0
- robosystems_client/api/auth/register_user.py +189 -0
- robosystems_client/api/auth/sso_login.py +177 -0
- robosystems_client/api/auth/sso_token_exchange.py +181 -0
- robosystems_client/api/backup/__init__.py +1 -0
- robosystems_client/api/backup/create_backup.py +401 -0
- robosystems_client/api/backup/export_backup.py +225 -0
- robosystems_client/api/backup/get_backup_download_url.py +258 -0
- robosystems_client/api/backup/get_backup_stats.py +182 -0
- robosystems_client/api/backup/kuzu_backup_health.py +202 -0
- robosystems_client/api/backup/list_backups.py +217 -0
- robosystems_client/api/backup/restore_backup.py +401 -0
- robosystems_client/api/billing/__init__.py +1 -0
- robosystems_client/api/billing/get_available_subscription_plans_v1_graph_id_billing_available_plans_get.py +198 -0
- robosystems_client/api/billing/get_credit_billing_info_v1_graph_id_billing_credits_get.py +210 -0
- robosystems_client/api/billing/get_current_graph_bill.py +285 -0
- robosystems_client/api/billing/get_graph_billing_history.py +329 -0
- robosystems_client/api/billing/get_graph_monthly_bill.py +315 -0
- robosystems_client/api/billing/get_graph_pricing_info_v1_graph_id_billing_pricing_get.py +198 -0
- robosystems_client/api/billing/get_graph_subscription_v1_graph_id_billing_subscription_get.py +198 -0
- robosystems_client/api/billing/get_graph_usage_details.py +350 -0
- robosystems_client/api/billing/upgrade_graph_subscription_v1_graph_id_billing_subscription_upgrade_post.py +216 -0
- robosystems_client/api/connections/__init__.py +1 -0
- robosystems_client/api/connections/create_connection.py +327 -0
- robosystems_client/api/connections/create_link_token.py +281 -0
- robosystems_client/api/connections/delete_connection.py +278 -0
- robosystems_client/api/connections/exchange_link_token.py +301 -0
- robosystems_client/api/connections/get_connection.py +262 -0
- robosystems_client/api/connections/get_connection_options.py +285 -0
- robosystems_client/api/connections/init_o_auth.py +230 -0
- robosystems_client/api/connections/list_connections.py +314 -0
- robosystems_client/api/connections/oauth_callback.py +318 -0
- robosystems_client/api/connections/sync_connection.py +362 -0
- robosystems_client/api/create/__init__.py +1 -0
- robosystems_client/api/create/create_graph.py +375 -0
- robosystems_client/api/create/get_available_extensions.py +134 -0
- robosystems_client/api/credits_/__init__.py +1 -0
- robosystems_client/api/credits_/check_credit_balance.py +299 -0
- robosystems_client/api/credits_/check_storage_limits.py +249 -0
- robosystems_client/api/credits_/get_credit_summary.py +245 -0
- robosystems_client/api/credits_/get_storage_usage.py +279 -0
- robosystems_client/api/credits_/list_credit_transactions.py +392 -0
- robosystems_client/api/graph_analytics/__init__.py +1 -0
- robosystems_client/api/graph_analytics/get_graph_metrics.py +285 -0
- robosystems_client/api/graph_analytics/get_graph_usage_stats.py +329 -0
- robosystems_client/api/graph_status/__init__.py +1 -0
- robosystems_client/api/graph_status/get_database_health.py +273 -0
- robosystems_client/api/graph_status/get_database_info.py +277 -0
- robosystems_client/api/mcp/__init__.py +1 -0
- robosystems_client/api/mcp/call_mcp_tool.py +432 -0
- robosystems_client/api/mcp/list_mcp_tools.py +265 -0
- robosystems_client/api/operations/__init__.py +1 -0
- robosystems_client/api/operations/cancel_operation.py +246 -0
- robosystems_client/api/operations/get_operation_status.py +273 -0
- robosystems_client/api/operations/stream_operation_events.py +415 -0
- robosystems_client/api/query/__init__.py +1 -0
- robosystems_client/api/query/execute_cypher_query.py +482 -0
- robosystems_client/api/schema/__init__.py +1 -0
- robosystems_client/api/schema/export_graph_schema.py +239 -0
- robosystems_client/api/schema/get_graph_schema_info.py +277 -0
- robosystems_client/api/schema/list_schema_extensions.py +216 -0
- robosystems_client/api/schema/validate_schema.py +326 -0
- robosystems_client/api/service_offerings/__init__.py +1 -0
- robosystems_client/api/service_offerings/get_service_offerings.py +197 -0
- robosystems_client/api/status/__init__.py +1 -0
- robosystems_client/api/status/get_mcp_health.py +136 -0
- robosystems_client/api/status/get_service_status.py +134 -0
- robosystems_client/api/user/__init__.py +1 -0
- robosystems_client/api/user/create_user_api_key.py +205 -0
- robosystems_client/api/user/get_all_credit_summaries.py +256 -0
- robosystems_client/api/user/get_current_user.py +187 -0
- robosystems_client/api/user/get_user_graphs.py +187 -0
- robosystems_client/api/user/list_user_api_keys.py +187 -0
- robosystems_client/api/user/revoke_user_api_key.py +209 -0
- robosystems_client/api/user/select_user_graph.py +213 -0
- robosystems_client/api/user/update_user.py +205 -0
- robosystems_client/api/user/update_user_api_key.py +218 -0
- robosystems_client/api/user/update_user_password.py +218 -0
- robosystems_client/api/user_analytics/__init__.py +1 -0
- robosystems_client/api/user_analytics/get_detailed_user_analytics.py +222 -0
- robosystems_client/api/user_analytics/get_user_usage_overview.py +187 -0
- robosystems_client/api/user_limits/__init__.py +1 -0
- robosystems_client/api/user_limits/get_user_limits.py +190 -0
- robosystems_client/api/user_limits/get_user_usage.py +187 -0
- robosystems_client/api/user_subscriptions/__init__.py +1 -0
- robosystems_client/api/user_subscriptions/cancel_shared_repository_subscription.py +209 -0
- robosystems_client/api/user_subscriptions/get_repository_credits.py +206 -0
- robosystems_client/api/user_subscriptions/get_shared_repository_credits.py +193 -0
- robosystems_client/api/user_subscriptions/get_user_shared_subscriptions.py +213 -0
- robosystems_client/api/user_subscriptions/subscribe_to_shared_repository.py +214 -0
- robosystems_client/api/user_subscriptions/upgrade_shared_repository_subscription.py +228 -0
- robosystems_client/client.py +278 -0
- robosystems_client/errors.py +16 -0
- robosystems_client/extensions/README.md +611 -0
- robosystems_client/extensions/__init__.py +108 -0
- robosystems_client/extensions/auth_integration.py +210 -0
- robosystems_client/extensions/extensions.py +170 -0
- robosystems_client/extensions/operation_client.py +368 -0
- robosystems_client/extensions/query_client.py +375 -0
- robosystems_client/extensions/sse_client.py +520 -0
- robosystems_client/extensions/tests/__init__.py +1 -0
- robosystems_client/extensions/tests/test_integration.py +490 -0
- robosystems_client/extensions/tests/test_unit.py +560 -0
- robosystems_client/extensions/utils.py +526 -0
- robosystems_client/models/__init__.py +379 -0
- robosystems_client/models/account_info.py +79 -0
- robosystems_client/models/add_on_credit_info.py +119 -0
- robosystems_client/models/agent_message.py +68 -0
- robosystems_client/models/agent_request.py +132 -0
- robosystems_client/models/agent_request_context_type_0.py +44 -0
- robosystems_client/models/agent_response.py +132 -0
- robosystems_client/models/agent_response_metadata_type_0.py +44 -0
- robosystems_client/models/api_key_info.py +134 -0
- robosystems_client/models/api_keys_response.py +74 -0
- robosystems_client/models/auth_response.py +82 -0
- robosystems_client/models/auth_response_user.py +44 -0
- robosystems_client/models/available_extension.py +78 -0
- robosystems_client/models/available_extensions_response.py +73 -0
- robosystems_client/models/backup_create_request.py +117 -0
- robosystems_client/models/backup_export_request.py +72 -0
- robosystems_client/models/backup_list_response.py +90 -0
- robosystems_client/models/backup_response.py +200 -0
- robosystems_client/models/backup_restore_request.py +81 -0
- robosystems_client/models/backup_stats_response.py +156 -0
- robosystems_client/models/backup_stats_response_backup_formats.py +44 -0
- robosystems_client/models/cancel_operation_response_canceloperation.py +44 -0
- robosystems_client/models/cancellation_response.py +76 -0
- robosystems_client/models/check_credit_balance_response_checkcreditbalance.py +44 -0
- robosystems_client/models/connection_options_response.py +82 -0
- robosystems_client/models/connection_provider_info.py +203 -0
- robosystems_client/models/connection_provider_info_auth_type.py +11 -0
- robosystems_client/models/connection_provider_info_provider.py +10 -0
- robosystems_client/models/connection_response.py +149 -0
- robosystems_client/models/connection_response_metadata.py +44 -0
- robosystems_client/models/connection_response_provider.py +10 -0
- robosystems_client/models/create_api_key_request.py +82 -0
- robosystems_client/models/create_api_key_response.py +74 -0
- robosystems_client/models/create_connection_request.py +179 -0
- robosystems_client/models/create_connection_request_provider.py +10 -0
- robosystems_client/models/create_graph_request.py +183 -0
- robosystems_client/models/credit_check_request.py +82 -0
- robosystems_client/models/credit_summary.py +128 -0
- robosystems_client/models/credit_summary_response.py +140 -0
- robosystems_client/models/credits_summary_response.py +122 -0
- robosystems_client/models/credits_summary_response_credits_by_addon_item.py +44 -0
- robosystems_client/models/custom_schema_definition.py +194 -0
- robosystems_client/models/custom_schema_definition_metadata.py +49 -0
- robosystems_client/models/custom_schema_definition_nodes_item.py +44 -0
- robosystems_client/models/custom_schema_definition_relationships_item.py +44 -0
- robosystems_client/models/cypher_query_request.py +128 -0
- robosystems_client/models/cypher_query_request_parameters_type_0.py +44 -0
- robosystems_client/models/database_health_response.py +181 -0
- robosystems_client/models/database_info_response.py +191 -0
- robosystems_client/models/detailed_transactions_response.py +124 -0
- robosystems_client/models/detailed_transactions_response_date_range.py +44 -0
- robosystems_client/models/detailed_transactions_response_summary.py +59 -0
- robosystems_client/models/enhanced_credit_transaction_response.py +192 -0
- robosystems_client/models/enhanced_credit_transaction_response_metadata.py +44 -0
- robosystems_client/models/error_response.py +145 -0
- robosystems_client/models/exchange_token_request.py +116 -0
- robosystems_client/models/exchange_token_request_metadata_type_0.py +44 -0
- robosystems_client/models/get_all_credit_summaries_response_getallcreditsummaries.py +44 -0
- robosystems_client/models/get_backup_download_url_response_getbackupdownloadurl.py +44 -0
- robosystems_client/models/get_current_auth_user_response_getcurrentauthuser.py +44 -0
- robosystems_client/models/get_current_graph_bill_response_getcurrentgraphbill.py +44 -0
- robosystems_client/models/get_graph_billing_history_response_getgraphbillinghistory.py +44 -0
- robosystems_client/models/get_graph_monthly_bill_response_getgraphmonthlybill.py +44 -0
- robosystems_client/models/get_graph_schema_info_response_getgraphschemainfo.py +44 -0
- robosystems_client/models/get_graph_usage_details_response_getgraphusagedetails.py +44 -0
- robosystems_client/models/get_mcp_health_response_getmcphealth.py +44 -0
- robosystems_client/models/get_operation_status_response_getoperationstatus.py +44 -0
- robosystems_client/models/get_storage_usage_response_getstorageusage.py +44 -0
- robosystems_client/models/graph_info.py +92 -0
- robosystems_client/models/graph_metadata.py +105 -0
- robosystems_client/models/graph_metrics_response.py +188 -0
- robosystems_client/models/graph_metrics_response_estimated_size.py +44 -0
- robosystems_client/models/graph_metrics_response_health_status.py +44 -0
- robosystems_client/models/graph_metrics_response_node_counts.py +44 -0
- robosystems_client/models/graph_metrics_response_relationship_counts.py +44 -0
- robosystems_client/models/graph_usage_response.py +116 -0
- robosystems_client/models/graph_usage_response_query_statistics.py +44 -0
- robosystems_client/models/graph_usage_response_recent_activity.py +44 -0
- robosystems_client/models/graph_usage_response_storage_usage.py +44 -0
- robosystems_client/models/health_status.py +110 -0
- robosystems_client/models/health_status_details_type_0.py +44 -0
- robosystems_client/models/http_validation_error.py +75 -0
- robosystems_client/models/initial_entity_data.py +212 -0
- robosystems_client/models/kuzu_backup_health_response_kuzubackuphealth.py +44 -0
- robosystems_client/models/link_token_request.py +174 -0
- robosystems_client/models/link_token_request_options_type_0.py +44 -0
- robosystems_client/models/link_token_request_provider_type_0.py +10 -0
- robosystems_client/models/list_connections_provider_type_0.py +10 -0
- robosystems_client/models/list_schema_extensions_response_listschemaextensions.py +44 -0
- robosystems_client/models/login_request.py +68 -0
- robosystems_client/models/logout_user_response_logoutuser.py +44 -0
- robosystems_client/models/mcp_tool_call.py +84 -0
- robosystems_client/models/mcp_tool_call_arguments.py +44 -0
- robosystems_client/models/mcp_tools_response.py +74 -0
- robosystems_client/models/mcp_tools_response_tools_item.py +44 -0
- robosystems_client/models/o_auth_callback_request.py +130 -0
- robosystems_client/models/o_auth_init_request.py +128 -0
- robosystems_client/models/o_auth_init_request_additional_params_type_0.py +44 -0
- robosystems_client/models/o_auth_init_response.py +78 -0
- robosystems_client/models/password_check_request.py +82 -0
- robosystems_client/models/password_check_response.py +112 -0
- robosystems_client/models/password_check_response_character_types.py +44 -0
- robosystems_client/models/password_policy_response.py +66 -0
- robosystems_client/models/password_policy_response_policy.py +44 -0
- robosystems_client/models/plaid_connection_config.py +209 -0
- robosystems_client/models/plaid_connection_config_accounts_type_0_item.py +44 -0
- robosystems_client/models/plaid_connection_config_institution_type_0.py +44 -0
- robosystems_client/models/quick_books_connection_config.py +92 -0
- robosystems_client/models/register_request.py +98 -0
- robosystems_client/models/repository_credits_response.py +101 -0
- robosystems_client/models/repository_plan.py +10 -0
- robosystems_client/models/repository_type.py +10 -0
- robosystems_client/models/response_mode.py +11 -0
- robosystems_client/models/schema_export_response.py +163 -0
- robosystems_client/models/schema_export_response_data_stats_type_0.py +44 -0
- robosystems_client/models/schema_export_response_schema_definition_type_0.py +44 -0
- robosystems_client/models/schema_validation_request.py +142 -0
- robosystems_client/models/schema_validation_request_schema_definition_type_0.py +44 -0
- robosystems_client/models/schema_validation_response.py +227 -0
- robosystems_client/models/schema_validation_response_compatibility_type_0.py +44 -0
- robosystems_client/models/schema_validation_response_stats_type_0.py +44 -0
- robosystems_client/models/sec_connection_config.py +82 -0
- robosystems_client/models/sso_complete_request.py +60 -0
- robosystems_client/models/sso_exchange_request.py +90 -0
- robosystems_client/models/sso_exchange_response.py +78 -0
- robosystems_client/models/sso_login_request.py +60 -0
- robosystems_client/models/sso_token_response.py +78 -0
- robosystems_client/models/storage_limit_response.py +149 -0
- robosystems_client/models/subscription_info.py +180 -0
- robosystems_client/models/subscription_info_metadata.py +44 -0
- robosystems_client/models/subscription_request.py +89 -0
- robosystems_client/models/subscription_response.py +82 -0
- robosystems_client/models/success_response.py +112 -0
- robosystems_client/models/success_response_data_type_0.py +44 -0
- robosystems_client/models/sync_connection_request.py +106 -0
- robosystems_client/models/sync_connection_request_sync_options_type_0.py +44 -0
- robosystems_client/models/sync_connection_response_syncconnection.py +44 -0
- robosystems_client/models/tier_upgrade_request.py +62 -0
- robosystems_client/models/transaction_summary_response.py +126 -0
- robosystems_client/models/update_api_key_request.py +92 -0
- robosystems_client/models/update_password_request.py +76 -0
- robosystems_client/models/update_user_request.py +92 -0
- robosystems_client/models/upgrade_subscription_request.py +82 -0
- robosystems_client/models/user_analytics_response.py +132 -0
- robosystems_client/models/user_analytics_response_api_usage.py +44 -0
- robosystems_client/models/user_analytics_response_graph_usage.py +44 -0
- robosystems_client/models/user_analytics_response_limits.py +44 -0
- robosystems_client/models/user_analytics_response_recent_activity_item.py +44 -0
- robosystems_client/models/user_analytics_response_user_info.py +44 -0
- robosystems_client/models/user_graph_summary.py +134 -0
- robosystems_client/models/user_graphs_response.py +96 -0
- robosystems_client/models/user_limits_response.py +95 -0
- robosystems_client/models/user_response.py +132 -0
- robosystems_client/models/user_subscriptions_response.py +90 -0
- robosystems_client/models/user_usage_response.py +90 -0
- robosystems_client/models/user_usage_response_graphs.py +44 -0
- robosystems_client/models/user_usage_summary_response.py +130 -0
- robosystems_client/models/user_usage_summary_response_usage_vs_limits.py +44 -0
- robosystems_client/models/validation_error.py +88 -0
- robosystems_client/py.typed +1 -0
- robosystems_client/sdk-config.yaml +5 -0
- robosystems_client/types.py +54 -0
- robosystems_client-0.1.9.dist-info/METADATA +302 -0
- robosystems_client-0.1.9.dist-info/RECORD +282 -0
- robosystems_client-0.1.9.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
"""Integration Tests for RoboSystems SDK Extensions
|
|
2
|
+
|
|
3
|
+
These tests demonstrate real usage patterns and verify the extensions work correctly
|
|
4
|
+
with the generated SDK.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
import time
|
|
9
|
+
from unittest.mock import Mock, patch
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
|
|
12
|
+
# Import extensions
|
|
13
|
+
from robosystems_client.extensions import (
|
|
14
|
+
RoboSystemsExtensionConfig,
|
|
15
|
+
QueryBuilder,
|
|
16
|
+
CacheManager,
|
|
17
|
+
ProgressTracker,
|
|
18
|
+
AuthenticatedExtensions,
|
|
19
|
+
create_extensions,
|
|
20
|
+
SSEClient,
|
|
21
|
+
SSEConfig,
|
|
22
|
+
EventType,
|
|
23
|
+
QueryClient,
|
|
24
|
+
estimate_query_cost,
|
|
25
|
+
validate_cypher_query,
|
|
26
|
+
format_duration,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class TestAuthenticatedIntegration:
|
|
31
|
+
"""Test authenticated extensions integration"""
|
|
32
|
+
|
|
33
|
+
@pytest.fixture
|
|
34
|
+
def mock_api_key(self):
|
|
35
|
+
return "test_api_key_12345"
|
|
36
|
+
|
|
37
|
+
@pytest.fixture
|
|
38
|
+
def extensions(self, mock_api_key):
|
|
39
|
+
return AuthenticatedExtensions(
|
|
40
|
+
api_key=mock_api_key,
|
|
41
|
+
config=RoboSystemsExtensionConfig(
|
|
42
|
+
base_url="https://api.test.robosystems.ai", timeout=30
|
|
43
|
+
),
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
def test_authenticated_extensions_initialization(self, extensions, mock_api_key):
|
|
47
|
+
"""Test that authenticated extensions initialize correctly"""
|
|
48
|
+
assert extensions.config["base_url"] == "https://api.test.robosystems.ai"
|
|
49
|
+
assert extensions.config["headers"]["X-API-Key"] == mock_api_key
|
|
50
|
+
assert extensions.config["headers"]["Authorization"] == f"Bearer {mock_api_key}"
|
|
51
|
+
|
|
52
|
+
def test_create_extensions_factory(self, mock_api_key):
|
|
53
|
+
"""Test the extensions factory function"""
|
|
54
|
+
# API Key method
|
|
55
|
+
ext = create_extensions(
|
|
56
|
+
"api_key", api_key=mock_api_key, base_url="https://api.test.robosystems.ai"
|
|
57
|
+
)
|
|
58
|
+
assert isinstance(ext, AuthenticatedExtensions)
|
|
59
|
+
|
|
60
|
+
# Cookie method
|
|
61
|
+
ext = create_extensions(
|
|
62
|
+
"cookie",
|
|
63
|
+
cookies={"auth-token": "cookie_token"},
|
|
64
|
+
base_url="https://api.test.robosystems.ai",
|
|
65
|
+
)
|
|
66
|
+
assert ext.config["base_url"] == "https://api.test.robosystems.ai"
|
|
67
|
+
|
|
68
|
+
# Token method
|
|
69
|
+
ext = create_extensions(
|
|
70
|
+
"token", token="jwt_token_here", base_url="https://api.test.robosystems.ai"
|
|
71
|
+
)
|
|
72
|
+
assert ext.config["headers"]["Authorization"] == "Bearer jwt_token_here"
|
|
73
|
+
|
|
74
|
+
@patch("robosystems_client.extensions.auth_integration.sync_detailed")
|
|
75
|
+
def test_cypher_query_execution(self, mock_sync_detailed, extensions):
|
|
76
|
+
"""Test executing Cypher queries through authenticated client"""
|
|
77
|
+
# Mock the response
|
|
78
|
+
mock_response = Mock()
|
|
79
|
+
mock_response.parsed = Mock()
|
|
80
|
+
mock_response.parsed.data = [{"name": "Company A", "revenue": 1000000}]
|
|
81
|
+
mock_response.parsed.columns = ["name", "revenue"]
|
|
82
|
+
mock_response.parsed.row_count = 1
|
|
83
|
+
mock_response.parsed.execution_time_ms = 150
|
|
84
|
+
mock_sync_detailed.return_value = mock_response
|
|
85
|
+
|
|
86
|
+
result = extensions.execute_cypher_query(
|
|
87
|
+
graph_id="test_graph",
|
|
88
|
+
query="MATCH (c:Company) RETURN c.name, c.revenue",
|
|
89
|
+
parameters={"limit": 10},
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
assert result["data"] == [{"name": "Company A", "revenue": 1000000}]
|
|
93
|
+
assert result["columns"] == ["name", "revenue"]
|
|
94
|
+
assert result["row_count"] == 1
|
|
95
|
+
assert result["execution_time_ms"] == 150
|
|
96
|
+
|
|
97
|
+
# Verify the SDK was called correctly
|
|
98
|
+
mock_sync_detailed.assert_called_once()
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class TestSSEIntegration:
|
|
102
|
+
"""Test SSE client integration"""
|
|
103
|
+
|
|
104
|
+
@pytest.fixture
|
|
105
|
+
def sse_config(self):
|
|
106
|
+
return SSEConfig(
|
|
107
|
+
base_url="https://api.test.robosystems.ai", max_retries=2, timeout=10
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
@pytest.fixture
|
|
111
|
+
def sse_client(self, sse_config):
|
|
112
|
+
return SSEClient(sse_config)
|
|
113
|
+
|
|
114
|
+
def test_sse_event_parsing(self, sse_client):
|
|
115
|
+
"""Test proper SSE event parsing according to specification"""
|
|
116
|
+
events_received = []
|
|
117
|
+
|
|
118
|
+
def event_handler(data):
|
|
119
|
+
events_received.append(data)
|
|
120
|
+
|
|
121
|
+
sse_client.on(EventType.OPERATION_PROGRESS.value, event_handler)
|
|
122
|
+
|
|
123
|
+
# Test multiline event parsing
|
|
124
|
+
event_buffer = {
|
|
125
|
+
"event": "operation_progress",
|
|
126
|
+
"data": ['{"message": "Step 1 complete"}', '{"percentage": 25}'],
|
|
127
|
+
"id": "123",
|
|
128
|
+
"retry": None,
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
sse_client._dispatch_event(event_buffer)
|
|
132
|
+
|
|
133
|
+
# Should receive the parsed event
|
|
134
|
+
assert len(events_received) == 1
|
|
135
|
+
# Note: Real SSE data would be joined with newlines, this tests the parsing logic
|
|
136
|
+
|
|
137
|
+
def test_sse_connection_management(self, sse_client):
|
|
138
|
+
"""Test SSE connection lifecycle"""
|
|
139
|
+
assert not sse_client.is_connected()
|
|
140
|
+
|
|
141
|
+
# Test event listener registration
|
|
142
|
+
handler = Mock()
|
|
143
|
+
sse_client.on("test_event", handler)
|
|
144
|
+
|
|
145
|
+
# Test event emission
|
|
146
|
+
sse_client.emit("test_event", {"test": "data"})
|
|
147
|
+
handler.assert_called_once_with({"test": "data"})
|
|
148
|
+
|
|
149
|
+
# Test cleanup
|
|
150
|
+
sse_client.close()
|
|
151
|
+
assert sse_client.closed
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class TestQueryIntegration:
|
|
155
|
+
"""Test query client integration"""
|
|
156
|
+
|
|
157
|
+
@pytest.fixture
|
|
158
|
+
def query_client(self):
|
|
159
|
+
return QueryClient({"base_url": "https://api.test.robosystems.ai"})
|
|
160
|
+
|
|
161
|
+
def test_query_builder_integration(self):
|
|
162
|
+
"""Test QueryBuilder creates valid queries"""
|
|
163
|
+
builder = QueryBuilder()
|
|
164
|
+
query, params = (
|
|
165
|
+
builder.match("(c:Company)")
|
|
166
|
+
.where("c.revenue > $min_revenue")
|
|
167
|
+
.return_("c.name", "c.revenue")
|
|
168
|
+
.limit(10)
|
|
169
|
+
.with_param("min_revenue", 100000)
|
|
170
|
+
.build()
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
# Validate the query
|
|
174
|
+
validation = validate_cypher_query(query)
|
|
175
|
+
assert validation["valid"]
|
|
176
|
+
|
|
177
|
+
# Estimate cost
|
|
178
|
+
cost = estimate_query_cost(query, params)
|
|
179
|
+
assert cost["complexity_category"] in ["low", "medium", "high", "very_high"]
|
|
180
|
+
assert cost["complexity_score"] > 0
|
|
181
|
+
|
|
182
|
+
# Test parameters
|
|
183
|
+
assert params["min_revenue"] == 100000
|
|
184
|
+
|
|
185
|
+
def test_query_validation_integration(self):
|
|
186
|
+
"""Test query validation with various query types"""
|
|
187
|
+
test_cases = [
|
|
188
|
+
# Valid queries
|
|
189
|
+
("MATCH (n) RETURN n", True),
|
|
190
|
+
("MATCH (c:Company) WHERE c.revenue > 1000 RETURN c.name", True),
|
|
191
|
+
("CREATE (n:Test) RETURN n", True),
|
|
192
|
+
# Invalid queries
|
|
193
|
+
("MATCH (n RETURN n", False), # Missing closing parenthesis
|
|
194
|
+
("", False), # Empty query
|
|
195
|
+
("MATCH [n] RETURN n", False), # Wrong bracket type
|
|
196
|
+
]
|
|
197
|
+
|
|
198
|
+
for query, should_be_valid in test_cases:
|
|
199
|
+
result = validate_cypher_query(query)
|
|
200
|
+
assert result["valid"] == should_be_valid, f"Query '{query}' validation failed"
|
|
201
|
+
|
|
202
|
+
def test_query_cost_estimation_accuracy(self):
|
|
203
|
+
"""Test query cost estimation provides reasonable results"""
|
|
204
|
+
queries = [
|
|
205
|
+
# Simple query - should be low cost
|
|
206
|
+
("MATCH (n:Company) RETURN n.name LIMIT 10", "low"),
|
|
207
|
+
# Complex query - should be higher cost
|
|
208
|
+
(
|
|
209
|
+
"MATCH (c:Company)-[:HAS_TRANSACTION]->(t:Transaction) "
|
|
210
|
+
+ "WHERE c.revenue > 1000000 "
|
|
211
|
+
+ "WITH c, COUNT(t) as tx_count "
|
|
212
|
+
+ "ORDER BY tx_count DESC "
|
|
213
|
+
+ "RETURN c.name, tx_count",
|
|
214
|
+
"high",
|
|
215
|
+
),
|
|
216
|
+
# Very complex query
|
|
217
|
+
(
|
|
218
|
+
"MATCH (c:Company)-[:HAS_TRANSACTION]->(t:Transaction) "
|
|
219
|
+
+ "MATCH (c)-[:LOCATED_IN]->(l:Location) "
|
|
220
|
+
+ "MATCH (c)-[:HAS_SUBSIDIARY]->(s:Company) "
|
|
221
|
+
+ "WHERE c.revenue > 1000000 AND t.amount > 10000 "
|
|
222
|
+
+ "WITH c, l, COUNT(t) as tx_count, SUM(t.amount) as total_amount, "
|
|
223
|
+
+ " AVG(t.amount) as avg_amount, MAX(t.amount) as max_amount "
|
|
224
|
+
+ "ORDER BY total_amount DESC, tx_count DESC "
|
|
225
|
+
+ "RETURN c.name, l.city, tx_count, total_amount, avg_amount",
|
|
226
|
+
"very_high",
|
|
227
|
+
),
|
|
228
|
+
]
|
|
229
|
+
|
|
230
|
+
for query, expected_complexity in queries:
|
|
231
|
+
result = estimate_query_cost(query)
|
|
232
|
+
actual_complexity = result["complexity_category"]
|
|
233
|
+
|
|
234
|
+
# Allow some flexibility in complexity categorization
|
|
235
|
+
complexity_levels = ["low", "medium", "high", "very_high"]
|
|
236
|
+
expected_idx = complexity_levels.index(expected_complexity)
|
|
237
|
+
actual_idx = complexity_levels.index(actual_complexity)
|
|
238
|
+
|
|
239
|
+
# Should be within 1 level of expected
|
|
240
|
+
assert abs(actual_idx - expected_idx) <= 1, (
|
|
241
|
+
f"Query complexity mismatch: expected {expected_complexity}, got {actual_complexity}"
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
class TestCacheIntegration:
|
|
246
|
+
"""Test cache manager integration"""
|
|
247
|
+
|
|
248
|
+
@pytest.fixture
|
|
249
|
+
def cache_manager(self):
|
|
250
|
+
return CacheManager(max_size=10, ttl_seconds=5)
|
|
251
|
+
|
|
252
|
+
def test_cache_lifecycle(self, cache_manager):
|
|
253
|
+
"""Test complete cache lifecycle"""
|
|
254
|
+
graph_id = "test_graph"
|
|
255
|
+
query = "MATCH (n:Company) RETURN COUNT(n)"
|
|
256
|
+
|
|
257
|
+
# Cache miss initially
|
|
258
|
+
result = cache_manager.get(graph_id, query)
|
|
259
|
+
assert result is None
|
|
260
|
+
|
|
261
|
+
# Store result
|
|
262
|
+
test_result = {"count": 100, "execution_time_ms": 50}
|
|
263
|
+
cache_manager.set(graph_id, query, test_result)
|
|
264
|
+
|
|
265
|
+
# Cache hit
|
|
266
|
+
cached_result = cache_manager.get(graph_id, query)
|
|
267
|
+
assert cached_result == test_result
|
|
268
|
+
|
|
269
|
+
# Test with parameters
|
|
270
|
+
query_with_params = (
|
|
271
|
+
"MATCH (n:Company) WHERE n.revenue > $min_revenue RETURN COUNT(n)"
|
|
272
|
+
)
|
|
273
|
+
params = {"min_revenue": 100000}
|
|
274
|
+
|
|
275
|
+
cache_manager.set(graph_id, query_with_params, test_result, params)
|
|
276
|
+
cached_with_params = cache_manager.get(graph_id, query_with_params, params)
|
|
277
|
+
assert cached_with_params == test_result
|
|
278
|
+
|
|
279
|
+
# Different parameters should be cache miss
|
|
280
|
+
different_params = {"min_revenue": 200000}
|
|
281
|
+
cache_miss = cache_manager.get(graph_id, query_with_params, different_params)
|
|
282
|
+
assert cache_miss is None
|
|
283
|
+
|
|
284
|
+
def test_cache_eviction(self, cache_manager):
|
|
285
|
+
"""Test LRU eviction works correctly"""
|
|
286
|
+
# Fill cache to capacity
|
|
287
|
+
for i in range(10):
|
|
288
|
+
cache_manager.set(f"graph_{i}", f"query_{i}", f"result_{i}")
|
|
289
|
+
|
|
290
|
+
assert len(cache_manager.cache) == 10
|
|
291
|
+
|
|
292
|
+
# Access first few items to make them recently used
|
|
293
|
+
for i in range(3):
|
|
294
|
+
cache_manager.get(f"graph_{i}", f"query_{i}")
|
|
295
|
+
|
|
296
|
+
# Add one more item - should evict least recently used
|
|
297
|
+
cache_manager.set("graph_new", "query_new", "result_new")
|
|
298
|
+
|
|
299
|
+
assert len(cache_manager.cache) == 10 # Still at max capacity
|
|
300
|
+
|
|
301
|
+
# Recently accessed items should still be there
|
|
302
|
+
assert cache_manager.get("graph_0", "query_0") == "result_0"
|
|
303
|
+
assert cache_manager.get("graph_1", "query_1") == "result_1"
|
|
304
|
+
assert cache_manager.get("graph_2", "query_2") == "result_2"
|
|
305
|
+
|
|
306
|
+
# New item should be there
|
|
307
|
+
assert cache_manager.get("graph_new", "query_new") == "result_new"
|
|
308
|
+
|
|
309
|
+
def test_cache_expiration(self, cache_manager):
|
|
310
|
+
"""Test cache TTL expiration"""
|
|
311
|
+
graph_id = "test_graph"
|
|
312
|
+
query = "MATCH (n) RETURN COUNT(n)"
|
|
313
|
+
result = {"count": 50}
|
|
314
|
+
|
|
315
|
+
# Store with short TTL
|
|
316
|
+
cache_manager.set(graph_id, query, result)
|
|
317
|
+
|
|
318
|
+
# Should be available immediately
|
|
319
|
+
assert cache_manager.get(graph_id, query) == result
|
|
320
|
+
|
|
321
|
+
# Wait for expiration (TTL is 5 seconds in fixture)
|
|
322
|
+
time.sleep(6)
|
|
323
|
+
|
|
324
|
+
# Should be expired now
|
|
325
|
+
expired_result = cache_manager.get(graph_id, query)
|
|
326
|
+
assert expired_result is None
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
class TestProgressTracking:
|
|
330
|
+
"""Test progress tracking integration"""
|
|
331
|
+
|
|
332
|
+
def test_progress_tracker_lifecycle(self):
|
|
333
|
+
"""Test complete progress tracking"""
|
|
334
|
+
operation_id = "test_operation_123"
|
|
335
|
+
tracker = ProgressTracker(operation_id)
|
|
336
|
+
tracker.set_total_steps(5)
|
|
337
|
+
|
|
338
|
+
# Simulate progress updates
|
|
339
|
+
steps = [
|
|
340
|
+
("Initializing...", 0),
|
|
341
|
+
("Loading data...", 20),
|
|
342
|
+
("Processing...", 60),
|
|
343
|
+
("Finalizing...", 90),
|
|
344
|
+
("Complete", 100),
|
|
345
|
+
]
|
|
346
|
+
|
|
347
|
+
for i, (message, percentage) in enumerate(steps, 1):
|
|
348
|
+
tracker.update(message, percentage, step=i)
|
|
349
|
+
time.sleep(0.1) # Small delay to see time progression
|
|
350
|
+
|
|
351
|
+
# Verify final state
|
|
352
|
+
summary = tracker.get_summary()
|
|
353
|
+
assert summary["operation_id"] == operation_id
|
|
354
|
+
assert summary["current_step"] == 5
|
|
355
|
+
assert summary["total_steps"] == 5
|
|
356
|
+
assert summary["latest_message"] == "Complete"
|
|
357
|
+
assert summary["percentage_complete"] == 100
|
|
358
|
+
assert summary["total_updates"] == 5
|
|
359
|
+
|
|
360
|
+
# Check elapsed time is reasonable
|
|
361
|
+
elapsed_time = tracker.get_elapsed_time()
|
|
362
|
+
assert elapsed_time.total_seconds() >= 0.5 # At least the sleep time
|
|
363
|
+
|
|
364
|
+
def test_estimated_completion(self):
|
|
365
|
+
"""Test progress estimation"""
|
|
366
|
+
tracker = ProgressTracker("test_op")
|
|
367
|
+
|
|
368
|
+
# No estimation without progress
|
|
369
|
+
assert tracker.get_estimated_completion() is None
|
|
370
|
+
|
|
371
|
+
# Add progress
|
|
372
|
+
tracker.update("50% complete", 50.0)
|
|
373
|
+
|
|
374
|
+
# Should have an estimation now
|
|
375
|
+
estimation = tracker.get_estimated_completion()
|
|
376
|
+
assert estimation is not None
|
|
377
|
+
assert isinstance(estimation, datetime)
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
class TestUtilityIntegration:
|
|
381
|
+
"""Test utility function integration"""
|
|
382
|
+
|
|
383
|
+
def test_duration_formatting(self):
|
|
384
|
+
"""Test duration formatting utility"""
|
|
385
|
+
test_cases = [(100, "100ms"), (1500, "1.5s"), (65000, "1m 5s"), (3661000, "1h 1m")]
|
|
386
|
+
|
|
387
|
+
for ms, expected in test_cases:
|
|
388
|
+
result = format_duration(ms)
|
|
389
|
+
assert result == expected, (
|
|
390
|
+
f"Duration {ms}ms formatted as '{result}', expected '{expected}'"
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
def test_end_to_end_query_workflow(self):
|
|
394
|
+
"""Test complete query workflow with utilities"""
|
|
395
|
+
# Build query
|
|
396
|
+
builder = QueryBuilder()
|
|
397
|
+
query, params = (
|
|
398
|
+
builder.match("(c:Company)-[:LOCATED_IN]->(l:Location)")
|
|
399
|
+
.where("c.revenue > $min_revenue")
|
|
400
|
+
.where("l.country = $country")
|
|
401
|
+
.return_("c.name", "c.revenue", "l.city")
|
|
402
|
+
.order_by("c.revenue DESC")
|
|
403
|
+
.limit(25)
|
|
404
|
+
.with_param("min_revenue", 1000000)
|
|
405
|
+
.with_param("country", "USA")
|
|
406
|
+
.build()
|
|
407
|
+
)
|
|
408
|
+
|
|
409
|
+
# Validate query
|
|
410
|
+
validation = validate_cypher_query(query)
|
|
411
|
+
assert validation["valid"], f"Generated query is invalid: {validation['issues']}"
|
|
412
|
+
|
|
413
|
+
# Estimate cost
|
|
414
|
+
cost = estimate_query_cost(query, params)
|
|
415
|
+
assert cost["complexity_score"] > 0
|
|
416
|
+
assert len(cost["cost_factors"]) > 0
|
|
417
|
+
|
|
418
|
+
# Cache the estimated result
|
|
419
|
+
cache = CacheManager()
|
|
420
|
+
mock_result = {
|
|
421
|
+
"data": [{"name": "TechCorp", "revenue": 5000000, "city": "San Francisco"}],
|
|
422
|
+
"columns": ["name", "revenue", "city"],
|
|
423
|
+
"row_count": 1,
|
|
424
|
+
"execution_time_ms": 250,
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
cache.set("production_graph", query, mock_result, params)
|
|
428
|
+
|
|
429
|
+
# Retrieve from cache
|
|
430
|
+
cached = cache.get("production_graph", query, params)
|
|
431
|
+
assert cached == mock_result
|
|
432
|
+
|
|
433
|
+
# Test execution time formatting
|
|
434
|
+
formatted_time = format_duration(mock_result["execution_time_ms"])
|
|
435
|
+
assert formatted_time == "250ms"
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
# Integration test runner
|
|
439
|
+
def run_integration_tests():
|
|
440
|
+
"""Run all integration tests manually (for environments without pytest)"""
|
|
441
|
+
print("Running RoboSystems SDK Extensions Integration Tests...")
|
|
442
|
+
|
|
443
|
+
# Test classes to run
|
|
444
|
+
test_classes = [
|
|
445
|
+
TestAuthenticatedIntegration(),
|
|
446
|
+
TestSSEIntegration(),
|
|
447
|
+
TestQueryIntegration(),
|
|
448
|
+
TestCacheIntegration(),
|
|
449
|
+
TestProgressTracking(),
|
|
450
|
+
TestUtilityIntegration(),
|
|
451
|
+
]
|
|
452
|
+
|
|
453
|
+
total_tests = 0
|
|
454
|
+
passed_tests = 0
|
|
455
|
+
|
|
456
|
+
for test_instance in test_classes:
|
|
457
|
+
class_name = test_instance.__class__.__name__
|
|
458
|
+
print(f"\n--- {class_name} ---")
|
|
459
|
+
|
|
460
|
+
# Get all test methods
|
|
461
|
+
test_methods = [
|
|
462
|
+
method
|
|
463
|
+
for method in dir(test_instance)
|
|
464
|
+
if method.startswith("test_") and callable(getattr(test_instance, method))
|
|
465
|
+
]
|
|
466
|
+
|
|
467
|
+
for method_name in test_methods:
|
|
468
|
+
total_tests += 1
|
|
469
|
+
try:
|
|
470
|
+
# Create fixtures if needed
|
|
471
|
+
if hasattr(test_instance, "mock_api_key"):
|
|
472
|
+
test_instance.mock_api_key = lambda: "test_key_123"
|
|
473
|
+
|
|
474
|
+
# Run the test
|
|
475
|
+
test_method = getattr(test_instance, method_name)
|
|
476
|
+
test_method()
|
|
477
|
+
|
|
478
|
+
print(f" ✓ {method_name}")
|
|
479
|
+
passed_tests += 1
|
|
480
|
+
|
|
481
|
+
except Exception as e:
|
|
482
|
+
print(f" ✗ {method_name}: {e}")
|
|
483
|
+
|
|
484
|
+
print(f"\nIntegration Tests Completed: {passed_tests}/{total_tests} passed")
|
|
485
|
+
return passed_tests == total_tests
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
if __name__ == "__main__":
|
|
489
|
+
success = run_integration_tests()
|
|
490
|
+
exit(0 if success else 1)
|