From 255eeaf4f615a48f32d4d60e1ff4c882dff38d74 Mon Sep 17 00:00:00 2001 From: Martin Renvoize Date: Wed, 16 Sep 2026 08:38:51 +0100 Subject: [PATCH] Bug 43375: (QA follow-up) Add test coverage for form-data fallback in userinfo parsing _get_data_and_patron() falls back to Mojo::Parameters form-data parsing whenever $tx->res->json fails to decode the userinfo response body. That branch was untested: all existing userinfo_url subtests mock json() to return a hashref, so the fallback path was never actually exercised. This adds a subtest that mocks a genuine url-encoded response body (json() returning undef) and confirms the fallback still maps data and finds the matching patron correctly. Test plan: 1. Run: $ ktd --shell k$ prove t/db_dependent/Koha/Auth/Client/OAuth.t => SUCCESS: All 6 subtests pass, including the new fallback-path test 2. Sign off Co-Authored-By: Claude Sonnet 5 Signed-off-by: Martin Renvoize Signed-off-by: Pedro Amorim --- t/db_dependent/Koha/Auth/Client/OAuth.t | 89 ++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 1 deletion(-) diff --git a/t/db_dependent/Koha/Auth/Client/OAuth.t b/t/db_dependent/Koha/Auth/Client/OAuth.t index 3f7f075ca2..646de947c2 100755 --- a/t/db_dependent/Koha/Auth/Client/OAuth.t +++ b/t/db_dependent/Koha/Auth/Client/OAuth.t @@ -19,7 +19,7 @@ use Modern::Perl; -use Test::More tests => 5; +use Test::More tests => 6; use Test::MockModule; use Test::NoWarnings; @@ -355,3 +355,90 @@ subtest '_get_data_and_patron() userinfo_url with extra Content-Type params (bug $schema->storage->txn_rollback; }; + +subtest '_get_data_and_patron() userinfo_url falls back to form-encoded body (bug 43375)' => sub { + plan tests => 2; + + $schema->storage->txn_begin; + + my $client = Koha::Auth::Client::OAuth->new; + + # Create test patron + my $patron = $builder->build_object( + { + class => 'Koha::Patrons', + value => { email => 'formuser@example.com' } + } + ); + + # Create provider with email matchpoint + my $provider = $builder->build_object( + { + class => 'Koha::Auth::Identity::Providers', + value => { + matchpoint => 'email', + mapping => encode_json( + { + email => 'mail', + firstname => 'given_name', + } + ) + } + } + ); + + # Mock UserAgent - simulate a provider that returns a genuine + # url-encoded body, so res->json fails to decode (returns undef) + # and _get_data_and_patron must fall back to Mojo::Parameters + my $ua_mock = Test::MockModule->new('Mojo::UserAgent'); + my $tx_mock = Test::MockModule->new('Mojo::Transaction::HTTP'); + my $res_mock = Test::MockModule->new('Mojo::Message::Response'); + my $headers_mock = Test::MockModule->new('Mojo::Headers'); + + $headers_mock->mock( 'content_type', sub { 'application/x-www-form-urlencoded' } ); + $res_mock->mock( 'code', sub { '200' } ); + $res_mock->mock( 'json', sub { undef } ); + $res_mock->mock( 'body', sub { 'mail=formuser%40example.com&given_name=Form' } ); + $res_mock->mock( + 'headers', + sub { + my $headers = {}; + bless $headers, 'Mojo::Headers'; + return $headers; + } + ); + + $tx_mock->mock( + 'res', + sub { + my $res = {}; + bless $res, 'Mojo::Message::Response'; + return $res; + } + ); + + $ua_mock->mock( + 'get', + sub { + my $tx = {}; + bless $tx, 'Mojo::Transaction::HTTP'; + return $tx; + } + ); + + my $data = { access_token => 'form_token' }; + my $config = { userinfo_url => 'https://provider.example.com/userinfo' }; + + my ( $mapped_data, $found_patron ) = $client->_get_data_and_patron( + { + provider => $provider, + data => $data, + config => $config + } + ); + + is( $mapped_data->{email}, 'formuser@example.com', 'Email mapped from url-encoded fallback body' ); + is( $found_patron->id, $patron->id, 'Patron found via form-data fallback parsing' ); + + $schema->storage->txn_rollback; +};