Skip to content

Commit e3d0dbd

Browse files
committed
All make command tests pass
1 parent 4d7ce9d commit e3d0dbd

File tree

3 files changed

+817
-0
lines changed

3 files changed

+817
-0
lines changed
Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: MIT-0
3+
4+
"""
5+
Tests for progress monitor module
6+
"""
7+
8+
import json
9+
from unittest.mock import MagicMock, patch
10+
11+
import pytest
12+
from idp_cli.progress_monitor import ProgressMonitor
13+
14+
15+
class TestProgressMonitor:
16+
"""Test progress monitoring functionality"""
17+
18+
@patch("boto3.client")
19+
def test_init_success(self, mock_boto_client):
20+
"""Test successful initialization"""
21+
resources = {
22+
"LookupFunctionName": "test-lookup-function",
23+
"InputBucket": "input-bucket",
24+
}
25+
26+
monitor = ProgressMonitor("test-stack", resources)
27+
28+
assert monitor.stack_name == "test-stack"
29+
assert monitor.lookup_function == "test-lookup-function"
30+
31+
def test_init_missing_lookup_function(self):
32+
"""Test initialization fails without LookupFunctionName"""
33+
resources = {}
34+
35+
with pytest.raises(ValueError, match="LookupFunctionName not found"):
36+
ProgressMonitor("test-stack", resources)
37+
38+
@patch("boto3.client")
39+
def test_get_document_status_completed(self, mock_boto_client):
40+
"""Test getting status of completed document"""
41+
mock_lambda = MagicMock()
42+
mock_boto_client.return_value = mock_lambda
43+
44+
# Mock Lambda response
45+
lookup_result = {
46+
"status": "COMPLETED",
47+
"WorkflowExecutionArn": "arn:aws:states:us-east-1:123456789012:execution:test",
48+
"StartTime": "2025-01-10T10:00:00Z",
49+
"EndTime": "2025-01-10T10:05:00Z",
50+
"Duration": 300,
51+
"NumSections": 3,
52+
}
53+
54+
mock_lambda.invoke.return_value = {
55+
"Payload": MagicMock(read=lambda: json.dumps(lookup_result).encode())
56+
}
57+
58+
resources = {"LookupFunctionName": "test-function"}
59+
monitor = ProgressMonitor("test-stack", resources)
60+
61+
status = monitor.get_document_status("doc1")
62+
63+
assert status["status"] == "COMPLETED"
64+
assert status["document_id"] == "doc1"
65+
assert status["duration"] == 300
66+
assert status["num_sections"] == 3
67+
68+
@patch("boto3.client")
69+
def test_get_document_status_running(self, mock_boto_client):
70+
"""Test getting status of running document"""
71+
mock_lambda = MagicMock()
72+
mock_boto_client.return_value = mock_lambda
73+
74+
lookup_result = {
75+
"status": "RUNNING",
76+
"CurrentStep": "Extraction",
77+
"StartTime": "2025-01-10T10:00:00Z",
78+
}
79+
80+
mock_lambda.invoke.return_value = {
81+
"Payload": MagicMock(read=lambda: json.dumps(lookup_result).encode())
82+
}
83+
84+
resources = {"LookupFunctionName": "test-function"}
85+
monitor = ProgressMonitor("test-stack", resources)
86+
87+
status = monitor.get_document_status("doc1")
88+
89+
assert status["status"] == "RUNNING"
90+
assert status["current_step"] == "Extraction"
91+
92+
@patch("boto3.client")
93+
def test_get_document_status_failed(self, mock_boto_client):
94+
"""Test getting status of failed document"""
95+
mock_lambda = MagicMock()
96+
mock_boto_client.return_value = mock_lambda
97+
98+
lookup_result = {
99+
"status": "FAILED",
100+
"Error": "Classification timeout",
101+
"FailedStep": "Classification",
102+
}
103+
104+
mock_lambda.invoke.return_value = {
105+
"Payload": MagicMock(read=lambda: json.dumps(lookup_result).encode())
106+
}
107+
108+
resources = {"LookupFunctionName": "test-function"}
109+
monitor = ProgressMonitor("test-stack", resources)
110+
111+
status = monitor.get_document_status("doc1")
112+
113+
assert status["status"] == "FAILED"
114+
assert status["error"] == "Classification timeout"
115+
assert status["failed_step"] == "Classification"
116+
117+
@patch("boto3.client")
118+
def test_get_batch_status(self, mock_boto_client):
119+
"""Test getting batch status"""
120+
mock_lambda = MagicMock()
121+
mock_boto_client.return_value = mock_lambda
122+
123+
# Mock different document statuses
124+
def mock_invoke(FunctionName, InvocationType, Payload):
125+
payload_data = json.loads(Payload)
126+
doc_id = payload_data["object_key"]
127+
128+
if doc_id == "doc1":
129+
result = {"status": "COMPLETED", "Duration": 100}
130+
elif doc_id == "doc2":
131+
result = {"status": "RUNNING", "CurrentStep": "Extraction"}
132+
elif doc_id == "doc3":
133+
result = {"status": "FAILED", "Error": "Test error"}
134+
else:
135+
result = {"status": "QUEUED"}
136+
137+
return {"Payload": MagicMock(read=lambda: json.dumps(result).encode())}
138+
139+
mock_lambda.invoke.side_effect = mock_invoke
140+
141+
resources = {"LookupFunctionName": "test-function"}
142+
monitor = ProgressMonitor("test-stack", resources)
143+
144+
status_data = monitor.get_batch_status(["doc1", "doc2", "doc3", "doc4"])
145+
146+
assert len(status_data["completed"]) == 1
147+
assert len(status_data["running"]) == 1
148+
assert len(status_data["failed"]) == 1
149+
assert len(status_data["queued"]) == 1
150+
assert status_data["total"] == 4
151+
assert status_data["all_complete"] is False
152+
153+
@patch("boto3.client")
154+
def test_get_batch_status_all_complete(self, mock_boto_client):
155+
"""Test batch status when all documents are complete"""
156+
mock_lambda = MagicMock()
157+
mock_boto_client.return_value = mock_lambda
158+
159+
def mock_invoke(FunctionName, InvocationType, Payload):
160+
# Return batch query response
161+
return {
162+
"Payload": MagicMock(
163+
read=lambda: json.dumps(
164+
{
165+
"results": [
166+
{
167+
"object_key": "doc1",
168+
"status": "COMPLETED",
169+
"timing": {"elapsed": {"total": 100000}},
170+
},
171+
{
172+
"object_key": "doc2",
173+
"status": "COMPLETED",
174+
"timing": {"elapsed": {"total": 200000}},
175+
},
176+
]
177+
}
178+
).encode()
179+
)
180+
}
181+
182+
mock_lambda.invoke.side_effect = mock_invoke
183+
184+
resources = {"LookupFunctionName": "test-function"}
185+
monitor = ProgressMonitor("test-stack", resources)
186+
187+
status_data = monitor.get_batch_status(["doc1", "doc2"])
188+
189+
assert len(status_data["completed"]) == 2
190+
assert status_data["all_complete"] is True
191+
192+
@patch("boto3.client")
193+
def test_calculate_statistics(self, mock_boto_client):
194+
"""Test statistics calculation"""
195+
resources = {"LookupFunctionName": "test-function"}
196+
monitor = ProgressMonitor("test-stack", resources)
197+
198+
status_data = {
199+
"total": 10,
200+
"completed": [{"duration": 100}, {"duration": 200}, {"duration": 300}],
201+
"running": [{}],
202+
"queued": [{}] * 4,
203+
"failed": [{}] * 2,
204+
"all_complete": False,
205+
}
206+
207+
stats = monitor.calculate_statistics(status_data)
208+
209+
assert stats["total"] == 10
210+
assert stats["completed"] == 3
211+
assert stats["failed"] == 2
212+
assert stats["running"] == 1
213+
assert stats["queued"] == 4
214+
assert stats["completion_percentage"] == 50.0 # (3 + 2) / 10 * 100
215+
assert stats["success_rate"] == 60.0 # 3 / (3 + 2) * 100
216+
assert stats["avg_duration_seconds"] == 200.0 # (100 + 200 + 300) / 3
217+
218+
@patch("boto3.client")
219+
def test_get_recent_completions(self, mock_boto_client):
220+
"""Test getting recent completions"""
221+
resources = {"LookupFunctionName": "test-function"}
222+
monitor = ProgressMonitor("test-stack", resources)
223+
224+
status_data = {
225+
"completed": [
226+
{"document_id": "doc1", "end_time": "2025-01-10T10:00:00Z"},
227+
{"document_id": "doc2", "end_time": "2025-01-10T10:05:00Z"},
228+
{"document_id": "doc3", "end_time": "2025-01-10T10:03:00Z"},
229+
]
230+
}
231+
232+
recent = monitor.get_recent_completions(status_data, limit=2)
233+
234+
# Should return 2 most recent (sorted by end_time)
235+
assert len(recent) == 2
236+
assert recent[0]["document_id"] == "doc2" # Most recent
237+
assert recent[1]["document_id"] == "doc3"
238+
239+
@patch("boto3.client")
240+
def test_get_failed_documents(self, mock_boto_client):
241+
"""Test getting failed documents"""
242+
resources = {"LookupFunctionName": "test-function"}
243+
monitor = ProgressMonitor("test-stack", resources)
244+
245+
status_data = {
246+
"failed": [
247+
{"document_id": "doc1", "error": "Timeout", "failed_step": "OCR"},
248+
{
249+
"document_id": "doc2",
250+
"error": "Invalid format",
251+
"failed_step": "Classification",
252+
},
253+
]
254+
}
255+
256+
failed = monitor.get_failed_documents(status_data)
257+
258+
assert len(failed) == 2
259+
assert failed[0]["document_id"] == "doc1"
260+
assert failed[0]["error"] == "Timeout"
261+
assert failed[1]["document_id"] == "doc2"

0 commit comments

Comments
 (0)