Skip to content

Commit 8af0ee9

Browse files
committed
Fix homecontroller tests
1 parent 3f319c2 commit 8af0ee9

19 files changed

+153
-87
lines changed

Pipfile

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ quart = "*"
2828
pytest-flask = "*"
2929
pytest = "*"
3030
pytest-asyncio = "*"
31+
beautifulsoup4 = "*"
3132

3233
[requires]
3334
python_version = "3.12"

Pipfile.lock

+33-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pytest.ini

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# pytest.ini or .pytest.ini
2+
[pytest]
3+
minversion = 8.3.2
4+
addopts = -ra -q
5+
testpaths =
6+
test
7+
asyncio_mode = auto
8+
asyncio_default_fixture_loop_scope = function

src/app.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import quart_flask_patch, json, logging, os
66
from quart import Quart, request
77
from flask_healthz import HealthError
8-
from datetime import datetime
8+
from datetime import datetime, timezone
99
from src.controllers.AuthenticationController import auth_api as auth_blueprint
1010
from src.controllers.UserController import user_api as user_blueprint
1111
from src.controllers.AuthorController import author_api as author_blueprint

src/common/Authentication.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import jwt, datetime, logging
1+
import jwt, logging
2+
from datetime import datetime, timezone
23
from quart import json, Response, session, redirect, url_for, session, abort, current_app
34
#from flask_oidc import OpenIDConnect
45
from functools import wraps
@@ -19,7 +20,7 @@ def generate_token(user_id):
1920
raise Exception("Invalid user id!")
2021
if user_id:
2122
try:
22-
now = datetime.datetime.utcnow()
23+
now = datetime.now(timezone.utc)
2324
# https://pyjwt.readthedocs.io/en/latest/usage.html#registered-claim-names
2425
payload = {
2526
"exp": now + datetime.timedelta(hours=1),
@@ -94,7 +95,6 @@ def decorated_auth_required(*args, **kwargs):
9495
# @staticmethod
9596
# def isAuthenticated():
9697
# return oidc.user_loggedin and "user" in session and "token" in session["user"]
97-
9898
@staticmethod
9999
def require_role(role):
100100
def decorated_require_role(func):

src/controllers/AuthenticationController.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import logging
22
from quart import request, json, Blueprint, session, render_template, session, redirect, url_for
33
from marshmallow import ValidationError
4-
from datetime import datetime
4+
from datetime import datetime, timezone
55
from base64 import b64decode
66
from ..models.UserModel import UserModel, UserSchema
77
from ..common.Authentication import Authentication
@@ -11,7 +11,7 @@
1111
user_schema = UserSchema()
1212
@auth_api.context_processor
1313
def inject_now():
14-
return {'now': datetime.utcnow()}
14+
return {'now': datetime.now(timezone.utc)}
1515

1616
@auth_api.route("/login", methods=["GET", "POST"])
1717
async def login():
@@ -43,7 +43,7 @@ async def login():
4343
token = Authentication.generate_token(ser_data.get("id"))
4444
session["user"] = {"id": ser_data.get("id"), "email": user.email, "token": token}
4545
#return custom_response({"jwt_token": token}, 200)
46-
data["lastlogin"] = datetime.utcnow()
46+
data["lastlogin"] = datetime.now(timezone.utc)
4747
user.update(data)
4848
logging.info(f"[Auth] User {user.email} logged in")
4949
if "url" in session and session["url"]:

src/controllers/AuthorController.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import re, logging
22
from quart import request, Blueprint, session, render_template, flash, redirect, url_for
33
from marshmallow import ValidationError
4-
from datetime import datetime
4+
from datetime import datetime, timezone
55
from ..common.Authentication import Authentication
66
from ..common.Response import custom_response
77
from ..models.AuthorModel import AuthorModel, AuthorSchema
88
author_api = Blueprint("author", __name__)
99
author_schema = AuthorSchema()
1010
@author_api.context_processor
1111
def inject_now():
12-
return {'now': datetime.utcnow()}
12+
return {'now': datetime.now(timezone.utc)}
1313

1414
@author_api.route("/index", methods=["GET"])
1515
async def index():

src/controllers/BookController.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import re, logging
22
from quart import request, json, Blueprint, session, render_template, flash, redirect, url_for
3-
from datetime import datetime
3+
from datetime import datetime, timezone
44
from marshmallow import ValidationError
55
from ..common.Authentication import Authentication
66
from ..common.Response import custom_response
@@ -12,7 +12,7 @@
1212
author_schema = AuthorSchema()
1313
@book_api.context_processor
1414
def inject_now():
15-
return {'now': datetime.utcnow()}
15+
return {'now': datetime.now(timezone.utc)}
1616

1717
@book_api.route("/index", methods=["GET"])
1818
async def index():

src/controllers/FibonacciController.py

+19-15
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
from quart import request, session, Blueprint, flash, render_template, session
22
from quart.utils import run_sync
3-
from datetime import datetime
3+
from datetime import datetime, timezone
44
from array import array
55
from ..common.Response import custom_response
66
from ..common.Authentication import Authentication
77
from ..models.UserModel import UserModel
8-
import re
8+
from urllib.parse import urlparse, parse_qs
99
fibonacci_api = Blueprint("fibonacci", __name__)
1010
@fibonacci_api.context_processor
1111
def inject_now():
12-
return {'now': datetime.utcnow()}
12+
return {'now': datetime.now(timezone.utc)}
1313

1414
@fibonacci_api.route("/", methods=["GET", "POST"])
1515
async def fibonacci():
16+
print("fibonacci()")
1617
fibonacci = None
1718
error = None
1819
user = None
@@ -26,18 +27,21 @@ async def fibonacci():
2627
if not user:
2728
return await render_template("login.html", title="Welcome to Python Flask RESTful API", error="Invalid user!")
2829
if request.method == "POST":
29-
form = await request.form
30-
if form['n']:
31-
n = form["n"]
32-
if n and n.strip():
33-
if n.isnumeric():
34-
try:
35-
fibonacci = f"Hello {('there' if not user else user.firstname)}, fibonacci(" + n + "): " + str(await run_sync(fib)(int(n)))
36-
"""Renders a greetings page."""
37-
except (Exception) as error:
38-
error = "Exception {0}".format(error)
39-
await flash(f"Fibonacci {n} failed! {error}", "danger")
40-
return await render_template("fibonacci.html", title="Welcome to Python Flask Fibonacci calculator")
30+
print("fibonacci() POST")
31+
data = await request.get_data()
32+
params = parse_qs(data.decode('utf-8'))
33+
print(f"data: {data}, params: {params}")
34+
if params['n'] and params["n"][0].strip() and params["n"][0].strip().isdigit():
35+
n = int(params["n"][0].strip())
36+
print(f"fibonacci(): {n}")
37+
try:
38+
result = await run_sync(fib)(n)
39+
print(f"result: {result}")
40+
fibonacci = f"Hello {('there' if not user else user.firstname)}, fibonacci({n}): {await run_sync(fib)(n)}"
41+
except (Exception) as error:
42+
error = "Exception {0}".format(error)
43+
await flash(f"Fibonacci {n} failed! {error}", "danger")
44+
return await render_template("fibonacci.html", title="Welcome to Python Flask Fibonacci calculator")
4145
if not fibonacci:
4246
#error = custom_response({"error": "Please provide an 'N' for the fibonacci number!"}, 400)
4347
await flash("Please provide a numeric value 'N' for the fibonacci number!", "danger")

src/controllers/HomeController.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
from quart import Blueprint, render_template, session
2-
from datetime import datetime
2+
from datetime import datetime, timezone
33
from ..common.Authentication import Authentication
44
from ..models.UserModel import UserModel
55
import re
66
home_api = Blueprint("home", __name__)
77
@home_api.context_processor
88
def inject_now():
9-
return {'now': datetime.utcnow()}
9+
return {'now': datetime.now(timezone.utc)}
1010

1111
@home_api.route("/")
1212
@home_api.route("/index")

src/controllers/UserController.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import re, logging
22
from quart import request, Blueprint, session, render_template, flash, redirect, url_for
33
from marshmallow import ValidationError
4-
from datetime import datetime
4+
from datetime import datetime, timezone
55
from ..models.UserModel import UserModel, UserSchema
66
from ..common.Authentication import Authentication
77
from ..common.Response import custom_response
88
user_api = Blueprint("user", __name__)
99
user_schema = UserSchema()
1010
@user_api.context_processor
1111
def inject_now():
12-
return {'now': datetime.utcnow()}
12+
return {'now': datetime.now(timezone.utc)}
1313

1414
@user_api.route("/index", methods=["GET"])
1515
async def index():

src/models/AuthorModel.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from marshmallow import fields, Schema
22
from sqlalchemy.sql import func
33
from .BookModel import BookSchema
4-
import datetime
4+
from datetime import datetime, timezone
55
from . import db, bcrypt
66

77
class AuthorModel(db.Model):

src/models/BookModel.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from . import db
22
from marshmallow import fields, Schema
33
from sqlalchemy.sql import func
4-
import datetime
4+
from datetime import datetime, timezone
55

66
class BookModel(db.Model):
77
"""

src/models/UserModel.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from marshmallow import fields, Schema
22
from sqlalchemy.sql import func
3-
import datetime
3+
from datetime import datetime, timezone
44
from . import db, bcrypt
55
from .BookModel import BookSchema
66
class UserModel(db.Model):

test/authentication_test.py

+7-26
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,23 @@
11
import pytest, sys, asyncio
2-
from hypercorn.config import Config
3-
from hypercorn.asyncio import serve
42
from os.path import dirname, join, abspath
5-
from src.app import create_app
63
#from src.main import app
74
from quart_cors import cors
85
sys.path.insert(0, abspath(join(dirname(__file__), '../src')))
96
from common.Authentication import Authentication
10-
pytest_plugins = ('pytest_asyncio',)
117

12-
@pytest.fixture()
13-
async def app_context():
14-
config = Config()
15-
config.bind = ["localhost:4433"]
16-
config.insecure_bind = ["localhost:8080"]
17-
config.worker_class = "asyncio"
18-
config.alt_svc_headers = ["h3=\":443\"; ma=3600, h3-29=\":443\"; ma=3600"]
19-
config.loglevel = "DEBUG"
20-
config.quic_bind = ["localhost:4433"]
21-
app = create_app()
22-
app = cors(app, allow_credentials=True, allow_origin="https://localhost:4433")
23-
asyncio.run(serve(app, config))
24-
async with app.app_context() as app_context:
25-
yield app_context
26-
@pytest.mark.asyncio
27-
async def test_tokengeneration_pass(app_context):
8+
def test_tokengeneration_pass():
289
""" JWT token generation should pass with valid user input parameter """
2910
token = Authentication.generate_token("test_user")
3011
assert type(token) is str
3112
assert token != ""
32-
@pytest.mark.asyncio
33-
async def test_tokengeneration_fail(app_context):
13+
14+
def test_tokengeneration_fail():
3415
""" JWT token generation should fail without valid user input parameter """
3516
with pytest.raises(Exception) as e:
3617
token = Authentication.generate_token("")
3718
assert "Invalid user id!" in str(e.value)
38-
@pytest.mark.asyncio
39-
async def test_tokendecoding_pass(app_context):
19+
20+
def test_tokendecoding_pass():
4021
""" JWT token decoding should pass with valid user input parameter """
4122
token = Authentication.generate_token("test_user")
4223
assert type(token) is str
@@ -49,8 +30,8 @@ async def test_tokendecoding_pass(app_context):
4930
assert decode["data"]["user_id"] == "test_user"
5031
expect = dict(data=dict(user_id="test_user"), error=dict())
5132
assert decode == expect
52-
@pytest.mark.asyncio
53-
async def test_tokendecoding_fail(app_context):
33+
34+
def test_tokendecoding_fail():
5435
""" JWT token decoding should fail without valid user input parameter """
5536
with pytest.raises(Exception) as e:
5637
token = Authentication.decode_token("")

test/conftest.py

+22-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,32 @@
1-
import pytest
1+
import pytest, sys, asyncio
22
import os, sys
33
from src.main import app
4+
#from src.app import create_app
5+
from hypercorn.config import Config
6+
from hypercorn.asyncio import serve
47
from os.path import dirname, join, abspath
58
sys.path.insert(0, abspath(join(dirname(__file__), '../src')))
9+
pytest_plugins = ('pytest_asyncio',)
610

7-
@pytest.fixture
11+
@pytest.fixture(scope="function")
812
def client():
913
return app.test_client()
1014

15+
@pytest.fixture(scope="function")
16+
async def app_context():
17+
config = Config()
18+
config.bind = ["localhost:4433"]
19+
config.insecure_bind = ["localhost:8080"]
20+
config.worker_class = "asyncio"
21+
config.alt_svc_headers = ["h3=\":443\"; ma=3600, h3-29=\":443\"; ma=3600"]
22+
config.loglevel = "DEBUG"
23+
config.quic_bind = ["localhost:4433"]
24+
#app = create_app()
25+
#app = cors(app, allow_credentials=True, allow_origin="https://localhost:4433")
26+
#asyncio.run(serve(app, config))
27+
async with app.app_context() as app_context:
28+
yield app_context
29+
1130
def pytest_generate_tests(metafunc):
31+
""" called once per each test function """
1232
os.environ['JWT_SECRET_KEY'] = 'pythonflaskrestapipostgres'

0 commit comments

Comments
 (0)