| # 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'); |
| } |
| |