EV-ClickHouse
view release on metacpan or search on metacpan
t/28_pass2_coverage.t view on Meta::CPAN
# reset() called from a query-timeout error callback and from a cancel
# error callback both survive the surrounding teardown (the same
# connect_gen guard mechanism that protects the on_error path).
# 12a. reset() from inside a query-timeout callback.
{
my $tries = 0;
my $ok;
my $ch; $ch = EV::ClickHouse->new(
host => $host, port => $nport, protocol => 'native',
on_connect => sub {
return if $tries;
$ch->query("select sleep(2)", { query_timeout => 0.1 }, sub {
my (undef, $err) = @_;
return if $tries++;
# On timeout, reset and re-issue a real query â the new
# socket must survive the outer cleanup_connection.
$ch->reset;
$ch->query("select 1", sub {
my ($r) = @_;
$ok = $r && @$r ? $r->[0][0] == 1 : 0;
EV::break;
});
});
},
on_error => sub { },
);
run_with_timeout(5);
ok $ok, '$ch->reset from query-timeout cb survives outer teardown';
$ch->finish if $ch->is_connected;
}
# 12b. reset() from inside a query callback that received a cancel error.
{
my $tries = 0;
my $ok;
my $ch; $ch = EV::ClickHouse->new(
host => $host, port => $nport, protocol => 'native',
on_connect => sub {
return if $tries;
$ch->query("select sleep(2)", sub {
my (undef, $err) = @_;
return if $tries++;
$ch->reset;
$ch->query("select 2", sub {
my ($r) = @_;
$ok = $r && @$r ? $r->[0][0] == 2 : 0;
EV::break;
});
});
EV::timer(0.1, 0, sub { $ch->cancel });
},
on_error => sub { },
);
run_with_timeout(5);
ok $ok, '$ch->reset from cancel cb survives outer teardown';
$ch->finish if $ch->is_connected;
}
# Regression: Pool::_pick prefers any idle member over a busy one
# (regression: the previous logic round-robined whenever ANY member was
# idle, which could route the next pick to a busy connection).
{
my $pool = EV::ClickHouse::Pool->new(
host => $host, port => $nport, protocol => 'native',
size => 3,
);
my @c = $pool->conns;
# Wait for all to connect.
my $cn = 0;
$_->ping(sub { $cn++ }) for @c;
my $w = EV::timer(0, 0.05, sub { EV::break if $cn >= 3 });
run_with_timeout(5);
undef $w;
# Force c[0] busy with a long sleep, leave c[1], c[2] idle.
$c[0]->query("select sleep(2)", sub { });
# Now _pick should NEVER return c[0] while it's busy.
my %picks;
$picks{ "$_" }++ for map { $pool->_pick } 1 .. 6;
ok !exists $picks{"$c[0]"},
'Pool::_pick avoids the busy member when others are idle';
eval { $c[0]->cancel };
eval { $pool->finish };
}
# Coverage: reconnect_jitter accepted, insert_streamer named-rows.
# 13. reconnect_jitter is accepted as a constructor option without croaking,
# and a fully-disabled value (0) keeps backoff deterministic.
{
my $ok;
my $ch; $ch = EV::ClickHouse->new(
host => $host, port => $nport, protocol => 'native',
reconnect_delay => 0.1,
reconnect_jitter => 0.5,
on_connect => sub { $ok = 1; EV::break },
);
run_with_timeout(5);
ok $ok, 'reconnect_jitter accepted without breaking connect';
$ch->finish;
}
# 14. insert_streamer columns => [...] reorders hash rows positionally.
{
my $err;
my $ch; $ch = EV::ClickHouse->new(
host => $host, port => $nport, protocol => 'native',
on_connect => sub {
$ch->query("create temporary table _named28 (a UInt32, b String) engine = Memory", sub {
my $s = $ch->insert_streamer('_named28',
columns => [qw(a b)],
batch_size => 10,
);
# mix hashref + arrayref pushes; column order in hash is
# deliberately not the table order.
$s->push_row({ b => 'x', a => 1 });
$s->push_row({ a => 2, b => 'y' });
$s->push_row([3, 'z']);
$s->finish(sub {
(undef, $err) = @_;
EV::break;
});
});
},
on_error => sub { $err = $_[0]; EV::break },
);
run_with_timeout(5);
is $err, undef, 'insert_streamer columns => [...] reorders hash rows';
# And verify the rows landed in the right columns.
my $ch2; $ch2 = EV::ClickHouse->new(
host => $host, port => $nport, protocol => 'native',
on_connect => sub {
$ch->query("select a, b from _named28 order by a format TabSeparated", sub {
my ($rows) = @_;
is_deeply $rows, [[1, 'x'], [2, 'y'], [3, 'z']],
' rows landed in declared column order';
EV::break;
});
},
);
( run in 0.424 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )