cornflow 1.1.2__py3-none-any.whl → 1.1.5a1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cornflow/app.py +8 -0
- cornflow/config.py +43 -5
- cornflow/endpoints/login.py +86 -35
- cornflow/schemas/user.py +18 -2
- cornflow/shared/authentication/auth.py +10 -4
- cornflow/shared/exceptions.py +9 -8
- cornflow/tests/custom_test_case.py +342 -0
- cornflow/tests/unit/test_actions.py +46 -1
- cornflow/tests/unit/test_alarms.py +57 -9
- cornflow/tests/unit/test_apiview.py +45 -1
- cornflow/tests/unit/test_application.py +60 -0
- cornflow/tests/unit/test_cases.py +483 -5
- cornflow/tests/unit/test_cli.py +233 -0
- cornflow/tests/unit/test_commands.py +230 -2
- cornflow/tests/unit/test_dags.py +139 -11
- cornflow/tests/unit/test_data_checks.py +134 -2
- cornflow/tests/unit/test_log_in.py +481 -3
- {cornflow-1.1.2.dist-info → cornflow-1.1.5a1.dist-info}/METADATA +23 -19
- {cornflow-1.1.2.dist-info → cornflow-1.1.5a1.dist-info}/RECORD +22 -21
- {cornflow-1.1.2.dist-info → cornflow-1.1.5a1.dist-info}/WHEEL +1 -1
- {cornflow-1.1.2.dist-info → cornflow-1.1.5a1.dist-info}/entry_points.txt +0 -1
- {cornflow-1.1.2.dist-info → cornflow-1.1.5a1.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,34 @@
|
|
1
1
|
"""
|
2
|
-
Unit
|
2
|
+
Unit tests for the cases models and endpoints.
|
3
|
+
|
4
|
+
This module contains tests for the cases functionality, including:
|
5
|
+
- Case model operations and relationships
|
6
|
+
- Case API endpoints
|
7
|
+
- Case data manipulation and validation
|
8
|
+
- Case tree structure management
|
9
|
+
|
10
|
+
Classes
|
11
|
+
-------
|
12
|
+
TestCasesModels
|
13
|
+
Tests for the case model functionality and relationships
|
14
|
+
TestCasesFromInstanceExecutionEndpoint
|
15
|
+
Tests for creating cases from instances and executions
|
16
|
+
TestCasesRawDataEndpoint
|
17
|
+
Tests for handling raw case data
|
18
|
+
TestCaseCopyEndpoint
|
19
|
+
Tests for case copying functionality
|
20
|
+
TestCaseListEndpoint
|
21
|
+
Tests for case listing functionality
|
22
|
+
TestCaseDetailEndpoint
|
23
|
+
Tests for case detail operations
|
24
|
+
TestCaseToInstanceEndpoint
|
25
|
+
Tests for converting cases to instances
|
26
|
+
TestCaseJsonPatch
|
27
|
+
Tests for JSON patch operations on cases
|
28
|
+
TestCaseDataEndpoint
|
29
|
+
Tests for case data operations
|
30
|
+
TestCaseCompare
|
31
|
+
Tests for case comparison functionality
|
3
32
|
"""
|
4
33
|
|
5
34
|
# Import from libraries
|
@@ -33,7 +62,24 @@ from cornflow.tests.custom_test_case import CustomTestCase, BaseTestCases
|
|
33
62
|
|
34
63
|
|
35
64
|
class TestCasesModels(CustomTestCase):
|
65
|
+
"""
|
66
|
+
Test cases for the case model functionality.
|
67
|
+
|
68
|
+
This class tests the core case model operations including:
|
69
|
+
- Case creation and relationships
|
70
|
+
- Case tree structure management
|
71
|
+
- Case deletion and cascading effects
|
72
|
+
"""
|
73
|
+
|
36
74
|
def setUp(self):
|
75
|
+
"""
|
76
|
+
Set up test environment before each test.
|
77
|
+
|
78
|
+
Initializes test data including:
|
79
|
+
- Base test case setup
|
80
|
+
- Test case data and relationships
|
81
|
+
- Case tree structure
|
82
|
+
"""
|
37
83
|
super().setUp()
|
38
84
|
|
39
85
|
def load_file(_file):
|
@@ -53,6 +99,13 @@ class TestCasesModels(CustomTestCase):
|
|
53
99
|
node.save()
|
54
100
|
|
55
101
|
def test_new_case(self):
|
102
|
+
"""
|
103
|
+
Test creating new cases with parent-child relationships.
|
104
|
+
|
105
|
+
Verifies:
|
106
|
+
- Correct path generation for cases
|
107
|
+
- Proper parent-child relationships
|
108
|
+
"""
|
56
109
|
user = UserModel.get_one_user(self.user)
|
57
110
|
case = CaseModel.get_one_object(user=user, idx=6)
|
58
111
|
self.assertEqual(case.path, "1/3/")
|
@@ -60,6 +113,13 @@ class TestCasesModels(CustomTestCase):
|
|
60
113
|
self.assertEqual(case.path, "1/7/")
|
61
114
|
|
62
115
|
def test_move_case(self):
|
116
|
+
"""
|
117
|
+
Test moving cases within the case tree.
|
118
|
+
|
119
|
+
Verifies:
|
120
|
+
- Cases can be moved to new parents
|
121
|
+
- Path updates correctly after move
|
122
|
+
"""
|
63
123
|
user = UserModel.get_one_user(self.user)
|
64
124
|
case6 = CaseModel.get_one_object(user=user, idx=6)
|
65
125
|
case11 = CaseModel.get_one_object(user=user, idx=11)
|
@@ -67,6 +127,14 @@ class TestCasesModels(CustomTestCase):
|
|
67
127
|
self.assertEqual(case6.path, "1/7/11/")
|
68
128
|
|
69
129
|
def test_move_case2(self):
|
130
|
+
"""
|
131
|
+
Test complex case movement scenarios.
|
132
|
+
|
133
|
+
Verifies:
|
134
|
+
- Multiple case movements
|
135
|
+
- Nested path updates
|
136
|
+
- Path integrity after moves
|
137
|
+
"""
|
70
138
|
user = UserModel.get_one_user(self.user)
|
71
139
|
case3 = CaseModel.get_one_object(user=user, idx=3)
|
72
140
|
case11 = CaseModel.get_one_object(user=user, idx=11)
|
@@ -77,6 +145,13 @@ class TestCasesModels(CustomTestCase):
|
|
77
145
|
self.assertEqual(case10.path, "1/7/11/3/9/")
|
78
146
|
|
79
147
|
def test_delete_case(self):
|
148
|
+
"""
|
149
|
+
Test case deletion with cascading effects.
|
150
|
+
|
151
|
+
Verifies:
|
152
|
+
- Case deletion removes the case
|
153
|
+
- Child cases are properly handled
|
154
|
+
"""
|
80
155
|
user = UserModel.get_one_user(self.user)
|
81
156
|
case7 = CaseModel.get_one_object(user=user, idx=7)
|
82
157
|
case7.delete()
|
@@ -84,18 +159,49 @@ class TestCasesModels(CustomTestCase):
|
|
84
159
|
self.assertIsNone(case11)
|
85
160
|
|
86
161
|
def test_descendants(self):
|
162
|
+
"""
|
163
|
+
Test retrieval of case descendants.
|
164
|
+
|
165
|
+
Verifies:
|
166
|
+
- Correct counting of descendants
|
167
|
+
- Proper descendant relationships
|
168
|
+
"""
|
87
169
|
user = UserModel.get_one_user(self.user)
|
88
170
|
case7 = CaseModel.get_one_object(user=user, idx=7)
|
89
171
|
self.assertEqual(len(case7.descendants), 4)
|
90
172
|
|
91
173
|
def test_depth(self):
|
174
|
+
"""
|
175
|
+
Test case depth calculation.
|
176
|
+
|
177
|
+
Verifies:
|
178
|
+
- Correct depth calculation in case tree
|
179
|
+
- Proper nesting level determination
|
180
|
+
"""
|
92
181
|
user = UserModel.get_one_user(self.user)
|
93
182
|
case10 = CaseModel.get_one_object(user=user, idx=10)
|
94
183
|
self.assertEqual(case10.depth, 4)
|
95
184
|
|
96
185
|
|
97
186
|
class TestCasesFromInstanceExecutionEndpoint(CustomTestCase):
|
187
|
+
"""
|
188
|
+
Test cases for creating cases from instances and executions.
|
189
|
+
|
190
|
+
This class tests the functionality of:
|
191
|
+
- Creating cases from existing instances
|
192
|
+
- Creating cases from executions
|
193
|
+
- Validating case data from different sources
|
194
|
+
"""
|
195
|
+
|
98
196
|
def setUp(self):
|
197
|
+
"""
|
198
|
+
Set up test environment before each test.
|
199
|
+
|
200
|
+
Initializes:
|
201
|
+
- Test instance and execution data
|
202
|
+
- API endpoints and models
|
203
|
+
- Response validation parameters
|
204
|
+
"""
|
99
205
|
super().setUp()
|
100
206
|
|
101
207
|
payload = self.load_file(INSTANCE_PATH)
|
@@ -137,6 +243,14 @@ class TestCasesFromInstanceExecutionEndpoint(CustomTestCase):
|
|
137
243
|
)
|
138
244
|
|
139
245
|
def test_new_case_execution(self):
|
246
|
+
"""
|
247
|
+
Test creating a new case from an execution.
|
248
|
+
|
249
|
+
Verifies:
|
250
|
+
- Case creation from execution data
|
251
|
+
- Proper data and solution mapping
|
252
|
+
- Correct metadata assignment
|
253
|
+
"""
|
140
254
|
self.payload.pop("instance_id")
|
141
255
|
|
142
256
|
case_id = self.create_new_row(self.url, self.model, self.payload)
|
@@ -159,6 +273,14 @@ class TestCasesFromInstanceExecutionEndpoint(CustomTestCase):
|
|
159
273
|
self.assertEqual(self.payload[key], created_case.json[key])
|
160
274
|
|
161
275
|
def test_new_case_instance(self):
|
276
|
+
"""
|
277
|
+
Test creating a new case from an instance.
|
278
|
+
|
279
|
+
Verifies:
|
280
|
+
- Case creation from instance data
|
281
|
+
- Proper data mapping
|
282
|
+
- Correct handling of missing solution
|
283
|
+
"""
|
162
284
|
self.payload.pop("execution_id")
|
163
285
|
case_id = self.create_new_row(self.url, self.model, self.payload)
|
164
286
|
|
@@ -179,13 +301,35 @@ class TestCasesFromInstanceExecutionEndpoint(CustomTestCase):
|
|
179
301
|
self.assertEqual(self.payload[key], created_case.json[key])
|
180
302
|
|
181
303
|
def test_case_not_created(self):
|
304
|
+
"""
|
305
|
+
Test case creation failure scenarios.
|
306
|
+
|
307
|
+
Verifies proper error handling when case creation fails.
|
308
|
+
"""
|
182
309
|
self.create_new_row(
|
183
310
|
self.url, self.model, self.payload, expected_status=400, check_payload=False
|
184
311
|
)
|
185
312
|
|
186
313
|
|
187
314
|
class TestCasesRawDataEndpoint(CustomTestCase):
|
315
|
+
"""
|
316
|
+
Test cases for handling raw case data operations.
|
317
|
+
|
318
|
+
This class tests the functionality of:
|
319
|
+
- Creating cases with raw data
|
320
|
+
- Handling cases with and without solutions
|
321
|
+
- Managing case parent-child relationships
|
322
|
+
"""
|
323
|
+
|
188
324
|
def setUp(self):
|
325
|
+
"""
|
326
|
+
Set up test environment before each test.
|
327
|
+
|
328
|
+
Initializes:
|
329
|
+
- Test case data
|
330
|
+
- API endpoints
|
331
|
+
- Test model configuration
|
332
|
+
"""
|
189
333
|
super().setUp()
|
190
334
|
self.payload = self.load_file(CASE_PATH)
|
191
335
|
self.url = CASE_URL
|
@@ -193,11 +337,26 @@ class TestCasesRawDataEndpoint(CustomTestCase):
|
|
193
337
|
self.items_to_check = ["name", "description", "schema"]
|
194
338
|
|
195
339
|
def test_new_case(self):
|
340
|
+
"""
|
341
|
+
Test creating a new case with raw data.
|
342
|
+
|
343
|
+
Verifies:
|
344
|
+
- Case creation with complete data
|
345
|
+
- Solution data handling
|
346
|
+
"""
|
196
347
|
self.items_to_check = ["name", "description", "schema", "data", "solution"]
|
197
348
|
self.payload["solution"] = self.payload["data"]
|
198
349
|
self.create_new_row(self.url, self.model, self.payload)
|
199
350
|
|
200
351
|
def test_new_case_without_solution(self):
|
352
|
+
"""
|
353
|
+
Test creating a case without solution data.
|
354
|
+
|
355
|
+
Verifies:
|
356
|
+
- Case creation without solution
|
357
|
+
- Proper handling of missing solution fields
|
358
|
+
- Correct response structure
|
359
|
+
"""
|
201
360
|
self.payload.pop("solution")
|
202
361
|
self.items_to_check = ["name", "description", "schema", "data"]
|
203
362
|
_id = self.create_new_row(self.url, self.model, self.payload)
|
@@ -228,6 +387,14 @@ class TestCasesRawDataEndpoint(CustomTestCase):
|
|
228
387
|
self.assertIsNone(data["solution"])
|
229
388
|
|
230
389
|
def test_case_with_parent(self):
|
390
|
+
"""
|
391
|
+
Test creating cases with parent-child relationships.
|
392
|
+
|
393
|
+
Verifies:
|
394
|
+
- Case creation with parent reference
|
395
|
+
- Proper path generation
|
396
|
+
- Correct relationship establishment
|
397
|
+
"""
|
231
398
|
payload = dict(self.payload)
|
232
399
|
payload.pop("data")
|
233
400
|
case_id = self.create_new_row(self.url, self.model, payload)
|
@@ -244,6 +411,11 @@ class TestCasesRawDataEndpoint(CustomTestCase):
|
|
244
411
|
self.assertEqual(len(diff), 0)
|
245
412
|
|
246
413
|
def test_case_with_bad_parent(self):
|
414
|
+
"""
|
415
|
+
Test case creation with invalid parent reference.
|
416
|
+
|
417
|
+
Verifies proper error handling for non-existent parent cases.
|
418
|
+
"""
|
247
419
|
payload = dict(self.payload)
|
248
420
|
payload["parent_id"] = 1
|
249
421
|
self.create_new_row(
|
@@ -251,6 +423,11 @@ class TestCasesRawDataEndpoint(CustomTestCase):
|
|
251
423
|
)
|
252
424
|
|
253
425
|
def test_case_with_case_parent(self):
|
426
|
+
"""
|
427
|
+
Test case creation with invalid parent type.
|
428
|
+
|
429
|
+
Verifies proper error handling when using invalid parent references.
|
430
|
+
"""
|
254
431
|
case_id = self.create_new_row(self.url, self.model, self.payload)
|
255
432
|
payload = dict(self.payload)
|
256
433
|
payload["parent_id"] = case_id
|
@@ -260,7 +437,24 @@ class TestCasesRawDataEndpoint(CustomTestCase):
|
|
260
437
|
|
261
438
|
|
262
439
|
class TestCaseCopyEndpoint(CustomTestCase):
|
440
|
+
"""
|
441
|
+
Test cases for case copying functionality.
|
442
|
+
|
443
|
+
This class tests the functionality of:
|
444
|
+
- Copying existing cases
|
445
|
+
- Validating copied case data
|
446
|
+
- Handling metadata in copied cases
|
447
|
+
"""
|
448
|
+
|
263
449
|
def setUp(self):
|
450
|
+
"""
|
451
|
+
Set up test environment before each test.
|
452
|
+
|
453
|
+
Initializes:
|
454
|
+
- Source case data
|
455
|
+
- Copy operation parameters
|
456
|
+
- Validation fields
|
457
|
+
"""
|
264
458
|
super().setUp()
|
265
459
|
payload = self.load_file(CASE_PATH)
|
266
460
|
self.model = CaseModel
|
@@ -283,6 +477,14 @@ class TestCaseCopyEndpoint(CustomTestCase):
|
|
283
477
|
self.new_items = ["created_at", "updated_at"]
|
284
478
|
|
285
479
|
def test_copy_case(self):
|
480
|
+
"""
|
481
|
+
Test copying a case.
|
482
|
+
|
483
|
+
Verifies:
|
484
|
+
- Successful case duplication
|
485
|
+
- Correct copying of case attributes
|
486
|
+
- Proper handling of modified and new attributes
|
487
|
+
"""
|
286
488
|
new_case = self.create_new_row(
|
287
489
|
self.url + str(self.case_id) + "/copy/", self.model, {}, check_payload=False
|
288
490
|
)
|
@@ -305,7 +507,24 @@ class TestCaseCopyEndpoint(CustomTestCase):
|
|
305
507
|
|
306
508
|
|
307
509
|
class TestCaseListEndpoint(BaseTestCases.ListFilters):
|
510
|
+
"""
|
511
|
+
Test cases for case listing functionality.
|
512
|
+
|
513
|
+
This class tests the functionality of:
|
514
|
+
- Retrieving case listings
|
515
|
+
- Applying filters to case lists
|
516
|
+
- Validating case list responses
|
517
|
+
"""
|
518
|
+
|
308
519
|
def setUp(self):
|
520
|
+
"""
|
521
|
+
Set up test environment before each test.
|
522
|
+
|
523
|
+
Initializes:
|
524
|
+
- Test case data
|
525
|
+
- List operation parameters
|
526
|
+
- Response validation fields
|
527
|
+
"""
|
309
528
|
super().setUp()
|
310
529
|
self.payload = self.load_file(CASE_PATH)
|
311
530
|
self.payloads = [self.load_file(f) for f in CASES_LIST]
|
@@ -314,6 +533,14 @@ class TestCaseListEndpoint(BaseTestCases.ListFilters):
|
|
314
533
|
self.url = CASE_URL
|
315
534
|
|
316
535
|
def test_get_rows(self):
|
536
|
+
"""
|
537
|
+
Test retrieving multiple cases.
|
538
|
+
|
539
|
+
Verifies:
|
540
|
+
- Successful retrieval of case listings
|
541
|
+
- Proper response structure
|
542
|
+
- Correct field validation
|
543
|
+
"""
|
317
544
|
keys_to_check = [
|
318
545
|
"data_hash",
|
319
546
|
"created_at",
|
@@ -332,7 +559,24 @@ class TestCaseListEndpoint(BaseTestCases.ListFilters):
|
|
332
559
|
|
333
560
|
|
334
561
|
class TestCaseDetailEndpoint(BaseTestCases.DetailEndpoint):
|
562
|
+
"""
|
563
|
+
Test cases for case detail operations.
|
564
|
+
|
565
|
+
This class tests the functionality of:
|
566
|
+
- Retrieving individual case details
|
567
|
+
- Updating case information
|
568
|
+
- Handling case deletion
|
569
|
+
"""
|
570
|
+
|
335
571
|
def setUp(self):
|
572
|
+
"""
|
573
|
+
Set up test environment before each test.
|
574
|
+
|
575
|
+
Initializes:
|
576
|
+
- Test case data
|
577
|
+
- Detail operation parameters
|
578
|
+
- Response validation fields
|
579
|
+
"""
|
336
580
|
super().setUp()
|
337
581
|
self.payload = self.load_file(CASE_PATH)
|
338
582
|
self.model = CaseModel
|
@@ -360,6 +604,14 @@ class TestCaseDetailEndpoint(BaseTestCases.DetailEndpoint):
|
|
360
604
|
self.url = CASE_URL
|
361
605
|
|
362
606
|
def test_delete_children(self):
|
607
|
+
"""
|
608
|
+
Test case deletion with child cases.
|
609
|
+
|
610
|
+
Verifies:
|
611
|
+
- Successful deletion of parent case
|
612
|
+
- Proper handling of child cases
|
613
|
+
- Cascade deletion behavior
|
614
|
+
"""
|
363
615
|
payload = dict(self.payload)
|
364
616
|
payload.pop("data")
|
365
617
|
case_id = self.create_new_row(self.url, self.model, payload)
|
@@ -376,7 +628,24 @@ class TestCaseDetailEndpoint(BaseTestCases.DetailEndpoint):
|
|
376
628
|
|
377
629
|
|
378
630
|
class TestCaseToInstanceEndpoint(CustomTestCase):
|
631
|
+
"""
|
632
|
+
Test cases for converting cases to instances.
|
633
|
+
|
634
|
+
This class tests the functionality of:
|
635
|
+
- Converting cases to instances
|
636
|
+
- Validating converted instance data
|
637
|
+
- Handling conversion errors
|
638
|
+
"""
|
639
|
+
|
379
640
|
def setUp(self):
|
641
|
+
"""
|
642
|
+
Set up test environment before each test.
|
643
|
+
|
644
|
+
Initializes:
|
645
|
+
- Test case data
|
646
|
+
- Conversion parameters
|
647
|
+
- Response validation fields
|
648
|
+
"""
|
380
649
|
super().setUp()
|
381
650
|
self.payload = self.load_file(CASE_PATH)
|
382
651
|
self.model = CaseModel
|
@@ -393,6 +662,14 @@ class TestCaseToInstanceEndpoint(CustomTestCase):
|
|
393
662
|
}
|
394
663
|
|
395
664
|
def test_case_to_new_instance(self):
|
665
|
+
"""
|
666
|
+
Test converting a case to a new instance.
|
667
|
+
|
668
|
+
Verifies:
|
669
|
+
- Successful case to instance conversion
|
670
|
+
- Proper data mapping
|
671
|
+
- Correct response structure
|
672
|
+
"""
|
396
673
|
response = self.client.post(
|
397
674
|
CASE_URL + str(self.case_id) + "/instance/",
|
398
675
|
follow_redirects=True,
|
@@ -413,8 +690,8 @@ class TestCaseToInstanceEndpoint(CustomTestCase):
|
|
413
690
|
result = self.get_one_row(
|
414
691
|
INSTANCE_URL + payload["id"] + "/", payload, keys_to_check=keys_to_check
|
415
692
|
)
|
416
|
-
|
417
|
-
self.assertEqual(len(
|
693
|
+
diff = self.response_items.symmetric_difference(result.keys())
|
694
|
+
self.assertEqual(len(diff), 0)
|
418
695
|
|
419
696
|
self.items_to_check = [
|
420
697
|
"id",
|
@@ -450,6 +727,11 @@ class TestCaseToInstanceEndpoint(CustomTestCase):
|
|
450
727
|
self.assertEqual(len(dif), 0)
|
451
728
|
|
452
729
|
def test_case_does_not_exist(self):
|
730
|
+
"""
|
731
|
+
Test conversion of non-existent case.
|
732
|
+
|
733
|
+
Verifies proper error handling when converting non-existent cases.
|
734
|
+
"""
|
453
735
|
response = self.client.post(
|
454
736
|
CASE_URL + str(2) + "/instance/",
|
455
737
|
follow_redirects=True,
|
@@ -460,7 +742,24 @@ class TestCaseToInstanceEndpoint(CustomTestCase):
|
|
460
742
|
|
461
743
|
|
462
744
|
class TestCaseJsonPatch(CustomTestCase):
|
745
|
+
"""
|
746
|
+
Test cases for JSON patch operations on cases.
|
747
|
+
|
748
|
+
This class tests the functionality of:
|
749
|
+
- Applying JSON patches to cases
|
750
|
+
- Validating patched case data
|
751
|
+
- Handling patch errors
|
752
|
+
"""
|
753
|
+
|
463
754
|
def setUp(self):
|
755
|
+
"""
|
756
|
+
Set up test environment before each test.
|
757
|
+
|
758
|
+
Initializes:
|
759
|
+
- Test case data
|
760
|
+
- Patch operation parameters
|
761
|
+
- Test payloads
|
762
|
+
"""
|
464
763
|
super().setUp()
|
465
764
|
self.payload = self.load_file(CASE_PATH)
|
466
765
|
self.model = CaseModel
|
@@ -476,6 +775,14 @@ class TestCaseJsonPatch(CustomTestCase):
|
|
476
775
|
self.patch_file = self.load_file(JSON_PATCH_GOOD_PATH)
|
477
776
|
|
478
777
|
def test_json_patch(self):
|
778
|
+
"""
|
779
|
+
Test applying a JSON patch to a case.
|
780
|
+
|
781
|
+
Verifies:
|
782
|
+
- Successful patch application
|
783
|
+
- Correct data transformation
|
784
|
+
- Proper validation of patched data
|
785
|
+
"""
|
479
786
|
self.patch_row(
|
480
787
|
self.url + str(self.case_id) + "/data/",
|
481
788
|
self.patch,
|
@@ -490,6 +797,14 @@ class TestCaseJsonPatch(CustomTestCase):
|
|
490
797
|
self.assertIsNone(row.json["checks"])
|
491
798
|
|
492
799
|
def test_json_patch_complete(self):
|
800
|
+
"""
|
801
|
+
Test applying a complete JSON patch.
|
802
|
+
|
803
|
+
Verifies:
|
804
|
+
- Complex patch operations
|
805
|
+
- Data and solution patching
|
806
|
+
- Response validation
|
807
|
+
"""
|
493
808
|
original = self.load_file(FULL_CASE_LIST[0])
|
494
809
|
original["data"] = get_pulp_jsonschema("../tests/data/gc_input.json")
|
495
810
|
original["solution"] = get_pulp_jsonschema("../tests/data/gc_output.json")
|
@@ -513,6 +828,11 @@ class TestCaseJsonPatch(CustomTestCase):
|
|
513
828
|
self.assertIsNone(row.json["solution_checks"])
|
514
829
|
|
515
830
|
def test_json_patch_file(self):
|
831
|
+
"""
|
832
|
+
Test applying a JSON patch from a file.
|
833
|
+
|
834
|
+
Verifies successful patch application from file source.
|
835
|
+
"""
|
516
836
|
self.patch_row(
|
517
837
|
self.url + str(self.case_id) + "/data/",
|
518
838
|
self.patch_file,
|
@@ -520,6 +840,11 @@ class TestCaseJsonPatch(CustomTestCase):
|
|
520
840
|
)
|
521
841
|
|
522
842
|
def test_not_valid_json_patch(self):
|
843
|
+
"""
|
844
|
+
Test handling of invalid JSON patches.
|
845
|
+
|
846
|
+
Verifies proper error handling for malformed patches.
|
847
|
+
"""
|
523
848
|
payload = {"patch": "Not a valid patch"}
|
524
849
|
self.patch_row(
|
525
850
|
self.url + str(self.case_id) + "/data/",
|
@@ -530,6 +855,11 @@ class TestCaseJsonPatch(CustomTestCase):
|
|
530
855
|
)
|
531
856
|
|
532
857
|
def test_not_valid_json_patch_2(self):
|
858
|
+
"""
|
859
|
+
Test handling of invalid JSON patch structure.
|
860
|
+
|
861
|
+
Verifies proper error handling for patches with invalid structure.
|
862
|
+
"""
|
533
863
|
payload = {"some_key": "some_value"}
|
534
864
|
self.patch_row(
|
535
865
|
self.url + str(self.case_id) + "/data/",
|
@@ -540,6 +870,11 @@ class TestCaseJsonPatch(CustomTestCase):
|
|
540
870
|
)
|
541
871
|
|
542
872
|
def test_not_valid_json_patch_3(self):
|
873
|
+
"""
|
874
|
+
Test handling of invalid patch operations.
|
875
|
+
|
876
|
+
Verifies proper error handling for invalid patch operations.
|
877
|
+
"""
|
543
878
|
patch = {
|
544
879
|
"patch": jsonpatch.make_patch(self.payloads[0], self.payloads[1]).patch
|
545
880
|
}
|
@@ -552,6 +887,11 @@ class TestCaseJsonPatch(CustomTestCase):
|
|
552
887
|
)
|
553
888
|
|
554
889
|
def test_not_valid_json_patch_4(self):
|
890
|
+
"""
|
891
|
+
Test handling of bad patch file content.
|
892
|
+
|
893
|
+
Verifies proper error handling for invalid patch file content.
|
894
|
+
"""
|
555
895
|
patch = self.load_file(JSON_PATCH_BAD_PATH)
|
556
896
|
self.patch_row(
|
557
897
|
self.url + str(self.case_id) + "/data/",
|
@@ -562,6 +902,11 @@ class TestCaseJsonPatch(CustomTestCase):
|
|
562
902
|
)
|
563
903
|
|
564
904
|
def test_patch_non_existing_case(self):
|
905
|
+
"""
|
906
|
+
Test patching non-existent case.
|
907
|
+
|
908
|
+
Verifies proper error handling when patching non-existent cases.
|
909
|
+
"""
|
565
910
|
self.patch_row(
|
566
911
|
self.url + str(500) + "/data/",
|
567
912
|
self.patch,
|
@@ -571,24 +916,49 @@ class TestCaseJsonPatch(CustomTestCase):
|
|
571
916
|
)
|
572
917
|
|
573
918
|
def test_patch_created_properly(self):
|
919
|
+
"""
|
920
|
+
Test proper patch creation.
|
921
|
+
|
922
|
+
Verifies correct patch generation and structure.
|
923
|
+
"""
|
574
924
|
self.assertEqual(
|
575
925
|
len(self.patch_file["data_patch"]), len(self.patch["data_patch"])
|
576
926
|
)
|
577
927
|
|
578
928
|
def test_patch_not_created_properly(self):
|
579
|
-
|
929
|
+
"""
|
930
|
+
Test improper patch creation scenarios.
|
931
|
+
|
932
|
+
Verifies detection of improperly created patches.
|
933
|
+
"""
|
580
934
|
self.assertNotEqual(
|
581
935
|
len(self.patch_file["data_patch"]),
|
582
936
|
len(jsonpatch.make_patch(self.payloads[0], self.payloads[1]).patch),
|
583
937
|
)
|
584
938
|
|
585
|
-
# Compares the number of operations, not the operations themselves
|
586
939
|
patch = self.load_file(JSON_PATCH_BAD_PATH)
|
587
940
|
self.assertNotEqual(len(patch["data_patch"]), len(self.patch["data_patch"]))
|
588
941
|
|
589
942
|
|
590
943
|
class TestCaseDataEndpoint(CustomTestCase):
|
944
|
+
"""
|
945
|
+
Test cases for case data operations.
|
946
|
+
|
947
|
+
This class tests the functionality of:
|
948
|
+
- Retrieving case data
|
949
|
+
- Handling compressed data
|
950
|
+
- Validating data responses
|
951
|
+
"""
|
952
|
+
|
591
953
|
def setUp(self):
|
954
|
+
"""
|
955
|
+
Set up test environment before each test.
|
956
|
+
|
957
|
+
Initializes:
|
958
|
+
- Test case data
|
959
|
+
- Data operation parameters
|
960
|
+
- Response validation fields
|
961
|
+
"""
|
592
962
|
super().setUp()
|
593
963
|
self.payload = self.load_file(CASE_PATH)
|
594
964
|
self.model = CaseModel
|
@@ -602,6 +972,14 @@ class TestCaseDataEndpoint(CustomTestCase):
|
|
602
972
|
]
|
603
973
|
|
604
974
|
def test_get_data(self):
|
975
|
+
"""
|
976
|
+
Test retrieving case data.
|
977
|
+
|
978
|
+
Verifies:
|
979
|
+
- Successful data retrieval
|
980
|
+
- Proper response structure
|
981
|
+
- Field validation
|
982
|
+
"""
|
605
983
|
keys_to_check = [
|
606
984
|
"data",
|
607
985
|
"solution_checks",
|
@@ -627,6 +1005,11 @@ class TestCaseDataEndpoint(CustomTestCase):
|
|
627
1005
|
)
|
628
1006
|
|
629
1007
|
def test_get_no_data(self):
|
1008
|
+
"""
|
1009
|
+
Test retrieving non-existent case data.
|
1010
|
+
|
1011
|
+
Verifies proper error handling for non-existent cases.
|
1012
|
+
"""
|
630
1013
|
self.get_one_row(
|
631
1014
|
self.url + str(500) + "/data/",
|
632
1015
|
{},
|
@@ -636,6 +1019,14 @@ class TestCaseDataEndpoint(CustomTestCase):
|
|
636
1019
|
)
|
637
1020
|
|
638
1021
|
def test_get_compressed_data(self):
|
1022
|
+
"""
|
1023
|
+
Test retrieving compressed case data.
|
1024
|
+
|
1025
|
+
Verifies:
|
1026
|
+
- Successful compression
|
1027
|
+
- Proper decompression
|
1028
|
+
- Data integrity
|
1029
|
+
"""
|
639
1030
|
headers = self.get_header_with_auth(self.token)
|
640
1031
|
headers["Accept-Encoding"] = "gzip"
|
641
1032
|
|
@@ -650,7 +1041,24 @@ class TestCaseDataEndpoint(CustomTestCase):
|
|
650
1041
|
|
651
1042
|
|
652
1043
|
class TestCaseCompare(CustomTestCase):
|
1044
|
+
"""
|
1045
|
+
Test cases for case comparison functionality.
|
1046
|
+
|
1047
|
+
This class tests the functionality of:
|
1048
|
+
- Comparing different cases
|
1049
|
+
- Generating comparison patches
|
1050
|
+
- Handling comparison errors
|
1051
|
+
"""
|
1052
|
+
|
653
1053
|
def setUp(self):
|
1054
|
+
"""
|
1055
|
+
Set up test environment before each test.
|
1056
|
+
|
1057
|
+
Initializes:
|
1058
|
+
- Test cases for comparison
|
1059
|
+
- Comparison parameters
|
1060
|
+
- Validation fields
|
1061
|
+
"""
|
654
1062
|
super().setUp()
|
655
1063
|
self.payloads = [self.load_file(f) for f in FULL_CASE_LIST]
|
656
1064
|
self.payloads[0]["data"] = get_pulp_jsonschema("../tests/data/gc_input.json")
|
@@ -669,6 +1077,14 @@ class TestCaseCompare(CustomTestCase):
|
|
669
1077
|
self.items_to_check = ["name", "description", "schema"]
|
670
1078
|
|
671
1079
|
def test_get_full_patch(self):
|
1080
|
+
"""
|
1081
|
+
Test generating full comparison patch.
|
1082
|
+
|
1083
|
+
Verifies:
|
1084
|
+
- Successful patch generation
|
1085
|
+
- Correct patch structure
|
1086
|
+
- Proper response format
|
1087
|
+
"""
|
672
1088
|
response = self.client.get(
|
673
1089
|
self.url + str(self.cases_id[0]) + "/" + str(self.cases_id[1]) + "/",
|
674
1090
|
follow_redirects=True,
|
@@ -680,6 +1096,11 @@ class TestCaseCompare(CustomTestCase):
|
|
680
1096
|
self.assertEqual(200, response.status_code)
|
681
1097
|
|
682
1098
|
def test_same_case_error(self):
|
1099
|
+
"""
|
1100
|
+
Test comparing a case with itself.
|
1101
|
+
|
1102
|
+
Verifies proper error handling for self-comparison.
|
1103
|
+
"""
|
683
1104
|
response = self.client.get(
|
684
1105
|
self.url + str(self.cases_id[0]) + "/" + str(self.cases_id[0]) + "/",
|
685
1106
|
follow_redirects=True,
|
@@ -689,6 +1110,14 @@ class TestCaseCompare(CustomTestCase):
|
|
689
1110
|
self.assertEqual(400, response.status_code)
|
690
1111
|
|
691
1112
|
def test_get_only_data(self):
|
1113
|
+
"""
|
1114
|
+
Test comparing only case data.
|
1115
|
+
|
1116
|
+
Verifies:
|
1117
|
+
- Data-only comparison
|
1118
|
+
- Proper exclusion of solution
|
1119
|
+
- Correct response format
|
1120
|
+
"""
|
692
1121
|
response = self.client.get(
|
693
1122
|
self.url
|
694
1123
|
+ str(self.cases_id[0])
|
@@ -705,6 +1134,14 @@ class TestCaseCompare(CustomTestCase):
|
|
705
1134
|
self.assertEqual(200, response.status_code)
|
706
1135
|
|
707
1136
|
def test_get_only_solution(self):
|
1137
|
+
"""
|
1138
|
+
Test comparing only case solutions.
|
1139
|
+
|
1140
|
+
Verifies:
|
1141
|
+
- Solution-only comparison
|
1142
|
+
- Proper exclusion of data
|
1143
|
+
- Correct response format
|
1144
|
+
"""
|
708
1145
|
response = self.client.get(
|
709
1146
|
self.url + str(self.cases_id[0]) + "/" + str(self.cases_id[1]) + "/?data=0",
|
710
1147
|
follow_redirects=True,
|
@@ -717,6 +1154,11 @@ class TestCaseCompare(CustomTestCase):
|
|
717
1154
|
self.assertEqual(200, response.status_code)
|
718
1155
|
|
719
1156
|
def test_patch_not_symmetric(self):
|
1157
|
+
"""
|
1158
|
+
Test patch asymmetry.
|
1159
|
+
|
1160
|
+
Verifies that patches are direction-dependent.
|
1161
|
+
"""
|
720
1162
|
response = self.client.get(
|
721
1163
|
self.url + str(self.cases_id[1]) + "/" + str(self.cases_id[0]) + "/",
|
722
1164
|
follow_redirects=True,
|
@@ -728,6 +1170,11 @@ class TestCaseCompare(CustomTestCase):
|
|
728
1170
|
self.assertEqual(200, response.status_code)
|
729
1171
|
|
730
1172
|
def test_case_does_not_exist(self):
|
1173
|
+
"""
|
1174
|
+
Test comparing with non-existent case.
|
1175
|
+
|
1176
|
+
Verifies proper error handling for non-existent cases.
|
1177
|
+
"""
|
731
1178
|
response = self.client.get(
|
732
1179
|
self.url + str(self.cases_id[0]) + "/" + str(500) + "/",
|
733
1180
|
follow_redirects=True,
|
@@ -745,6 +1192,14 @@ class TestCaseCompare(CustomTestCase):
|
|
745
1192
|
self.assertEqual(404, response.status_code)
|
746
1193
|
|
747
1194
|
def test_get_patch_and_apply(self):
|
1195
|
+
"""
|
1196
|
+
Test generating and applying a patch.
|
1197
|
+
|
1198
|
+
Verifies:
|
1199
|
+
- Patch generation
|
1200
|
+
- Successful patch application
|
1201
|
+
- Data consistency
|
1202
|
+
"""
|
748
1203
|
response = self.client.get(
|
749
1204
|
self.url + str(self.cases_id[0]) + "/" + str(self.cases_id[1]) + "/",
|
750
1205
|
follow_redirects=True,
|
@@ -764,6 +1219,14 @@ class TestCaseCompare(CustomTestCase):
|
|
764
1219
|
)
|
765
1220
|
|
766
1221
|
def test_case_compare_compression(self):
|
1222
|
+
"""
|
1223
|
+
Test case comparison with compression.
|
1224
|
+
|
1225
|
+
Verifies:
|
1226
|
+
- Successful compression
|
1227
|
+
- Proper decompression
|
1228
|
+
- Data integrity
|
1229
|
+
"""
|
767
1230
|
headers = self.get_header_with_auth(self.token)
|
768
1231
|
headers["Accept-Encoding"] = "gzip"
|
769
1232
|
response = self.client.get(
|
@@ -780,6 +1243,11 @@ class TestCaseCompare(CustomTestCase):
|
|
780
1243
|
|
781
1244
|
|
782
1245
|
def modify_data(data):
|
1246
|
+
"""
|
1247
|
+
Modify test case data.
|
1248
|
+
|
1249
|
+
Helper function to modify case data for testing.
|
1250
|
+
"""
|
783
1251
|
data["pairs"][16]["n2"] = 10
|
784
1252
|
data["pairs"][27]["n2"] = 3
|
785
1253
|
data["pairs"][30]["n1"] = 6
|
@@ -790,6 +1258,11 @@ def modify_data(data):
|
|
790
1258
|
|
791
1259
|
|
792
1260
|
def modify_solution(solution):
|
1261
|
+
"""
|
1262
|
+
Modify test case solution.
|
1263
|
+
|
1264
|
+
Helper function to modify case solution for testing.
|
1265
|
+
"""
|
793
1266
|
solution["assignment"][4]["color"] = 3
|
794
1267
|
solution["assignment"][7]["color"] = 2
|
795
1268
|
solution["assignment"][24]["color"] = 1
|
@@ -797,6 +1270,11 @@ def modify_solution(solution):
|
|
797
1270
|
|
798
1271
|
|
799
1272
|
def modify_data_solution(data):
|
1273
|
+
"""
|
1274
|
+
Modify both test case data and solution.
|
1275
|
+
|
1276
|
+
Helper function to modify both case data and solution for testing.
|
1277
|
+
"""
|
800
1278
|
modify_data(data["data"])
|
801
1279
|
modify_solution(data["solution"])
|
802
1280
|
return data
|