Skip to content

Commit 3926dfe

Browse files
committed
add tests
1 parent 0caed68 commit 3926dfe

File tree

2 files changed

+104
-15
lines changed

2 files changed

+104
-15
lines changed

learning_resources/content_summarizer.py

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -128,15 +128,15 @@ def get_unprocessed_content_file_ids(
128128

129129
def summarize_content_files_by_ids(
130130
self, content_file_ids: list[int], overwrite
131-
) -> None:
131+
) -> list[str]:
132132
"""Process multiple content files by id.
133133
134134
Args:
135135
- ids (list[int]): List of content file ids to process
136136
- overwrite (bool): Whether to overwrite existing summary and flashcards
137137
138138
Returns:
139-
- None
139+
- list[str]: List of status messages for each content file
140140
"""
141141
status_messages = []
142142
for content_file_id in content_file_ids:
@@ -150,7 +150,7 @@ def summarize_single_content_file(
150150
self,
151151
content_file_id: int,
152152
overwrite,
153-
) -> tuple[bool, str]:
153+
) -> str:
154154
"""Process a single content file
155155
Args:
156156
- content_file_id (int): Id of the content file to process
@@ -184,19 +184,23 @@ def summarize_single_content_file(
184184

185185
if updated:
186186
content_file.save()
187-
return f"Content file summarization succeeded for CONTENT_FILE_ID: {content_file_id}" # noqa: E501
188-
return f"Content file summarization skipped for CONTENT_FILE_ID: {content_file_id}" # noqa: E501
189-
187+
return f"Summarization succeeded for CONTENT_FILE_ID: {content_file_id}" # noqa: E501
188+
return f"Summarization skipped for CONTENT_FILE_ID: {content_file_id}"
190189
except SummaryGenerationError as exc:
191-
return f"Content file summary generation failed for CONTENT_FILE_ID: {content_file_id}\nError: {exc.args[0]}\n\n" # noqa: E501
192-
190+
# Log and return a specific readable error message when summary
191+
# generation fails.
192+
logger.exception("Error processing content: %d", content_file.id)
193+
return f"Summary generation failed for CONTENT_FILE_ID: {content_file_id}\nError: {exc.args[0]}\n\n" # noqa: E501
193194
except FlashcardsGenerationError as exc:
194-
return f"Content file flashcards generation failed for CONTENT_FILE_ID: {content_file_id}\nError: {exc.args[0]}\n\n" # noqa: E501
195+
# Log and return a specific readable error message when flashcards
196+
# generation fails.
197+
return f"Flashcards generation failed for CONTENT_FILE_ID: {content_file_id}\nError: {exc.args[0]}\n\n" # noqa: E501
195198
except Exception as exc:
199+
# Log and return a specific readable error message when an unknown
200+
# error occurs.
196201
logger.exception("Error processing content: %d", content_file.id)
197202
return (
198-
False,
199-
f"Content file summarization failed for CONTENT_FILE_ID: {content_file_id}\nError: {exc.args[0]}\n\n", # noqa: E501
203+
f"Summarization failed for CONTENT_FILE_ID: {content_file_id}\nError: {exc.args[0]}\n\n", # noqa: E501
200204
)
201205

202206
def _get_llm(self, model=None, temperature=0.0, max_tokens=1000) -> ChatLiteLLM:
@@ -236,13 +240,16 @@ def _generate_summary(self, content: str, llm_model: str) -> str:
236240
logger.info("Generated summary: %s", generated_summary)
237241

238242
except Exception as exc:
243+
# We do not want to raise the exception as is, we will log the exception and
244+
# raise SummaryGenerationError that will be used to make further decisions
245+
# in the code.
239246
logger.exception(
240247
"An error occurred while generating summary using model: %s", llm_model
241248
)
242249
raise SummaryGenerationError(exc) from exc
243250

244251
else:
245-
return True, generated_summary
252+
return generated_summary
246253

247254
def _generate_flashcards(
248255
self, content: str, llm_model: str
@@ -264,11 +271,13 @@ def _generate_flashcards(
264271
generated_flashcards = response.get("flashcards")
265272
logger.info("Generated flashcards: %s", generated_flashcards)
266273
except Exception as exc:
274+
# We do not want to raise the exception as is, we will log the exception and
275+
# raise FlashcardsGenerationError that will be used to make further
276+
# decisions in the code.
267277
logger.exception(
268278
"An error occurred while generating flashcards using model: %s",
269279
llm_model,
270280
)
271281
raise FlashcardsGenerationError(exc) from exc
272-
273282
else:
274283
return generated_flashcards

learning_resources/content_summarizer_test.py

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
PlatformType,
77
)
88
from learning_resources.content_summarizer import ContentSummarizer
9+
from learning_resources.exceptions import (
10+
FlashcardsGenerationError,
11+
SummaryGenerationError,
12+
)
913
from learning_resources.factories import (
1014
ContentFileFactory,
1115
ContentSummarizerConfigurationFactory,
@@ -242,9 +246,9 @@ def test_get_unprocessed_content_files_with_platform_and_config(
242246
def test_summarize_content_files_by_ids(
243247
processable_content_files, mock_summarize_single_content_file
244248
):
245-
"""The summarizer should process content files that are processable"""
249+
"""The summarizer should process content files that are processable and return the status results"""
246250
summarizer = ContentSummarizer()
247-
summarizer.summarize_content_files_by_ids(
251+
results = summarizer.summarize_content_files_by_ids(
248252
overwrite=False,
249253
content_file_ids=[
250254
content_file.id for content_file in processable_content_files
@@ -253,6 +257,8 @@ def test_summarize_content_files_by_ids(
253257
assert mock_summarize_single_content_file.call_count == len(
254258
processable_content_files
255259
)
260+
assert isinstance(results, list)
261+
assert len(results) == len(processable_content_files)
256262

257263

258264
def test_summarize_single_content_file(mocker, processable_content_files):
@@ -332,3 +338,77 @@ def test_process_single_file_calls_llm_summary(
332338
assert mock_instance.with_structured_output.call_count == 1
333339
elif has_flashcards:
334340
assert mock_instance.invoke.call_count == 1
341+
342+
343+
@pytest.mark.parametrize(
344+
("process_type", "expected_exception"),
345+
[("summary", SummaryGenerationError), ("flashcards", FlashcardsGenerationError)],
346+
)
347+
def test_generate_summary_flashcards_exception(
348+
mocker, processable_content_files, settings, process_type, expected_exception
349+
):
350+
"""Test the exception handling in the generate_summary and generate_flashcards methods"""
351+
settings.OPENAI_API_KEY = "test"
352+
summarizer = ContentSummarizer()
353+
content_file = processable_content_files[0]
354+
content_file.save()
355+
356+
# Mock the ChatLiteLLM class and its methods
357+
mock_chat_llm = mocker.patch(
358+
"learning_resources.content_summarizer.ChatLiteLLM", autospec=True
359+
)
360+
mock_instance = mock_chat_llm.return_value
361+
362+
# Mock the response for _generate_summary to raise an exception
363+
mock_instance.invoke.side_effect = Exception("Test exception")
364+
# Mock the response for _generate_flashcards to raise an exception
365+
mock_instance.with_structured_output.return_value.invoke.side_effect = Exception(
366+
"INVALID_FORMAT"
367+
)
368+
369+
if process_type == "summary":
370+
with pytest.raises(expected_exception):
371+
summarizer._generate_summary( # noqa: SLF001
372+
llm_model="llm_model", content=content_file.content
373+
)
374+
else:
375+
with pytest.raises(expected_exception):
376+
summarizer._generate_flashcards( # noqa: SLF001
377+
llm_model="llm_model", content=content_file.content
378+
)
379+
380+
381+
def test_summarize_single_content_file_with_exception(
382+
mocker, processable_content_files, settings
383+
):
384+
"""Test the exception handling in the summarize_single_content_file method"""
385+
settings.OPENAI_API_KEY = "test"
386+
summarizer = ContentSummarizer()
387+
content_file = processable_content_files[0]
388+
389+
# Mock the ChatLiteLLM class and its methods
390+
mock_chat_llm = mocker.patch(
391+
"learning_resources.content_summarizer.ChatLiteLLM", autospec=True
392+
)
393+
mock_instance = mock_chat_llm.return_value
394+
395+
# Mock the response for _generate_summary to raise an exception
396+
mock_instance.invoke.side_effect = Exception("Test exception")
397+
# Mock the response for _generate_flashcards to raise an exception
398+
mock_instance.with_structured_output.return_value.invoke.side_effect = Exception(
399+
"INVALID_FORMAT"
400+
)
401+
402+
error = summarizer.summarize_single_content_file(content_file.id, overwrite=False)
403+
assert (
404+
error
405+
== f"Summary generation failed for CONTENT_FILE_ID: {content_file.id}\nError: Test exception\n\n"
406+
)
407+
content_file.summary = "Test summary"
408+
content_file.save()
409+
content_file.refresh_from_db()
410+
error = summarizer.summarize_single_content_file(content_file.id, overwrite=False)
411+
assert (
412+
error
413+
== f"Flashcards generation failed for CONTENT_FILE_ID: {content_file.id}\nError: INVALID_FORMAT\n\n"
414+
)

0 commit comments

Comments
 (0)