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 )