iatoolkit 0.8.1__py3-none-any.whl → 0.63.4__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 iatoolkit might be problematic. Click here for more details.

Files changed (159) hide show
  1. iatoolkit/__init__.py +8 -34
  2. iatoolkit/base_company.py +14 -3
  3. iatoolkit/common/routes.py +83 -52
  4. iatoolkit/common/session_manager.py +0 -1
  5. iatoolkit/common/util.py +0 -27
  6. iatoolkit/iatoolkit.py +61 -46
  7. iatoolkit/infra/llm_client.py +7 -8
  8. iatoolkit/infra/openai_adapter.py +1 -1
  9. iatoolkit/infra/redis_session_manager.py +48 -2
  10. iatoolkit/repositories/database_manager.py +17 -2
  11. iatoolkit/repositories/models.py +31 -6
  12. iatoolkit/repositories/profile_repo.py +7 -2
  13. iatoolkit/services/auth_service.py +188 -0
  14. iatoolkit/services/branding_service.py +147 -0
  15. iatoolkit/services/dispatcher_service.py +10 -40
  16. iatoolkit/services/excel_service.py +15 -15
  17. iatoolkit/services/history_service.py +3 -12
  18. iatoolkit/services/jwt_service.py +15 -24
  19. iatoolkit/services/onboarding_service.py +43 -0
  20. iatoolkit/services/profile_service.py +97 -44
  21. iatoolkit/services/query_service.py +124 -81
  22. iatoolkit/services/tasks_service.py +1 -1
  23. iatoolkit/services/user_feedback_service.py +67 -31
  24. iatoolkit/services/user_session_context_service.py +112 -54
  25. iatoolkit/static/images/fernando.jpeg +0 -0
  26. iatoolkit/static/js/{chat_feedback.js → chat_feedback_button.js} +6 -11
  27. iatoolkit/static/js/chat_history_button.js +126 -0
  28. iatoolkit/static/js/chat_logout_button.js +36 -0
  29. iatoolkit/static/js/chat_main.js +130 -220
  30. iatoolkit/static/js/chat_onboarding_button.js +97 -0
  31. iatoolkit/static/js/chat_prompt_manager.js +94 -0
  32. iatoolkit/static/js/chat_reload_button.js +52 -0
  33. iatoolkit/static/styles/chat_iatoolkit.css +329 -507
  34. iatoolkit/static/styles/chat_modal.css +95 -56
  35. iatoolkit/static/styles/landing_page.css +182 -0
  36. iatoolkit/static/styles/onboarding.css +169 -0
  37. iatoolkit/system_prompts/query_main.prompt +3 -12
  38. iatoolkit/templates/_company_header.html +20 -0
  39. iatoolkit/templates/_login_widget.html +40 -0
  40. iatoolkit/templates/base.html +8 -3
  41. iatoolkit/templates/change_password.html +54 -37
  42. iatoolkit/templates/chat.html +149 -66
  43. iatoolkit/templates/chat_modals.html +47 -18
  44. iatoolkit/templates/error.html +41 -8
  45. iatoolkit/templates/forgot_password.html +37 -24
  46. iatoolkit/templates/index.html +140 -0
  47. iatoolkit/templates/login_simulation.html +34 -0
  48. iatoolkit/templates/onboarding_shell.html +105 -0
  49. iatoolkit/templates/signup.html +64 -66
  50. iatoolkit/views/base_login_view.py +81 -0
  51. iatoolkit/views/change_password_view.py +23 -12
  52. iatoolkit/views/external_login_view.py +61 -28
  53. iatoolkit/views/{file_store_view.py → file_store_api_view.py} +9 -2
  54. iatoolkit/views/forgot_password_view.py +23 -13
  55. iatoolkit/views/history_api_view.py +52 -0
  56. iatoolkit/views/home_view.py +58 -25
  57. iatoolkit/views/index_view.py +14 -0
  58. iatoolkit/views/init_context_api_view.py +68 -0
  59. iatoolkit/views/llmquery_api_view.py +45 -0
  60. iatoolkit/views/login_simulation_view.py +81 -0
  61. iatoolkit/views/login_view.py +118 -34
  62. iatoolkit/views/logout_api_view.py +45 -0
  63. iatoolkit/views/{prompt_view.py → prompt_api_view.py} +7 -7
  64. iatoolkit/views/signup_view.py +38 -29
  65. iatoolkit/views/{tasks_view.py → tasks_api_view.py} +10 -36
  66. iatoolkit/views/tasks_review_api_view.py +55 -0
  67. iatoolkit/views/{user_feedback_view.py → user_feedback_api_view.py} +16 -31
  68. iatoolkit/views/verify_user_view.py +13 -8
  69. {iatoolkit-0.8.1.dist-info → iatoolkit-0.63.4.dist-info}/METADATA +2 -2
  70. iatoolkit-0.63.4.dist-info/RECORD +113 -0
  71. {iatoolkit-0.8.1.dist-info → iatoolkit-0.63.4.dist-info}/top_level.txt +0 -1
  72. iatoolkit/common/auth.py +0 -200
  73. iatoolkit/static/images/arrow_up.png +0 -0
  74. iatoolkit/static/images/diagrama_iatoolkit.jpg +0 -0
  75. iatoolkit/static/images/logo_clinica.png +0 -0
  76. iatoolkit/static/images/logo_iatoolkit.png +0 -0
  77. iatoolkit/static/images/logo_maxxa.png +0 -0
  78. iatoolkit/static/images/logo_notaria.png +0 -0
  79. iatoolkit/static/images/logo_tarjeta.png +0 -0
  80. iatoolkit/static/images/logo_umayor.png +0 -0
  81. iatoolkit/static/images/upload.png +0 -0
  82. iatoolkit/static/js/chat_history.js +0 -117
  83. iatoolkit/templates/home.html +0 -201
  84. iatoolkit/templates/login.html +0 -43
  85. iatoolkit/views/chat_token_request_view.py +0 -98
  86. iatoolkit/views/chat_view.py +0 -51
  87. iatoolkit/views/download_file_view.py +0 -58
  88. iatoolkit/views/external_chat_login_view.py +0 -88
  89. iatoolkit/views/history_view.py +0 -57
  90. iatoolkit/views/llmquery_view.py +0 -65
  91. iatoolkit/views/tasks_review_view.py +0 -83
  92. iatoolkit-0.8.1.dist-info/RECORD +0 -175
  93. tests/__init__.py +0 -5
  94. tests/common/__init__.py +0 -0
  95. tests/common/test_auth.py +0 -279
  96. tests/common/test_routes.py +0 -42
  97. tests/common/test_session_manager.py +0 -59
  98. tests/common/test_util.py +0 -444
  99. tests/companies/__init__.py +0 -5
  100. tests/conftest.py +0 -36
  101. tests/infra/__init__.py +0 -5
  102. tests/infra/connectors/__init__.py +0 -5
  103. tests/infra/connectors/test_google_drive_connector.py +0 -107
  104. tests/infra/connectors/test_local_file_connector.py +0 -85
  105. tests/infra/connectors/test_s3_connector.py +0 -95
  106. tests/infra/test_call_service.py +0 -92
  107. tests/infra/test_database_manager.py +0 -59
  108. tests/infra/test_gemini_adapter.py +0 -137
  109. tests/infra/test_google_chat_app.py +0 -68
  110. tests/infra/test_llm_client.py +0 -165
  111. tests/infra/test_llm_proxy.py +0 -122
  112. tests/infra/test_mail_app.py +0 -94
  113. tests/infra/test_openai_adapter.py +0 -105
  114. tests/infra/test_redis_session_manager_service.py +0 -117
  115. tests/repositories/__init__.py +0 -5
  116. tests/repositories/test_database_manager.py +0 -87
  117. tests/repositories/test_document_repo.py +0 -76
  118. tests/repositories/test_llm_query_repo.py +0 -340
  119. tests/repositories/test_models.py +0 -38
  120. tests/repositories/test_profile_repo.py +0 -142
  121. tests/repositories/test_tasks_repo.py +0 -76
  122. tests/repositories/test_vs_repo.py +0 -107
  123. tests/services/__init__.py +0 -5
  124. tests/services/test_dispatcher_service.py +0 -274
  125. tests/services/test_document_service.py +0 -181
  126. tests/services/test_excel_service.py +0 -208
  127. tests/services/test_file_processor_service.py +0 -121
  128. tests/services/test_history_service.py +0 -164
  129. tests/services/test_jwt_service.py +0 -255
  130. tests/services/test_load_documents_service.py +0 -112
  131. tests/services/test_mail_service.py +0 -70
  132. tests/services/test_profile_service.py +0 -379
  133. tests/services/test_prompt_manager_service.py +0 -190
  134. tests/services/test_query_service.py +0 -243
  135. tests/services/test_search_service.py +0 -39
  136. tests/services/test_sql_service.py +0 -160
  137. tests/services/test_tasks_service.py +0 -252
  138. tests/services/test_user_feedback_service.py +0 -389
  139. tests/services/test_user_session_context_service.py +0 -132
  140. tests/views/__init__.py +0 -5
  141. tests/views/test_change_password_view.py +0 -191
  142. tests/views/test_chat_token_request_view.py +0 -188
  143. tests/views/test_chat_view.py +0 -98
  144. tests/views/test_download_file_view.py +0 -149
  145. tests/views/test_external_chat_login_view.py +0 -120
  146. tests/views/test_external_login_view.py +0 -102
  147. tests/views/test_file_store_view.py +0 -128
  148. tests/views/test_forgot_password_view.py +0 -142
  149. tests/views/test_history_view.py +0 -336
  150. tests/views/test_home_view.py +0 -61
  151. tests/views/test_llm_query_view.py +0 -154
  152. tests/views/test_login_view.py +0 -114
  153. tests/views/test_prompt_view.py +0 -111
  154. tests/views/test_signup_view.py +0 -140
  155. tests/views/test_tasks_review_view.py +0 -104
  156. tests/views/test_tasks_view.py +0 -130
  157. tests/views/test_user_feedback_view.py +0 -214
  158. tests/views/test_verify_user_view.py +0 -110
  159. {iatoolkit-0.8.1.dist-info → iatoolkit-0.63.4.dist-info}/WHEEL +0 -0
@@ -1,255 +0,0 @@
1
- # Copyright (c) 2024 Fernando Libedinsky
2
- # Product: IAToolkit
3
- #
4
- # IAToolkit is open source software.
5
-
6
- import pytest
7
- import time
8
- import jwt # Necesario para crear tokens con payloads específicos para casos de error
9
- from flask import Flask
10
- from iatoolkit.services.jwt_service import JWTService # Asegúrate que la ruta de importación sea correcta
11
- from unittest.mock import patch
12
-
13
-
14
- # Datos comunes para los tests, pueden ser definidos a nivel de módulo o clase
15
- COMPANY_ID = 1
16
- COMPANY_SHORT_NAME = "testcomp"
17
- EXTERNAL_USER_ID = "user123"
18
- EXPIRES_DELTA_SECONDS = 300 # 5 minutos
19
- TEST_SECRET_KEY = 'test-super-secret-key'
20
- TEST_ALGORITHM = 'HS256'
21
-
22
- @pytest.fixture
23
- def app():
24
- """Fixture para crear una instancia de la aplicación Flask para tests."""
25
- flask_app = Flask(__name__)
26
- flask_app.config['JWT_SECRET_KEY'] = TEST_SECRET_KEY
27
- flask_app.config['JWT_ALGORITHM'] = TEST_ALGORITHM
28
- return flask_app
29
-
30
- @pytest.fixture
31
- def jwt_service(app):
32
- """Fixture para crear una instancia de JWTService."""
33
- return JWTService(app)
34
-
35
- class TestJWTService:
36
-
37
- def test_initialization_missing_config(self):
38
- """Prueba que JWTService levante RuntimeError si falta configuración."""
39
- app_sin_config_key = Flask(__name__)
40
- app_sin_config_key.config['JWT_ALGORITHM'] = TEST_ALGORITHM # Falta JWT_SECRET_KEY
41
- with pytest.raises(RuntimeError, match="Configuración JWT esencial faltante: 'JWT_SECRET_KEY'"):
42
- JWTService(app_sin_config_key)
43
-
44
- app_sin_config_algo = Flask(__name__)
45
- app_sin_config_algo.config['JWT_SECRET_KEY'] = TEST_SECRET_KEY # Falta JWT_ALGORITHM
46
- with pytest.raises(RuntimeError, match="Configuración JWT esencial faltante: 'JWT_ALGORITHM'"):
47
- JWTService(app_sin_config_algo)
48
-
49
- def test_generate_chat_jwt_success(self, jwt_service, app):
50
- """Prueba la generación exitosa de un JWT."""
51
- token = jwt_service.generate_chat_jwt(
52
- COMPANY_ID,
53
- COMPANY_SHORT_NAME,
54
- EXTERNAL_USER_ID,
55
- EXPIRES_DELTA_SECONDS
56
- )
57
- assert token is not None
58
- assert isinstance(token, str)
59
-
60
- # Decodificar para verificar el payload
61
- payload = jwt.decode(
62
- token,
63
- app.config['JWT_SECRET_KEY'],
64
- algorithms=[app.config['JWT_ALGORITHM']]
65
- )
66
- assert payload['company_id'] == COMPANY_ID
67
- assert payload['company_short_name'] == COMPANY_SHORT_NAME
68
- assert payload['external_user_id'] == EXTERNAL_USER_ID
69
- assert payload['type'] == 'chat_session'
70
- assert 'exp' in payload
71
- assert 'iat' in payload
72
- # Usar pytest.approx para comparar timestamps con una tolerancia
73
- assert payload['exp'] == pytest.approx(time.time() + EXPIRES_DELTA_SECONDS, abs=5)
74
-
75
- @patch('jwt.encode')
76
- def test_generate_chat_jwt_encode_exception(self, mock_jwt_encode, jwt_service):
77
- mock_jwt_encode.side_effect = Exception("JWT Encode Error")
78
- token = jwt_service.generate_chat_jwt(
79
- COMPANY_ID,
80
- COMPANY_SHORT_NAME,
81
- EXTERNAL_USER_ID,
82
- EXPIRES_DELTA_SECONDS
83
- )
84
- assert token is None
85
-
86
- def test_validate_chat_jwt_success(self, jwt_service):
87
- """Prueba la validación exitosa de un JWT."""
88
- token = jwt_service.generate_chat_jwt(
89
- COMPANY_ID,
90
- COMPANY_SHORT_NAME,
91
- EXTERNAL_USER_ID,
92
- EXPIRES_DELTA_SECONDS
93
- )
94
- payload = jwt_service.validate_chat_jwt(token, COMPANY_SHORT_NAME)
95
- assert payload is not None
96
- assert payload['company_id'] == COMPANY_ID
97
- assert payload['company_short_name'] == COMPANY_SHORT_NAME
98
- assert payload['external_user_id'] == EXTERNAL_USER_ID
99
- assert payload['type'] == 'chat_session'
100
-
101
- def test_validate_chat_jwt_expired(self, jwt_service):
102
- """Prueba la validación de un JWT expirado."""
103
- token = jwt_service.generate_chat_jwt(
104
- COMPANY_ID,
105
- COMPANY_SHORT_NAME,
106
- EXTERNAL_USER_ID,
107
- expires_delta_seconds=1 # Expira en 1 segundo
108
- )
109
- time.sleep(2) # Esperar a que expire
110
- payload = jwt_service.validate_chat_jwt(token, COMPANY_SHORT_NAME)
111
- assert payload is None
112
-
113
- def test_validate_chat_jwt_invalid_signature(self, jwt_service, app):
114
- """Prueba la validación de un JWT con firma inválida."""
115
- payload_data = {
116
- 'company_id': COMPANY_ID,
117
- 'company_short_name': COMPANY_SHORT_NAME,
118
- 'external_user_id': EXTERNAL_USER_ID,
119
- 'exp': time.time() + EXPIRES_DELTA_SECONDS,
120
- 'iat': time.time(),
121
- 'type': 'chat_session'
122
- }
123
- # Generar token con una clave secreta diferente
124
- invalid_token = jwt.encode(
125
- payload_data,
126
- 'another-wrong-secret-key',
127
- algorithm=app.config['JWT_ALGORITHM']
128
- )
129
- payload = jwt_service.validate_chat_jwt(invalid_token, COMPANY_SHORT_NAME)
130
- assert payload is None
131
-
132
- def test_validate_chat_jwt_wrong_company_short_name(self, jwt_service):
133
- """Prueba la validación con un company_short_name incorrecto."""
134
- token = jwt_service.generate_chat_jwt(
135
- COMPANY_ID,
136
- COMPANY_SHORT_NAME, # "testcomp"
137
- EXTERNAL_USER_ID,
138
- EXPIRES_DELTA_SECONDS
139
- )
140
- payload = jwt_service.validate_chat_jwt(token, "anothercomp")
141
- assert payload is None
142
-
143
- def test_validate_chat_jwt_incorrect_type(self, jwt_service, app):
144
- """Prueba la validación de un JWT con un tipo incorrecto."""
145
- payload_data = {
146
- 'company_id': COMPANY_ID,
147
- 'company_short_name': COMPANY_SHORT_NAME,
148
- 'external_user_id': EXTERNAL_USER_ID,
149
- 'exp': time.time() + EXPIRES_DELTA_SECONDS,
150
- 'iat': time.time(),
151
- 'type': 'not_chat_session' # Tipo incorrecto
152
- }
153
- token_wrong_type = jwt.encode(
154
- payload_data,
155
- app.config['JWT_SECRET_KEY'],
156
- algorithm=app.config['JWT_ALGORITHM']
157
- )
158
- payload = jwt_service.validate_chat_jwt(token_wrong_type, COMPANY_SHORT_NAME)
159
- assert payload is None
160
-
161
- def test_validate_chat_jwt_missing_external_user_id(self, jwt_service, app):
162
- """Prueba la validación de un JWT sin external_user_id."""
163
- payload_data_missing = {
164
- 'company_id': COMPANY_ID,
165
- 'company_short_name': COMPANY_SHORT_NAME,
166
- # 'external_user_id': EXTERNAL_USER_ID, # Ausente
167
- 'exp': time.time() + EXPIRES_DELTA_SECONDS,
168
- 'iat': time.time(),
169
- 'type': 'chat_session'
170
- }
171
- token_missing_field = jwt.encode(
172
- payload_data_missing,
173
- app.config['JWT_SECRET_KEY'],
174
- algorithm=app.config['JWT_ALGORITHM']
175
- )
176
- payload = jwt_service.validate_chat_jwt(token_missing_field, COMPANY_SHORT_NAME)
177
- assert payload is None
178
-
179
- payload_data_empty_user_id = {
180
- 'company_id': COMPANY_ID,
181
- 'company_short_name': COMPANY_SHORT_NAME,
182
- 'external_user_id': "", # Vacío
183
- 'exp': time.time() + EXPIRES_DELTA_SECONDS,
184
- 'iat': time.time(),
185
- 'type': 'chat_session'
186
- }
187
- token_empty_user_id = jwt.encode(
188
- payload_data_empty_user_id,
189
- app.config['JWT_SECRET_KEY'],
190
- algorithm=app.config['JWT_ALGORITHM']
191
- )
192
- payload = jwt_service.validate_chat_jwt(token_empty_user_id, COMPANY_SHORT_NAME)
193
- assert payload is None
194
-
195
- def test_validate_chat_jwt_missing_company_id(self, jwt_service, app):
196
- """Prueba la validación de un JWT sin company_id."""
197
- payload_data = {
198
- # 'company_id': COMPANY_ID, # Ausente
199
- 'company_short_name': COMPANY_SHORT_NAME,
200
- 'external_user_id': EXTERNAL_USER_ID,
201
- 'exp': time.time() + EXPIRES_DELTA_SECONDS,
202
- 'iat': time.time(),
203
- 'type': 'chat_session'
204
- }
205
- token_missing_field = jwt.encode(
206
- payload_data,
207
- app.config['JWT_SECRET_KEY'],
208
- algorithm=app.config['JWT_ALGORITHM']
209
- )
210
- payload = jwt_service.validate_chat_jwt(token_missing_field, COMPANY_SHORT_NAME)
211
- assert payload is None
212
-
213
- def test_validate_chat_jwt_invalid_company_id_type(self, jwt_service, app):
214
- """Prueba la validación de un JWT con company_id de tipo incorrecto."""
215
- payload_data = {
216
- 'company_id': "not_an_int", # Tipo incorrecto
217
- 'company_short_name': COMPANY_SHORT_NAME,
218
- 'external_user_id': EXTERNAL_USER_ID,
219
- 'exp': time.time() + EXPIRES_DELTA_SECONDS,
220
- 'iat': time.time(),
221
- 'type': 'chat_session'
222
- }
223
- token_invalid_type = jwt.encode(
224
- payload_data,
225
- app.config['JWT_SECRET_KEY'],
226
- algorithm=app.config['JWT_ALGORITHM']
227
- )
228
- payload = jwt_service.validate_chat_jwt(token_invalid_type, COMPANY_SHORT_NAME)
229
- assert payload is None
230
-
231
- def test_validate_chat_jwt_empty_token(self, jwt_service):
232
- """Prueba la validación con un token vacío."""
233
- payload = jwt_service.validate_chat_jwt("", COMPANY_SHORT_NAME)
234
- assert payload is None
235
-
236
- def test_validate_chat_jwt_none_token(self, jwt_service):
237
- """Prueba la validación con un token None."""
238
- payload = jwt_service.validate_chat_jwt(None, COMPANY_SHORT_NAME)
239
- assert payload is None
240
-
241
- @patch('jwt.decode')
242
- def test_validate_chat_jwt_decode_exception(self, mock_jwt_decode, jwt_service):
243
- """Prueba que validate_chat_jwt maneje excepciones generales de jwt.decode (no InvalidTokenError)."""
244
- mock_jwt_decode.side_effect = Exception("JWT Decode Error")
245
- # Necesitamos un token, aunque será el mock el que falle.
246
- # Podríamos pasar cualquier string, pero generar uno real es más consistente.
247
- token = jwt_service.generate_chat_jwt(
248
- COMPANY_ID,
249
- COMPANY_SHORT_NAME,
250
- EXTERNAL_USER_ID,
251
- EXPIRES_DELTA_SECONDS
252
- )
253
- payload = jwt_service.validate_chat_jwt(token, COMPANY_SHORT_NAME)
254
- assert payload is None
255
-
@@ -1,112 +0,0 @@
1
- # Copyright (c) 2024 Fernando Libedinsky
2
- # Product: IAToolkit
3
- #
4
- # IAToolkit is open source software.
5
-
6
- import pytest
7
- from unittest.mock import patch, MagicMock
8
- from iatoolkit.services.load_documents_service import LoadDocumentsService
9
- from iatoolkit.repositories.models import Company
10
- from iatoolkit.common.exceptions import IAToolkitException
11
-
12
-
13
- class TestLoadDocumentsService:
14
- def setup_method(self):
15
- self.mock_vector_store = MagicMock()
16
- self.mock_file_connector_factory = MagicMock()
17
- self.mock_dispatcher = MagicMock()
18
- self.mock_doc_service = MagicMock()
19
- self.mock_doc_repo = MagicMock()
20
- self.mock_profile_repo = MagicMock()
21
- self.mock_llm_query_repo = MagicMock()
22
-
23
- self.service = LoadDocumentsService(
24
- doc_service=self.mock_doc_service,
25
- doc_repo=self.mock_doc_repo,
26
- profile_repo=self.mock_profile_repo,
27
- llm_query_repo=self.mock_llm_query_repo,
28
- vector_store=self.mock_vector_store,
29
- file_connector_factory=self.mock_file_connector_factory,
30
- dispatcher=self.mock_dispatcher
31
- )
32
-
33
- self.company = Company(
34
- id=1,
35
- name='a big company',
36
- short_name='company'
37
- )
38
- self.mock_profile_repo.get_companies.return_value = [self.company]
39
-
40
- def test_load_company_files_when_missing_connector(self):
41
-
42
- with pytest.raises(IAToolkitException) as excinfo:
43
- self.service.load_company_files(company=self.company,
44
- connector_config={})
45
-
46
- assert excinfo.value.error_type == IAToolkitException.ErrorType.MISSING_PARAMETER
47
- assert "configurar conector" in str(excinfo.value)
48
-
49
- @patch("logging.exception")
50
- def test_load_company_files_when_exception(self, mock_logging_exception):
51
- mock_connector_config = {"type": "s3"}
52
- self.mock_file_connector_factory.create.side_effect = Exception("Test exception")
53
-
54
- result = self.service.load_company_files(company=self.company,
55
- connector_config=mock_connector_config)
56
-
57
- assert result == {"error": "Test exception"}
58
- mock_logging_exception.assert_called_once_with("Loading files error: %s", "Test exception")
59
-
60
-
61
- def test_load_file_when_document_exists(self, ):
62
- filename = "mock_file.pdf"
63
- content = b"mock content"
64
- self.mock_doc_repo.get.return_value = True
65
-
66
- self.service.load_file_callback(company=self.company,
67
- filename=filename,
68
- content=content)
69
-
70
- self.service.doc_service.file_to_txt.assert_not_called()
71
- self.mock_doc_repo.insert.assert_not_called()
72
- self.service.vector_store.add_document.assert_not_called()
73
-
74
- def test_load_files_when_exception_adding_document(self):
75
- self.mock_doc_repo.get.return_value = None
76
- self.mock_vector_store.add_document.side_effect = Exception("Error adding document")
77
-
78
- filename = "mock_file.pdf"
79
- content = b"mock content"
80
- with pytest.raises(IAToolkitException) as excinfo:
81
- result = self.service.load_file_callback(
82
- company=self.company,
83
- filename=filename,
84
- content=content)
85
-
86
- assert excinfo.value.error_type == IAToolkitException.ErrorType.LOAD_DOCUMENT_ERROR
87
- assert "Error al procesar el archivo" in str(excinfo.value)
88
-
89
- def test_load_when_file_is_created(self):
90
- # Mock del archivo y contenido
91
- filename = "mock_file.pdf"
92
- content = b"mock content"
93
- self.service.company = self.company
94
- context = {'metadata': {"document_type": "certificate"}}
95
-
96
- # Mock simulando que el archivo no existe
97
- self.mock_doc_repo.get.return_value = None
98
-
99
- # Mock de extracción de texto
100
- extracted_text = "mock extracted content"
101
- self.service.doc_service.file_to_txt.return_value = extracted_text
102
- self.mock_dispatcher.get_metadata_from_filename.return_value = {}
103
-
104
- self.service.load_file_callback(company=self.company,
105
- filename=filename,
106
- content=content,
107
- context=context)
108
-
109
- # Verificaciones
110
- self.mock_doc_repo.get.assert_called_once_with(company_id=self.company.id, filename=filename)
111
- self.service.doc_service.file_to_txt.assert_called_once_with(filename, content)
112
- self.service.vector_store.add_document.assert_called_once()
@@ -1,70 +0,0 @@
1
- # Copyright (c) 2024 Fernando Libedinsky
2
- # Product: IAToolkit
3
- #
4
- # IAToolkit is open source software.
5
-
6
- from unittest.mock import MagicMock
7
- from iatoolkit.services.mail_service import MailService
8
-
9
-
10
- class TestMailService:
11
-
12
- def setup_method(self):
13
- self.mock_mail_app = MagicMock()
14
-
15
- # Instancia de MailService con la dependencia inyectada como mock
16
- self.mail_service = MailService(mail_app=self.mock_mail_app)
17
-
18
- # Datos por defecto para enviar email
19
- self.recipient = 'destinatario@test.com'
20
- self.subject = 'Prueba'
21
- self.body = 'Contenido del mensaje'
22
-
23
-
24
- def test_send_mail_when_success(self):
25
- result = self.mail_service.send_mail(
26
- recipient=self.recipient,
27
- subject=self.subject,
28
- body=self.body,
29
- attachments=[]
30
- )
31
-
32
- # Comprobamos si mail_app.send_email fue invocado correctamente
33
- self.mock_mail_app.send_email.assert_called_once_with(
34
- sender={'email': 'iatoolkit@iatoolkit.com', 'name': 'IAToolkit'},
35
- to=self.recipient,
36
- subject=self.subject,
37
- body=self.body,
38
- attachments=[] )
39
- assert result == 'mail enviado'
40
-
41
- def test_send_mail_when_no_recipient(self):
42
- # Probamos el comportamiento cuando falta el receptor del mensaje
43
- result = self.mail_service.send_mail(
44
- subject=self.subject,
45
- body=self.body
46
- )
47
-
48
- '''
49
- self.mock_mail_app.send_email.assert_called_once_with(
50
- sender={'email': 'iatoolkit@iatoolkit.com', 'name': 'IAToolkit'},
51
- to=None,
52
- subject=self.subject,
53
- body=self.body,
54
- attach=None,
55
- attachments=None
56
- )
57
- assert result == 'mail enviado'
58
- '''
59
-
60
- def test_send_mail_partial_args(self):
61
- # Comprobamos cuando faltan parcialmente argumentos como subject y body
62
- result = self.mail_service.send_mail(recipient=self.recipient)
63
-
64
- self.mock_mail_app.send_email.assert_called_once_with(
65
- sender={'email': 'iatoolkit@iatoolkit.com', 'name': 'IAToolkit'},
66
- to=self.recipient,
67
- subject=None,
68
- body=None,
69
- attachments=[] )
70
- assert result == 'mail enviado'