shell bypass 403
#!/usr/bin/perl -w
# vim: ts=2 sw=2 expandtab
# Tests NFA sessions.
use strict;
use lib qw(./mylib ../mylib);
sub POE::Kernel::ASSERT_DEFAULT () { 1 }
BEGIN {
package
POE::Kernel;
use constant TRACE_DEFAULT => exists($INC{'Devel/Cover.pm'});
}
use Test::More;
use POE qw(NFA);
my $NEW_POE;
BEGIN {
# fixes Argument "1.294_272" isn't numeric in numeric le
my $poe_ver = eval("\$POE::VER" . "SION"); # Pesky CPAN indexer.
$poe_ver = $1 if $poe_ver =~ /^(?:[^_]+)\_/;
if ($poe_ver <= 1.003) {
$NEW_POE = 0;
plan tests => 28;
} else {
$NEW_POE = 1;
plan tests => 39;
}
}
### Plain NFA. This simulates a pushbutton that toggles a light.
### This goes in its own package because POE::Session and POE::NFA
### export conflicting constants.
package
Switch;
use POE::NFA;
sub new {
my $class = shift;
return bless {}, $class;
}
sub _default {
0;
}
sub off_enter {
Test::More::is($_[OBJECT], 'Switch', '$_[OBJECT] is a package')
if ($NEW_POE);
$_[KERNEL]->post( $_[ARG0] => visibility => 0 );
}
sub off_pushed {
$_[MACHINE]->goto_state( on => enter => $_[SENDER] );
}
sub enter {
Test::More::isa_ok($_[OBJECT], 'Switch', '$_[OBJECT]')
if ($NEW_POE);
$_[KERNEL]->post( $_[ARG0] => visibility => 1 );
}
sub pushed {
$_[MACHINE]->goto_state( off => enter => $_[SENDER] );
}
my $self = Switch->new;
my $args = {
inline_states => {
# The initial state, and its start event. Make the switch
# visible by name, and start in the 'off' state.
initial => {
start => sub {
Test::More::is($_[OBJECT], undef, 'no object')
if ($NEW_POE);
$_[KERNEL]->alias_set( 'switch' );
$_[MACHINE]->goto_state( 'off' );
},
_default => \&_default,
},
},
};
if ($NEW_POE) {
$args->{package_states} = {
off => [
Switch => {
enter => 'off_enter',
pushed => 'off_pushed',
_default => '_default',
},
],
};
$args->{object_states} = {
# The light is on. When this state is entered, post a visibility
# event at whatever had caused the light to go on. When it's
# pushed, have the light go off.
on => [
$self => [qw(enter pushed _default)],
],
},
} else {
$args->{inline_states}->{off} = {
enter => \&off_enter,
pushed => \&off_pushed,
_default => \&_default,
};
$args->{inline_states}->{on} = {
enter => \&enter,
pushed => \&pushed,
_default => \&_default,
};
}
POE::NFA->spawn(%$args)
->goto_state( initial => 'start' ); # enter the initial state
### This NFA uses the stop() method. Gabriel Kihlman discovered that
### POE::NFA lags behind POE::Kernel after 0.24, and stop() wasn't
### fixed to use the new _data_ses_free() method of POE::Kernel.
POE::NFA->spawn(
inline_states => {
initial => {
start => sub { $_[MACHINE]->stop() }
}
}
)->goto_state(initial => 'start');
### A plain session to interact with the switch. It's in its own
### package to avoid conflicting constants. This simulates a causal
### observer who pushes the light's button over and over, watching it
### as it goes on and off.
package
Operator;
use POE::Session;
POE::Session->create(
inline_states => {
# Start by giving the session a name. This keeps the session
# alive while other sessions (the light) operate. Set a test
# counter, and yield to the 'push' handler.
_start => sub {
$_[KERNEL]->alias_set( 'operator' );
$_[KERNEL]->yield( 'push' );
$_[HEAP]->{push_count} = 0;
},
# Push the button, and count the button push for testing.
push => sub {
$_[HEAP]->{push_count}++;
$_[KERNEL]->post( switch => 'pushed' );
},
# The light did something observable. Check that its on/off
# state matches our expectation. If we need to test some more,
# push the button again.
visibility => sub {
Test::More::ok(
($_[HEAP]->{push_count} & 1) == $_[ARG0],
"light state matches expected state"
);
$_[KERNEL]->yield( 'push' ) if $_[HEAP]->{push_count} < 10;
},
# Dummy handlers to avoid ASSERT_STATES warnings.
_stop => sub { 0 },
}
);
### This is a Fibonacci number servlet. Post it a request with the F
### number you want, and it calculates and returns it.
package
FibServer;
use POE::NFA;
POE::NFA->spawn(
inline_states => {
# Set up an alias so that clients can find us.
initial =>
{ start => sub { $_[KERNEL]->alias_set( 'server' );
$_[MACHINE]->goto_state( 'listen' );
},
_default => sub { 0 },
},
# Listen for a request. The request includes which Fibonacci
# number to return.
listen =>
{ request => sub {
$_[RUNSTATE]->{client} = $_[SENDER];
$_[MACHINE]->call_state( answer => # return event
calculate => # new state
start => # new state's entry event
$_[ARG0] # F-number to return
);
},
answer => sub {
$_[KERNEL]->post( delete($_[RUNSTATE]->{client}), 'fib', $_[ARG0] );
},
_default => sub { 0 },
},
calculate =>
{ start => sub {
$_[MACHINE]->return_state( 0 ) if $_[ARG0] == 0;
$_[MACHINE]->return_state( 1 ) if $_[ARG0] == 1;
$_[RUNSTATE]->{f} = [ 0, 1 ];
$_[RUNSTATE]->{n} = 1;
$_[RUNSTATE]->{target} = $_[ARG0];
$_[KERNEL]->yield( 'next' );
},
next => sub {
$_[RUNSTATE]->{n}++;
$_[RUNSTATE]->{f}->[2] =
$_[RUNSTATE]->{f}->[0] + $_[RUNSTATE]->{f}->[1];
shift @{$_[RUNSTATE]->{f}};
if ($_[RUNSTATE]->{n} == $_[RUNSTATE]->{target}) {
$_[MACHINE]->return_state( $_[RUNSTATE]->{f}->[1] );
}
else {
$_[KERNEL]->yield( 'next' );
}
},
_default => sub { 0 },
},
}
)->goto_state( initial => 'start' );
### This is a Fibonacci client. It asks for F numbers and checks the
### responses vs. expectations.
package
FibClient;
use POE::Session;
my $test_number = 11;
my @test = (
[ 0, 0 ],
[ 1, 1 ],
[ 2, 1 ],
[ 3, 2 ],
[ 4, 3 ],
[ 5, 5 ],
[ 17, 1597 ],
[ 23, 28657 ],
[ 29, 514229 ],
[ 43, 433494437 ],
);
POE::Session->create(
inline_states => {
_start => sub {
# Set up an alias so we'll stay alive until everything is done.
$_[KERNEL]->alias_set( 'client' );
$_[KERNEL]->yield( 'next_test' );
},
next_test => sub {
$_[KERNEL]->post( server => request => $test[0]->[0] );
},
fib => sub {
Test::More::ok(
$_[ARG0] == $test[0]->[1],
"fib($test[0]->[0]) returned $_[ARG0] (wanted $test[0]->[1])"
);
shift @test;
$test_number++;
$_[KERNEL]->yield( 'next_test' ) if @test;
},
# Dummy handlers to avoid ASSERT_STATES warnings.
_stop => sub { 0 },
},
);
### This tests using POE::Kernel->state() with a POE::NFA in the same way
### attaching a wheel to a session does
### Also tests options, and (call|post)backs
package
DynamicStates;
use POE::NFA;
POE::NFA->spawn(
inline_states => {
initial => {
start => sub {
$_[KERNEL]->alias_set( 'dynamicstates' );
$_[MACHINE]->goto_state( 'listen', 'send' );
$_[KERNEL]->state("test_wheel_event" => sub {
$_[KERNEL]->yield("happened");
}
);
# test options
my $orig = $_[MACHINE]->option(default => 1);
my $rv = $_[MACHINE]->option('default');
Test::More::ok($rv, "set default option successfully");
$rv = $_[MACHINE]->option('default' => $orig);
Test::More::ok($rv, "reset default option successfully");
$rv = $_[MACHINE]->option('default');
Test::More::ok(!($rv xor $orig), "reset default option successfully");
# test (post|call)backs
$_[MACHINE]->callback("callback")->();
$_[MACHINE]->postback("postback")->();
},
_default => sub { 0 },
callback => sub {
Test::More::pass("POE::NFA::callback");
},
postback => sub {
Test::More::fail("POE::NFA::postback");
},
},
listen => {
send => sub {
$_[KERNEL]->yield("test_wheel_event");
},
happened => sub {
Test::More::pass("wheel event happened");
Test::More::is($_[MACHINE]->get_current_state(), $_[STATE],
"get_current_state returns the same as \$_[STATE]");
Test::More::is_deeply($_[MACHINE]->get_runstate(), $_[RUNSTATE],
"get_runstate returns the same as \$_[RUNSTATE]");
},
callback => sub {
Test::More::fail("POE::NFA::callback");
},
postback => sub {
Test::More::pass("POE::NFA::postback");
},
},
},
)->goto_state("initial", "start");
### Run everything until it's all done.
package
main;
POE::Kernel->run();
1;