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.
@@ -1,3 +1,20 @@
1
+ """
2
+ Unit tests for Cornflow command functionality.
3
+
4
+ This module contains tests for various command operations, including:
5
+
6
+ - User management commands (service, admin, base users)
7
+ - Action registration and management
8
+ - View registration and management
9
+ - Role management
10
+ - Permission assignment and validation
11
+ - DAG deployment and permissions
12
+ - Command argument validation
13
+
14
+ The tests verify both successful operations and error handling
15
+ for various command scenarios and configurations.
16
+ """
17
+
1
18
  import json
2
19
 
3
20
  from flask_testing import TestCase
@@ -37,12 +54,45 @@ from cornflow.tests.integration.test_cornflowclient import load_file
37
54
 
38
55
 
39
56
  class TestCommands(TestCase):
57
+ """
58
+ Test suite for Cornflow command functionality.
59
+
60
+ This class tests various command operations and their effects on the system:
61
+
62
+ - User creation and management commands
63
+ - Action and view registration
64
+ - Role initialization and management
65
+ - Permission system configuration
66
+ - DAG deployment and permissions
67
+ - Command argument validation and error handling
68
+
69
+ Each test method focuses on a specific command or related set of commands,
70
+ verifying both successful execution and proper error handling.
71
+ """
72
+
40
73
  def create_app(self):
74
+ """
75
+ Create and configure the Flask application for testing.
76
+
77
+ :return: The configured Flask application instance with testing configuration
78
+ :rtype: Flask
79
+ """
41
80
  app = create_app("testing")
42
81
  app.config["OPEN_DEPLOYMENT"] = 1
43
82
  return app
44
83
 
45
84
  def setUp(self):
85
+ """
86
+ Set up test environment before each test.
87
+
88
+ Initializes:
89
+
90
+ - Database tables
91
+ - Test user credentials
92
+ - API resources
93
+ - CLI runner
94
+ - Base roles
95
+ """
46
96
  db.create_all()
47
97
  self.payload = {
48
98
  "email": "testemail@test.org",
@@ -53,10 +103,32 @@ class TestCommands(TestCase):
53
103
  self.runner.invoke(register_roles, ["-v"])
54
104
 
55
105
  def tearDown(self):
106
+ """
107
+ Clean up test environment after each test.
108
+
109
+ Removes database session and drops all tables.
110
+ """
56
111
  db.session.remove()
57
112
  db.drop_all()
58
113
 
59
114
  def user_command(self, command, username, email):
115
+ """
116
+ Helper method to test user creation commands.
117
+
118
+ :param command: The user creation command to test
119
+ :type command: function
120
+ :param username: Username for the new user
121
+ :type username: str
122
+ :param email: Email for the new user
123
+ :type email: str
124
+ :return: The created user object
125
+ :rtype: UserModel
126
+
127
+ Verifies:
128
+
129
+ - User creation success
130
+ - Correct user attributes
131
+ """
60
132
  self.runner.invoke(
61
133
  command,
62
134
  ["-u", username, "-e", email, "-p", self.payload["password"], "-v"],
@@ -69,6 +141,18 @@ class TestCommands(TestCase):
69
141
  return user
70
142
 
71
143
  def user_missing_arguments(self, command):
144
+ """
145
+ Test user creation with missing required arguments.
146
+
147
+ :param command: The user creation command to test
148
+ :type command: function
149
+
150
+ Verifies:
151
+
152
+ - Proper error handling for missing username
153
+ - Proper error handling for missing email
154
+ - Proper error handling for missing password
155
+ """
72
156
  result = self.runner.invoke(
73
157
  command,
74
158
  [
@@ -106,9 +190,27 @@ class TestCommands(TestCase):
106
190
  self.assertIn("Missing option '-p' / '--password'", result.output)
107
191
 
108
192
  def test_service_user_command(self):
193
+ """
194
+ Test service user creation command.
195
+
196
+ Verifies:
197
+
198
+ - Successful service user creation
199
+ - Correct user attributes
200
+ - Service role assignment
201
+ """
109
202
  return self.user_command(create_service_user, "cornflow", self.payload["email"])
110
203
 
111
204
  def test_service_user_existing_admin(self):
205
+ """
206
+ Test service user creation when admin user exists.
207
+
208
+ Verifies:
209
+
210
+ - Successful service user creation with existing admin
211
+ - Correct user attributes
212
+ - Proper role assignments
213
+ """
112
214
  self.test_admin_user_command()
113
215
  self.runner.invoke(
114
216
  create_service_user,
@@ -127,22 +229,56 @@ class TestCommands(TestCase):
127
229
  self.assertNotEqual(None, user)
128
230
  self.assertEqual(self.payload["email"], user.email)
129
231
  self.assertEqual("cornflow", user.username)
130
- # TODO: check the user has both roles
131
232
 
132
233
  def test_service_user_existing_service(self):
234
+ """
235
+ Test service user creation when service user exists.
236
+
237
+ Verifies:
238
+
239
+ - Proper handling of existing service user
240
+ - Correct user attributes
241
+ - Role consistency
242
+ """
133
243
  self.test_service_user_command()
134
244
  user = self.test_service_user_command()
135
245
 
136
246
  self.assertEqual("cornflow", user.username)
137
- # TODO: check the user has the role
138
247
 
139
248
  def test_admin_user_command(self):
249
+ """
250
+ Test admin user creation command.
251
+
252
+ Verifies:
253
+
254
+ - Successful admin user creation
255
+ - Correct user attributes
256
+ - Admin role assignment
257
+ """
140
258
  return self.user_command(create_admin_user, "admin", "admin@test.org")
141
259
 
142
260
  def test_base_user_command(self):
261
+ """
262
+ Test base user creation command.
263
+
264
+ Verifies:
265
+
266
+ - Successful base user creation
267
+ - Correct user attributes
268
+ - Base role assignment
269
+ """
143
270
  return self.user_command(create_base_user, "base", "base@test.org")
144
271
 
145
272
  def test_register_actions(self):
273
+ """
274
+ Test action registration command.
275
+
276
+ Verifies:
277
+
278
+ - Successful action registration
279
+ - Correct action names and mappings
280
+ - Database state after registration
281
+ """
146
282
  self.runner.invoke(register_actions)
147
283
 
148
284
  actions = ActionModel.query.all()
@@ -151,6 +287,15 @@ class TestCommands(TestCase):
151
287
  self.assertEqual(ACTIONS_MAP[a.id], a.name)
152
288
 
153
289
  def test_register_views(self):
290
+ """
291
+ Test view registration command.
292
+
293
+ Verifies:
294
+
295
+ - Successful view registration
296
+ - Correct view endpoints
297
+ - Proper mapping to resources
298
+ """
154
299
  self.runner.invoke(register_views)
155
300
 
156
301
  views = ViewModel.query.all()
@@ -162,11 +307,29 @@ class TestCommands(TestCase):
162
307
  self.assertCountEqual(views_list, resources_list)
163
308
 
164
309
  def test_register_roles(self):
310
+ """
311
+ Test role registration command.
312
+
313
+ Verifies:
314
+
315
+ - Successful role registration
316
+ - Correct role names and mappings
317
+ - Database state after registration
318
+ """
165
319
  roles = RoleModel.query.all()
166
320
  for r in roles:
167
321
  self.assertEqual(ROLES_MAP[r.id], r.name)
168
322
 
169
323
  def test_base_permissions_assignation(self):
324
+ """
325
+ Test base permission assignment.
326
+
327
+ Verifies:
328
+
329
+ - Successful permission assignment
330
+ - Correct role-view-action mappings
331
+ - Proper access control setup
332
+ """
170
333
  self.runner.invoke(access_init)
171
334
 
172
335
  for base in BASE_PERMISSION_ASSIGNATION:
@@ -183,12 +346,30 @@ class TestCommands(TestCase):
183
346
  self.assertEqual(True, permission)
184
347
 
185
348
  def test_deployed_dags_test_command(self):
349
+ """
350
+ Test DAG deployment command in test mode.
351
+
352
+ Verifies:
353
+
354
+ - Successful DAG deployment
355
+ - Correct DAG registration
356
+ - Presence of required DAGs
357
+ """
186
358
  register_deployed_dags_command_test(verbose=True)
187
359
  dags = DeployedDAG.get_all_objects()
188
360
  for dag in ["solve_model_dag", "gc", "timer"]:
189
361
  self.assertIn(dag, [d.id for d in dags])
190
362
 
191
363
  def test_dag_permissions_command(self):
364
+ """
365
+ Test DAG permissions command with open deployment.
366
+
367
+ Verifies:
368
+
369
+ - Successful permission assignment
370
+ - Correct permissions for service and admin users
371
+ - Proper access control setup
372
+ """
192
373
  register_deployed_dags_command_test()
193
374
  self.test_service_user_command()
194
375
  self.test_admin_user_command()
@@ -204,6 +385,15 @@ class TestCommands(TestCase):
204
385
  self.assertEqual(3, len(admin_permissions))
205
386
 
206
387
  def test_dag_permissions_command_no_open(self):
388
+ """
389
+ Test DAG permissions command without open deployment.
390
+
391
+ Verifies:
392
+
393
+ - Successful permission assignment
394
+ - Restricted access for admin users
395
+ - Proper service user permissions
396
+ """
207
397
  register_deployed_dags_command_test()
208
398
  self.test_service_user_command()
209
399
  self.test_admin_user_command()
@@ -219,6 +409,15 @@ class TestCommands(TestCase):
219
409
  self.assertEqual(0, len(admin_permissions))
220
410
 
221
411
  def test_argument_parsing_correct(self):
412
+ """
413
+ Test correct argument parsing for DAG permissions.
414
+
415
+ Verifies:
416
+
417
+ - Proper handling of invalid arguments
418
+ - Error messages for incorrect input
419
+ - No permission changes on error
420
+ """
222
421
  self.test_service_user_command()
223
422
  result = self.runner.invoke(register_dag_permissions, ["-o", "a"])
224
423
 
@@ -230,21 +429,50 @@ class TestCommands(TestCase):
230
429
  self.assertEqual(0, len(service_permissions))
231
430
 
232
431
  def test_argument_parsing_incorrect(self):
432
+ """
433
+ Test incorrect argument parsing for DAG permissions.
434
+
435
+ Verifies:
436
+
437
+ - Error handling for invalid input types
438
+ - Proper error messages
439
+ - Command failure behavior
440
+ """
233
441
  self.test_service_user_command()
234
442
  result = self.runner.invoke(register_dag_permissions, ["-o", "a"])
235
443
  self.assertEqual(2, result.exit_code)
236
444
  self.assertIn("is not a valid integer", result.output)
237
445
 
238
446
  def test_missing_required_argument_service(self):
447
+ """
448
+ Test missing arguments for service user creation.
449
+
450
+ Verifies proper error handling for missing required arguments.
451
+ """
239
452
  self.user_missing_arguments(create_service_user)
240
453
 
241
454
  def test_missing_required_argument_admin(self):
455
+ """
456
+ Test missing arguments for admin user creation.
457
+
458
+ Verifies proper error handling for missing required arguments.
459
+ """
242
460
  self.user_missing_arguments(create_admin_user)
243
461
 
244
462
  def test_missing_required_argument_user(self):
463
+ """
464
+ Test missing arguments for base user creation.
465
+
466
+ Verifies proper error handling for missing required arguments.
467
+ """
245
468
  self.user_missing_arguments(create_base_user)
246
469
 
247
470
  def test_error_no_views(self):
471
+ """
472
+ Test error handling when views are not registered.
473
+
474
+ Verifies proper error handling when attempting operations without registered views.
475
+ """
248
476
  self.test_service_user_command()
249
477
  token = self.client.post(
250
478
  LOGIN_URL,
@@ -1,5 +1,17 @@
1
1
  """
2
- Unit test for the DAG endpoints
2
+ Unit tests for the DAG endpoints.
3
+
4
+ This module contains tests for DAG (Directed Acyclic Graph) functionality, including:
5
+
6
+ - DAG execution and state management
7
+ - Manual and automated DAG operations
8
+ - Service and planner user permissions
9
+ - DAG deployment and registration
10
+ - Permission cascade deletion
11
+ - DAG configuration and data handling
12
+
13
+ The tests verify both successful operations and proper error handling
14
+ for various DAG-related scenarios.
3
15
  """
4
16
 
5
17
  # Import from libraries
@@ -31,7 +43,28 @@ from cornflow_client import get_pulp_jsonschema, get_empty_schema
31
43
 
32
44
 
33
45
  class TestDagEndpoint(TestExecutionsDetailEndpointMock):
46
+ """
47
+ Test suite for DAG endpoint functionality.
48
+
49
+ This class tests the DAG endpoints for different user roles and states:
50
+
51
+ - Manual DAG operations for service users
52
+ - Manual DAG operations for planner users
53
+ - DAG state management
54
+ - Data validation and processing
55
+ """
56
+
34
57
  def test_manual_dag_service_user(self):
58
+ """
59
+ Test manual DAG operations for service users.
60
+
61
+ Verifies:
62
+
63
+ - Service user can create manual DAGs
64
+ - Proper state assignment
65
+ - Correct data handling
66
+ - Required fields validation
67
+ """
35
68
  with open(CASE_PATH) as f:
36
69
  payload = json.load(f)
37
70
  data = dict(
@@ -59,6 +92,16 @@ class TestDagEndpoint(TestExecutionsDetailEndpointMock):
59
92
  )
60
93
 
61
94
  def test_manual_dag_planner_user(self):
95
+ """
96
+ Test manual DAG operations for planner users.
97
+
98
+ Verifies:
99
+
100
+ - Planner user can create manual DAGs
101
+ - Proper state assignment
102
+ - Correct data handling
103
+ - Required fields validation
104
+ """
62
105
  with open(CASE_PATH) as f:
63
106
  payload = json.load(f)
64
107
  data = dict(
@@ -87,7 +130,29 @@ class TestDagEndpoint(TestExecutionsDetailEndpointMock):
87
130
 
88
131
 
89
132
  class TestDagDetailEndpoint(TestExecutionsDetailEndpointMock):
133
+ """
134
+ Test suite for DAG detail endpoint functionality.
135
+
136
+ This class tests detailed DAG operations including:
137
+
138
+ - DAG updates and modifications
139
+ - Log handling and validation
140
+ - Data retrieval and verification
141
+ - Error handling for unauthorized access
142
+ """
143
+
90
144
  def test_put_dag(self):
145
+ """
146
+ Test updating a DAG.
147
+
148
+ Verifies:
149
+
150
+ - Successful DAG update
151
+ - Log JSON handling
152
+ - State transition
153
+ - Field validation
154
+ - Log field filtering
155
+ """
91
156
  idx = self.create_new_row(EXECUTION_URL_NORUN, self.model, self.payload)
92
157
  with open(CASE_PATH) as f:
93
158
  payload = json.load(f)
@@ -104,19 +169,12 @@ class TestDagDetailEndpoint(TestExecutionsDetailEndpointMock):
104
169
  data = dict(
105
170
  data=payload["data"],
106
171
  state=EXEC_STATE_CORRECT,
107
- log_json={
108
- "time": 10.3,
109
- "solver": "dummy",
110
- "status": "feasible",
111
- "status_code": 2,
112
- "sol_code": 1,
113
- "some_other_key": "this should be excluded",
114
- },
172
+ log_json=log_json,
115
173
  )
116
174
  payload_to_check = {**self.payload, **data}
117
175
  token = self.create_service_user()
118
176
  self.update_row(
119
- url=DAG_URL + idx + "/",
177
+ url=f"{DAG_URL}{idx}/",
120
178
  payload_to_check=payload_to_check,
121
179
  change=data,
122
180
  token=token,
@@ -124,7 +182,7 @@ class TestDagDetailEndpoint(TestExecutionsDetailEndpointMock):
124
182
  )
125
183
 
126
184
  data = self.get_one_row(
127
- url=EXECUTION_URL + idx + "/log/",
185
+ url=f"{EXECUTION_URL}{idx}/log/",
128
186
  token=token,
129
187
  check_payload=False,
130
188
  payload=self.payload,
@@ -137,6 +195,16 @@ class TestDagDetailEndpoint(TestExecutionsDetailEndpointMock):
137
195
  self.assertNotIn("some_other_key", data["log"].keys())
138
196
 
139
197
  def test_get_dag(self):
198
+ """
199
+ Test retrieving a DAG.
200
+
201
+ Verifies:
202
+
203
+ - Successful DAG retrieval
204
+ - Correct data structure
205
+ - Instance data consistency
206
+ - Configuration validation
207
+ """
140
208
  idx = self.create_new_row(EXECUTION_URL_NORUN, self.model, self.payload)
141
209
  token = self.create_service_user()
142
210
  keys_to_check = ["id", "data", "solution_data", "config"]
@@ -169,6 +237,15 @@ class TestDagDetailEndpoint(TestExecutionsDetailEndpointMock):
169
237
  return
170
238
 
171
239
  def test_get_no_dag(self):
240
+ """
241
+ Test retrieving a non-existent DAG.
242
+
243
+ Verifies:
244
+
245
+ - Proper error handling for missing DAGs
246
+ - Correct error status code
247
+ - Error message validation
248
+ """
172
249
  idx = self.create_new_row(EXECUTION_URL_NORUN, self.model, self.payload)
173
250
  data = self.get_one_row(
174
251
  url=DAG_URL + idx + "/",
@@ -181,11 +258,39 @@ class TestDagDetailEndpoint(TestExecutionsDetailEndpointMock):
181
258
 
182
259
 
183
260
  class TestDeployedDAG(TestCase):
261
+ """
262
+ Test suite for deployed DAG functionality.
263
+
264
+ This class tests deployed DAG operations including:
265
+
266
+ - DAG deployment and registration
267
+ - Permission management
268
+ - Cascade deletion
269
+ - User role interactions
270
+ """
271
+
184
272
  def create_app(self):
273
+ """
274
+ Create and configure the Flask application for testing.
275
+
276
+ :return: The configured Flask application instance
277
+ :rtype: Flask
278
+ """
185
279
  app = create_app("testing")
186
280
  return app
187
281
 
188
282
  def setUp(self):
283
+ """
284
+ Set up test environment before each test.
285
+
286
+ Initializes:
287
+
288
+ - Database tables
289
+ - Access controls
290
+ - Test DAGs
291
+ - Admin user with roles
292
+ - DAG permissions
293
+ """
189
294
  db.create_all()
190
295
  access_init_command(verbose=False)
191
296
  register_deployed_dags_command_test(verbose=False)
@@ -226,10 +331,24 @@ class TestDeployedDAG(TestCase):
226
331
  register_dag_permissions_command(verbose=False)
227
332
 
228
333
  def tearDown(self):
334
+ """
335
+ Clean up test environment after each test.
336
+
337
+ Removes database session and drops all tables.
338
+ """
229
339
  db.session.remove()
230
340
  db.drop_all()
231
341
 
232
342
  def test_permission_cascade_deletion(self):
343
+ """
344
+ Test cascade deletion of DAG permissions.
345
+
346
+ Verifies:
347
+
348
+ - Successful permission deletion on DAG removal
349
+ - Proper cascade effect
350
+ - Permission count validation
351
+ """
233
352
  before = PermissionsDAG.get_user_dag_permissions(self.admin["id"])
234
353
  self.assertIsNotNone(before)
235
354
  dag = DeployedDAG.query.get("solve_model_dag")
@@ -239,6 +358,15 @@ class TestDeployedDAG(TestCase):
239
358
  self.assertGreater(len(before), len(after))
240
359
 
241
360
  def test_get_deployed_dags(self):
361
+ """
362
+ Test retrieving deployed DAGs.
363
+
364
+ Verifies:
365
+
366
+ - Successful DAG listing
367
+ - Proper authorization
368
+ - Response structure
369
+ """
242
370
  response = self.client.get(
243
371
  DEPLOYED_DAG_URL,
244
372
  follow_redirects=True,