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

#                                      Copyright 2024 WebPros International, LLC
#                                                           All rights reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited.

use v5.36;
use Test::More;
use Test::Deep;
use Test::MockModule;
use Test::MockFile qw/nostrict/;
use Test::Warn;
use Test::Exception;

use Whostmgr::360Monitoring::Setup;

subtest "test_is_setup" => sub {

    my $mock_pwcache = Test::MockModule->new('Cpanel::PwCache');
    $mock_pwcache->redefine( 'getusername' => 'testissetup' );

    my $mock_setup = Test::MockModule->new('Whostmgr::360Monitoring::Setup');
    $mock_setup->redefine(
        'is_agent360_running'                  => 1,
        'are_agent360_default_plugins_enabled' => 1,

    );
    my $is_setup = Whostmgr::360Monitoring::Setup::is_setup();
    is( $is_setup, 1, "is_setup returns true" );

    $mock_setup->redefine(
        'is_agent360_running'                  => 0,
        'are_agent360_default_plugins_enabled' => 0,

    );

    my $is_setup_f = Whostmgr::360Monitoring::Setup::is_setup();
    is( $is_setup_f, 0, "is_setup returns false" );
};

subtest "test_is_360Monitoring_allowed" => sub {

    my $mock_comp_rules = Test::MockModule->new('Cpanel::Plugins::Components::Rules');
    $mock_comp_rules->redefine(
        'new' => sub {
            return bless {}, 'Cpanel::Plugins::Components::Rules';
        },
        'is_allowed' => 1,
    );

    is( Whostmgr::360Monitoring::Setup::is_360Monitoring_allowed(), 1, "is_360Monitoring_allowed returns true" );

};

subtest "test_is_agent360_running" => sub {

    my $mock_agent_manager = Test::MockModule->new('Whostmgr::360Monitoring::AgentManager');
    $mock_agent_manager->redefine( 'get_status' => 'active' );

    is( Whostmgr::360Monitoring::Setup::is_agent360_running(), 1, "test_is_agent360_running returns true" );

};

subtest "test_are_agent360_default_plugins_enabled" => sub {

    my $mock_agent = Test::MockModule->new('Whostmgr::360Monitoring::Agent');

    $mock_agent->redefine(
        'load_from_file' => sub {
            return bless { 'default_plugins' => ['httpd'], }, 'Whostmgr::360Monitoring::Agent';
        },
        'get_plugin' => sub {
            return;
        },
        'install_plugins' => 1,
    );

    my $mock_setup = Test::MockModule->new('Whostmgr::360Monitoring::Setup');
    $mock_setup->redefine( '_restart_agent' => 1 );

    is( Whostmgr::360Monitoring::Setup::are_agent360_default_plugins_enabled(), 1, "test_are_agent360_default_plugins_enabled returns true" );

};
subtest "test_setup_monitoring" => sub {

    my $mock_agent = Test::MockModule->new('Whostmgr::360Monitoring::Agent');

    $mock_agent->redefine(
        'load_from_file' => sub {
            return bless { 'default_plugins' => ['httpd'], }, 'Whostmgr::360Monitoring::Agent';
        },
        'get_plugin' => sub {
            return bless {
                'name'    => 'httpd',
                'enabled' => 0,
              },
              'Whostmgr::360Monitoring::Agent::Plugins::Httpd';
        },
        'install_plugins' => 1,
    );

    my $mock_saferun = Test::MockModule->new('Cpanel::SafeRun::Object');
    my ( $program, $args );
    $mock_saferun->redefine(
        'new'    => sub { return bless {}, 'Cpanel::SafeRun::Object'; },
        'stdout' => 1,
    );

    my $mock_setup = Test::MockModule->new('Whostmgr::360Monitoring::Setup');
    $mock_setup->redefine( '_restart_agent' => 1 );

    is( Whostmgr::360Monitoring::Setup::setup_monitoring('test_user'), 1, "test_setup_monitoring returns true" );

};
subtest "test_check_runscript_task" => sub {

    my $mock_taskqueue = Test::MockModule->new('Cpanel::TaskQueue::Reader');
    $mock_taskqueue->redefine(
        'read_queue' => sub {
            my $queue = {
                'processing_queue' => [
                    {
                        '_args'    => ['/usr/local/cpanel/scripts/initialize_360monitoring'],
                        '_command' => 'run_script',
                    }
                ],
                'waiting_queue' => [],
            };
            return $queue;
        }
    );

    my $proc_queue = Whostmgr::360Monitoring::Setup::check_runscript_task('/usr/local/cpanel/scripts/initialize_360monitoring');
    is( $proc_queue->{'status'}, 0, "returns false when task in process queue" );
    is(
        $proc_queue->{'error'},
        "Initialization is in progress. Please wait and try again.",
        "returns error message when task in process queue"
    );

    $mock_taskqueue->redefine(
        'read_queue' => sub {
            return {
                'waiting_queue' => [
                    {
                        '_args'    => ['/usr/local/cpanel/scripts/initialize_360monitoring'],
                        '_command' => 'run_script',
                    }
                ],
                'processing_queue' => [],
            };
        }
    );

    my $wait_queue = Whostmgr::360Monitoring::Setup::check_runscript_task('/usr/local/cpanel/scripts/initialize_360monitoring');
    is(
        $wait_queue->{'error'},
        "Initialization is queued. Please wait and try again.",
        "returns error message when task in process queue"
    );

    $mock_taskqueue->redefine(
        'read_queue' => sub {
            return {
                'waiting_queue'    => [],
                'processing_queue' => [],
            };
        }
    );

    my $empty_queue = Whostmgr::360Monitoring::Setup::check_runscript_task('/usr/local/cpanel/scripts/initialize_360monitoring');
    is( $empty_queue->{'status'}, 1,     "returns true when queue is empty" );
    is( $empty_queue->{'error'},  undef, "returns no errors when queue is empty" );

};

subtest "test_initialize" => sub {

    my $mock_pwcache   = Test::MockModule->new('Cpanel::PwCache');
    my $mock_taskqueue = Test::MockModule->new('Cpanel::TaskQueue::Reader');
    my $mock_360_auth  = Test::MockModule->new('Whostmgr::360Monitoring::Auth');
    my $mock_360_user  = Test::MockModule->new('Whostmgr::360Monitoring::User');
    my $mock_setup     = Test::MockModule->new('Whostmgr::360Monitoring::Setup');
    my $mock_agent     = Test::MockModule->new('Whostmgr::360Monitoring::Agent');
    my $mock_logger    = Test::MockModule->new('Cpanel::Logger');

    $mock_agent->redefine(
        'load_from_file' => sub {
            return bless { 'default_plugins' => ['httpd'], }, 'Whostmgr::360Monitoring::Agent';
        },
        'get_plugin' => sub {
            return bless {
                'name'    => 'httpd',
                'enabled' => 0,
              },
              'Whostmgr::360Monitoring::Agent::Plugins::Httpd';
        },
        'install_plugins' => 1,
    );
    $mock_pwcache->redefine( 'getusername' => 'testinit' );
    $mock_taskqueue->redefine(
        'read_queue' => sub {
            return {
                'waiting_queue'    => [],
                'processing_queue' => [],
            };
        }
    );

    subtest "test_setup_failure" => sub {
        $mock_360_auth->redefine(
            'new' => sub {
                my ( $class, $user_360 ) = @_;
                return bless { locale => 'en' }, 'Whostmgr::360Monitoring::Auth';
            },
        );
        $mock_360_user->redefine(
            'new' => sub {
                my ( $class, $user_360 ) = @_;
                return bless {
                    username => $user_360,
                    user_id  => '9999999999',
                    api_key  => 'test',
                  },
                  'Whostmgr::360Monitoring::User';
            }
        );
        $mock_setup->redefine(
            'is_360Monitoring_allowed' => 1,
            'is_setup'                 => 0,
            'setup_staging'            => 1,
            'setup_miniapp'            => 1,
            'enable_user_config'       => 1,
            'setup_monitoring'         => sub {
                die "setup_monitoring failed";
            },

        );

        eval { Whostmgr::360Monitoring::Setup::initialize() };
        my $error_user = $@;
        like( $error_user, qr/Failed to setup Server Monitoring for user/, "initialize returns error when setup_monitoring fails" );
    };
    subtest "test_setup_failure" => sub {
        $mock_360_auth->redefine(
            'new' => sub {
                my ( $class, $user_360 ) = @_;
                return bless { locale => 'en' }, 'Whostmgr::360Monitoring::Auth';
            },
            'create_user' => sub {
                die "Create user failed";
            },
        );
        $mock_360_user->redefine(
            'new' => sub {
                my ( $class, $user_360 ) = @_;
                return bless {
                    username => $user_360,
                    user_id  => '',
                    api_key  => '',
                  },
                  'Whostmgr::360Monitoring::User';
            }
        );
        $mock_setup->redefine(
            'setup_miniapp'            => 1,
            'is_360Monitoring_allowed' => 1,
            'enable_user_config'       => 1,
        );
        eval { Whostmgr::360Monitoring::Setup::initialize() };
        my $error_user = $@;
        like( $error_user, qr/Unable to create an user account in Server Monitoring for user/, "initialize returns error when user can not be created" );
    };

    subtest "test_setups" => sub {
        $mock_agent = Test::MockModule->new('Whostmgr::360Monitoring::Agent');
        $mock_agent->redefine( 'IS_STAGING' => 1 );

        my $mock_slurper = Test::MockModule->new('Cpanel::Slurper');
        my ( $read_file, $write_file );
        $mock_slurper->redefine(
            'read' => sub {
                $read_file = shift;
                return 1;
            },
            'write' => sub {
                $write_file = shift;
                return 1;
            }
        );

        my $mock_saferun = Test::MockModule->new('Cpanel::SafeRun::Object');
        my ( $program, $args );
        $mock_saferun->redefine(
            'new'    => sub { die; },
            'stdout' => 1,
        );

        $mock_360_auth->redefine(
            'new' => sub {
                my ( $class, $user_360 ) = @_;
                return bless {
                    locale => 'en',
                  },
                  'Whostmgr::360Monitoring::Auth';
            },
            'create_user' => sub {
                my $class = shift;
                return Whostmgr::360Monitoring::User->new();
            }
        );

        $mock_360_user->redefine(
            'new' => sub {
                my ( $class, $user_360 ) = @_;
                return bless {
                    username => $user_360,
                    user_id  => '9999999999',
                    api_key  => 'test',
                  },
                  'Whostmgr::360Monitoring::User';
            },
            'enabled' => sub {
                my ( $class, $value ) = @_;
                return $value;
            },
            'save_user_info' => sub {
                my $class = shift;
                return 1;
            }
        );

        eval { Whostmgr::360Monitoring::Setup::initialize(); };
        my $error_user = $@;
        like( $error_user, qr/Failed to setup Server Monitoring/, "initialize returns error on failed setup" );
    };
    subtest "test_setup_with_already_running_agent360" => sub {
        $mock_360_auth->redefine(
            'new' => sub {
                my ( $class, $user_360 ) = @_;
                return bless { locale => 'en' }, 'Whostmgr::360Monitoring::Auth';
            },
            'create_user' => sub {
                my $class = shift;
                return Whostmgr::360Monitoring::User->new();
            }
        );
        $mock_360_user->redefine(
            'new' => sub {
                my ( $class, $user_360 ) = @_;
                return bless {
                    username => $user_360,
                    user_id  => '',
                    api_key  => '',
                  },
                  'Whostmgr::360Monitoring::User';
            }
        );
        $mock_setup->redefine(
            'is_360Monitoring_allowed'       => 1,
            'is_agent360_running'            => 1,
            'is_monitoring_plugin_installed' => 0,
            'enable_user_config'             => 1,
        );
        my @warn;
        $mock_logger->redefine( 'warn', sub { shift @_; push @warn, @_ } );

        my $init_user = Whostmgr::360Monitoring::Setup::initialize();
        is( scalar @warn, 1, 'expected number of logger warn captured' )
          or diag explain \@warn;
        like( $warn[-1], qr/360 Monitoring will not be installed/, 'expected info log captured' );
        is( $init_user, undef, "360 Monitoring is not installed when agent360 is already running" );
    };

    $mock_agent = Test::MockModule->new('Whostmgr::360Monitoring::Agent');
    $mock_agent->redefine( 'IS_STAGING' => 1 );

    my $mock_agent_manager = Test::MockModule->new('Whostmgr::360Monitoring::AgentManager');
    $mock_agent_manager->redefine( 'restart' => 1 );

    my $mock_slurper = Test::MockModule->new('Cpanel::Slurper');
    my ( $read_file, $write_file );
    $mock_slurper->redefine(
        'read' => sub {
            $read_file = shift;
            return 1;
        },
        'write' => sub {
            $write_file = shift;
            return 1;
        }
    );
    $mock_360_auth->redefine(
        'new' => sub {
            my ( $class, $user_360 ) = @_;
            return bless { locale => 'en' }, 'Whostmgr::360Monitoring::Auth';
        },
        'create_user' => sub {
            die "Create user failed";
        },
    );
    $mock_360_user->redefine(
        'new' => sub {
            my ( $class, $user_360 ) = @_;
            return bless {
                username => $user_360,
                user_id  => '99999999',
                api_key  => 'test',
              },
              'Whostmgr::360Monitoring::User';
        }
    );

    my $mock_saferun = Test::MockModule->new('Cpanel::SafeRun::Object');
    my ( $program, $args );
    $mock_saferun->redefine(
        'new'    => sub { return bless {}, 'Cpanel::SafeRun::Object'; },
        'stdout' => 1,
    );
    $mock_setup = '';
    $mock_setup = Test::MockModule->new('Whostmgr::360Monitoring::Setup');
    $mock_setup->redefine(
        'is_360Monitoring_allowed' => 1,
        'is_setup'                 => 0,
        'setup_staging'            => 1,
        'setup_miniapp'            => 1,
        'enable_user_config'       => 1,

    );

    my @info;
    $mock_logger->redefine( 'info', sub { shift @_; push @info, @_ } );

    my $init_user = Whostmgr::360Monitoring::Setup::initialize();
    is( scalar @info, 5, 'expected number of logger info captured' )
      or diag explain \@info;
    like( $info[-1], qr/Restarting the 360 Agent/, 'expected info log captured' );

    ok( $init_user, '360Monitoring initialized' );
};

subtest "test_setup_miniapp" => sub {
    Whostmgr::360Monitoring::Config::clear_cache();
    my $config = <<~"END_CONFIG";
        auto-enable-miniapp:
        - company-id:
          - 7     # cpanel employess, dns only
        END_CONFIG
    my $mock_config = Test::MockFile->file( '/var/cpanel/plugins/monitoring/config.yaml', $config );

    my ( $store, $name, $value );
    my $mock = Test::MockModule->new('Cpanel::License::CompanyID');
    $mock->redefine(
        'get_company_id' => 7,
    );

    my $mock_acls = Test::MockModule->new('Whostmgr::ACLS');
    $mock_acls->redefine(
        'init_acls' => 1,
    );
    my $mock_set_nv_data = Test::MockModule->new('Cpanel::Plugins::Components::Rules::Util::NVData');
    $mock_set_nv_data->redefine(
        'set_nv_data' => sub {
            ( $store, $name, $value ) = @_;
            return 1;
        },
    );
    my @info;
    my $mock_logger = Test::MockModule->new('Cpanel::Logger');
    $mock_logger->redefine( 'info', sub { shift @_; push @info, @_ } );

    lives_ok( sub { Whostmgr::360Monitoring::Setup::setup_miniapp() }, 'setup_miniapp runs as expected' );
    like( $info[-1], qr/Enabled miniapp for default company_id list/, 'Miniapp enabled as expected in info log' );
    cmp_deeply(
        {
            store => $store,
            name  => $name,
            value => $value,
        },
        {
            store => 'cpanel.360-monitoring.plugin',
            name  => 'homepage-app-enabled',
            value => 1,
        },
        'Miniapp enabled as expected in NVData'
    );

    $mock->redefine(
        'get_company_id' => 17,
    );
    @info = ();
    lives_ok( sub { Whostmgr::360Monitoring::Setup::setup_miniapp() }, 'setup_miniapp runs fine as expected for non-default company ids' );
    is( @info, 0, 'Did not enable miniapp for non default company id list' );
};

subtest 'is_monitoring_plugin_installed' => sub {
    subtest 'when monitoring is already installed' => sub {
        my $mock = Test::MockModule->new('Cpanel::AppConfig');
        $mock->redefine(
            'get_application_list' => sub {
                return { whostmgr => [ { origin => 'whm-360-monitoring.conf' } ] };
            },
        );

        is( Whostmgr::360Monitoring::Setup::is_monitoring_plugin_installed(), 1, 'return true value when monitoring plugin is installed' );
    };

    subtest 'when monitoring is NOT already installed' => sub {
        my $mock = Test::MockModule->new('Cpanel::AppConfig');
        $mock->redefine(
            'get_application_list' => sub {
                return { whostmgr => [] };
            },
        );

        is( Whostmgr::360Monitoring::Setup::is_monitoring_plugin_installed(), 0, 'returns false value when monitoring plugin is installed' );
    };
};

subtest "test_local_disable" => sub {

    my $mock_feature_flags = Test::MockModule->new('Cpanel::FeatureFlags');
    my @disable_feature_flags;
    my ($enable_feature_flags);

    $mock_feature_flags->redefine(
        'disable' => sub {
            my $disable_feature_flag = shift;
            push @disable_feature_flags, $disable_feature_flag;
            return 1;
        },
        'enable' => sub {
            $enable_feature_flags = shift;
            return 1;
        },
    );

    my $mock_saferun = Test::MockModule->new('Cpanel::SafeRun::Object');
    my ( $class, $program, $args );
    $mock_saferun->redefine(
        'new' => sub {
            ( $class, $program, $args ) = @_;
            return bless {}, 'Cpanel::SafeRun::Object';
        },
        'stdout'      => 1,
        'CHILD_ERROR' => 0,
    );

    my $mock_agent_manager = Test::MockModule->new('Whostmgr::360Monitoring::AgentManager');
    $mock_agent_manager->redefine( 'disable' => 1 );

    my @info;
    my $mock_logger = Test::MockModule->new('Cpanel::Logger');
    $mock_logger->redefine( 'info', sub { shift @_; push @info, @_ } );

    lives_ok( sub { Whostmgr::360Monitoring::Setup::local_disable() }, 'local_disable runs fine as expected' );
    my @expected_disable_feature_flags = ( 'cpanel.360-monitoring.plugin.local.enable', 'cpanel.360-monitoring.plugin.installed' );
    is( @disable_feature_flags, @expected_disable_feature_flags,               "local_disable disables the expected list of disable feature flags." );
    is( $enable_feature_flags,  'cpanel.360-monitoring.plugin.local.disable',  "local_disable enables the right feature flag as expected." );
    is( $args,                  '/var/cpanel/plugins/monitoring/uninstall.sh', "local_disable is expected to run uninstall.sh." );

    is( @info, 1, "local_disable returns the exact number of logs as expected." );

    # die on error
    $mock_saferun->redefine( 'CHILD_ERROR' => 1 );
    dies_ok(
        sub {
            Whostmgr::360Monitoring::Setup::local_disable();
        },
        "local_disable dies as expected for saferun failure ."
    );

};

subtest "test_local_enable" => sub {

    my $mock_feature_flags = Test::MockModule->new('Cpanel::FeatureFlags');
    my $disable_feature_flags;
    my @enable_feature_flags;

    $mock_feature_flags->redefine(
        'enable' => sub {
            my $enable_feature_flag = shift;
            push @enable_feature_flags, $enable_feature_flag;
            return 1;
        },
        'disable' => sub {
            $disable_feature_flags = shift;
            return 1;
        },
        'is_feature_enabled' => 0,
    );

    my $mock_setup = Test::MockModule->new('Whostmgr::360Monitoring::Setup');
    $mock_setup->redefine( 'initialize' => 1 );

    lives_ok( sub { Whostmgr::360Monitoring::Setup::local_enable() }, 'local_enable runs fine as expected' );
    my @expected_enable_feature_flags = ( 'cpanel.360-monitoring.plugin.local.enable', 'cpanel.360-monitoring.plugin.installed' );
    is( @enable_feature_flags,  @expected_enable_feature_flags,               "local_enable enables the expected list of enable feature flags." );
    is( $disable_feature_flags, 'cpanel.360-monitoring.plugin.local.disable', "local_enable disables the right feature flag as expected." );

    # if it is disabled globally
    $mock_feature_flags->redefine( 'is_feature_enabled' => 1 );
    eval { Whostmgr::360Monitoring::Setup::local_enable() };

    my $exception = $@;
    like( $exception, qr/360 Monitoring cannot be installed currently/, "local_enable does not enable when there is a global disabled flag" );

};

subtest "test_disable_user_config" => sub {

    my $user_360   = '360test';
    my $mock_setup = Test::MockModule->new('Whostmgr::360Monitoring::Setup');
    my ( $src, $dest );
    $mock_setup->redefine( '_get_username' => $user_360 );
    $mock_setup->redefine(
        '_move_files' => sub {
            ( $src, $dest ) = @_;
            return 1;
        }
    );

    my $config          = '/root/.360monitoring/testconfig';
    my $disabled_config = '/root/.360monitoring/testconfig.disabled';
    my $conf_dir        = '/root/.360monitoring';
    my $config_data     = {
        username     => $user_360,
        user_id      => '99999999',
        api_key      => 'test',
        '_conf_file' => $config,
        '_conf_dir'  => $conf_dir,
    };
    my $mock_config          = Test::MockFile->file( $config,          $config_data );
    my $mock_disabled_config = Test::MockFile->file( $disabled_config, '' );
    my $mock_360_user        = Test::MockModule->new('Whostmgr::360Monitoring::User');
    $mock_360_user->redefine(
        'new' => sub {
            my ( $class, $user_360 ) = @_;
            return bless $config_data, 'Whostmgr::360Monitoring::User';
        }
    );
    is( Whostmgr::360Monitoring::Setup::disable_user_config(), 1,                "test_disable_user_config returns true" );
    is( $src,                                                  $config,          "test_disable_user_config returns the expected user conf file" );
    is( $dest,                                                 $disabled_config, "test_disable_user_config returns the expected disabled conf file" );

};

subtest "test_enable_user_config" => sub {

    my $user_360   = '360test';
    my $mock_setup = Test::MockModule->new('Whostmgr::360Monitoring::Setup');
    my ( $src, $dest );
    $mock_setup->redefine( '_get_username' => $user_360 );
    $mock_setup->redefine(
        '_move_files' => sub {
            ( $src, $dest ) = @_;
            return 1;
        }
    );

    my $config          = '/root/.360monitoring/testconfig';
    my $disabled_config = '/root/.360monitoring/testconfig.disabled';
    my $conf_dir        = '/root/.360monitoring';
    my $config_data     = {
        username     => $user_360,
        user_id      => '99999999',
        api_key      => 'test',
        '_conf_file' => $config,
        '_conf_dir'  => $conf_dir,
    };
    my $mock_config          = Test::MockFile->file( $config,          $config_data );
    my $mock_disabled_config = Test::MockFile->file( $disabled_config, $config_data );
    my $mock_360_user        = Test::MockModule->new('Whostmgr::360Monitoring::User');
    $mock_360_user->redefine(
        'new' => sub {
            my ( $class, $user_360 ) = @_;
            return bless $config_data, 'Whostmgr::360Monitoring::User';
        }
    );
    is( Whostmgr::360Monitoring::Setup::enable_user_config(), 1,                "test_enable_user_config returns true" );
    is( $src,                                                 $disabled_config, "test_enable_user_config returns the disabled conf file" );
    is( $dest,                                                $config,          "test_enable_user_config returns the expected user conf file" );

};
done_testing();
