package Tapper::SimNow;
# git description: v4.0.1-3-g06f7e02

BEGIN {
  $Tapper::SimNow::AUTHORITY = 'cpan:AMD';
}
{
  $Tapper::SimNow::VERSION = '4.1.0';
}
# ABSTRACT: Tapper - Support for running SimNow sessions

use Moose;
use common::sense;

use File::Basename;

use Tapper::Remote::Config;
use Tapper::Remote::Net;

extends 'Tapper::Base';

has cfg => (is      => 'rw',
            isa     => 'HashRef',
            default => sub { {} },
           );



sub get_static_tap_headers
{
        my ($self, $report) = @_;
        $report->{headers}{'Tapper-reportgroup-testrun'} = $self->cfg->{test_run};
        $report->{headers}{'Tapper-suite-name'}          = "SimNow-Metainfo";
        $report->{headers}{'Tapper-suite-version'}       = $Tapper::SimNow::VERSION;
        $report->{headers}{'Tapper-machine-name'}        = $self->cfg->{hostname};
        return $report;
}


sub generate_meta_report
{

        my ($self) = @_;
        my $report;
        $report = $self->get_static_tap_headers($report);

        my $error  = 0;
        my ($success, $retval) = $self->log_and_exec($self->cfg->{paths}->{simnow_path}."/simnow","--version");
        if ($success) {
                push @{$report->{tests}}, {error => 1, test => "Getting SimNow version"};
        } else {
                push @{$report->{tests}}, {test => "Getting SimNow version"};

                if ($retval =~ m/This is AMD SimNow version (\d+\.\d+\.\d+(-NDA)?)/) {
                        $report->{headers}{'Tapper-SimNow-Version'} = $1;
                } else {
                        $report->{headers}{'Tapper-SimNow-Version'} = 'Not set';
                        $error = 1;
                }
                push @{$report->{tests}}, {error => $error, test => "Parsing SimNow version"};


                $error = 0;
                if ($retval =~ m/This internal release is built from revision: (.+) of SVN URL: (.+)/) {
                        $report->{headers}{'Tapper-SimNow-SVN-Version'}    =  $1;
                        $report->{headers}{'Tapper-SimNow-SVN-Repository'} =  $2;
                } elsif ($retval =~ m/Build number: (.+)/) {
                        $report->{headers}{'Tapper-SimNow-SVN-Version'}    =  $1;
                        $report->{headers}{'Tapper-SimNow-SVN-Repository'} =  'Not set';
                } else {
                        $report->{headers}{'Tapper-SimNow-SVN-Version'}    =  'Not set';
                        $report->{headers}{'Tapper-SimNow-SVN-Repository'} =  'Not set';
                        $error = 1;
                }
                push @{$report->{tests}}, {error => $error, test => "Parsing SVN version"};

                $error = 0;
                if ($retval =~ m/supporting version (\d+) of the AMD SimNow Device Interface/) {
                        $report->{headers}{'Tapper-SimNow-Device-Interface-Version'} = $1;
                } else {
                        $report->{headers}{'Tapper-SimNow-Device-Interface-Version'} = 'Not set';
                        $error = 1;
                }
                push @{$report->{tests}}, {error => $error, test => "Parsing device interface version"};
        }

        $error = 0;
        if (open my $fh ,"<", $self->cfg->{files}{simnow_script}) {
                my $content = do {local $/; <$fh>};
                close $fh;

                if ($content =~ m|open bsds/(\w+)\.bsd|) {
                        $report->{headers}{'Tapper-SimNow-BSD-File'} = $1;
                } else {
                        $error = 1;
                }
                push @{$report->{tests}}, {error => $error, test => "Getting BSD file information"};

                $error = 0;
                if ($content =~ m|ide:0.image master .*/((?:\w\|\.)+?)(?:\.[a-zA-Z]+)?$|m) {
                        $report->{headers}{'Tapper-SimNow-Image-File'} = $1;
                } else {
                        $error = 1;
                }
                push @{$report->{tests}}, {error => $error, test => "Getting image file information"};

                $error = 0;
        } else {
                $report->{headers}{'Tapper-SimNow-BSD-File'} = 'Not set';
                $report->{headers}{'Tapper-SimNow-Image-File'} = 'Not set';
                $error = 1;
        }
        push @{$report->{tests}}, {error => $error, test => "Reading Simnow config file"};
        return $report;

}




sub create_console
{
        my ($self) = @_;
        $self->log->debug("Creating console links");
        my $test_run        = $self->cfg->{test_run};
        my $out_dir         = $self->cfg->{paths}{output_dir}."/$test_run/test/";
        $self->makedir($out_dir) unless -d $out_dir;
        my $outfile         = $out_dir."/simnow_console";

        # create the file, otherwise simnow can't write to it
        open my $fh, ">", $outfile or return "Can not open $outfile: $!";
        close $fh;

        my $pipedir         = dirname($self->cfg->{files}{simnow_console});
        $self->makedir($pipedir) unless -d $pipedir;
        my $retval          = $self->log_and_exec("ln","-sf", $outfile, $self->cfg->{files}{simnow_console});
        return $retval;
}



sub start_simnow
{
        my ($self) = @_;
        $self->log->debug("starting simnow");

        my $simnow_script   = $self->cfg->{files}{simnow_script};
        my $test_run        = $self->cfg->{test_run};
        my $out_dir         = $self->cfg->{paths}{output_dir}."/$test_run/test/";
        $self->makedir($out_dir) unless -d $out_dir;
        my $output          = $out_dir.'/simnow';

        open (STDOUT, ">>", "$output.stdout") or return("Can't open output file $output.stdout: $!");
        open (STDERR, ">>", "$output.stderr") or return("Can't open output file $output.stderr: $!");

        my $retval          = $self->run_one({command  => $self->cfg->{paths}->{simnow_path}."/simnow",
                                              argv     => [ "-e", $simnow_script, '--nogui' ],
                                              pid_file => $self->cfg->{paths}->{pids_path}."/simnow.pid",
                                             });
        return $retval;
}



sub start_mediator
{
        my ($self) = @_;
        $self->log->debug("starting mediator");

        my $retval = $self->run_one({command  => $self->cfg->{paths}->{simnow_path}."/mediator",
                                     pid_file => $self->cfg->{paths}->{pids_path}."/mediator.pid",
                                    });
        return $retval;
}




sub run
{
        my ($self) = @_;
        $self->log->info("Starting Simnow");

        my $consumer = Tapper::Remote::Config->new();
        my $config   = $consumer->get_local_data('simnow');
        die $config unless ref($config) eq 'HASH';
        my $net      = Tapper::Remote::Net->new($config);
        $self->cfg( $config );
        $net->mcp_inform("start-test");

        # simnow only runs in its own directory due to lib issues
        chdir $self->cfg->{paths}->{simnow_path};

        my $retval;
        {
                $retval = $self->kill_instance($self->cfg->{paths}->{pids_path}."/simnow.pid");
                last if $retval;

                $retval = $self->create_console();
                last if $retval;


                $retval = $self->start_mediator();
                last if $retval;

                $retval = $self->start_simnow();
                last if $retval;

                my $report = $self->generate_meta_report();
                my $tap = $net->tap_report_create($report);
                my $error;
                ($error, $retval) = $net->tap_report_away($tap);
                last if $error;

        }
        if ($retval) {
                $net->mcp_send({state => 'error-guest', error => $retval});
                $self->log->logdie($retval);
        }
        $net->mcp_inform("end-test");

        $self->log->info("Simnow prepared and running");
        return 0;
}

1; # End of Tapper::SimNow

__END__
=pod

=encoding utf-8

=head1 NAME

Tapper::SimNow - Tapper - Support for running SimNow sessions

=head1 SYNOPSIS

Tapper::SimNow controls running SimNow session with Tapper. With this
module Tapper is able to treat similar to virtualisation tests.

    use Tapper::SimNow;

    my $simnow = Tapper::SimNow->new();
    $simnow->run();

=head1 FUNCTIONS

=head2 get_static_tap_headers

Create a report hash that contains all headers that do not need to be
produced somehow. This includes suite-name and suite-version for
example.

@return string - tap headers

=head2 generate_meta_report

Generate a report containing metainformation about the SimNow we use.

@return hash ref - report data as expected by Remote::Net->tap_report_create()

=head2 create_console

Create console file for output of system under test in simnow.

@param hash ref - config

@return success - 0
@return error   - error string

=head2 start_simnow

Start the simnow process.

@param hash ref - config

@return success - 0
@return error   - error string

=head2 start_mediator

Start the mediator process.

@param hash ref - config

@return success - 0
@return error   - error string

=head2 run

Control a SimNow session. Handles getting config, sending status
messages to MCP and console handling.

@return success - 0
@return error   - error string

=head1 AUTHOR

AMD OSRC Tapper Team <tapper@amd64.org>

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2012 by Advanced Micro Devices, Inc..

This is free software, licensed under:

  The (two-clause) FreeBSD License

=cut

