409 lines
10 KiB
Perl
409 lines
10 KiB
Perl
# Net::ZooKeeper - Perl extension for Apache ZooKeeper
|
|
#
|
|
# Licensed to the Apache Software Foundation (ASF) under one
|
|
# or more contributor license agreements. See the NOTICE file
|
|
# distributed with this work for additional information
|
|
# regarding copyright ownership. The ASF licenses this file
|
|
# to you under the Apache License, Version 2.0 (the
|
|
# "License"); you may not use this file except in compliance
|
|
# with the License. You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
use File::Spec;
|
|
use Test::More tests => 47;
|
|
|
|
BEGIN { use_ok('Net::ZooKeeper', qw(:all)) };
|
|
|
|
|
|
my $test_dir;
|
|
(undef, $test_dir, undef) = File::Spec->splitpath($0);
|
|
require File::Spec->catfile($test_dir, 'util.pl');
|
|
|
|
my($hosts, $root_path, $node_path) = zk_test_setup(0);
|
|
|
|
|
|
SKIP: {
|
|
my $zkh = Net::ZooKeeper->new($hosts);
|
|
|
|
skip 'no valid handle', 15 unless (defined($zkh));
|
|
|
|
my $stat = $zkh->stat();
|
|
my $watch = $zkh->watch();
|
|
|
|
|
|
## DESTROY() on reblessed handle
|
|
|
|
bless($zkh, 'My::ZooKeeper');
|
|
is(ref($zkh), 'My::ZooKeeper',
|
|
'bless(): reblessed handle');
|
|
|
|
eval {
|
|
$zkh->EXISTS();
|
|
};
|
|
like($@, qr/Can't locate object method "EXISTS" via package "My::ZooKeeper"/,
|
|
'EXISTS(): not defined on reblessed handle');
|
|
|
|
my $attr = tied(%{$zkh});
|
|
|
|
my $ret = $attr->DESTROY();
|
|
ok($ret,
|
|
'DESTROY(): destroyed inner hash of reblessed handle');
|
|
|
|
$ret = $attr->DESTROY();
|
|
ok(!$ret,
|
|
'DESTROY(): no action on destroyed inner hash of reblessed handle');
|
|
|
|
undef $zkh;
|
|
ok(!defined($zkh),
|
|
'undef: released reblessed handle');
|
|
|
|
|
|
## DESTROY() on reblessed stat handle
|
|
|
|
bless($stat, 'My::ZooKeeper::Stat');
|
|
is(ref($stat), 'My::ZooKeeper::Stat',
|
|
'bless(): reblessed stat handle');
|
|
|
|
eval {
|
|
$stat->EXISTS(1);
|
|
};
|
|
like($@, qr/Can't locate object method "EXISTS" via package "My::ZooKeeper::Stat"/,
|
|
'stat EXISTS(): not defined on reblessed stat handle');
|
|
|
|
$attr = tied(%{$stat});
|
|
|
|
$ret = $attr->DESTROY();
|
|
ok($ret,
|
|
'stat DESTROY(): destroyed inner hash of reblessed stat handle');
|
|
|
|
$ret = $attr->DESTROY();
|
|
ok(!$ret,
|
|
'stat DESTROY(): no action on destroyed inner hash of ' .
|
|
'reblessed stat handle');
|
|
|
|
undef $stat;
|
|
ok(!defined($stat),
|
|
'undef: released reblessed stat handle');
|
|
|
|
|
|
## DESTROY() on reblessed watch handle
|
|
|
|
bless($watch, 'My::ZooKeeper::Watch');
|
|
is(ref($watch), 'My::ZooKeeper::Watch',
|
|
'bless(): reblessed watch handle');
|
|
|
|
eval {
|
|
$watch->EXISTS(1);
|
|
};
|
|
like($@, qr/Can't locate object method "EXISTS" via package "My::ZooKeeper::Watch"/,
|
|
'watch EXISTS(): not defined on reblessed watch handle');
|
|
|
|
$attr = tied(%{$watch});
|
|
|
|
$ret = $attr->DESTROY();
|
|
ok($ret,
|
|
'watch DESTROY(): destroyed inner hash of reblessed watch handle');
|
|
|
|
$ret = $attr->DESTROY();
|
|
ok(!$ret,
|
|
'watch DESTROY(): no action on destroyed inner hash of ' .
|
|
'reblessed watch handle');
|
|
|
|
undef $watch;
|
|
ok(!defined($watch),
|
|
'undef: released reblessed watch handle');
|
|
}
|
|
|
|
SKIP: {
|
|
my $zkh = Net::ZooKeeper->new($hosts);
|
|
|
|
skip 'no valid handle', 9 unless (defined($zkh));
|
|
|
|
my $stat = $zkh->stat();
|
|
my $watch = $zkh->watch();
|
|
|
|
|
|
## UNTIE() on reblessed handle
|
|
|
|
bless($zkh, 'My::ZooKeeper');
|
|
is(ref($zkh), 'My::ZooKeeper',
|
|
'bless(): reblessed handle');
|
|
|
|
eval {
|
|
untie(%{$zkh});
|
|
};
|
|
like($@, qr/untying hashes of class Net::ZooKeeper not supported/,
|
|
'untie(): untying hashes from reblessed handle not supported');
|
|
|
|
my $attr = tied(%{$zkh});
|
|
|
|
eval {
|
|
$attr->UNTIE(0);
|
|
};
|
|
like($@, qr/untying hashes of class Net::ZooKeeper not supported/,
|
|
'UNTIE(): untying hashes from reblessed handle not supported');
|
|
|
|
|
|
## UNTIE() on reblessed stat handle
|
|
|
|
bless($stat, 'My::ZooKeeper::Stat');
|
|
is(ref($stat), 'My::ZooKeeper::Stat',
|
|
'bless(): reblessed stat handle');
|
|
|
|
eval {
|
|
untie(%{$stat});
|
|
};
|
|
like($@, qr/untying hashes of class Net::ZooKeeper::Stat not supported/,
|
|
'untie(): untying hashes from reblessed stat handle not supported');
|
|
|
|
$attr = tied(%{$stat});
|
|
|
|
eval {
|
|
$attr->UNTIE(0);
|
|
};
|
|
like($@, qr/untying hashes of class Net::ZooKeeper::Stat not supported/,
|
|
'stat UNTIE(): untying hashes from reblessed stat handle ' .
|
|
'not supported');
|
|
|
|
|
|
## UNTIE() on reblessed watch handle
|
|
|
|
bless($watch, 'My::ZooKeeper::Watch');
|
|
is(ref($watch), 'My::ZooKeeper::Watch',
|
|
'bless(): reblessed watch handle');
|
|
|
|
eval {
|
|
untie(%{$watch});
|
|
};
|
|
like($@, qr/untying hashes of class Net::ZooKeeper::Watch not supported/,
|
|
'untie(): untying hashes from reblessed watch handle not supported');
|
|
|
|
$attr = tied(%{$watch});
|
|
|
|
eval {
|
|
$attr->UNTIE(0);
|
|
};
|
|
like($@, qr/untying hashes of class Net::ZooKeeper::Watch not supported/,
|
|
'watch UNTIE(): untying hashes from reblessed watch handle ' .
|
|
'not supported');
|
|
}
|
|
|
|
|
|
package Net::ZooKeeper::Test;
|
|
|
|
use Net::ZooKeeper qw(:acls);
|
|
|
|
our @ISA = qw(Net::ZooKeeper);
|
|
|
|
sub create
|
|
{
|
|
my($self, $path, $buf) = @_;
|
|
|
|
return $self->SUPER::create($path, $buf,
|
|
'path_read_len' => length($path),
|
|
'acl' => ZOO_OPEN_ACL_UNSAFE);
|
|
}
|
|
|
|
sub get_first_child
|
|
{
|
|
my($self, $path) = @_;
|
|
|
|
my @child_paths = $self->get_children($path);
|
|
|
|
if (@child_paths > 0) {
|
|
return $path . (($path =~ /\/$/) ? '' : '/') . $child_paths[0];
|
|
}
|
|
|
|
return undef;
|
|
}
|
|
|
|
sub stat
|
|
{
|
|
my $self = shift;
|
|
|
|
my $stat = $self->SUPER::stat();
|
|
|
|
return bless($stat, 'Net::ZooKeeper::Test::Stat');
|
|
}
|
|
|
|
|
|
sub watch
|
|
{
|
|
my $self = shift;
|
|
|
|
my $watch = $self->SUPER::watch();
|
|
|
|
return bless($watch, 'Net::ZooKeeper::Test::Watch');
|
|
}
|
|
|
|
|
|
package Net::ZooKeeper::Test::Stat;
|
|
|
|
our @ISA = qw(Net::ZooKeeper::Stat);
|
|
|
|
sub get_ctime
|
|
{
|
|
my $self = shift;
|
|
|
|
return $self->{'ctime'};
|
|
}
|
|
|
|
|
|
package Net::ZooKeeper::Test::Watch;
|
|
|
|
our @ISA = qw(Net::ZooKeeper::Watch);
|
|
|
|
sub get_timeout
|
|
{
|
|
my $self = shift;
|
|
|
|
return $self->{'timeout'};
|
|
}
|
|
|
|
|
|
package main;
|
|
|
|
my $sub_zkh = Net::ZooKeeper::Test->new($hosts);
|
|
isa_ok($sub_zkh, 'Net::ZooKeeper::Test',
|
|
'new(): created subclassed handle');
|
|
|
|
SKIP: {
|
|
skip 'no valid subclassed handle', 21 unless (defined($sub_zkh));
|
|
|
|
is($sub_zkh->{'data_read_len'}, 1023,
|
|
'FETCH(): default data read length using subclassed handle');
|
|
|
|
my $path;
|
|
|
|
SKIP: {
|
|
my $ret = $sub_zkh->exists($root_path);
|
|
|
|
skip 'no connection to ZooKeeper', 1 unless
|
|
(defined($ret) and $ret);
|
|
|
|
$path = $sub_zkh->create($node_path, 'foo',
|
|
'acl' => ZOO_OPEN_ACL_UNSAFE);
|
|
is($path, $node_path,
|
|
'create(): created node with subclassed handle');
|
|
}
|
|
|
|
SKIP: {
|
|
skip 'no connection to ZooKeeper', 1 unless
|
|
(defined($path) and $path eq $node_path);
|
|
|
|
my $child_path = $sub_zkh->get_first_child($root_path);
|
|
is($child_path, $node_path,
|
|
'get_first_child(): retrieved first child with subclassed handle');
|
|
}
|
|
|
|
my $sub_stat = $sub_zkh->stat();
|
|
isa_ok($sub_stat, 'Net::ZooKeeper::Test::Stat',
|
|
'stat(): created subclassed stat handle');
|
|
|
|
SKIP: {
|
|
skip 'no valid subclassed stat handle', 6 unless
|
|
(defined($sub_stat));
|
|
|
|
is($sub_stat->{'ctime'}, 0,
|
|
'stat FETCH(): default ctime using subclassed stat handle');
|
|
|
|
SKIP: {
|
|
my $ret = $sub_zkh->exists($node_path, 'stat' => $sub_stat) if
|
|
(defined($path) and $path eq $node_path);
|
|
|
|
skip 'no connection to ZooKeeper', 2 unless
|
|
(defined($ret) and $ret);
|
|
|
|
my $ctime = $sub_stat->get_ctime();
|
|
ok($ctime > 0,
|
|
'get_ctime(): retrieved ctime with subclassed stat handle');
|
|
|
|
is($sub_stat->{'ctime'}, $ctime,
|
|
'stat FETCH(): ctime using subclassed stat handle');
|
|
}
|
|
|
|
my $ret = $sub_stat->DESTROY();
|
|
ok($ret,
|
|
'stat DESTROY(): destroyed subclassed stat handle');
|
|
|
|
$ret = $sub_stat->DESTROY();
|
|
ok(!$ret,
|
|
'stat DESTROY(): no action on destroyed subclassed stat handle');
|
|
|
|
undef $sub_stat;
|
|
ok(!defined($sub_stat),
|
|
'undef: released subclassed stat handle');
|
|
}
|
|
|
|
my $sub_watch = $sub_zkh->watch();
|
|
isa_ok($sub_watch, 'Net::ZooKeeper::Test::Watch',
|
|
'watch(): created subclassed watch handle');
|
|
|
|
SKIP: {
|
|
skip 'no valid subclassed watch handle', 6 unless
|
|
(defined($sub_watch));
|
|
|
|
SKIP: {
|
|
my $ret = $sub_zkh->exists($root_path, 'watch' => $sub_watch);
|
|
|
|
skip 'no connection to ZooKeeper', 3 unless
|
|
(defined($ret) and $ret);
|
|
|
|
$sub_watch->{'timeout'} = 50;
|
|
|
|
is($sub_watch->get_timeout(), 50,
|
|
'get_timeout(): retrieved timeout with subclassed ' .
|
|
'watch handle');
|
|
|
|
is($sub_watch->{'timeout'}, 50,
|
|
'watch FETCH(): timeout using subclassed stat handle');
|
|
|
|
$ret = $sub_watch->wait();
|
|
ok(!$ret,
|
|
'wait(): watch after checking node existence timed out with ' .
|
|
'subclassed watch handle');
|
|
}
|
|
|
|
my $ret = $sub_watch->DESTROY();
|
|
ok($ret,
|
|
'watch DESTROY(): destroyed subclassed watch handle');
|
|
|
|
$ret = $sub_watch->DESTROY();
|
|
ok(!$ret,
|
|
'watch DESTROY(): no action on destroyed subclassed watch handle');
|
|
|
|
undef $sub_watch;
|
|
ok(!defined($sub_watch),
|
|
'undef: released subclassed watch handle');
|
|
}
|
|
|
|
SKIP: {
|
|
skip 'no connection to ZooKeeper', 1 unless
|
|
(defined($path) and $path eq $node_path);
|
|
|
|
my $ret = $sub_zkh->delete($node_path);
|
|
ok($ret,
|
|
'delete(): deleted node with subclassed handle');
|
|
}
|
|
|
|
my $ret = $sub_zkh->DESTROY();
|
|
ok($ret,
|
|
'DESTROY(): destroyed subclassed handle');
|
|
|
|
$ret = $sub_zkh->DESTROY();
|
|
ok(!$ret,
|
|
'DESTROY(): no action on destroyed subclassed handle');
|
|
|
|
undef $sub_zkh;
|
|
ok(!defined($sub_zkh),
|
|
'undef: released subclassed handle');
|
|
}
|
|
|