# -*-perl-*-
use strict;
use warnings;
use Test::More tests => 11;
use Data::Dumper;
use Carp qw(croak);
use MogileFS::ReplicationPolicy::MultipleHosts;
{
my %all_devs;
for my $i (1..3) {
$all_devs{$i} = MogileFS::Test::Device->new(
hostid => 1,
id => $i,
state => "alive",
percent_free => 0,
should_get_replicated_files => 0,
);
}
for my $i (4..6) {
$all_devs{$i} = MogileFS::Test::Device->new(
hostid => 2,
id => $i,
state => "alive",
percent_free => 0,
should_get_replicated_files => 0,
);
}
for my $i (7..9) {
$all_devs{$i} = MogileFS::Test::Device->new(
hostid => 3,
id => $i,
state => "alive",
percent_free => .2,
should_get_replicated_files => 1,
);
}
for my $i (10..12) {
$all_devs{$i} = MogileFS::Test::Device->new(
hostid => 4,
id => $i,
state => "alive",
percent_free => .2,
should_get_replicated_files => 1,
);
}
# Now for the actual tests
{
my $res = run(
mindevcount => 3,
policy_class => "MogileFS::ReplicationPolicy::MultipleHosts",
on_devs => [ $all_devs{4}, $all_devs{7}, $all_devs{10} ],
all_devs => \%all_devs,
);
ok($res->is_happy, "Expected happiness");
ok(!$res->too_happy, "... but not too happy");
}
{
my $res = run(
mindevcount => 3,
policy_class => "MogileFS::ReplicationPolicy::MultipleHosts",
on_devs => [ $all_devs{1}, $all_devs{4}, $all_devs{7}, $all_devs{10} ],
all_devs => \%all_devs,
);
ok($res->is_happy, "Expected happiness");
ok($res->too_happy, "... and too happy too");
}
{
my $res = run(
mindevcount => 3,
policy_class => "MogileFS::ReplicationPolicy::MultipleHosts",
on_devs => [ $all_devs{1}, $all_devs{2}, $all_devs{4} ],
all_devs => \%all_devs,
);
ok(!$res->is_happy, "Expected unhappiness");
my @ideals = $res->copy_to_one_of_ideally;
ok(@ideals, "List of ideal devices");
my @desperate = $res->copy_to_one_of_desperate;
is(@desperate, 0, "Empty list of desperate devices");
}
{
my $res = run(
mindevcount => 3,
policy_class => "MogileFS::ReplicationPolicy::MultipleHosts",
on_devs => [ $all_devs{7}, $all_devs{10} ],
all_devs => \%all_devs,
);
ok(!$res->is_happy, "Expected unhappiness");
my @ideals = $res->copy_to_one_of_ideally;
is(@ideals, 0, "No ideal devices");
my @desperate = $res->copy_to_one_of_desperate;
ok(@desperate, "List of desperate devices");
}
{
my $res = run(
mindevcount => 3,
policy_class => "MogileFS::ReplicationPolicy::MultipleHosts",
on_devs => [ $all_devs{7}, $all_devs{10}, $all_devs{11} ],
all_devs => \%all_devs,
);
ok($res->temp_fail, "Expected temporary failure");
}
}
sub run {
my %args = @_;
my $fidid = delete($args{fidid}) || 1;
my $mindevcount = delete($args{mindevcount}) || croak "mindevcount arg required";
my $policy_class = delete($args{policy_class}) || croak "policy_class arg required";
my $on_devs = delete($args{on_devs}) || croak "on_devs arg required";
my $all_devs = delete($args{all_devs}) || croak "all_devs arg required";
my $failed = delete($args{failed}) || {};
eval "use $policy_class";
my $policy = $policy_class->new;
my $class = MogileFS::Test::Class->new(
repl_policy_obj => $policy,
mindevcount => $mindevcount,
);
my $devfid = MogileFS::Test::DevFID->new(
id => $fidid,
class => $class,
);
my $polobj = $class->repl_policy_obj;
return $polobj->replicate_to(
fid => $fidid,
on_devs => $on_devs,
all_devs => $all_devs,
failed => $failed,
min => $mindevcount,
);
}
package MogileFS::Test::Device;
use MogileFS::DeviceState;
use Carp qw(croak);
sub new {
my $class = shift;
my %opts = @_;
my $self = bless {}, (ref $class || $class);
foreach my $optkey (qw(id hostid state should_get_replicated_files percent_free)) {
croak "$optkey argument not supplied" unless exists $opts{$optkey};
$self->{$optkey} = delete $opts{$optkey};
}
croak "Extra args:" if (keys %opts);
$self->{dstate} = MogileFS::DeviceState->of_string($self->{state});
return $self;
}
sub hostid {
return $_[0]->{hostid};
}
sub id {
return $_[0]->{id};
}
sub devid {
return $_[0]->{id};
}
sub dstate {
return $_[0]->{dstate};
}
sub should_get_replicated_files {
return $_[0]->{should_get_replicated_files};
}
sub percent_free {
return $_[0]->{percent_free};
}
package MogileFS::Test::DevFID;
use strict;
use warnings;
sub new {
my $class = shift;
my %opts = @_;
my $self = bless {}, (ref $class || $class);
foreach my $optkey (qw(id class)) {
$self->{$optkey} = delete $opts{$optkey} || die("$optkey argument not supplied");
}
die "Extra args:" if (keys %opts);
return $self;
}
sub id {
return $_[0]->{id};
}
sub class {
return $_[0]->{class};
}
package MogileFS::Test::Class;
use strict;
use warnings;
sub new {
my $class = shift;
my %opts = @_;
my $self = bless {}, (ref $class || $class);
foreach my $optkey (qw(repl_policy_obj mindevcount)) {
$self->{$optkey} = delete $opts{$optkey} || die("$optkey argument not supplied");
}
die "Extra args:" if (keys %opts);
return $self;
}
sub repl_policy_obj {
return $_[0]->{repl_policy_obj};
}
sub mindevcount {
return $_[0]->{mindevcount};
}