Firefox-Marionette

 view release on metacpan or  search on metacpan

t/test_daemons.pm  view on Meta::CPAN

    my $debug;
    if ( $ENV{FIREFOX_DEBUG} ) {
        $debug = $ENV{FIREFOX_DEBUG};
    }
    my $dev_null = File::Spec->devnull();
    if ( my $pid = fork ) {
        waitpid $pid, 0;
    }
    else {
        eval {
            open STDOUT, q[>], $dev_null
              or Carp::croak(
                "Failed to redirect STDOUT to $dev_null:$EXTENDED_OS_ERROR");
            if ( !$debug ) {
                open STDERR, q[>], $dev_null
                  or Carp::croak(
                    "Failed to redirect STDERR to $dev_null:$EXTENDED_OS_ERROR"
                  );
            }
            open STDIN, q[<], $dev_null
              or Carp::croak(
                "Failed to redirect STDIN to $dev_null:$EXTENDED_OS_ERROR");
            exec {$binary} $binary, @arguments;
        } or do {

            # absolutely nothing, this is allowed to fail
        };
        exit 1;
    }
    return $CHILD_ERROR == 0 ? 1 : 0;
}

package Test::CA;

use strict;
use warnings;
use English qw( -no_match_vars );

@Test::CA::ISA = qw(Test::Binary::Available Test::File::Temp);

my $openssl_binary = 'openssl';

sub available {
    my ($class) = @_;
    return $class->SUPER::available( $openssl_binary, 'version' );
}

sub new {
    my ( $class, $key_size ) = @_;
    my $self = bless {}, $class;
    $self->{ca_directory} = $class->tmp_directory('ca');
    $self->{ca_cert_path} =
      File::Spec->catfile( $self->{ca_directory}->dirname(), 'ca.crt' );
    $self->{ca_cert_handle} = FileHandle->new(
        $self->{ca_cert_path},
        Fcntl::O_EXCL() | Fcntl::O_RDWR() | Fcntl::O_CREAT(),
        Fcntl::S_IRUSR() | Fcntl::S_IWUSR()
      )
      or
      Carp::croak("Failed to create $self->{ca_cert_path}:$EXTENDED_OS_ERROR");
    $self->{ca_private_key_path} =
      File::Spec->catfile( $self->{ca_directory}->dirname(), 'ca.key' );
    $self->{ca_private_key_handle} =
      $class->new_key( $key_size, $self->{ca_private_key_path} );
    $self->{ca_serial_path} =
      File::Spec->catfile( $self->{ca_directory}->dirname(), 'ca.serial' );
    $self->{ca_serial_handle} = FileHandle->new(
        $self->{ca_serial_path},
        Fcntl::O_EXCL() | Fcntl::O_RDWR() | Fcntl::O_CREAT(),
        Fcntl::S_IRUSR() | Fcntl::S_IWUSR()
      )
      or Carp::croak(
        "Failed to create $self->{ca_serial_path}:$EXTENDED_OS_ERROR");
    print { $self->{ca_serial_handle} } '01'
      or Carp::croak(
        "Failed to write to $self->{ca_serial_path}:$EXTENDED_OS_ERROR");
    close $self->{ca_serial_handle}
      or
      Carp::croak("Failed to close $self->{ca_serial_path}:$EXTENDED_OS_ERROR");
    $self->{ca_config_path} =
      File::Spec->catfile( $self->{ca_directory}->dirname(), 'ca.config' );
    $self->{ca_config_handle} = FileHandle->new(
        $self->{ca_config_path},
        Fcntl::O_EXCL() | Fcntl::O_RDWR() | Fcntl::O_CREAT(),
        Fcntl::S_IRUSR() | Fcntl::S_IWUSR()
      )
      or Carp::croak(
        "Failed to create $self->{ca_config_path}:$EXTENDED_OS_ERROR");
    $self->{ca_config_handle}->print(<<"_CONFIG_");
[ req ]
distinguished_name     = req_distinguished_name
x509_extensions        = v3_ca
attributes             = req_attributes
prompt                 = no

[ req_distinguished_name ]
C                      = AU
ST                     = Victoria
L                      = Melbourne
O                      = David Dick
OU                     = CPAN
CN                     = Firefox::Marionette Root CA
emailAddress           = ddick\@cpan.org

[ req_attributes ]

[ signing_policy ]
countryName            = optional
stateOrProvinceName    = optional
localityName           = optional
organizationName       = optional
organizationalUnitName = optional
commonName             = supplied
emailAddress           = optional

####################################################################
[ signing_req ]
subjectKeyIdentifier   = hash
authorityKeyIdentifier = keyid,issuer
basicConstraints       = CA:FALSE
keyUsage               = digitalSignature, keyEncipherment
prompt                 = no

[ v3_ca ]
keyUsage=critical, keyCertSign
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer:always
basicConstraints=critical,CA:TRUE,pathlen:1
extendedKeyUsage=serverAuth

_CONFIG_
    seek $self->{ca_config_handle}, 0, 0
      or Carp::croak(
        "Failed to seek to start of temporary file:$EXTENDED_OS_ERROR");
    system {$openssl_binary} $openssl_binary, 'req', '-new', '-x509',
      '-config' => $self->{ca_config_path},
      '-days'   => 10,
      '-key'    => $self->{ca_private_key_path},
      '-out'    => $self->{ca_cert_path}
      and Carp::croak(
        "Failed to generate a CA root certificate:$EXTENDED_OS_ERROR");
    return $self;
}

sub config {
    my ($self) = @_;
    return $self->{ca_config_path};
}

sub serial {
    my ($self) = @_;
    return $self->{ca_serial_path};
}

sub cert {
    my ($self) = @_;
    return $self->{ca_cert_path};
}

sub key {
    my ($self) = @_;
    return $self->{ca_private_key_path};
}

sub new_cert {
    my ( $self, $key_path, $host_name, $path ) = @_;
    my $csr = $self->tmp_handle('csr');
    my $cert_handle;
    my $cert_path;
    if ($path) {
        $cert_handle = FileHandle->new(
            $path,
            Fcntl::O_EXCL() | Fcntl::O_RDWR() | Fcntl::O_CREAT(),
            Fcntl::S_IRUSR() | Fcntl::S_IWUSR()
        ) or Carp::croak("Failed to create $path:$EXTENDED_OS_ERROR");
        $cert_path = $path;
    }
    else {
        $cert_handle = $self->tmp_handle('cert');
        $cert_path   = $cert_handle->filename();
    }
    system {$openssl_binary} $openssl_binary, 'req', '-new', '-sha256',
      '-config' => $self->config(),
      '-key'    => $key_path,
      '-subj'   =>
      "/C=AU/ST=Victoria/L=Melbourne/O=David Dick/OU=CPAN/CN=$host_name",
      '-out' => $csr->filename()
      and Carp::croak(
        "Failed to generate a certificate signing request:$EXTENDED_OS_ERROR");
    my $cert_extensions_handle = $self->tmp_handle('cert_ext');
    $cert_extensions_handle->print(<<"_CONFIG_");
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName = \@alt_names
[alt_names]
IP.1 = $host_name
_CONFIG_
    seek $cert_extensions_handle, 0, 0
      or Carp::croak(
        "Failed to seek to start of temporary file:$EXTENDED_OS_ERROR");
    system {$openssl_binary} $openssl_binary, 'x509', '-req',
      '-in'       => $csr->filename(),
      '-CA'       => $self->cert(),
      '-CAkey'    => $self->key(),
      '-extfile'  => $cert_extensions_handle->filename(),
      '-CAserial' => $self->serial(),
      '-sha256',
      '-days' => 10,
      '-out'  => $cert_path
      and Carp::croak("Failed to generate a certificate:$EXTENDED_OS_ERROR");
    my $ca_cert = FileHandle->new( $self->cert(), Fcntl::O_RDONLY() )
      or Carp::croak(
        'Failed to open ' . $self->cert() . " for reading:$EXTENDED_OS_ERROR" );

    seek $cert_handle, 0, Fcntl::SEEK_END()
      or Carp::croak(
        "Failed to seek to start of temporary file:$EXTENDED_OS_ERROR");
    while ( my $line = <$ca_cert> ) {
        print {$cert_handle} $line
          or
          Carp::croak("Failed to write to temporary file:$EXTENDED_OS_ERROR");
    }
    seek $cert_handle, 0, Fcntl::SEEK_SET()
      or Carp::croak(
        "Failed to seek to start of temporary file:$EXTENDED_OS_ERROR");
    return $cert_handle;
}

sub new_key {
    my ( $class, $size, $path ) = @_;
    my $private_key_handle;
    my $private_key_path;
    if ($path) {
        $private_key_handle = FileHandle->new(
            $path,
            Fcntl::O_EXCL() | Fcntl::O_RDWR() | Fcntl::O_CREAT(),
            Fcntl::S_IRUSR() | Fcntl::S_IWUSR()
        ) or Carp::croak("Failed to create $path:$EXTENDED_OS_ERROR");
        $private_key_path = $path;
    }
    else {
        $private_key_handle = $class->tmp_handle('private_key');
        $private_key_path   = $private_key_handle->filename();
    }
    system {$openssl_binary} $openssl_binary, 'genrsa',
      '-out' => $private_key_path,
      $size
      and Carp::croak("Failed to generate a private key:$EXTENDED_OS_ERROR");
    return $private_key_handle;
}

package Test::Daemon;

use strict;
use warnings;
use Carp();
use Config;
use Socket();
use English qw( -no_match_vars );

@Test::Daemon::ISA = qw(Test::File::Temp);

sub CONVERT_TO_PROCESS_GROUP { return -1 }

my @sig_nums  = split q[ ], $Config{sig_num};
my @sig_names = split q[ ], $Config{sig_name};
my %signals_by_name;
my $idx = 0;
foreach my $sig_name (@sig_names) {
    $signals_by_name{$sig_name} = $sig_nums[$idx];
    $idx += 1;
}

sub new {
    my ( $class, %parameters ) = @_;
    my $debug = delete $parameters{debug};
    if ( $ENV{FIREFOX_DEBUG} ) {
        $debug = $ENV{FIREFOX_DEBUG};
    }
    my @arguments = @{ delete $parameters{arguments} };
    my %extra     = %parameters;
    my $self      = bless {
        binary    => $parameters{binary},
        arguments => \@arguments,
        port      => $parameters{port},
        debug     => $debug,
        %extra
    }, $class;
    $self->start();
    return $self;
}

sub debug {
    my ($self) = @_;
    return $self->{debug};
}

sub arguments {
    my ($self) = @_;
    return @{ $self->{arguments} };
}

sub address {
    my ($self) = @_;
    return $self->{listen};
}

sub wait_until_port_open {
    my ($self)     = @_;



( run in 1.209 second using v1.01-cache-2.11-cpan-98e64b0badf )