|
Packit Service |
584ef9 |
#!/usr/bin/perl
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
use strict;
|
|
Packit Service |
584ef9 |
use warnings;
|
|
Packit Service |
584ef9 |
use Test::More;
|
|
Packit Service |
584ef9 |
use FindBin qw($Bin);
|
|
Packit Service |
584ef9 |
use lib "$Bin/lib";
|
|
Packit Service |
584ef9 |
use MemcachedTest;
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
my $server = new_memcached();
|
|
Packit Service |
584ef9 |
my $sock = $server->sock;
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# command syntax:
|
|
Packit Service |
584ef9 |
# mg [key] [flags] [tokens]\r\n
|
|
Packit Service |
584ef9 |
# response:
|
|
Packit Service |
584ef9 |
# VA [flags] [tokens]\r\n
|
|
Packit Service |
584ef9 |
# data\r\n
|
|
Packit Service |
584ef9 |
# EN\r\n
|
|
Packit Service |
584ef9 |
#
|
|
Packit Service |
584ef9 |
# flags:
|
|
Packit Service |
584ef9 |
# - s: item size
|
|
Packit Service |
584ef9 |
# - v: return item value
|
|
Packit Service |
584ef9 |
# - c: return item cas
|
|
Packit Service |
584ef9 |
# - t: return item TTL remaining (-1 for unlimited)
|
|
Packit Service |
584ef9 |
# - f: client flags
|
|
Packit Service |
584ef9 |
# - l: last access time
|
|
Packit Service |
584ef9 |
# - h: whether item has been hit before
|
|
Packit Service |
584ef9 |
# - O: opaque to copy back.
|
|
Packit Service |
584ef9 |
# - k: return key
|
|
Packit Service |
584ef9 |
# - q: noreply semantics.
|
|
Packit Service |
584ef9 |
# - u: don't bump the item
|
|
Packit Service |
584ef9 |
# updaters:
|
|
Packit Service |
584ef9 |
# - N (token): vivify on miss, takes TTL as a argument
|
|
Packit Service |
584ef9 |
# - R (token): if token is less than item TTL win for recache
|
|
Packit Service |
584ef9 |
# - T (token): update remaining TTL
|
|
Packit Service |
584ef9 |
# FIXME: do I need a "if stale and no token sent, flip" explicit flag?
|
|
Packit Service |
584ef9 |
# extra response flags:
|
|
Packit Service |
584ef9 |
# - W: client has "won" the token
|
|
Packit Service |
584ef9 |
# - X: object is stale
|
|
Packit Service |
584ef9 |
# - Z: object has sent a winning token
|
|
Packit Service |
584ef9 |
#
|
|
Packit Service |
584ef9 |
# ms [key] [flags] [tokens]\r\n
|
|
Packit Service |
584ef9 |
# value\r\n
|
|
Packit Service |
584ef9 |
# response:
|
|
Packit Service |
584ef9 |
# ST [flags] [tokens]\r\n
|
|
Packit Service |
584ef9 |
# ST STORED, NS NOT_STORED, EX EXISTS, NF NOT_FOUND
|
|
Packit Service |
584ef9 |
#
|
|
Packit Service |
584ef9 |
# flags:
|
|
Packit Service |
584ef9 |
# - q: noreply
|
|
Packit Service |
584ef9 |
# - F (token): set client flags
|
|
Packit Service |
584ef9 |
# - C (token): compare CAS value
|
|
Packit Service |
584ef9 |
# - S (token): item size
|
|
Packit Service |
584ef9 |
# - T (token): TTL
|
|
Packit Service |
584ef9 |
# - O: opaque to copy back.
|
|
Packit Service |
584ef9 |
# - k: return key
|
|
Packit Service |
584ef9 |
# - I: invalid. set-to-invalid if CAS is older than it should be.
|
|
Packit Service |
584ef9 |
# Not implemented:
|
|
Packit Service |
584ef9 |
# - E: add if not exists (influences other options)
|
|
Packit Service |
584ef9 |
# - A: append (exclusive)
|
|
Packit Service |
584ef9 |
# - P: prepend (exclusive)
|
|
Packit Service |
584ef9 |
# - L: replace (exclusive)
|
|
Packit Service |
584ef9 |
# - incr/decr? pushing it, I guess.
|
|
Packit Service |
584ef9 |
#
|
|
Packit Service |
584ef9 |
# md [key] [flags] [tokens]\r\n
|
|
Packit Service |
584ef9 |
# response:
|
|
Packit Service |
584ef9 |
# DE [flags] [tokens]
|
|
Packit Service |
584ef9 |
# flags:
|
|
Packit Service |
584ef9 |
# - q: noreply
|
|
Packit Service |
584ef9 |
# - T (token): updates TTL
|
|
Packit Service |
584ef9 |
# - C (token): compare CAS value
|
|
Packit Service |
584ef9 |
# - I: invalidate. mark as stale, bumps CAS.
|
|
Packit Service |
584ef9 |
# - O: opaque to copy back.
|
|
Packit Service |
584ef9 |
# - k: return key
|
|
Packit Service |
584ef9 |
#
|
|
Packit Service |
584ef9 |
# mn\r\n
|
|
Packit Service |
584ef9 |
# response:
|
|
Packit Service |
584ef9 |
# EN
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# metaget tests
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# basic test
|
|
Packit Service |
584ef9 |
# - raw mget
|
|
Packit Service |
584ef9 |
# - raw mget miss
|
|
Packit Service |
584ef9 |
# - raw mget bad key
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
{
|
|
Packit Service |
584ef9 |
print $sock "set foo 0 0 2\r\nhi\r\n";
|
|
Packit Service |
584ef9 |
is(scalar <$sock>, "STORED\r\n", "stored test value");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
print $sock "me none\r\n";
|
|
Packit Service |
584ef9 |
is(scalar <$sock>, "EN\r\n", "raw mget miss");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
print $sock "me foo\r\n";
|
|
Packit Service |
584ef9 |
like(scalar <$sock>, qr/^ME foo /, "raw mget result");
|
|
Packit Service |
584ef9 |
# bleed the EN off the socket.
|
|
Packit Service |
584ef9 |
my $dud = scalar <$sock>;
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# mget with arguments
|
|
Packit Service |
584ef9 |
# - set some specific TTL and get it back (within reason)
|
|
Packit Service |
584ef9 |
# - get cas
|
|
Packit Service |
584ef9 |
# - autovivify and bit-win
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
{
|
|
Packit Service |
584ef9 |
print $sock "set foo2 0 90 2\r\nho\r\n";
|
|
Packit Service |
584ef9 |
is(scalar <$sock>, "STORED\r\n", "stored test value");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
mget_is({ sock => $sock,
|
|
Packit Service |
584ef9 |
flags => 'sv',
|
|
Packit Service |
584ef9 |
etokens => [2] },
|
|
Packit Service |
584ef9 |
'foo2', 'ho', "retrieved test value");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
my $res = mget($sock, 'foo2', 'stv');
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# lease-test, use two sockets? one socket should be fine, actually.
|
|
Packit Service |
584ef9 |
# - get a win on autovivify
|
|
Packit Service |
584ef9 |
# - get a loss on the same command
|
|
Packit Service |
584ef9 |
# - have a set/cas fail
|
|
Packit Service |
584ef9 |
# - have a cas succeed
|
|
Packit Service |
584ef9 |
# - repeat for "triggered on TTL"
|
|
Packit Service |
584ef9 |
# - test just modifying the TTL (touch)
|
|
Packit Service |
584ef9 |
# - test fetching without value
|
|
Packit Service |
584ef9 |
{
|
|
Packit Service |
584ef9 |
my $res = mget($sock, 'needwin', 'scvNt 30');
|
|
Packit Service |
584ef9 |
like($res->{flags}, qr/scvNt/, "got main flags back");
|
|
Packit Service |
584ef9 |
like($res->{flags}, qr/W/, "got a win result");
|
|
Packit Service |
584ef9 |
unlike($res->{flags}, qr/Z/, "no token already sent warning");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# asked for size and TTL. size should be 0, TTL should be > 0 and < 30
|
|
Packit Service |
584ef9 |
is($res->{tokens}->[0], 0, "got zero size: autovivified response");
|
|
Packit Service |
584ef9 |
my $ttl = $res->{tokens}->[1];
|
|
Packit Service |
584ef9 |
ok($ttl > 0 && $ttl <= 30, "auto TTL is within requested window");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# try to fail this time.
|
|
Packit Service |
584ef9 |
{
|
|
Packit Service |
584ef9 |
my $res = mget($sock, 'needwin', 'stcvN 30');
|
|
Packit Service |
584ef9 |
ok(keys %$res, "got a non-empty response");
|
|
Packit Service |
584ef9 |
unlike($res->{flags}, qr/W/, "not a win result");
|
|
Packit Service |
584ef9 |
like($res->{flags}, qr/Z/, "object already sent win result");
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# set back with the wrong CAS
|
|
Packit Service |
584ef9 |
print $sock "ms needwin CST 5000 2 120\r\nnu\r\n";
|
|
Packit Service |
584ef9 |
like(scalar <$sock>, qr/^EX /, "failed to SET: CAS didn't match");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# again, but succeed.
|
|
Packit Service |
584ef9 |
# TODO: the actual CAS command should work here too?
|
|
Packit Service |
584ef9 |
my $cas = $res->{tokens}->[1];
|
|
Packit Service |
584ef9 |
print $sock "ms needwin CST $cas 2 120\r\nmu\r\n";
|
|
Packit Service |
584ef9 |
like(scalar <$sock>, qr/^ST /, "SET: CAS matched");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# now we repeat the original mget, but the data should be different.
|
|
Packit Service |
584ef9 |
$res = mget($sock, 'needwin', 'sktcvN 30');
|
|
Packit Service |
584ef9 |
ok(keys %$res, "not a miss");
|
|
Packit Service |
584ef9 |
like($res->{flags}, qr/sktcvN/, "got main flags back");
|
|
Packit Service |
584ef9 |
unlike($res->{flags}, qr/[WZ]/, "not a win or token result");
|
|
Packit Service |
584ef9 |
is($res->{tokens}->[1], 'needwin', "key matches");
|
|
Packit Service |
584ef9 |
$ttl = $res->{tokens}->[2];
|
|
Packit Service |
584ef9 |
ok($ttl > 100 && $ttl <= 120, "TTL is within requested window: $ttl");
|
|
Packit Service |
584ef9 |
is($res->{val}, "mu", "value matches");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# now we do the whole routine again, but for "triggered on TTL being low"
|
|
Packit Service |
584ef9 |
# TTL was set to 120 just now, so anything lower than this should trigger.
|
|
Packit Service |
584ef9 |
$res = mget($sock, 'needwin', 'stcvNR 30 130');
|
|
Packit Service |
584ef9 |
like($res->{flags}, qr/stcvNR/, "got main flags back");
|
|
Packit Service |
584ef9 |
like($res->{flags}, qr/W/, "got a win result");
|
|
Packit Service |
584ef9 |
unlike($res->{flags}, qr/Z/, "no token already sent warning");
|
|
Packit Service |
584ef9 |
is($res->{val}, "mu", "value matches");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# try to fail this time.
|
|
Packit Service |
584ef9 |
{
|
|
Packit Service |
584ef9 |
my $res = mget($sock, 'needwin', 'stcvNR 30 130');
|
|
Packit Service |
584ef9 |
ok(keys %$res, "got a non-empty response");
|
|
Packit Service |
584ef9 |
unlike($res->{flags}, qr/W/, "not a win result");
|
|
Packit Service |
584ef9 |
like($res->{flags}, qr/Z/, "object already sent win result");
|
|
Packit Service |
584ef9 |
is($res->{val}, "mu", "value matches");
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# again, but succeed.
|
|
Packit Service |
584ef9 |
$cas = $res->{tokens}->[2];
|
|
Packit Service |
584ef9 |
print $sock "ms needwin CST $cas 4 300\r\nzuuu\r\n";
|
|
Packit Service |
584ef9 |
like(scalar <$sock>, qr/^ST /, "SET: CAS matched");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# now we repeat the original mget, but the data should be different.
|
|
Packit Service |
584ef9 |
$res = mget($sock, 'needwin', 'stcvN 30');
|
|
Packit Service |
584ef9 |
ok(keys %$res, "not a miss");
|
|
Packit Service |
584ef9 |
like($res->{flags}, qr/stcvN/, "got main flags back");
|
|
Packit Service |
584ef9 |
unlike($res->{flags}, qr/[WZ]/, "not a win or token result");
|
|
Packit Service |
584ef9 |
$ttl = $res->{tokens}->[1];
|
|
Packit Service |
584ef9 |
ok($ttl > 250 && $ttl <= 300, "TTL is within requested window");
|
|
Packit Service |
584ef9 |
ok($res->{tokens}->[0] == 4, "Size returned correctly");
|
|
Packit Service |
584ef9 |
is($res->{val}, "zuuu", "value matches: " . $res->{val});
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# test get-and-touch mode
|
|
Packit Service |
584ef9 |
{
|
|
Packit Service |
584ef9 |
# Set key with lower initial TTL.
|
|
Packit Service |
584ef9 |
print $sock "ms gatkey ST 4 100\r\nooom\r\n";
|
|
Packit Service |
584ef9 |
like(scalar <$sock>, qr/^ST /, "set gatkey");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# Coolish side feature and/or bringer of bugs: 't' before 'T' gives TTL
|
|
Packit Service |
584ef9 |
# before adjustment. 'T' before 't' gives TTL after adjustment.
|
|
Packit Service |
584ef9 |
# Here we want 'T' before 't' to ensure we did adjust the value.
|
|
Packit Service |
584ef9 |
my $res = mget($sock, 'gatkey', 'svTt 300');
|
|
Packit Service |
584ef9 |
ok(keys %$res, "not a miss");
|
|
Packit Service |
584ef9 |
unlike($res->{flags}, qr/[WZ]/, "not a win or token result");
|
|
Packit Service |
584ef9 |
my $ttl = $res->{tokens}->[1];
|
|
Packit Service |
584ef9 |
ok($ttl > 280 && $ttl <= 300, "TTL is within requested window: $ttl");
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# test no-value mode
|
|
Packit Service |
584ef9 |
{
|
|
Packit Service |
584ef9 |
# Set key with lower initial TTL.
|
|
Packit Service |
584ef9 |
print $sock "ms hidevalue ST 4 100\r\nhide\r\n";
|
|
Packit Service |
584ef9 |
like(scalar <$sock>, qr/^ST /, "set hidevalue");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
my $res = mget($sock, 'hidevalue', 'st');
|
|
Packit Service |
584ef9 |
ok(keys %$res, "not a miss");
|
|
Packit Service |
584ef9 |
is($res->{val}, '', "no value returned");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
$res = mget($sock, 'hidevalue', 'stv');
|
|
Packit Service |
584ef9 |
ok(keys %$res, "not a miss");
|
|
Packit Service |
584ef9 |
is($res->{val}, 'hide', "real value returned");
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# test hit-before? flag
|
|
Packit Service |
584ef9 |
{
|
|
Packit Service |
584ef9 |
print $sock "ms hitflag ST 3 100\r\nhit\r\n";
|
|
Packit Service |
584ef9 |
like(scalar <$sock>, qr/^ST /, "set hitflag");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
my $res = mget($sock, 'hitflag', 'sth');
|
|
Packit Service |
584ef9 |
ok(keys %$res, "not a miss");
|
|
Packit Service |
584ef9 |
is($res->{tokens}->[2], 0, "not been hit before");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
$res = mget($sock, 'hitflag', 'sth');
|
|
Packit Service |
584ef9 |
ok(keys %$res, "not a miss");
|
|
Packit Service |
584ef9 |
is($res->{tokens}->[2], 1, "been hit before");
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# test no-update flag
|
|
Packit Service |
584ef9 |
{
|
|
Packit Service |
584ef9 |
print $sock "ms noupdate ST 3 100\r\nhit\r\n";
|
|
Packit Service |
584ef9 |
like(scalar <$sock>, qr/^ST /, "set noupdate");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
my $res = mget($sock, 'noupdate', 'stuh');
|
|
Packit Service |
584ef9 |
ok(keys %$res, "not a miss");
|
|
Packit Service |
584ef9 |
is($res->{tokens}->[2], 0, "not been hit before");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# _next_ request should show a hit.
|
|
Packit Service |
584ef9 |
# gets modified here but returns previous state.
|
|
Packit Service |
584ef9 |
$res = mget($sock, 'noupdate', 'sth');
|
|
Packit Service |
584ef9 |
is($res->{tokens}->[2], 0, "still not a hit");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
$res = mget($sock, 'noupdate', 'stuh');
|
|
Packit Service |
584ef9 |
is($res->{tokens}->[2], 1, "finally a hit");
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# test last-access time
|
|
Packit Service |
584ef9 |
{
|
|
Packit Service |
584ef9 |
print $sock "ms la_test ST 2 100\r\nla\r\n";
|
|
Packit Service |
584ef9 |
like(scalar <$sock>, qr/^ST /, "set la_test");
|
|
Packit Service |
584ef9 |
sleep 2;
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
my $res = mget($sock, 'la_test', 'stl');
|
|
Packit Service |
584ef9 |
ok(keys %$res, "not a miss");
|
|
Packit Service |
584ef9 |
print STDERR "Last access is: ", $res->{tokens}->[2], "\n";
|
|
Packit Service |
584ef9 |
isnt($res->{tokens}->[2], 0, "been over a second since most recently accessed");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# TODO: Can't test re-accessing since it requires a long wait right now.
|
|
Packit Service |
584ef9 |
# I want to adjust the LA time accuracy in a deliberate change.
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# high level tests:
|
|
Packit Service |
584ef9 |
# - mget + mset with serve-stale
|
|
Packit Service |
584ef9 |
# - set a value
|
|
Packit Service |
584ef9 |
# - mget it back. should be no XZW tokens
|
|
Packit Service |
584ef9 |
# - invalidate via mdelete and mget/revalidate with mset
|
|
Packit Service |
584ef9 |
# - remember failure scenarios!
|
|
Packit Service |
584ef9 |
# - TTL timed out?
|
|
Packit Service |
584ef9 |
# - CAS too high?
|
|
Packit Service |
584ef9 |
# - also test re-setting as stale (CAS is below requested)
|
|
Packit Service |
584ef9 |
# - this should probably be conditional.
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
{
|
|
Packit Service |
584ef9 |
diag "starting serve stale with mdelete";
|
|
Packit Service |
584ef9 |
my ($ttl, $cas, $res);
|
|
Packit Service |
584ef9 |
print $sock "set toinv 0 0 3\r\nmoo\r\n";
|
|
Packit Service |
584ef9 |
is(scalar <$sock>, "STORED\r\n", "stored key 'toinv'");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
$res = mget($sock, 'toinv', 'sv');
|
|
Packit Service |
584ef9 |
unlike($res->{flags}, qr/[XWZ]/, "no extra flags");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# Lets mark the sucker as invalid, and drop its TTL to 30s
|
|
Packit Service |
584ef9 |
diag "running mdelete";
|
|
Packit Service |
584ef9 |
print $sock "md toinv IT 30\r\n";
|
|
Packit Service |
584ef9 |
like(scalar <$sock>, qr/^DE /, "mdelete'd key");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# TODO: decide on if we need an explicit flag for "if I fetched a stale
|
|
Packit Service |
584ef9 |
# value, does winning matter?
|
|
Packit Service |
584ef9 |
# I think it's probably fine. clients can always ignore the win, or we can
|
|
Packit Service |
584ef9 |
# add an option later to "don't try to revalidate if stale", perhaps.
|
|
Packit Service |
584ef9 |
$res = mget($sock, 'toinv', 'stcv');
|
|
Packit Service |
584ef9 |
ok(keys %$res, "not a miss");
|
|
Packit Service |
584ef9 |
like($res->{flags}, qr/stcv/, "got main flags back");
|
|
Packit Service |
584ef9 |
like($res->{flags}, qr/W/, "won the recache");
|
|
Packit Service |
584ef9 |
like($res->{flags}, qr/X/, "item is marked stale");
|
|
Packit Service |
584ef9 |
$ttl = $res->{tokens}->[1];
|
|
Packit Service |
584ef9 |
ok($ttl > 0 && $ttl <= 30, "TTL is within requested window");
|
|
Packit Service |
584ef9 |
ok($res->{tokens}->[0] == 3, "Size returned correctly");
|
|
Packit Service |
584ef9 |
is($res->{val}, "moo", "value matches");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
diag "trying to fail then stale set via mset";
|
|
Packit Service |
584ef9 |
print $sock "ms toinv STC 1 90 0\r\nf\r\n";
|
|
Packit Service |
584ef9 |
like(scalar <$sock>, qr/^EX /, "failed to SET: low CAS didn't match");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
print $sock "ms toinv SITC 1 90 0\r\nf\r\n";
|
|
Packit Service |
584ef9 |
like(scalar <$sock>, qr/^ST /, "SET an invalid/stale item");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
diag "confirm item still stale, and TTL wasn't raised.";
|
|
Packit Service |
584ef9 |
$res = mget($sock, 'toinv', 'stcv');
|
|
Packit Service |
584ef9 |
like($res->{flags}, qr/X/, "item is marked stale");
|
|
Packit Service |
584ef9 |
like($res->{flags}, qr/Z/, "win token already sent");
|
|
Packit Service |
584ef9 |
unlike($res->{flags}, qr/W/, "didn't win: token already sent");
|
|
Packit Service |
584ef9 |
$ttl = $res->{tokens}->[1];
|
|
Packit Service |
584ef9 |
ok($ttl > 0 && $ttl <= 30, "TTL wasn't modified");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# TODO: CAS too high?
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
diag "do valid mset";
|
|
Packit Service |
584ef9 |
$cas = $res->{tokens}->[2];
|
|
Packit Service |
584ef9 |
print $sock "ms toinv STC 1 90 $cas\r\ng\r\n";
|
|
Packit Service |
584ef9 |
like(scalar <$sock>, qr/^ST /, "SET over the stale item");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
$res = mget($sock, 'toinv', 'stcv');
|
|
Packit Service |
584ef9 |
ok(keys %$res, "not a miss");
|
|
Packit Service |
584ef9 |
unlike($res->{flags}, qr/[WXZ]/, "no stale, win, or tokens");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
$ttl = $res->{tokens}->[1];
|
|
Packit Service |
584ef9 |
ok($ttl > 30 && $ttl <= 90, "TTL was modified");
|
|
Packit Service |
584ef9 |
ok($cas != $res->{tokens}->[2], "CAS was updated");
|
|
Packit Service |
584ef9 |
is($res->{tokens}->[0], 1, "size updated");
|
|
Packit Service |
584ef9 |
is($res->{val}, "g", "value was updated");
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# Quiet flag suppresses most output. Badly invalid commands will still
|
|
Packit Service |
584ef9 |
# generate something. Not weird to parse like 'noreply' token was...
|
|
Packit Service |
584ef9 |
# mget's with hits should return real data.
|
|
Packit Service |
584ef9 |
{
|
|
Packit Service |
584ef9 |
diag "testing quiet flag";
|
|
Packit Service |
584ef9 |
print $sock "ms quiet Sq 2\r\nmo\r\n";
|
|
Packit Service |
584ef9 |
print $sock "md quiet q\r\n";
|
|
Packit Service |
584ef9 |
print $sock "mg quiet svq\r\n";
|
|
Packit Service |
584ef9 |
diag "now purposefully cause an error\r\n";
|
|
Packit Service |
584ef9 |
print $sock "ms quiet S\r\n";
|
|
Packit Service |
584ef9 |
like(scalar <$sock>, qr/^CLIENT_ERROR/, "resp not ST, DE, or EN");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# Now try a pipelined get. Throw an mnop at the end
|
|
Packit Service |
584ef9 |
print $sock "ms quiet Sq 2\r\nbo\r\n";
|
|
Packit Service |
584ef9 |
print $sock "mg quiet svq\r\nmg quiet svq\r\nmg quietmiss svq\r\nmn\r\n";
|
|
Packit Service |
584ef9 |
# Should get back VA/data/VA/data/EN
|
|
Packit Service |
584ef9 |
like(scalar <$sock>, qr/^VA svq 2/, "get response");
|
|
Packit Service |
584ef9 |
like(scalar <$sock>, qr/^bo/, "get value");
|
|
Packit Service |
584ef9 |
like(scalar <$sock>, qr/^VA svq 2/, "get response");
|
|
Packit Service |
584ef9 |
like(scalar <$sock>, qr/^bo/, "get value");
|
|
Packit Service |
584ef9 |
like(scalar <$sock>, qr/^EN/, "end token");
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
{
|
|
Packit Service |
584ef9 |
my $k = 'otest';
|
|
Packit Service |
584ef9 |
diag "testing mget opaque";
|
|
Packit Service |
584ef9 |
print $sock "ms $k ST 2 100\r\nra\r\n";
|
|
Packit Service |
584ef9 |
like(scalar <$sock>, qr/^ST /, "set $k");
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
my $res = mget($sock, $k, 'stvO opaque');
|
|
Packit Service |
584ef9 |
is($res->{tokens}->[2], 'opaque', "O flag returned opaque");
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
{
|
|
Packit Service |
584ef9 |
diag "flag and token count errors";
|
|
Packit Service |
584ef9 |
print $sock "mg foo sv extratoken\r\n";
|
|
Packit Service |
584ef9 |
like(scalar <$sock>, qr/^CLIENT_ERROR incorrect number of tokens/, "too many tokens");
|
|
Packit Service |
584ef9 |
print $sock "mg foo svN\r\n";
|
|
Packit Service |
584ef9 |
like(scalar <$sock>, qr/^CLIENT_ERROR incorrect number of tokens/, "too few tokens");
|
|
Packit Service |
584ef9 |
print $sock "mg foo mooooo\r\n";
|
|
Packit Service |
584ef9 |
like(scalar <$sock>, qr/^CLIENT_ERROR invalid or duplicate flag/, "gone silly with flags");
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# TODO: move wait_for_ext into Memcached.pm
|
|
Packit Service |
584ef9 |
sub wait_for_ext {
|
|
Packit Service |
584ef9 |
my $sock = shift;
|
|
Packit Service |
584ef9 |
my $target = shift || 0;
|
|
Packit Service |
584ef9 |
my $sum = $target + 1;
|
|
Packit Service |
584ef9 |
while ($sum > $target) {
|
|
Packit Service |
584ef9 |
my $s = mem_stats($sock, "items");
|
|
Packit Service |
584ef9 |
$sum = 0;
|
|
Packit Service |
584ef9 |
for my $key (keys %$s) {
|
|
Packit Service |
584ef9 |
if ($key =~ m/items:(\d+):number/) {
|
|
Packit Service |
584ef9 |
# Ignore classes which can contain extstore items
|
|
Packit Service |
584ef9 |
next if $1 < 3;
|
|
Packit Service |
584ef9 |
$sum += $s->{$key};
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
sleep 1 if $sum > $target;
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
my $ext_path;
|
|
Packit Service |
584ef9 |
# Do a basic extstore test if enabled.
|
|
Packit Service |
584ef9 |
if (supports_extstore()) {
|
|
Packit Service |
584ef9 |
diag "mget + extstore tests";
|
|
Packit Service |
584ef9 |
$ext_path = "/tmp/extstore.$$";
|
|
Packit Service |
584ef9 |
my $server = new_memcached("-m 64 -U 0 -o ext_page_size=8,ext_wbuf_size=2,ext_threads=1,ext_io_depth=2,ext_item_size=512,ext_item_age=2,ext_recache_rate=10000,ext_max_frag=0.9,ext_path=$ext_path:64m,slab_automove=0,ext_compact_under=1,no_lru_crawler");
|
|
Packit Service |
584ef9 |
my $sock = $server->sock;
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
my $value;
|
|
Packit Service |
584ef9 |
{
|
|
Packit Service |
584ef9 |
my @chars = ("C".."Z");
|
|
Packit Service |
584ef9 |
for (1 .. 20000) {
|
|
Packit Service |
584ef9 |
$value .= $chars[rand @chars];
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
my $keycount = 10;
|
|
Packit Service |
584ef9 |
for (1 .. $keycount) {
|
|
Packit Service |
584ef9 |
print $sock "set nfoo$_ 0 0 20000 noreply\r\n$value\r\n";
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
wait_for_ext($sock);
|
|
Packit Service |
584ef9 |
mget_is({ sock => $sock,
|
|
Packit Service |
584ef9 |
flags => 'sv',
|
|
Packit Service |
584ef9 |
etokens => [20000] },
|
|
Packit Service |
584ef9 |
'nfoo1', $value, "retrieved test value");
|
|
Packit Service |
584ef9 |
my $stats = mem_stats($sock);
|
|
Packit Service |
584ef9 |
cmp_ok($stats->{get_extstore}, '>', 0, 'one object was fetched');
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
my $ovalue = $value;
|
|
Packit Service |
584ef9 |
for (1 .. 4) {
|
|
Packit Service |
584ef9 |
$value .= $ovalue;
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
# Fill to eviction.
|
|
Packit Service |
584ef9 |
$keycount = 1000;
|
|
Packit Service |
584ef9 |
for (1 .. $keycount) {
|
|
Packit Service |
584ef9 |
print $sock "set mfoo$_ 0 0 100000 noreply\r\n$value\r\n";
|
|
Packit Service |
584ef9 |
# wait to avoid memory evictions
|
|
Packit Service |
584ef9 |
wait_for_ext($sock, 1) if ($_ % 250 == 0);
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
print $sock "mg mfoo1 sv\r\n";
|
|
Packit Service |
584ef9 |
is(scalar <$sock>, "EN\r\n");
|
|
Packit Service |
584ef9 |
print $sock "mg mfoo1 svq\r\nmn\r\n";
|
|
Packit Service |
584ef9 |
is(scalar <$sock>, "EN\r\n");
|
|
Packit Service |
584ef9 |
$stats = mem_stats($sock);
|
|
Packit Service |
584ef9 |
cmp_ok($stats->{miss_from_extstore}, '>', 0, 'at least one miss');
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
###
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# takes hash:
|
|
Packit Service |
584ef9 |
# - sock
|
|
Packit Service |
584ef9 |
# - args (metaget flags)
|
|
Packit Service |
584ef9 |
# - array of tokens
|
|
Packit Service |
584ef9 |
# - array of expected response tokens
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# returns hash:
|
|
Packit Service |
584ef9 |
# - win (if won a condition)
|
|
Packit Service |
584ef9 |
# - array of tokens
|
|
Packit Service |
584ef9 |
# - value, etc?
|
|
Packit Service |
584ef9 |
# useful to chain together for further requests.
|
|
Packit Service |
584ef9 |
# works only with single line values. no newlines in value.
|
|
Packit Service |
584ef9 |
# FIXME: some workaround for super long values :|
|
|
Packit Service |
584ef9 |
# TODO: move this to lib/MemcachedTest.pm
|
|
Packit Service |
584ef9 |
sub mget_is {
|
|
Packit Service |
584ef9 |
# single line values only
|
|
Packit Service |
584ef9 |
my ($o, $key, $val, $msg) = @_;
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
my $dval = defined $val ? "'$val'" : "<undef>";
|
|
Packit Service |
584ef9 |
$msg ||= "$key == $dval";
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
my $s = $o->{sock};
|
|
Packit Service |
584ef9 |
my $flags = $o->{flags};
|
|
Packit Service |
584ef9 |
# sometimes response flags can differ from request flags.
|
|
Packit Service |
584ef9 |
my $eflags = $o->{eflags} || $flags;
|
|
Packit Service |
584ef9 |
my $tokens = exists $o->{tokens} ? join(' ', @{$o->{tokens}}) : '';
|
|
Packit Service |
584ef9 |
my $etokens = exists $o->{etokens} ? join(' ', @{$o->{etokens}}) : '';
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
print $s "mg $key $flags $tokens\r\n";
|
|
Packit Service |
584ef9 |
if (! defined $val) {
|
|
Packit Service |
584ef9 |
my $line = scalar <$s>;
|
|
Packit Service |
584ef9 |
if ($line =~ /^VA/) {
|
|
Packit Service |
584ef9 |
$line .= scalar(<$s>) . scalar(<$s>);
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
Test::More::is($line, "EN\r\n", $msg);
|
|
Packit Service |
584ef9 |
} else {
|
|
Packit Service |
584ef9 |
my $len = length($val);
|
|
Packit Service |
584ef9 |
my $body = scalar(<$s>);
|
|
Packit Service |
584ef9 |
my $expected = "VA $eflags $etokens\r\n$val\r\nEN\r\n";
|
|
Packit Service |
584ef9 |
if (!$body || $body =~ /^EN/) {
|
|
Packit Service |
584ef9 |
Test::More::is($body, $expected, $msg);
|
|
Packit Service |
584ef9 |
return;
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
$body .= scalar(<$s>) . scalar(<$s>);
|
|
Packit Service |
584ef9 |
Test::More::is($body, $expected, $msg);
|
|
Packit Service |
584ef9 |
return mget_res($body);
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
return {};
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
sub mget {
|
|
Packit Service |
584ef9 |
my $s = shift;
|
|
Packit Service |
584ef9 |
my $key = shift;
|
|
Packit Service |
584ef9 |
my $flags = shift;
|
|
Packit Service |
584ef9 |
my $tokens = join(' ', @_);
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
print $s "mg $key $flags ", $tokens, "\r\n";
|
|
Packit Service |
584ef9 |
my $header = scalar(<$s>);
|
|
Packit Service |
584ef9 |
my $val = "\r\n";
|
|
Packit Service |
584ef9 |
if ($flags =~ m/v/) {
|
|
Packit Service |
584ef9 |
$val = scalar(<$s>);
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
my $end = scalar(<$s>);
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
return mget_res($header . $val);
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
# parse out a response
|
|
Packit Service |
584ef9 |
sub mget_res {
|
|
Packit Service |
584ef9 |
my $resp = shift;
|
|
Packit Service |
584ef9 |
my %r = ();
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
if ($resp =~ m/^VA ([^\s]+) ([^\r]+)\r\n(.*)\r\n/gm) {
|
|
Packit Service |
584ef9 |
$r{flags} = $1;
|
|
Packit Service |
584ef9 |
$r{val} = $3;
|
|
Packit Service |
584ef9 |
$r{tokens} = [split(/ /, $2)];
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
return \%r;
|
|
Packit Service |
584ef9 |
}
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
done_testing();
|
|
Packit Service |
584ef9 |
|
|
Packit Service |
584ef9 |
END {
|
|
Packit Service |
584ef9 |
unlink $ext_path if $ext_path;
|
|
Packit Service |
584ef9 |
}
|