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

# cpanel - t/medium/scripts-modify_default_featurelist.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::scripts::modify_default_featurelist_entry;

use Test2::V0 -no_utf8 => 1;
use Test2::Tools::Explain;
use Test2::Plugin::NoWarnings;
use Test2::Tools::Exception qw/dies/;
use Test2::Tools::Warnings;

use Test::Warn;
use Test::Cpanel::Policy;

use Cpanel::ConfigFiles ();

use parent qw(
  Cpanel::TestObj
);

require "/usr/local/cpanel/scripts/modify_default_featurelist_entry.pl";
$INC{'scripts/modify_default_featurelist_entry.pm'} = __PACKAGE__;

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

#----------------------------------------------------------------------

#e.g., num_method_tests()
sub new ( $class, @args ) {
    my $self = $class->SUPER::new(@args);
    return $self;
}

#e.g., set environs before running tests
sub runtests ( $self, @args ) {
    return $self->SUPER::runtests(@args);
}

sub test__verify_directories : Tests(1) ($self) {

    no warnings qw{redefine once};
    local *mkdir = sub { return 0 };

    my @mocks = (
        $self->mock_subs(
            'Cpanel::FileUtils::TouchFile::touchfile' => sub { return 1 },
        )
    );

    my $mocked_FEATURES_DIR        = Test::MockFile->new_dir($Cpanel::ConfigFiles::FEATURES_DIR);
    my $mocked_default_featurelist = Test::MockFile->file('/var/cpanel/features/default');

    my @logged_warnings;
    local *Cpanel::Logger::warn = sub {
        @logged_warnings = @_;
    };

    scripts::modify_default_featurelist_entry::_verify_directories();

    is( @logged_warnings, L(), 'warns when directory cannot be created' );
}

sub test_modify_feature_for_all_feature_lists : Tests(1) ($self) {

    my $mocked_FEATURES_DIR = Test::MockFile->dir($Cpanel::ConfigFiles::FEATURES_DIR);
    my %features            = (
        'filemanager'     => 1,
        'popaccts'        => 1,
        'addondomains'    => 1,
        'sslmanager'      => 1,
        'webmail'         => 1,
        'version_control' => 1,
        'postgres'        => 1
    );
    my $mocked_default_featurelist  = Test::MockFile->file( '/var/cpanel/features/default',  \%features );
    my $mocked_disabled_featurelist = Test::MockFile->file( '/var/cpanel/features/disabled', '' );
    my $mocked_custom_featurelist   = Test::MockFile->file( '/var/cpanel/features/custom',   \%features );

    my @mocks = (
        $self->mock_subs(
            'scripts::modify_default_featurelist_entry::_verify_directories' => sub { return 1 },
            'Cpanel::Features::Load::load_featurelist'                       => sub {
                my $featurelist_name = shift;
                my $feature_list;
                if ( $featurelist_name eq "default" ) {
                    $feature_list = $mocked_default_featurelist->contents();
                }
                if ( $featurelist_name eq "custom" ) {
                    $feature_list = $mocked_custom_featurelist->contents();
                }
                return $feature_list;
            },
            'Cpanel::Features::Write::write_featurelist' => sub {
                my ( $featurelist_name, $new_feature_list ) = @_;
                my $feature_list;
                if ( $featurelist_name eq "default" ) {
                    $feature_list = $mocked_default_featurelist->contents();
                }
                if ( $featurelist_name eq "custom" ) {
                    $feature_list = $mocked_custom_featurelist->contents();
                }
                return $feature_list;
            },
        )
    );

    my $modify = scripts::modify_default_featurelist_entry::modify_feature_for_all_feature_lists( 'sitejet', 1 );
    is( $modify, 1, 'modify does not fail' ) or diag explain $modify;
}

sub test_do_once : Tests(7) ($self) {
    my $touchfile_succeeds = 1;
    my $version            = "11.110_disable_sitejet";
    my $VERSION_DIR        = '/var/cpanel/version';

    my $mocked_lockfile = Test::MockFile->file( $VERSION_DIR . '/cpanel' . "$version" );

    my @mocks = (
        $self->mock_subs(
            'scripts::modify_default_featurelist_entry::_verify_directories' => sub { return 1 },
            'Cpanel::FileUtils::TouchFile::touchfile'                        => sub {
                $mocked_lockfile->touch() if $touchfile_succeeds;
                return $touchfile_succeeds;
            },
            'scripts::modify_default_featurelist_entry::modify_feature_for_all_feature_lists' => sub { return 1 },
        )
    );

    # test invalid params
    my $invalid_params = scripts::modify_default_featurelist_entry::do_once();
    is( $invalid_params, undef, 'returns early if no params' );

    # test happy path
    my $do_once = eval {
        scripts::modify_default_featurelist_entry::do_once(
            'version' => "$version",
            'eol'     => 'never',
            'code'    => sub { scripts::modify_default_featurelist_entry::modify_feature_for_all_feature_lists( 'sitejet', 1 ) },
        );
    };
    is( $do_once, 1, 'do_once executes and calls method to modify feature lists' );

    # test when the touchfile already exists
    $touchfile_succeeds = 1;
    my $ret_preexist_touchfile;
    ok(
        lives {
            $ret_preexist_touchfile = scripts::modify_default_featurelist_entry::do_once(
                'version' => "$version",
                'eol'     => 'never',
                'code'    => sub { scripts::modify_default_featurelist_entry::modify_feature_for_all_feature_lists( 'sitejet', 1 ) },
            );
        },
        "did not die, despite touchfile problem"
    ) or note($@);

    is( $ret_preexist_touchfile, undef, 'does nothing and returns undef if touchfile already exists' );

    # test when there's a problem creating the touchfile
    $mocked_lockfile->unlink();
    $touchfile_succeeds = 0;
    my $ret_no_touchfile;
    warnings_like {
        ok(
            lives {
                $ret_no_touchfile = scripts::modify_default_featurelist_entry::do_once(
                    'version' => "$version",
                    'eol'     => 'never',
                    'code'    => sub { scripts::modify_default_featurelist_entry::modify_feature_for_all_feature_lists( 'sitejet', 1 ) },
                );
            },
            "does not die, even if there's a problem creating the touchfile"
        ) or note($@);
    }
    [qr/Failed to touch.*version file/], "do_once warns and returns if touch file can't be created";

    is( $ret_no_touchfile, 1, 'return 1 if it fails to touch the touchfile successfully' );
}
