MogensR commited on
Commit
b76f5a3
·
1 Parent(s): 3a9b622

Create tests/test_models.py

Browse files
Files changed (1) hide show
  1. tests/test_models.py +349 -0
tests/test_models.py ADDED
@@ -0,0 +1,349 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Tests for the processing pipeline.
3
+ """
4
+
5
+ import pytest
6
+ import numpy as np
7
+ import cv2
8
+ from unittest.mock import Mock, patch, MagicMock
9
+ from pathlib import Path
10
+
11
+ from api.pipeline import (
12
+ ProcessingPipeline,
13
+ PipelineConfig,
14
+ PipelineResult,
15
+ ProcessingMode,
16
+ PipelineStage
17
+ )
18
+
19
+
20
+ class TestPipelineConfig:
21
+ """Test pipeline configuration."""
22
+
23
+ def test_default_config(self):
24
+ """Test default configuration values."""
25
+ config = PipelineConfig()
26
+ assert config.mode == ProcessingMode.PHOTO
27
+ assert config.quality_preset == "high"
28
+ assert config.use_gpu == True
29
+ assert config.enable_cache == True
30
+
31
+ def test_custom_config(self):
32
+ """Test custom configuration."""
33
+ config = PipelineConfig(
34
+ mode=ProcessingMode.VIDEO,
35
+ quality_preset="ultra",
36
+ use_gpu=False,
37
+ batch_size=4
38
+ )
39
+ assert config.mode == ProcessingMode.VIDEO
40
+ assert config.quality_preset == "ultra"
41
+ assert config.use_gpu == False
42
+ assert config.batch_size == 4
43
+
44
+
45
+ class TestProcessingPipeline:
46
+ """Test the main processing pipeline."""
47
+
48
+ @pytest.fixture
49
+ def mock_pipeline(self, pipeline_config):
50
+ """Create a pipeline with mocked components."""
51
+ with patch('api.pipeline.ModelFactory') as mock_factory:
52
+ with patch('api.pipeline.DeviceManager') as mock_device:
53
+ mock_device.return_value.get_device.return_value = 'cpu'
54
+ mock_factory.return_value.load_model.return_value = Mock()
55
+
56
+ pipeline = ProcessingPipeline(pipeline_config)
57
+ return pipeline
58
+
59
+ def test_pipeline_initialization(self, mock_pipeline):
60
+ """Test pipeline initialization."""
61
+ assert mock_pipeline is not None
62
+ assert mock_pipeline.config is not None
63
+ assert mock_pipeline.current_stage == PipelineStage.INITIALIZATION
64
+
65
+ def test_process_image_success(self, mock_pipeline, sample_image, sample_background):
66
+ """Test successful image processing."""
67
+ # Mock the processing methods
68
+ mock_pipeline._segment_image = Mock(return_value=np.ones((512, 512), dtype=np.uint8) * 255)
69
+ mock_pipeline.alpha_matting.process = Mock(return_value={
70
+ 'alpha': np.ones((512, 512), dtype=np.float32),
71
+ 'confidence': 0.95
72
+ })
73
+
74
+ result = mock_pipeline.process_image(sample_image, sample_background)
75
+
76
+ assert result is not None
77
+ assert isinstance(result, PipelineResult)
78
+ assert result.success == True
79
+ assert result.output_image is not None
80
+
81
+ def test_process_image_with_effects(self, mock_pipeline, sample_image):
82
+ """Test image processing with effects."""
83
+ mock_pipeline.config.apply_effects = ['bokeh', 'vignette']
84
+
85
+ # Mock processing
86
+ mock_pipeline._segment_image = Mock(return_value=np.ones((512, 512), dtype=np.uint8) * 255)
87
+ mock_pipeline.alpha_matting.process = Mock(return_value={
88
+ 'alpha': np.ones((512, 512), dtype=np.float32),
89
+ 'confidence': 0.95
90
+ })
91
+
92
+ result = mock_pipeline.process_image(sample_image, None)
93
+
94
+ assert result is not None
95
+ assert result.success == True
96
+
97
+ def test_process_image_failure(self, mock_pipeline, sample_image):
98
+ """Test image processing failure handling."""
99
+ # Mock segmentation to fail
100
+ mock_pipeline._segment_image = Mock(side_effect=Exception("Segmentation failed"))
101
+
102
+ result = mock_pipeline.process_image(sample_image, None)
103
+
104
+ assert result is not None
105
+ assert result.success == False
106
+ assert len(result.errors) > 0
107
+
108
+ @pytest.mark.parametrize("quality", ["low", "medium", "high", "ultra"])
109
+ def test_quality_presets(self, mock_pipeline, sample_image, quality):
110
+ """Test different quality presets."""
111
+ mock_pipeline.config.quality_preset = quality
112
+
113
+ # Mock processing
114
+ mock_pipeline._segment_image = Mock(return_value=np.ones((512, 512), dtype=np.uint8) * 255)
115
+ mock_pipeline.alpha_matting.process = Mock(return_value={
116
+ 'alpha': np.ones((512, 512), dtype=np.float32),
117
+ 'confidence': 0.95
118
+ })
119
+
120
+ result = mock_pipeline.process_image(sample_image, None)
121
+
122
+ assert result is not None
123
+ assert result.success == True
124
+
125
+ def test_batch_processing(self, mock_pipeline, sample_image):
126
+ """Test batch processing of multiple images."""
127
+ images = [sample_image] * 3
128
+
129
+ # Mock processing
130
+ mock_pipeline.process_image = Mock(return_value=PipelineResult(
131
+ success=True,
132
+ output_image=sample_image,
133
+ quality_score=0.9
134
+ ))
135
+
136
+ results = mock_pipeline.process_batch(images)
137
+
138
+ assert len(results) == 3
139
+ assert all(r.success for r in results)
140
+
141
+ def test_progress_callback(self, mock_pipeline, sample_image):
142
+ """Test progress callback functionality."""
143
+ progress_values = []
144
+
145
+ def progress_callback(value, message):
146
+ progress_values.append(value)
147
+
148
+ mock_pipeline.config.progress_callback = progress_callback
149
+
150
+ # Mock processing
151
+ mock_pipeline._segment_image = Mock(return_value=np.ones((512, 512), dtype=np.uint8) * 255)
152
+ mock_pipeline.alpha_matting.process = Mock(return_value={
153
+ 'alpha': np.ones((512, 512), dtype=np.float32),
154
+ 'confidence': 0.95
155
+ })
156
+
157
+ result = mock_pipeline.process_image(sample_image, None)
158
+
159
+ assert len(progress_values) > 0
160
+ assert 0.0 <= max(progress_values) <= 1.0
161
+
162
+ def test_cache_functionality(self, mock_pipeline, sample_image):
163
+ """Test caching functionality."""
164
+ mock_pipeline.config.enable_cache = True
165
+
166
+ # Mock processing
167
+ mock_pipeline._segment_image = Mock(return_value=np.ones((512, 512), dtype=np.uint8) * 255)
168
+ mock_pipeline.alpha_matting.process = Mock(return_value={
169
+ 'alpha': np.ones((512, 512), dtype=np.float32),
170
+ 'confidence': 0.95
171
+ })
172
+
173
+ # First call
174
+ result1 = mock_pipeline.process_image(sample_image, None)
175
+
176
+ # Second call (should use cache)
177
+ result2 = mock_pipeline.process_image(sample_image, None)
178
+
179
+ assert result1.success == result2.success
180
+ # Verify segmentation was only called once (cache hit on second call)
181
+ assert mock_pipeline._segment_image.call_count == 1
182
+
183
+ def test_memory_management(self, mock_pipeline):
184
+ """Test memory management and cleanup."""
185
+ initial_cache_size = len(mock_pipeline.cache)
186
+
187
+ # Process multiple images to fill cache
188
+ for i in range(10):
189
+ image = np.random.randint(0, 255, (512, 512, 3), dtype=np.uint8)
190
+ mock_pipeline.cache[f"test_{i}"] = PipelineResult(success=True)
191
+
192
+ # Clear cache
193
+ mock_pipeline.clear_cache()
194
+
195
+ assert len(mock_pipeline.cache) == 0
196
+
197
+ def test_statistics_tracking(self, mock_pipeline, sample_image):
198
+ """Test statistics tracking."""
199
+ # Mock processing
200
+ mock_pipeline._segment_image = Mock(return_value=np.ones((512, 512), dtype=np.uint8) * 255)
201
+ mock_pipeline.alpha_matting.process = Mock(return_value={
202
+ 'alpha': np.ones((512, 512), dtype=np.float32),
203
+ 'confidence': 0.95
204
+ })
205
+
206
+ # Process image
207
+ result = mock_pipeline.process_image(sample_image, None)
208
+
209
+ # Get statistics
210
+ stats = mock_pipeline.get_statistics()
211
+
212
+ assert 'total_processed' in stats
213
+ assert stats['total_processed'] > 0
214
+ assert 'avg_time' in stats
215
+
216
+
217
+ class TestPipelineIntegration:
218
+ """Integration tests for the pipeline."""
219
+
220
+ @pytest.mark.integration
221
+ @pytest.mark.slow
222
+ def test_end_to_end_processing(self, sample_image, sample_background, temp_dir):
223
+ """Test end-to-end processing pipeline."""
224
+ config = PipelineConfig(
225
+ use_gpu=False,
226
+ quality_preset="medium",
227
+ enable_cache=False
228
+ )
229
+
230
+ # Create pipeline (will use real components if available)
231
+ try:
232
+ pipeline = ProcessingPipeline(config)
233
+ except Exception:
234
+ pytest.skip("Models not available for integration test")
235
+
236
+ # Process image
237
+ result = pipeline.process_image(sample_image, sample_background)
238
+
239
+ if result.success:
240
+ assert result.output_image is not None
241
+ assert result.output_image.shape == sample_image.shape
242
+ assert result.quality_score > 0
243
+
244
+ # Save output
245
+ output_path = temp_dir / "test_output.png"
246
+ cv2.imwrite(str(output_path), result.output_image)
247
+ assert output_path.exists()
248
+
249
+ @pytest.mark.integration
250
+ @pytest.mark.slow
251
+ def test_video_frame_processing(self, sample_video, temp_dir):
252
+ """Test processing video frames."""
253
+ config = PipelineConfig(
254
+ mode=ProcessingMode.VIDEO,
255
+ use_gpu=False,
256
+ quality_preset="low"
257
+ )
258
+
259
+ try:
260
+ pipeline = ProcessingPipeline(config)
261
+ except Exception:
262
+ pytest.skip("Models not available for integration test")
263
+
264
+ # Open video
265
+ cap = cv2.VideoCapture(sample_video)
266
+ processed_frames = []
267
+
268
+ # Process first 5 frames
269
+ for i in range(5):
270
+ ret, frame = cap.read()
271
+ if not ret:
272
+ break
273
+
274
+ result = pipeline.process_image(frame, None)
275
+ if result.success:
276
+ processed_frames.append(result.output_image)
277
+
278
+ cap.release()
279
+
280
+ assert len(processed_frames) > 0
281
+
282
+ # Save as video
283
+ if processed_frames:
284
+ output_path = temp_dir / "test_video_out.mp4"
285
+ fourcc = cv2.VideoWriter_fourcc(*'mp4v')
286
+ out = cv2.VideoWriter(str(output_path), fourcc, 30.0,
287
+ (processed_frames[0].shape[1], processed_frames[0].shape[0]))
288
+
289
+ for frame in processed_frames:
290
+ out.write(frame)
291
+
292
+ out.release()
293
+ assert output_path.exists()
294
+
295
+
296
+ class TestPipelinePerformance:
297
+ """Performance tests for the pipeline."""
298
+
299
+ @pytest.mark.slow
300
+ def test_processing_speed(self, mock_pipeline, sample_image, performance_timer):
301
+ """Test processing speed."""
302
+ # Mock processing
303
+ mock_pipeline._segment_image = Mock(return_value=np.ones((512, 512), dtype=np.uint8) * 255)
304
+ mock_pipeline.alpha_matting.process = Mock(return_value={
305
+ 'alpha': np.ones((512, 512), dtype=np.float32),
306
+ 'confidence': 0.95
307
+ })
308
+
309
+ with performance_timer as timer:
310
+ result = mock_pipeline.process_image(sample_image, None)
311
+
312
+ assert result.success == True
313
+ assert timer.elapsed < 1.0 # Should process in under 1 second
314
+
315
+ @pytest.mark.slow
316
+ def test_batch_processing_speed(self, mock_pipeline, sample_image, performance_timer):
317
+ """Test batch processing speed."""
318
+ images = [sample_image] * 10
319
+
320
+ # Mock processing
321
+ mock_pipeline.process_image = Mock(return_value=PipelineResult(
322
+ success=True,
323
+ output_image=sample_image,
324
+ quality_score=0.9
325
+ ))
326
+
327
+ with performance_timer as timer:
328
+ results = mock_pipeline.process_batch(images)
329
+
330
+ assert len(results) == 10
331
+ assert timer.elapsed < 5.0 # Should process 10 images in under 5 seconds
332
+
333
+ def test_memory_usage(self, mock_pipeline, sample_image):
334
+ """Test memory usage during processing."""
335
+ import psutil
336
+ import os
337
+
338
+ process = psutil.Process(os.getpid())
339
+ initial_memory = process.memory_info().rss / 1024 / 1024 # MB
340
+
341
+ # Process multiple images
342
+ for _ in range(10):
343
+ mock_pipeline.process_image(sample_image, None)
344
+
345
+ final_memory = process.memory_info().rss / 1024 / 1024 # MB
346
+ memory_increase = final_memory - initial_memory
347
+
348
+ # Memory increase should be reasonable (less than 500MB for 10 images)
349
+ assert memory_increase < 500