File Coverage

blib/lib/Prophet/Test/Arena.pm
Criterion Covered Total %
statement 4 9 44.4
branch n/a
condition n/a
subroutine 2 3 66.6
pod n/a
total 6 12 50.0


line stmt bran cond sub pod time code
1             package Prophet::Test::Arena;
2 6     6   7223 use Any::Moose;
  6         212663  
  6         46  
3              
4             has chickens => (
5             is => 'rw',
6             isa => 'ArrayRef',
7             default => sub { [] },
8             auto_deref => 1,
9             );
10              
11             has record_callback => (
12             is => 'rw',
13             isa => 'CodeRef',
14             );
15              
16             has history => (
17             is => 'rw',
18             isa => 'ArrayRef',
19             default => sub { [] },
20             );
21              
22             sub add_history {
23 0     0     my $self = shift;
24 0           push @{ $self->history }, @_;
  0            
25             }
26              
27 6     6   8076 use Prophet::Test::Participant;
  0            
  0            
28             use Prophet::Test;
29              
30             sub setup {
31             my $self = shift;
32             my $count = shift;
33             my @names = ref $count ? @$count : ( map { "person" . $_ } (1..$count));
34              
35             my @chickens = map { Prophet::Test::Participant->new( { name => $_, arena => $self } ) } @names;
36            
37             for my $c (@chickens) {
38              
39             as_user($c->name => sub {
40             my $p = Prophet::CLI->new();
41             diag($c => $p->handle->display_name_for_replica);
42             });
43             }
44            
45             $self->chickens(\@chickens);
46             }
47              
48             sub run_from_yaml {
49             my $self = shift;
50             my @c = caller(0);
51             no strict 'refs';
52             my $fh = *{ $c[0] . '::DATA' };
53              
54             return $self->run_from_yamlfile(@ARGV) unless fileno($fh);
55              
56             local $/;
57             eval { require YAML::Syck; } || Test::More::plan(skip_all => 'YAML::Syck required for these tests');
58             $self->run_from_data( YAML::Syck::Load(<$fh>) );
59              
60             }
61              
62             sub run_from_yamlfile {
63             my ( $self, $file ) = @_;
64             eval { require YAML::Syck; } || Test::More::plan(skip_all => 'YAML::Syck required for these tests');
65             $self->run_from_data( YAML::Syck::LoadFile($file) );
66             }
67              
68             sub run_from_data {
69             my ( $self, $data ) = @_;
70              
71             Test::More::plan( tests => scalar @{ $data->{recipe} } + scalar @{ $data->{chickens} } );
72             my $arena = Prophet::Test::Arena->new(
73             { record_callback => sub {
74             my ( $name, $action, $args ) = @_;
75             return;
76             },
77             }
78             );
79             $arena->setup( $data->{chickens} );
80              
81             my $record_map;
82              
83             for ( @{ $data->{recipe} } ) {
84             my ( $name, $action, $args ) = @$_;
85             my ($chicken) = grep { $_->name eq $name } $arena->chickens;
86             if ( $args->{record} ) {
87             $args->{record} = $record_map->{ $args->{record} };
88             }
89             my $next_result = $args->{result};
90              
91             as_user(
92             $chicken->name,
93             sub {
94             @_ = ( $chicken, $action, $args );
95             goto $chicken->can('take_one_step');
96             }
97             );
98              
99             if ( $args->{result} ) {
100             $record_map->{$next_result} = $args->{result};
101             }
102             }
103              
104             # my $third = $arena->dump_state;
105             # $arena->sync_all_pairs;
106             # my $fourth = $arena->dump_state;
107             # is_deeply($third,$fourth);
108              
109             }
110              
111             my $TB = Test::Builder->new();
112              
113             sub step {
114             my $self = shift;
115             my $step_name = shift || undef;
116             my $step_display = defined($step_name) ? $step_name : "(undef)";
117              
118             for my $chicken ($self->chickens) {
119              
120             diag(" as ".$chicken->name. ": $step_display");
121             # walk the arena, noting the type of each value
122             as_user( $chicken->name, sub { $chicken->take_one_step($step_name) } );
123             die "We failed some tests; aborting" if grep { !$_ } $TB->summary;
124              
125             }
126              
127             # for x rounds, have each participant execute a random action
128             }
129              
130             sub dump_state {
131             my $self = shift;
132             my %state;
133             for my $chicken ($self->chickens) {
134             $state{ $chicken->name } = as_user( $chicken->name, sub { $chicken->dump_state } );
135             }
136             return \%state;
137             }
138              
139             use List::Util qw/shuffle/;
140              
141             sub sync_all_pairs {
142             my $self = shift;
143              
144             diag("now syncing all pairs");
145              
146             my @chickens_a = shuffle $self->chickens;
147             my @chickens_b = shuffle $self->chickens;
148              
149             for my $a (@chickens_a) {
150             for my $b (@chickens_b) {
151             next if $a->name eq $b->name;
152             diag( $a->name, $b->name );
153             as_user( $a->name, sub { $a->sync_from_peer( { from => $b->name } ) } );
154             die if ( grep { !$_ } $TB->summary );
155             }
156              
157             }
158             return 1;
159             }
160              
161             sub record {
162             my ( $self, $name, $action, $args ) = @_;
163             my $stored = {%$args};
164             if ( my $record = $stored->{record} ) {
165             $stored->{record} = $self->{record_map}{$record};
166             } elsif ( my $result = $stored->{result} ) {
167             $stored->{result} = $self->{record_map}{$result} = ++$self->{record_cnt};
168             }
169             return $self->record_callback->( $name, $action, $args )
170             if $self->record_callback;
171              
172             # XXX: move to some kind of recorder class and make use of callback
173             $self->add_history([$name, $action, $stored]);
174             }
175              
176             __PACKAGE__->meta->make_immutable;
177             no Any::Moose;
178              
179             1;