Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package qt6-networkauth for openSUSE:Factory 
checked in at 2023-10-13 23:14:19
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/qt6-networkauth (Old)
 and      /work/SRC/openSUSE:Factory/.qt6-networkauth.new.20540 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "qt6-networkauth"

Fri Oct 13 23:14:19 2023 rev:24 rq:1116941 version:6.6.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/qt6-networkauth/qt6-networkauth.changes  
2023-10-02 20:07:27.868958053 +0200
+++ 
/work/SRC/openSUSE:Factory/.qt6-networkauth.new.20540/qt6-networkauth.changes   
    2023-10-13 23:14:47.399274081 +0200
@@ -1,0 +2,6 @@
+Tue Oct 10 09:39:54 UTC 2023 - Christophe Marin <christo...@krop.fr>
+
+- Update to 6.6.0
+  * https://www.qt.io/blog/qt-6.6-released
+
+-------------------------------------------------------------------

Old:
----
  qtnetworkauth-everywhere-src-6.5.3.tar.xz

New:
----
  qtnetworkauth-everywhere-src-6.6.0.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ qt6-networkauth.spec ++++++
--- /var/tmp/diff_new_pack.KeHN71/_old  2023-10-13 23:14:49.051334002 +0200
+++ /var/tmp/diff_new_pack.KeHN71/_new  2023-10-13 23:14:49.051334002 +0200
@@ -16,8 +16,8 @@
 #
 
 
-%define real_version 6.5.3
-%define short_version 6.5
+%define real_version 6.6.0
+%define short_version 6.6
 %define short_name qtnetworkauth
 %define tar_name qtnetworkauth-everywhere-src
 %define tar_suffix %{nil}
@@ -28,7 +28,7 @@
 %endif
 #
 Name:           qt6-networkauth%{?pkg_suffix}
-Version:        6.5.3
+Version:        6.6.0
 Release:        0
 Summary:        Set of APIs to obtain limited access to online accounts and 
HTTP services
 License:        GPL-3.0-only WITH Qt-GPL-exception-1.0

++++++ qtnetworkauth-everywhere-src-6.5.3.tar.xz -> 
qtnetworkauth-everywhere-src-6.6.0.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qtnetworkauth-everywhere-src-6.5.3/.cmake.conf 
new/qtnetworkauth-everywhere-src-6.6.0/.cmake.conf
--- old/qtnetworkauth-everywhere-src-6.5.3/.cmake.conf  2023-09-24 
09:06:35.000000000 +0200
+++ new/qtnetworkauth-everywhere-src-6.6.0/.cmake.conf  2023-10-02 
05:05:49.000000000 +0200
@@ -1,3 +1,3 @@
-set(QT_REPO_MODULE_VERSION "6.5.3")
+set(QT_REPO_MODULE_VERSION "6.6.0")
 set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "alpha1")
 set(QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_NO_AS_CONST=1")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qtnetworkauth-everywhere-src-6.5.3/.tag 
new/qtnetworkauth-everywhere-src-6.6.0/.tag
--- old/qtnetworkauth-everywhere-src-6.5.3/.tag 2023-09-24 09:06:35.000000000 
+0200
+++ new/qtnetworkauth-everywhere-src-6.6.0/.tag 2023-10-02 05:05:49.000000000 
+0200
@@ -1 +1 @@
-70e2a96d3bfdd8fab6c48a80ee0147a56233b894
+8c7a6264d1ae09d2d0143655642d6f6530701420
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtnetworkauth-everywhere-src-6.5.3/coin/axivion/ci_config_linux.json 
new/qtnetworkauth-everywhere-src-6.6.0/coin/axivion/ci_config_linux.json
--- old/qtnetworkauth-everywhere-src-6.5.3/coin/axivion/ci_config_linux.json    
1970-01-01 01:00:00.000000000 +0100
+++ new/qtnetworkauth-everywhere-src-6.6.0/coin/axivion/ci_config_linux.json    
2023-10-02 05:05:49.000000000 +0200
@@ -0,0 +1,59 @@
+{
+    "Project": {
+        "Git": {
+            "_active": true,
+            "sourceserver_gitdir": 
"/data/axivion/databases/$(env:TESTED_MODULE_COIN).git"
+        },
+        "BuildSystemIntegration": {
+            "child_order": [
+                "GCCSetup",
+                "CMake",
+                "LinkLibraries"
+            ]
+        },
+        "CMake": {
+            "_active": true,
+            "_copy_from": "CMakeIntegration",
+            "build_environment": {},
+            "build_options": "-j4",
+            "generate_options": "--fresh",
+            "generator": "Ninja"
+        },
+        "GCCSetup": {
+            "_active": true,
+            "_copy_from": "Command",
+            "build_command": "gccsetup --cc gcc --cxx g++ --config 
../../../axivion/"
+        },
+        "LinkLibraries": {
+            "_active": true,
+            "_copy_from": "AxivionLinker",
+            "input_files": [
+                "build/lib/lib*.so*.ir"
+            ],
+            "ir": "build/$(env:TESTED_MODULE_COIN).ir"
+        },
+        "Project-GlobalOptions": {
+            "directory": "../work/qt/$(env:TESTED_MODULE_COIN)",
+            "ir": "build/$(env:TESTED_MODULE_COIN).ir",
+            "name": "qt_$(env:TESTED_MODULE_COIN)_dev_$(env:TARGET_OS_COIN)"
+        }
+    },
+    "Results": {
+        "Dashboard": {
+            "dashboard_url": "https://axivion-srv.ci.qt.io/axivion/";
+        },
+        "Database": {
+            "ci_mode": {
+                "directory": "/data/axivion/databases"
+            }
+        }
+    },
+    "_Format": "1.0",
+    "_Version": "trunk-9e0ef9c5818",
+    "_VersionNum": [
+        7,
+        6,
+        9999,
+        11489
+    ]
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qtnetworkauth-everywhere-src-6.5.3/dependencies.yaml 
new/qtnetworkauth-everywhere-src-6.6.0/dependencies.yaml
--- old/qtnetworkauth-everywhere-src-6.5.3/dependencies.yaml    2023-09-24 
09:06:35.000000000 +0200
+++ new/qtnetworkauth-everywhere-src-6.6.0/dependencies.yaml    2023-10-02 
05:05:49.000000000 +0200
@@ -1,4 +1,4 @@
 dependencies:
   ../qtbase:
-    ref: 372eaedc5b8c771c46acc4c96e91bbade4ca3624
+    ref: 33f5e985e480283bb0ca9dea5f82643e825ba87c
     required: true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtnetworkauth-everywhere-src-6.5.3/src/oauth/qabstractoauth.cpp 
new/qtnetworkauth-everywhere-src-6.6.0/src/oauth/qabstractoauth.cpp
--- old/qtnetworkauth-everywhere-src-6.5.3/src/oauth/qabstractoauth.cpp 
2023-09-24 09:06:35.000000000 +0200
+++ new/qtnetworkauth-everywhere-src-6.6.0/src/oauth/qabstractoauth.cpp 
2023-10-02 05:05:49.000000000 +0200
@@ -91,7 +91,8 @@
     \value NetworkError                     Failed to connect to the server.
 
     \value ServerError                      The server answered the
-    request with an error.
+    request with an error, or its response was not successfully received
+    (for example, due to a state mismatch).
 
     \value OAuthTokenNotFoundError          The server's response to
     a token request provided no token identifier.
@@ -163,6 +164,16 @@
 */
 
 /*!
+    \fn void QAbstractOAuth::requestFailed(const QAbstractOAuth::Error error)
+
+    This signal is emitted to indicate that a request to a server has failed.
+    The \a error supplied indicates how the request failed.
+
+    \sa QAbstractOAuth2::error()
+    \sa QAbstractOAuthReplyHandler::tokenRequestErrorOccurred()
+*/
+
+/*!
     \fn QNetworkReply *QAbstractOAuth::head(const QUrl &url, const QVariantMap 
&parameters)
 
     Sends an authenticated HEAD request and returns a new
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtnetworkauth-everywhere-src-6.5.3/src/oauth/qabstractoauth2.cpp 
new/qtnetworkauth-everywhere-src-6.6.0/src/oauth/qabstractoauth2.cpp
--- old/qtnetworkauth-everywhere-src-6.5.3/src/oauth/qabstractoauth2.cpp        
2023-09-24 09:06:35.000000000 +0200
+++ new/qtnetworkauth-everywhere-src-6.6.0/src/oauth/qabstractoauth2.cpp        
2023-10-02 05:05:49.000000000 +0200
@@ -79,10 +79,14 @@
 /*!
     \fn QAbstractOAuth2::error(const QString &error, const QString 
&errorDescription, const QUrl &uri)
 
-    Signal emitted when the server responds to the request with an
-    error: \a error is the name of the error; \a errorDescription describes
-    the error and \a uri is an optional URI containing more
-    information about the error.
+    Signal emitted when the server responds to the authorization request with
+    an error as defined in \l 
{https://www.rfc-editor.org/rfc/rfc6749#section-5.2}
+    {RFC 6749 error response}.
+
+    \a error is the name of the error; \a errorDescription describes the error
+    and \a uri is an optional URI containing more information about the error.
+
+    \sa QAbstractOAuth::requestFailed()
 */
 
 /*!
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtnetworkauth-everywhere-src-6.5.3/src/oauth/qabstractoauthreplyhandler.cpp 
new/qtnetworkauth-everywhere-src-6.6.0/src/oauth/qabstractoauthreplyhandler.cpp
--- 
old/qtnetworkauth-everywhere-src-6.5.3/src/oauth/qabstractoauthreplyhandler.cpp 
    2023-09-24 09:06:35.000000000 +0200
+++ 
new/qtnetworkauth-everywhere-src-6.6.0/src/oauth/qabstractoauthreplyhandler.cpp 
    2023-10-02 05:05:49.000000000 +0200
@@ -69,6 +69,18 @@
 */
 
 /*!
+
+    \fn void 
QAbstractOAuthReplyHandler::tokenRequestErrorOccurred(QAbstractOAuth::Error 
error,
+                                                           const QString& 
errorString)
+
+    This signal is emitted when a token request or refresh \a error has
+    occurred. The \a errorString may provide further details on the error.
+
+    \sa QAbstractOAuth::requestFailed()
+    \since 6.6
+*/
+
+/*!
     \fn void QAbstractOAuthReplyHandler::replyDataReceived(const QByteArray 
&data)
 
     This signal is emitted when an HTTP request finishes and the
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtnetworkauth-everywhere-src-6.5.3/src/oauth/qabstractoauthreplyhandler.h 
new/qtnetworkauth-everywhere-src-6.6.0/src/oauth/qabstractoauthreplyhandler.h
--- 
old/qtnetworkauth-everywhere-src-6.5.3/src/oauth/qabstractoauthreplyhandler.h   
    2023-09-24 09:06:35.000000000 +0200
+++ 
new/qtnetworkauth-everywhere-src-6.6.0/src/oauth/qabstractoauthreplyhandler.h   
    2023-10-02 05:05:49.000000000 +0200
@@ -29,6 +29,7 @@
 Q_SIGNALS:
     void callbackReceived(const QVariantMap &values);
     void tokensReceived(const QVariantMap &tokens);
+    void tokenRequestErrorOccurred(QAbstractOAuth::Error error, const QString& 
errorString);
 
     void replyDataReceived(const QByteArray &data);
     void callbackDataReceived(const QByteArray &data);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtnetworkauth-everywhere-src-6.5.3/src/oauth/qoauth2authorizationcodeflow.cpp
 
new/qtnetworkauth-everywhere-src-6.6.0/src/oauth/qoauth2authorizationcodeflow.cpp
--- 
old/qtnetworkauth-everywhere-src-6.5.3/src/oauth/qoauth2authorizationcodeflow.cpp
   2023-09-24 09:06:35.000000000 +0200
+++ 
new/qtnetworkauth-everywhere-src-6.6.0/src/oauth/qoauth2authorizationcodeflow.cpp
   2023-10-02 05:05:49.000000000 +0200
@@ -19,6 +19,8 @@
 
 QT_BEGIN_NAMESPACE
 
+using namespace Qt::StringLiterals;
+
 /*!
     \class QOAuth2AuthorizationCodeFlow
     \inmodule QtNetworkAuth
@@ -61,7 +63,8 @@
     using Key = QAbstractOAuth2Private::OAuth2KeyString;
 
     if (status != QAbstractOAuth::Status::NotAuthenticated) {
-        qCWarning(loggingCategory, "Unexpected call");
+        qCWarning(loggingCategory) << "Authorization stage: callback in 
unexpected status:"
+                                   << static_cast<int>(status) << ", ignoring 
the callback";
         return;
     }
 
@@ -71,23 +74,30 @@
     const QString code = data.value(Key::code).toString();
     const QString receivedState = data.value(Key::state).toString();
     if (error.size()) {
+        // RFC 6749, Section 5.2 Error Response
         const QString uri = data.value(Key::errorUri).toString();
         const QString description = 
data.value(Key::errorDescription).toString();
-        qCWarning(loggingCategory, "AuthenticationError: %s(%s): %s",
-                 qPrintable(error), qPrintable(uri), qPrintable(description));
+        qCWarning(loggingCategory, "Authorization stage: AuthenticationError: 
%s(%s): %s",
+                  qPrintable(error), qPrintable(uri), qPrintable(description));
         Q_EMIT q->error(error, description, uri);
+        // Emit also requestFailed() so that it is a signal for all errors
+        emit q->requestFailed(QAbstractOAuth::Error::ServerError);
         return;
     }
+
     if (code.isEmpty()) {
-        qCWarning(loggingCategory, "AuthenticationError: Code not received");
+        qCWarning(loggingCategory, "Authorization stage: Code not received");
+        emit q->requestFailed(QAbstractOAuth::Error::OAuthTokenNotFoundError);
         return;
     }
     if (receivedState.isEmpty()) {
-        qCWarning(loggingCategory, "State not received");
+        qCWarning(loggingCategory, "Authorization stage: State not received");
+        emit q->requestFailed(QAbstractOAuth::Error::ServerError);
         return;
     }
     if (state != receivedState) {
-        qCWarning(loggingCategory, "State mismatch");
+        qCWarning(loggingCategory) << "Authorization stage: State mismatch";
+        emit q->requestFailed(QAbstractOAuth::Error::ServerError);
         return;
     }
 
@@ -105,8 +115,8 @@
     using Key = QAbstractOAuth2Private::OAuth2KeyString;
 
     if (values.contains(Key::error)) {
-        const QString error = values.value(Key::error).toString();
-        qCWarning(loggingCategory, "Error: %s", qPrintable(error));
+        _q_accessTokenRequestFailed(QAbstractOAuth::Error::ServerError,
+                                    values.value(Key::error).toString());
         return;
     }
 
@@ -120,7 +130,8 @@
         q->setRefreshToken(values.value(Key::refreshToken).toString());
     scope = values.value(Key::scope).toString();
     if (accessToken.isEmpty()) {
-        qCWarning(loggingCategory, "Access token not received");
+        
_q_accessTokenRequestFailed(QAbstractOAuth::Error::OAuthTokenNotFoundError,
+                                    "Access token not received"_L1);
         return;
     }
     q->setToken(accessToken);
@@ -142,6 +153,23 @@
     setStatus(QAbstractOAuth::Status::Granted);
 }
 
+void 
QOAuth2AuthorizationCodeFlowPrivate::_q_accessTokenRequestFailed(QAbstractOAuth::Error
 error,
+                                                                      const 
QString& errorString)
+{
+    Q_Q(QOAuth2AuthorizationCodeFlow);
+    qCWarning(loggingCategory) << "Token request failed:" << errorString;
+    // If we were refreshing, reset status to Granted if we have an access 
token.
+    // The access token might still be valid, and even if it wouldn't be,
+    // refreshing can be attempted again.
+    if (q->status() == QAbstractOAuth::Status::RefreshingToken) {
+        if (!q->token().isEmpty())
+            setStatus(QAbstractOAuth::Status::Granted);
+        else
+            setStatus(QAbstractOAuth::Status::NotAuthenticated);
+    }
+    emit q->requestFailed(error);
+}
+
 void QOAuth2AuthorizationCodeFlowPrivate::_q_authenticate(QNetworkReply *reply,
                                                           QAuthenticator 
*authenticator)
 {
@@ -273,8 +301,12 @@
     permanent. After a time specified along with the access token
     when it was obtained, the access token will become invalid.
 
-    \b {See also}:
-    \l {https://tools.ietf.org/html/rfc6749#section-1.5}{Refresh
+    If refreshing the token fails and an access token exists, the status is
+    set to QAbstractOAuth::Status::Granted, and to
+    QAbstractOAuth::Status::NotAuthenticated otherwise.
+
+    \sa QAbstractOAuth::requestFailed()
+    \sa {https://tools.ietf.org/html/rfc6749#section-1.5}{Refresh
     Token}
 */
 void QOAuth2AuthorizationCodeFlow::refreshAccessToken()
@@ -313,7 +345,7 @@
 
     const QString data = query.toString(QUrl::FullyEncoded);
     d->currentReply = d->networkAccessManager()->post(request, data.toUtf8());
-    d->status = Status::RefreshingToken;
+    setStatus(Status::RefreshingToken);
 
     QNetworkReply *reply = d->currentReply.data();
     QAbstractOAuthReplyHandler *handler = replyHandler();
@@ -327,6 +359,10 @@
                             &QNetworkAccessManager::authenticationRequired,
                             d, 
&QOAuth2AuthorizationCodeFlowPrivate::_q_authenticate,
                             Qt::UniqueConnection);
+    QObjectPrivate::connect(d->replyHandler.data(),
+                            
&QAbstractOAuthReplyHandler::tokenRequestErrorOccurred,
+                            d, 
&QOAuth2AuthorizationCodeFlowPrivate::_q_accessTokenRequestFailed,
+                            Qt::UniqueConnection);
 }
 
 /*!
@@ -404,6 +440,10 @@
                             &QNetworkAccessManager::authenticationRequired,
                             d, 
&QOAuth2AuthorizationCodeFlowPrivate::_q_authenticate,
                             Qt::UniqueConnection);
+    QObjectPrivate::connect(d->replyHandler.data(),
+                            
&QAbstractOAuthReplyHandler::tokenRequestErrorOccurred,
+                            d, 
&QOAuth2AuthorizationCodeFlowPrivate::_q_accessTokenRequestFailed,
+                            Qt::UniqueConnection);
 }
 
 /*!
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtnetworkauth-everywhere-src-6.5.3/src/oauth/qoauth2authorizationcodeflow_p.h
 
new/qtnetworkauth-everywhere-src-6.6.0/src/oauth/qoauth2authorizationcodeflow_p.h
--- 
old/qtnetworkauth-everywhere-src-6.5.3/src/oauth/qoauth2authorizationcodeflow_p.h
   2023-09-24 09:06:35.000000000 +0200
+++ 
new/qtnetworkauth-everywhere-src-6.6.0/src/oauth/qoauth2authorizationcodeflow_p.h
   2023-10-02 05:05:49.000000000 +0200
@@ -39,6 +39,7 @@
 
     void _q_handleCallback(const QVariantMap &data);
     void _q_accessTokenRequestFinished(const QVariantMap &values);
+    void _q_accessTokenRequestFailed(QAbstractOAuth::Error error, const 
QString &errorString = {});
     void _q_authenticate(QNetworkReply *reply, QAuthenticator *authenticator);
 
     QUrl accessTokenUrl;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtnetworkauth-everywhere-src-6.5.3/src/oauth/qoauthoobreplyhandler.cpp 
new/qtnetworkauth-everywhere-src-6.6.0/src/oauth/qoauthoobreplyhandler.cpp
--- old/qtnetworkauth-everywhere-src-6.5.3/src/oauth/qoauthoobreplyhandler.cpp  
2023-09-24 09:06:35.000000000 +0200
+++ new/qtnetworkauth-everywhere-src-6.6.0/src/oauth/qoauthoobreplyhandler.cpp  
2023-10-02 05:05:49.000000000 +0200
@@ -15,6 +15,8 @@
 
 QT_BEGIN_NAMESPACE
 
+using namespace Qt::StringLiterals;
+
 QOAuthOobReplyHandler::QOAuthOobReplyHandler(QObject *parent)
     : QAbstractOAuthReplyHandler(parent)
 {}
@@ -27,11 +29,12 @@
 void QOAuthOobReplyHandler::networkReplyFinished(QNetworkReply *reply)
 {
     if (reply->error() != QNetworkReply::NoError) {
-        qCWarning(lcReplyHandler, "%s", qPrintable(reply->errorString()));
+        emit tokenRequestErrorOccurred(QAbstractOAuth::Error::NetworkError, 
reply->errorString());
         return;
     }
     if (reply->header(QNetworkRequest::ContentTypeHeader).isNull()) {
-        qCWarning(lcReplyHandler, "Empty Content-type header");
+        emit tokenRequestErrorOccurred(QAbstractOAuth::Error::NetworkError,
+                                       u"Empty Content-type header"_s);
         return;
     }
     const QString contentType = 
reply->header(QNetworkRequest::ContentTypeHeader).isNull() ?
@@ -39,7 +42,7 @@
                 reply->header(QNetworkRequest::ContentTypeHeader).toString();
     const QByteArray data = reply->readAll();
     if (data.isEmpty()) {
-        qCWarning(lcReplyHandler, "No received data");
+        emit tokenRequestErrorOccurred(QAbstractOAuth::Error::NetworkError, 
u"No received data"_s);
         return;
     }
 
@@ -54,8 +57,8 @@
                || contentType.startsWith(QStringLiteral("text/javascript"))) {
         const QJsonDocument document = QJsonDocument::fromJson(data);
         if (!document.isObject()) {
-            qCWarning(lcReplyHandler, "Received data is not a JSON object: %s",
-                      qPrintable(QString::fromUtf8(data)));
+            emit tokenRequestErrorOccurred(QAbstractOAuth::Error::ServerError,
+                          u"Received data is not a JSON object: 
%1"_s.arg(QString::fromUtf8(data)));
             return;
         }
         const QJsonObject object = document.object();
@@ -65,7 +68,8 @@
         }
         ret = object.toVariantMap();
     } else {
-        qCWarning(lcReplyHandler, "Unknown Content-type: %s", 
qPrintable(contentType));
+        emit tokenRequestErrorOccurred(QAbstractOAuth::Error::ServerError,
+                               u"Unknown Content-type %1"_s.arg(contentType));
         return;
     }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qtnetworkauth-everywhere-src-6.5.3/tests/auto/oauth2/tst_oauth2.cpp 
new/qtnetworkauth-everywhere-src-6.6.0/tests/auto/oauth2/tst_oauth2.cpp
--- old/qtnetworkauth-everywhere-src-6.5.3/tests/auto/oauth2/tst_oauth2.cpp     
2023-09-24 09:06:35.000000000 +0200
+++ new/qtnetworkauth-everywhere-src-6.6.0/tests/auto/oauth2/tst_oauth2.cpp     
2023-10-02 05:05:49.000000000 +0200
@@ -13,6 +13,8 @@
 #include "webserver.h"
 #include "tlswebserver.h"
 
+using namespace Qt::StringLiterals;
+
 class tst_OAuth2 : public QObject
 {
     Q_OBJECT
@@ -22,6 +24,8 @@
     void getToken();
     void refreshToken();
     void getAndRefreshToken();
+    void tokenRequestErrors();
+    void authorizationErrors();
     void prepareRequest();
 #ifndef QT_NO_SSL
     void setSslConfig();
@@ -39,13 +43,19 @@
         return QLatin1String("test");
     }
 
+    QAbstractOAuth::Error aTokenRequestError = QAbstractOAuth::Error::NoError;
+
     void networkReplyFinished(QNetworkReply *reply) override
     {
         QVariantMap data;
         const auto items = QUrlQuery(reply->readAll()).queryItems();
         for (const auto &pair : items)
             data.insert(pair.first, pair.second);
-        Q_EMIT tokensReceived(data);
+
+        if (aTokenRequestError == QAbstractOAuth::Error::NoError)
+            emit tokensReceived(data);
+        else
+            emit tokenRequestErrorOccurred(aTokenRequestError, "a token 
request error");
     }
 
     void emitCallbackReceived(const QVariantMap &data)
@@ -56,6 +66,7 @@
 
 void tst_OAuth2::initTestCase()
 {
+    // QLoggingCategory::setFilterRules(QStringLiteral("qt.networkauth* = 
true"));
     testDataDir = QFileInfo(QFINDTESTDATA("certs")).absolutePath();
     if (testDataDir.isEmpty())
         testDataDir = QCoreApplication::applicationDirPath();
@@ -63,6 +74,91 @@
         testDataDir += QLatin1String("/");
 }
 
+void tst_OAuth2::authorizationErrors()
+{
+    // This tests failures in authorization stage. For this test we don't need 
a web server
+    // as we emit the final (failing) callbackReceived directly.
+    // Helper to catch the expected warning messages:
+    constexpr auto expectWarning = [](){
+        static const QRegularExpression authStageWarning{"Authorization 
stage:.*"};
+        QTest::ignoreMessage(QtWarningMsg, authStageWarning);
+    };
+
+    QOAuth2AuthorizationCodeFlow oauth2;
+    oauth2.setAuthorizationUrl(QUrl{"authorization"_L1});
+    oauth2.setAccessTokenUrl(QUrl{"accessToken"_L1});
+    ReplyHandler replyHandler;
+    oauth2.setReplyHandler(&replyHandler);
+
+    QVariantMap callbackParameters;
+    connect(&oauth2, &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser,
+            &oauth2, [&](const QUrl& /* url */) {
+        replyHandler.emitCallbackReceived(callbackParameters);
+    });
+
+    QSignalSpy requestFailedSpy(&oauth2, &QAbstractOAuth::requestFailed);
+    QSignalSpy errorSpy(&oauth2, &QAbstractOAuth2::error);
+    QSignalSpy statusSpy(&oauth2, &QAbstractOAuth2::statusChanged);
+    auto clearSpies = [&](){
+        requestFailedSpy.clear();
+        errorSpy.clear();
+        statusSpy.clear();
+    };
+
+    // Test error response from the authorization server (RFC 6749 section 5.2)
+    callbackParameters = {{"error"_L1, "invalid_grant"_L1},
+                          {"error_description"_L1, "The error description"_L1},
+                          {"error_uri"_L1, "The error URI"_L1}};
+    expectWarning();
+    oauth2.grant();
+    QTRY_COMPARE(errorSpy.count(), 1);
+    QTRY_COMPARE(requestFailedSpy.count(), 1);
+    QCOMPARE(errorSpy.first().at(0).toString(), "invalid_grant"_L1);
+    QCOMPARE(errorSpy.first().at(1).toString(), "The error description"_L1);
+    QCOMPARE(errorSpy.first().at(2).toString(), "The error URI"_L1);
+    QCOMPARE(requestFailedSpy.first().at(0).value<QAbstractOAuth::Error>(),
+             QAbstractOAuth::Error::ServerError);
+    QVERIFY(statusSpy.isEmpty());
+    QCOMPARE(oauth2.status(), QAbstractOAuth::Status::NotAuthenticated);
+
+    // Test not providing authorization code
+    clearSpies();
+    callbackParameters = {{"state"_L1, "thestate"_L1}};
+    expectWarning();
+    oauth2.grant();
+    QTRY_COMPARE(requestFailedSpy.count(), 1);
+    QCOMPARE(requestFailedSpy.first().at(0).value<QAbstractOAuth::Error>(),
+             QAbstractOAuth::Error::OAuthTokenNotFoundError);
+    QCOMPARE(errorSpy.count(), 0);
+    QVERIFY(statusSpy.isEmpty());
+    QCOMPARE(oauth2.status(), QAbstractOAuth::Status::NotAuthenticated);
+
+    // Test not providing a state
+    clearSpies();
+    callbackParameters = {{"code"_L1, "thecode"_L1}};
+    expectWarning();
+    oauth2.grant();
+    QTRY_COMPARE(requestFailedSpy.count(), 1);
+    QCOMPARE(requestFailedSpy.first().at(0).value<QAbstractOAuth::Error>(),
+             QAbstractOAuth::Error::ServerError);
+    QCOMPARE(errorSpy.count(), 0);
+    QVERIFY(statusSpy.isEmpty());
+    QCOMPARE(oauth2.status(), QAbstractOAuth::Status::NotAuthenticated);
+
+    // Test state mismatch (here we use "thestate" while the actual, expected, 
state is a
+    // random generated string varying each run
+    clearSpies();
+    callbackParameters = {{"code"_L1, "thecode"_L1}, {"state"_L1, 
"thestate"_L1}};
+    expectWarning();
+    oauth2.grant();
+    QTRY_COMPARE(requestFailedSpy.count(), 1);
+    QCOMPARE(requestFailedSpy.first().at(0).value<QAbstractOAuth::Error>(),
+             QAbstractOAuth::Error::ServerError);
+    QCOMPARE(errorSpy.count(), 0);
+    QVERIFY(statusSpy.isEmpty());
+    QCOMPARE(oauth2.status(), QAbstractOAuth::Status::NotAuthenticated);
+}
+
 void tst_OAuth2::getToken()
 {
     WebServer webServer([](const WebServer::HttpRequest &request, QTcpSocket 
*socket) {
@@ -163,6 +259,122 @@
     QCOMPARE(oauth2.token(), QLatin1String("refresh_token"));
 }
 
+void tst_OAuth2::tokenRequestErrors()
+{
+    // This test tests the token acquisition and refreshing errors.
+    // Helper to catch the expected warning messages:
+    constexpr auto expectWarning = [](){
+        static const QRegularExpression tokenWarning{"Token request 
failed:.*"};
+        QTest::ignoreMessage(QtWarningMsg, tokenWarning);
+    };
+
+    QByteArray accessTokenResponse; // Varying reply for the auth server
+    WebServer authServer([&](const WebServer::HttpRequest &request, QTcpSocket 
*socket) {
+        if (request.url.path() == QLatin1String("/accessToken"))
+            socket->write(accessTokenResponse);
+    });
+
+    QOAuth2AuthorizationCodeFlow oauth2;
+    oauth2.setAuthorizationUrl(authServer.url(QLatin1String("authorization")));
+    oauth2.setAccessTokenUrl(authServer.url(QLatin1String("accessToken")));
+
+    ReplyHandler replyHandler;
+    oauth2.setReplyHandler(&replyHandler);
+
+    QSignalSpy requestFailedSpy(&oauth2, &QAbstractOAuth::requestFailed);
+    QSignalSpy grantedSpy(&oauth2, &QOAuth2AuthorizationCodeFlow::granted);
+    QSignalSpy statusSpy(&oauth2, &QAbstractOAuth2::statusChanged);
+    auto clearSpies = [&](){
+        requestFailedSpy.clear();
+        grantedSpy.clear();
+        statusSpy.clear();
+    };
+
+    connect(&oauth2, &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser,
+            &oauth2, [&](const QUrl &url) {
+        // Successful authorization stage, after which we can test token 
requests.
+        // For clarity: in these tests we omit browser interaction by directly 
triggering
+        // the emission of replyhandler::callbackReceived() signal
+        const QUrlQuery query(url.query());
+        replyHandler.emitCallbackReceived(QVariantMap {
+            { QLatin1String("code"), QLatin1String("test") },
+            { QLatin1String("state"),
+             query.queryItemValue(QLatin1String("state")) }
+        });
+    });
+
+    // Check the initial state
+    QVERIFY(requestFailedSpy.isEmpty());
+    QVERIFY(grantedSpy.isEmpty());
+    QVERIFY(statusSpy.isEmpty());
+    QCOMPARE(oauth2.status(), QAbstractOAuth::Status::NotAuthenticated);
+
+    // Try to get an access token with an invalid response
+    accessTokenResponse = "an invalid response"_ba;
+    expectWarning();
+    oauth2.grant();
+    QTRY_COMPARE(requestFailedSpy.size(), 1);
+    QVERIFY(grantedSpy.isEmpty());
+    QCOMPARE(statusSpy.size(), 1); // Authorization was successful so we get 
one signal
+    QCOMPARE(oauth2.status(), 
QAbstractOAuth::Status::TemporaryCredentialsReceived);
+
+    // Try to get an access token, but replyhandler indicates an error
+    clearSpies();
+    replyHandler.aTokenRequestError = QAbstractOAuth::Error::NetworkError;
+    expectWarning();
+    oauth2.grant();
+    QTRY_COMPARE(requestFailedSpy.size(), 1);
+    QVERIFY(grantedSpy.isEmpty());
+    QCOMPARE(oauth2.status(), 
QAbstractOAuth::Status::TemporaryCredentialsReceived);
+
+    // Make a successful access & refresh token acquisition
+    replyHandler.aTokenRequestError = QAbstractOAuth::Error::NoError;
+    clearSpies();
+    accessTokenResponse =
+        "HTTP/1.0 200 OK\r\n"
+        "Content-Type: application/x-www-form-urlencoded; 
charset=\"utf-8\"\r\n"
+        "\r\n"
+        
"access_token=the_access_token&token_type=bearer&refresh_token=the_refresh_token"_ba;
+    oauth2.grant();
+    QTRY_COMPARE(grantedSpy.size(), 1);
+    QCOMPARE(statusSpy.size(), 3);
+    // First status change is going from TempCred back to NotAuthenticated
+    QCOMPARE(statusSpy.takeFirst().at(0).value<QAbstractOAuth::Status>(),
+             QAbstractOAuth::Status::NotAuthenticated);
+    QCOMPARE(statusSpy.takeFirst().at(0).value<QAbstractOAuth::Status>(),
+             QAbstractOAuth::Status::TemporaryCredentialsReceived);
+    QCOMPARE(statusSpy.takeFirst().at(0).value<QAbstractOAuth::Status>(),
+             QAbstractOAuth::Status::Granted);
+    QVERIFY(requestFailedSpy.isEmpty());
+    QCOMPARE(oauth2.status(), QAbstractOAuth::Status::Granted);
+    QCOMPARE(oauth2.token(), u"the_access_token"_s);
+    QCOMPARE(oauth2.refreshToken(), u"the_refresh_token"_s);
+
+    // Successfully refresh access token
+    clearSpies();
+    oauth2.refreshAccessToken();
+    QTRY_COMPARE(statusSpy.size(), 2);
+    QCOMPARE(statusSpy.takeFirst().at(0).value<QAbstractOAuth::Status>(),
+             QAbstractOAuth::Status::RefreshingToken);
+    QCOMPARE(statusSpy.takeFirst().at(0).value<QAbstractOAuth::Status>(),
+             QAbstractOAuth::Status::Granted);
+    QCOMPARE(oauth2.status(), QAbstractOAuth::Status::Granted);
+    QVERIFY(requestFailedSpy.isEmpty());
+
+    // Failed access token refresh
+    clearSpies();
+    replyHandler.aTokenRequestError = QAbstractOAuth::Error::ServerError;
+    expectWarning();
+    oauth2.refreshAccessToken();
+    QTRY_COMPARE(statusSpy.size(), 2);
+    QCOMPARE(statusSpy.takeFirst().at(0).value<QAbstractOAuth::Status>(),
+             QAbstractOAuth::Status::RefreshingToken);
+    QCOMPARE(statusSpy.takeFirst().at(0).value<QAbstractOAuth::Status>(),
+             QAbstractOAuth::Status::Granted); // back to granted since we 
have an access token
+    QCOMPARE(requestFailedSpy.size(), 1);
+    QCOMPARE(oauth2.status(), QAbstractOAuth::Status::Granted);
+}
+
 void tst_OAuth2::prepareRequest()
 {
     QOAuth2AuthorizationCodeFlow oauth2;

Reply via email to