pygeai 0.5.0__py3-none-any.whl → 0.6.0b3__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 -1
- pygeai/auth/__init__.py +0 -0
- pygeai/auth/clients.py +55 -0
- pygeai/auth/endpoints.py +2 -0
- pygeai/cli/__init__.py +0 -1
- pygeai/cli/commands/auth.py +123 -0
- pygeai/cli/commands/base.py +22 -1
- pygeai/cli/commands/docs.py +105 -0
- pygeai/cli/texts/help.py +157 -24
- pygeai/core/files/responses.py +4 -3
- pygeai/lab/clients.py +3 -3
- pygeai/lab/tools/clients.py +4 -4
- pygeai/tests/admin/test_clients.py +143 -0
- pygeai/tests/auth/__init__.py +0 -0
- pygeai/tests/auth/test_clients.py +105 -0
- pygeai/tests/cli/commands/lab/test_ai_lab.py +41 -35
- pygeai/tests/cli/commands/lab/test_spec.py +24 -56
- pygeai/tests/cli/commands/test_chat.py +21 -3
- pygeai/tests/cli/commands/test_evaluation.py +649 -0
- pygeai/tests/cli/commands/test_secrets.py +171 -0
- pygeai/tests/core/base/data/models.py +7 -0
- pygeai/tests/core/base/test_mappers.py +43 -11
- pygeai/tests/core/base/test_models.py +3 -1
- pygeai/tests/core/base/test_responses.py +53 -0
- pygeai/tests/core/common/test_config.py +2 -3
- pygeai/tests/core/files/test_mappers.py +137 -0
- pygeai/tests/core/plugins/__init__.py +0 -0
- pygeai/tests/core/plugins/test_clients.py +64 -0
- pygeai/tests/evaluation/__init__.py +0 -0
- pygeai/tests/evaluation/dataset/__init__.py +0 -0
- pygeai/tests/evaluation/dataset/test_clients.py +263 -0
- pygeai/tests/evaluation/plan/__init__.py +0 -0
- pygeai/tests/evaluation/plan/test_clients.py +193 -0
- pygeai/tests/evaluation/result/__init__.py +0 -0
- pygeai/tests/evaluation/result/test_clients.py +64 -0
- pygeai/tests/integration/assistants/rag/test_create_rag.py +1 -1
- pygeai/tests/integration/chat/test_generate_image.py +1 -1
- pygeai/tests/integration/lab/agents/test_agents_list.py +1 -1
- pygeai/tests/integration/lab/agents/test_create_agent.py +3 -3
- pygeai/tests/integration/lab/agents/test_create_sharing_link.py +1 -1
- pygeai/tests/integration/lab/agents/test_delete_agent.py +2 -2
- pygeai/tests/integration/lab/agents/test_get_agent.py +1 -1
- pygeai/tests/integration/lab/agents/test_publish_agent_revision.py +2 -2
- pygeai/tests/integration/lab/agents/test_update_agent.py +3 -3
- pygeai/tests/integration/lab/processes/test_create_process.py +1 -1
- pygeai/tests/integration/lab/processes/test_create_task.py +211 -0
- pygeai/tests/integration/lab/processes/test_delete_process.py +111 -0
- pygeai/tests/integration/lab/processes/test_get_process.py +1 -1
- pygeai/tests/integration/lab/processes/test_list_process_instances.py +91 -0
- pygeai/tests/integration/lab/processes/test_list_processes.py +138 -0
- pygeai/tests/integration/lab/processes/test_publish_process_revision.py +232 -0
- pygeai/tests/integration/lab/processes/test_update_process.py +1 -1
- pygeai/tests/integration/lab/reasoning_strategies/test_get_reasoning_strategy.py +1 -1
- pygeai/tests/integration/lab/reasoning_strategies/test_list_reasoning_strategies.py +1 -1
- pygeai/tests/integration/lab/reasoning_strategies/test_update_reasoning_strategy.py +1 -1
- pygeai/tests/integration/lab/tools/test_create_tool.py +1 -1
- pygeai/tests/integration/lab/tools/test_delete_tool.py +1 -1
- pygeai/tests/integration/lab/tools/test_get_parameter.py +1 -1
- pygeai/tests/integration/lab/tools/test_get_tool.py +1 -1
- pygeai/tests/integration/lab/tools/test_list_tools.py +1 -1
- pygeai/tests/integration/lab/tools/test_publish_tool_revision.py +1 -1
- pygeai/tests/integration/lab/tools/test_set_parameter.py +1 -1
- pygeai/tests/integration/lab/tools/test_update_tool.py +1 -1
- pygeai/tests/lab/agents/test_clients.py +17 -34
- pygeai/tests/lab/processes/test_clients.py +30 -93
- pygeai/tests/lab/processes/test_mappers.py +12 -71
- pygeai/tests/lab/strategies/test_clients.py +63 -63
- pygeai/tests/lab/test_managers.py +3 -6
- pygeai/tests/lab/test_models.py +9 -8
- pygeai/tests/lab/tools/test_clients.py +22 -45
- pygeai/tests/migration/test_strategies.py +16 -16
- pygeai/tests/organization/test_mappers.py +11 -4
- pygeai/tests/organization/test_responses.py +137 -0
- {pygeai-0.5.0.dist-info → pygeai-0.6.0b3.dist-info}/METADATA +1 -1
- {pygeai-0.5.0.dist-info → pygeai-0.6.0b3.dist-info}/RECORD +79 -53
- {pygeai-0.5.0.dist-info → pygeai-0.6.0b3.dist-info}/WHEEL +0 -0
- {pygeai-0.5.0.dist-info → pygeai-0.6.0b3.dist-info}/entry_points.txt +0 -0
- {pygeai-0.5.0.dist-info → pygeai-0.6.0b3.dist-info}/licenses/LICENSE +0 -0
- {pygeai-0.5.0.dist-info → pygeai-0.6.0b3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from unittest.mock import patch, Mock
|
|
3
|
+
|
|
4
|
+
from pygeai.cli.commands.secrets import (
|
|
5
|
+
show_help,
|
|
6
|
+
get_secret,
|
|
7
|
+
create_secret,
|
|
8
|
+
update_secret,
|
|
9
|
+
list_secrets,
|
|
10
|
+
set_secret_accesses,
|
|
11
|
+
get_secret_accesses
|
|
12
|
+
)
|
|
13
|
+
from pygeai.core.common.exceptions import MissingRequirementException, WrongArgumentError
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TestSecretsCommands(unittest.TestCase):
|
|
17
|
+
"""
|
|
18
|
+
python -m unittest pygeai.tests.cli.commands.test_secrets.TestSecretsCommands
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def test_show_help(self):
|
|
22
|
+
with patch('pygeai.core.utils.console.Console.write_stdout') as mock_stdout:
|
|
23
|
+
show_help()
|
|
24
|
+
mock_stdout.assert_called_once()
|
|
25
|
+
|
|
26
|
+
def test_get_secret_success(self):
|
|
27
|
+
option_list = [
|
|
28
|
+
(Mock(spec=['name'], name="secret_id"), "secret-123")
|
|
29
|
+
]
|
|
30
|
+
option_list[0][0].name = "secret_id"
|
|
31
|
+
|
|
32
|
+
with patch('pygeai.core.secrets.clients.SecretClient.get_secret', return_value="Secret data") as mock_get:
|
|
33
|
+
with patch('pygeai.core.utils.console.Console.write_stdout') as mock_stdout:
|
|
34
|
+
get_secret(option_list)
|
|
35
|
+
mock_get.assert_called_once_with(secret_id="secret-123")
|
|
36
|
+
mock_stdout.assert_called_once_with("Get secret result: \nSecret data")
|
|
37
|
+
|
|
38
|
+
def test_get_secret_missing_id(self):
|
|
39
|
+
option_list = []
|
|
40
|
+
with self.assertRaises(MissingRequirementException) as context:
|
|
41
|
+
get_secret(option_list)
|
|
42
|
+
self.assertEqual(str(context.exception), "Cannot retrieve secret without specifying secret-id")
|
|
43
|
+
|
|
44
|
+
def test_create_secret_success(self):
|
|
45
|
+
option_list = [
|
|
46
|
+
(Mock(spec=['name'], name="name"), "MySecret"),
|
|
47
|
+
(Mock(spec=['name'], name="secret_string"), "secret-value"),
|
|
48
|
+
(Mock(spec=['name'], name="description"), "Test description")
|
|
49
|
+
]
|
|
50
|
+
for opt, _ in option_list:
|
|
51
|
+
opt.name = opt._mock_name
|
|
52
|
+
|
|
53
|
+
with patch('pygeai.core.secrets.clients.SecretClient.create_secret', return_value="Created secret") as mock_create:
|
|
54
|
+
with patch('pygeai.core.utils.console.Console.write_stdout') as mock_stdout:
|
|
55
|
+
create_secret(option_list)
|
|
56
|
+
mock_create.assert_called_once_with(
|
|
57
|
+
name="MySecret",
|
|
58
|
+
secret_string="secret-value",
|
|
59
|
+
description="Test description"
|
|
60
|
+
)
|
|
61
|
+
mock_stdout.assert_called_once_with("Create secret result: \nCreated secret")
|
|
62
|
+
|
|
63
|
+
def test_create_secret_missing_name(self):
|
|
64
|
+
option_list = [
|
|
65
|
+
(Mock(spec=['name'], name="secret_string"), "secret-value")
|
|
66
|
+
]
|
|
67
|
+
option_list[0][0].name = "secret_string"
|
|
68
|
+
|
|
69
|
+
with self.assertRaises(MissingRequirementException) as context:
|
|
70
|
+
create_secret(option_list)
|
|
71
|
+
self.assertEqual(str(context.exception), "Cannot create secret without specifying name and secret-string")
|
|
72
|
+
|
|
73
|
+
def test_create_secret_missing_secret_string(self):
|
|
74
|
+
option_list = [
|
|
75
|
+
(Mock(spec=['name'], name="name"), "MySecret")
|
|
76
|
+
]
|
|
77
|
+
option_list[0][0].name = "name"
|
|
78
|
+
|
|
79
|
+
with self.assertRaises(MissingRequirementException) as context:
|
|
80
|
+
create_secret(option_list)
|
|
81
|
+
self.assertEqual(str(context.exception), "Cannot create secret without specifying name and secret-string")
|
|
82
|
+
|
|
83
|
+
def test_update_secret_success(self):
|
|
84
|
+
option_list = [
|
|
85
|
+
(Mock(spec=['name'], name="secret_id"), "secret-123"),
|
|
86
|
+
(Mock(spec=['name'], name="name"), "UpdatedSecret"),
|
|
87
|
+
(Mock(spec=['name'], name="secret_string"), "updated-value")
|
|
88
|
+
]
|
|
89
|
+
for opt, _ in option_list:
|
|
90
|
+
opt.name = opt._mock_name
|
|
91
|
+
|
|
92
|
+
with patch('pygeai.core.secrets.clients.SecretClient.update_secret', return_value="Updated secret") as mock_update:
|
|
93
|
+
with patch('pygeai.core.utils.console.Console.write_stdout') as mock_stdout:
|
|
94
|
+
update_secret(option_list)
|
|
95
|
+
mock_update.assert_called_once()
|
|
96
|
+
mock_stdout.assert_called_once_with("Update secret result: \nUpdated secret")
|
|
97
|
+
|
|
98
|
+
def test_update_secret_missing_id(self):
|
|
99
|
+
option_list = [
|
|
100
|
+
(Mock(spec=['name'], name="name"), "UpdatedSecret")
|
|
101
|
+
]
|
|
102
|
+
option_list[0][0].name = "name"
|
|
103
|
+
|
|
104
|
+
with self.assertRaises(MissingRequirementException) as context:
|
|
105
|
+
update_secret(option_list)
|
|
106
|
+
self.assertEqual(str(context.exception), "Cannot update secret without specifying secret-id, name, and secret-string")
|
|
107
|
+
|
|
108
|
+
def test_list_secrets_success(self):
|
|
109
|
+
option_list = []
|
|
110
|
+
|
|
111
|
+
with patch('pygeai.core.secrets.clients.SecretClient.list_secrets', return_value="Secrets list") as mock_list:
|
|
112
|
+
with patch('pygeai.core.utils.console.Console.write_stdout') as mock_stdout:
|
|
113
|
+
list_secrets(option_list)
|
|
114
|
+
mock_list.assert_called_once_with(name=None, id=None, start=0, count=10)
|
|
115
|
+
mock_stdout.assert_called_once_with("List secrets result: \nSecrets list")
|
|
116
|
+
|
|
117
|
+
def test_set_secret_accesses_success(self):
|
|
118
|
+
option_list = [
|
|
119
|
+
(Mock(spec=['name'], name="secret_id"), "secret-123"),
|
|
120
|
+
(Mock(spec=['name'], name="access_list"), '[{"project_id": "project-456"}]')
|
|
121
|
+
]
|
|
122
|
+
for opt, _ in option_list:
|
|
123
|
+
opt.name = opt._mock_name
|
|
124
|
+
|
|
125
|
+
with patch('pygeai.core.secrets.clients.SecretClient.set_secret_accesses', return_value="Access set") as mock_set:
|
|
126
|
+
with patch('pygeai.core.utils.console.Console.write_stdout') as mock_stdout:
|
|
127
|
+
set_secret_accesses(option_list)
|
|
128
|
+
mock_set.assert_called_once()
|
|
129
|
+
mock_stdout.assert_called_once_with("Set secret accesses result: \nAccess set")
|
|
130
|
+
|
|
131
|
+
def test_set_secret_accesses_missing_secret_id(self):
|
|
132
|
+
option_list = [
|
|
133
|
+
(Mock(spec=['name'], name="project_id"), "project-456")
|
|
134
|
+
]
|
|
135
|
+
option_list[0][0].name = "project_id"
|
|
136
|
+
|
|
137
|
+
with self.assertRaises(MissingRequirementException) as context:
|
|
138
|
+
set_secret_accesses(option_list)
|
|
139
|
+
self.assertEqual(str(context.exception), "Cannot set secret accesses without specifying secret-id and access-list")
|
|
140
|
+
|
|
141
|
+
def test_set_secret_accesses_missing_project_id(self):
|
|
142
|
+
option_list = [
|
|
143
|
+
(Mock(spec=['name'], name="secret_id"), "secret-123")
|
|
144
|
+
]
|
|
145
|
+
option_list[0][0].name = "secret_id"
|
|
146
|
+
|
|
147
|
+
with self.assertRaises(MissingRequirementException) as context:
|
|
148
|
+
set_secret_accesses(option_list)
|
|
149
|
+
self.assertEqual(str(context.exception), "Cannot set secret accesses without specifying secret-id and access-list")
|
|
150
|
+
|
|
151
|
+
def test_get_secret_accesses_success(self):
|
|
152
|
+
option_list = [
|
|
153
|
+
(Mock(spec=['name'], name="secret_id"), "secret-123")
|
|
154
|
+
]
|
|
155
|
+
option_list[0][0].name = "secret_id"
|
|
156
|
+
|
|
157
|
+
with patch('pygeai.core.secrets.clients.SecretClient.get_secret_accesses', return_value="Access list") as mock_get:
|
|
158
|
+
with patch('pygeai.core.utils.console.Console.write_stdout') as mock_stdout:
|
|
159
|
+
get_secret_accesses(option_list)
|
|
160
|
+
mock_get.assert_called_once_with(secret_id="secret-123")
|
|
161
|
+
mock_stdout.assert_called_once_with("Get secret accesses result: \nAccess list")
|
|
162
|
+
|
|
163
|
+
def test_get_secret_accesses_missing_id(self):
|
|
164
|
+
option_list = []
|
|
165
|
+
with self.assertRaises(MissingRequirementException) as context:
|
|
166
|
+
get_secret_accesses(option_list)
|
|
167
|
+
self.assertEqual(str(context.exception), "Cannot retrieve secret accesses without specifying secret-id")
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
if __name__ == '__main__':
|
|
171
|
+
unittest.main()
|
|
@@ -149,12 +149,19 @@ LLM_SETTINGS_5 = {
|
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
REQUEST_ITEM = {
|
|
152
|
+
"apiToken": "test-api-token",
|
|
152
153
|
"assistant": "N/D",
|
|
154
|
+
"cost": 0.001,
|
|
155
|
+
"elapsedTimeMs": 1500,
|
|
156
|
+
"endTimestamp": "2025-02-25T15:03:15.144",
|
|
153
157
|
"intent": None,
|
|
154
158
|
"timestamp": "2025-02-25T15:03:13.644",
|
|
155
159
|
"prompt": None,
|
|
156
160
|
"output": None,
|
|
157
161
|
"inputText": None,
|
|
162
|
+
"module": "test-module",
|
|
163
|
+
"sessionId": "test-session-id",
|
|
164
|
+
"startTimestamp": "2025-02-25T15:03:13.644",
|
|
158
165
|
"status": "succeeded"
|
|
159
166
|
}
|
|
160
167
|
|
|
@@ -351,8 +351,22 @@ class TestModelMapper(TestCase):
|
|
|
351
351
|
self.assertEqual(usage_limit.remaining_usage, 50)
|
|
352
352
|
|
|
353
353
|
def test_map_to_item(self):
|
|
354
|
-
data = {
|
|
355
|
-
|
|
354
|
+
data = {
|
|
355
|
+
"apiToken": "test-token",
|
|
356
|
+
"assistant": "Assistant 1",
|
|
357
|
+
"cost": 0.5,
|
|
358
|
+
"elapsedTimeMs": 100,
|
|
359
|
+
"endTimestamp": "2025-02-05T12:00:05Z",
|
|
360
|
+
"intent": "Intent 1",
|
|
361
|
+
"module": "test-module",
|
|
362
|
+
"timestamp": "2025-02-05T12:00:00Z",
|
|
363
|
+
"prompt": "Test prompt",
|
|
364
|
+
"output": "Test output",
|
|
365
|
+
"inputText": "Test input",
|
|
366
|
+
"sessionId": "test-session",
|
|
367
|
+
"startTimestamp": "2025-02-05T12:00:00Z",
|
|
368
|
+
"status": "succeeded"
|
|
369
|
+
}
|
|
356
370
|
item = ModelMapper.map_to_item(data)
|
|
357
371
|
|
|
358
372
|
self.assertTrue(isinstance(item, RequestItem))
|
|
@@ -472,45 +486,65 @@ class TestModelMapper(TestCase):
|
|
|
472
486
|
|
|
473
487
|
def test_map_to_project_item(self):
|
|
474
488
|
data = {
|
|
489
|
+
"apiToken": "test-token",
|
|
475
490
|
"assistant": "Test Assistant",
|
|
491
|
+
"cost": 0.5,
|
|
492
|
+
"elapsedTimeMs": 100,
|
|
493
|
+
"endTimestamp": "2025-02-05T12:00:05Z",
|
|
476
494
|
"intent": "Test Intent",
|
|
495
|
+
"module": "test-module",
|
|
477
496
|
"timestamp": "2025-02-05T12:00:00Z",
|
|
478
497
|
"prompt": "Test prompt",
|
|
479
498
|
"output": "Test output",
|
|
480
499
|
"inputText": "Test input text",
|
|
481
|
-
"
|
|
500
|
+
"sessionId": "test-session-id",
|
|
501
|
+
"startTimestamp": "2025-02-05T12:00:00Z",
|
|
502
|
+
"status": "succeeded"
|
|
482
503
|
}
|
|
483
504
|
item = ModelMapper.map_to_item(data)
|
|
484
505
|
|
|
485
506
|
self.assertTrue(isinstance(item, RequestItem))
|
|
486
507
|
self.assertEqual(item.assistant, "Test Assistant")
|
|
487
508
|
self.assertEqual(item.intent, "Test Intent")
|
|
488
|
-
self.assertEqual(item.timestamp, "2025-02-05T12:00:00Z")
|
|
489
509
|
self.assertEqual(item.prompt, "Test prompt")
|
|
490
510
|
self.assertEqual(item.output, "Test output")
|
|
491
511
|
self.assertEqual(item.input_text, "Test input text")
|
|
492
|
-
self.assertEqual(item.status, "
|
|
512
|
+
self.assertEqual(item.status, "succeeded")
|
|
493
513
|
|
|
494
514
|
def test_map_to_item_list(self):
|
|
495
515
|
data = {
|
|
496
516
|
"items": [
|
|
497
517
|
{
|
|
518
|
+
"apiToken": "test-token-1",
|
|
498
519
|
"assistant": "Assistant 1",
|
|
520
|
+
"cost": 0.5,
|
|
521
|
+
"elapsedTimeMs": 100,
|
|
522
|
+
"endTimestamp": "2025-02-05T12:00:05Z",
|
|
499
523
|
"intent": "Intent 1",
|
|
524
|
+
"module": "test-module",
|
|
500
525
|
"timestamp": "2025-02-05T12:00:00Z",
|
|
501
526
|
"prompt": "Prompt 1",
|
|
502
527
|
"output": "Output 1",
|
|
503
528
|
"inputText": "Input Text 1",
|
|
504
|
-
"
|
|
529
|
+
"sessionId": "test-session-1",
|
|
530
|
+
"startTimestamp": "2025-02-05T12:00:00Z",
|
|
531
|
+
"status": "succeeded"
|
|
505
532
|
},
|
|
506
533
|
{
|
|
534
|
+
"apiToken": "test-token-2",
|
|
507
535
|
"assistant": "Assistant 2",
|
|
536
|
+
"cost": 0.7,
|
|
537
|
+
"elapsedTimeMs": 150,
|
|
538
|
+
"endTimestamp": "2025-02-05T12:05:10Z",
|
|
508
539
|
"intent": "Intent 2",
|
|
540
|
+
"module": "test-module",
|
|
509
541
|
"timestamp": "2025-02-05T12:05:00Z",
|
|
510
542
|
"prompt": "Prompt 2",
|
|
511
543
|
"output": "Output 2",
|
|
512
544
|
"inputText": "Input Text 2",
|
|
513
|
-
"
|
|
545
|
+
"sessionId": "test-session-2",
|
|
546
|
+
"startTimestamp": "2025-02-05T12:05:00Z",
|
|
547
|
+
"status": "succeeded"
|
|
514
548
|
}
|
|
515
549
|
]
|
|
516
550
|
}
|
|
@@ -522,16 +556,14 @@ class TestModelMapper(TestCase):
|
|
|
522
556
|
|
|
523
557
|
self.assertEqual(items[0].assistant, "Assistant 1")
|
|
524
558
|
self.assertEqual(items[0].intent, "Intent 1")
|
|
525
|
-
self.assertEqual(items[0].timestamp, "2025-02-05T12:00:00Z")
|
|
526
559
|
self.assertEqual(items[0].prompt, "Prompt 1")
|
|
527
560
|
self.assertEqual(items[0].output, "Output 1")
|
|
528
561
|
self.assertEqual(items[0].input_text, "Input Text 1")
|
|
529
|
-
self.assertEqual(items[0].status, "
|
|
562
|
+
self.assertEqual(items[0].status, "succeeded")
|
|
530
563
|
|
|
531
564
|
self.assertEqual(items[1].assistant, "Assistant 2")
|
|
532
565
|
self.assertEqual(items[1].intent, "Intent 2")
|
|
533
|
-
self.assertEqual(items[1].timestamp, "2025-02-05T12:05:00Z")
|
|
534
566
|
self.assertEqual(items[1].prompt, "Prompt 2")
|
|
535
567
|
self.assertEqual(items[1].output, "Output 2")
|
|
536
568
|
self.assertEqual(items[1].input_text, "Input Text 2")
|
|
537
|
-
self.assertEqual(items[1].status, "
|
|
569
|
+
self.assertEqual(items[1].status, "succeeded")
|
|
@@ -192,7 +192,9 @@ class TestModels(TestCase):
|
|
|
192
192
|
request_item = RequestItem.model_validate(request_item_data)
|
|
193
193
|
self.assertEqual(request_item.assistant, request_item_data.get("assistant"))
|
|
194
194
|
self.assertEqual(request_item.intent, request_item_data.get("intent"))
|
|
195
|
-
|
|
195
|
+
# Compare timestamps by checking that the string representation starts with the expected value
|
|
196
|
+
expected_timestamp = request_item_data.get("timestamp").replace("Z", "+00:00") if request_item_data.get("timestamp").endswith("Z") else request_item_data.get("timestamp")
|
|
197
|
+
self.assertTrue(request_item.timestamp.isoformat().startswith(expected_timestamp))
|
|
196
198
|
self.assertEqual(request_item.prompt, request_item_data.get("prompt"))
|
|
197
199
|
self.assertEqual(request_item.output, request_item_data.get("output"))
|
|
198
200
|
self.assertEqual(request_item.input_text, request_item_data.get("inputText"))
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from unittest.mock import MagicMock
|
|
3
|
+
|
|
4
|
+
from pygeai.core.base.responses import ErrorListResponse, EmptyResponse
|
|
5
|
+
from pygeai.core.base.models import Error
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TestCoreBaseResponses(unittest.TestCase):
|
|
9
|
+
"""
|
|
10
|
+
python -m unittest pygeai.tests.core.base.test_responses.TestCoreBaseResponses
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def test_error_list_response_to_dict(self):
|
|
14
|
+
error1 = MagicMock(spec=Error)
|
|
15
|
+
error1.to_dict.return_value = {"code": "E001", "message": "Error 1"}
|
|
16
|
+
error2 = MagicMock(spec=Error)
|
|
17
|
+
error2.to_dict.return_value = {"code": "E002", "message": "Error 2"}
|
|
18
|
+
|
|
19
|
+
response = ErrorListResponse(errors=[error1, error2])
|
|
20
|
+
result = response.to_dict()
|
|
21
|
+
|
|
22
|
+
self.assertEqual(len(result), 2)
|
|
23
|
+
self.assertEqual(result[0], {"code": "E001", "message": "Error 1"})
|
|
24
|
+
self.assertEqual(result[1], {"code": "E002", "message": "Error 2"})
|
|
25
|
+
|
|
26
|
+
def test_empty_response_with_dict_content(self):
|
|
27
|
+
response = EmptyResponse(content={"key": "value"})
|
|
28
|
+
result = response.to_dict()
|
|
29
|
+
|
|
30
|
+
self.assertEqual(result, {"content": {"key": "value"}})
|
|
31
|
+
|
|
32
|
+
def test_empty_response_with_string_content(self):
|
|
33
|
+
response = EmptyResponse(content="test message")
|
|
34
|
+
result = response.to_dict()
|
|
35
|
+
|
|
36
|
+
self.assertEqual(result, {"content": "test message"})
|
|
37
|
+
|
|
38
|
+
def test_empty_response_with_none_content(self):
|
|
39
|
+
response = EmptyResponse(content=None)
|
|
40
|
+
result = response.to_dict()
|
|
41
|
+
|
|
42
|
+
self.assertEqual(result, {})
|
|
43
|
+
|
|
44
|
+
def test_empty_response_str(self):
|
|
45
|
+
response = EmptyResponse(content={"test": "data"})
|
|
46
|
+
result = str(response)
|
|
47
|
+
|
|
48
|
+
self.assertIn("content", result)
|
|
49
|
+
self.assertIn("test", result)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
if __name__ == '__main__':
|
|
53
|
+
unittest.main()
|
|
@@ -90,9 +90,8 @@ GEAI_API_BASE_URL = https://api.alias1.com
|
|
|
90
90
|
self.assertEqual(value, "test_api_key")
|
|
91
91
|
|
|
92
92
|
def test_get_setting_value_non_existing_alias(self):
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
self.assertIn("Alias 'invalid_alias' not found", str(context.exception))
|
|
93
|
+
value = self.settings.get_setting_value("GEAI_API_KEY", "invalid_alias")
|
|
94
|
+
self.assertIsNone(value)
|
|
96
95
|
|
|
97
96
|
def test_get_setting_value_non_existing_key(self):
|
|
98
97
|
with patch('sys.stdout.write') as mock_write:
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
|
|
3
|
+
from pygeai.core.files.mappers import FileResponseMapper
|
|
4
|
+
from pygeai.core.files.models import FileList, File
|
|
5
|
+
from pygeai.core.files.responses import UploadFileResponse
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TestFileResponseMapper(unittest.TestCase):
|
|
9
|
+
"""
|
|
10
|
+
python -m unittest pygeai.tests.core.files.test_mappers.TestFileResponseMapper
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def test_map_to_upload_file_response(self):
|
|
14
|
+
data = {
|
|
15
|
+
'dataFileId': 'file-123',
|
|
16
|
+
'dataFileUrl': 'https://example.com/file.txt',
|
|
17
|
+
'success': True
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
result = FileResponseMapper.map_to_upload_file_response(data)
|
|
21
|
+
|
|
22
|
+
self.assertIsInstance(result, UploadFileResponse)
|
|
23
|
+
self.assertEqual(result.id, 'file-123')
|
|
24
|
+
self.assertEqual(result.url, 'https://example.com/file.txt')
|
|
25
|
+
self.assertTrue(result.success)
|
|
26
|
+
|
|
27
|
+
def test_map_to_upload_file_response_missing_fields(self):
|
|
28
|
+
data = {}
|
|
29
|
+
|
|
30
|
+
result = FileResponseMapper.map_to_upload_file_response(data)
|
|
31
|
+
|
|
32
|
+
self.assertIsNone(result.id)
|
|
33
|
+
self.assertIsNone(result.url)
|
|
34
|
+
self.assertIsNone(result.success)
|
|
35
|
+
|
|
36
|
+
def test_map_to_file_list_response(self):
|
|
37
|
+
data = {
|
|
38
|
+
'dataFiles': [
|
|
39
|
+
{
|
|
40
|
+
'dataFileId': 'file-1',
|
|
41
|
+
'dataFileName': 'test1.txt',
|
|
42
|
+
'dataFileExtension': 'txt',
|
|
43
|
+
'dataFilePurpose': 'testing',
|
|
44
|
+
'dataFileSize': 1024,
|
|
45
|
+
'dataFileUrl': 'https://example.com/file1.txt'
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
'dataFileId': 'file-2',
|
|
49
|
+
'dataFileName': 'test2.pdf',
|
|
50
|
+
'dataFileExtension': 'pdf',
|
|
51
|
+
'dataFilePurpose': 'document',
|
|
52
|
+
'dataFileSize': 2048,
|
|
53
|
+
'dataFileUrl': 'https://example.com/file2.pdf'
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
result = FileResponseMapper.map_to_file_list_response(data)
|
|
59
|
+
|
|
60
|
+
self.assertIsInstance(result, FileList)
|
|
61
|
+
self.assertEqual(len(result.files), 2)
|
|
62
|
+
self.assertEqual(result.files[0].id, 'file-1')
|
|
63
|
+
self.assertEqual(result.files[1].id, 'file-2')
|
|
64
|
+
|
|
65
|
+
def test_map_to_file_list_empty(self):
|
|
66
|
+
data = {'dataFiles': []}
|
|
67
|
+
|
|
68
|
+
result = FileResponseMapper.map_to_file_list(data)
|
|
69
|
+
|
|
70
|
+
self.assertEqual(result, [])
|
|
71
|
+
|
|
72
|
+
def test_map_to_file_list_none(self):
|
|
73
|
+
data = {}
|
|
74
|
+
|
|
75
|
+
result = FileResponseMapper.map_to_file_list(data)
|
|
76
|
+
|
|
77
|
+
self.assertEqual(result, [])
|
|
78
|
+
|
|
79
|
+
def test_map_to_file_lowercase_keys(self):
|
|
80
|
+
data = {
|
|
81
|
+
'dataFileId': 'file-1',
|
|
82
|
+
'dataFileName': 'test.txt',
|
|
83
|
+
'dataFileExtension': 'txt',
|
|
84
|
+
'dataFilePurpose': 'testing',
|
|
85
|
+
'dataFileSize': 1024,
|
|
86
|
+
'dataFileUrl': 'https://example.com/file.txt'
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
result = FileResponseMapper.map_to_file(data)
|
|
90
|
+
|
|
91
|
+
self.assertIsInstance(result, File)
|
|
92
|
+
self.assertEqual(result.id, 'file-1')
|
|
93
|
+
self.assertEqual(result.name, 'test.txt')
|
|
94
|
+
self.assertEqual(result.extension, 'txt')
|
|
95
|
+
self.assertEqual(result.purpose, 'testing')
|
|
96
|
+
self.assertEqual(result.size, 1024)
|
|
97
|
+
self.assertEqual(result.url, 'https://example.com/file.txt')
|
|
98
|
+
|
|
99
|
+
def test_map_to_file_uppercase_keys(self):
|
|
100
|
+
data = {
|
|
101
|
+
'DataFileId': 'file-2',
|
|
102
|
+
'DataFileName': 'document.pdf',
|
|
103
|
+
'DataFileExtension': 'pdf',
|
|
104
|
+
'DataFilePurpose': 'documentation',
|
|
105
|
+
'DataFileSize': 2048,
|
|
106
|
+
'DataFileUrl': 'https://example.com/doc.pdf'
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
result = FileResponseMapper.map_to_file(data)
|
|
110
|
+
|
|
111
|
+
self.assertIsInstance(result, File)
|
|
112
|
+
self.assertEqual(result.id, 'file-2')
|
|
113
|
+
self.assertEqual(result.name, 'document.pdf')
|
|
114
|
+
self.assertEqual(result.extension, 'pdf')
|
|
115
|
+
self.assertEqual(result.purpose, 'documentation')
|
|
116
|
+
self.assertEqual(result.size, 2048)
|
|
117
|
+
self.assertEqual(result.url, 'https://example.com/doc.pdf')
|
|
118
|
+
|
|
119
|
+
def test_map_to_file_mixed_keys(self):
|
|
120
|
+
data = {
|
|
121
|
+
'DataFileId': 'file-3',
|
|
122
|
+
'dataFileName': 'mixed.csv',
|
|
123
|
+
'DataFileExtension': 'csv',
|
|
124
|
+
'dataFilePurpose': 'data',
|
|
125
|
+
'DataFileSize': 512,
|
|
126
|
+
'dataFileUrl': 'https://example.com/data.csv'
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
result = FileResponseMapper.map_to_file(data)
|
|
130
|
+
|
|
131
|
+
self.assertEqual(result.id, 'file-3')
|
|
132
|
+
self.assertEqual(result.name, 'mixed.csv')
|
|
133
|
+
self.assertEqual(result.extension, 'csv')
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
if __name__ == '__main__':
|
|
137
|
+
unittest.main()
|
|
File without changes
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from unittest.mock import patch, MagicMock
|
|
3
|
+
from json import JSONDecodeError
|
|
4
|
+
|
|
5
|
+
from pygeai.core.plugins.clients import PluginClient
|
|
6
|
+
from pygeai.core.common.exceptions import InvalidAPIResponseException
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TestPluginClient(unittest.TestCase):
|
|
10
|
+
"""
|
|
11
|
+
python -m unittest pygeai.tests.core.plugins.test_clients.TestPluginClient
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def setUp(self):
|
|
15
|
+
self.client = PluginClient()
|
|
16
|
+
self.mock_response = MagicMock()
|
|
17
|
+
|
|
18
|
+
@patch('pygeai.core.services.rest.ApiService.get')
|
|
19
|
+
def test_list_assistants_success(self, mock_get):
|
|
20
|
+
self.mock_response.json.return_value = {
|
|
21
|
+
"assistants": [
|
|
22
|
+
{"id": "assistant-1", "name": "Assistant 1"},
|
|
23
|
+
{"id": "assistant-2", "name": "Assistant 2"}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
mock_get.return_value = self.mock_response
|
|
27
|
+
|
|
28
|
+
result = self.client.list_assistants(
|
|
29
|
+
organization_id="org-123",
|
|
30
|
+
project_id="proj-456"
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
mock_get.assert_called_once()
|
|
34
|
+
call_args = mock_get.call_args
|
|
35
|
+
self.assertEqual(call_args[1]['params']['organization'], "org-123")
|
|
36
|
+
self.assertEqual(call_args[1]['params']['project'], "proj-456")
|
|
37
|
+
self.assertEqual(len(result["assistants"]), 2)
|
|
38
|
+
|
|
39
|
+
@patch('pygeai.core.services.rest.ApiService.get')
|
|
40
|
+
def test_list_assistants_empty(self, mock_get):
|
|
41
|
+
self.mock_response.json.return_value = {"assistants": []}
|
|
42
|
+
mock_get.return_value = self.mock_response
|
|
43
|
+
|
|
44
|
+
result = self.client.list_assistants(
|
|
45
|
+
organization_id="org-123",
|
|
46
|
+
project_id="proj-456"
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
self.assertEqual(result["assistants"], [])
|
|
50
|
+
|
|
51
|
+
@patch('pygeai.core.services.rest.ApiService.get')
|
|
52
|
+
def test_list_assistants_json_decode_error(self, mock_get):
|
|
53
|
+
self.mock_response.json.side_effect = JSONDecodeError("error", "doc", 0)
|
|
54
|
+
self.mock_response.status_code = 500
|
|
55
|
+
self.mock_response.text = "Internal server error"
|
|
56
|
+
mock_get.return_value = self.mock_response
|
|
57
|
+
|
|
58
|
+
with self.assertRaises(InvalidAPIResponseException) as context:
|
|
59
|
+
self.client.list_assistants("org-123", "proj-456")
|
|
60
|
+
self.assertIn("Unable to list assistants for organization org-123 and project proj-456", str(context.exception))
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
if __name__ == '__main__':
|
|
64
|
+
unittest.main()
|
|
File without changes
|
|
File without changes
|