PAGI-Server
view release on metacpan or search on metacpan
'dies on missing file'
);
};
# Test 13: Error on invalid module
subtest 'error on invalid module' => sub {
my $runner = PAGI::Server::Runner->new;
$runner->{argv} = ['PAGI::App::NonExistent12345'];
like(
dies { $runner->load_app },
qr/Cannot find module/i,
'dies on invalid module'
);
};
# Test 14: Error on file that doesn't return coderef
subtest 'error on non-coderef file' => sub {
my $tmpdir = tempdir(CLEANUP => 1);
my $bad_app = "$tmpdir/bad_app.pl";
# Write a file that returns a hashref instead of coderef
open my $fh, '>', $bad_app or die "Cannot write $bad_app: $!";
print $fh "{ foo => 'bar' };\n";
close $fh;
my $runner = PAGI::Server::Runner->new;
$runner->{app_spec} = $bad_app;
like(
dies { $runner->load_app },
qr/must return a coderef/i,
'dies on non-coderef'
);
};
# Test 15: load_server constructs the configured server class
subtest 'load_server creates server' => sub {
my $runner = PAGI::Server::Runner->new(server => 'PAGITest::FakeServer', port => 0, quiet => 1);
$runner->{app} = sub { };
my $fake = $runner->load_server;
isa_ok($fake, ['PAGITest::FakeServer'], 'load_server constructs the configured class');
is($fake->{options}{app}, $runner->{app}, 'app passed to constructor');
# SSL config must be forwarded unchanged â whether the server honours it
# (cert-file validation etc.) is tested in PAGI-Server's own suite.
my $ssl_runner = PAGI::Server::Runner->new(
server => 'PAGITest::FakeServer',
quiet => 1,
server_options => { ssl => { cert_file => 'c', key_file => 'k' } },
);
$ssl_runner->{app} = sub { };
my $ssl_fake = $ssl_runner->load_server;
is($ssl_fake->{options}{ssl}, { cert_file => 'c', key_file => 'k' },
'ssl config passed through unchanged');
};
# Tests 16-19 (load_server dies without app, integration: server responds to
# requests, integration: module-based app serves files, SSL options validation)
# have been relocated to the PAGI-Server distribution because they exercise
# PAGI::Server internals or require a real socket. Saved verbatim to
# /tmp/pagi-moved-subtests.pl for that relocation task.
# Test 20: help flag
subtest 'help flag sets show_help' => sub {
my $runner = PAGI::Server::Runner->new;
$runner->parse_options('--help');
ok($runner->{show_help}, 'show_help is set');
};
# Test 21: production CLI options parsing
subtest 'production CLI options parsing' => sub {
my $runner = PAGI::Server::Runner->new;
$runner->parse_options(
'-D',
'--pid', '/tmp/test.pid',
'--user', 'nobody',
'--group', 'nogroup',
);
is($runner->{daemonize}, 1, '--daemonize parsed');
is($runner->{pid_file}, '/tmp/test.pid', '--pid parsed');
is($runner->{user}, 'nobody', '--user parsed');
is($runner->{group}, 'nogroup', '--group parsed');
};
# Test 22: _drop_privileges validation
subtest '_drop_privileges validation' => sub {
# Skip on Windows - getpwnam/getgrnam not available
if ($^O eq 'MSWin32') {
skip_all 'User/group privilege tests not supported on Windows';
}
# Test 1: Returns early if neither user nor group specified
my $runner1 = PAGI::Server::Runner->new(port => 0, quiet => 1);
ok(lives { $runner1->_drop_privileges }, '_drop_privileges returns early when no user/group');
# Test 2: Requires root for --user
my $runner2 = PAGI::Server::Runner->new(
user => 'nobody',
port => 0,
quiet => 1,
);
if ($> == 0) {
# Running as root - test should validate user exists
my $runner3 = PAGI::Server::Runner->new(
user => 'nonexistent_user_12345',
port => 0,
quiet => 1,
);
like(
dies { $runner3->_drop_privileges },
qr/Unknown user/,
'rejects unknown user (as root)'
);
} else {
# Not root - should require root
like(
dies { $runner2->_drop_privileges },
qr/Must run as root/,
( run in 0.811 second using v1.01-cache-2.11-cpan-84de2e75c66 )