Skip to content

Commit 8e46b03

Browse files
tests: add tests for extract_metadata_from_image
1 parent 9045237 commit 8e46b03

File tree

1 file changed

+204
-0
lines changed

1 file changed

+204
-0
lines changed
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
import json
2+
import logging
3+
from unittest.mock import MagicMock, patch
4+
5+
import pytest
6+
from PIL import Image
7+
8+
from invokeai.app.api.extract_metadata_from_image import ExtractedMetadata, extract_metadata_from_image
9+
10+
11+
@pytest.fixture
12+
def mock_logger():
13+
return MagicMock(spec=logging.Logger)
14+
15+
16+
@pytest.fixture
17+
def valid_metadata():
18+
return json.dumps({"param1": "value1", "param2": 123})
19+
20+
21+
@pytest.fixture
22+
def valid_workflow():
23+
return json.dumps({"name": "test_workflow", "version": "1.0"})
24+
25+
26+
@pytest.fixture
27+
def valid_graph():
28+
return json.dumps({"nodes": [], "edges": []})
29+
30+
31+
def test_extract_valid_metadata_from_image(mock_logger, valid_metadata, valid_workflow, valid_graph):
32+
# Create a mock image with valid metadata
33+
mock_image = MagicMock(spec=Image.Image)
34+
mock_image.info = {
35+
"invokeai_metadata": valid_metadata,
36+
"invokeai_workflow": valid_workflow,
37+
"invokeai_graph": valid_graph,
38+
}
39+
40+
# Mock the validation functions
41+
with patch(
42+
"invokeai.app.services.workflow_records.workflow_records_common.WorkflowWithoutIDValidator.validate_json"
43+
) as mock_workflow_validate:
44+
with patch("invokeai.app.services.shared.graph.Graph.model_validate_json") as mock_graph_validate:
45+
result = extract_metadata_from_image(mock_image, None, None, None, mock_logger)
46+
47+
# Assert correct calls to validators
48+
mock_workflow_validate.assert_called_once_with(valid_workflow)
49+
mock_graph_validate.assert_called_once_with(valid_graph)
50+
51+
# Assert correct extraction
52+
assert result == ExtractedMetadata(
53+
invokeai_metadata=valid_metadata, invokeai_workflow=valid_workflow, invokeai_graph=valid_graph
54+
)
55+
56+
57+
def test_extract_invalid_metadata(mock_logger, valid_workflow, valid_graph):
58+
# Invalid metadata (not JSON)
59+
invalid_metadata = "not a valid json"
60+
61+
mock_image = MagicMock(spec=Image.Image)
62+
mock_image.info = {
63+
"invokeai_metadata": invalid_metadata,
64+
"invokeai_workflow": valid_workflow,
65+
"invokeai_graph": valid_graph,
66+
}
67+
68+
with patch(
69+
"invokeai.app.services.workflow_records.workflow_records_common.WorkflowWithoutIDValidator.validate_json"
70+
):
71+
with patch("invokeai.app.services.shared.graph.Graph.model_validate_json"):
72+
result = extract_metadata_from_image(mock_image, None, None, None, mock_logger)
73+
74+
assert mock_logger.debug.to_have_been_called_with("Failed to parse metadata for uploaded image")
75+
76+
# Invalid metadata should be None, others valid
77+
assert result.invokeai_metadata is None
78+
assert result.invokeai_workflow == valid_workflow
79+
assert result.invokeai_graph == valid_graph
80+
81+
82+
def test_metadata_wrong_type(mock_logger, valid_workflow, valid_graph):
83+
# Valid JSON but not a dict
84+
metadata_array = json.dumps(["item1", "item2"])
85+
86+
mock_image = MagicMock(spec=Image.Image)
87+
mock_image.info = {
88+
"invokeai_metadata": metadata_array,
89+
"invokeai_workflow": valid_workflow,
90+
"invokeai_graph": valid_graph,
91+
}
92+
93+
with patch(
94+
"invokeai.app.services.workflow_records.workflow_records_common.WorkflowWithoutIDValidator.validate_json"
95+
):
96+
with patch("invokeai.app.services.shared.graph.Graph.model_validate_json"):
97+
result = extract_metadata_from_image(mock_image, None, None, None, mock_logger)
98+
99+
# Metadata should be None as it's not a dict
100+
assert result.invokeai_metadata is None
101+
assert result.invokeai_workflow == valid_workflow
102+
assert result.invokeai_graph == valid_graph
103+
104+
105+
def test_with_non_string_metadata(mock_logger, valid_workflow, valid_graph):
106+
# Some implementations might include metadata as non-string values
107+
mock_image = MagicMock(spec=Image.Image)
108+
mock_image.info = {
109+
"invokeai_metadata": 12345, # Not a string
110+
"invokeai_workflow": valid_workflow,
111+
"invokeai_graph": valid_graph,
112+
}
113+
114+
with patch(
115+
"invokeai.app.services.workflow_records.workflow_records_common.WorkflowWithoutIDValidator.validate_json"
116+
):
117+
with patch("invokeai.app.services.shared.graph.Graph.model_validate_json"):
118+
result = extract_metadata_from_image(mock_image, None, None, None, mock_logger)
119+
120+
assert mock_logger.debug.to_have_been_called_with("Failed to parse metadata for uploaded image")
121+
122+
assert result.invokeai_metadata is None
123+
assert result.invokeai_workflow == valid_workflow
124+
assert result.invokeai_graph == valid_graph
125+
126+
127+
def test_invalid_workflow(mock_logger, valid_metadata, valid_graph):
128+
invalid_workflow = "not a valid workflow json"
129+
130+
mock_image = MagicMock(spec=Image.Image)
131+
mock_image.info = {
132+
"invokeai_metadata": valid_metadata,
133+
"invokeai_workflow": invalid_workflow,
134+
"invokeai_graph": valid_graph,
135+
}
136+
137+
with patch(
138+
"invokeai.app.services.workflow_records.workflow_records_common.WorkflowWithoutIDValidator.validate_json"
139+
) as mock_validate:
140+
mock_validate.side_effect = ValueError("Invalid workflow")
141+
with patch("invokeai.app.services.shared.graph.Graph.model_validate_json"):
142+
result = extract_metadata_from_image(mock_image, None, None, None, mock_logger)
143+
144+
assert result.invokeai_metadata == valid_metadata
145+
assert result.invokeai_workflow is None
146+
assert result.invokeai_graph == valid_graph
147+
148+
149+
def test_invalid_graph(mock_logger, valid_metadata, valid_workflow):
150+
invalid_graph = "not a valid graph json"
151+
152+
mock_image = MagicMock(spec=Image.Image)
153+
mock_image.info = {
154+
"invokeai_metadata": valid_metadata,
155+
"invokeai_workflow": valid_workflow,
156+
"invokeai_graph": invalid_graph,
157+
}
158+
159+
with patch(
160+
"invokeai.app.services.workflow_records.workflow_records_common.WorkflowWithoutIDValidator.validate_json"
161+
):
162+
with patch("invokeai.app.services.shared.graph.Graph.model_validate_json") as mock_validate:
163+
mock_validate.side_effect = ValueError("Invalid graph")
164+
result = extract_metadata_from_image(mock_image, None, None, None, mock_logger)
165+
166+
assert result.invokeai_metadata == valid_metadata
167+
assert result.invokeai_workflow == valid_workflow
168+
assert result.invokeai_graph is None
169+
170+
171+
def test_with_overrides(mock_logger, valid_metadata, valid_workflow, valid_graph):
172+
# Different values in the image
173+
mock_image = MagicMock(spec=Image.Image)
174+
175+
# When overrides are provided, they should be used instead of the values in the image, we shouldn'teven try
176+
# to parse the values in the image
177+
mock_image.info = {
178+
"invokeai_metadata": 12345,
179+
"invokeai_workflow": 12345,
180+
"invokeai_graph": 12345,
181+
}
182+
183+
with patch(
184+
"invokeai.app.services.workflow_records.workflow_records_common.WorkflowWithoutIDValidator.validate_json"
185+
):
186+
with patch("invokeai.app.services.shared.graph.Graph.model_validate_json"):
187+
result = extract_metadata_from_image(mock_image, valid_metadata, valid_workflow, valid_graph, mock_logger)
188+
189+
# Override values should be used
190+
assert result.invokeai_metadata == valid_metadata
191+
assert result.invokeai_workflow == valid_workflow
192+
assert result.invokeai_graph == valid_graph
193+
194+
195+
def test_with_no_metadata(mock_logger):
196+
# Image with no metadata
197+
mock_image = MagicMock(spec=Image.Image)
198+
mock_image.info = {}
199+
200+
result = extract_metadata_from_image(mock_image, None, None, None, mock_logger)
201+
202+
assert result.invokeai_metadata is None
203+
assert result.invokeai_workflow is None
204+
assert result.invokeai_graph is None

0 commit comments

Comments
 (0)