#!/usr/local/cpanel/3rdparty/bin/perl -w

# cpanel - t/medium/Cpanel-Koality-ApiClient.t     Copyright 2023 cPanel, L.L.C.
#                                                           All rights reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited

package t::medium::Cpanel::Koality::ApiClient;

use cPstrict;
use Test::Cpanel::Policy;
use Test::Cpanel::Logger;
use Test::MockModule;
use Test::MockObject;

use Test2::V0;
use Test2::Plugin::NoWarnings;

use Cpanel::Koality::ApiClient ();

use base qw(Test::Class);

__PACKAGE__->new()->runtests() if !caller;

sub test_all : Tests(5) {

    my $mock_stage_file = Test::MockFile->file('/var/cpanel/use_koality_stage');
    my $mock_privs      = Test::MockModule->new('Cpanel::AccessIds::ReducedPrivileges');

    $mock_privs->redefine( 'new' => sub { return 1 } );

    my $mock_locale = Test::MockModule->new('Cpanel::Locale::Utils::User');
    $mock_locale->redefine( 'get_user_locale' => sub { return 'en' } );

    my $mock_username = Test::MockModule->new('Cpanel::Validate::Username');
    $mock_username->redefine( 'user_exists_or_die' => sub { return 1 } );

    my $expected_user = 'cpanel_user';
    $Cpanel::user = $expected_user;

    my $obj = Cpanel::Koality::ApiClient->new( http_client => 1, base_url => 'https://example.com' );
    is( $obj->cpanel_username, $expected_user, "Got correct user set with Cpanel::user." );

    ok( $obj->can('reauth_handler'), "Has a reauth handler." );

    my $mock_auth          = Test::MockModule->new('Cpanel::Koality::Auth');
    my $mock_no_verify_SSL = Test::MockFile->file( '/var/cpanel/no_verify_SSL', '' );
    $mock_auth->redefine( 'new'          => sub { return bless {}, 'Cpanel::Koality::Auth' } );
    $mock_auth->redefine( 'auth_session' => sub { return bless {}, 'Cpanel::Koality::Mock::User' } );
    $obj->payload( { access_token => 'abcd' } );

    ok( $obj->reauth_handler(), "reauth handler returns 1" );
    is( $obj->auth_token,              '1234', "Got updated auth_token." );
    is( $obj->payload->{access_token}, '1234', "Got updated access_token." );

    return;
}

sub test_handle_error : Tests() {

    my $mock_self = bless {}, 'mock::self';
    my $mock_rand = Test::MockModule->new('Cpanel::Rand::Get');
    $mock_rand->redefine( 'getranddata' => sub { return '123456' } );

    my $expected_die_message = "[123456] The Site Quality Monitoring service is experiencing technical difficulties. Try again later.\n";

    my $tests = [
        {
            isa     => 'Cpanel::HTTP::Client::Response',
            methods => {
                url     => 'http://url.test/response',
                status  => '500',
                reason  => 'a failure reason',
                content => '{"error":"some content"}',
            },
            expected => '[123456] The Site Quality Monitoring request to http://url.test/response returned a 500 status: a failure reason: some content',
            testname => 'Cpanel::HTTP::Client::Response exception',
        },
        {
            isa     => 'Cpanel::Exception::HTTP::Network',
            methods => {
                get_url_without_password => 'http://url.test/network',
                get                      => 'an error message',
            },
            expected => '[123456] The Site Quality Monitoring request to http://url.test/network failed: an error message',
            testname => 'Cpanel::Exception::HTTP::Network exception',
        },
        {
            string   => 'a stringy error',
            expected => '[123456] A Site Quality Monitoring remote request failed: a stringy error',
            testname => 'error as a string',
        },
        {
            isa      => 'Cpanel::Unexpected::Object',
            expected => '[123456] A Site Quality Monitoring remote request failed.',
            testname => 'Unexpected error',
        },

    ];

    my ( @log_msgs, $excep );

    foreach my $test ( $tests->@* ) {

        Test::Cpanel::Logger::clear_logger();

        if ( $test->{isa} ) {
            my $mock_obj = Test::MockObject->new();
            $mock_obj->set_isa( $test->{isa} );

            foreach my $method ( keys $test->{methods}->%* ) {
                $mock_obj->set_always( $method, $test->{methods}{$method} );
            }

            local $@;
            eval { Cpanel::Koality::ApiClient::handle_error( $mock_self, $mock_obj ) };
            $excep = $@;

            @log_msgs = Test::Cpanel::Logger::get_logger_messages();
        }
        elsif ( $test->{string} ) {

            local $@;
            eval { Cpanel::Koality::ApiClient::handle_error( $mock_self, $test->{string} ) };
            $excep = $@;

            @log_msgs = Test::Cpanel::Logger::get_logger_messages();
        }

        is( $excep,                     $expected_die_message, $test->{testname} . ": The method died with the correct message." );
        is( @log_msgs,                  1,                     $test->{testname} . ": There is only one log message" );
        is( $log_msgs[0][0]->{message}, $test->{expected},     $test->{testname} . ": The expected log message is logged." );
    }

    Test::Cpanel::Logger::clear_logger();

    return;
}

sub test_handle_success : Tests() {

    my $mock_self = bless {}, 'mock::self';

    my $mock_rand = Test::MockModule->new('Cpanel::Rand::Get');
    $mock_rand->redefine( 'getranddata' => sub { return '123456' } );

    my $mock_json = Test::MockModule->new('Cpanel::JSON');
    my $response_content;
    my $should_die = 0;
    $mock_json->redefine( 'Load' => sub { die "Died\n" if $should_die; return $response_content } );

    my $expected_die_message = "[123456] The Site Quality Monitoring service is experiencing technical difficulties. Try again later.\n";
    my $expected_log_message = "[123456] A request to the Site Quality Monitoring service returned an invalid response: Died\n";

    my $mock_obj = Test::MockObject->new();
    $mock_obj->set_isa('Cpanel::HTTP::Client::Response');
    $mock_obj->set_always( 'content', 'some content' );

    local $@;
    $response_content = "expected content";
    my $ret = eval { Cpanel::Koality::ApiClient::handle_success( $mock_self, $mock_obj ) };
    ok( !$@, 'Happy path: No exception is thrown.' );
    is( $ret, $response_content, 'Happy path: got expected reponse content' );

    Test::Cpanel::Logger::clear_logger();

    $should_die = 1;

    $ret = eval { Cpanel::Koality::ApiClient::handle_success( $mock_self, $mock_obj ) };
    is( $@, $expected_die_message, "Bad Response: Died with the correct message." );

    my @log_msgs = Test::Cpanel::Logger::get_logger_messages();
    is( @log_msgs,                  1,                     "Bad Response: There is only one log message" );
    is( $log_msgs[0][0]->{message}, $expected_log_message, 'Bad Response: The expected log message is logged.' );

    Test::Cpanel::Logger::clear_logger();

    return;
}

1;

package Cpanel::Koality::Mock::User;

sub session_token { return '1234' }

1;
