1#!/usr/bin/env perl
2
3use strict;
4use Test::More tests => 113;
5use FindBin qw($Bin);
6use lib "$Bin/lib";
7use MemcachedTest;
8
9my $server = new_memcached("-I 1024 -o slab_chunk_max=1,no_lru_crawler,no_lru_maintainer");
10my $sock = $server->sock;
11
12
13## Output looks like this:
14##
15## STAT pid 22969
16## STAT uptime 13
17## STAT time 1259170891
18## STAT version 1.4.3
19## STAT libevent 1.4.13-stable.
20## see doc/protocol.txt for others
21# note that auth stats are tested in auth specific tests
22
23
24my $stats = mem_stats($sock);
25
26# Test number of keys
27if (MemcachedTest::enabled_tls_testing()) {
28    # when TLS is enabled, stats contains additional keys:
29    #   - ssl_handshake_errors
30    #   - time_since_server_cert_refresh
31    is(scalar(keys(%$stats)), 85, "expected count of stats values");
32} else {
33    is(scalar(keys(%$stats)), 83, "expected count of stats values");
34}
35
36# Test initial state
37foreach my $key (qw(curr_items total_items bytes cmd_get cmd_set get_hits evictions get_misses get_expired
38                 bytes_written delete_hits delete_misses incr_hits incr_misses decr_hits get_flushed
39                 decr_misses listen_disabled_num lrutail_reflocked time_in_listen_disabled_us
40                 store_too_large store_no_memory)) {
41    is($stats->{$key}, 0, "initial $key is zero");
42}
43is($stats->{accepting_conns}, 1, "initial accepting_conns is one");
44
45# Do some operations
46
47print $sock "set foo 0 0 6\r\nfooval\r\n";
48is(scalar <$sock>, "STORED\r\n", "stored foo");
49mem_get_is($sock, "foo", "fooval");
50
51my $stats = mem_stats($sock);
52
53foreach my $key (qw(total_items curr_items cmd_get cmd_set get_hits)) {
54    is($stats->{$key}, 1, "after one set/one get $key is 1");
55}
56
57my $cache_dump = mem_stats($sock, " cachedump 1 100");
58ok(defined $cache_dump->{'foo'}, "got foo from cachedump");
59
60print $sock "delete foo\r\n";
61is(scalar <$sock>, "DELETED\r\n", "deleted foo");
62
63my $stats = mem_stats($sock);
64is($stats->{delete_hits}, 1);
65is($stats->{delete_misses}, 0);
66
67print $sock "delete foo\r\n";
68is(scalar <$sock>, "NOT_FOUND\r\n", "shouldn't delete foo again");
69
70my $stats = mem_stats($sock);
71is($stats->{delete_hits}, 1);
72is($stats->{delete_misses}, 1);
73
74# incr stats
75
76sub check_incr_stats {
77    my ($ih, $im, $dh, $dm) = @_;
78    my $stats = mem_stats($sock);
79
80    is($stats->{incr_hits}, $ih);
81    is($stats->{incr_misses}, $im);
82    is($stats->{decr_hits}, $dh);
83    is($stats->{decr_misses}, $dm);
84}
85
86print $sock "incr i 1\r\n";
87is(scalar <$sock>, "NOT_FOUND\r\n", "shouldn't incr a missing thing");
88check_incr_stats(0, 1, 0, 0);
89
90print $sock "decr d 1\r\n";
91is(scalar <$sock>, "NOT_FOUND\r\n", "shouldn't decr a missing thing");
92check_incr_stats(0, 1, 0, 1);
93
94print $sock "set n 0 0 1\r\n0\r\n";
95is(scalar <$sock>, "STORED\r\n", "stored n");
96
97print $sock "incr n 3\r\n";
98is(scalar <$sock>, "3\r\n", "incr works");
99check_incr_stats(1, 1, 0, 1);
100
101print $sock "decr n 1\r\n";
102is(scalar <$sock>, "2\r\n", "decr works");
103check_incr_stats(1, 1, 1, 1);
104
105# cas stats
106
107sub check_cas_stats {
108    my ($ch, $cm, $cb) = @_;
109    my $stats = mem_stats($sock);
110
111    is($stats->{cas_hits}, $ch);
112    is($stats->{cas_misses}, $cm);
113    is($stats->{cas_badval}, $cb);
114}
115
116check_cas_stats(0, 0, 0);
117
118print $sock "cas c 0 0 1 99999999\r\nz\r\n";
119is(scalar <$sock>, "NOT_FOUND\r\n", "missed cas");
120check_cas_stats(0, 1, 0);
121
122print $sock "set c 0 0 1\r\nx\r\n";
123is(scalar <$sock>, "STORED\r\n", "stored c");
124my ($id, $v) = mem_gets($sock, 'c');
125is('x', $v, 'got the expected value');
126
127print $sock "cas c 0 0 1 99999999\r\nz\r\n";
128is(scalar <$sock>, "EXISTS\r\n", "missed cas");
129check_cas_stats(0, 1, 1);
130my ($newid, $v) = mem_gets($sock, 'c');
131is('x', $v, 'got the expected value');
132
133print $sock "cas c 0 0 1 $id\r\nz\r\n";
134is(scalar <$sock>, "STORED\r\n", "good cas");
135check_cas_stats(1, 1, 1);
136my ($newid, $v) = mem_gets($sock, 'c');
137is('z', $v, 'got the expected value');
138
139my $settings = mem_stats($sock, ' settings');
140is(1024, $settings->{'maxconns'});
141# we run SSL tests over TCP; hence the domain_socket
142# is expected to be NULL.
143if (enabled_tls_testing() || !supports_unix_socket()) {
144    is('NULL', $settings->{'domain_socket'});
145} else {
146    isnt('NULL', $settings->{'domain_socket'});
147}
148is('on', $settings->{'evictions'});
149is('yes', $settings->{'cas_enabled'});
150is('no', $settings->{'auth_enabled_sasl'});
151is('no', $settings->{'shutdown_command'});
152
153print $sock "stats reset\r\n";
154is(scalar <$sock>, "RESET\r\n", "good stats reset");
155
156my $stats = mem_stats($sock);
157is(0, $stats->{'cmd_get'});
158is(0, $stats->{'cmd_set'});
159is(0, $stats->{'get_hits'});
160is(0, $stats->{'get_misses'});
161is(0, $stats->{'get_expired'});
162is(0, $stats->{'get_flushed'});
163is(0, $stats->{'delete_misses'});
164is(0, $stats->{'delete_hits'});
165is(0, $stats->{'incr_misses'});
166is(0, $stats->{'incr_hits'});
167is(0, $stats->{'decr_misses'});
168is(0, $stats->{'decr_hits'});
169is(0, $stats->{'cas_misses'});
170is(0, $stats->{'cas_hits'});
171is(0, $stats->{'cas_badval'});
172is(0, $stats->{'evictions'});
173is(0, $stats->{'reclaimed'});
174is(0, $stats->{'lrutail_reflocked'});
175
176# item expired
177print $sock "set should_expire 0 2678400 6\r\nfooval\r\n"; #2678400 = 31 days in seconds
178is(scalar <$sock>, "STORED\r\n", "set item to expire");
179print $sock "get should_expire\r\n";
180is(scalar <$sock>, "END\r\n", "item not returned");
181my $stats = mem_stats($sock);
182is(1, $stats->{'get_expired'}, "get_expired counter is 1");
183
184print $sock "set should_be_flushed 0 0 6\r\nbooval\r\n";
185is(scalar <$sock>, "STORED\r\n", "set item to flush");
186mem_move_time($sock, 3); # need to wait so `flush_all` doesn't nuke the item.
187print $sock "flush_all\r\n";
188is(scalar <$sock>, "OK\r\n", "flushed");
189print $sock "get should_be_flushed\r\n";
190is(scalar <$sock>, "END\r\n", "flushed item not returned");
191
192my $stats = mem_stats($sock);
193is($stats->{cmd_flush}, 1, "after one flush cmd_flush is 1");
194is($stats->{get_flushed}, 1, "after flush and a get, get_flushed is 1");
195
196# item too large
197my $large = "B" x 2048;
198my $largelen = length($large);
199print $sock "set too_large 0 0 $largelen\r\n$large\r\n";
200is(scalar <$sock>, "SERVER_ERROR object too large for cache\r\n",
201    "set rejected due to value too large");
202$stats = mem_stats($sock);
203is($stats->{'store_too_large'}, 1,
204    "recorded store failure due to value too large")
205