Firefox-Marionette

 view release on metacpan or  search on metacpan

README  view on Meta::CPAN


    See IMITATING OTHER BROWSERS a discussion of these types of techniques.
    These changes are not foolproof, but it is interesting to see what can
    be done with modern browsers. All this behaviour should be regarded as
    extremely experimental and subject to change. Feedback welcome.

 alert_text

    Returns the message shown in a currently displayed modal message box

 alive

    This method returns true or false depending on if the Firefox process
    is still running.

 application_type

    returns the application type for the Marionette protocol. Should be
    'gecko'.

 arch

README.md  view on Meta::CPAN

- [https://lraj22.github.io/browserfeatcl/](https://lraj22.github.io/browserfeatcl/)

Importantly, this will break [feature detection](https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Feature_detection) for any website that relies on it.

See [IMITATING OTHER BROWSERS](#imitating-other-browsers) a discussion of these types of techniques.  These changes are not foolproof, but it is interesting to see what can be done with modern browsers.  All this behaviour should be regarded as extre...

## alert\_text

Returns the message shown in a currently displayed modal message box

## alive

This method returns true or false depending on if the Firefox process is still running.

## application\_type

returns the application type for the Marionette protocol.  Should be 'gecko'.

## arch

returns the architecture of the machine running firefox.  Should be something like 'x86\_64' or 'arm'.  This is only intended for test suite support.

lib/Firefox/Marionette.pm  view on Meta::CPAN

        }
    }
    return $port || _DEFAULT_PORT();
}

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

sub _check_reconnecting_firefox_process_is_alive {
    my ( $self, $pid ) = @_;
    if ( $OSNAME eq 'MSWin32' ) {
        if (
            Win32::Process::Open(
                my $process, $pid, _WIN32_PROCESS_INHERIT_FLAGS()
            )
          )
        {
            $self->{_win32_firefox_process} = $process;
            return $pid;

lib/Firefox/Marionette.pm  view on Meta::CPAN

    $local_name_regex = qr/${local_name_regex}\w+/smx;
    return $local_name_regex;
}

sub _get_local_reconnect_pid {
    my ($self)         = @_;
    my $temp_directory = File::Spec->tmpdir();
    my $temp_handle    = DirHandle->new($temp_directory)
      or Firefox::Marionette::Exception->throw(
        "Failed to open directory '$temp_directory':$EXTENDED_OS_ERROR");
    my $alive_pid;
    my $local_name_regex = $self->_get_local_name_regex();

  TEMP_DIR_LISTING: while ( my $tainted_entry = $temp_handle->read() ) {
        next if ( $tainted_entry eq File::Spec->curdir() );
        next if ( $tainted_entry eq File::Spec->updir() );
        if ( $tainted_entry =~ /^($local_name_regex)$/smx ) {
            my ($untainted_entry) = ($1);
            my $possible_root_directory =
              File::Spec->catfile( $temp_directory, $untainted_entry );
            my $local_proxy = $self->_read_possible_proxy_path(

lib/Firefox/Marionette.pm  view on Meta::CPAN

                }
            }
            elsif ( $self->_binary() ) {
                next TEMP_DIR_LISTING;
            }
            if (   ( defined $local_proxy->{firefox} )
                && ( $local_proxy->{firefox}->{pid} ) )
            {
                if (
                    my $check_pid =
                    $self->_check_reconnecting_firefox_process_is_alive(
                        $local_proxy->{firefox}->{pid}
                    )
                  )
                {
                    $alive_pid = $check_pid;
                }
                else {
                    next TEMP_DIR_LISTING;
                }
            }
            else {
                next TEMP_DIR_LISTING;
            }
            if (   ( defined $local_proxy->{xvfb} )
                && ( defined $local_proxy->{xvfb}->{pid} )

lib/Firefox/Marionette.pm  view on Meta::CPAN

                $self->{_xvfb_pid} = $local_proxy->{xvfb}->{pid};
            }
            $self->{_initial_version} = $local_proxy->{firefox}->{version};
            $self->{_root_directory}  = $possible_root_directory;
            $self->_setup_profile();
        }
    }
    closedir $temp_handle
      or Firefox::Marionette::Exception->throw(
        "Failed to close directory '$temp_directory':$EXTENDED_OS_ERROR");
    return $alive_pid;
}

sub _setup_profile {
    my ($self) = @_;
    if ( $self->{profile_name} ) {
        $self->{_profile_directory} =
          Firefox::Marionette::Profile->directory( $self->{profile_name} );
        $self->{profile_path} =
          File::Spec->catfile( $self->{_profile_directory}, 'prefs.js' );
    }

lib/Firefox/Marionette.pm  view on Meta::CPAN

            push @other_processes, $process;
        }
    }
    $self->{_other_win32_ssh_processes} = \@other_processes;
    return;
}

sub _remote_process_running {
    my ( $self, $remote_pid ) = @_;
    my $now = time;
    if (   ( defined $self->{last_remote_alive_status} )
        && ( $self->{last_remote_kill_time} >= $now ) )
    {
        return $self->{last_remote_alive_status};
    }
    $self->{last_remote_kill_time} = $now;
    my $remote_uname = $self->_remote_uname();
    if ( !defined $remote_uname ) {
        return;
    }
    elsif ( $remote_uname eq 'MSWin32' ) {
        return $self->_win32_remote_process_running($remote_pid);
    }
    else {
        return $self->_generic_remote_process_running($remote_pid);
    }
}

sub _win32_remote_process_running {
    my ( $self, $remote_pid ) = @_;
    my $binary    = 'tasklist';
    my @arguments = ( '/FI', q["PID eq ] . $remote_pid . q["] );
    $self->{last_remote_alive_status} = 0;
    foreach my $line ( split /\r?\n/smx, $self->execute( $binary, @arguments ) )
    {
        if ( $line =~ /^firefox[.]exe[ ]+(\d+)[ ]/smx ) {
            if ( $1 == $remote_pid ) {
                $self->{last_remote_alive_status} = 1;
            }
        }
    }
    return $self->{last_remote_alive_status};
}

sub _generic_remote_process_running {
    my ( $self, $remote_pid ) = @_;
    my $result = $self->_execute_via_ssh(
        { return_exit_status => 1 },
        (
            $self->_remote_uname() eq 'cygwin'
            ? ( '/bin/kill', '-W' )
            : ('kill')
        ),
        '-0',
        $remote_pid
    );
    if ( $result == 0 ) {
        $self->{last_remote_alive_status} = 1;
    }
    else {
        $self->{last_remote_alive_status} = 0;
    }
    return $self->{last_remote_alive_status};
}

sub alive {
    my ($self) = @_;
    if ( $self->_adb() ) {
        my $parameters;
        my $binary = q[adb];
        my @arguments =
          ( qw(-s), $self->_adb_serial(), qw(shell am stack list) );
        my $handle =
          $self->_get_local_handle_for_generic_command_output( $parameters,
            $binary, @arguments );
        my $quoted_package_name   = quotemeta $self->_adb_package_name();

lib/Firefox/Marionette.pm  view on Meta::CPAN

    return $connected;
}

sub _setup_local_connection_to_firefox {
    my ( $self, @arguments ) = @_;
    my $host = _DEFAULT_HOST();
    my $port;
    my $socket;
    my $sock_addr;
    my $connected;
    while ( ( !$connected ) && ( $self->alive() ) ) {
        if ( $self->_adb() ) {
            Firefox::Marionette::Exception->throw(
                'TODO: Cannot connect to android yet. Patches welcome');
        }
        $socket = undef;
        socket $socket,
          $self->_using_unix_sockets_for_ssh_connection()
          ? Socket::PF_UNIX()
          : Socket::PF_INET(), Socket::SOCK_STREAM(), 0
          or Firefox::Marionette::Exception->throw(

lib/Firefox/Marionette.pm  view on Meta::CPAN

        $port ||= $self->_get_marionette_port_or_undef();
        next if ( !defined $port );
        $sock_addr ||= $self->_get_sock_addr( $host, $port );
        next if ( !defined $sock_addr );

        $connected =
          $self->_network_connection_and_initial_read_from_marionette( $socket,
            $sock_addr );
    }
    $self->_reap();
    if ( ( $self->alive() ) && ($socket) ) {
    }
    else {
        my $error_message =
            $self->error_message()
          ? $self->error_message()
          : q[Firefox was not launched];
        Firefox::Marionette::Exception->throw($error_message);
    }
    return $socket;
}

lib/Firefox/Marionette.pm  view on Meta::CPAN

    my $message_id = $self->_new_message_id();
    $self->_send_request(
        [ _COMMAND(), $message_id, $self->_command('WebDriver:GetTitle') ] );
    my $response = $self->_get_response($message_id);
    return $self->_response_result_value($response);
}

sub quit {
    my ( $self, $flags ) = @_;
    my $ssh_local_directory = $self->ssh_local_directory();
    if ( !$self->alive() ) {
        my $socket = delete $self->{_socket};
        if ($socket) {
            close $socket
              or Firefox::Marionette::Exception->throw(
                "Failed to close socket to firefox:$EXTENDED_OS_ERROR");
        }
        $self->_terminate_xvfb();
    }
    elsif ( $self->_socket() ) {
        eval {

lib/Firefox/Marionette.pm  view on Meta::CPAN

    my $encoder = JSON->new()->convert_blessed()->ascii();
    if ( $self->debug() ) {
        $encoder->canonical(1);
    }
    my $json   = $encoder->encode($object);
    my $length = length $json;
    if ( $self->debug() ) {
        warn ">> $length:$json\n";
    }
    my $result;
    if ( $self->alive() ) {
        $result = syswrite $self->_socket(), "$length:$json";
    }
    if ( !defined $result ) {
        my $socket_error = $EXTENDED_OS_ERROR;
        if ( $self->alive() ) {
            Firefox::Marionette::Exception->throw(
                "Failed to send request to firefox:$socket_error");
        }
        else {
            my $error_message =
              $self->error_message() ? $self->error_message() : q[];
            Firefox::Marionette::Exception->throw($error_message);
        }
    }
    return;
}

sub _handle_socket_read_failure {
    my ($self) = @_;
    my $socket_error = $EXTENDED_OS_ERROR;
    if ( $self->alive() ) {
        Firefox::Marionette::Exception->throw(
"Failed to read size of response from socket to firefox:$socket_error"
        );
    }
    else {
        my $error_message =
          $self->error_message() ? $self->error_message() : q[];
        Firefox::Marionette::Exception->throw($error_message);
    }
    return;
}

sub _read_from_socket {
    my ($self) = @_;
    my $number_of_bytes_in_response;
    my $initial_buffer;
    while ( ( !defined $number_of_bytes_in_response ) && ( $self->alive() ) ) {
        my $number_of_bytes;
        my $octet;
        if ( $self->{_initial_octet_read_from_marionette_socket} ) {
            $octet = delete $self->{_initial_octet_read_from_marionette_socket};
            $number_of_bytes = length $octet;
        }
        else {
            $number_of_bytes = sysread $self->_socket(), $octet, 1;
        }
        if ( defined $number_of_bytes ) {

lib/Firefox/Marionette.pm  view on Meta::CPAN

            ($number_of_bytes_in_response) = ($1);
        }
    }
    if ( !defined $self->{_initial_packet_size} ) {
        $self->{_initial_packet_size} = $number_of_bytes_in_response;
    }
    my $number_of_bytes_already_read = 0;
    my $json                         = q[];
    while (( defined $number_of_bytes_in_response )
        && ( $number_of_bytes_already_read < $number_of_bytes_in_response )
        && ( $self->alive() ) )
    {
        my $number_of_bytes_read = sysread $self->_socket(), my $buffer,
          $number_of_bytes_in_response - $number_of_bytes_already_read;
        if ( defined $number_of_bytes_read ) {
            $json .= $buffer;
            $number_of_bytes_already_read += $number_of_bytes_read;
        }
        else {
            my $socket_error = $EXTENDED_OS_ERROR;
            if ( $self->alive() ) {
                Firefox::Marionette::Exception->throw(
"Failed to read response from socket to firefox:$socket_error"
                );
            }
            else {
                my $error_message =
                  $self->error_message() ? $self->error_message() : q[];
                Firefox::Marionette::Exception->throw($error_message);
            }
        }

lib/Firefox/Marionette.pm  view on Meta::CPAN

    if ( ( $self->debug() ) && ( defined $number_of_bytes_in_response ) ) {
        warn "<< $number_of_bytes_in_response:$json\n";
    }
    return $self->_decode_json($json);
}

sub _decode_json {
    my ( $self, $json ) = @_;
    my $parameters;
    eval { $parameters = JSON::decode_json($json); } or do {
        if ( $self->alive() ) {
            if ($EVAL_ERROR) {
                chomp $EVAL_ERROR;
                die "$EVAL_ERROR\n";
            }
        }
        else {
            my $error_message =
              $self->error_message() ? $self->error_message() : q[];
            Firefox::Marionette::Exception->throw($error_message);
        }

lib/Firefox/Marionette.pm  view on Meta::CPAN

=back

Importantly, this will break L<feature detection|https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Feature_detection> for any website that relies on it.

See L<IMITATING OTHER BROWSERS|/IMITATING-OTHER-BROWSERS> a discussion of these types of techniques.  These changes are not foolproof, but it is interesting to see what can be done with modern browsers.  All this behaviour should be regarded as extre...

=head2 alert_text

Returns the message shown in a currently displayed modal message box

=head2 alive

This method returns true or false depending on if the Firefox process is still running.

=head2 application_type

returns the application type for the Marionette protocol.  Should be 'gecko'.

=head2 arch

returns the architecture of the machine running firefox.  Should be something like 'x86_64' or 'arm'.  This is only intended for test suite support.

t/01-marionette.t  view on Meta::CPAN

}

sub empty_port {
	socket my $socket, Socket::PF_INET(), Socket::SOCK_STREAM(), 0 or die "Failed to create a socket:$!";
	bind $socket, Socket::sockaddr_in( 0, Socket::INADDR_LOOPBACK() ) or die "Failed to bind socket:$!";
	my $port = ( Socket::sockaddr_in( getsockname $socket ) )[0];
	close $socket or die "Failed to close random socket:$!";
	return $port;
}

sub process_alive {
	my ($pid) = @_;
	if ($^O eq 'MSWin32') {
		if (Win32::Process::Open(my $process, $pid, 0)) {
			$process->GetExitCode( my $exit_code );
			if ( $exit_code == Win32::Process::STILL_ACTIVE() ) {
				return 1;
			}
		} else {
			return 0;
		}

t/01-marionette.t  view on Meta::CPAN

	ok($timeouts->script() == $script_timeout, "\$timeouts->script() is $script_timeout");
	ok($timeouts->implicit() == $implicit_timeout, "\$timeouts->implicit() is $implicit_timeout");
	if ($major_version >= $min_stealth_version) {
		TODO: {
			local $TODO = "Some installations of firefox can default to webdriver being off"; # such as http://www.cpantesters.org/cpan/report/a0532bce-c32c-11ee-ae2f-883f6e8775ea (FreeBSD 14.0-STABLE) (BuildID 20240123011445)
			my $webdriver = $firefox->script('return navigator.webdriver');
			ok($webdriver, "navigator.webdriver returns true:" . (defined $webdriver ? $webdriver : q[undef]));
		}
	}
	ok(!defined $firefox->child_error(), "Firefox does not have a value for child_error");
	ok($firefox->alive(), "Firefox is still alive");
	ok(not($firefox->script('window.open("about:blank", "_blank");')), "Opening new window to about:blank via 'window.open' script");
	ok($firefox->close_current_window_handle(), "Closed new tab/window");
	SKIP: {
		if ($major_version < 55) {
			skip("Deleting and re-creating sessions can hang firefox for old versions", 1);
		}
		ok($firefox->delete_session()->new_session(), "\$firefox->delete_session()->new_session() has cleared the old session and created a new session");
	}
	my $child_error = $firefox->quit();
	if ($child_error != 0) {
		diag("Firefox exited with a \$? of $child_error");
	}
	ok($child_error =~ /^\d+$/, "Firefox has closed with an integer exit status of " . $child_error);
	if ($major_version < 50) {
		$correct_exit_status = $child_error;
	}
	ok($firefox->child_error() == $child_error, "Firefox returns $child_error for the child error, matching the return value of quit():$child_error:" . $firefox->child_error());
	ok(!$firefox->alive(), "Firefox is not still alive");
}
if ((!defined $major_version) || ($major_version < 40)) {
	$profile->set_value('security.tls.version.max', 3); 
}
$profile->set_value('browser.newtabpage.activity-stream.feeds.favicon', 'true'); 
$profile->set_value('browser.shell.shortcutFavicons', 'true'); 
$profile->set_value('browser.newtabpage.enabled', 'true'); 
$profile->set_value('browser.pagethumbnails.capturing_disabled', 'false', 0); 
$profile->set_value('startup.homepage_welcome_url', 'false', 0); 

t/01-marionette.t  view on Meta::CPAN

	}
	if ($skip_message) {
		skip($skip_message, 8);
	}
	ok($firefox, "Firefox has started in Marionette mode with as survivable");
	my $capabilities = $firefox->capabilities();
	ok((ref $capabilities) eq 'Firefox::Marionette::Capabilities', "\$firefox->capabilities() returns a Firefox::Marionette::Capabilities object");
	my $firefox_pid = $capabilities->moz_process_id();
	ok($firefox_pid, "Firefox process has a process id of $firefox_pid");
	if (!$ENV{FIREFOX_HOST}) {
		ok(process_alive($firefox_pid), "Can contact firefox process ($firefox_pid)");
	}
	$firefox = undef;
	if (!$ENV{FIREFOX_HOST}) {
		ok(process_alive($firefox_pid), "Can contact firefox process ($firefox_pid)");
	}
	($skip_message, $firefox) = start_firefox(0, debug => 1, reconnect => 1);
	ok($firefox, "Firefox has reconnected in Marionette mode");
	$capabilities = $firefox->capabilities();
	ok($firefox_pid == $capabilities->moz_process_id(), "Firefox has the same process id");
	$firefox = undef;
	if (!$ENV{FIREFOX_HOST}) {
		ok(!process_alive($firefox_pid), "Cannot contact firefox process ($firefox_pid)");
	}
	if ($ENV{FIREFOX_HOST}) {
		if ($ENV{FIREFOX_BINARY}) {
			skip("No profile testing when the FIREFOX_BINARY override is used", 6);
		}
		if (!$ENV{RELEASE_TESTING}) {
			skip("No profile testing except for RELEASE_TESTING", 6);
		}
		if (($ENV{WATERFOX}) || ($ENV{WATERFOX_VIA_FIREFOX})) {
			skip("No profile testing when any WATERFOX override is used", 6);

t/01-marionette.t  view on Meta::CPAN

		ok($firefox_pid, "Firefox process has a process id of $firefox_pid when using a profile_name");
		my $child_error = $firefox->quit();
		if ($child_error != 0) {
			diag("Firefox exited with a \$? of $child_error");
		}
		ok($child_error =~ /^\d+$/, "Firefox has closed with an integer exit status of " . $child_error);
		if ($major_version < 50) {
			$correct_exit_status = $child_error;
		}
		ok($firefox->child_error() == $child_error, "Firefox returns $child_error for the child error, matching the return value of quit():$child_error:" . $firefox->child_error());
		ok(!$firefox->alive(), "Firefox is not still alive");
	} else {
		if ($ENV{FIREFOX_BINARY}) {
			skip("No profile testing when the FIREFOX_BINARY override is used", 6);
		}
		if (!$ENV{RELEASE_TESTING}) {
			skip("No profile testing except for RELEASE_TESTING", 6);
		}
		if (($ENV{WATERFOX}) || ($ENV{WATERFOX_VIA_FIREFOX})) {
			skip("No profile testing when any WATERFOX override is used", 6);
		}

t/01-marionette.t  view on Meta::CPAN

			$at_least_one_success = 1;
		}
		if ($skip_message) {
			skip($skip_message, 8);
		}
		ok($firefox, "Firefox has started in Marionette mode with as survivable with a profile_name and har");
		my $capabilities = $firefox->capabilities();
		ok((ref $capabilities) eq 'Firefox::Marionette::Capabilities', "\$firefox->capabilities() returns a Firefox::Marionette::Capabilities object");
		my $firefox_pid = $capabilities->moz_process_id();
		ok($firefox_pid, "Firefox process has a process id of $firefox_pid when using a profile_name");
		ok(process_alive($firefox_pid), "Can contact firefox process ($firefox_pid) when using a profile_name");
		$firefox = undef;
		ok(process_alive($firefox_pid), "Can contact firefox process ($firefox_pid) when using a profile_name");
		($skip_message, $firefox) = start_firefox(0, debug => 1, reconnect => 1, profile_name => $name);
		ok($firefox, "Firefox has reconnected in Marionette mode when using a profile_name");
		ok($firefox_pid == $capabilities->moz_process_id(), "Firefox has the same process id when using a profile_name");
		$firefox = undef;
		ok(!process_alive($firefox_pid), "Cannot contact firefox process ($firefox_pid)");
	}
}

if ($^O eq 'MSWin32') {
} elsif ($ENV{RELEASE_TESTING}) {
	eval {
		$ca_cert_handle = File::Temp->new( TEMPLATE => File::Spec->catfile( File::Spec->tmpdir(), 'firefox_test_ca_cert_XXXXXXXXXXX')) or Firefox::Marionette::Exception->throw( "Failed to open temporary file for writing:$!");
		fcntl $ca_cert_handle, Fcntl::F_SETFD(), 0 or Carp::croak("Can't clear close-on-exec flag on temporary file:$!");
		$ca_private_key_handle = File::Temp->new( TEMPLATE => File::Spec->catfile( File::Spec->tmpdir(), 'firefox_test_ca_private_XXXXXXXXXXX')) or Firefox::Marionette::Exception->throw( "Failed to open temporary file for writing:$!");
		system {'openssl'} 'openssl', 'genrsa', '-out' => $ca_private_key_handle->filename(), 4096 and Carp::croak("Failed to generate a private key:$!");

t/01-marionette.t  view on Meta::CPAN

	} elsif ($^O eq 'cygwin') {
		SKIP: {
			skip("Not testing dead firefox processes for cygwin", 2);	
		}
		TODO: {
			local $TODO = $correct_exit_status == 0 ? q[] : $capabilities->browser_version() . " is not exiting cleanly";
			ok($firefox->quit() == $correct_exit_status, "Firefox has closed with an exit status of $correct_exit_status:" . $firefox->child_error());
		}
	} else {
		my $xvfb_pid = $firefox->xvfb_pid();
		while($firefox->alive()) {
			diag("Killing PID " . $capabilities->moz_process_id() . " with a signal " . $signals_by_name{TERM});
			sleep 1; 
			kill $signals_by_name{TERM}, $capabilities->moz_process_id();
			sleep 1; 
		}
		eval { $firefox->go('https://metacpan.org') };
		chomp $@;
		ok($@ =~ /Firefox[ ]killed[ ]by[ ]a[ ]TERM[ ]signal/smx, "Exception is thrown when a command is issued to a dead firefox process:$@");
		eval { $firefox->go('https://metacpan.org') };
		chomp $@;

t/author/bulk_test.pl  view on Meta::CPAN

	}
	return 1;
}

sub _win32_path {
	my ($unix_path) = @_;
	my $windows_path = join q[\\], split /[\/]/smx, $unix_path;
	return $windows_path;
}

sub _check_parent_alive {
	if (!kill 0, $parent_pid) {
		die "Parent ($parent_pid) is no longer running.  Terminating\n";
	}
}

sub _sleep_until_shutdown {
	my ($server) = @_;
	while (_virsh_node_running($server)) {
		_virsh_shutdown($server);
		_log_stderr($server, "Waiting for $server->{name} to shutdown");

t/author/bulk_test.pl  view on Meta::CPAN

	print {*STDERR} _prefix($server) . "$message\n" or die "Failed to print to STDERR:$EXTENDED_OS_ERROR";
}

sub _log_stdout {
	my ($server, $message) = @_;
	print _prefix($server) . "$message\n" or die "Failed to print to STDOUT:$EXTENDED_OS_ERROR";
}

sub _contents {
	my ($server, $parameters, $command, @arguments) = @_;
	_check_parent_alive();
	my @lines;
	my $return_result;
	my $handle = FileHandle->new();
	if (my $pid = $handle->open(q[-|])) {
		my $alarm_method;
		my $alarm_killed;
		if ($parameters->{alarm_after}) {
			_log_stderr($server, "Alarm is $parameters->{alarm_after} seconds");
			alarm $parameters->{alarm_after};
			$alarm_method = sub {

t/author/bulk_test.pl  view on Meta::CPAN

						_log_stderr($server, "Killed local process $pid after $parameters->{alarm_after} seconds at " . localtime);
						$alarm_killed = 1;
					};
		}
		local $SIG{ALRM} = $alarm_method;
		COMMAND: while(my $line = <$handle>) {
			$line =~ s/\r?\n$//smx;
			$line =~ s/\e\[(K|\d+;1H|\??25[lh]|2J|[mHG]|23X|17X)//smxg;
			$line =~ s/\e\]0;//smxg;
			$line =~ s/\x7//smxg;
			_check_parent_alive();
			_log_stdout($server, $line);
			push @lines, $line;
			if ($alarm_killed) {
				last COMMAND;
			}
		}
		if (!$alarm_killed) {
			my $result = close $handle;
			if ($result == 1) {
				$return_result = 0;

t/test_daemons.pm  view on Meta::CPAN

http {
    client_body_temp_path   $temp_directories{client_body_temp};
    proxy_temp_path         $temp_directories{proxy_temp};
    fastcgi_temp_path       $temp_directories{fastcgi_temp};
    uwsgi_temp_path         $temp_directories{uwsgi_temp};
    scgi_temp_path          $temp_directories{scgi_temp};
    access_log              logs/access.log;
    sendfile                on;
    tcp_nopush              on;
    tcp_nodelay             on;
    keepalive_timeout       65;
    types_hash_max_size     4096;

    types {
        text/html           html;
        text/javascript     js;
        text/css            css;
        application/json    json;
    }
    default_type            text/plain;



( run in 3.627 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )