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,17 @@
|
|
1
1
|
"""
|
2
|
-
Unit
|
2
|
+
Unit tests for the data check endpoints.
|
3
|
+
|
4
|
+
This module contains tests for data validation functionality, including:
|
5
|
+
|
6
|
+
- Execution data checks
|
7
|
+
- Instance data validation
|
8
|
+
- Case data verification
|
9
|
+
- Airflow integration testing
|
10
|
+
- Run and no-run scenarios
|
11
|
+
- Response validation
|
12
|
+
|
13
|
+
The tests verify both successful validation operations and proper error handling
|
14
|
+
for various data check scenarios.
|
3
15
|
"""
|
4
16
|
|
5
17
|
# Import from libraries
|
@@ -11,7 +23,6 @@ from cornflow.models import ExecutionModel, InstanceModel, CaseModel
|
|
11
23
|
from cornflow.tests.const import (
|
12
24
|
INSTANCE_PATH,
|
13
25
|
EXECUTION_PATH,
|
14
|
-
EXECUTION_URL,
|
15
26
|
CASE_PATH,
|
16
27
|
EXECUTION_URL_NORUN,
|
17
28
|
DATA_CHECK_EXECUTION_URL,
|
@@ -25,7 +36,28 @@ from cornflow.tests.unit.tools import patch_af_client
|
|
25
36
|
|
26
37
|
|
27
38
|
class TestDataChecksExecutionEndpoint(CustomTestCase):
|
39
|
+
"""
|
40
|
+
Test suite for execution data check endpoints.
|
41
|
+
|
42
|
+
This class tests data validation for executions:
|
43
|
+
|
44
|
+
- Direct execution checks
|
45
|
+
- Run and no-run validation scenarios
|
46
|
+
- Response structure validation
|
47
|
+
- Airflow integration testing
|
48
|
+
"""
|
49
|
+
|
28
50
|
def setUp(self):
|
51
|
+
"""
|
52
|
+
Set up test environment before each test.
|
53
|
+
|
54
|
+
Initializes:
|
55
|
+
|
56
|
+
- Base test configuration
|
57
|
+
- Test instance data
|
58
|
+
- Execution model
|
59
|
+
- Test payload
|
60
|
+
"""
|
29
61
|
super().setUp()
|
30
62
|
|
31
63
|
with open(INSTANCE_PATH) as f:
|
@@ -42,6 +74,16 @@ class TestDataChecksExecutionEndpoint(CustomTestCase):
|
|
42
74
|
self.payload = load_file_fk(EXECUTION_PATH)
|
43
75
|
|
44
76
|
def test_check_execution(self):
|
77
|
+
"""
|
78
|
+
Test execution data check without running.
|
79
|
+
|
80
|
+
Verifies:
|
81
|
+
|
82
|
+
- Successful data check creation
|
83
|
+
- Correct response status
|
84
|
+
- Proper ID assignment
|
85
|
+
- Data consistency
|
86
|
+
"""
|
45
87
|
exec_to_check_id = self.create_new_row(
|
46
88
|
EXECUTION_URL_NORUN, self.model, payload=self.payload
|
47
89
|
)
|
@@ -61,6 +103,16 @@ class TestDataChecksExecutionEndpoint(CustomTestCase):
|
|
61
103
|
|
62
104
|
@patch("cornflow.endpoints.data_check.Airflow")
|
63
105
|
def test_check_execution_run(self, af_client_class):
|
106
|
+
"""
|
107
|
+
Test execution data check with Airflow integration.
|
108
|
+
|
109
|
+
Verifies:
|
110
|
+
|
111
|
+
- Successful data check creation
|
112
|
+
- Airflow client interaction
|
113
|
+
- Response validation
|
114
|
+
- Data consistency
|
115
|
+
"""
|
64
116
|
patch_af_client(af_client_class)
|
65
117
|
|
66
118
|
exec_to_check_id = self.create_new_row(
|
@@ -83,7 +135,28 @@ class TestDataChecksExecutionEndpoint(CustomTestCase):
|
|
83
135
|
|
84
136
|
|
85
137
|
class TestDataChecksInstanceEndpoint(CustomTestCase):
|
138
|
+
"""
|
139
|
+
Test suite for instance data check endpoints.
|
140
|
+
|
141
|
+
This class tests data validation for instances:
|
142
|
+
|
143
|
+
- Instance data validation
|
144
|
+
- Run and no-run scenarios
|
145
|
+
- Configuration verification
|
146
|
+
- Response structure validation
|
147
|
+
"""
|
148
|
+
|
86
149
|
def setUp(self):
|
150
|
+
"""
|
151
|
+
Set up test environment before each test.
|
152
|
+
|
153
|
+
Initializes:
|
154
|
+
|
155
|
+
- Base test configuration
|
156
|
+
- Test instance data
|
157
|
+
- Instance ID reference
|
158
|
+
- Execution model
|
159
|
+
"""
|
87
160
|
super().setUp()
|
88
161
|
|
89
162
|
with open(INSTANCE_PATH) as f:
|
@@ -93,7 +166,16 @@ class TestDataChecksInstanceEndpoint(CustomTestCase):
|
|
93
166
|
self.model = ExecutionModel
|
94
167
|
|
95
168
|
def test_new_data_check_execution(self):
|
169
|
+
"""
|
170
|
+
Test instance data check without running.
|
171
|
+
|
172
|
+
Verifies:
|
96
173
|
|
174
|
+
- Successful data check creation
|
175
|
+
- Correct response status
|
176
|
+
- Instance ID association
|
177
|
+
- Configuration settings
|
178
|
+
"""
|
97
179
|
url = DATA_CHECK_INSTANCE_URL + self.instance_id + "/?run=0"
|
98
180
|
response = self.client.post(
|
99
181
|
url,
|
@@ -112,6 +194,16 @@ class TestDataChecksInstanceEndpoint(CustomTestCase):
|
|
112
194
|
|
113
195
|
@patch("cornflow.endpoints.data_check.Airflow")
|
114
196
|
def test_new_data_check_execution_run(self, af_client_class):
|
197
|
+
"""
|
198
|
+
Test instance data check with Airflow integration.
|
199
|
+
|
200
|
+
Verifies:
|
201
|
+
|
202
|
+
- Successful data check creation
|
203
|
+
- Airflow client interaction
|
204
|
+
- Instance association
|
205
|
+
- Configuration validation
|
206
|
+
"""
|
115
207
|
patch_af_client(af_client_class)
|
116
208
|
|
117
209
|
url = DATA_CHECK_INSTANCE_URL + self.instance_id + "/"
|
@@ -132,7 +224,28 @@ class TestDataChecksInstanceEndpoint(CustomTestCase):
|
|
132
224
|
|
133
225
|
|
134
226
|
class TestDataChecksCaseEndpoint(CustomTestCase):
|
227
|
+
"""
|
228
|
+
Test suite for case data check endpoints.
|
229
|
+
|
230
|
+
This class tests data validation for cases:
|
231
|
+
|
232
|
+
- Case data validation
|
233
|
+
- Run and no-run scenarios
|
234
|
+
- Configuration verification
|
235
|
+
- Response structure validation
|
236
|
+
"""
|
237
|
+
|
135
238
|
def setUp(self):
|
239
|
+
"""
|
240
|
+
Set up test environment before each test.
|
241
|
+
|
242
|
+
Initializes:
|
243
|
+
|
244
|
+
- Base test configuration
|
245
|
+
- Test case data
|
246
|
+
- Case ID reference
|
247
|
+
- Execution model
|
248
|
+
"""
|
136
249
|
super().setUp()
|
137
250
|
|
138
251
|
with open(CASE_PATH) as f:
|
@@ -142,7 +255,16 @@ class TestDataChecksCaseEndpoint(CustomTestCase):
|
|
142
255
|
self.model = ExecutionModel
|
143
256
|
|
144
257
|
def test_new_data_check_execution(self):
|
258
|
+
"""
|
259
|
+
Test case data check without running.
|
145
260
|
|
261
|
+
Verifies:
|
262
|
+
|
263
|
+
- Successful data check creation
|
264
|
+
- Correct response status
|
265
|
+
- Configuration settings
|
266
|
+
- Response validation
|
267
|
+
"""
|
146
268
|
url = DATA_CHECK_CASE_URL + str(self.case_id) + "/?run=0"
|
147
269
|
response = self.client.post(
|
148
270
|
url,
|
@@ -159,6 +281,16 @@ class TestDataChecksCaseEndpoint(CustomTestCase):
|
|
159
281
|
|
160
282
|
@patch("cornflow.endpoints.data_check.Airflow")
|
161
283
|
def test_new_data_check_execution_run(self, af_client_class):
|
284
|
+
"""
|
285
|
+
Test case data check with Airflow integration.
|
286
|
+
|
287
|
+
Verifies:
|
288
|
+
|
289
|
+
- Successful data check creation
|
290
|
+
- Airflow client interaction
|
291
|
+
- Configuration validation
|
292
|
+
- Response structure
|
293
|
+
"""
|
162
294
|
patch_af_client(af_client_class)
|
163
295
|
|
164
296
|
url = DATA_CHECK_CASE_URL + str(self.case_id) + "/"
|
@@ -2,13 +2,21 @@
|
|
2
2
|
Unit test for the log in endpoint
|
3
3
|
"""
|
4
4
|
|
5
|
-
|
5
|
+
import json
|
6
|
+
import logging as log
|
7
|
+
from unittest import mock
|
8
|
+
|
6
9
|
from flask import current_app
|
7
10
|
|
8
|
-
|
11
|
+
|
12
|
+
from cornflow.app import create_app
|
13
|
+
from cornflow.commands.access import access_init_command
|
14
|
+
from cornflow.commands.dag import register_deployed_dags_command_test
|
9
15
|
from cornflow.models import UserModel
|
10
16
|
from cornflow.shared import db
|
11
|
-
from cornflow.
|
17
|
+
from cornflow.shared.const import SERVICE_ROLE, OID_GOOGLE, OID_AZURE, OID_NONE
|
18
|
+
from cornflow.tests.const import LOGIN_URL
|
19
|
+
from cornflow.tests.custom_test_case import CustomTestCase, LoginTestCases
|
12
20
|
|
13
21
|
|
14
22
|
class TestLogIn(LoginTestCases.LoginEndpoint):
|
@@ -29,5 +37,475 @@ class TestLogIn(LoginTestCases.LoginEndpoint):
|
|
29
37
|
self.idx = UserModel.query.filter_by(username="testname").first().id
|
30
38
|
|
31
39
|
def test_successful_log_in(self):
|
40
|
+
"""
|
41
|
+
Test the successful log in
|
42
|
+
"""
|
32
43
|
super().test_successful_log_in()
|
33
44
|
self.assertEqual(self.idx, self.response.json["id"])
|
45
|
+
|
46
|
+
@mock.patch("cornflow.endpoints.login.Auth.generate_token")
|
47
|
+
def test_exception_on_token_generation(self, mock_generate_token):
|
48
|
+
# Simulate an exception when generate_token is called
|
49
|
+
mock_generate_token.side_effect = Exception("Custom exception")
|
50
|
+
|
51
|
+
# Prepare login payload
|
52
|
+
payload = self.data
|
53
|
+
|
54
|
+
# Make a login request
|
55
|
+
response = self.client.post(
|
56
|
+
LOGIN_URL,
|
57
|
+
data=json.dumps(payload),
|
58
|
+
follow_redirects=True,
|
59
|
+
headers={"Content-Type": "application/json"},
|
60
|
+
)
|
61
|
+
|
62
|
+
# Assert that the response is a 400 error
|
63
|
+
self.assertEqual(400, response.status_code)
|
64
|
+
# Assert that the error message contains the expected text
|
65
|
+
self.assertIn("Error in generating user token", response.json["error"])
|
66
|
+
|
67
|
+
|
68
|
+
class TestLogInOpenAuthNoConfig(CustomTestCase):
|
69
|
+
def create_app(self):
|
70
|
+
"""
|
71
|
+
Creates and configures a Flask application for testing.
|
72
|
+
|
73
|
+
:returns: A configured Flask application instance
|
74
|
+
:rtype: Flask
|
75
|
+
"""
|
76
|
+
app = create_app("testing-oauth")
|
77
|
+
app.config["SERVICE_USER_ALLOW_PASSWORD_LOGIN"] = 0
|
78
|
+
return app
|
79
|
+
|
80
|
+
def setUp(self):
|
81
|
+
log.root.setLevel(current_app.config["LOG_LEVEL"])
|
82
|
+
db.create_all()
|
83
|
+
access_init_command(verbose=False)
|
84
|
+
register_deployed_dags_command_test(verbose=False)
|
85
|
+
self.user_data = {
|
86
|
+
"username": "testname",
|
87
|
+
"email": "test@test.com",
|
88
|
+
"password": "Testpassword1!",
|
89
|
+
}
|
90
|
+
|
91
|
+
test_user = UserModel(data=self.user_data)
|
92
|
+
test_user.save()
|
93
|
+
|
94
|
+
self.user_data.pop("email")
|
95
|
+
|
96
|
+
self.test_user_id = test_user.id
|
97
|
+
|
98
|
+
self.service_data = {
|
99
|
+
"username": "service_user",
|
100
|
+
"email": "service@test.com",
|
101
|
+
"password": "Testpassword1!",
|
102
|
+
}
|
103
|
+
|
104
|
+
service_user = UserModel(data=self.service_data)
|
105
|
+
service_user.save()
|
106
|
+
|
107
|
+
self.service_data.pop("email")
|
108
|
+
self.service_user_id = service_user.id
|
109
|
+
|
110
|
+
self.assign_role(self.service_user_id, SERVICE_ROLE)
|
111
|
+
|
112
|
+
def test_service_user_login(self):
|
113
|
+
"""
|
114
|
+
Tests that a service user can not log in with username and password
|
115
|
+
"""
|
116
|
+
response = self.client.post(
|
117
|
+
LOGIN_URL,
|
118
|
+
data=json.dumps(self.service_data),
|
119
|
+
headers={"Content-Type": "application/json"},
|
120
|
+
)
|
121
|
+
|
122
|
+
self.assertEqual(400, response.status_code)
|
123
|
+
self.assertEqual(response.json["error"], "Invalid request")
|
124
|
+
|
125
|
+
def test_other_user_password(self):
|
126
|
+
"""
|
127
|
+
Tests that a user can not log in with username and password
|
128
|
+
"""
|
129
|
+
response = self.client.post(
|
130
|
+
LOGIN_URL,
|
131
|
+
data=json.dumps(self.user_data),
|
132
|
+
headers={"Content-Type": "application/json"},
|
133
|
+
)
|
134
|
+
|
135
|
+
self.assertEqual(400, response.status_code)
|
136
|
+
self.assertEqual(response.json["error"], "Invalid request")
|
137
|
+
|
138
|
+
|
139
|
+
class TestLogInOpenAuthAzure(CustomTestCase):
|
140
|
+
def create_app(self):
|
141
|
+
"""
|
142
|
+
Creates and configures a Flask application for testing.
|
143
|
+
|
144
|
+
:returns: A configured Flask application instance
|
145
|
+
:rtype: Flask
|
146
|
+
"""
|
147
|
+
app = create_app("testing-oauth")
|
148
|
+
app.config["SERVICE_USER_ALLOW_PASSWORD_LOGIN"] = 0
|
149
|
+
app.config["OID_PROVIDER"] = OID_AZURE
|
150
|
+
app.config["OID_CLIENT_ID"] = "SOME_SECRET"
|
151
|
+
app.config["OID_TENANT_ID"] = "SOME_SECRET"
|
152
|
+
app.config["OID_ISSUER"] = "SOME_SECRET"
|
153
|
+
return app
|
154
|
+
|
155
|
+
def setUp(self):
|
156
|
+
log.root.setLevel(current_app.config["LOG_LEVEL"])
|
157
|
+
db.create_all()
|
158
|
+
access_init_command(verbose=False)
|
159
|
+
register_deployed_dags_command_test(verbose=False)
|
160
|
+
|
161
|
+
self.service_data = {
|
162
|
+
"username": "service_user",
|
163
|
+
"email": "service@test.com",
|
164
|
+
"password": "Testpassword1!",
|
165
|
+
}
|
166
|
+
|
167
|
+
service_user = UserModel(data=self.service_data)
|
168
|
+
service_user.save()
|
169
|
+
|
170
|
+
self.service_data.pop("email")
|
171
|
+
self.service_user_id = service_user.id
|
172
|
+
|
173
|
+
self.assign_role(self.service_user_id, SERVICE_ROLE)
|
174
|
+
|
175
|
+
def test_service_user_login_first_fail(self):
|
176
|
+
"""
|
177
|
+
Tests that a service user can not log in with username and password
|
178
|
+
"""
|
179
|
+
response = self.client.post(
|
180
|
+
LOGIN_URL,
|
181
|
+
data=json.dumps({"token": "some_token"}),
|
182
|
+
headers={"Content-Type": "application/json"},
|
183
|
+
)
|
184
|
+
|
185
|
+
self.assertEqual(400, response.status_code)
|
186
|
+
self.assertEqual(response.json["error"], "Token is not valid")
|
187
|
+
|
188
|
+
@mock.patch("cornflow.shared.authentication.auth.jwt")
|
189
|
+
def test_service_user_login_second_fail(self, mock_header):
|
190
|
+
"""
|
191
|
+
Tests second exit point on token validation
|
192
|
+
"""
|
193
|
+
mock_header.get_unverified_header.return_value = None
|
194
|
+
response = self.client.post(
|
195
|
+
LOGIN_URL,
|
196
|
+
data=json.dumps({"token": "some_token"}),
|
197
|
+
headers={"Content-Type": "application/json"},
|
198
|
+
)
|
199
|
+
|
200
|
+
self.assertEqual(400, response.status_code)
|
201
|
+
self.assertEqual(response.json["error"], "Token is missing the headers")
|
202
|
+
|
203
|
+
@mock.patch("cornflow.shared.authentication.auth.jwt")
|
204
|
+
def test_service_user_login_third_fail(self, mock_header):
|
205
|
+
"""
|
206
|
+
Tests third exit point on token validation
|
207
|
+
"""
|
208
|
+
mock_header.get_unverified_header.return_value = {"kid": "some_value"}
|
209
|
+
response = self.client.post(
|
210
|
+
LOGIN_URL,
|
211
|
+
data=json.dumps({"token": "some_token"}),
|
212
|
+
headers={"Content-Type": "application/json"},
|
213
|
+
)
|
214
|
+
|
215
|
+
self.assertEqual(400, response.status_code)
|
216
|
+
self.assertIn(
|
217
|
+
"Error getting issuer discovery meta from", response.json["error"]
|
218
|
+
)
|
219
|
+
|
220
|
+
@mock.patch("cornflow.endpoints.login.Auth.validate_oid_token")
|
221
|
+
def test_service_user_login_no_fail(self, mock_auth):
|
222
|
+
mock_auth.return_value = {"preferred_username": "service_user"}
|
223
|
+
response = self.client.post(
|
224
|
+
LOGIN_URL,
|
225
|
+
data=json.dumps({"token": "some_token"}),
|
226
|
+
headers={"Content-Type": "application/json"},
|
227
|
+
)
|
228
|
+
|
229
|
+
print(response.json)
|
230
|
+
|
231
|
+
self.assertEqual(200, response.status_code)
|
232
|
+
self.assertEqual(self.service_user_id, response.json["id"])
|
233
|
+
|
234
|
+
@mock.patch("cornflow.endpoints.login.Auth.validate_oid_token")
|
235
|
+
def test_new_user_login_no_fail(self, mock_auth):
|
236
|
+
mock_auth.return_value = {"preferred_username": "test_user"}
|
237
|
+
response = self.client.post(
|
238
|
+
LOGIN_URL,
|
239
|
+
data=json.dumps({"token": "some_token"}),
|
240
|
+
headers={"Content-Type": "application/json"},
|
241
|
+
)
|
242
|
+
|
243
|
+
self.assertEqual(200, response.status_code)
|
244
|
+
self.assertEqual(self.service_user_id + 1, response.json["id"])
|
245
|
+
|
246
|
+
|
247
|
+
class TestLogInOpenAuthGoogle(CustomTestCase):
|
248
|
+
def create_app(self):
|
249
|
+
"""
|
250
|
+
Creates and configures a Flask application for testing.
|
251
|
+
|
252
|
+
:returns: A configured Flask application instance
|
253
|
+
:rtype: Flask
|
254
|
+
"""
|
255
|
+
app = create_app("testing-oauth")
|
256
|
+
app.config["SERVICE_USER_ALLOW_PASSWORD_LOGIN"] = 0
|
257
|
+
app.config["OID_PROVIDER"] = OID_GOOGLE
|
258
|
+
app.config["OID_CLIENT_ID"] = "SOME_SECRET"
|
259
|
+
app.config["OID_TENANT_ID"] = "SOME_SECRET"
|
260
|
+
app.config["OID_ISSUER"] = "SOME_SECRET"
|
261
|
+
return app
|
262
|
+
|
263
|
+
def setUp(self):
|
264
|
+
log.root.setLevel(current_app.config["LOG_LEVEL"])
|
265
|
+
db.create_all()
|
266
|
+
access_init_command(verbose=False)
|
267
|
+
register_deployed_dags_command_test(verbose=False)
|
268
|
+
|
269
|
+
self.service_data = {
|
270
|
+
"username": "service_user",
|
271
|
+
"email": "service@test.com",
|
272
|
+
"password": "Testpassword1!",
|
273
|
+
}
|
274
|
+
|
275
|
+
service_user = UserModel(data=self.service_data)
|
276
|
+
service_user.save()
|
277
|
+
|
278
|
+
self.service_data.pop("email")
|
279
|
+
self.service_user_id = service_user.id
|
280
|
+
|
281
|
+
self.assign_role(self.service_user_id, SERVICE_ROLE)
|
282
|
+
|
283
|
+
def test_service_user_login(self):
|
284
|
+
"""
|
285
|
+
Tests that a service user can not log in with username and password
|
286
|
+
"""
|
287
|
+
response = self.client.post(
|
288
|
+
LOGIN_URL,
|
289
|
+
data=json.dumps({"token": "some_token"}),
|
290
|
+
headers={"Content-Type": "application/json"},
|
291
|
+
)
|
292
|
+
|
293
|
+
self.assertEqual(501, response.status_code)
|
294
|
+
self.assertEqual(
|
295
|
+
response.json["error"], "The selected OID provider is not implemented"
|
296
|
+
)
|
297
|
+
|
298
|
+
|
299
|
+
class TestLogInOpenAuthNone(CustomTestCase):
|
300
|
+
def create_app(self):
|
301
|
+
"""
|
302
|
+
Creates and configures a Flask application for testing.
|
303
|
+
|
304
|
+
:returns: A configured Flask application instance
|
305
|
+
:rtype: Flask
|
306
|
+
"""
|
307
|
+
app = create_app("testing-oauth")
|
308
|
+
app.config["SERVICE_USER_ALLOW_PASSWORD_LOGIN"] = 0
|
309
|
+
app.config["OID_PROVIDER"] = OID_NONE
|
310
|
+
app.config["OID_CLIENT_ID"] = "SOME_SECRET"
|
311
|
+
app.config["OID_TENANT_ID"] = "SOME_SECRET"
|
312
|
+
app.config["OID_ISSUER"] = "SOME_SECRET"
|
313
|
+
return app
|
314
|
+
|
315
|
+
def setUp(self):
|
316
|
+
log.root.setLevel(current_app.config["LOG_LEVEL"])
|
317
|
+
db.create_all()
|
318
|
+
access_init_command(verbose=False)
|
319
|
+
register_deployed_dags_command_test(verbose=False)
|
320
|
+
|
321
|
+
self.service_data = {
|
322
|
+
"username": "service_user",
|
323
|
+
"email": "service@test.com",
|
324
|
+
"password": "Testpassword1!",
|
325
|
+
}
|
326
|
+
|
327
|
+
service_user = UserModel(data=self.service_data)
|
328
|
+
service_user.save()
|
329
|
+
|
330
|
+
self.service_data.pop("email")
|
331
|
+
self.service_user_id = service_user.id
|
332
|
+
|
333
|
+
self.assign_role(self.service_user_id, SERVICE_ROLE)
|
334
|
+
|
335
|
+
def test_service_user_login(self):
|
336
|
+
"""
|
337
|
+
Tests that a service user can not log in with username and password
|
338
|
+
"""
|
339
|
+
response = self.client.post(
|
340
|
+
LOGIN_URL,
|
341
|
+
data=json.dumps({"token": "some_token"}),
|
342
|
+
headers={"Content-Type": "application/json"},
|
343
|
+
)
|
344
|
+
|
345
|
+
self.assertEqual(501, response.status_code)
|
346
|
+
self.assertEqual(
|
347
|
+
response.json["error"], "The OID provider configuration is not valid"
|
348
|
+
)
|
349
|
+
|
350
|
+
|
351
|
+
class TestLogInOpenAuthOther(CustomTestCase):
|
352
|
+
def create_app(self):
|
353
|
+
"""
|
354
|
+
Creates and configures a Flask application for testing.
|
355
|
+
|
356
|
+
:returns: A configured Flask application instance
|
357
|
+
:rtype: Flask
|
358
|
+
"""
|
359
|
+
app = create_app("testing-oauth")
|
360
|
+
app.config["SERVICE_USER_ALLOW_PASSWORD_LOGIN"] = 0
|
361
|
+
app.config["OID_PROVIDER"] = 3
|
362
|
+
app.config["OID_CLIENT_ID"] = "SOME_SECRET"
|
363
|
+
app.config["OID_TENANT_ID"] = "SOME_SECRET"
|
364
|
+
app.config["OID_ISSUER"] = "SOME_SECRET"
|
365
|
+
return app
|
366
|
+
|
367
|
+
def setUp(self):
|
368
|
+
log.root.setLevel(current_app.config["LOG_LEVEL"])
|
369
|
+
db.create_all()
|
370
|
+
access_init_command(verbose=False)
|
371
|
+
register_deployed_dags_command_test(verbose=False)
|
372
|
+
|
373
|
+
self.service_data = {
|
374
|
+
"username": "service_user",
|
375
|
+
"email": "service@test.com",
|
376
|
+
"password": "Testpassword1!",
|
377
|
+
}
|
378
|
+
|
379
|
+
service_user = UserModel(data=self.service_data)
|
380
|
+
service_user.save()
|
381
|
+
|
382
|
+
self.service_data.pop("email")
|
383
|
+
self.service_user_id = service_user.id
|
384
|
+
|
385
|
+
self.assign_role(self.service_user_id, SERVICE_ROLE)
|
386
|
+
|
387
|
+
def test_service_user_login(self):
|
388
|
+
"""
|
389
|
+
Tests that a service user can not log in with username and password
|
390
|
+
"""
|
391
|
+
response = self.client.post(
|
392
|
+
LOGIN_URL,
|
393
|
+
data=json.dumps({"token": "some_token"}),
|
394
|
+
headers={"Content-Type": "application/json"},
|
395
|
+
)
|
396
|
+
|
397
|
+
self.assertEqual(501, response.status_code)
|
398
|
+
self.assertEqual(
|
399
|
+
response.json["error"], "The OID provider configuration is not valid"
|
400
|
+
)
|
401
|
+
|
402
|
+
|
403
|
+
class TestLogInOpenAuthService(CustomTestCase):
|
404
|
+
|
405
|
+
def create_app(self):
|
406
|
+
"""
|
407
|
+
Creates and configures a Flask application for testing.
|
408
|
+
|
409
|
+
:returns: A configured Flask application instance
|
410
|
+
:rtype: Flask
|
411
|
+
"""
|
412
|
+
app = create_app("testing-oauth")
|
413
|
+
return app
|
414
|
+
|
415
|
+
def setUp(self):
|
416
|
+
log.root.setLevel(current_app.config["LOG_LEVEL"])
|
417
|
+
db.create_all()
|
418
|
+
access_init_command(verbose=False)
|
419
|
+
register_deployed_dags_command_test(verbose=False)
|
420
|
+
self.user_data = {
|
421
|
+
"username": "testname",
|
422
|
+
"email": "test@test.com",
|
423
|
+
"password": "Testpassword1!",
|
424
|
+
}
|
425
|
+
|
426
|
+
test_user = UserModel(data=self.user_data)
|
427
|
+
test_user.save()
|
428
|
+
|
429
|
+
self.user_data.pop("email")
|
430
|
+
|
431
|
+
self.test_user_id = test_user.id
|
432
|
+
|
433
|
+
self.service_data = {
|
434
|
+
"username": "service_user",
|
435
|
+
"email": "service@test.com",
|
436
|
+
"password": "Testpassword1!",
|
437
|
+
}
|
438
|
+
|
439
|
+
service_user = UserModel(data=self.service_data)
|
440
|
+
service_user.save()
|
441
|
+
|
442
|
+
self.service_data.pop("email")
|
443
|
+
self.service_user_id = service_user.id
|
444
|
+
|
445
|
+
self.assign_role(self.service_user_id, SERVICE_ROLE)
|
446
|
+
|
447
|
+
def test_service_user_login(self):
|
448
|
+
"""
|
449
|
+
Tests that a service user can log in with username and password
|
450
|
+
"""
|
451
|
+
|
452
|
+
response = self.client.post(
|
453
|
+
LOGIN_URL,
|
454
|
+
data=json.dumps(self.service_data),
|
455
|
+
headers={"Content-Type": "application/json"},
|
456
|
+
)
|
457
|
+
|
458
|
+
self.assertEqual(200, response.status_code)
|
459
|
+
self.assertEqual(self.service_user_id, response.json["id"])
|
460
|
+
|
461
|
+
def test_validation_error(self):
|
462
|
+
"""
|
463
|
+
Tests that a user can not log in without token or username and password
|
464
|
+
"""
|
465
|
+
response = self.client.post(
|
466
|
+
LOGIN_URL,
|
467
|
+
data=json.dumps({}),
|
468
|
+
headers={"Content-Type": "application/json"},
|
469
|
+
)
|
470
|
+
|
471
|
+
self.assertEqual(400, response.status_code)
|
472
|
+
|
473
|
+
def test_other_user_password(self):
|
474
|
+
"""
|
475
|
+
Tests that a user can not log in with username and password
|
476
|
+
"""
|
477
|
+
response = self.client.post(
|
478
|
+
LOGIN_URL,
|
479
|
+
data=json.dumps(self.user_data),
|
480
|
+
headers={"Content-Type": "application/json"},
|
481
|
+
)
|
482
|
+
|
483
|
+
self.assertEqual(400, response.status_code)
|
484
|
+
self.assertEqual(response.json["error"], "Invalid request")
|
485
|
+
|
486
|
+
def test_token_login(self):
|
487
|
+
"""
|
488
|
+
Tests that a user can log in with a token
|
489
|
+
"""
|
490
|
+
response = self.client.post(
|
491
|
+
LOGIN_URL,
|
492
|
+
data=json.dumps({"token": "test"}),
|
493
|
+
headers={"Content-Type": "application/json"},
|
494
|
+
)
|
495
|
+
|
496
|
+
self.assertEqual(501, response.status_code)
|
497
|
+
self.assertEqual(
|
498
|
+
response.json["error"], "The OID provider configuration is not valid"
|
499
|
+
)
|
500
|
+
|
501
|
+
def test_log_in_with_all_fields(self):
|
502
|
+
"""
|
503
|
+
Tests that a user can not log in with username and password and a token
|
504
|
+
"""
|
505
|
+
response = self.client.post(
|
506
|
+
LOGIN_URL,
|
507
|
+
data=json.dumps({**self.service_data, "token": "test"}),
|
508
|
+
headers={"Content-Type": "application/json"},
|
509
|
+
)
|
510
|
+
|
511
|
+
self.assertEqual(400, response.status_code)
|