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

# cpanel - t/medium/Cpanel-API-Sitejet.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::API::Sitejet;

use cPstrict;

use Test2::V0;

use Test::MockFile;
use Test::MockObject;

use Test::Cpanel::Policy;

use parent qw(
  Cpanel::TestObj
);

use Cpanel::Result ();
use Cpanel::Args   ();

use Cpanel::API::Sitejet ();

__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_create_account : Tests(5) ($self) {
    my ( $namespace, $module, $action, $api_key );
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new( {} );
    my @mocks  = $self->mock_subs(
        'Cpanel::Sitejet::Connector::createAccount' => sub {
            my $ret = {
                'key' => 'api_key',
            };
            return $ret;
        },
        'Cpanel::AdminBin::Call::call' => sub {
            ( $namespace, $module, $action, $api_key ) = @_;
            return;
        },
        'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; },
    );

    local $Cpanel::homedir = '/home/foobar';
    Cpanel::API::Sitejet::create_account( $args, $result );

    is( $namespace,      'Cpanel',                                    "AdminBin namespace is Cpanel" )       or diag explain $namespace;
    is( $module,         'sitejet',                                   "AdminBin module is sitejet" )         or diag explain $module;
    is( $action,         'ADD_API_TOKEN',                             "AdminBin action is ADD_API_TOKEN" )   or diag explain $action;
    is( $api_key,        'api_key',                                   "AdminBin data is the api key" )       or diag explain $api_key;
    is( $result->{data}, Cpanel::Sitejet::Connector::createAccount(), "UAPI call returns sitejet response" ) or diag explain $result;
}

sub test_get_templates : Tests(1) ($self) {
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new( {} );
    my @mocks  = $self->mock_subs(
        'Cpanel::Sitejet::Connector::cp_get_templates' => sub {
            my $ret = [
                {
                    "createdAt"   => "2023-03-18T10:01:02+01:00",
                    "description" => "",
                    "id"          => 371507,
                    "image"       => "/images/1024/6687284/OG_Image_Drive.png",
                    "name"        => "Drive",
                    "previewUrl"  => "https://www.template-drive.de.rs",
                    "tags"        => [
                        "onepager",
                        "new",
                        "services"
                    ],
                    "updatedAt" => "2023-07-03T16:22:12+02:00"
                },
                {
                    "createdAt"   => "2018-11-08T19:16:19+01:00",
                    "description" => '',
                    "id"          => 145599,
                    "image"       => "/images/1024/2958576/wireframe.jpg",
                    "name"        => "Wireframe",
                    "previewUrl"  => "https://www.template-wireframe.de.rs",
                    "tags"        => [
                        "multipager",
                        "trending",
                        "wireframe"
                    ],
                    "updatedAt" => "2022-12-09T18:18:00+01:00"
                },
            ];
            return $ret;
        },
        'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; },
    );

    local $Cpanel::homedir = '/home/foobar';
    Cpanel::API::Sitejet::get_templates( $args, $result );
    is( $result->{data}, Cpanel::Sitejet::Connector::cp_get_templates, "UAPI call returns sitejet response" ) or diag explain $result->{data};
}

sub test_set_template : Tests(4) ($self) {
    my ( $connector, $domain, $templateID, $templateName );
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new( { 'domain' => "example.com", 'templateId' => "12345", 'templateName' => 'foo' } );
    my @mocks  = $self->mock_subs(
        'Cpanel::Sitejet::Connector::selectTemplateForWebsite' => sub {
            ( $connector, $domain, $templateID, $templateName ) = @_;
            return { "success" => "true" };
        },
        'Cpanel::API::Sitejet::_validate_user_domain'      => 1,
        'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; },
    );

    local $Cpanel::homedir = '/home/foobar';
    Cpanel::API::Sitejet::set_template( $args, $result );
    is( $domain,         $args->{_args}{'domain'},       "domain is passed in correctly" )             or diag explain $domain;
    is( $templateID,     $args->{_args}{'templateId'},   "templateId is passed in correctly" )         or diag explain $templateID;
    is( $templateName,   $args->{_args}{'templateName'}, "templateName is passed in correctly" )       or diag explain $templateName;
    is( $result->{data}, { "success" => "true" },        "data field contains success key and value" ) or diag explain $result;
}

sub test_get_sso_link : Tests(3) ($self) {
    my ( $connector, $domain, $referrer );
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new( { 'domain' => "example.com", 'referrer' => "cpanel" } );
    my @mocks  = $self->mock_subs(
        'Cpanel::Sitejet::Connector::getSSOLinkForWebsite' => sub {
            my $opts;
            ( $connector, $opts ) = @_;
            $domain   = $opts->{'domain'};
            $referrer = $opts->{'referrer'};
            my $ret = 'example.com/SSO_link';
            return $ret;
        },
        'Cpanel::API::Sitejet::_validate_user_domain'      => 1,
        'Cpanel::Locale::Utils::User::get_user_locale'     => 'en',
        'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; },
        'Cpanel::License::CompanyID::get_company_id'       => 215,
    );

    local $Cpanel::homedir = '/home/foobar';
    Cpanel::API::Sitejet::get_sso_link( $args, $result );
    is( $domain,         $args->{_args}{'domain'},                           "domain is passed in correctly" )   or diag explain $domain;
    is( $referrer,       $args->{_args}{'referrer'},                         "referrer is passed in correctly" ) or diag explain $referrer;
    is( $result->{data}, Cpanel::Sitejet::Connector::getSSOLinkForWebsite(), "data field contains SSO link" )    or diag explain $result;
}

sub test_get_preview_url : Tests(1) ($self) {
    my ( $connector, $websiteId );
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new( { 'websiteId' => "12345" } );
    my @mocks  = $self->mock_subs(
        'Cpanel::Sitejet::Connector::cp_getPreviewUrl' => sub {
            ( $connector, $websiteId ) = @_;
            my $ret = 'example.com/website/12345/previewurl';
            return $ret;
        },
        'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; },
    );

    local $Cpanel::homedir = '/home/foobar';
    Cpanel::API::Sitejet::get_preview_url( $args, $result );
    is( $result->{data}, Cpanel::Sitejet::Connector::cp_getPreviewUrl(), "data field contains preview url" ) or diag explain $result;
}

sub test_get_api_token : Tests(1) ($self) {
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new( {} );
    my @mocks  = $self->mock_subs(
        'Cpanel::Sitejet::Connector::loadApiKey' => sub {
            my $ret = 'api_key ';
            return $ret;
        },
    );

    local $Cpanel::homedir = '/home/foobar';
    Cpanel::API::Sitejet::get_api_token( $args, $result );
    is( $result->{data}, Cpanel::Sitejet::Connector::loadApiKey(), "data field contains api token" ) or diag explain $result;
}

sub test_add_api_token : Tests(4) ($self) {
    my ( $namespace, $module, $action, $api_key );
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new( { "api_token" => "api_key" } );
    my @mocks  = $self->mock_subs(
        'Cpanel::Sitejet::Connector::loadApiKey' => sub {
            my $ret = 'api_key ';
            return $ret;
        },
        'Cpanel::AdminBin::Call::call' => sub {
            ( $namespace, $module, $action, $api_key ) = @_;
            return;
        },
    );

    local $Cpanel::homedir = '/home/foobar';
    Cpanel::API::Sitejet::add_api_token( $args, $result );
    is( $namespace, 'Cpanel',                    "AdminBin namespace is Cpanel" )     or diag explain $namespace;
    is( $module,    'sitejet',                   "AdminBin module is sitejet" )       or diag explain $module;
    is( $action,    'ADD_API_TOKEN',             "AdminBin action is ADD_API_TOKEN" ) or diag explain $action;
    is( $api_key,   $args->{_args}{"api_token"}, "AdminBin data is the api key" )     or diag explain $api_key;
}

sub test_create_website : Tests(2) ($self) {
    my ( $connector, $website_info_hr );
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new(
        {
            "domain"  => "example.com",
            "company" => "WebPros",
        }
    );    # Testing with minimum params first
    my @mocks = $self->mock_subs(
        'Cpanel::Sitejet::Connector::createWebsite' => sub {
            ( $connector, $website_info_hr ) = @_;
            $website_info_hr->{website_id} = "12345";
            return $website_info_hr->{website_id};
        },
        'Cpanel::API::Sitejet::_validate_user_domain'      => 1,
        'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; },
    );

    local $Cpanel::homedir = '/home/foobar';
    Cpanel::API::Sitejet::create_website( $args, $result );

    is( $result->{data}, $website_info_hr->{website_id}, "create_website returns website id (min params)" ) or diag explain $result;

    $args->{_args}{'Title'}     = 'myWebsite';
    $args->{_args}{'firstname'} = 'example';
    $args->{_args}{'lastname'}  = 'user';
    $args->{_args}{'street'}    = 'main st';
    $args->{_args}{'zip'}       = '00000';
    $args->{_args}{'city'}      = 'city';
    $args->{_args}{'country'}   = 'country';
    $args->{_args}{'email'}     = 'example.user@email.com';
    $args->{_args}{'phone'}     = '999-999-9999';
    $args->{_args}{'note'}      = 'example user';
    $args->{_args}{'metadata'}  = { 'website_id' => "12345", 'template_id' => "54321" };
    $args->{_args}{'assignTo'}  = 'example user';

    Cpanel::API::Sitejet::create_website( $args, $result );

    is( $result->{data}, $website_info_hr->{website_id}, "create_website returns website id (all params)" ) or diag explain $result;
}

sub test_get_user_site_metadata : Tests(1) ($self) {
    my ( $connector, $domain );
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new( { "domain" => "example.com" } );
    my $metadata;
    my @mocks = $self->mock_subs(
        'Cpanel::Sitejet::Connector::cp_load_sitejet_metadata' => sub {
            ( $connector, $domain ) = @_;
            $metadata = {
                "company"         => "example_company",
                "domain"          => "example.com",
                "fullcms"         => 1,
                "language"        => "en",
                "pleskDomainGUID" => "example.com",
                "publish_status"  => 1,
                "templateId"      => "333333",
                "websiteId"       => "999999",
            };
            return $metadata;
        },
        'Cpanel::API::Sitejet::_validate_user_domain'      => 1,
        'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; },
    );

    local $Cpanel::homedir = '/home/foobar';
    Cpanel::API::Sitejet::get_user_site_metadata( $args, $result );

    is( $result->{data}, $metadata, "get_user_site_metadata returns metadata" ) or diag explain $result;
}

sub test_get_all_sites_metadata : Tests(1) ($self) {
    my ( $connector, $domain );
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new( {} );
    my $metadata;
    my @mocks = $self->mock_subs(
        'Cpanel::Sitejet::Connector::cp_load_all_sitejet_domains_metadata' => sub {
            ( $connector, $domain ) = @_;
            $metadata = [
                {
                    "company"         => "example_company",
                    "domain"          => "example.com",
                    "fullcms"         => 1,
                    "language"        => "en",
                    "pleskDomainGUID" => "example.com",
                    "publish_status"  => 1,
                    "templateId"      => "333333",
                    "websiteId"       => "999999",
                }
            ];
            return $metadata;
        },
        'Cpanel::API::Sitejet::_validate_user_domain'      => 1,
        'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; },
    );

    local $Cpanel::homedir = '/home/foobar';
    Cpanel::API::Sitejet::get_all_sites_metadata( $args, $result );

    is( $result->{data}, $metadata, "get_all_sites_metadata returns metadata" ) or diag explain $result;
}

sub test_publish : Tests(1) ($self) {
    my ( $connector, $domain );
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new( { "domain" => "example.com" } );
    $Cpanel::homedir = "home";
    $Cpanel::user    = "test";
    my $mock_autodie = Test::MockModule->new('Cpanel::Autodie');
    $mock_autodie->define(
        'symlink' => 1,
    );
    my @mocks = $self->mock_subs(
        'Cpanel::Daemonizer::Tiny::run_as_daemon' => sub {
            return "999";
        },
        'Cpanel::API::Sitejet::_create_logging_stream_dir' => sub {
            return ( "path/to/log/txt", "LOG_ENTRY" );
        },
        'Cpanel::API::Sitejet::_validate_user_domain' => 1,
    );
    local $Cpanel::homedir = '/home/foobar';
    Cpanel::API::Sitejet::publish( $args, $result );

    is( $result->{data}, { "pid" => "999", "log_entry" => "LOG_ENTRY", "user" => $Cpanel::user }, "publish returns success" ) or diag explain $result;
}

sub test_start_publish : Tests(1) ($self) {
    my ( $connector, $domain );
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new( { "domain" => "example.com" } );
    $Cpanel::homedir = "/home/test";
    $Cpanel::user    = "test";
    my $temp_dir = "$Cpanel::homedir/logs";
    my @mocks    = $self->mock_subs(
        'Cpanel::Daemonizer::Tiny::run_as_daemon' => sub {
            return "999";
        },
        'Cpanel::API::Sitejet::_validate_user_domain' => 1,
        'Cpanel::SafeDir::MK::safemkdir_or_die'       => 1,
        'Cpanel::FileUtils::TouchFile::touchfile'     => 1,
    );
    my $mock_dir    = Test::MockFile->new_dir($temp_dir);
    my $publish_log = "$temp_dir/publish_" . DateTime->now->datetime . ".log";
    my $mock_file   = Test::MockFile->file( $publish_log, '' );
    Cpanel::API::Sitejet::start_publish( $args, $result );

    is( $result->{data}, { "pid" => "999", "file_name" => $publish_log }, "start_publish returns success" ) or diag explain $result;
}

sub _validate_user_domain : Tests(1) ($self) {
    my @mocks = $self->mock_subs(
        'Cpanel::DomainLookup::DocRoot::getdocroots' => {
            'foo.bar.tld'  => '/some/where',
            'same.bar.tld' => '/some/where/else',
            'main.tld'     => '/my/docroot',
            'parked.tld'   => '/my/docroot',
            '*.real.tld'   => '/wildcard/docroot',
            ( map { ( "$_.parked.tld" => "/my/$_" ) } qw( cpanel mail www ) ),
        },
    );
    my $ret = Cpanel::API::Sitejet::_validate_user_domain('main.tld');

    is( $ret, 1, "_validate_user_domain happy path returns success" );
}

sub test_get_sitebuilder_domain_statuses : Tests(1) ($self) {
    my ( $connector, $domain );
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new( { 'domain' => 'example.com' } );
    my @mocks  = $self->mock_subs(
        'Cpanel::Sitejet::Connector::cp_list_all_domain_sitebuilders' => sub {
            ( $connector, $domain ) = @_;
            return $domain;
        },
        'Cpanel::API::Sitejet::_validate_user_domain'      => 1,
        'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; },
    );

    local $Cpanel::homedir = '/home/foobar';
    Cpanel::API::Sitejet::get_sitebuilder_domain_statuses( $args, $result );
    is( $domain, 'example.com', "connector module receives the domain" ) or diag explain $domain;
}

sub test_disk_quota_check : Tests(4) ($self) {
    my ( $namespace, $module, $action, $domain );
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new( { 'domain' => 'example.com' } );
    my @mocks  = $self->mock_subs(
        'Cpanel::API::Sitejet::_validate_user_domain' => 1,
        'Cpanel::Sitejet::Publish::get_document_root' => '/home/user/public_html',
        'Cpanel::AdminBin::Call::call'                => sub {
            ( $namespace, $module, $action, $domain ) = @_;
            return;
        },
    );

    local $Cpanel::homedir = '/home/foobar';
    Cpanel::API::Sitejet::disk_quota_check( $args, $result );

    is( $namespace, 'Cpanel',           "AdminBin namespace is Cpanel" )        or diag explain $namespace;
    is( $module,    'sitejet',          "AdminBin module is sitejet" )          or diag explain $module;
    is( $action,    'DISK_QUOTA_CHECK', "AdminBin action is DISK_QUOTA_CHECK" ) or diag explain $action;
    is( $domain,    'example.com',      "AdminBin data is the domain" )         or diag explain $domain;

    return;
}

sub test_get_all_user_sitejet_info : Tests(8) ($self) {
    my ( $namespace, $module, $action, $domain_adminbin );
    my ( $func,      $method, $data_ref );
    my ( $connector, $domain_metadata, $domain_statuses, $metadata, $statuses, $quota );
    my $result      = Cpanel::Result->new();
    my $mocks       = _get_mocks_data();
    my $main_domain = $mocks->{'main_domain'};
    my $args        = Cpanel::Args->new( { 'domain' => $main_domain } );
    $Cpanel::homedir = "home";
    $Cpanel::user    = "testuser";
    my @mocks = $self->mock_subs(
        'Cpanel::API::Sitejet::_validate_user_domain' => 1,
        'Cpanel::Sitejet::Publish::get_document_root' => '/home/testuser/public_html',
        'Cpanel::AdminBin::Call::call'                => sub {
            ( $namespace, $module, $action, $domain_adminbin ) = @_;
            $quota = $mocks->{$domain_adminbin}->{'quota'};
            return $quota;
        },
        'Cpanel::Sitejet::Connector::cp_load_sitejet_metadata' => sub {
            ( $connector, $domain_metadata ) = @_;
            $metadata = $mocks->{$domain_metadata}->{'metadata'};
            return $metadata;
        },
        'Cpanel::Sitejet::Connector::cp_list_all_domain_sitebuilders' => sub {
            ( $connector, $domain_statuses ) = @_;
            $statuses = $mocks->{$domain_statuses}->{'statuses'};
            return $statuses;
        },
        'Cpanel::API::execute_or_die' => sub {
            ( $func, $method,, $data_ref ) = @_;
            my $data       = ( $func eq 'DomainInfo' && $method eq 'list_domains' ) ? $mocks->{'list_domains'} : $mocks->{'redirect_data'};
            my $result_obj = bless(
                {
                    'status'           => 1,
                    'warnings'         => undef,
                    'messages'         => undef,
                    '_done_sorts'      => [],
                    '_done_filters'    => [],
                    'metadata'         => {},
                    '_done_pagination' => undef,
                    '_total_results'   => undef,
                    'data'             => $data,
                },
                'Cpanel::Result',
            );
            return $result_obj;
        },
        'Cpanel::DomainLookup::DocRoot::getdocroots'       => $mocks->{'doc_root'},
        'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; },
    );

    local $Cpanel::homedir = '/home/foobar';
    Cpanel::API::Sitejet::get_all_user_sitejet_info( $args, $result );

    my $final_data = [
        {
            'metadata'                   => $mocks->{$main_domain}->{'metadata'},
            'status'                     => $mocks->{$main_domain}->{'statuses'}->{$main_domain},
            'quota'                      => $mocks->{$main_domain}->{'quota'}->{$main_domain},
            'domain'                     => $main_domain,
            'redirection_enabled'        => 1,
            'shared_doc_root'            => 0,
            'is_restore_point_available' => 0,
        }
    ];

    is( $namespace,       'Cpanel',           "AdminBin namespace is Cpanel" )        or diag explain $namespace;
    is( $module,          'sitejet',          "AdminBin module is sitejet" )          or diag explain $module;
    is( $action,          'DISK_QUOTA_CHECK', "AdminBin action is DISK_QUOTA_CHECK" ) or diag explain $action;
    is( $domain_adminbin, $main_domain,       "AdminBin data is the domain" )         or diag explain $domain_adminbin;

    is( $domain_metadata, $main_domain, "domain sent to cp_load_all_sitejet_domains_metadata" ) or diag explain $domain_adminbin;
    is( $domain_statuses, $main_domain, "domain sent to cp_list_all_domain_sitebuilders" )      or diag explain $domain_statuses;

    is( $result->{data}, $final_data, "returned data is correct in format and content" ) or diag explain $result;

    $result = Cpanel::Result->new();
    $args   = Cpanel::Args->new( {} );

    local $Cpanel::homedir = '/home/foobar';
    Cpanel::API::Sitejet::get_all_user_sitejet_info( $args, $result );

    is( $result->{data}, $mocks->{'final_data'}, "returned data is correct in format and content when no args are passed" ) or diag explain $result;
}

sub test_poll_publish : Tests(3) ($self) {
    my ( $connector, $domain );
    my $result = Cpanel::Result->new();
    $Cpanel::homedir = "home";
    $Cpanel::user    = "test";
    my $temp_dir    = "$Cpanel::homedir/$Cpanel::user/logs";
    my $publish_log = "$temp_dir/publish.log";
    my $args        = Cpanel::Args->new( { "pid" => $$, "file_name" => $publish_log } );

    my $mock_file_contents = "2024-02-01 16:21:19 -0600] info [uapi] [0 s] Starting sync for sub1.nositejet.tld at 1706826079.\n[2024-02-01 16:21:20 -0600] info [uapi] [1 s] Download sitemap xml:https://212b8b-6daf9.preview.sitehub.io/sitemap.xml\n[2024-02-01 16:21:20 -0600] info [uapi] [1 s] Store content for /sitemap.xml\n[2024-02-01 16:21:20 -0600] info [uapi] [1 s] Completed status: 100%\n";
    my $mock_dir           = Test::MockFile->new_dir($temp_dir);
    my $mock_file          = Test::MockFile->file( $publish_log,           $mock_file_contents );
    my $success_mock_file  = Test::MockFile->file( "$publish_log.success", '' );
    my $failed_mock_file   = Test::MockFile->file("$publish_log.failed");
    my @expected_content   = split( "\n", $mock_file_contents );
    *Cpanel::Autodie::open = *CORE::GLOBAL::open;
    Cpanel::API::Sitejet::poll_publish( $args, $result );

    is( $result->{data}, { 'is_running' => 1, 'failed' => 0, 'log' => \@expected_content, 'progress' => 100 }, "poll_publish returns success as expected." ) or diag explain $result;

    # send non-existent pid
    my $new_mock_file_contents = $mock_file_contents . "[2024-02-01 16:21:20 -0600] info [uapi] [1 s] Completed status: 120%\n";
    my @new_expected_content   = split( "\n", $new_mock_file_contents );
    $mock_file = '';
    $mock_file = Test::MockFile->file( $publish_log, $new_mock_file_contents );
    $args      = Cpanel::Args->new( { "pid" => 12345, "file_name" => $publish_log } );
    Cpanel::API::Sitejet::poll_publish( $args, $result );
    is( $result->{data}, { 'is_running' => 0, 'failed' => 0, 'log' => \@new_expected_content, 'progress' => 100 }, "poll_publish returns success as expected when pid is not available." ) or diag explain $result;

    # adding mocks for failure
    $failed_mock_file = '';
    $failed_mock_file = Test::MockFile->file( "$publish_log.failed", '' );
    $args             = Cpanel::Args->new( { "pid" => 12345, "file_name" => $publish_log } );
    Cpanel::API::Sitejet::poll_publish( $args, $result );
    is( $result->{data}, { 'is_running' => 0, 'failed' => 1, 'log' => \@new_expected_content, 'progress' => 100 }, "poll_publish fails when there is a failed flat file." ) or diag explain $result;

}

sub test_create_restore_point : Tests(6) ($self) {

    # Vars in the order they'll get used
    $Cpanel::user    = 'mockuser';
    $Cpanel::homedir = "/home/$Cpanel::user";
    my $config_dir     = "$Cpanel::homedir/.cpanel/sitejet";
    my $main_domain    = 'mockuser.tld';
    my $cpuser_www_dir = "$Cpanel::homedir/public_html";
    my $got_cp_user;
    my $args   = Cpanel::Args->new( { 'domain' => $main_domain } );
    my $result = Cpanel::Result->new();

    # XXX Missing assertions: This test tests cleanup of public_html, but not cleanup of any subodomains
    my %expected_docrootlist = (
        '/home/mockuser/public_html'                                             => 1,
        '/home/mockuser/notshared-3-outsidepub.test'                             => 1,
        '/home/mockuser/public_html/notshared-2.test'                            => 1,
        '/home/mockuser/public_html/notshared-2.test/notshared-4--nested-1.test' => 1,
        '/home/mockuser/public_html/sub1.test'                                   => 1,
    );

    my @dirs_to_protect = grep { !/^$cpuser_www_dir$/ } ( keys %expected_docrootlist );

    my $got_homedir_in_list_wds;
    my @expected_webdisks = (
        {
            'homedir' => '/home/mockuser/public_html/awebd1',
            'login'   => 'awebd1@mockuser.test',
            'reldir'  => 'public_html/awebd1',
            'user'    => 'awebd1',
        },
        {
            'homedir' => '/home/mockuser/a1',
            'login'   => 'a1@mockuser.test',
            'reldir'  => 'a1',
            'user'    => 'a1',
        },
    );
    my @expected_webdisk_dirs = map { $_->{homedir} } @expected_webdisks;
    push @dirs_to_protect, @expected_webdisk_dirs;

    my $expected_tar_bin = '/bin/mocktar';
    my $saferun_got_tarbin;
    my $saferun_got_target_dir;
    my $saferun_got_document_root;

    my @got_dirs_to_delete;
    my @got_files_to_delete;

    my ( $arg_self, $arg_dom, $arg_data );

    # Mocks
    *Cpanel::Autodie::opendir = *CORE::GLOBAL::opendir;
    my $mock_autodie = Test::MockModule->new('Cpanel::Autodie::CORE::unlink_if_exists');
    my @mocks        = $self->mock_subs(
        'Cpanel::DomainLookup::getdocrootlist' => sub {
            $got_cp_user = shift;
            return \%expected_docrootlist;
        },
        'Cpanel::WebDisk::api2_listwebdisks' => sub {
            my %in = @_;
            $got_homedir_in_list_wds = $in{homedir};
            return @expected_webdisks;
        },
        'Cpanel::Tar::load_tarcfg' => sub {
            return { 'bin' => $expected_tar_bin };
        },
        'Cpanel::SafeRun::Object::new' => sub {
            my ( $class, %args_hash ) = @_;
            my @args = @{ $args_hash{args} };
            $saferun_got_tarbin        = $args_hash{program};
            $saferun_got_target_dir    = $args[-2];
            $saferun_got_document_root = $args[-1];
            return bless {}, 'Cpanel::SafeRun::Object';

        },
        'Cpanel::SafeRun::Object::CHILD_ERROR' => 0,
        'Cpanel::SafeDir::RM::safermdir'       => sub {
            my $dir = shift;
            push @got_dirs_to_delete, $dir;
        },
        'Cpanel::Autodie::unlink_if_exists' => sub {
            my $file = shift;
            push @got_files_to_delete, $file;
        },
        'Cpanel::API::Sitejet::_validate_user_domain'            => 1,
        'Cpanel::Sitejet::Connector::cp_update_sitejet_metadata' => sub {
            my ( $obj, $data ) = @_;
            return;
        },
        'Cpanel::Sitejet::Connector::cp_update_sitejet_metadata' => sub {
            my ( $obj, $data ) = @_;
            return;
        },
        'Cpanel::Sitejet::Publish::get_document_root'      => sub { return $cpuser_www_dir; },
        'Cpanel::SafeDir::MK::safemkdir_or_die'            => 1,
        'Umask::Local::new'                                => 1,
        'Cpanel::Sitejet::Connector::_check_domain_config' => 1,
    );
    push @mocks, $mock_autodie;

    # Add an index.html to every dir. Some of these should get deleted, some saved.
    foreach my $dir ( keys %expected_docrootlist, @expected_webdisk_dirs ) {
        push @mocks, (
            Test::MockFile->dir($dir),
            Test::MockFile->file( "$dir/index.html", 'mocked index content' ),
        );
    }

    my @dirs_should_be_removed = qq{$cpuser_www_dir/mocked_custom_dir};
    foreach my $dir (@dirs_should_be_removed) {
        push @mocks, [
            Test::MockFile->dir($dir),
            Test::MockFile->file( "$dir/index.html", 'mocked index content' ),
        ];
    }

    my $mock_config_dir = Test::MockFile->dir($config_dir);
    my $mock_metadata   = Test::MockFile->file( "$config_dir/$main_domain", 'metadata content' );

    my @expected_files_removed = map { "$cpuser_www_dir/$_" } qw/ index.php /;
    foreach my $file (@expected_files_removed) {
        push @mocks, Test::MockFile->file( $file, 'mocked content' );
    }

    my %expected_files_to_remain = map { $_ . '/index.html' => 1 } @dirs_to_protect;

    Cpanel::API::Sitejet::create_restore_point( $args, $result );

    # html was added to all the dirs, but this is the only one that should be deleted
    push @expected_files_removed, "$cpuser_www_dir/index.html";

    # Assertions
    my $zip_file = "/home/mockuser/$main_domain";
    is( $saferun_got_tarbin, $expected_tar_bin, "test_create_restore_point - passed tar binary path to run tar" );
    like( $saferun_got_target_dir, qr{$zip_file.*.gz}, "test_create_restore_point - passed correct target to run tar (saving gz file in user homedir)" );
    is( $saferun_got_document_root, $cpuser_www_dir, "test_create_restore_point - passed correct to run tar" );

    # -e didn't work due to mocking.  Don't know why bag didn't work.
    is( [ sort @expected_files_removed ], [ sort @got_files_to_delete ], "test_create_restore_point - all custom files were sent for deletion" );

    is( [ sort @dirs_should_be_removed ], [ sort @got_dirs_to_delete ], "test_create_restore_point - all custom dirs were sent for deletion" );

    my @shouldnt_have_deleted = grep { $expected_files_to_remain{$_} } @got_files_to_delete;
    my $failed                = scalar @shouldnt_have_deleted;
    is( $failed, 0, 'test_create_restore_point - did not delete any files it was not supposed to' );

    return;
}

sub test_restore_document_root : Tests(6) ($self) {

    # Vars in the order they'll get used
    $Cpanel::user    = 'mockuser';
    $Cpanel::homedir = "/home/$Cpanel::user";
    my $config_dir     = "$Cpanel::homedir/.cpanel/sitejet";
    my $main_domain    = 'mockuser.tld';
    my $cpuser_www_dir = "$Cpanel::homedir/public_html";
    my $got_cp_user;
    my $args   = Cpanel::Args->new( { 'domain' => $main_domain } );
    my $result = Cpanel::Result->new();

    my %expected_docrootlist = (
        '/home/mockuser/public_html'                                             => 1,
        '/home/mockuser/notshared-3-outsidepub.test'                             => 1,
        '/home/mockuser/public_html/notshared-2.test'                            => 1,
        '/home/mockuser/public_html/notshared-2.test/notshared-4--nested-1.test' => 1,
        '/home/mockuser/public_html/sub1.test'                                   => 1,
    );

    my @dirs_to_protect = grep { !/^$cpuser_www_dir$/ } ( keys %expected_docrootlist );

    my $got_homedir_in_list_wds;
    my @expected_webdisks = (
        {
            'homedir' => '/home/mockuser/public_html/awebd1',
            'login'   => 'awebd1@mockuser.test',
            'reldir'  => 'public_html/awebd1',
            'user'    => 'awebd1',
        },
        {
            'homedir' => '/home/mockuser/a1',
            'login'   => 'a1@mockuser.test',
            'reldir'  => 'a1',
            'user'    => 'a1',
        },
    );
    my @expected_webdisk_dirs = map { $_->{homedir} } @expected_webdisks;
    push @dirs_to_protect, @expected_webdisk_dirs;

    my $expected_tar_bin = '/bin/mocktar';
    my $saferun_got_tarbin;
    my $restore_file = '/home/mockuser/mockuser.tld_1234567.gz';
    my $saferun_got_document_root;

    my @got_dirs_to_delete;
    my @got_files_to_delete;
    my @delete_list;
    my ( $class, %safe_run_args );

    my ( $conn_obj, $update_domain, $update_json_data, $arg_dom );

    # Mocks
    *Cpanel::Autodie::open = *CORE::GLOBAL::open;
    my $mock_autodie = Test::MockModule->new('Cpanel::Autodie::CORE::unlink_if_exists');
    my @mocks        = $self->mock_subs(
        'Cpanel::DomainLookup::getdocrootlist' => sub {
            $got_cp_user = shift;
            return \%expected_docrootlist;
        },
        'Cpanel::WebDisk::api2_listwebdisks' => sub {
            my %in = @_;
            $got_homedir_in_list_wds = $in{homedir};
            return @expected_webdisks;
        },
        'Cpanel::Tar::load_tarcfg' => sub {
            return { 'bin' => $expected_tar_bin };
        },
        'Cpanel::SafeRun::Object::new' => sub {
            ( $class, %safe_run_args ) = @_;
            return bless {}, 'Cpanel::SafeRun::Object';

        },
        'Cpanel::SafeRun::Object::CHILD_ERROR' => 0,
        'Cpanel::Autodie::unlink_if_exists'    => sub {
            my $file = shift;
            push @got_files_to_delete, $file;
        },
        'Cpanel::API::Sitejet::_validate_user_domain'          => 1,
        'Cpanel::Sitejet::Connector::cp_load_sitejet_metadata' => sub {
            my ( $obj, $dom ) = @_;
            return { 'restore_file' => $restore_file };
        },
        'Cpanel::Sitejet::Connector::cp_update_sitejet_metadata' => sub {
            ( $conn_obj, $update_domain, $update_json_data ) = @_;
            return;
        },
        'Cpanel::Sitejet::Publish::get_document_root'            => sub { return $cpuser_www_dir; },
        'Cpanel::SafeDir::MK::safemkdir_or_die'                  => 1,
        'Cpanel::Sitejet::Connector::_check_domain_config'       => 1,
        'Cpanel::Sitejet::Publish::cp_remove_unused_directories' => sub {
            ( $arg_dom, @delete_list ) = @_;
            return;
        },
    );
    push @mocks, $mock_autodie;

    my %expected_saferun_args = (
        'program' => $expected_tar_bin,
        'args'    => [ '-x', '-v', '-f', $restore_file, '-C', '/' ],
    );

    my %expected_files_to_remain = map { $_ . '/index.html' => 1 } @dirs_to_protect;

    # Add an index.html to every dir. Some of these should get deleted, some saved.
    foreach my $dir ( keys %expected_docrootlist, @expected_webdisk_dirs ) {
        push @mocks, (
            Test::MockFile->dir($dir),
            Test::MockFile->file( "$dir/index.html", 'mocked index content' ),
        );
    }

    my @tracking_files_list = ( "$cpuser_www_dir/api.php", "$cpuser_www_dir/sitemap.xml", "$cpuser_www_dir/g/fonts.css" );

    foreach my $file (@tracking_files_list) {
        push @mocks, (
            Test::MockFile->file( $file, 'mocked file content' ),
        );
    }
    my @sitejet_tracking_file_list = ( @tracking_files_list, ( keys %expected_files_to_remain ) );
    my $content                    = join "\n", @sitejet_tracking_file_list;
    my $mock_config_dir            = Test::MockFile->dir($config_dir);
    my $mock_metadata              = Test::MockFile->file( "$config_dir/$main_domain-files", $content );

    my $mock_restore_file = Test::MockFile->file( $restore_file, 'zip file' );
    push @mocks, $mock_restore_file;
    push @mocks, $mock_metadata;

    my @expected_files_removed = ( @tracking_files_list, $restore_file );

    Cpanel::API::Sitejet::restore_document_root( $args, $result );

    is( \%safe_run_args, \%expected_saferun_args, "test_restore_document_root - saferun args are passed as expected." );

    # -e didn't work due to mocking.  Don't know why bag didn't work.
    is( [ sort @expected_files_removed ], [ sort @got_files_to_delete ], "test_restore_document_root - deletes files based on sitejet tracking as expected." );

    # update_metadata validation
    is( $update_json_data->{'restored_from_file'}, $restore_file, "test_restore_document_root - updates restored_from_file as expected." );
    is( $update_json_data->{'restore_file'},       '',            "test_restore_document_root - updates restore_file as expected." );
    like( $update_json_data->{'latest_restore_date'}, qr/^\d{10}$/, "test_restore_document_root - updates latest_restore_date as expected." );

    my @shouldnt_have_deleted = grep { $expected_files_to_remain{$_} } @got_files_to_delete;
    my $failed                = scalar @shouldnt_have_deleted;
    is( $failed, 0, 'test_restore_document_root - did not delete any files it was not supposed to' );

    return;
}

sub _get_mocks_data {
    my $mocks = {};
    my $data  = {};
    my @final_data;
    $mocks->{'list_domains'} = {
        'addon_domains' => [
            'bin.com',
        ],
        'main_domain'    => 'foobar.com',
        'sub_domains'    => ['default.foobar.com'],
        'parked_domains' => ['park.foobar.com'],
    };
    $mocks->{'redirect_data'} = { 'redirection_enabled' => 1 };
    $mocks->{'main_domain'}   = 'foobar.com';
    my @domains = ( 'foobar.com', 'default.foobar.com', 'bin.com', 'park.foobar.com' );
    $mocks->{'doc_root'} = {
        'foobar.com'         => '/home/foobar/public_html',
        'default.foobar.com' => '/home/foobar/public_html/default',
        'bin.com'            => '/home/foobar/bin',
        'park.foobar.com'    => '/home/foobar/public_html'
    };
    foreach my $domain ( sort @domains ) {
        if ( $domain eq 'default.foobar.com' ) {
            $mocks->{$domain}->{'metadata'} = {};
            $mocks->{$domain}->{'statuses'} = {
                $domain => {
                    'has_sitejet_published'  => 0,
                    'is_sitejet'             => 0,
                    'has_sitejet_templateid' => 0,
                    'has_sitejet_website'    => 0
                }
            };
            $mocks->{$domain}->{'quota'} = {
                $domain => {
                    'required_space'   => 22,
                    'can_backup'       => 1,
                    'available_space'  => 281,
                    'is_docroot_empty' => 0
                }
            };
            $data = {
                'metadata'                   => $mocks->{$domain}->{'metadata'},
                'status'                     => $mocks->{$domain}->{'statuses'}->{$domain},
                'quota'                      => $mocks->{$domain}->{'quota'}->{$domain},
                'domain'                     => $domain,
                'redirection_enabled'        => 1,
                'shared_doc_root'            => ( $domain eq 'park.foobar.com' ) ? 1 : 0,
                'is_restore_point_available' => 0,
            };
            push @final_data, $data;
            next;
        }
        $mocks->{$domain}->{'metadata'} = {
            "company"         => "foobar_company",
            "domain"          => $domain,
            "fullcms"         => 1,
            "language"        => "en",
            "pleskDomainGUID" => $domain,
            "publish_status"  => 1,
            "templateId"      => "333333",
            "websiteId"       => "999999",
            'zz_light_bg'     => "",
            'zz_dark_bg'      => "",
        };
        $mocks->{$domain}->{'statuses'} = {
            $domain => {
                'has_sitejet_published'  => 1,
                'is_sitejet'             => 1,
                'has_sitejet_templateid' => 1,
                'has_sitejet_website'    => 1
            }
        };
        $mocks->{$domain}->{'quota'} = {
            $domain => {
                'required_space'   => 22,
                'can_backup'       => 1,
                'available_space'  => 281,
                'is_docroot_empty' => 0
            }
        };
        $data = {
            'metadata'                   => $mocks->{$domain}->{'metadata'},
            'status'                     => $mocks->{$domain}->{'statuses'}->{$domain},
            'quota'                      => $mocks->{$domain}->{'quota'}->{$domain},
            'domain'                     => $domain,
            'redirection_enabled'        => 1,
            'shared_doc_root'            => ( $domain eq 'park.foobar.com' ) ? 1 : 0,
            'is_restore_point_available' => 0,
        };
        push @final_data, $data;

    }
    $mocks->{'final_data'} = \@final_data;
    return $mocks;
}
