pygeai 0.6.0b14__py3-none-any.whl → 0.6.1__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.
- pygeai/__init__.py +1 -2
- pygeai/_docs/source/content/api_reference/project.rst +392 -0
- pygeai/_docs/source/content/authentication.rst +130 -1
- pygeai/_docs/source/content/debugger.rst +327 -157
- pygeai/_docs/source/pygeai.core.common.rst +8 -0
- pygeai/_docs/source/pygeai.tests.auth.rst +56 -0
- pygeai/_docs/source/pygeai.tests.cli.rst +8 -0
- pygeai/admin/clients.py +1 -3
- pygeai/analytics/clients.py +1 -1
- pygeai/assistant/clients.py +2 -7
- pygeai/assistant/data/clients.py +0 -8
- pygeai/assistant/data_analyst/clients.py +0 -2
- pygeai/assistant/managers.py +1 -1
- pygeai/assistant/rag/clients.py +0 -2
- pygeai/assistant/rag/mappers.py +9 -11
- pygeai/auth/clients.py +26 -7
- pygeai/auth/endpoints.py +2 -1
- pygeai/chat/clients.py +2 -2
- pygeai/chat/managers.py +1 -1
- pygeai/cli/commands/admin.py +13 -25
- pygeai/cli/commands/analytics.py +31 -71
- pygeai/cli/commands/assistant.py +84 -138
- pygeai/cli/commands/auth.py +23 -46
- pygeai/cli/commands/base.py +0 -1
- pygeai/cli/commands/chat.py +218 -209
- pygeai/cli/commands/common.py +5 -5
- pygeai/cli/commands/configuration.py +79 -29
- pygeai/cli/commands/docs.py +3 -4
- pygeai/cli/commands/embeddings.py +13 -19
- pygeai/cli/commands/evaluation.py +133 -344
- pygeai/cli/commands/feedback.py +7 -15
- pygeai/cli/commands/files.py +26 -53
- pygeai/cli/commands/gam.py +28 -69
- pygeai/cli/commands/lab/ai_lab.py +96 -142
- pygeai/cli/commands/lab/common.py +1 -1
- pygeai/cli/commands/lab/spec.py +12 -32
- pygeai/cli/commands/llm.py +9 -18
- pygeai/cli/commands/migrate.py +43 -99
- pygeai/cli/commands/organization.py +223 -196
- pygeai/cli/commands/rag.py +35 -58
- pygeai/cli/commands/rerank.py +21 -25
- pygeai/cli/commands/secrets.py +39 -67
- pygeai/cli/commands/usage_limits.py +50 -136
- pygeai/cli/commands/validators.py +1 -1
- pygeai/cli/geai.py +32 -3
- pygeai/cli/geai_proxy.py +6 -2
- pygeai/cli/install_man.py +1 -1
- pygeai/cli/parsers.py +1 -1
- pygeai/core/base/clients.py +90 -21
- pygeai/core/base/mappers.py +39 -55
- pygeai/core/base/session.py +129 -18
- pygeai/core/common/config.py +50 -13
- pygeai/core/common/constants.py +8 -0
- pygeai/core/common/exceptions.py +6 -0
- pygeai/core/embeddings/clients.py +0 -1
- pygeai/core/embeddings/managers.py +0 -1
- pygeai/core/feedback/clients.py +0 -2
- pygeai/core/feedback/models.py +1 -1
- pygeai/core/files/clients.py +0 -3
- pygeai/core/files/managers.py +1 -1
- pygeai/core/files/mappers.py +4 -5
- pygeai/core/llm/clients.py +0 -1
- pygeai/core/models.py +4 -4
- pygeai/core/plugins/clients.py +0 -3
- pygeai/core/plugins/models.py +2 -2
- pygeai/core/rerank/clients.py +0 -2
- pygeai/core/secrets/clients.py +0 -2
- pygeai/core/services/rest.py +80 -14
- pygeai/core/singleton.py +24 -0
- pygeai/dbg/__init__.py +2 -2
- pygeai/dbg/debugger.py +276 -38
- pygeai/evaluation/clients.py +2 -4
- pygeai/evaluation/dataset/clients.py +0 -1
- pygeai/evaluation/plan/clients.py +0 -2
- pygeai/evaluation/result/clients.py +0 -2
- pygeai/gam/clients.py +1 -3
- pygeai/health/clients.py +1 -3
- pygeai/lab/clients.py +0 -1
- pygeai/lab/managers.py +0 -1
- pygeai/lab/models.py +0 -1
- pygeai/lab/strategies/clients.py +1 -2
- pygeai/lab/tools/clients.py +2 -2
- pygeai/lab/tools/mappers.py +1 -1
- pygeai/migration/strategies.py +5 -6
- pygeai/migration/tools.py +1 -1
- pygeai/organization/clients.py +118 -12
- pygeai/organization/endpoints.py +1 -0
- pygeai/organization/limits/clients.py +4 -6
- pygeai/organization/limits/managers.py +1 -4
- pygeai/organization/managers.py +2 -2
- pygeai/proxy/config.py +1 -0
- pygeai/proxy/managers.py +6 -5
- pygeai/tests/admin/test_clients.py +11 -11
- pygeai/tests/assistants/rag/test_clients.py +1 -1
- pygeai/tests/assistants/rag/test_models.py +1 -2
- pygeai/tests/assistants/test_clients.py +1 -1
- pygeai/tests/assistants/test_managers.py +1 -3
- pygeai/tests/auth/test_cli_configuration.py +252 -0
- pygeai/tests/auth/test_client_initialization.py +411 -0
- pygeai/tests/auth/test_clients.py +29 -27
- pygeai/tests/auth/test_config_manager.py +305 -0
- pygeai/tests/auth/test_header_injection.py +294 -0
- pygeai/tests/auth/test_oauth.py +3 -1
- pygeai/tests/auth/test_session_logging.py +119 -0
- pygeai/tests/auth/test_session_validation.py +408 -0
- pygeai/tests/auth/test_singleton_reset.py +201 -0
- pygeai/tests/chat/test_clients.py +1 -1
- pygeai/tests/chat/test_iris.py +1 -1
- pygeai/tests/chat/test_ui.py +0 -2
- pygeai/tests/cli/commands/lab/test_ai_lab.py +1 -3
- pygeai/tests/cli/commands/lab/test_common.py +0 -1
- pygeai/tests/cli/commands/test_chat.py +1 -1
- pygeai/tests/cli/commands/test_common.py +0 -1
- pygeai/tests/cli/commands/test_embeddings.py +2 -2
- pygeai/tests/cli/commands/test_evaluation.py +1 -9
- pygeai/tests/cli/commands/test_llm.py +1 -1
- pygeai/tests/cli/commands/test_migrate.py +1 -1
- pygeai/tests/cli/commands/test_rerank.py +0 -1
- pygeai/tests/cli/commands/test_secrets.py +1 -1
- pygeai/tests/cli/commands/test_show_help.py +0 -1
- pygeai/tests/cli/commands/test_validators.py +0 -1
- pygeai/tests/cli/test_credentials_flag.py +312 -0
- pygeai/tests/cli/test_error_handler.py +0 -1
- pygeai/tests/core/base/test_mappers.py +2 -2
- pygeai/tests/core/base/test_models.py +4 -4
- pygeai/tests/core/common/test_config.py +2 -7
- pygeai/tests/core/common/test_decorators.py +0 -1
- pygeai/tests/core/embeddings/test_managers.py +1 -1
- pygeai/tests/core/feedback/test_clients.py +2 -2
- pygeai/tests/core/files/test_clients.py +6 -6
- pygeai/tests/core/files/test_models.py +0 -1
- pygeai/tests/core/files/test_responses.py +0 -1
- pygeai/tests/core/llm/test_clients.py +1 -1
- pygeai/tests/core/plugins/test_clients.py +4 -4
- pygeai/tests/core/rerank/test_mappers.py +1 -3
- pygeai/tests/core/secrets/test_clients.py +2 -3
- pygeai/tests/core/services/test_rest.py +10 -10
- pygeai/tests/core/utils/test_console.py +0 -1
- pygeai/tests/dbg/test_debugger.py +95 -8
- pygeai/tests/evaluation/dataset/test_clients.py +24 -27
- pygeai/tests/evaluation/plan/test_clients.py +16 -18
- pygeai/tests/evaluation/result/test_clients.py +4 -5
- pygeai/tests/health/test_clients.py +2 -2
- pygeai/tests/integration/lab/agents/test_create_agent.py +1 -3
- pygeai/tests/integration/lab/agents/test_get_agent.py +1 -1
- pygeai/tests/integration/lab/processes/test_create_process.py +2 -2
- pygeai/tests/integration/lab/processes/test_create_task.py +2 -3
- pygeai/tests/integration/lab/processes/test_delete_process.py +0 -1
- pygeai/tests/integration/lab/processes/test_get_process.py +2 -4
- pygeai/tests/integration/lab/processes/test_list_process_instances.py +1 -3
- pygeai/tests/integration/lab/processes/test_update_process.py +3 -9
- pygeai/tests/integration/lab/reasoning_strategies/test_update_reasoning_strategy.py +1 -2
- pygeai/tests/integration/lab/tools/test_delete_tool.py +1 -1
- pygeai/tests/integration/lab/tools/test_list_tools.py +1 -1
- pygeai/tests/integration/lab/tools/test_update_tool.py +1 -1
- pygeai/tests/lab/agents/test_clients.py +17 -17
- pygeai/tests/lab/processes/test_clients.py +67 -67
- pygeai/tests/lab/processes/test_mappers.py +23 -23
- pygeai/tests/lab/spec/test_loader.py +0 -2
- pygeai/tests/lab/spec/test_parsers.py +1 -2
- pygeai/tests/lab/strategies/test_clients.py +10 -10
- pygeai/tests/lab/test_managers.py +3 -5
- pygeai/tests/lab/test_mappers.py +1 -4
- pygeai/tests/lab/tools/test_clients.py +21 -21
- pygeai/tests/lab/tools/test_mappers.py +0 -1
- pygeai/tests/organization/limits/test_clients.py +33 -33
- pygeai/tests/organization/limits/test_managers.py +7 -7
- pygeai/tests/organization/test_clients.py +78 -60
- pygeai/tests/proxy/test_clients.py +1 -1
- pygeai/tests/proxy/test_integration.py +1 -4
- pygeai/tests/proxy/test_managers.py +1 -2
- pygeai/tests/proxy/test_servers.py +1 -2
- pygeai/tests/snippets/assistants/rag/delete_rag_assistant.py +0 -1
- pygeai/tests/snippets/assistants/rag/get_documents.py +0 -1
- pygeai/tests/snippets/assistants/rag/get_rag_assistant_data.py +0 -1
- pygeai/tests/snippets/chat/get_request_status.py +0 -1
- pygeai/tests/snippets/dbg/file_debugging.py +72 -0
- pygeai/tests/snippets/dbg/module_debugging.py +60 -0
- pygeai/tests/snippets/embeddings/cohere_example.py +2 -2
- pygeai/tests/snippets/embeddings/openai_base64_example.py +1 -1
- pygeai/tests/snippets/evaluation/dataset/complete_workflow_example.py +8 -8
- pygeai/tests/snippets/evaluation/plan/complete_workflow_example.py +5 -5
- pygeai/tests/snippets/evaluation/result/complete_workflow_example.py +3 -3
- pygeai/tests/snippets/lab/agentic_flow_example_1.py +1 -1
- pygeai/tests/snippets/lab/agentic_flow_example_2.py +3 -4
- pygeai/tests/snippets/lab/agents/create_agent_with_permissions.py +2 -2
- pygeai/tests/snippets/lab/agents/delete_agent.py +1 -2
- pygeai/tests/snippets/lab/agents/get_agent.py +1 -1
- pygeai/tests/snippets/lab/agents/get_agent_with_new_fields.py +10 -10
- pygeai/tests/snippets/lab/agents/get_sharing_link.py +0 -1
- pygeai/tests/snippets/lab/agents/list_agents.py +1 -1
- pygeai/tests/snippets/lab/agents/publish_agent_revision.py +0 -1
- pygeai/tests/snippets/lab/agents/update_agent_properties.py +1 -1
- pygeai/tests/snippets/lab/crud_ui.py +3 -5
- pygeai/tests/snippets/lab/processes/kbs/get_kb.py +0 -1
- pygeai/tests/snippets/lab/processes/kbs/list_kbs.py +0 -1
- pygeai/tests/snippets/lab/processes/list_processes.py +1 -1
- pygeai/tests/snippets/lab/samples/summarize_files.py +0 -3
- pygeai/tests/snippets/lab/strategies/get_reasoning_strategy.py +0 -1
- pygeai/tests/snippets/lab/strategies/list_reasoning_strategies.py +1 -1
- pygeai/tests/snippets/lab/tools/get_tool.py +1 -1
- pygeai/tests/snippets/lab/tools/publish_tool_revision.py +0 -1
- pygeai/tests/snippets/lab/tools/set_parameters.py +1 -2
- pygeai/tests/snippets/lab/use_cases/c_code_fixer_agent_flow.py +2 -3
- pygeai/tests/snippets/lab/use_cases/file_summarizer_example_2.py +1 -1
- pygeai/tests/snippets/lab/use_cases/update_cli_expert.py +0 -1
- pygeai/tests/snippets/lab/use_cases/update_lab_expert.py +0 -1
- pygeai/tests/snippets/lab/use_cases/update_web_designer.py +0 -1
- pygeai/tests/snippets/lab/use_cases/update_web_reader.py +0 -1
- pygeai/tests/snippets/migrate/orchestrator_examples.py +1 -1
- {pygeai-0.6.0b14.dist-info → pygeai-0.6.1.dist-info}/METADATA +32 -7
- {pygeai-0.6.0b14.dist-info → pygeai-0.6.1.dist-info}/RECORD +216 -205
- {pygeai-0.6.0b14.dist-info → pygeai-0.6.1.dist-info}/WHEEL +0 -0
- {pygeai-0.6.0b14.dist-info → pygeai-0.6.1.dist-info}/entry_points.txt +0 -0
- {pygeai-0.6.0b14.dist-info → pygeai-0.6.1.dist-info}/licenses/LICENSE +0 -0
- {pygeai-0.6.0b14.dist-info → pygeai-0.6.1.dist-info}/top_level.txt +0 -0
|
@@ -3,7 +3,7 @@ from unittest.mock import patch, MagicMock
|
|
|
3
3
|
from json import JSONDecodeError
|
|
4
4
|
|
|
5
5
|
from pygeai.auth.clients import AuthClient
|
|
6
|
-
from pygeai.core.common.exceptions import
|
|
6
|
+
from pygeai.core.common.exceptions import APIResponseError
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class TestAuthClient(unittest.TestCase):
|
|
@@ -16,7 +16,7 @@ class TestAuthClient(unittest.TestCase):
|
|
|
16
16
|
self.mock_response = MagicMock()
|
|
17
17
|
self.mock_response.status_code = 200 # Default to success status
|
|
18
18
|
|
|
19
|
-
@patch('pygeai.core.services.rest.
|
|
19
|
+
@patch('pygeai.core.services.rest.GEAIApiService.get')
|
|
20
20
|
def test_get_oauth2_access_token_success(self, mock_get):
|
|
21
21
|
self.mock_response.json.return_value = {"access_token": "token-123", "token_type": "Bearer"}
|
|
22
22
|
mock_get.return_value = self.mock_response
|
|
@@ -35,7 +35,7 @@ class TestAuthClient(unittest.TestCase):
|
|
|
35
35
|
self.assertEqual(call_args[1]['params']['scope'], "gam_user_data gam_user_roles")
|
|
36
36
|
self.assertEqual(result, {"access_token": "token-123", "token_type": "Bearer"})
|
|
37
37
|
|
|
38
|
-
@patch('pygeai.core.services.rest.
|
|
38
|
+
@patch('pygeai.core.services.rest.GEAIApiService.get')
|
|
39
39
|
def test_get_oauth2_access_token_custom_scope(self, mock_get):
|
|
40
40
|
self.mock_response.json.return_value = {"access_token": "token-123"}
|
|
41
41
|
self.mock_response.status_code = 200
|
|
@@ -51,7 +51,7 @@ class TestAuthClient(unittest.TestCase):
|
|
|
51
51
|
call_args = mock_get.call_args
|
|
52
52
|
self.assertEqual(call_args[1]['params']['scope'], "custom_scope")
|
|
53
53
|
|
|
54
|
-
@patch('pygeai.core.services.rest.
|
|
54
|
+
@patch('pygeai.core.services.rest.GEAIApiService.get')
|
|
55
55
|
def test_get_oauth2_access_token_error_status(self, mock_get):
|
|
56
56
|
self.mock_response.status_code = 401
|
|
57
57
|
self.mock_response.text = "Invalid credentials"
|
|
@@ -65,44 +65,46 @@ class TestAuthClient(unittest.TestCase):
|
|
|
65
65
|
)
|
|
66
66
|
self.assertIn("API returned an error", str(context.exception)) # "API returned an error", str(context.exception))
|
|
67
67
|
|
|
68
|
-
@patch
|
|
69
|
-
def test_get_user_profile_information_success(self,
|
|
68
|
+
@patch('pygeai.core.services.rest.GEAIApiService')
|
|
69
|
+
def test_get_user_profile_information_success(self, mock_api_service_class):
|
|
70
70
|
self.mock_response.json.return_value = {
|
|
71
71
|
"user_id": "user-123",
|
|
72
72
|
"email": "user@example.com",
|
|
73
73
|
"name": "Test User"
|
|
74
74
|
}
|
|
75
75
|
self.mock_response.status_code = 200
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
|
|
77
|
+
mock_api_service_instance = MagicMock()
|
|
78
|
+
mock_api_service_instance.get.return_value = self.mock_response
|
|
79
|
+
mock_api_service_class.return_value = mock_api_service_instance
|
|
78
80
|
|
|
79
81
|
client = AuthClient()
|
|
80
|
-
client.
|
|
81
|
-
result = client.get_user_profile_information("access-token-123")
|
|
82
|
+
result = client.get_user_profile_information("access-token-123", project_id="proj-123")
|
|
82
83
|
|
|
83
|
-
|
|
84
|
+
mock_api_service_instance.get.assert_called_once()
|
|
84
85
|
self.assertEqual(result, {
|
|
85
86
|
"user_id": "user-123",
|
|
86
87
|
"email": "user@example.com",
|
|
87
88
|
"name": "Test User"
|
|
88
89
|
})
|
|
89
90
|
|
|
90
|
-
@patch
|
|
91
|
-
def test_get_user_profile_information_json_decode_error(self,
|
|
91
|
+
@patch('pygeai.core.services.rest.GEAIApiService')
|
|
92
|
+
def test_get_user_profile_information_json_decode_error(self, mock_api_service_class):
|
|
92
93
|
self.mock_response.json.side_effect = JSONDecodeError("error", "doc", 0)
|
|
93
94
|
self.mock_response.status_code = 401
|
|
94
95
|
self.mock_response.text = "Invalid token"
|
|
95
|
-
|
|
96
|
-
|
|
96
|
+
|
|
97
|
+
mock_api_service_instance = MagicMock()
|
|
98
|
+
mock_api_service_instance.get.return_value = self.mock_response
|
|
99
|
+
mock_api_service_class.return_value = mock_api_service_instance
|
|
97
100
|
|
|
98
101
|
client = AuthClient()
|
|
99
|
-
client.api_service = mock_api_service
|
|
100
102
|
|
|
101
103
|
with self.assertRaises(APIResponseError) as context:
|
|
102
|
-
client.get_user_profile_information("invalid-token")
|
|
104
|
+
client.get_user_profile_information("invalid-token", project_id="proj-123")
|
|
103
105
|
self.assertIn("API returned an error", str(context.exception)) # "API returned an error", str(context.exception))
|
|
104
106
|
|
|
105
|
-
@patch('pygeai.core.services.rest.
|
|
107
|
+
@patch('pygeai.core.services.rest.GEAIApiService.post')
|
|
106
108
|
def test_create_project_api_token_success(self, mock_post):
|
|
107
109
|
self.mock_response.json.return_value = {
|
|
108
110
|
"id": "test_token_id",
|
|
@@ -138,7 +140,7 @@ class TestAuthClient(unittest.TestCase):
|
|
|
138
140
|
self.assertEqual(result['name'], "TestToken")
|
|
139
141
|
self.assertEqual(result['id'], "test_token_id")
|
|
140
142
|
|
|
141
|
-
@patch('pygeai.core.services.rest.
|
|
143
|
+
@patch('pygeai.core.services.rest.GEAIApiService.post')
|
|
142
144
|
def test_create_project_api_token_without_description(self, mock_post):
|
|
143
145
|
self.mock_response.json.return_value = {
|
|
144
146
|
"id": "test_token_id",
|
|
@@ -156,7 +158,7 @@ class TestAuthClient(unittest.TestCase):
|
|
|
156
158
|
call_args = mock_post.call_args
|
|
157
159
|
self.assertNotIn('description', call_args[1]['data'])
|
|
158
160
|
|
|
159
|
-
@patch('pygeai.core.services.rest.
|
|
161
|
+
@patch('pygeai.core.services.rest.GEAIApiService.post')
|
|
160
162
|
def test_create_project_api_token_json_decode_error(self, mock_post):
|
|
161
163
|
self.mock_response.json.side_effect = JSONDecodeError("error", "doc", 0)
|
|
162
164
|
self.mock_response.status_code = 400
|
|
@@ -170,7 +172,7 @@ class TestAuthClient(unittest.TestCase):
|
|
|
170
172
|
)
|
|
171
173
|
self.assertIn("API returned an error", str(context.exception)) # "API returned an error", str(context.exception))
|
|
172
174
|
|
|
173
|
-
@patch('pygeai.core.services.rest.
|
|
175
|
+
@patch('pygeai.core.services.rest.GEAIApiService.delete')
|
|
174
176
|
def test_delete_project_api_token_success(self, mock_delete):
|
|
175
177
|
self.mock_response.json.return_value = {}
|
|
176
178
|
self.mock_response.status_code = 200
|
|
@@ -183,7 +185,7 @@ class TestAuthClient(unittest.TestCase):
|
|
|
183
185
|
self.assertIn("token-123", call_args[1]['endpoint'])
|
|
184
186
|
self.assertEqual(result, {})
|
|
185
187
|
|
|
186
|
-
@patch('pygeai.core.services.rest.
|
|
188
|
+
@patch('pygeai.core.services.rest.GEAIApiService.delete')
|
|
187
189
|
def test_delete_project_api_token_json_decode_error(self, mock_delete):
|
|
188
190
|
self.mock_response.json.side_effect = JSONDecodeError("error", "doc", 0)
|
|
189
191
|
self.mock_response.status_code = 404
|
|
@@ -194,7 +196,7 @@ class TestAuthClient(unittest.TestCase):
|
|
|
194
196
|
self.client.delete_project_api_token(api_token_id="invalid-token")
|
|
195
197
|
self.assertIn("API returned an error", str(context.exception)) # "API returned an error", str(context.exception))
|
|
196
198
|
|
|
197
|
-
@patch('pygeai.core.services.rest.
|
|
199
|
+
@patch('pygeai.core.services.rest.GEAIApiService.put')
|
|
198
200
|
def test_update_project_api_token_success(self, mock_put):
|
|
199
201
|
self.mock_response.json.return_value = [
|
|
200
202
|
{
|
|
@@ -218,7 +220,7 @@ class TestAuthClient(unittest.TestCase):
|
|
|
218
220
|
self.assertIsInstance(result, list)
|
|
219
221
|
self.assertEqual(result[0]['type'], "Success")
|
|
220
222
|
|
|
221
|
-
@patch('pygeai.core.services.rest.
|
|
223
|
+
@patch('pygeai.core.services.rest.GEAIApiService.put')
|
|
222
224
|
def test_update_project_api_token_only_description(self, mock_put):
|
|
223
225
|
self.mock_response.json.return_value = [
|
|
224
226
|
{
|
|
@@ -238,7 +240,7 @@ class TestAuthClient(unittest.TestCase):
|
|
|
238
240
|
self.assertEqual(call_args[1]['data']['description'], "New description")
|
|
239
241
|
self.assertNotIn('status', call_args[1]['data'])
|
|
240
242
|
|
|
241
|
-
@patch('pygeai.core.services.rest.
|
|
243
|
+
@patch('pygeai.core.services.rest.GEAIApiService.put')
|
|
242
244
|
def test_update_project_api_token_json_decode_error(self, mock_put):
|
|
243
245
|
self.mock_response.json.side_effect = JSONDecodeError("error", "doc", 0)
|
|
244
246
|
self.mock_response.status_code = 400
|
|
@@ -252,7 +254,7 @@ class TestAuthClient(unittest.TestCase):
|
|
|
252
254
|
)
|
|
253
255
|
self.assertIn("API returned an error", str(context.exception)) # "API returned an error", str(context.exception))
|
|
254
256
|
|
|
255
|
-
@patch('pygeai.core.services.rest.
|
|
257
|
+
@patch('pygeai.core.services.rest.GEAIApiService.get')
|
|
256
258
|
def test_get_project_api_token_success(self, mock_get):
|
|
257
259
|
self.mock_response.json.return_value = {
|
|
258
260
|
"id": "token-123",
|
|
@@ -273,7 +275,7 @@ class TestAuthClient(unittest.TestCase):
|
|
|
273
275
|
self.assertEqual(result['id'], "token-123")
|
|
274
276
|
self.assertEqual(result['status'], "Active")
|
|
275
277
|
|
|
276
|
-
@patch('pygeai.core.services.rest.
|
|
278
|
+
@patch('pygeai.core.services.rest.GEAIApiService.get')
|
|
277
279
|
def test_get_project_api_token_json_decode_error(self, mock_get):
|
|
278
280
|
self.mock_response.json.side_effect = JSONDecodeError("error", "doc", 0)
|
|
279
281
|
self.mock_response.status_code = 404
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import tempfile
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
from pygeai.core.common.config import SettingsManager, get_settings, reset_settings
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TestSettingsManager(unittest.TestCase):
|
|
9
|
+
"""
|
|
10
|
+
Tests for SettingsManager configuration file operations.
|
|
11
|
+
|
|
12
|
+
python -m unittest pygeai.tests.auth.test_config_manager.TestSettingsManager
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def setUp(self):
|
|
16
|
+
"""Set up test fixtures"""
|
|
17
|
+
reset_settings()
|
|
18
|
+
self.temp_creds_file = tempfile.NamedTemporaryFile(mode='w', suffix='_credentials', delete=False)
|
|
19
|
+
self.temp_creds_file.close()
|
|
20
|
+
|
|
21
|
+
def tearDown(self):
|
|
22
|
+
"""Clean up test fixtures"""
|
|
23
|
+
if os.path.exists(self.temp_creds_file.name):
|
|
24
|
+
os.unlink(self.temp_creds_file.name)
|
|
25
|
+
reset_settings()
|
|
26
|
+
|
|
27
|
+
def test_creates_empty_credentials_file_if_not_exists(self):
|
|
28
|
+
"""Test that SettingsManager creates empty credentials file if it doesn't exist"""
|
|
29
|
+
os.unlink(self.temp_creds_file.name)
|
|
30
|
+
|
|
31
|
+
settings = SettingsManager(credentials_file=self.temp_creds_file.name)
|
|
32
|
+
|
|
33
|
+
self.assertTrue(os.path.exists(self.temp_creds_file.name))
|
|
34
|
+
|
|
35
|
+
def test_set_and_get_api_key(self):
|
|
36
|
+
"""Test setting and getting API key for an alias"""
|
|
37
|
+
settings = SettingsManager(credentials_file=self.temp_creds_file.name)
|
|
38
|
+
|
|
39
|
+
settings.set_api_key("test_api_key", alias="test")
|
|
40
|
+
api_key = settings.get_api_key(alias="test")
|
|
41
|
+
|
|
42
|
+
self.assertEqual(api_key, "test_api_key")
|
|
43
|
+
|
|
44
|
+
def test_set_and_get_base_url(self):
|
|
45
|
+
"""Test setting and getting base URL for an alias"""
|
|
46
|
+
settings = SettingsManager(credentials_file=self.temp_creds_file.name)
|
|
47
|
+
|
|
48
|
+
settings.set_base_url("https://test.example.com", alias="test")
|
|
49
|
+
base_url = settings.get_base_url(alias="test")
|
|
50
|
+
|
|
51
|
+
self.assertEqual(base_url, "https://test.example.com")
|
|
52
|
+
|
|
53
|
+
def test_set_and_get_access_token(self):
|
|
54
|
+
"""Test setting and getting OAuth access token"""
|
|
55
|
+
settings = SettingsManager(credentials_file=self.temp_creds_file.name)
|
|
56
|
+
|
|
57
|
+
settings.set_access_token("oauth_token_123", alias="test")
|
|
58
|
+
access_token = settings.get_access_token(alias="test")
|
|
59
|
+
|
|
60
|
+
self.assertEqual(access_token, "oauth_token_123")
|
|
61
|
+
|
|
62
|
+
def test_set_and_get_project_id(self):
|
|
63
|
+
"""Test setting and getting project ID"""
|
|
64
|
+
settings = SettingsManager(credentials_file=self.temp_creds_file.name)
|
|
65
|
+
|
|
66
|
+
settings.set_project_id("project-456", alias="test")
|
|
67
|
+
project_id = settings.get_project_id(alias="test")
|
|
68
|
+
|
|
69
|
+
self.assertEqual(project_id, "project-456")
|
|
70
|
+
|
|
71
|
+
def test_set_and_get_organization_id(self):
|
|
72
|
+
"""Test setting and getting organization ID"""
|
|
73
|
+
settings = SettingsManager(credentials_file=self.temp_creds_file.name)
|
|
74
|
+
|
|
75
|
+
settings.set_organization_id("org-789", alias="test")
|
|
76
|
+
org_id = settings.get_organization_id(alias="test")
|
|
77
|
+
|
|
78
|
+
self.assertEqual(org_id, "org-789")
|
|
79
|
+
|
|
80
|
+
def test_set_and_get_eval_url(self):
|
|
81
|
+
"""Test setting and getting eval URL"""
|
|
82
|
+
settings = SettingsManager(credentials_file=self.temp_creds_file.name)
|
|
83
|
+
|
|
84
|
+
settings.set_eval_url("https://eval.example.com", alias="test")
|
|
85
|
+
eval_url = settings.get_eval_url(alias="test")
|
|
86
|
+
|
|
87
|
+
self.assertEqual(eval_url, "https://eval.example.com")
|
|
88
|
+
|
|
89
|
+
def test_multiple_aliases(self):
|
|
90
|
+
"""Test that multiple aliases can be managed independently"""
|
|
91
|
+
settings = SettingsManager(credentials_file=self.temp_creds_file.name)
|
|
92
|
+
|
|
93
|
+
settings.set_api_key("dev_key", alias="dev")
|
|
94
|
+
settings.set_base_url("https://dev.example.com", alias="dev")
|
|
95
|
+
|
|
96
|
+
settings.set_api_key("prod_key", alias="prod")
|
|
97
|
+
settings.set_base_url("https://prod.example.com", alias="prod")
|
|
98
|
+
|
|
99
|
+
self.assertEqual(settings.get_api_key(alias="dev"), "dev_key")
|
|
100
|
+
self.assertEqual(settings.get_base_url(alias="dev"), "https://dev.example.com")
|
|
101
|
+
|
|
102
|
+
self.assertEqual(settings.get_api_key(alias="prod"), "prod_key")
|
|
103
|
+
self.assertEqual(settings.get_base_url(alias="prod"), "https://prod.example.com")
|
|
104
|
+
|
|
105
|
+
def test_list_aliases(self):
|
|
106
|
+
"""Test listing all configured aliases"""
|
|
107
|
+
settings = SettingsManager(credentials_file=self.temp_creds_file.name)
|
|
108
|
+
|
|
109
|
+
settings.set_base_url("https://dev.example.com", alias="dev")
|
|
110
|
+
settings.set_base_url("https://staging.example.com", alias="staging")
|
|
111
|
+
settings.set_base_url("https://prod.example.com", alias="prod")
|
|
112
|
+
|
|
113
|
+
aliases = settings.list_aliases()
|
|
114
|
+
|
|
115
|
+
self.assertEqual(len(aliases), 3)
|
|
116
|
+
self.assertIn("dev", aliases)
|
|
117
|
+
self.assertIn("staging", aliases)
|
|
118
|
+
self.assertIn("prod", aliases)
|
|
119
|
+
self.assertEqual(aliases["dev"], "https://dev.example.com")
|
|
120
|
+
|
|
121
|
+
def test_has_value_returns_true_for_existing(self):
|
|
122
|
+
"""Test has_value returns True for existing setting"""
|
|
123
|
+
settings = SettingsManager(credentials_file=self.temp_creds_file.name)
|
|
124
|
+
|
|
125
|
+
settings.set_api_key("test_key", alias="test")
|
|
126
|
+
|
|
127
|
+
self.assertTrue(settings.has_value("GEAI_API_KEY", "test"))
|
|
128
|
+
|
|
129
|
+
def test_has_value_returns_false_for_missing(self):
|
|
130
|
+
"""Test has_value returns False for missing setting"""
|
|
131
|
+
settings = SettingsManager(credentials_file=self.temp_creds_file.name)
|
|
132
|
+
|
|
133
|
+
settings.set_api_key("test_key", alias="test")
|
|
134
|
+
|
|
135
|
+
self.assertFalse(settings.has_value("GEAI_API_BASE_URL", "test"))
|
|
136
|
+
|
|
137
|
+
def test_has_value_returns_false_for_missing_alias(self):
|
|
138
|
+
"""Test has_value returns False for non-existent alias"""
|
|
139
|
+
settings = SettingsManager(credentials_file=self.temp_creds_file.name)
|
|
140
|
+
|
|
141
|
+
self.assertFalse(settings.has_value("GEAI_API_KEY", "nonexistent"))
|
|
142
|
+
|
|
143
|
+
def test_get_setting_value_returns_empty_for_missing_alias(self):
|
|
144
|
+
"""Test get_setting_value returns None and logs warning for missing alias"""
|
|
145
|
+
settings = SettingsManager(credentials_file=self.temp_creds_file.name)
|
|
146
|
+
|
|
147
|
+
value = settings.get_setting_value("GEAI_API_KEY", "nonexistent")
|
|
148
|
+
|
|
149
|
+
self.assertIsNone(value)
|
|
150
|
+
|
|
151
|
+
def test_auto_adds_eval_url_when_missing(self):
|
|
152
|
+
"""Test that eval_url is auto-added when requested but missing"""
|
|
153
|
+
settings = SettingsManager(credentials_file=self.temp_creds_file.name)
|
|
154
|
+
|
|
155
|
+
settings.set_api_key("test_key", alias="test")
|
|
156
|
+
settings.set_base_url("https://test.example.com", alias="test")
|
|
157
|
+
|
|
158
|
+
eval_url = settings.get_setting_value("GEAI_API_EVAL_URL", "test")
|
|
159
|
+
|
|
160
|
+
self.assertEqual(eval_url, "")
|
|
161
|
+
self.assertTrue(settings.has_value("GEAI_API_EVAL_URL", "test"))
|
|
162
|
+
|
|
163
|
+
def test_auto_adds_oauth_vars_when_access_token_present(self):
|
|
164
|
+
"""Test that OAuth vars are auto-added when access_token is present"""
|
|
165
|
+
settings = SettingsManager(credentials_file=self.temp_creds_file.name)
|
|
166
|
+
|
|
167
|
+
settings.set_access_token("oauth_token_123", alias="test")
|
|
168
|
+
|
|
169
|
+
project_id = settings.get_setting_value("GEAI_PROJECT_ID", "test")
|
|
170
|
+
org_id = settings.get_setting_value("GEAI_ORGANIZATION_ID", "test")
|
|
171
|
+
|
|
172
|
+
self.assertEqual(project_id, "")
|
|
173
|
+
self.assertEqual(org_id, "")
|
|
174
|
+
self.assertTrue(settings.has_value("GEAI_PROJECT_ID", "test"))
|
|
175
|
+
self.assertTrue(settings.has_value("GEAI_ORGANIZATION_ID", "test"))
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class TestSettingsManagerEnvironmentVariables(unittest.TestCase):
|
|
179
|
+
"""
|
|
180
|
+
Tests for environment variable precedence in SettingsManager.
|
|
181
|
+
|
|
182
|
+
python -m unittest pygeai.tests.auth.test_config_manager.TestSettingsManagerEnvironmentVariables
|
|
183
|
+
"""
|
|
184
|
+
|
|
185
|
+
def setUp(self):
|
|
186
|
+
"""Set up test fixtures"""
|
|
187
|
+
reset_settings()
|
|
188
|
+
self.temp_creds_file = tempfile.NamedTemporaryFile(mode='w', suffix='_credentials', delete=False)
|
|
189
|
+
self.temp_creds_file.close()
|
|
190
|
+
|
|
191
|
+
self.original_env = {}
|
|
192
|
+
for key in ['GEAI_API_KEY', 'GEAI_API_BASE_URL', 'GEAI_OAUTH_ACCESS_TOKEN',
|
|
193
|
+
'GEAI_PROJECT_ID', 'GEAI_ORGANIZATION_ID', 'GEAI_API_EVAL_URL']:
|
|
194
|
+
self.original_env[key] = os.environ.get(key)
|
|
195
|
+
if key in os.environ:
|
|
196
|
+
del os.environ[key]
|
|
197
|
+
|
|
198
|
+
def tearDown(self):
|
|
199
|
+
"""Clean up test fixtures"""
|
|
200
|
+
for key, value in self.original_env.items():
|
|
201
|
+
if value is not None:
|
|
202
|
+
os.environ[key] = value
|
|
203
|
+
elif key in os.environ:
|
|
204
|
+
del os.environ[key]
|
|
205
|
+
|
|
206
|
+
if os.path.exists(self.temp_creds_file.name):
|
|
207
|
+
os.unlink(self.temp_creds_file.name)
|
|
208
|
+
reset_settings()
|
|
209
|
+
|
|
210
|
+
def test_env_var_overrides_config_for_default_alias(self):
|
|
211
|
+
"""Test that environment variable overrides config file for default alias"""
|
|
212
|
+
settings = SettingsManager(credentials_file=self.temp_creds_file.name)
|
|
213
|
+
settings.set_api_key("config_key", alias="default")
|
|
214
|
+
|
|
215
|
+
os.environ['GEAI_API_KEY'] = "env_key"
|
|
216
|
+
|
|
217
|
+
api_key = settings.get_api_key(alias="default")
|
|
218
|
+
|
|
219
|
+
self.assertEqual(api_key, "env_key")
|
|
220
|
+
|
|
221
|
+
def test_env_var_does_not_override_non_default_alias(self):
|
|
222
|
+
"""Test that environment variable doesn't override non-default alias"""
|
|
223
|
+
settings = SettingsManager(credentials_file=self.temp_creds_file.name)
|
|
224
|
+
settings.set_api_key("config_key", alias="staging")
|
|
225
|
+
|
|
226
|
+
os.environ['GEAI_API_KEY'] = "env_key"
|
|
227
|
+
|
|
228
|
+
api_key = settings.get_api_key(alias="staging")
|
|
229
|
+
|
|
230
|
+
self.assertEqual(api_key, "config_key")
|
|
231
|
+
|
|
232
|
+
def test_env_var_used_when_no_config_for_default(self):
|
|
233
|
+
"""Test that environment variable is used when no config exists for default"""
|
|
234
|
+
settings = SettingsManager(credentials_file=self.temp_creds_file.name)
|
|
235
|
+
|
|
236
|
+
os.environ['GEAI_API_KEY'] = "env_key"
|
|
237
|
+
|
|
238
|
+
api_key = settings.get_api_key(alias="default")
|
|
239
|
+
|
|
240
|
+
self.assertEqual(api_key, "env_key")
|
|
241
|
+
|
|
242
|
+
def test_all_env_vars_work_for_default_alias(self):
|
|
243
|
+
"""Test that all supported environment variables work"""
|
|
244
|
+
os.environ['GEAI_API_KEY'] = "env_api_key"
|
|
245
|
+
os.environ['GEAI_API_BASE_URL'] = "https://env.example.com"
|
|
246
|
+
os.environ['GEAI_OAUTH_ACCESS_TOKEN'] = "env_oauth_token"
|
|
247
|
+
os.environ['GEAI_PROJECT_ID'] = "env_project_id"
|
|
248
|
+
os.environ['GEAI_ORGANIZATION_ID'] = "env_org_id"
|
|
249
|
+
os.environ['GEAI_API_EVAL_URL'] = "https://env.eval.example.com"
|
|
250
|
+
|
|
251
|
+
settings = SettingsManager(credentials_file=self.temp_creds_file.name)
|
|
252
|
+
|
|
253
|
+
self.assertEqual(settings.get_api_key(), "env_api_key")
|
|
254
|
+
self.assertEqual(settings.get_base_url(), "https://env.example.com")
|
|
255
|
+
self.assertEqual(settings.get_access_token(), "env_oauth_token")
|
|
256
|
+
self.assertEqual(settings.get_project_id(), "env_project_id")
|
|
257
|
+
self.assertEqual(settings.get_organization_id(), "env_org_id")
|
|
258
|
+
self.assertEqual(settings.get_eval_url(), "https://env.eval.example.com")
|
|
259
|
+
|
|
260
|
+
def test_env_var_only_applies_to_default_alias_query(self):
|
|
261
|
+
"""Test that env vars only apply when querying default or no alias"""
|
|
262
|
+
os.environ['GEAI_API_KEY'] = "env_key"
|
|
263
|
+
|
|
264
|
+
settings = SettingsManager(credentials_file=self.temp_creds_file.name)
|
|
265
|
+
|
|
266
|
+
default_key = settings.get_api_key()
|
|
267
|
+
self.assertEqual(default_key, "env_key")
|
|
268
|
+
|
|
269
|
+
explicit_default_key = settings.get_api_key(alias="default")
|
|
270
|
+
self.assertEqual(explicit_default_key, "env_key")
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
class TestGetSettingsSingleton(unittest.TestCase):
|
|
274
|
+
"""
|
|
275
|
+
Tests for get_settings singleton behavior.
|
|
276
|
+
|
|
277
|
+
python -m unittest pygeai.tests.auth.test_config_manager.TestGetSettingsSingleton
|
|
278
|
+
"""
|
|
279
|
+
|
|
280
|
+
def setUp(self):
|
|
281
|
+
"""Set up test fixtures"""
|
|
282
|
+
reset_settings()
|
|
283
|
+
|
|
284
|
+
def tearDown(self):
|
|
285
|
+
"""Clean up test fixtures"""
|
|
286
|
+
reset_settings()
|
|
287
|
+
|
|
288
|
+
def test_get_settings_returns_singleton(self):
|
|
289
|
+
"""Test that get_settings returns the same instance"""
|
|
290
|
+
settings1 = get_settings()
|
|
291
|
+
settings2 = get_settings()
|
|
292
|
+
|
|
293
|
+
self.assertIs(settings1, settings2)
|
|
294
|
+
|
|
295
|
+
def test_reset_settings_clears_singleton(self):
|
|
296
|
+
"""Test that reset_settings clears the singleton"""
|
|
297
|
+
settings1 = get_settings()
|
|
298
|
+
reset_settings()
|
|
299
|
+
settings2 = get_settings()
|
|
300
|
+
|
|
301
|
+
self.assertIsNot(settings1, settings2)
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
if __name__ == '__main__':
|
|
305
|
+
unittest.main()
|