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.
Files changed (79) hide show
  1. pygeai/__init__.py +1 -1
  2. pygeai/auth/__init__.py +0 -0
  3. pygeai/auth/clients.py +55 -0
  4. pygeai/auth/endpoints.py +2 -0
  5. pygeai/cli/__init__.py +0 -1
  6. pygeai/cli/commands/auth.py +123 -0
  7. pygeai/cli/commands/base.py +22 -1
  8. pygeai/cli/commands/docs.py +105 -0
  9. pygeai/cli/texts/help.py +157 -24
  10. pygeai/core/files/responses.py +4 -3
  11. pygeai/lab/clients.py +3 -3
  12. pygeai/lab/tools/clients.py +4 -4
  13. pygeai/tests/admin/test_clients.py +143 -0
  14. pygeai/tests/auth/__init__.py +0 -0
  15. pygeai/tests/auth/test_clients.py +105 -0
  16. pygeai/tests/cli/commands/lab/test_ai_lab.py +41 -35
  17. pygeai/tests/cli/commands/lab/test_spec.py +24 -56
  18. pygeai/tests/cli/commands/test_chat.py +21 -3
  19. pygeai/tests/cli/commands/test_evaluation.py +649 -0
  20. pygeai/tests/cli/commands/test_secrets.py +171 -0
  21. pygeai/tests/core/base/data/models.py +7 -0
  22. pygeai/tests/core/base/test_mappers.py +43 -11
  23. pygeai/tests/core/base/test_models.py +3 -1
  24. pygeai/tests/core/base/test_responses.py +53 -0
  25. pygeai/tests/core/common/test_config.py +2 -3
  26. pygeai/tests/core/files/test_mappers.py +137 -0
  27. pygeai/tests/core/plugins/__init__.py +0 -0
  28. pygeai/tests/core/plugins/test_clients.py +64 -0
  29. pygeai/tests/evaluation/__init__.py +0 -0
  30. pygeai/tests/evaluation/dataset/__init__.py +0 -0
  31. pygeai/tests/evaluation/dataset/test_clients.py +263 -0
  32. pygeai/tests/evaluation/plan/__init__.py +0 -0
  33. pygeai/tests/evaluation/plan/test_clients.py +193 -0
  34. pygeai/tests/evaluation/result/__init__.py +0 -0
  35. pygeai/tests/evaluation/result/test_clients.py +64 -0
  36. pygeai/tests/integration/assistants/rag/test_create_rag.py +1 -1
  37. pygeai/tests/integration/chat/test_generate_image.py +1 -1
  38. pygeai/tests/integration/lab/agents/test_agents_list.py +1 -1
  39. pygeai/tests/integration/lab/agents/test_create_agent.py +3 -3
  40. pygeai/tests/integration/lab/agents/test_create_sharing_link.py +1 -1
  41. pygeai/tests/integration/lab/agents/test_delete_agent.py +2 -2
  42. pygeai/tests/integration/lab/agents/test_get_agent.py +1 -1
  43. pygeai/tests/integration/lab/agents/test_publish_agent_revision.py +2 -2
  44. pygeai/tests/integration/lab/agents/test_update_agent.py +3 -3
  45. pygeai/tests/integration/lab/processes/test_create_process.py +1 -1
  46. pygeai/tests/integration/lab/processes/test_create_task.py +211 -0
  47. pygeai/tests/integration/lab/processes/test_delete_process.py +111 -0
  48. pygeai/tests/integration/lab/processes/test_get_process.py +1 -1
  49. pygeai/tests/integration/lab/processes/test_list_process_instances.py +91 -0
  50. pygeai/tests/integration/lab/processes/test_list_processes.py +138 -0
  51. pygeai/tests/integration/lab/processes/test_publish_process_revision.py +232 -0
  52. pygeai/tests/integration/lab/processes/test_update_process.py +1 -1
  53. pygeai/tests/integration/lab/reasoning_strategies/test_get_reasoning_strategy.py +1 -1
  54. pygeai/tests/integration/lab/reasoning_strategies/test_list_reasoning_strategies.py +1 -1
  55. pygeai/tests/integration/lab/reasoning_strategies/test_update_reasoning_strategy.py +1 -1
  56. pygeai/tests/integration/lab/tools/test_create_tool.py +1 -1
  57. pygeai/tests/integration/lab/tools/test_delete_tool.py +1 -1
  58. pygeai/tests/integration/lab/tools/test_get_parameter.py +1 -1
  59. pygeai/tests/integration/lab/tools/test_get_tool.py +1 -1
  60. pygeai/tests/integration/lab/tools/test_list_tools.py +1 -1
  61. pygeai/tests/integration/lab/tools/test_publish_tool_revision.py +1 -1
  62. pygeai/tests/integration/lab/tools/test_set_parameter.py +1 -1
  63. pygeai/tests/integration/lab/tools/test_update_tool.py +1 -1
  64. pygeai/tests/lab/agents/test_clients.py +17 -34
  65. pygeai/tests/lab/processes/test_clients.py +30 -93
  66. pygeai/tests/lab/processes/test_mappers.py +12 -71
  67. pygeai/tests/lab/strategies/test_clients.py +63 -63
  68. pygeai/tests/lab/test_managers.py +3 -6
  69. pygeai/tests/lab/test_models.py +9 -8
  70. pygeai/tests/lab/tools/test_clients.py +22 -45
  71. pygeai/tests/migration/test_strategies.py +16 -16
  72. pygeai/tests/organization/test_mappers.py +11 -4
  73. pygeai/tests/organization/test_responses.py +137 -0
  74. {pygeai-0.5.0.dist-info → pygeai-0.6.0b3.dist-info}/METADATA +1 -1
  75. {pygeai-0.5.0.dist-info → pygeai-0.6.0b3.dist-info}/RECORD +79 -53
  76. {pygeai-0.5.0.dist-info → pygeai-0.6.0b3.dist-info}/WHEEL +0 -0
  77. {pygeai-0.5.0.dist-info → pygeai-0.6.0b3.dist-info}/entry_points.txt +0 -0
  78. {pygeai-0.5.0.dist-info → pygeai-0.6.0b3.dist-info}/licenses/LICENSE +0 -0
  79. {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 = {"assistant": "Assistant 1", "intent": "Intent 1", "timestamp": "2025-02-05T12:00:00Z",
355
- "prompt": "Test prompt", "output": "Test output", "inputText": "Test input", "status": "Success"}
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
- "status": "active"
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, "active")
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
- "status": "active"
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
- "status": "inactive"
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, "active")
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, "inactive")
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
- self.assertEqual(request_item.timestamp, request_item_data.get("timestamp"))
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
- with self.assertRaises(ValueError) as context:
94
- self.settings.get_setting_value("GEAI_API_KEY", "invalid_alias")
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