From c90e67c179cfa750bab8bb92a85016874e7081df Mon Sep 17 00:00:00 2001 From: David Baumgold Date: Fri, 5 Jan 2024 00:33:38 +0100 Subject: [PATCH] fix tests for werkzeug 3 (#426) * fix tests for werkzeug 3 * Pin Pillow to 9.5 so docs can build --------- Co-authored-by: Ryan Schaffer --- flask_dance/consumer/base.py | 6 ++-- pyproject.toml | 1 + tests/consumer/storage/test_sqla.py | 1 + tests/consumer/test_oauth1.py | 10 +++--- tests/consumer/test_oauth2.py | 29 ++++++++-------- tests/contrib/test_gitlab.py | 1 + tests/contrib/test_slack.py | 51 +++++++++++++++-------------- 7 files changed, 52 insertions(+), 47 deletions(-) diff --git a/flask_dance/consumer/base.py b/flask_dance/consumer/base.py index 13ac398..e7a9e32 100644 --- a/flask_dance/consumer/base.py +++ b/flask_dance/consumer/base.py @@ -134,8 +134,8 @@ def token(self): # Update the `expires_in` value, so that requests-oauthlib # can handle automatic token refreshing. Assume that # `expires_at` is a valid Unix timestamp. - expires_at = datetime.utcfromtimestamp(_token["expires_at"]) - expires_in = expires_at - datetime.utcnow() + expires_at = datetime.fromtimestamp(_token["expires_at"], timezone.utc) + expires_in = expires_at - datetime.now(timezone.utc) _token["expires_in"] = expires_in.total_seconds() return _token @@ -146,7 +146,7 @@ def token(self, value): # Set the `expires_at` value, overwriting any value # that may already be there. delta = timedelta(seconds=int(_token["expires_in"])) - expires_at = datetime.utcnow() + delta + expires_at = datetime.now(timezone.utc) + delta _token["expires_at"] = expires_at.replace(tzinfo=timezone.utc).timestamp() self.storage.set(self, _token) try: diff --git a/pyproject.toml b/pyproject.toml index e29922f..fca880f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,6 +62,7 @@ docs = [ "sqlalchemy>=1.3.11", "pytest", "betamax", + "pillow<=9.5" ] sqla = ["sqlalchemy>=1.3.11"] signals = ["blinker"] diff --git a/tests/consumer/storage/test_sqla.py b/tests/consumer/storage/test_sqla.py index c129a97..b40d2b5 100644 --- a/tests/consumer/storage/test_sqla.py +++ b/tests/consumer/storage/test_sqla.py @@ -62,6 +62,7 @@ def db(): def app(blueprint, db, request): "Make a Flask app, attach Flask-SQLAlchemy, and establish an app context" app = flask.Flask(__name__) + app.config["SERVER_NAME"] = "a.b.c" app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("DATABASE_URI", "sqlite://") app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False app.config["CACHE_TYPE"] = "SimpleCache" diff --git a/tests/consumer/test_oauth1.py b/tests/consumer/test_oauth1.py index 476fa84..78617d2 100644 --- a/tests/consumer/test_oauth1.py +++ b/tests/consumer/test_oauth1.py @@ -39,6 +39,7 @@ def make_app(login_url=None): app = flask.Flask(__name__) app.secret_key = "secret" app.register_blueprint(blueprint, url_prefix="/login") + app.config["SERVER_NAME"] = "a.b.c" @app.route("/") def index(): @@ -149,11 +150,10 @@ def test_authorized_url(): assert auth_header["oauth_token"] == "foobar" assert auth_header["oauth_verifier"] == "xyz" # check that we stored the access token and secret in the session - with client.session_transaction() as sess: - assert sess["test-service_oauth_token"] == { - "oauth_token": "xxx", - "oauth_token_secret": "yyy", - } + assert flask.session["test-service_oauth_token"] == { + "oauth_token": "xxx", + "oauth_token_secret": "yyy", + } @responses.activate diff --git a/tests/consumer/test_oauth2.py b/tests/consumer/test_oauth2.py index 20216fb..78fcdb0 100644 --- a/tests/consumer/test_oauth2.py +++ b/tests/consumer/test_oauth2.py @@ -47,6 +47,7 @@ def make_app(login_url=None, debug=False, **kwargs): app.secret_key = "secret" app.register_blueprint(blueprint, url_prefix="/login") app.debug = debug + app.config["SERVER_NAME"] = "a.b.c" @app.route("/") def index(): @@ -77,8 +78,7 @@ def test_login_url(): "/login/test-service", base_url="https://a.b.c", follow_redirects=False ) # check that we saved the state in the session - with client.session_transaction() as sess: - assert sess["test-service_oauth_state"] == "random-string" + assert flask.session["test-service_oauth_state"] == "random-string" # check that we redirected the client assert resp.status_code == 302 location = URLObject(resp.headers["Location"]) @@ -94,28 +94,27 @@ def test_login_url(): @responses.activate def test_login_url_with_pkce(): - _code_challenge_method = "S256" # That should be a default value + code_challenge_method = "S256" # That should be a default value app, _ = make_app(use_pkce=True) with app.test_client() as client: resp = client.get( "/login/test-service", base_url="https://a.b.c", follow_redirects=False ) # check that we saved the code verifier in the session - with client.session_transaction() as sess: - assert "test-service_oauth_code_verifier" in sess - _code_verifier = sess["test-service_oauth_code_verifier"] - assert 43 <= len(_code_verifier) <= 128 # RFC7636 section 4.1 - _code_challenge = OAuth2Client("123").create_code_challenge( - _code_verifier, _code_challenge_method - ) + assert "test-service_oauth_code_verifier" in flask.session + code_verifier = flask.session["test-service_oauth_code_verifier"] + assert 43 <= len(code_verifier) <= 128 # RFC7636 section 4.1 + code_challenge = OAuth2Client("123").create_code_challenge( + code_verifier, code_challenge_method + ) # check that we redirected the client assert resp.status_code == 302 location = URLObject(resp.headers["Location"]) assert location.without_query() == "https://example.com/oauth/authorize" # check PKCE specific query parameters - assert location.query_dict["code_challenge_method"] == _code_challenge_method - assert location.query_dict["code_challenge"] == _code_challenge + assert location.query_dict["code_challenge_method"] == code_challenge_method + assert location.query_dict["code_challenge"] == code_challenge @responses.activate @@ -126,8 +125,7 @@ def test_login_url_with_invalid_code_challenge_method(): "/login/test-service", base_url="https://a.b.c", follow_redirects=False ) # the code verifier is saved in the session ... - with client.session_transaction() as sess: - assert "test-service_oauth_code_verifier" in sess + assert "test-service_oauth_code_verifier" in flask.session location = URLObject(resp.headers["Location"]) assert location.without_query() == "https://example.com/oauth/authorize" @@ -428,6 +426,7 @@ def test_redirect_url(): ) app = flask.Flask(__name__) app.secret_key = "secret" + app.config["SERVER_NAME"] = "a.b.c" app.register_blueprint(blueprint, url_prefix="/login") with app.test_client() as client: @@ -464,6 +463,7 @@ def test_redirect_to(): ) app = flask.Flask(__name__) app.secret_key = "secret" + app.config["SERVER_NAME"] = "a.b.c" app.register_blueprint(blueprint, url_prefix="/login") @app.route("/blargl") @@ -503,6 +503,7 @@ def test_redirect_fallback(): ) app = flask.Flask(__name__) app.secret_key = "secret" + app.config["SERVER_NAME"] = "a.b.c" app.register_blueprint(blueprint, url_prefix="/login") @app.route("/blargl") diff --git a/tests/contrib/test_gitlab.py b/tests/contrib/test_gitlab.py index 9cfd9a9..a6a8558 100644 --- a/tests/contrib/test_gitlab.py +++ b/tests/contrib/test_gitlab.py @@ -14,6 +14,7 @@ def make_app(): def _make_app(*args, **kwargs): app = Flask(__name__) + app.config["SERVER_NAME"] = "a.b.c" app.secret_key = "whatever" blueprint = make_gitlab_blueprint(*args, **kwargs) app.register_blueprint(blueprint) diff --git a/tests/contrib/test_slack.py b/tests/contrib/test_slack.py index ad9542d..d146039 100644 --- a/tests/contrib/test_slack.py +++ b/tests/contrib/test_slack.py @@ -1,9 +1,10 @@ +from urllib.parse import parse_qs + import pytest import requests_oauthlib import responses from flask import Flask from urlobject import URLObject -from werkzeug.urls import url_decode from flask_dance.consumer import OAuth2ConsumerBlueprint from flask_dance.consumer.storage import MemoryStorage @@ -117,12 +118,12 @@ def test_auto_token_get(make_app): "chat.postMessage", data={"channel": "#general", "text": "ping", "icon_emoji": ":robot_face:"}, ) - request_data = url_decode(resp.request.body) - assert request_data["channel"] == "#general" - assert request_data["text"] == "ping" - assert request_data["icon_emoji"] == ":robot_face:" + request_data = parse_qs(resp.request.body) + assert request_data["channel"] == ["#general"] + assert request_data["text"] == ["ping"] + assert request_data["icon_emoji"] == [":robot_face:"] # the `token` parameter should have been automatically added - assert request_data["token"] == "abcde" + assert request_data["token"] == ["abcde"] @responses.activate @@ -141,12 +142,12 @@ def test_auto_token_post(make_app): "chat.postMessage", data={"channel": "#general", "text": "ping", "icon_emoji": ":robot_face:"}, ) - request_data = url_decode(resp.request.body) - assert request_data["channel"] == "#general" - assert request_data["text"] == "ping" - assert request_data["icon_emoji"] == ":robot_face:" + request_data = parse_qs(resp.request.body) + assert request_data["channel"] == ["#general"] + assert request_data["text"] == ["ping"] + assert request_data["icon_emoji"] == [":robot_face:"] # the `token` parameter should have been automatically added - assert request_data["token"] == "abcde" + assert request_data["token"] == ["abcde"] @responses.activate @@ -161,10 +162,10 @@ def test_auto_token_post_no_token(make_app): "chat.postMessage", data={"channel": "#general", "text": "ping", "icon_emoji": ":robot_face:"}, ) - request_data = url_decode(resp.request.body) - assert request_data["channel"] == "#general" - assert request_data["text"] == "ping" - assert request_data["icon_emoji"] == ":robot_face:" + request_data = parse_qs(resp.request.body) + assert request_data["channel"] == ["#general"] + assert request_data["text"] == ["ping"] + assert request_data["icon_emoji"] == [":robot_face:"] assert "token" not in request_data url = URLObject(resp.request.url) assert "token" not in url.query_dict @@ -191,11 +192,11 @@ def test_override_token_get(make_app): "icon_emoji": ":robot_face:", }, ) - request_data = url_decode(resp.request.body) - assert request_data["token"] == "xyz" - assert request_data["channel"] == "#general" - assert request_data["text"] == "ping" - assert request_data["icon_emoji"] == ":robot_face:" + request_data = parse_qs(resp.request.body) + assert request_data["token"] == ["xyz"] + assert request_data["channel"] == ["#general"] + assert request_data["text"] == ["ping"] + assert request_data["icon_emoji"] == [":robot_face:"] # should not be present in URL url = URLObject(resp.request.url) assert "token" not in url.query_dict @@ -222,11 +223,11 @@ def test_override_token_post(make_app): "icon_emoji": ":robot_face:", }, ) - request_data = url_decode(resp.request.body) - assert request_data["token"] == "xyz" - assert request_data["channel"] == "#general" - assert request_data["text"] == "ping" - assert request_data["icon_emoji"] == ":robot_face:" + request_data = parse_qs(resp.request.body) + assert request_data["token"] == ["xyz"] + assert request_data["channel"] == ["#general"] + assert request_data["text"] == ["ping"] + assert request_data["icon_emoji"] == [":robot_face:"] # should not be present url = URLObject(resp.request.url) assert "token" not in url.query_dict