petter2025 commited on
Commit
b211251
·
verified ·
1 Parent(s): 667dbb5

Create test_input_validation.py

Browse files
Files changed (1) hide show
  1. tests/test_input_validation.py +316 -0
tests/test_input_validation.py ADDED
@@ -0,0 +1,316 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Unit tests for input validation functions
3
+ """
4
+
5
+ import pytest
6
+ from app import validate_inputs, validate_component_id
7
+
8
+
9
+ class TestComponentIDValidation:
10
+ """Test component ID validation"""
11
+
12
+ def test_valid_component_ids(self):
13
+ """Test that valid component IDs pass validation"""
14
+ valid_ids = [
15
+ "api-service",
16
+ "auth-service",
17
+ "payment-service-v2",
18
+ "db-01",
19
+ "cache",
20
+ "a", # Single character
21
+ "api-gateway-prod-001",
22
+ ]
23
+
24
+ for component_id in valid_ids:
25
+ is_valid, msg = validate_component_id(component_id)
26
+ assert is_valid is True, f"'{component_id}' should be valid but got: {msg}"
27
+ assert msg == ""
28
+
29
+ def test_invalid_uppercase(self):
30
+ """Test that uppercase letters are rejected"""
31
+ invalid_ids = ["API-SERVICE", "Auth-Service", "PaymentService"]
32
+
33
+ for component_id in invalid_ids:
34
+ is_valid, msg = validate_component_id(component_id)
35
+ assert is_valid is False
36
+ assert "lowercase" in msg.lower()
37
+
38
+ def test_invalid_underscore(self):
39
+ """Test that underscores are rejected"""
40
+ is_valid, msg = validate_component_id("api_service")
41
+ assert is_valid is False
42
+ assert "lowercase" in msg.lower() or "hyphen" in msg.lower()
43
+
44
+ def test_invalid_special_characters(self):
45
+ """Test that special characters are rejected"""
46
+ invalid_ids = [
47
+ "api@service",
48
+ "api.service",
49
+ "api service", # Space
50
+ "api/service",
51
+ "api&service",
52
+ ]
53
+
54
+ for component_id in invalid_ids:
55
+ is_valid, msg = validate_component_id(component_id)
56
+ assert is_valid is False, f"'{component_id}' should be invalid"
57
+
58
+ def test_empty_string(self):
59
+ """Test that empty string is rejected"""
60
+ is_valid, msg = validate_component_id("")
61
+ assert is_valid is False
62
+ assert "1-255" in msg or "character" in msg.lower()
63
+
64
+ def test_too_long(self):
65
+ """Test that component IDs longer than 255 chars are rejected"""
66
+ long_id = "a" * 256
67
+ is_valid, msg = validate_component_id(long_id)
68
+ assert is_valid is False
69
+ assert "255" in msg
70
+
71
+ def test_non_string_type(self):
72
+ """Test that non-string types are rejected"""
73
+ is_valid, msg = validate_component_id(123)
74
+ assert is_valid is False
75
+ assert "string" in msg.lower()
76
+
77
+
78
+ class TestNumericInputValidation:
79
+ """Test numeric input validation"""
80
+
81
+ def test_valid_inputs(self):
82
+ """Test that valid inputs pass validation"""
83
+ is_valid, msg = validate_inputs(
84
+ latency=150.0,
85
+ error_rate=0.05,
86
+ throughput=1000.0,
87
+ cpu_util=0.7,
88
+ memory_util=0.6
89
+ )
90
+
91
+ assert is_valid is True
92
+ assert msg == ""
93
+
94
+ def test_valid_inputs_with_none_optionals(self):
95
+ """Test that None is valid for optional fields"""
96
+ is_valid, msg = validate_inputs(
97
+ latency=150.0,
98
+ error_rate=0.05,
99
+ throughput=1000.0,
100
+ cpu_util=None,
101
+ memory_util=None
102
+ )
103
+
104
+ assert is_valid is True
105
+ assert msg == ""
106
+
107
+
108
+ class TestLatencyValidation:
109
+ """Test latency validation"""
110
+
111
+ def test_valid_latency(self):
112
+ """Test valid latency values"""
113
+ valid_values = [0, 1, 100, 500, 1000, 9999]
114
+
115
+ for latency in valid_values:
116
+ is_valid, msg = validate_inputs(latency, 0.05, 1000, None, None)
117
+ assert is_valid is True, f"Latency {latency} should be valid"
118
+
119
+ def test_negative_latency(self):
120
+ """Test that negative latency is rejected"""
121
+ is_valid, msg = validate_inputs(-10, 0.05, 1000, None, None)
122
+ assert is_valid is False
123
+ assert "latency" in msg.lower()
124
+
125
+ def test_excessive_latency(self):
126
+ """Test that excessive latency is rejected"""
127
+ is_valid, msg = validate_inputs(20000, 0.05, 1000, None, None)
128
+ assert is_valid is False
129
+ assert "latency" in msg.lower()
130
+
131
+ def test_non_numeric_latency(self):
132
+ """Test that non-numeric latency is rejected"""
133
+ is_valid, msg = validate_inputs("invalid", 0.05, 1000, None, None)
134
+ assert is_valid is False
135
+ assert "latency" in msg.lower()
136
+
137
+
138
+ class TestErrorRateValidation:
139
+ """Test error rate validation"""
140
+
141
+ def test_valid_error_rates(self):
142
+ """Test valid error rate values"""
143
+ valid_values = [0, 0.01, 0.05, 0.5, 0.99, 1.0]
144
+
145
+ for error_rate in valid_values:
146
+ is_valid, msg = validate_inputs(100, error_rate, 1000, None, None)
147
+ assert is_valid is True, f"Error rate {error_rate} should be valid"
148
+
149
+ def test_negative_error_rate(self):
150
+ """Test that negative error rate is rejected"""
151
+ is_valid, msg = validate_inputs(100, -0.1, 1000, None, None)
152
+ assert is_valid is False
153
+ assert "error rate" in msg.lower()
154
+
155
+ def test_error_rate_exceeds_one(self):
156
+ """Test that error rate > 1 is rejected"""
157
+ is_valid, msg = validate_inputs(100, 1.5, 1000, None, None)
158
+ assert is_valid is False
159
+ assert "error rate" in msg.lower()
160
+
161
+ def test_non_numeric_error_rate(self):
162
+ """Test that non-numeric error rate is rejected"""
163
+ is_valid, msg = validate_inputs(100, "high", 1000, None, None)
164
+ assert is_valid is False
165
+ assert "error rate" in msg.lower()
166
+
167
+
168
+ class TestThroughputValidation:
169
+ """Test throughput validation"""
170
+
171
+ def test_valid_throughput(self):
172
+ """Test valid throughput values"""
173
+ valid_values = [0, 1, 100, 1000, 10000]
174
+
175
+ for throughput in valid_values:
176
+ is_valid, msg = validate_inputs(100, 0.05, throughput, None, None)
177
+ assert is_valid is True, f"Throughput {throughput} should be valid"
178
+
179
+ def test_negative_throughput(self):
180
+ """Test that negative throughput is rejected"""
181
+ is_valid, msg = validate_inputs(100, 0.05, -500, None, None)
182
+ assert is_valid is False
183
+ assert "throughput" in msg.lower()
184
+
185
+ def test_non_numeric_throughput(self):
186
+ """Test that non-numeric throughput is rejected"""
187
+ is_valid, msg = validate_inputs(100, 0.05, "many", None, None)
188
+ assert is_valid is False
189
+ assert "throughput" in msg.lower()
190
+
191
+
192
+ class TestCPUUtilizationValidation:
193
+ """Test CPU utilization validation"""
194
+
195
+ def test_valid_cpu_util(self):
196
+ """Test valid CPU utilization values"""
197
+ valid_values = [0, 0.1, 0.5, 0.85, 1.0]
198
+
199
+ for cpu_util in valid_values:
200
+ is_valid, msg = validate_inputs(100, 0.05, 1000, cpu_util, None)
201
+ assert is_valid is True, f"CPU util {cpu_util} should be valid"
202
+
203
+ def test_negative_cpu_util(self):
204
+ """Test that negative CPU utilization is rejected"""
205
+ is_valid, msg = validate_inputs(100, 0.05, 1000, -0.1, None)
206
+ assert is_valid is False
207
+ assert "cpu" in msg.lower()
208
+
209
+ def test_cpu_util_exceeds_one(self):
210
+ """Test that CPU utilization > 1 is rejected"""
211
+ is_valid, msg = validate_inputs(100, 0.05, 1000, 1.5, None)
212
+ assert is_valid is False
213
+ assert "cpu" in msg.lower()
214
+
215
+ def test_non_numeric_cpu_util(self):
216
+ """Test that non-numeric CPU utilization is rejected"""
217
+ is_valid, msg = validate_inputs(100, 0.05, 1000, "high", None)
218
+ assert is_valid is False
219
+ assert "cpu" in msg.lower()
220
+
221
+
222
+ class TestMemoryUtilizationValidation:
223
+ """Test memory utilization validation"""
224
+
225
+ def test_valid_memory_util(self):
226
+ """Test valid memory utilization values"""
227
+ valid_values = [0, 0.1, 0.5, 0.85, 1.0]
228
+
229
+ for memory_util in valid_values:
230
+ is_valid, msg = validate_inputs(100, 0.05, 1000, None, memory_util)
231
+ assert is_valid is True, f"Memory util {memory_util} should be valid"
232
+
233
+ def test_negative_memory_util(self):
234
+ """Test that negative memory utilization is rejected"""
235
+ is_valid, msg = validate_inputs(100, 0.05, 1000, None, -0.1)
236
+ assert is_valid is False
237
+ assert "memory" in msg.lower()
238
+
239
+ def test_memory_util_exceeds_one(self):
240
+ """Test that memory utilization > 1 is rejected"""
241
+ is_valid, msg = validate_inputs(100, 0.05, 1000, None, 1.5)
242
+ assert is_valid is False
243
+ assert "memory" in msg.lower()
244
+
245
+ def test_non_numeric_memory_util(self):
246
+ """Test that non-numeric memory utilization is rejected"""
247
+ is_valid, msg = validate_inputs(100, 0.05, 1000, None, "full")
248
+ assert is_valid is False
249
+ assert "memory" in msg.lower()
250
+
251
+
252
+ class TestEdgeCases:
253
+ """Test edge cases and boundary conditions"""
254
+
255
+ def test_zero_values(self):
256
+ """Test that zero is valid for all metrics"""
257
+ is_valid, msg = validate_inputs(0, 0, 0, 0, 0)
258
+ assert is_valid is True
259
+
260
+ def test_maximum_values(self):
261
+ """Test maximum boundary values"""
262
+ is_valid, msg = validate_inputs(10000, 1.0, 999999, 1.0, 1.0)
263
+ assert is_valid is True
264
+
265
+ def test_float_precision(self):
266
+ """Test that high-precision floats are handled"""
267
+ is_valid, msg = validate_inputs(
268
+ latency=123.456789,
269
+ error_rate=0.123456,
270
+ throughput=1234.56,
271
+ cpu_util=0.87654321,
272
+ memory_util=0.76543210
273
+ )
274
+ assert is_valid is True
275
+
276
+ def test_integer_inputs(self):
277
+ """Test that integer inputs are accepted"""
278
+ is_valid, msg = validate_inputs(100, 0, 1000, 1, 1)
279
+ assert is_valid is True
280
+
281
+ def test_string_numbers(self):
282
+ """Test that string numbers are converted"""
283
+ is_valid, msg = validate_inputs("100", "0.05", "1000", "0.7", "0.6")
284
+ assert is_valid is True
285
+
286
+
287
+ class TestErrorMessages:
288
+ """Test that error messages are helpful"""
289
+
290
+ def test_error_message_contains_field_name(self):
291
+ """Test that error messages identify the problematic field"""
292
+ # Latency error
293
+ is_valid, msg = validate_inputs(-10, 0.05, 1000, None, None)
294
+ assert "latency" in msg.lower()
295
+
296
+ # Error rate error
297
+ is_valid, msg = validate_inputs(100, 2.0, 1000, None, None)
298
+ assert "error rate" in msg.lower()
299
+
300
+ # Throughput error
301
+ is_valid, msg = validate_inputs(100, 0.05, -100, None, None)
302
+ assert "throughput" in msg.lower()
303
+
304
+ def test_error_message_has_emoji(self):
305
+ """Test that error messages include emoji for visibility"""
306
+ is_valid, msg = validate_inputs(-10, 0.05, 1000, None, None)
307
+ assert "❌" in msg
308
+
309
+ def test_error_message_provides_guidance(self):
310
+ """Test that error messages provide guidance"""
311
+ is_valid, msg = validate_inputs(-10, 0.05, 1000, None, None)
312
+ assert "between" in msg.lower() or "range" in msg.lower() or "0-10000" in msg
313
+
314
+
315
+ if __name__ == "__main__":
316
+ pytest.main([__file__, "-v", "--tb=short"])