FlaskTester 3.4__tar.gz → 3.6__tar.gz
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.
- {FlaskTester-3.4 → FlaskTester-3.6}/FlaskTester.egg-info/PKG-INFO +4 -4
- {FlaskTester-3.4 → FlaskTester-3.6}/FlaskTester.egg-info/SOURCES.txt +2 -1
- {FlaskTester-3.4 → FlaskTester-3.6}/FlaskTester.py +27 -20
- {FlaskTester-3.4 → FlaskTester-3.6}/PKG-INFO +4 -4
- {FlaskTester-3.4 → FlaskTester-3.6}/README.md +3 -3
- {FlaskTester-3.4 → FlaskTester-3.6}/pyproject.toml +1 -1
- FlaskTester-3.4/tests/test.py → FlaskTester-3.6/tests/test_app.py +14 -11
- FlaskTester-3.6/tests/test_app2.py +28 -0
- {FlaskTester-3.4 → FlaskTester-3.6}/FlaskTester.egg-info/dependency_links.txt +0 -0
- {FlaskTester-3.4 → FlaskTester-3.6}/FlaskTester.egg-info/requires.txt +0 -0
- {FlaskTester-3.4 → FlaskTester-3.6}/FlaskTester.egg-info/top_level.txt +0 -0
- {FlaskTester-3.4 → FlaskTester-3.6}/LICENSE +0 -0
- {FlaskTester-3.4 → FlaskTester-3.6}/MANIFEST.in +0 -0
- {FlaskTester-3.4 → FlaskTester-3.6}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: FlaskTester
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.6
|
|
4
4
|
Summary: Pytest fixtures for Flask internal and external authenticated tests
|
|
5
5
|
Author-email: Fabien Coelho <flask.tester@coelho.net>
|
|
6
6
|
License: CC0
|
|
@@ -52,7 +52,7 @@ Only one set of tests is needed, switching from internal to external is
|
|
|
52
52
|
achieved through environment variables.
|
|
53
53
|
|
|
54
54
|

|
|
55
|
-

|
|
56
56
|

|
|
57
57
|

|
|
58
58
|

|
|
@@ -107,7 +107,7 @@ This can be run against a (local) server:
|
|
|
107
107
|
export TEST_SEED="some-random-data" # shared test seed
|
|
108
108
|
flask --app app:app run & # start flask app
|
|
109
109
|
pid=$! # keep pid
|
|
110
|
-
export
|
|
110
|
+
export FLASK_TESTER_APP="http://localhost:5000" # set app local url
|
|
111
111
|
pytest test.py # run external tests
|
|
112
112
|
kill $pid # stop app with pid
|
|
113
113
|
```
|
|
@@ -115,7 +115,7 @@ kill $pid # stop app with pid
|
|
|
115
115
|
Or locally with the Flask internal test infrastructure:
|
|
116
116
|
|
|
117
117
|
```shell
|
|
118
|
-
export FLASK_TESTER_APP="app:app" # set app
|
|
118
|
+
export FLASK_TESTER_APP="app:app" # set app package
|
|
119
119
|
pytest test.py # run internal tests
|
|
120
120
|
```
|
|
121
121
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""FlaskTester - Pytest fixtures for Flask authenticated internal and external tests.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
used depending on the ``assert``: PYTEST_DONT_REWRITE
|
|
3
|
+
PYTEST_DONT_REWRITE: local assertions are really that, not pytest assertions.
|
|
5
4
|
"""
|
|
6
5
|
|
|
7
6
|
import os
|
|
@@ -25,6 +24,20 @@ class AuthError(FlaskTesterError):
|
|
|
25
24
|
pass
|
|
26
25
|
|
|
27
26
|
|
|
27
|
+
class _AssertError(FlaskTesterError):
|
|
28
|
+
"""User assertion Exception, only for internal testing."""
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _raiseError(msg: str):
|
|
33
|
+
"""Undocumented switch for FlaskTester own tests."""
|
|
34
|
+
log.error(msg)
|
|
35
|
+
if "FLASK_TESTER_TESTING" in os.environ:
|
|
36
|
+
raise _AssertError(msg)
|
|
37
|
+
else: # pragma: no cover # cannot cover an expected pytest failure!
|
|
38
|
+
pytest.fail(msg)
|
|
39
|
+
|
|
40
|
+
|
|
28
41
|
class Authenticator:
|
|
29
42
|
"""Manage HTTP request authentication.
|
|
30
43
|
|
|
@@ -336,14 +349,12 @@ class Client:
|
|
|
336
349
|
# check status
|
|
337
350
|
if status is not None:
|
|
338
351
|
if res.status_code != status: # show error before aborting
|
|
339
|
-
|
|
340
|
-
assert res.status_code == status, f"unexpected status {res.status_code}, expecting {status}"
|
|
352
|
+
_raiseError(f"bad {status} result: {res.status_code} {res.text[:512]}...")
|
|
341
353
|
|
|
342
354
|
# check content
|
|
343
355
|
if content is not None:
|
|
344
356
|
if not re.search(content, res.text, re.DOTALL):
|
|
345
|
-
|
|
346
|
-
assert False, f"expected content {content} not found in {res.text}"
|
|
357
|
+
_raiseError(f"cannot find {content} in {res.text[:512]}...")
|
|
347
358
|
|
|
348
359
|
return res
|
|
349
360
|
|
|
@@ -521,15 +532,14 @@ def _ft_client(authenticator):
|
|
|
521
532
|
default_login = os.environ.get("FLASK_TESTER_DEFAULT", None)
|
|
522
533
|
client: Client
|
|
523
534
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
app_url = os.environ["FLASK_TESTER_URL"]
|
|
527
|
-
client = RequestClient(authenticator, app_url, default_login)
|
|
528
|
-
|
|
529
|
-
elif "FLASK_TESTER_APP" in os.environ:
|
|
535
|
+
app_def = os.environ.get("FLASK_TESTER_URL", "app")
|
|
536
|
+
app_def = os.environ.get("FLASK_TESTER_APP", app_def)
|
|
530
537
|
|
|
538
|
+
if app_def.startswith("http://") or app_def.startswith("https://"):
|
|
539
|
+
client = RequestClient(authenticator, app_def, default_login)
|
|
540
|
+
else:
|
|
531
541
|
# load app package
|
|
532
|
-
pkg_name, app =
|
|
542
|
+
pkg_name, app = app_def, None
|
|
533
543
|
app_names = ["app", "application", "create_app", "make_app"]
|
|
534
544
|
if ":" in pkg_name: # override defaults
|
|
535
545
|
pkg_name, app_name = pkg_name.split(":", 1)
|
|
@@ -546,20 +556,17 @@ def _ft_client(authenticator):
|
|
|
546
556
|
raise FlaskTesterError(f"cannot find Flask app in {pkg_name}")
|
|
547
557
|
client = FlaskClient(authenticator, app.test_client(), default_login)
|
|
548
558
|
|
|
549
|
-
else:
|
|
550
|
-
|
|
551
|
-
raise FlaskTesterError("no Flask application to test")
|
|
552
|
-
|
|
553
559
|
return client
|
|
554
560
|
|
|
555
561
|
@pytest.fixture
|
|
556
562
|
def ft_client(ft_authenticator):
|
|
557
563
|
"""Pytest Fixture: ft_client.
|
|
558
564
|
|
|
559
|
-
Target environment variable
|
|
565
|
+
Target environment variable:
|
|
560
566
|
|
|
561
|
-
- ``
|
|
562
|
-
|
|
567
|
+
- ``FLASK_TESTER_APP``: find the Flask application, eg
|
|
568
|
+
``app:create_app`` for an internal test, or
|
|
569
|
+
``http://localhost:5000`` for an external test.
|
|
563
570
|
|
|
564
571
|
Other environment variable:
|
|
565
572
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: FlaskTester
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.6
|
|
4
4
|
Summary: Pytest fixtures for Flask internal and external authenticated tests
|
|
5
5
|
Author-email: Fabien Coelho <flask.tester@coelho.net>
|
|
6
6
|
License: CC0
|
|
@@ -52,7 +52,7 @@ Only one set of tests is needed, switching from internal to external is
|
|
|
52
52
|
achieved through environment variables.
|
|
53
53
|
|
|
54
54
|

|
|
55
|
-

|
|
56
56
|

|
|
57
57
|

|
|
58
58
|

|
|
@@ -107,7 +107,7 @@ This can be run against a (local) server:
|
|
|
107
107
|
export TEST_SEED="some-random-data" # shared test seed
|
|
108
108
|
flask --app app:app run & # start flask app
|
|
109
109
|
pid=$! # keep pid
|
|
110
|
-
export
|
|
110
|
+
export FLASK_TESTER_APP="http://localhost:5000" # set app local url
|
|
111
111
|
pytest test.py # run external tests
|
|
112
112
|
kill $pid # stop app with pid
|
|
113
113
|
```
|
|
@@ -115,7 +115,7 @@ kill $pid # stop app with pid
|
|
|
115
115
|
Or locally with the Flask internal test infrastructure:
|
|
116
116
|
|
|
117
117
|
```shell
|
|
118
|
-
export FLASK_TESTER_APP="app:app" # set app
|
|
118
|
+
export FLASK_TESTER_APP="app:app" # set app package
|
|
119
119
|
pytest test.py # run internal tests
|
|
120
120
|
```
|
|
121
121
|
|
|
@@ -9,7 +9,7 @@ Only one set of tests is needed, switching from internal to external is
|
|
|
9
9
|
achieved through environment variables.
|
|
10
10
|
|
|
11
11
|

|
|
12
|
-

|
|
13
13
|

|
|
14
14
|

|
|
15
15
|

|
|
@@ -64,7 +64,7 @@ This can be run against a (local) server:
|
|
|
64
64
|
export TEST_SEED="some-random-data" # shared test seed
|
|
65
65
|
flask --app app:app run & # start flask app
|
|
66
66
|
pid=$! # keep pid
|
|
67
|
-
export
|
|
67
|
+
export FLASK_TESTER_APP="http://localhost:5000" # set app local url
|
|
68
68
|
pytest test.py # run external tests
|
|
69
69
|
kill $pid # stop app with pid
|
|
70
70
|
```
|
|
@@ -72,7 +72,7 @@ kill $pid # stop app with pid
|
|
|
72
72
|
Or locally with the Flask internal test infrastructure:
|
|
73
73
|
|
|
74
74
|
```shell
|
|
75
|
-
export FLASK_TESTER_APP="app:app" # set app
|
|
75
|
+
export FLASK_TESTER_APP="app:app" # set app package
|
|
76
76
|
pytest test.py # run internal tests
|
|
77
77
|
```
|
|
78
78
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "FlaskTester"
|
|
7
|
-
version = "3.
|
|
7
|
+
version = "3.6"
|
|
8
8
|
authors = [ { name = "Fabien Coelho", email = "flask.tester@coelho.net" } ]
|
|
9
9
|
description = "Pytest fixtures for Flask internal and external authenticated tests"
|
|
10
10
|
readme = "README.md"
|
|
@@ -15,6 +15,7 @@ logging.basicConfig(level=logging.INFO)
|
|
|
15
15
|
|
|
16
16
|
# set authn for ft_authenticator
|
|
17
17
|
os.environ.update(
|
|
18
|
+
FLASK_TESTER_TESTING="*",
|
|
18
19
|
FLASK_TESTER_ALLOW="bearer basic param none",
|
|
19
20
|
FLASK_TESTER_AUTH=",".join(f"{l}:{p}" for l, p in secret.PASSES.items()),
|
|
20
21
|
)
|
|
@@ -109,25 +110,32 @@ def test_admin(api):
|
|
|
109
110
|
api.get("/admin", 403, login="hobbes", auth=auth)
|
|
110
111
|
api.get("/admin", 401, login="moe", auth=auth)
|
|
111
112
|
api.get("/admin", 401, login=None, auth=auth)
|
|
113
|
+
# test status error
|
|
112
114
|
try:
|
|
113
115
|
api.get("/admin", status=599, login="calvin", auth=auth)
|
|
114
116
|
pytest.fail("assert on status must fail") # pragma: no cover
|
|
115
|
-
except
|
|
117
|
+
except ft._AssertError as e:
|
|
116
118
|
assert "200" in str(e)
|
|
119
|
+
# test content error
|
|
117
120
|
try:
|
|
118
121
|
api.get("/admin", status=200, login="calvin", auth=auth, content="NOT THERE")
|
|
119
122
|
pytest.fail("assert on content must fail") # pragma: no cover
|
|
120
|
-
except
|
|
123
|
+
except ft._AssertError as e:
|
|
121
124
|
assert "NOT THERE" in str(e)
|
|
122
125
|
|
|
123
126
|
def test_errors(api):
|
|
124
127
|
# these schemes are not allowed
|
|
125
|
-
for scheme in ("header", "cookie", "fake", "tparam"
|
|
128
|
+
for scheme in ("header", "cookie", "fake", "tparam"):
|
|
126
129
|
try:
|
|
127
130
|
api.get("/login", login="calvin", auth=scheme)
|
|
128
131
|
pytest.fail("must raise an exception") # pragma: no cover
|
|
129
132
|
except ft.AuthError as e:
|
|
130
|
-
assert
|
|
133
|
+
assert "auth is not allowed" in str(e)
|
|
134
|
+
try:
|
|
135
|
+
api.get("/login", login="calvin", auth="foobla")
|
|
136
|
+
pytest.fail("must raise an exception") # pragma: no cover
|
|
137
|
+
except ft.AuthError as e:
|
|
138
|
+
assert "unexpected auth" in str(e)
|
|
131
139
|
|
|
132
140
|
def test_methods(api):
|
|
133
141
|
res = api.get("/who-am-i", login="susie", status=200, cookies={"lang": "it"})
|
|
@@ -301,7 +309,6 @@ def test_client_fixture():
|
|
|
301
309
|
# ft_client coverage
|
|
302
310
|
auth = ft._ft_authenticator()
|
|
303
311
|
# check and save env
|
|
304
|
-
# assert "FLASK_TESTER_URL" not in os.environ
|
|
305
312
|
url = None
|
|
306
313
|
if "FLASK_TESTER_URL" in os.environ: # pragma: no cover
|
|
307
314
|
url = os.environ["FLASK_TESTER_URL"]
|
|
@@ -310,12 +317,8 @@ def test_client_fixture():
|
|
|
310
317
|
if "FLASK_TESTER_APP" in os.environ:
|
|
311
318
|
app = os.environ["FLASK_TESTER_APP"]
|
|
312
319
|
del os.environ["FLASK_TESTER_APP"]
|
|
313
|
-
# no url nor app
|
|
314
|
-
|
|
315
|
-
init = ft._ft_client(auth)
|
|
316
|
-
pytest.fail("must fail without environment variables") # pragma: no cover
|
|
317
|
-
except ft.FlaskTesterError:
|
|
318
|
-
assert True, "expected error raised"
|
|
320
|
+
# no url nor app, defaults to "app"
|
|
321
|
+
init = ft._ft_client(auth)
|
|
319
322
|
# url
|
|
320
323
|
os.environ["FLASK_TESTER_URL"] = "http://localhost:5000"
|
|
321
324
|
init = ft._ft_client(auth)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import pytest
|
|
3
|
+
from FlaskTester import ft_client, ft_authenticator
|
|
4
|
+
|
|
5
|
+
os.environ.update(FLASK_TESTER_ALLOW="basic param none")
|
|
6
|
+
|
|
7
|
+
@pytest.fixture
|
|
8
|
+
def app(ft_client):
|
|
9
|
+
ft_client.setPass("calvin", "clv-pw")
|
|
10
|
+
ft_client.setCookie("calvin", "lang", "en")
|
|
11
|
+
ft_client.setPass("hobbes", "hbs-pw")
|
|
12
|
+
ft_client.setCookie("hobbes", "lang", "fr")
|
|
13
|
+
yield ft_client
|
|
14
|
+
|
|
15
|
+
def test_something(app):
|
|
16
|
+
# requires an authentication
|
|
17
|
+
app.get("/authenticated", 401, login=None)
|
|
18
|
+
res = app.get("/authenticated", 200, login="calvin")
|
|
19
|
+
assert "Hello" in res.text
|
|
20
|
+
app.get("/authenticated", 200, "Bonjour", login="hobbes")
|
|
21
|
+
# only allowed to calvin
|
|
22
|
+
app.get("/only-calvin", 401, login=None)
|
|
23
|
+
app.get("/only-calvin", 200, login="calvin")
|
|
24
|
+
app.get("/only-calvin", 403, login="hobbes")
|
|
25
|
+
# no authentication required, but depends on lang
|
|
26
|
+
res = app.get("/no-auth", 200, login="calvin", auth="none")
|
|
27
|
+
assert "Hello" in res.text
|
|
28
|
+
app.get("/no-auth", 200, "Bonjour", login="hobbes", auth="none")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|