sub
setup_client :Test(startup)
{
my
$self
=
shift
;
$self
->mock_init();
my
%options
= (%{
$self
->common_options});
my
$o
= Couchbase::Bucket->new(\
%options
);
$self
->cbo(
$o
);
$self
->{basic_keys} = [
qw(
Foo Bar Baz Blargh Bleh Meh Grr Gah)
];
}
sub
cbo {
if
(
@_
== 1) {
return
$_
[0]->{object};
}
elsif
(
@_
== 2) {
$_
[0]->{object} =
$_
[1];
return
$_
[1];
}
}
sub
k2v {
my
(
$self
,
$k
) =
@_
;
reverse
(
$k
);
}
sub
v2k {
my
(
$self
,
$v
) =
@_
;
reverse
(
$v
);
}
sub
set_ok {
my
(
$self
,
$msg
,
@args
) =
@_
;
my
$doc
= Couchbase::Document->new(
@args
);
$self
->cbo->upsert(
$doc
);
ok(
$doc
->is_ok,
$msg
);
if
(!
$doc
->is_ok) {
diag(
$doc
->errstr);
}
}
sub
get_ok {
my
(
$self
,
$key
,
$expected
) =
@_
;
my
$doc
= Couchbase::Document->new(
$key
);
$self
->cbo->get(
$doc
);
ok(
$doc
->is_ok,
"Status OK for GET($key)"
);
ok(
$doc
->value eq
$expected
,
"Got expected value for $key"
);
}
sub
T00_set_values_simple :Test(no_plan) {
my
$self
=
shift
;
foreach
my
$k
(@{
$self
->{basic_keys}}) {
$self
->set_ok(
"Key '$k'"
,
$k
,
$self
->k2v(
$k
));
$self
->get_ok(
$k
,
$self
->k2v(
$k
))
}
}
sub
T01_get_nonexistent :Test(no_plan) {
my
$self
=
shift
;
my
$doc
= Couchbase::Document->new(
'NonExistent'
);
$self
->cbo->get(
$doc
);
is(
$doc
->errnum, COUCHBASE_KEY_ENOENT,
"Got ENOENT for nonexistent key"
);
}
sub
T02_mutators :Test(no_plan) {
my
$self
=
shift
;
my
$o
=
$self
->cbo;
my
$doc
= Couchbase::Document->new(
"mutate_key"
,
"BASE"
);
$o
->remove(
$doc
);
$doc
->
format
(
'utf8'
);
ok(
$o
->insert(
$doc
));
ok(
$o
->prepend_bytes(
$doc
, {
fragment
=>
"PREFIX_"
}));
ok(
$o
->append_bytes(
$doc
, {
fragment
=>
"_SUFFIX"
}));
ok(
$o
->get(
$doc
));
is(
$doc
->value,
"PREFIX_BASE_SUFFIX"
,
"Got expected mutated value"
);
}
sub
T03_arithmetic :Test(no_plan) {
my
$self
=
shift
;
my
$o
=
$self
->cbo;
my
$doc
= Couchbase::Document->new(
"ArithmeticKey"
);
$o
->remove(
$doc
);
ok(
$o
->counter(
$doc
, {
delta
=> -12,
initial
=> 42 }),
"Set with initial value"
);
is(42,
$doc
->value);
$o
->counter(
$doc
, {
delta
=> -12,
initial
=> 42 });
is(30,
$doc
->value);
$o
->remove(
$doc
);
$o
->counter(
$doc
, {
delta
=> -12 });
ok(
$doc
->is_not_found,
"Not found error without initial"
);
ok (
$o
->counter(
$doc
, {
delta
=> -12,
initial
=> 0 }),
"Initial=0 works"
);
is(0,
$doc
->value);
ok (
$o
->counter(
$doc
, {
delta
=> 1 }));
is(1,
$doc
->value);
}
sub
T04_atomic :Test(no_plan) {
my
$self
=
shift
;
my
$o
=
$self
->cbo;
my
$doc
= Couchbase::Document->new(
"AtomicKey"
,
"SOMEVALUE"
);
$o
->remove(
$doc
);
$o
->replace(
$doc
);
ok(
$doc
->is_not_found,
"Can't replace missing document"
);
ok(
$o
->insert(
$doc
),
"Insert works on non-existent doc"
);
ok(
length
(
$doc
->_cas),
"Have a CAS"
);
my
$doc2
=
$doc
->copy();
$doc2
->_cas(0xdeadbeef);
$o
->replace(
$doc2
);
ok(
$doc2
->is_cas_mismatch,
"Got mismatch on bad CAS"
);
ok(
length
(
$doc2
->_cas),
"Still have CAS"
);
ok(
$o
->replace(
$doc2
, {
ignore_cas
=> 1}),
"Ignore cas works"
);
$o
->insert(
$doc2
);
ok(
$doc2
->is_already_exists,
"EEXISTS on insert existing"
);
my
$gdoc
= Couchbase::Document->new(
$doc
->id);
ok(
$o
->get(
$gdoc
));
ok(
length
(
$gdoc
->_cas));
my
$newv
=
$gdoc
->value .
$gdoc
->value;
$gdoc
->value(
$newv
);
ok(
$o
->replace(
$gdoc
));
$o
->get(
$doc2
);
is(
$gdoc
->value,
$doc2
->value);
$doc2
->_cas(0xCAFEBABE);
ok(!
$o
->remove(
$doc2
));
ok(
$doc2
->is_cas_mismatch);
ok(
$o
->remove(
$doc2
, {
ignore_cas
=> 1}));
}
sub
T05_conversion :Test(no_plan) {
my
$self
=
shift
;
my
$o
=
$self
->cbo;
my
$structure
= [
qw(foo bar baz)
];
my
$doc
= Couchbase::Document->new(
"Serialization"
,
$structure
);
ok(
$o
->upsert(
$doc
),
"Serialized OK"
);
ok(
$o
->get(
$doc
),
"Deserialized OK"
);
is_deeply(
$doc
->value,
$structure
,
"Got back our array"
);
eval
{
$o
->append_bytes(
$doc
, {
fragment
=>
$structure
}) };
ok($@,
"Got error for append/prepending a serialized structure ($@)"
);
eval
{
$o
->append_bytes(
$doc
, {
fragment
=>
"foo bar baz"
}) };
ok($@,
"Got error for append without proper format set ($@)"
);
$doc
->
format
(
'utf8'
);
ok(
$o
->append_bytes(
$doc
, {
fragment
=>
"foo bar baz"
}));
}
sub
multi_ok {
my
(
$rv
,
$msg
,
$expect
) =
@_
;
my
@errs
;
if
(
$expect
) {
@errs
=
grep
{
$_
->errnum !=
$expect
}
@$rv
;
}
else
{
@errs
=
grep
{ !
$_
->is_ok }
@$rv
;
}
ok(!
@errs
,
$msg
);
}
sub
T06_multi :Test(no_plan) {
my
$self
=
shift
;
my
$o
=
$self
->cbo;
my
@docs
=
map
{Couchbase::Document->new(
$_
,
$_
)} @{
$self
->{basic_keys}};
my
$batch
=
$o
->batch();
map
{
$batch
->upsert(
$_
)}
@docs
;
$batch
->wait_all();
multi_ok(\
@docs
,
"Multi upsert OK"
);
$batch
=
$o
->batch();
map
{
$batch
->get(
$_
)}
@docs
;
$batch
->wait_all();
multi_ok(\
@docs
,
"Multi get OK"
);
is(
scalar
grep
(
$_
->value eq
$_
->id,
@docs
),
scalar
@docs
,
"get_multi: Got expected values"
);
$batch
=
$o
->batch();
map
{
$batch
->remove(
$_
)}
@docs
;
$batch
->wait_all();
multi_ok(\
@docs
,
"Multi remove OK"
);
}
sub
T07_stats :Test(no_plan) {
my
$self
=
shift
;
my
$o
=
$self
->cbo;
my
$rv
=
$o
->stats();
ok(
$rv
->is_ok);
my
$stats
=
$rv
->value;
ok(
$stats
&&
ref
$stats
eq
'HASH'
,
"Got a hashref"
);
ok(
scalar
keys
%$stats
,
"stats not empty"
);
if
(
$self
->mock &&
$self
->mock->nodes) {
ok(
scalar
keys
%$stats
==
$self
->mock->nodes,
"Got expected stat count"
);
}
else
{
diag
"Cannot determine expected stat count for real cluster"
;
}
}
sub
T08_iterator :Test(no_plan) {
my
$self
=
shift
;
my
$o
=
$self
->cbo;
my
@docs
=
map
{ Couchbase::Document->new(
"T08_NonExistent_$_"
) } (1..200);
my
$batch
=
$o
->batch;
map
{
$batch
->get(
$_
)}
@docs
;
my
%khash
= ();
while
((
my
$doc
=
$batch
->wait_one)) {
if
(
exists
$khash
{
$doc
->id}) {
fail(
"Document returned twice!"
);
}
if
(!
$doc
->is_not_found) {
fail(
"Expected NOT_FOUND"
);
}
$khash
{
$doc
->id} = 1;
}
is(200,
scalar
values
%khash
)
}
sub
T10_locks :Test(no_plan) {
my
$self
=
shift
;
my
$o
=
$self
->cbo;
my
$doc
= Couchbase::Document->new(
"GETL"
,
"value"
);
$o
->remove(
$doc
);
$o
->insert(
$doc
);
ok(
$o
->get_and_lock(
$doc
, {
lock_duration
=>10}),
"Locked OK"
);
ok(
$o
->unlock(
$doc
),
"Unlocked OK"
);
my
$doc2
=
$doc
->copy();
ok(
$o
->get_and_lock(
$doc2
, {
lock_duration
=>10}));
$doc
->_cas(0xdeadbeef);
ok((!
$o
->unlock(
$doc
)),
"Can't unlock with stale CAS"
);
ok(
$o
->unlock(
$doc2
),
"Unlock with good CAS ok"
);
eval
{
$o
->get_and_lock(
$doc
) };
ok($@,
"Can't lock without explicit duration"
);
eval
{
$o
->unlock(Couchbase::Document->new(
"dummy"
))};
ok($@,
"Can't unlock with no CAS"
);
$o
->get_and_lock(
$doc
, {
lock_duration
=>5});
ok(
$o
->upsert(
$doc
),
"Implicit unlock with CAS ok"
);
}
sub
wait_for_exp {
my
(
$o
,
$doc
,
$limit
) =
@_
;
my
$begin_time
=
time
();
while
(
time
() -
$begin_time
<
$limit
) {
sleep
(1);
$o
->get(
$doc
);
if
(
$doc
->errnum == COUCHBASE_KEY_ENOENT) {
return
1;
}
diag(
"Sleeping again.."
);
}
return
0;
}
sub
T11_expiry :Test(no_plan) {
my
$self
=
shift
;
my
$o
=
$self
->cbo;
my
$doc
= Couchbase::Document->new(
"exp_key"
,
"exp_val"
, {
expiry
=>1});
ok(
$o
->upsert(
$doc
),
"Inserted document with expiry"
);
ok(wait_for_exp(
$o
,
$doc
, 3),
"Document is no longer here (expired!)"
);
$doc
->expiry(
"bad-expiry"
);
eval
{
$o
->upsert(
$doc
) };
ok($@,
"Set with bad expiry raises error ($@)"
);
$doc
->expiry(-1);
eval
{
$o
->upsert(
$doc
) };
ok($@,
"Set with negative expiry raises error ($@)"
);
$doc
->expiry(1);
}
sub
T12_observe :Test(no_plan) {
my
$self
=
shift
;
my
$cb
=
$self
->cbo;
my
$doc
= Couchbase::Document->new(
"Hello"
,
"World"
);
$cb
->upsert(
$doc
);
my
$obsret
=
$cb
->observe(
$doc
);
my
@m
=
grep
{
$_
->{master} } @{
$obsret
->value};
ok(
$m
[0]);
is(
$cb
->get_bucket_config->nreplicas+1,
scalar
@{
$obsret
->value});
$obsret
=
$cb
->observe(
$doc
, {
master_only
=>1});
ok(
$obsret
->is_ok);
is(1,
scalar
@{
$obsret
->value});
ok(
$obsret
->value->[0]->{master});
}
1;