line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package CHI::t::Driver; |
2
|
|
|
|
|
|
|
$CHI::t::Driver::VERSION = '0.60'; |
3
|
9
|
|
|
9
|
|
48
|
use strict; |
|
9
|
|
|
|
|
12
|
|
|
9
|
|
|
|
|
299
|
|
4
|
9
|
|
|
9
|
|
37
|
use warnings; |
|
9
|
|
|
|
|
12
|
|
|
9
|
|
|
|
|
253
|
|
5
|
9
|
|
|
9
|
|
37
|
use CHI::Test; |
|
9
|
|
|
|
|
13
|
|
|
9
|
|
|
|
|
61
|
|
6
|
|
|
|
|
|
|
use CHI::Test::Util |
7
|
9
|
|
|
9
|
|
49
|
qw(activate_test_logger cmp_bool is_between random_string skip_until); |
|
9
|
|
|
|
|
14
|
|
|
9
|
|
|
|
|
717
|
|
8
|
9
|
|
|
9
|
|
82
|
use CHI::Util qw(can_load dump_one_line write_file); |
|
9
|
|
|
|
|
19
|
|
|
9
|
|
|
|
|
509
|
|
9
|
9
|
|
|
9
|
|
44
|
use Encode; |
|
9
|
|
|
|
|
13
|
|
|
9
|
|
|
|
|
798
|
|
10
|
9
|
|
|
9
|
|
53
|
use File::Spec::Functions qw(tmpdir); |
|
9
|
|
|
|
|
12
|
|
|
9
|
|
|
|
|
559
|
|
11
|
9
|
|
|
9
|
|
2136
|
use File::Temp qw(tempdir); |
|
9
|
|
|
|
|
49716
|
|
|
9
|
|
|
|
|
451
|
|
12
|
9
|
|
|
9
|
|
57
|
use List::Util qw(shuffle); |
|
9
|
|
|
|
|
15
|
|
|
9
|
|
|
|
|
572
|
|
13
|
9
|
|
|
9
|
|
41
|
use Scalar::Util qw(weaken); |
|
9
|
|
|
|
|
14
|
|
|
9
|
|
|
|
|
372
|
|
14
|
9
|
|
|
9
|
|
39
|
use Storable qw(dclone); |
|
9
|
|
|
|
|
12
|
|
|
9
|
|
|
|
|
501
|
|
15
|
9
|
|
|
9
|
|
3536
|
use Test::Warn; |
|
9
|
|
|
|
|
11883
|
|
|
9
|
|
|
|
|
521
|
|
16
|
9
|
|
|
9
|
|
51
|
use Time::HiRes qw(usleep); |
|
9
|
|
|
|
|
13
|
|
|
9
|
|
|
|
|
78
|
|
17
|
9
|
|
|
9
|
|
1375
|
use base qw(CHI::Test::Class); |
|
9
|
|
|
|
|
15
|
|
|
9
|
|
|
|
|
3773
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
# Flags indicating what each test driver supports |
20
|
384
|
|
|
384
|
0
|
5537
|
sub supports_clear { 1 } |
21
|
7
|
|
|
7
|
0
|
44
|
sub supports_expires_on_backend { 0 } |
22
|
5
|
|
|
5
|
0
|
22
|
sub supports_get_namespaces { 1 } |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
sub standard_keys_and_values : Test(startup) { |
25
|
7
|
|
|
7
|
0
|
14269
|
my ($self) = @_; |
26
|
|
|
|
|
|
|
|
27
|
7
|
|
|
|
|
71
|
my ( $keys_ref, $values_ref ) = $self->set_standard_keys_and_values(); |
28
|
7
|
|
|
|
|
28
|
$self->{keys} = $keys_ref; |
29
|
7
|
|
|
|
|
21
|
$self->{values} = $values_ref; |
30
|
7
|
|
|
|
|
15
|
$self->{keynames} = [ keys( %{$keys_ref} ) ]; |
|
7
|
|
|
|
|
47
|
|
31
|
7
|
|
|
|
|
21
|
$self->{key_count} = scalar( @{ $self->{keynames} } ); |
|
7
|
|
|
|
|
26
|
|
32
|
7
|
|
|
|
|
103
|
$self->{all_test_keys} = [ values(%$keys_ref), $self->extra_test_keys() ]; |
33
|
7
|
|
|
|
|
212
|
my $cache = $self->new_cache(); |
34
|
7
|
|
|
|
|
31
|
push( |
35
|
7
|
|
|
|
|
118
|
@{ $self->{all_test_keys} }, |
36
|
7
|
|
|
|
|
25
|
$self->process_keys( $cache, @{ $self->{all_test_keys} } ) |
37
|
|
|
|
|
|
|
); |
38
|
644
|
|
|
|
|
1268
|
$self->{all_test_keys_hash} = |
39
|
7
|
|
|
|
|
34
|
{ map { ( $_, 1 ) } @{ $self->{all_test_keys} } }; |
|
7
|
|
|
|
|
34
|
|
40
|
9
|
|
|
9
|
|
87
|
} |
|
9
|
|
|
|
|
13
|
|
|
9
|
|
|
|
|
52
|
|
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
sub kvpair { |
43
|
151
|
|
|
151
|
0
|
281
|
my $self = shift; |
44
|
151
|
|
100
|
|
|
782
|
my $count = shift || 1; |
45
|
|
|
|
|
|
|
|
46
|
176
|
100
|
|
|
|
1673
|
return map { |
|
|
100
|
|
|
|
|
|
47
|
151
|
|
|
|
|
487
|
( |
48
|
|
|
|
|
|
|
$self->{keys}->{medium} . ( $_ == 1 ? '' : $_ ), |
49
|
|
|
|
|
|
|
$self->{values}->{medium} . ( $_ == 1 ? '' : $_ ) |
50
|
|
|
|
|
|
|
) |
51
|
|
|
|
|
|
|
} ( 1 .. $count ); |
52
|
|
|
|
|
|
|
} |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
sub setup : Test(setup) { |
55
|
367
|
|
|
367
|
0
|
610511
|
my $self = shift; |
56
|
|
|
|
|
|
|
|
57
|
367
|
|
|
|
|
2194
|
$self->{cache} = $self->new_cache(); |
58
|
367
|
50
|
|
|
|
12457
|
$self->{cache}->clear() if $self->supports_clear(); |
59
|
9
|
|
|
9
|
|
3724
|
} |
|
9
|
|
|
|
|
27
|
|
|
9
|
|
|
|
|
43
|
|
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
sub testing_driver_class { |
62
|
292
|
|
|
292
|
0
|
419
|
my $self = shift; |
63
|
292
|
|
|
|
|
556
|
my $class = ref($self); |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
# By default, take the last part of the classname and use it as driver |
66
|
292
|
|
|
|
|
1570
|
my $driver_class = 'CHI::Driver::' . ( split( '::', $class ) )[-1]; |
67
|
292
|
|
|
|
|
2489
|
return $driver_class; |
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
sub testing_chi_root_class { |
71
|
358
|
|
|
358
|
0
|
1875
|
return 'CHI'; |
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
sub new_cache { |
75
|
347
|
|
|
347
|
0
|
590
|
my $self = shift; |
76
|
|
|
|
|
|
|
|
77
|
347
|
|
|
|
|
1653
|
return $self->testing_chi_root_class->new( $self->new_cache_options(), @_ ); |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
sub new_cleared_cache { |
81
|
82
|
|
|
82
|
0
|
1027
|
my $self = shift; |
82
|
|
|
|
|
|
|
|
83
|
82
|
|
|
|
|
360
|
my $cache = $self->new_cache(@_); |
84
|
82
|
|
|
|
|
2111
|
$cache->clear(); |
85
|
82
|
|
|
|
|
1473
|
return $cache; |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
sub new_cache_options { |
89
|
631
|
|
|
631
|
0
|
968
|
my $self = shift; |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
return ( |
92
|
631
|
|
|
|
|
2617
|
driver => '+' . $self->testing_driver_class(), |
93
|
|
|
|
|
|
|
on_get_error => 'die', |
94
|
|
|
|
|
|
|
on_set_error => 'die' |
95
|
|
|
|
|
|
|
); |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
sub set_standard_keys_and_values { |
99
|
7
|
|
|
7
|
0
|
18
|
my $self = shift; |
100
|
|
|
|
|
|
|
|
101
|
7
|
|
|
|
|
12
|
my ( %keys, %values ); |
102
|
7
|
|
|
|
|
47
|
my @mixed_chars = ( 32 .. 48, 57 .. 65, 90 .. 97, 122 .. 126, 240 ); |
103
|
|
|
|
|
|
|
|
104
|
280
|
|
|
|
|
405
|
%keys = ( |
105
|
|
|
|
|
|
|
'space' => ' ', |
106
|
|
|
|
|
|
|
'newline' => "\n", |
107
|
|
|
|
|
|
|
'char' => 'a', |
108
|
|
|
|
|
|
|
'zero' => 0, |
109
|
|
|
|
|
|
|
'one' => 1, |
110
|
|
|
|
|
|
|
'medium' => 'medium', |
111
|
889
|
|
|
|
|
1342
|
'mixed' => join( "", map { chr($_) } @mixed_chars ), |
112
|
7
|
|
|
|
|
26
|
'binary' => join( "", map { chr($_) } ( 129 .. 255 ) ), |
113
|
|
|
|
|
|
|
'large' => scalar( 'ab' x 256 ), |
114
|
|
|
|
|
|
|
'empty' => 'empty', |
115
|
|
|
|
|
|
|
'arrayref' => [ 1, 2 ], |
116
|
|
|
|
|
|
|
'hashref' => { foo => [ 'bar', 'baz' ] }, |
117
|
|
|
|
|
|
|
'utf8' => "Have \x{263a} a nice day", |
118
|
|
|
|
|
|
|
); |
119
|
|
|
|
|
|
|
|
120
|
91
|
100
|
|
|
|
351
|
%values = map { |
121
|
7
|
|
|
|
|
102
|
( $_, ref( $keys{$_} ) ? $keys{$_} : scalar( reverse( $keys{$_} ) ) ) |
122
|
|
|
|
|
|
|
} keys(%keys); |
123
|
7
|
|
|
|
|
31
|
$values{empty} = ''; |
124
|
|
|
|
|
|
|
|
125
|
7
|
|
|
|
|
42
|
return ( \%keys, \%values ); |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
# Extra keys (beyond the standard keys above) that we may use in these |
129
|
|
|
|
|
|
|
# tests. We need to adhere to this for the benefit of drivers that don't |
130
|
|
|
|
|
|
|
# support get_keys (like memcached) - they simulate get_keys(), clear(), |
131
|
|
|
|
|
|
|
# etc. by using this fixed list of keys. |
132
|
|
|
|
|
|
|
# |
133
|
|
|
|
|
|
|
sub extra_test_keys { |
134
|
7
|
|
|
7
|
0
|
18
|
my ($class) = @_; |
135
|
|
|
|
|
|
|
return ( |
136
|
21
|
|
|
|
|
68
|
'', '2', |
137
|
|
|
|
|
|
|
'medium2', 'foo', |
138
|
|
|
|
|
|
|
'hashref', 'test_namespace_types', |
139
|
|
|
|
|
|
|
"utf8", "encoded", |
140
|
147
|
|
|
|
|
296
|
"binary", ( map { "done$_" } ( 0 .. 2 ) ), |
141
|
7
|
|
|
|
|
28
|
( map { "key$_" } ( 0 .. 20 ) ) |
142
|
|
|
|
|
|
|
); |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
sub set_some_keys { |
146
|
50
|
|
|
50
|
0
|
118
|
my ( $self, $c ) = @_; |
147
|
|
|
|
|
|
|
|
148
|
50
|
|
|
|
|
88
|
foreach my $keyname ( @{ $self->{keynames} } ) { |
|
50
|
|
|
|
|
199
|
|
149
|
590
|
|
|
|
|
8780
|
$c->set( $self->{keys}->{$keyname}, $self->{values}->{$keyname} ); |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
sub test_encode : Tests { |
154
|
7
|
|
|
7
|
0
|
1302
|
my $self = shift; |
155
|
7
|
|
|
|
|
41
|
my $cache = $self->new_cleared_cache(); |
156
|
|
|
|
|
|
|
|
157
|
7
|
|
|
|
|
31
|
my $utf8 = $self->{keys}->{utf8}; |
158
|
7
|
|
|
|
|
37
|
my $encoded = encode( utf8 => $utf8 ); |
159
|
7
|
|
|
|
|
262
|
my $binary_off = $self->{keys}->{binary}; |
160
|
7
|
|
|
|
|
64
|
my $binary_on = substr( $binary_off . $utf8, 0, length($binary_off) ); |
161
|
|
|
|
|
|
|
|
162
|
7
|
|
|
|
|
52
|
ok( $binary_off eq $binary_on, "binary_off eq binary_on" ); |
163
|
7
|
|
|
|
|
3225
|
ok( !Encode::is_utf8($binary_off), "!is_utf8(binary_off)" ); |
164
|
7
|
|
|
|
|
2680
|
ok( Encode::is_utf8($binary_on), "is_utf8(binary_on)" ); |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
# Key maps to same thing whether encoded or non-encoded |
167
|
|
|
|
|
|
|
# |
168
|
7
|
|
|
|
|
3344
|
my $value = time; |
169
|
7
|
|
|
|
|
191
|
$cache->set( $utf8, $value ); |
170
|
7
|
|
|
|
|
127
|
is( $cache->get($utf8), $value, "get" ); |
171
|
7
|
|
|
|
|
3031
|
is( $cache->get($encoded), |
172
|
|
|
|
|
|
|
$value, "encoded and non-encoded map to same value" ); |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
# Key maps to same thing whether utf8 flag is off or on |
175
|
|
|
|
|
|
|
# |
176
|
|
|
|
|
|
|
# Commenting out for now - this is broken on FastMmap and |
177
|
|
|
|
|
|
|
# DBI drivers (at least), and not entirely sure whether or |
178
|
|
|
|
|
|
|
# with what priority we should demand this behavior. |
179
|
|
|
|
|
|
|
# |
180
|
7
|
|
|
|
|
3011
|
if (0) { |
181
|
|
|
|
|
|
|
$cache->set( $binary_off, $value ); |
182
|
|
|
|
|
|
|
is( $cache->get($binary_off), $value, "get binary_off" ); |
183
|
|
|
|
|
|
|
is( $cache->get($binary_on), |
184
|
|
|
|
|
|
|
$value, "binary_off and binary_on map to same value" ); |
185
|
|
|
|
|
|
|
$cache->clear($binary_on); |
186
|
|
|
|
|
|
|
ok( !$cache->get($binary_off), "cleared binary_off" ); # |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
# Value is maintained as a utf8 or binary string, in scalar or in arrayref |
190
|
7
|
|
|
|
|
140
|
$cache->set( "utf8", $utf8 ); |
191
|
7
|
|
|
|
|
98
|
is( $cache->get("utf8"), $utf8, "utf8 in scalar" ); |
192
|
7
|
|
|
|
|
3419
|
$cache->set( "utf8", [$utf8] ); |
193
|
7
|
|
|
|
|
105
|
is( $cache->get("utf8")->[0], $utf8, "utf8 in arrayref" ); |
194
|
|
|
|
|
|
|
|
195
|
7
|
|
|
|
|
4091
|
$cache->set( "encoded", $encoded ); |
196
|
7
|
|
|
|
|
92
|
is( $cache->get("encoded"), $encoded, "encoded in scalar" ); |
197
|
7
|
|
|
|
|
3243
|
$cache->set( "encoded", [$encoded] ); |
198
|
7
|
|
|
|
|
100
|
is( $cache->get("encoded")->[0], $encoded, "encoded in arrayref" ); |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
# Value retrieves as same thing whether stored with utf8 flag off or on |
201
|
|
|
|
|
|
|
# |
202
|
7
|
|
|
|
|
5418
|
$cache->set( "binary", $binary_off ); |
203
|
7
|
|
|
|
|
91
|
is( $cache->get("binary"), $binary_on, "stored binary_off = binary_on" ); |
204
|
7
|
|
|
|
|
3021
|
$cache->set( "binary", $binary_on ); |
205
|
7
|
|
|
|
|
94
|
is( $cache->get("binary"), $binary_off, "stored binary_on = binary_off" ); |
206
|
9
|
|
|
9
|
|
9323
|
} |
|
9
|
|
|
|
|
21
|
|
|
9
|
|
|
|
|
45
|
|
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
sub test_simple : Tests { |
209
|
11
|
|
|
11
|
0
|
1395
|
my $self = shift; |
210
|
11
|
|
33
|
|
|
76
|
my $cache = shift || $self->{cache}; |
211
|
|
|
|
|
|
|
|
212
|
11
|
|
|
|
|
220
|
ok( $cache->set( $self->{keys}->{medium}, $self->{values}->{medium} ) ); |
213
|
9
|
|
|
|
|
4881
|
is( $cache->get( $self->{keys}->{medium} ), $self->{values}->{medium} ); |
214
|
9
|
|
|
9
|
|
2672
|
} |
|
9
|
|
|
|
|
23
|
|
|
9
|
|
|
|
|
39
|
|
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
sub test_driver_class : Tests { |
217
|
7
|
|
|
7
|
0
|
1484
|
my $self = shift; |
218
|
7
|
|
|
|
|
24
|
my $cache = $self->{cache}; |
219
|
|
|
|
|
|
|
|
220
|
7
|
|
|
|
|
44
|
isa_ok( $cache, 'CHI::Driver' ); |
221
|
7
|
|
|
|
|
4629
|
isa_ok( $cache, $cache->driver_class ); |
222
|
7
|
|
|
|
|
3256
|
can_ok( $cache, 'get', 'set', 'remove', 'clear', 'expire' ); |
223
|
9
|
|
|
9
|
|
2508
|
} |
|
9
|
|
|
|
|
19
|
|
|
9
|
|
|
|
|
46
|
|
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
sub test_key_types : Tests { |
226
|
7
|
|
|
7
|
0
|
1850
|
my $self = shift; |
227
|
7
|
|
|
|
|
24
|
my $cache = $self->{cache}; |
228
|
7
|
|
|
|
|
91
|
$self->num_tests( $self->{key_count} * 9 + 1 ); |
229
|
|
|
|
|
|
|
|
230
|
7
|
|
|
|
|
715
|
my @keys_set; |
231
|
|
|
|
|
|
|
my $check_keys_set = sub { |
232
|
149
|
|
|
149
|
|
573
|
my $desc = shift; |
233
|
149
|
|
|
|
|
690
|
cmp_set( [ $cache->get_keys ], \@keys_set, "checking keys $desc" ); |
234
|
7
|
|
|
|
|
47
|
}; |
235
|
|
|
|
|
|
|
|
236
|
7
|
|
|
|
|
21
|
$check_keys_set->("before sets"); |
237
|
7
|
|
|
|
|
5840
|
foreach my $keyname ( @{ $self->{keynames} } ) { |
|
7
|
|
|
|
|
37
|
|
238
|
79
|
|
|
|
|
65381
|
my $key = $self->{keys}->{$keyname}; |
239
|
79
|
|
|
|
|
316
|
my $value = $self->{values}->{$keyname}; |
240
|
79
|
|
|
|
|
1594
|
ok( !defined $cache->get($key), "miss for key '$keyname'" ); |
241
|
79
|
|
|
|
|
36017
|
is( $cache->set( $key, $value ), $value, "set for key '$keyname'" ); |
242
|
77
|
|
|
|
|
35039
|
push( @keys_set, $self->process_keys( $cache, $key ) ); |
243
|
77
|
|
|
|
|
355
|
$check_keys_set->("after set of key '$keyname'"); |
244
|
77
|
|
|
|
|
489026
|
cmp_deeply( $cache->get($key), $value, "hit for key '$keyname'" ); |
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
|
247
|
5
|
|
|
|
|
2317
|
foreach my $keyname ( reverse @{ $self->{keynames} } ) { |
|
5
|
|
|
|
|
21
|
|
248
|
65
|
|
|
|
|
305877
|
my $key = $self->{keys}->{$keyname}; |
249
|
65
|
|
|
|
|
2292
|
$cache->remove($key); |
250
|
65
|
|
|
|
|
954
|
ok( !defined $cache->get($key), |
251
|
|
|
|
|
|
|
"miss after remove for key '$keyname'" ); |
252
|
65
|
|
|
|
|
21760
|
pop(@keys_set); |
253
|
65
|
|
|
|
|
278
|
$check_keys_set->("after removal of key '$keyname'"); |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
# Confirm that transform_key is idempotent |
257
|
|
|
|
|
|
|
# |
258
|
5
|
|
|
|
|
2429
|
foreach my $keyname ( @{ $self->{keynames} } ) { |
|
5
|
|
|
|
|
20
|
|
259
|
65
|
|
|
|
|
30312
|
my $key = $self->{keys}->{$keyname}; |
260
|
65
|
|
|
|
|
146
|
my $value = $self->{values}->{$keyname}; |
261
|
65
|
|
|
|
|
205
|
is( |
262
|
|
|
|
|
|
|
$cache->transform_key( $cache->transform_key($key) ), |
263
|
|
|
|
|
|
|
$cache->transform_key($key), |
264
|
|
|
|
|
|
|
"transform_key is idempotent for '$keyname'" |
265
|
|
|
|
|
|
|
); |
266
|
65
|
|
|
|
|
19991
|
$cache->clear(); |
267
|
65
|
|
|
|
|
848
|
$cache->set( $key, $value ); |
268
|
65
|
|
|
|
|
173
|
is( scalar( $cache->get_keys() ), 1, "exactly one key" ); |
269
|
65
|
|
|
|
|
20469
|
cmp_deeply( $cache->get( ( $cache->get_keys )[0] ), |
270
|
|
|
|
|
|
|
$value, "get with get_keys[0] got same value" ); |
271
|
|
|
|
|
|
|
} |
272
|
9
|
|
|
9
|
|
5779
|
} |
|
9
|
|
|
|
|
18
|
|
|
9
|
|
|
|
|
40
|
|
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
sub test_deep_copy : Tests { |
275
|
6
|
|
|
6
|
0
|
1388
|
my $self = shift; |
276
|
6
|
|
|
|
|
18
|
my $cache = $self->{cache}; |
277
|
|
|
|
|
|
|
|
278
|
6
|
|
|
|
|
40
|
$self->set_some_keys($cache); |
279
|
4
|
|
|
|
|
11
|
foreach my $keyname (qw(arrayref hashref)) { |
280
|
8
|
|
|
|
|
1246
|
my $key = $self->{keys}->{$keyname}; |
281
|
8
|
|
|
|
|
20
|
my $value = $self->{values}->{$keyname}; |
282
|
8
|
|
|
|
|
132
|
cmp_deeply( $cache->get($key), $value, |
283
|
|
|
|
|
|
|
"get($key) returns original data structure" ); |
284
|
8
|
|
|
|
|
35154
|
cmp_deeply( $cache->get($key), $cache->get($key), |
285
|
|
|
|
|
|
|
"multiple get($key) return same data structure" ); |
286
|
8
|
|
|
|
|
13678
|
isnt( $cache->get($key), $value, |
287
|
|
|
|
|
|
|
"get($key) does not return original reference" ); |
288
|
8
|
|
|
|
|
3496
|
isnt( $cache->get($key), $cache->get($key), |
289
|
|
|
|
|
|
|
"multiple get($key) do not return same reference" ); |
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
|
292
|
4
|
|
|
|
|
1570
|
my $struct = { a => [ 1, 2 ], b => [ 4, 5 ] }; |
293
|
4
|
|
|
|
|
202
|
my $struct2 = dclone($struct); |
294
|
4
|
|
|
|
|
80
|
$cache->set( 'hashref', $struct ); |
295
|
4
|
|
|
|
|
7
|
push( @{ $struct->{a} }, 3 ); |
|
4
|
|
|
|
|
14
|
|
296
|
4
|
|
|
|
|
11
|
delete( $struct->{b} ); |
297
|
4
|
|
|
|
|
64
|
cmp_deeply( $cache->get('hashref'), |
298
|
|
|
|
|
|
|
$struct2, |
299
|
|
|
|
|
|
|
"altering original set structure does not affect cached copy" ); |
300
|
9
|
|
|
9
|
|
3965
|
} |
|
9
|
|
|
|
|
17
|
|
|
9
|
|
|
|
|
36
|
|
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
sub test_expires_immediately : Tests { |
303
|
7
|
|
|
7
|
0
|
1231
|
my $self = shift; |
304
|
|
|
|
|
|
|
|
305
|
7
|
50
|
|
|
|
44
|
return 'author testing only - timing is unreliable' |
306
|
|
|
|
|
|
|
unless ( $ENV{AUTHOR_TESTING} ); |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
# expires_in default should be ignored |
309
|
0
|
|
|
|
|
0
|
my $cache = $self->new_cache( expires_in => '1 hour' ); |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
# Expires immediately |
312
|
|
|
|
|
|
|
my $test_expires_immediately = sub { |
313
|
0
|
|
|
0
|
|
0
|
my ($set_option) = @_; |
314
|
0
|
|
|
|
|
0
|
my ( $key, $value ) = $self->kvpair(); |
315
|
0
|
|
|
|
|
0
|
my $desc = dump_one_line($set_option); |
316
|
0
|
|
|
|
|
0
|
is( $cache->set( $key, $value, $set_option ), $value, "set ($desc)" ); |
317
|
0
|
|
|
|
|
0
|
is_between( |
318
|
|
|
|
|
|
|
$cache->get_expires_at($key), |
319
|
|
|
|
|
|
|
time() - 4, |
320
|
|
|
|
|
|
|
time(), "expires_at ($desc)" |
321
|
|
|
|
|
|
|
); |
322
|
0
|
|
|
|
|
0
|
ok( $cache->exists_and_is_expired($key), "is_expired ($desc)" ); |
323
|
0
|
|
|
|
|
0
|
ok( !defined $cache->get($key), "immediate miss ($desc)" ); |
324
|
0
|
|
|
|
|
0
|
}; |
325
|
0
|
|
|
|
|
0
|
$test_expires_immediately->(0); |
326
|
0
|
|
|
|
|
0
|
$test_expires_immediately->(-1); |
327
|
0
|
|
|
|
|
0
|
$test_expires_immediately->("0 seconds"); |
328
|
0
|
|
|
|
|
0
|
$test_expires_immediately->("0 hours"); |
329
|
0
|
|
|
|
|
0
|
$test_expires_immediately->("-1 seconds"); |
330
|
0
|
|
|
|
|
0
|
$test_expires_immediately->( { expires_in => "0 seconds" } ); |
331
|
0
|
|
|
|
|
0
|
$test_expires_immediately->( { expires_at => time - 1 } ); |
332
|
0
|
|
|
|
|
0
|
$test_expires_immediately->("now"); |
333
|
9
|
|
|
9
|
|
3934
|
} |
|
9
|
|
|
|
|
15
|
|
|
9
|
|
|
|
|
46
|
|
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
sub test_expires_shortly : Tests { |
336
|
7
|
|
|
7
|
0
|
1591
|
my $self = shift; |
337
|
|
|
|
|
|
|
|
338
|
7
|
50
|
|
|
|
47
|
return 'author testing only - timing is unreliable' |
339
|
|
|
|
|
|
|
unless ( $ENV{AUTHOR_TESTING} ); |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
# expires_in default should be ignored |
342
|
0
|
|
|
|
|
0
|
my $cache = $self->new_cache( expires_in => '1 hour' ); |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
# Expires shortly (real time) |
345
|
|
|
|
|
|
|
my $test_expires_shortly = sub { |
346
|
0
|
|
|
0
|
|
0
|
my ($set_option) = @_; |
347
|
0
|
|
|
|
|
0
|
my ( $key, $value ) = $self->kvpair(); |
348
|
0
|
|
|
|
|
0
|
my $desc = "set_option = " . dump_one_line($set_option); |
349
|
0
|
|
|
|
|
0
|
my $start_time = time(); |
350
|
0
|
|
|
|
|
0
|
is( $cache->set( $key, $value, $set_option ), $value, "set ($desc)" ); |
351
|
0
|
|
|
|
|
0
|
is( $cache->get($key), $value, "hit ($desc)" ); |
352
|
0
|
|
|
|
|
0
|
is_between( |
353
|
|
|
|
|
|
|
$cache->get_expires_at($key), |
354
|
|
|
|
|
|
|
$start_time + 1, |
355
|
|
|
|
|
|
|
$start_time + 8, |
356
|
|
|
|
|
|
|
"expires_at ($desc)" |
357
|
|
|
|
|
|
|
); |
358
|
0
|
|
|
|
|
0
|
ok( !$cache->exists_and_is_expired($key), "not expired ($desc)" ); |
359
|
0
|
|
|
|
|
0
|
ok( $cache->is_valid($key), "valid ($desc)" ); |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
# Only bother sleeping and expiring for one of the variants |
362
|
0
|
0
|
|
|
|
0
|
if ( $set_option eq "3 seconds" ) { |
363
|
0
|
|
|
|
|
0
|
sleep(3); |
364
|
0
|
|
|
|
|
0
|
ok( !defined $cache->get($key), "miss after 2 seconds ($desc)" ); |
365
|
0
|
|
|
|
|
0
|
ok( $cache->exists_and_is_expired($key), "is_expired ($desc)" ); |
366
|
0
|
|
|
|
|
0
|
ok( !$cache->is_valid($key), "invalid ($desc)" ); |
367
|
|
|
|
|
|
|
} |
368
|
0
|
|
|
|
|
0
|
}; |
369
|
0
|
|
|
|
|
0
|
$test_expires_shortly->(3); |
370
|
0
|
|
|
|
|
0
|
$test_expires_shortly->("3 seconds"); |
371
|
0
|
|
|
|
|
0
|
$test_expires_shortly->( { expires_at => time + 3 } ); |
372
|
9
|
|
|
9
|
|
4169
|
} |
|
9
|
|
|
|
|
16
|
|
|
9
|
|
|
|
|
48
|
|
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
sub test_expires_later : Tests { |
375
|
7
|
|
|
7
|
0
|
1436
|
my $self = shift; |
376
|
|
|
|
|
|
|
|
377
|
7
|
50
|
|
|
|
45
|
return 'author testing only - timing is unreliable' |
378
|
|
|
|
|
|
|
unless ( $ENV{AUTHOR_TESTING} ); |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
# expires_in default should be ignored |
381
|
0
|
|
|
|
|
0
|
my $cache = $self->new_cache( expires_in => '1s' ); |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
# Expires later (test time) |
384
|
|
|
|
|
|
|
my $test_expires_later = sub { |
385
|
0
|
|
|
0
|
|
0
|
my ($set_option) = @_; |
386
|
0
|
|
|
|
|
0
|
my ( $key, $value ) = $self->kvpair(); |
387
|
0
|
|
|
|
|
0
|
my $desc = "set_option = " . dump_one_line($set_option); |
388
|
0
|
|
|
|
|
0
|
is( $cache->set( $key, $value, $set_option ), $value, "set ($desc)" ); |
389
|
0
|
|
|
|
|
0
|
is( $cache->get($key), $value, "hit ($desc)" ); |
390
|
0
|
|
|
|
|
0
|
my $start_time = time(); |
391
|
0
|
|
|
|
|
0
|
is_between( |
392
|
|
|
|
|
|
|
$cache->get_expires_at($key), |
393
|
|
|
|
|
|
|
$start_time + 3580, |
394
|
|
|
|
|
|
|
$start_time + 3620, |
395
|
|
|
|
|
|
|
"expires_at ($desc)" |
396
|
|
|
|
|
|
|
); |
397
|
0
|
|
|
|
|
0
|
ok( !$cache->exists_and_is_expired($key), "not expired ($desc)" ); |
398
|
0
|
|
|
|
|
0
|
ok( $cache->is_valid($key), "valid ($desc)" ); |
399
|
0
|
|
|
|
|
0
|
local $CHI::Driver::Test_Time = $start_time + 3590; |
400
|
0
|
|
|
|
|
0
|
ok( !$cache->exists_and_is_expired($key), "not expired ($desc)" ); |
401
|
0
|
|
|
|
|
0
|
ok( $cache->is_valid($key), "valid ($desc)" ); |
402
|
0
|
|
|
|
|
0
|
local $CHI::Driver::Test_Time = $start_time + 3610; |
403
|
0
|
|
|
|
|
0
|
ok( !defined $cache->get($key), "miss after 1 hour ($desc)" ); |
404
|
0
|
|
|
|
|
0
|
ok( $cache->exists_and_is_expired($key), "is_expired ($desc)" ); |
405
|
0
|
|
|
|
|
0
|
ok( !$cache->is_valid($key), "invalid ($desc)" ); |
406
|
0
|
|
|
|
|
0
|
}; |
407
|
0
|
|
|
|
|
0
|
$test_expires_later->(3600); |
408
|
0
|
|
|
|
|
0
|
$test_expires_later->("1 hour"); |
409
|
0
|
|
|
|
|
0
|
$test_expires_later->( { expires_at => time + 3600 } ); |
410
|
9
|
|
|
9
|
|
4692
|
} |
|
9
|
|
|
|
|
19
|
|
|
9
|
|
|
|
|
35
|
|
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
sub test_expires_never : Tests { |
413
|
7
|
|
|
7
|
0
|
1677
|
my $self = shift; |
414
|
7
|
|
|
|
|
15
|
my $cache; |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
# Expires never (will fail in 2037) |
417
|
7
|
|
|
|
|
42
|
my ( $key, $value ) = $self->kvpair(); |
418
|
|
|
|
|
|
|
my $test_expires_never = sub { |
419
|
14
|
|
|
14
|
|
37
|
my (@set_options) = @_; |
420
|
14
|
|
|
|
|
393
|
$cache->set( $key, $value, @set_options ); |
421
|
14
|
|
|
|
|
114
|
ok( |
422
|
|
|
|
|
|
|
$cache->get_expires_at($key) > |
423
|
|
|
|
|
|
|
time + Time::Duration::Parse::parse_duration('1 year'), |
424
|
|
|
|
|
|
|
"expires never" |
425
|
|
|
|
|
|
|
); |
426
|
14
|
|
|
|
|
7834
|
ok( !$cache->exists_and_is_expired($key), "not expired" ); |
427
|
14
|
|
|
|
|
5370
|
ok( $cache->is_valid($key), "valid" ); |
428
|
7
|
|
|
|
|
52
|
}; |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
# never is default |
431
|
7
|
|
|
|
|
43
|
$cache = $self->new_cache(); |
432
|
7
|
|
|
|
|
36
|
$test_expires_never->(); |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
# expires_in default should be ignored when never passed to set (RT #67970) |
435
|
7
|
|
|
|
|
2677
|
$cache = $self->new_cache( expires_in => '1s' ); |
436
|
7
|
|
|
|
|
243
|
$test_expires_never->('never'); |
437
|
9
|
|
|
9
|
|
3226
|
} |
|
9
|
|
|
|
|
21
|
|
|
9
|
|
|
|
|
42
|
|
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
sub test_expires_defaults : Tests { |
440
|
7
|
|
|
7
|
0
|
1701
|
my $self = shift; |
441
|
|
|
|
|
|
|
|
442
|
7
|
|
|
|
|
21
|
my $start_time = time(); |
443
|
7
|
|
|
|
|
20
|
local $CHI::Driver::Test_Time = $start_time; |
444
|
7
|
|
|
|
|
14
|
my $cache; |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
my $set_and_confirm_expires_at = sub { |
447
|
28
|
|
|
28
|
|
60
|
my ( $expected_expires_at, $desc ) = @_; |
448
|
28
|
|
|
|
|
123
|
my ( $key, $value ) = $self->kvpair(); |
449
|
28
|
|
|
|
|
472
|
$cache->set( $key, $value ); |
450
|
28
|
|
|
|
|
188
|
is( $cache->get_expires_at($key), $expected_expires_at, $desc ); |
451
|
28
|
|
|
|
|
14044
|
$cache->clear(); |
452
|
7
|
|
|
|
|
45
|
}; |
453
|
|
|
|
|
|
|
|
454
|
7
|
|
|
|
|
41
|
$cache = $self->new_cache( expires_in => 10 ); |
455
|
7
|
|
|
|
|
43
|
$set_and_confirm_expires_at->( |
456
|
|
|
|
|
|
|
$start_time + 10, |
457
|
|
|
|
|
|
|
"after expires_in constructor option" |
458
|
|
|
|
|
|
|
); |
459
|
7
|
|
|
|
|
215
|
$cache->expires_in(20); |
460
|
7
|
|
|
|
|
336
|
$set_and_confirm_expires_at->( $start_time + 20, |
461
|
|
|
|
|
|
|
"after expires_in method" ); |
462
|
|
|
|
|
|
|
|
463
|
7
|
|
|
|
|
60
|
$cache = $self->new_cache( expires_at => $start_time + 30 ); |
464
|
7
|
|
|
|
|
278
|
$set_and_confirm_expires_at->( |
465
|
|
|
|
|
|
|
$start_time + 30, |
466
|
|
|
|
|
|
|
"after expires_at constructor option" |
467
|
|
|
|
|
|
|
); |
468
|
7
|
|
|
|
|
53
|
$cache->expires_at( $start_time + 40 ); |
469
|
7
|
|
|
|
|
28
|
$set_and_confirm_expires_at->( $start_time + 40, |
470
|
|
|
|
|
|
|
"after expires_at method" ); |
471
|
9
|
|
|
9
|
|
3054
|
} |
|
9
|
|
|
|
|
14
|
|
|
9
|
|
|
|
|
37
|
|
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
sub test_expires_manually : Tests { |
474
|
7
|
|
|
7
|
0
|
1235
|
my $self = shift; |
475
|
7
|
|
|
|
|
19
|
my $cache = $self->{cache}; |
476
|
|
|
|
|
|
|
|
477
|
7
|
|
|
|
|
40
|
my ( $key, $value ) = $self->kvpair(); |
478
|
7
|
|
|
|
|
17
|
my $desc = "expires manually"; |
479
|
7
|
|
|
|
|
148
|
$cache->set( $key, $value ); |
480
|
7
|
|
|
|
|
130
|
is( $cache->get($key), $value, "hit ($desc)" ); |
481
|
7
|
|
|
|
|
3595
|
$cache->expire($key); |
482
|
7
|
|
|
|
|
124
|
ok( !defined $cache->get($key), "miss after expire ($desc)" ); |
483
|
7
|
|
|
|
|
2856
|
ok( !$cache->is_valid($key), "invalid after expire ($desc)" ); |
484
|
9
|
|
|
9
|
|
2884
|
} |
|
9
|
|
|
|
|
16
|
|
|
9
|
|
|
|
|
47
|
|
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
sub test_expires_conditionally : Tests { |
487
|
7
|
|
|
7
|
0
|
1893
|
my $self = shift; |
488
|
7
|
|
|
|
|
26
|
my $cache = $self->{cache}; |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
# Expires conditionally |
491
|
|
|
|
|
|
|
my $test_expires_conditionally = sub { |
492
|
28
|
|
|
28
|
|
68
|
my ( $code, $cond_desc, $expect_expire ) = @_; |
493
|
|
|
|
|
|
|
|
494
|
28
|
|
|
|
|
168
|
my ( $key, $value ) = $self->kvpair(); |
495
|
28
|
|
|
|
|
79
|
my $desc = "expires conditionally ($cond_desc)"; |
496
|
28
|
|
|
|
|
514
|
$cache->set( $key, $value ); |
497
|
28
|
100
|
|
|
|
404
|
is( |
498
|
|
|
|
|
|
|
$cache->get( $key, expire_if => $code ), |
499
|
|
|
|
|
|
|
$expect_expire ? undef : $value, |
500
|
|
|
|
|
|
|
"get result ($desc)" |
501
|
|
|
|
|
|
|
); |
502
|
|
|
|
|
|
|
|
503
|
28
|
|
|
|
|
15384
|
is( $cache->get($key), $value, "hit after expire_if ($desc)" ); |
504
|
|
|
|
|
|
|
|
505
|
7
|
|
|
|
|
49
|
}; |
506
|
7
|
|
|
|
|
21
|
my $time = time(); |
507
|
7
|
|
|
8
|
|
39
|
$test_expires_conditionally->( sub { 1 }, 'true', 1 ); |
|
8
|
|
|
|
|
29
|
|
508
|
7
|
|
|
7
|
|
3139
|
$test_expires_conditionally->( sub { 0 }, 'false', 0 ); |
|
7
|
|
|
|
|
28
|
|
509
|
|
|
|
|
|
|
$test_expires_conditionally->( |
510
|
8
|
|
|
8
|
|
41
|
sub { $_[0]->created_at >= $time }, |
511
|
7
|
|
|
|
|
3235
|
'created_at >= now', 1 |
512
|
|
|
|
|
|
|
); |
513
|
|
|
|
|
|
|
$test_expires_conditionally->( |
514
|
7
|
|
|
7
|
|
32
|
sub { $_[0]->created_at < $time }, |
515
|
7
|
|
|
|
|
3484
|
'created_at < now', 0 |
516
|
|
|
|
|
|
|
); |
517
|
9
|
|
|
9
|
|
3919
|
} |
|
9
|
|
|
|
|
16
|
|
|
9
|
|
|
|
|
40
|
|
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
sub test_expires_variance : Tests { |
520
|
7
|
|
|
7
|
0
|
1393
|
my $self = shift; |
521
|
7
|
|
|
|
|
21
|
my $cache = $self->{cache}; |
522
|
|
|
|
|
|
|
|
523
|
7
|
|
|
|
|
16
|
my $start_time = time(); |
524
|
7
|
|
|
|
|
18
|
my $expires_at = $start_time + 10; |
525
|
7
|
|
|
|
|
45
|
my ( $key, $value ) = $self->kvpair(); |
526
|
7
|
|
|
|
|
188
|
$cache->set( $key, $value, |
527
|
|
|
|
|
|
|
{ expires_at => $expires_at, expires_variance => 0.5 } ); |
528
|
7
|
|
|
|
|
91
|
is( $cache->get_object($key)->expires_at(), |
529
|
|
|
|
|
|
|
$expires_at, "expires_at = $start_time" ); |
530
|
7
|
|
|
|
|
3516
|
is( |
531
|
|
|
|
|
|
|
$cache->get_object($key)->early_expires_at(), |
532
|
|
|
|
|
|
|
$start_time + 5, |
533
|
|
|
|
|
|
|
"early_expires_at = $start_time + 5" |
534
|
|
|
|
|
|
|
); |
535
|
|
|
|
|
|
|
|
536
|
7
|
|
|
|
|
3068
|
my %expire_count; |
537
|
7
|
|
|
|
|
43
|
for ( my $time = $start_time + 3 ; $time <= $expires_at + 1 ; $time++ ) { |
538
|
63
|
|
|
|
|
129
|
local $CHI::Driver::Test_Time = $time; |
539
|
63
|
|
|
|
|
155
|
for ( my $i = 0 ; $i < 100 ; $i++ ) { |
540
|
6300
|
100
|
|
|
|
71755
|
if ( !defined $cache->get($key) ) { |
541
|
2755
|
|
|
|
|
7722
|
$expire_count{$time}++; |
542
|
|
|
|
|
|
|
} |
543
|
|
|
|
|
|
|
} |
544
|
|
|
|
|
|
|
} |
545
|
7
|
|
|
|
|
41
|
for ( my $time = $start_time + 3 ; $time <= $start_time + 5 ; $time++ ) { |
546
|
21
|
|
|
|
|
7595
|
ok( !$expire_count{$time}, "got no expires at $time" ); |
547
|
|
|
|
|
|
|
} |
548
|
7
|
|
|
|
|
2647
|
for ( my $time = $start_time + 7 ; $time <= $start_time + 8 ; $time++ ) { |
549
|
14
|
|
33
|
|
|
2829
|
ok( $expire_count{$time} > 0 && $expire_count{$time} < 100, |
550
|
|
|
|
|
|
|
"got some expires at $time" ); |
551
|
|
|
|
|
|
|
} |
552
|
7
|
|
|
|
|
2718
|
for ( my $time = $expires_at ; $time <= $expires_at + 1 ; $time++ ) { |
553
|
14
|
|
|
|
|
2772
|
ok( $expire_count{$time} == 100, "got all expires at $time" ); |
554
|
|
|
|
|
|
|
} |
555
|
9
|
|
|
9
|
|
4233
|
} |
|
9
|
|
|
|
|
16
|
|
|
9
|
|
|
|
|
39
|
|
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
sub test_not_in_cache : Tests { |
558
|
7
|
|
|
7
|
0
|
1510
|
my $self = shift; |
559
|
7
|
|
|
|
|
22
|
my $cache = $self->{cache}; |
560
|
|
|
|
|
|
|
|
561
|
7
|
|
|
|
|
91
|
ok( !defined $cache->get_object('not in cache') ); |
562
|
7
|
|
|
|
|
3343
|
ok( !defined $cache->get_expires_at('not in cache') ); |
563
|
7
|
|
|
|
|
2326
|
ok( !$cache->is_valid('not in cache') ); |
564
|
9
|
|
|
9
|
|
2691
|
} |
|
9
|
|
|
|
|
18
|
|
|
9
|
|
|
|
|
70
|
|
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
sub test_serialize : Tests { |
567
|
6
|
|
|
6
|
0
|
1381
|
my $self = shift; |
568
|
6
|
|
|
|
|
19
|
my $cache = $self->{cache}; |
569
|
6
|
|
|
|
|
76
|
$self->num_tests( $self->{key_count} ); |
570
|
|
|
|
|
|
|
|
571
|
6
|
|
|
|
|
647
|
$self->set_some_keys($cache); |
572
|
4
|
|
|
|
|
8
|
foreach my $keyname ( @{ $self->{keynames} } ) { |
|
4
|
|
|
|
|
15
|
|
573
|
52
|
100
|
100
|
|
|
16365
|
my $expect_transformed = |
|
|
100
|
|
|
|
|
|
574
|
|
|
|
|
|
|
( $keyname eq 'arrayref' || $keyname eq 'hashref' ) ? 1 |
575
|
|
|
|
|
|
|
: ( $keyname eq 'utf8' ) ? 2 |
576
|
|
|
|
|
|
|
: 0; |
577
|
52
|
|
|
|
|
245
|
is( |
578
|
|
|
|
|
|
|
$cache->get_object( $self->{keys}->{$keyname} )->_is_transformed(), |
579
|
|
|
|
|
|
|
$expect_transformed, |
580
|
|
|
|
|
|
|
"is_transformed = $expect_transformed ($keyname)" |
581
|
|
|
|
|
|
|
); |
582
|
|
|
|
|
|
|
} |
583
|
9
|
|
|
9
|
|
2825
|
} |
|
9
|
|
|
|
|
16
|
|
|
9
|
|
|
|
|
82
|
|
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
{ |
586
|
|
|
|
|
|
|
package DummySerializer; |
587
|
|
|
|
|
|
|
$DummySerializer::VERSION = '0.60'; |
588
|
0
|
|
|
0
|
|
0
|
sub serialize { } |
589
|
0
|
|
|
0
|
|
0
|
sub deserialize { } |
590
|
|
|
|
|
|
|
} |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
sub test_serializers : Tests { |
593
|
6
|
|
|
6
|
0
|
1455
|
my ($self) = @_; |
594
|
|
|
|
|
|
|
|
595
|
6
|
50
|
|
|
|
35
|
unless ( can_load('Data::Serializer') ) { |
596
|
6
|
|
|
|
|
87
|
$self->num_tests(1); |
597
|
6
|
|
|
|
|
748
|
return 'Data::Serializer not installed'; |
598
|
|
|
|
|
|
|
} |
599
|
|
|
|
|
|
|
|
600
|
0
|
|
|
|
|
0
|
my @modes = (qw(string hash object)); |
601
|
0
|
|
|
|
|
0
|
my @variants = (qw(Storable Data::Dumper YAML)); |
602
|
0
|
|
|
|
|
0
|
@variants = grep { can_load($_) } @variants; |
|
0
|
|
|
|
|
0
|
|
603
|
0
|
|
|
|
|
0
|
ok( scalar(@variants), "some variants ok" ); |
604
|
|
|
|
|
|
|
|
605
|
0
|
|
|
|
|
0
|
my $initial_count = 5; |
606
|
0
|
|
|
|
|
0
|
my $test_key_types_count = $self->{key_count}; |
607
|
0
|
|
|
|
|
0
|
my $test_count = $initial_count + |
608
|
|
|
|
|
|
|
scalar(@variants) * scalar(@modes) * ( 1 + $test_key_types_count ); |
609
|
|
|
|
|
|
|
|
610
|
0
|
|
|
|
|
0
|
my $cache1 = $self->new_cache(); |
611
|
0
|
|
|
|
|
0
|
isa_ok( $cache1->serializer, 'CHI::Serializer::Storable' ); |
612
|
0
|
|
|
|
|
0
|
my $cache2 = $self->new_cache(); |
613
|
0
|
|
|
|
|
0
|
is( $cache1->serializer, $cache2->serializer, |
614
|
|
|
|
|
|
|
'same serializer returned from two objects' ); |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
throws_ok( |
617
|
|
|
|
|
|
|
sub { |
618
|
0
|
|
|
0
|
|
0
|
$self->new_cache( serializer => [1] ); |
619
|
|
|
|
|
|
|
}, |
620
|
0
|
|
|
|
|
0
|
qr/Validation failed for|isa check for ".*?" failed/, |
621
|
|
|
|
|
|
|
"invalid serializer" |
622
|
|
|
|
|
|
|
); |
623
|
|
|
|
|
|
|
lives_ok( |
624
|
0
|
|
|
0
|
|
0
|
sub { $self->new_cache( serializer => bless( {}, 'DummySerializer' ) ) } |
625
|
|
|
|
|
|
|
, |
626
|
0
|
|
|
|
|
0
|
"valid dummy serializer" |
627
|
|
|
|
|
|
|
); |
628
|
|
|
|
|
|
|
|
629
|
0
|
|
|
|
|
0
|
foreach my $mode (@modes) { |
630
|
0
|
|
|
|
|
0
|
foreach my $variant (@variants) { |
631
|
0
|
0
|
|
|
|
0
|
my $serializer_param = ( |
|
|
0
|
|
|
|
|
|
632
|
|
|
|
|
|
|
$mode eq 'string' ? $variant |
633
|
|
|
|
|
|
|
: $mode eq 'hash' ? { serializer => $variant } |
634
|
|
|
|
|
|
|
: Data::Serializer->new( serializer => $variant ) |
635
|
|
|
|
|
|
|
); |
636
|
0
|
|
|
|
|
0
|
my $cache = $self->new_cache( serializer => $serializer_param ); |
637
|
0
|
|
|
|
|
0
|
is( $cache->serializer->serializer, |
638
|
|
|
|
|
|
|
$variant, "serializer = $variant, mode = $mode" ); |
639
|
0
|
|
|
|
|
0
|
$self->{cache} = $cache; |
640
|
|
|
|
|
|
|
|
641
|
0
|
|
|
|
|
0
|
foreach my $keyname ( @{ $self->{keynames} } ) { |
|
0
|
|
|
|
|
0
|
|
642
|
0
|
|
|
|
|
0
|
my $key = $self->{keys}->{$keyname}; |
643
|
0
|
|
|
|
|
0
|
my $value = $self->{values}->{$keyname}; |
644
|
0
|
|
|
|
|
0
|
$cache->set( $key, $value ); |
645
|
0
|
|
|
|
|
0
|
cmp_deeply( $cache->get($key), $value, |
646
|
|
|
|
|
|
|
"hit for key '$keyname'" ); |
647
|
|
|
|
|
|
|
} |
648
|
|
|
|
|
|
|
|
649
|
0
|
|
|
|
|
0
|
$self->num_tests($test_count); |
650
|
|
|
|
|
|
|
} |
651
|
|
|
|
|
|
|
} |
652
|
9
|
|
|
9
|
|
5749
|
} |
|
9
|
|
|
|
|
17
|
|
|
9
|
|
|
|
|
54
|
|
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
sub test_namespaces : Tests { |
655
|
7
|
|
|
7
|
0
|
1464
|
my $self = shift; |
656
|
7
|
|
|
|
|
25
|
my $cache = $self->{cache}; |
657
|
|
|
|
|
|
|
|
658
|
7
|
|
|
|
|
36
|
my $cache0 = $self->new_cache(); |
659
|
7
|
|
|
|
|
127
|
is( $cache0->namespace, 'Default', 'namespace defaults to "Default"' ); |
660
|
|
|
|
|
|
|
|
661
|
7
|
|
|
|
|
2868
|
my ( $ns1, $ns2, $ns3 ) = ( 'ns1', 'ns2', 'ns3' ); |
662
|
28
|
|
|
|
|
86
|
my ( $cache1, $cache1a, $cache2, $cache3 ) = |
663
|
7
|
|
|
|
|
25
|
map { $self->new_cache( namespace => $_ ) } ( $ns1, $ns1, $ns2, $ns3 ); |
664
|
28
|
|
|
|
|
125
|
cmp_deeply( |
665
|
7
|
|
|
|
|
26
|
[ map { $_->namespace } ( $cache1, $cache1a, $cache2, $cache3 ) ], |
666
|
|
|
|
|
|
|
[ $ns1, $ns1, $ns2, $ns3 ], |
667
|
|
|
|
|
|
|
'cache->namespace()' |
668
|
|
|
|
|
|
|
); |
669
|
7
|
|
|
|
|
11101
|
$self->set_some_keys($cache1); |
670
|
5
|
|
|
|
|
109
|
cmp_deeply( |
671
|
|
|
|
|
|
|
$cache1->dump_as_hash(), |
672
|
|
|
|
|
|
|
$cache1a->dump_as_hash(), |
673
|
|
|
|
|
|
|
'cache1 and cache1a are same cache' |
674
|
|
|
|
|
|
|
); |
675
|
5
|
|
|
|
|
18243
|
cmp_deeply( [ $cache2->get_keys() ], |
676
|
|
|
|
|
|
|
[], 'cache2 empty after setting keys in cache1' ); |
677
|
5
|
|
|
|
|
5655
|
$cache3->set( $self->{keys}->{medium}, 'different' ); |
678
|
5
|
|
|
|
|
69
|
is( |
679
|
|
|
|
|
|
|
$cache1->get('medium'), |
680
|
|
|
|
|
|
|
$self->{values}->{medium}, |
681
|
|
|
|
|
|
|
'cache1{medium} = medium' |
682
|
|
|
|
|
|
|
); |
683
|
5
|
|
|
|
|
2116
|
is( $cache3->get('medium'), 'different', 'cache1{medium} = different' ); |
684
|
|
|
|
|
|
|
|
685
|
5
|
50
|
|
|
|
1583
|
if ( $self->supports_get_namespaces() ) { |
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
# get_namespaces may or may not automatically include empty namespaces |
688
|
5
|
|
|
|
|
211
|
cmp_deeply( |
689
|
|
|
|
|
|
|
[ $cache1->get_namespaces() ], |
690
|
|
|
|
|
|
|
supersetof( $ns1, $ns3 ), |
691
|
|
|
|
|
|
|
"get_namespaces contains $ns1 and $ns3" |
692
|
|
|
|
|
|
|
); |
693
|
|
|
|
|
|
|
|
694
|
5
|
|
|
|
|
7141
|
foreach my $c ( $cache0, $cache1, $cache1a, $cache2, $cache3 ) { |
695
|
25
|
|
|
|
|
54258
|
cmp_set( |
696
|
|
|
|
|
|
|
[ $cache->get_namespaces() ], |
697
|
|
|
|
|
|
|
[ $c->get_namespaces() ], |
698
|
|
|
|
|
|
|
'get_namespaces the same regardless of which cache asks' |
699
|
|
|
|
|
|
|
); |
700
|
|
|
|
|
|
|
} |
701
|
|
|
|
|
|
|
} |
702
|
|
|
|
|
|
|
else { |
703
|
|
|
|
|
|
|
throws_ok( |
704
|
0
|
|
|
0
|
|
0
|
sub { $cache1->get_namespaces() }, |
705
|
0
|
|
|
|
|
0
|
qr/not supported/, |
706
|
|
|
|
|
|
|
"get_namespaces not supported" |
707
|
|
|
|
|
|
|
); |
708
|
0
|
|
|
|
|
0
|
SKIP: { skip "get_namespaces not supported", 5 } |
|
0
|
|
|
|
|
0
|
|
709
|
|
|
|
|
|
|
} |
710
|
9
|
|
|
9
|
|
4361
|
} |
|
9
|
|
|
|
|
18
|
|
|
9
|
|
|
|
|
37
|
|
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
sub test_persist : Tests { |
713
|
7
|
|
|
7
|
0
|
1691
|
my $self = shift; |
714
|
7
|
|
|
|
|
23
|
my $cache = $self->{cache}; |
715
|
|
|
|
|
|
|
|
716
|
7
|
|
|
|
|
13
|
my $hash; |
717
|
|
|
|
|
|
|
{ |
718
|
7
|
|
|
|
|
13
|
my $cache1 = $self->new_cache(); |
|
7
|
|
|
|
|
36
|
|
719
|
7
|
|
|
|
|
66
|
$self->set_some_keys($cache1); |
720
|
5
|
|
|
|
|
75
|
$hash = $cache1->dump_as_hash(); |
721
|
|
|
|
|
|
|
} |
722
|
5
|
|
|
|
|
31
|
my $cache2 = $self->new_cache(); |
723
|
5
|
|
|
|
|
32
|
cmp_deeply( |
724
|
|
|
|
|
|
|
$hash, |
725
|
|
|
|
|
|
|
$cache2->dump_as_hash(), |
726
|
|
|
|
|
|
|
'cache persisted between cache object creations' |
727
|
|
|
|
|
|
|
); |
728
|
9
|
|
|
9
|
|
2371
|
} |
|
9
|
|
|
|
|
17
|
|
|
9
|
|
|
|
|
58
|
|
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
sub test_multi : Tests { |
731
|
7
|
|
|
7
|
0
|
1557
|
my $self = shift; |
732
|
7
|
|
|
|
|
26
|
my $cache = $self->{cache}; |
733
|
|
|
|
|
|
|
|
734
|
7
|
|
|
|
|
39
|
my ( $keys, $values, $keynames ) = |
735
|
|
|
|
|
|
|
( $self->{keys}, $self->{values}, $self->{keynames} ); |
736
|
|
|
|
|
|
|
|
737
|
7
|
|
|
|
|
14
|
my @ordered_keys = map { $keys->{$_} } @{$keynames}; |
|
91
|
|
|
|
|
167
|
|
|
7
|
|
|
|
|
22
|
|
738
|
91
|
|
|
|
|
153
|
my @ordered_values = |
739
|
7
|
|
|
|
|
22
|
map { $values->{$_} } @{$keynames}; |
|
7
|
|
|
|
|
18
|
|
740
|
77
|
|
|
|
|
194
|
my %ordered_scalar_key_values = |
741
|
91
|
|
|
|
|
126
|
map { ( $keys->{$_}, $values->{$_} ) } |
742
|
7
|
|
|
|
|
21
|
grep { !ref( $keys->{$_} ) } @{$keynames}; |
|
7
|
|
|
|
|
18
|
|
743
|
|
|
|
|
|
|
|
744
|
7
|
|
|
|
|
141
|
cmp_deeply( $cache->get_multi_arrayref( ['foo'] ), |
745
|
|
|
|
|
|
|
[undef], "get_multi_arrayref before set" ); |
746
|
|
|
|
|
|
|
|
747
|
7
|
|
|
|
|
9902
|
$cache->set_multi( \%ordered_scalar_key_values ); |
748
|
5
|
|
|
|
|
79
|
$cache->set( $keys->{arrayref}, $values->{arrayref} ); |
749
|
5
|
|
|
|
|
55
|
$cache->set( $keys->{hashref}, $values->{hashref} ); |
750
|
|
|
|
|
|
|
|
751
|
5
|
|
|
|
|
29
|
cmp_deeply( $cache->get_multi_arrayref( \@ordered_keys ), |
752
|
|
|
|
|
|
|
\@ordered_values, "get_multi_arrayref" ); |
753
|
5
|
|
|
|
|
15479
|
cmp_deeply( $cache->get( $ordered_keys[0] ), |
754
|
|
|
|
|
|
|
$ordered_values[0], "get one after set_multi" ); |
755
|
5
|
|
|
|
|
2078
|
cmp_deeply( |
756
|
|
|
|
|
|
|
$cache->get_multi_arrayref( [ reverse @ordered_keys ] ), |
757
|
|
|
|
|
|
|
[ reverse @ordered_values ], |
758
|
|
|
|
|
|
|
"get_multi_arrayref" |
759
|
|
|
|
|
|
|
); |
760
|
65
|
|
|
|
|
207
|
cmp_deeply( |
761
|
5
|
|
|
|
|
15451
|
$cache->get_multi_hashref( [ grep { !ref($_) } @ordered_keys ] ), |
762
|
|
|
|
|
|
|
\%ordered_scalar_key_values, "get_multi_hashref" ); |
763
|
5
|
|
|
|
|
6791
|
cmp_set( |
764
|
|
|
|
|
|
|
[ $cache->get_keys ], |
765
|
|
|
|
|
|
|
[ $self->process_keys( $cache, @ordered_keys ) ], |
766
|
|
|
|
|
|
|
"get_keys after set_multi" |
767
|
|
|
|
|
|
|
); |
768
|
|
|
|
|
|
|
|
769
|
5
|
|
|
|
|
65808
|
$cache->remove_multi( \@ordered_keys ); |
770
|
5
|
|
|
|
|
33
|
cmp_deeply( |
771
|
|
|
|
|
|
|
$cache->get_multi_arrayref( \@ordered_keys ), |
772
|
|
|
|
|
|
|
[ (undef) x scalar(@ordered_values) ], |
773
|
|
|
|
|
|
|
"get_multi_arrayref after remove_multi" |
774
|
|
|
|
|
|
|
); |
775
|
5
|
|
|
|
|
6316
|
cmp_set( [ $cache->get_keys ], [], "get_keys after remove_multi" ); |
776
|
9
|
|
|
9
|
|
4320
|
} |
|
9
|
|
|
|
|
14
|
|
|
9
|
|
|
|
|
76
|
|
777
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
sub test_multi_no_keys : Tests { |
779
|
7
|
|
|
7
|
0
|
1577
|
my $self = shift; |
780
|
7
|
|
|
|
|
21
|
my $cache = $self->{cache}; |
781
|
|
|
|
|
|
|
|
782
|
7
|
|
|
|
|
125
|
cmp_deeply( $cache->get_multi_arrayref( [] ), |
783
|
|
|
|
|
|
|
[], "get_multi_arrayref (no args)" ); |
784
|
7
|
|
|
|
|
9189
|
cmp_deeply( $cache->get_multi_hashref( [] ), |
785
|
|
|
|
|
|
|
{}, "get_multi_hashref (no args)" ); |
786
|
7
|
|
|
7
|
|
12913
|
lives_ok { $cache->set_multi( {} ) } "set_multi (no args)"; |
|
7
|
|
|
|
|
332
|
|
787
|
7
|
|
|
7
|
|
2113
|
lives_ok { $cache->remove_multi( [] ) } "remove_multi (no args)"; |
|
7
|
|
|
|
|
203
|
|
788
|
9
|
|
|
9
|
|
2850
|
} |
|
9
|
|
|
|
|
20
|
|
|
9
|
|
|
|
|
38
|
|
789
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
sub test_l1_cache : Tests { |
791
|
5
|
|
|
5
|
0
|
1114
|
my $self = shift; |
792
|
5
|
|
|
|
|
18
|
my @keys = map { "key$_" } ( 0 .. 2 ); |
|
15
|
|
|
|
|
50
|
|
793
|
5
|
|
|
|
|
18
|
my @values = map { "value$_" } ( 0 .. 2 ); |
|
15
|
|
|
|
|
41
|
|
794
|
5
|
|
|
|
|
12
|
my ( $cache, $l1_cache ); |
795
|
|
|
|
|
|
|
|
796
|
5
|
50
|
|
|
|
31
|
return "skipping - no support for clear" unless $self->supports_clear(); |
797
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
my $test_l1_cache = sub { |
799
|
|
|
|
|
|
|
|
800
|
10
|
|
|
10
|
|
175
|
is( $l1_cache->subcache_type, "l1_cache", "subcache_type = l1_cache" ); |
801
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
# Get on cache should populate l1 cache |
803
|
|
|
|
|
|
|
# |
804
|
10
|
|
|
|
|
3348
|
$cache->set( $keys[0], $values[0] ); |
805
|
10
|
|
|
|
|
171
|
$l1_cache->clear(); |
806
|
10
|
|
|
|
|
152
|
ok( !$l1_cache->get( $keys[0] ), "l1 miss after clear" ); |
807
|
10
|
|
|
|
|
4171
|
is( $cache->get( $keys[0] ), |
808
|
|
|
|
|
|
|
$values[0], "primary hit after primary set" ); |
809
|
10
|
|
|
|
|
3491
|
is( $l1_cache->get( $keys[0] ), $values[0], |
810
|
|
|
|
|
|
|
"l1 hit after primary get" ); |
811
|
|
|
|
|
|
|
|
812
|
|
|
|
|
|
|
# Primary cache should be reading l1 cache first |
813
|
|
|
|
|
|
|
# |
814
|
10
|
|
|
|
|
3032
|
$l1_cache->set( $keys[0], $values[1] ); |
815
|
10
|
|
|
|
|
208
|
is( $cache->get( $keys[0] ), |
816
|
|
|
|
|
|
|
$values[1], "got new value set explicitly in l1 cache" ); |
817
|
10
|
|
|
|
|
3042
|
$l1_cache->remove( $keys[0] ); |
818
|
10
|
|
|
|
|
244
|
is( $cache->get( $keys[0] ), $values[0], "got old value again" ); |
819
|
|
|
|
|
|
|
|
820
|
10
|
|
|
|
|
3056
|
$cache->clear(); |
821
|
10
|
|
|
|
|
292
|
ok( !$cache->get( $keys[0] ), "miss after clear" ); |
822
|
10
|
|
|
|
|
2798
|
ok( !$l1_cache->get( $keys[0] ), "miss after clear" ); |
823
|
|
|
|
|
|
|
|
824
|
|
|
|
|
|
|
# get_multi_* - one from l1 cache, one from primary cache, one miss |
825
|
|
|
|
|
|
|
# |
826
|
10
|
|
|
|
|
2744
|
$cache->set( $keys[0], $values[0] ); |
827
|
10
|
|
|
|
|
271
|
$cache->set( $keys[1], $values[1] ); |
828
|
10
|
|
|
|
|
250
|
$l1_cache->remove( $keys[0] ); |
829
|
10
|
|
|
|
|
43
|
$l1_cache->set( $keys[1], $values[2] ); |
830
|
|
|
|
|
|
|
|
831
|
10
|
|
|
|
|
323
|
cmp_deeply( |
832
|
|
|
|
|
|
|
$cache->get_multi_arrayref( [ $keys[0], $keys[1], $keys[2] ] ), |
833
|
|
|
|
|
|
|
[ $values[0], $values[2], undef ], |
834
|
|
|
|
|
|
|
"get_multi_arrayref" |
835
|
|
|
|
|
|
|
); |
836
|
10
|
|
|
|
|
11978
|
cmp_deeply( |
837
|
|
|
|
|
|
|
$cache->get_multi_hashref( [ $keys[0], $keys[1], $keys[2] ] ), |
838
|
|
|
|
|
|
|
{ |
839
|
|
|
|
|
|
|
$keys[0] => $values[0], |
840
|
|
|
|
|
|
|
$keys[1] => $values[2], |
841
|
|
|
|
|
|
|
$keys[2] => undef |
842
|
|
|
|
|
|
|
}, |
843
|
|
|
|
|
|
|
"get_multi_hashref" |
844
|
|
|
|
|
|
|
); |
845
|
|
|
|
|
|
|
|
846
|
10
|
|
|
|
|
16580
|
$self->_test_logging_with_l1_cache( $cache, $l1_cache ); |
847
|
|
|
|
|
|
|
|
848
|
10
|
|
|
|
|
2817
|
$self->_test_common_subcache_features( $cache, $l1_cache, 'l1_cache' ); |
849
|
5
|
|
|
|
|
32
|
}; |
850
|
|
|
|
|
|
|
|
851
|
|
|
|
|
|
|
# Test with current cache in primary position... |
852
|
|
|
|
|
|
|
# |
853
|
5
|
|
|
|
|
43
|
$cache = |
854
|
|
|
|
|
|
|
$self->new_cache( l1_cache => { driver => 'Memory', datastore => {} } ); |
855
|
5
|
|
|
|
|
58
|
$l1_cache = $cache->l1_cache; |
856
|
5
|
|
|
|
|
647
|
isa_ok( $cache, $self->testing_driver_class, 'cache' ); |
857
|
5
|
|
|
|
|
2990
|
isa_ok( $l1_cache, 'CHI::Driver::Memory', 'l1_cache' ); |
858
|
5
|
|
|
|
|
1668
|
$test_l1_cache->(); |
859
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
# and in l1 position |
861
|
|
|
|
|
|
|
# |
862
|
5
|
|
|
|
|
1797
|
$cache = $self->testing_chi_root_class->new( |
863
|
|
|
|
|
|
|
driver => 'Memory', |
864
|
|
|
|
|
|
|
datastore => {}, |
865
|
|
|
|
|
|
|
l1_cache => { $self->new_cache_options() } |
866
|
|
|
|
|
|
|
); |
867
|
5
|
|
|
|
|
265
|
$l1_cache = $cache->l1_cache; |
868
|
5
|
|
|
|
|
677
|
isa_ok( $cache, 'CHI::Driver::Memory', 'cache' ); |
869
|
5
|
|
|
|
|
2297
|
isa_ok( $l1_cache, $self->testing_driver_class, 'l1_cache' ); |
870
|
5
|
|
|
|
|
1408
|
$test_l1_cache->(); |
871
|
9
|
|
|
9
|
|
5299
|
} |
|
9
|
|
|
|
|
18
|
|
|
9
|
|
|
|
|
39
|
|
872
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
sub test_mirror_cache : Tests { |
874
|
5
|
|
|
5
|
0
|
814
|
my $self = shift; |
875
|
5
|
|
|
|
|
10
|
my ( $cache, $mirror_cache ); |
876
|
5
|
|
|
|
|
29
|
my ( $key, $value, $key2, $value2 ) = $self->kvpair(2); |
877
|
|
|
|
|
|
|
|
878
|
5
|
50
|
|
|
|
23
|
return "skipping - no support for clear" unless $self->supports_clear(); |
879
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
my $test_mirror_cache = sub { |
881
|
|
|
|
|
|
|
|
882
|
10
|
|
|
10
|
|
114
|
is( $mirror_cache->subcache_type, "mirror_cache" ); |
883
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
# Get on either cache should not populate the other, and should not be able to see |
885
|
|
|
|
|
|
|
# mirror keys from regular cache |
886
|
|
|
|
|
|
|
# |
887
|
10
|
|
|
|
|
3539
|
$cache->set( $key, $value ); |
888
|
10
|
|
|
|
|
323
|
$mirror_cache->remove($key); |
889
|
10
|
|
|
|
|
303
|
$cache->get($key); |
890
|
10
|
|
|
|
|
99
|
ok( !$mirror_cache->get($key), "key not in mirror_cache" ); |
891
|
|
|
|
|
|
|
|
892
|
10
|
|
|
|
|
4232
|
$mirror_cache->set( $key2, $value2 ); |
893
|
10
|
|
|
|
|
201
|
ok( !$cache->get($key2), "key2 not in cache" ); |
894
|
|
|
|
|
|
|
|
895
|
10
|
|
|
|
|
3313
|
$self->_test_logging_with_mirror_cache( $cache, $mirror_cache ); |
896
|
|
|
|
|
|
|
|
897
|
10
|
|
|
|
|
3105
|
$self->_test_common_subcache_features( $cache, $mirror_cache, |
898
|
|
|
|
|
|
|
'mirror_cache' ); |
899
|
5
|
|
|
|
|
24
|
}; |
900
|
|
|
|
|
|
|
|
901
|
|
|
|
|
|
|
my $file_cache_options = sub { |
902
|
10
|
|
|
10
|
|
66
|
my $root_dir = |
903
|
|
|
|
|
|
|
tempdir( "chi-test-mirror-cache-XXXX", TMPDIR => 1, CLEANUP => 1 ); |
904
|
10
|
|
|
|
|
4660
|
return ( driver => 'File', root_dir => $root_dir, depth => 3 ); |
905
|
5
|
|
|
|
|
19
|
}; |
906
|
|
|
|
|
|
|
|
907
|
|
|
|
|
|
|
# Test with current cache in primary position... |
908
|
|
|
|
|
|
|
# |
909
|
5
|
|
|
|
|
17
|
$cache = $self->new_cache( mirror_cache => { $file_cache_options->() } ); |
910
|
5
|
|
|
|
|
44
|
$mirror_cache = $cache->mirror_cache; |
911
|
5
|
|
|
|
|
591
|
isa_ok( $cache, $self->testing_driver_class ); |
912
|
5
|
|
|
|
|
2791
|
isa_ok( $mirror_cache, 'CHI::Driver::File' ); |
913
|
5
|
|
|
|
|
1806
|
$test_mirror_cache->(); |
914
|
|
|
|
|
|
|
|
915
|
|
|
|
|
|
|
# and in mirror position |
916
|
|
|
|
|
|
|
# |
917
|
5
|
|
|
|
|
1703
|
$cache = |
918
|
|
|
|
|
|
|
$self->testing_chi_root_class->new( $file_cache_options->(), |
919
|
|
|
|
|
|
|
mirror_cache => { $self->new_cache_options() } ); |
920
|
5
|
|
|
|
|
253
|
$mirror_cache = $cache->mirror_cache; |
921
|
5
|
|
|
|
|
662
|
isa_ok( $cache, 'CHI::Driver::File' ); |
922
|
5
|
|
|
|
|
2404
|
isa_ok( $mirror_cache, $self->testing_driver_class ); |
923
|
5
|
|
|
|
|
1678
|
$test_mirror_cache->(); |
924
|
9
|
|
|
9
|
|
3929
|
} |
|
9
|
|
|
|
|
13
|
|
|
9
|
|
|
|
|
63
|
|
925
|
|
|
|
|
|
|
|
926
|
|
|
|
|
|
|
sub test_subcache_overridable_params : Tests { |
927
|
6
|
|
|
6
|
0
|
1236
|
my ($self) = @_; |
928
|
|
|
|
|
|
|
|
929
|
6
|
|
|
|
|
16
|
my $cache; |
930
|
|
|
|
|
|
|
warning_like { |
931
|
6
|
|
|
6
|
|
332
|
$cache = $self->new_cache( |
932
|
|
|
|
|
|
|
l1_cache => { |
933
|
|
|
|
|
|
|
driver => 'Memory', |
934
|
|
|
|
|
|
|
on_get_error => 'log', |
935
|
|
|
|
|
|
|
datastore => {}, |
936
|
|
|
|
|
|
|
expires_variance => 0.5, |
937
|
|
|
|
|
|
|
serializer => 'Foo' |
938
|
|
|
|
|
|
|
} |
939
|
|
|
|
|
|
|
); |
940
|
|
|
|
|
|
|
} |
941
|
6
|
|
|
|
|
68
|
qr/cannot override these keys/, "non-overridable subcache keys"; |
942
|
6
|
|
|
|
|
3887
|
is( $cache->l1_cache->expires_variance, $cache->expires_variance ); |
943
|
6
|
|
|
|
|
3098
|
is( $cache->l1_cache->serializer, $cache->serializer ); |
944
|
6
|
|
|
|
|
2308
|
is( $cache->l1_cache->on_set_error, $cache->on_set_error ); |
945
|
6
|
|
|
|
|
2374
|
is( $cache->l1_cache->on_get_error, 'log' ); |
946
|
9
|
|
|
9
|
|
3250
|
} |
|
9
|
|
|
|
|
14
|
|
|
9
|
|
|
|
|
77
|
|
947
|
|
|
|
|
|
|
|
948
|
|
|
|
|
|
|
# Run logging tests for a cache with an l1_cache |
949
|
|
|
|
|
|
|
# |
950
|
|
|
|
|
|
|
sub _test_logging_with_l1_cache { |
951
|
10
|
|
|
10
|
|
24
|
my ( $self, $cache ) = @_; |
952
|
|
|
|
|
|
|
|
953
|
10
|
|
|
|
|
274
|
$cache->clear(); |
954
|
10
|
|
|
|
|
94
|
my $log = activate_test_logger(); |
955
|
10
|
|
|
|
|
68
|
my ( $key, $value ) = $self->kvpair(); |
956
|
|
|
|
|
|
|
|
957
|
10
|
|
|
|
|
242
|
my $driver = $cache->label; |
958
|
|
|
|
|
|
|
|
959
|
10
|
|
|
|
|
582
|
my $miss_not_in_cache = 'MISS \(not in cache\)'; |
960
|
10
|
|
|
|
|
21
|
my $miss_expired = 'MISS \(expired\)'; |
961
|
|
|
|
|
|
|
|
962
|
10
|
|
|
|
|
21
|
my $start_time = time(); |
963
|
|
|
|
|
|
|
|
964
|
10
|
|
|
|
|
199
|
$cache->get($key); |
965
|
10
|
|
|
|
|
446
|
$log->contains_ok( |
966
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='$driver', time='[-\d]+ms': $miss_not_in_cache/ |
967
|
|
|
|
|
|
|
); |
968
|
10
|
|
|
|
|
3353
|
$log->contains_ok( |
969
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='.*l1.*', time='[-\d]+ms': $miss_not_in_cache/ |
970
|
|
|
|
|
|
|
); |
971
|
10
|
|
|
|
|
3001
|
$log->empty_ok(); |
972
|
|
|
|
|
|
|
|
973
|
10
|
|
|
|
|
2646
|
$cache->set( $key, $value, 81 ); |
974
|
10
|
|
|
|
|
364
|
$log->contains_ok( |
975
|
|
|
|
|
|
|
qr/cache set for .* key='$key', size=\d+, expires='1m2[012]s', cache='$driver', time='[-\d]+ms'/ |
976
|
|
|
|
|
|
|
); |
977
|
|
|
|
|
|
|
|
978
|
10
|
|
|
|
|
3248
|
$log->contains_ok( |
979
|
|
|
|
|
|
|
qr/cache set for .* key='$key', size=\d+, expires='1m2[012]s', cache='.*l1.*', time='[-\d]+ms'/ |
980
|
|
|
|
|
|
|
); |
981
|
10
|
|
|
|
|
2730
|
$log->empty_ok(); |
982
|
|
|
|
|
|
|
|
983
|
10
|
|
|
|
|
2632
|
$cache->get($key); |
984
|
10
|
|
|
|
|
182
|
$log->contains_ok( |
985
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='.*l1.*', time='[-\d]+ms': HIT/); |
986
|
10
|
|
|
|
|
2821
|
$log->empty_ok(); |
987
|
|
|
|
|
|
|
|
988
|
10
|
|
|
|
|
2411
|
local $CHI::Driver::Test_Time = $start_time + 120; |
989
|
10
|
|
|
|
|
294
|
$cache->get($key); |
990
|
10
|
|
|
|
|
281
|
$log->contains_ok( |
991
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='$driver', time='[-\d]+ms': $miss_expired/ |
992
|
|
|
|
|
|
|
); |
993
|
10
|
|
|
|
|
3051
|
$log->contains_ok( |
994
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='.*l1.*', time='[-\d]+ms': $miss_expired/ |
995
|
|
|
|
|
|
|
); |
996
|
10
|
|
|
|
|
2791
|
$log->empty_ok(); |
997
|
|
|
|
|
|
|
|
998
|
10
|
|
|
|
|
3711
|
$cache->remove($key); |
999
|
10
|
|
|
|
|
252
|
$cache->get($key); |
1000
|
10
|
|
|
|
|
319
|
$log->contains_ok( |
1001
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='$driver', time='[-\d]+ms': $miss_not_in_cache/ |
1002
|
|
|
|
|
|
|
); |
1003
|
10
|
|
|
|
|
3125
|
$log->contains_ok( |
1004
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='.*l1.*', time='[-\d]+ms': $miss_not_in_cache/ |
1005
|
|
|
|
|
|
|
); |
1006
|
10
|
|
|
|
|
2666
|
$log->empty_ok(); |
1007
|
|
|
|
|
|
|
} |
1008
|
|
|
|
|
|
|
|
1009
|
|
|
|
|
|
|
sub _test_logging_with_mirror_cache { |
1010
|
10
|
|
|
10
|
|
26
|
my ( $self, $cache ) = @_; |
1011
|
|
|
|
|
|
|
|
1012
|
10
|
|
|
|
|
337
|
$cache->clear(); |
1013
|
10
|
|
|
|
|
102
|
my $log = activate_test_logger(); |
1014
|
10
|
|
|
|
|
62
|
my ( $key, $value ) = $self->kvpair(); |
1015
|
|
|
|
|
|
|
|
1016
|
10
|
|
|
|
|
242
|
my $driver = $cache->label; |
1017
|
|
|
|
|
|
|
|
1018
|
10
|
|
|
|
|
73
|
my $miss_not_in_cache = 'MISS \(not in cache\)'; |
1019
|
10
|
|
|
|
|
21
|
my $miss_expired = 'MISS \(expired\)'; |
1020
|
|
|
|
|
|
|
|
1021
|
10
|
|
|
|
|
17
|
my $start_time = time(); |
1022
|
|
|
|
|
|
|
|
1023
|
10
|
|
|
|
|
197
|
$cache->get($key); |
1024
|
10
|
|
|
|
|
396
|
$log->contains_ok( |
1025
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='$driver', time='[-\d]+ms': $miss_not_in_cache/ |
1026
|
|
|
|
|
|
|
); |
1027
|
10
|
|
|
|
|
3993
|
$log->empty_ok(); |
1028
|
|
|
|
|
|
|
|
1029
|
10
|
|
|
|
|
3245
|
$cache->set( $key, $value, 81 ); |
1030
|
10
|
|
|
|
|
372
|
$log->contains_ok( |
1031
|
|
|
|
|
|
|
qr/cache set for .* key='$key', size=\d+, expires='1m2[012]s', cache='$driver', time='[-\d]+ms'/ |
1032
|
|
|
|
|
|
|
); |
1033
|
|
|
|
|
|
|
|
1034
|
10
|
|
|
|
|
4009
|
$log->contains_ok( |
1035
|
|
|
|
|
|
|
qr/cache set for .* key='$key', size=\d+, expires='1m2[012]s', cache='.*mirror.*', time='[-\d]+ms'/ |
1036
|
|
|
|
|
|
|
); |
1037
|
10
|
|
|
|
|
3279
|
$log->empty_ok(); |
1038
|
|
|
|
|
|
|
|
1039
|
10
|
|
|
|
|
3199
|
$cache->get($key); |
1040
|
10
|
|
|
|
|
282
|
$log->contains_ok( |
1041
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='$driver', time='[-\d]+ms': HIT/); |
1042
|
10
|
|
|
|
|
3440
|
$log->empty_ok(); |
1043
|
|
|
|
|
|
|
|
1044
|
10
|
|
|
|
|
3082
|
local $CHI::Driver::Test_Time = $start_time + 120; |
1045
|
10
|
|
|
|
|
296
|
$cache->get($key); |
1046
|
10
|
|
|
|
|
299
|
$log->contains_ok( |
1047
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='$driver', time='[-\d]+ms': $miss_expired/ |
1048
|
|
|
|
|
|
|
); |
1049
|
10
|
|
|
|
|
3725
|
$log->empty_ok(); |
1050
|
|
|
|
|
|
|
|
1051
|
10
|
|
|
|
|
4649
|
$cache->remove($key); |
1052
|
10
|
|
|
|
|
257
|
$cache->get($key); |
1053
|
10
|
|
|
|
|
376
|
$log->contains_ok( |
1054
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='$driver', time='[-\d]+ms': $miss_not_in_cache/ |
1055
|
|
|
|
|
|
|
); |
1056
|
10
|
|
|
|
|
3639
|
$log->empty_ok(); |
1057
|
|
|
|
|
|
|
} |
1058
|
|
|
|
|
|
|
|
1059
|
|
|
|
|
|
|
# Run tests common to l1_cache and mirror_cache |
1060
|
|
|
|
|
|
|
# |
1061
|
|
|
|
|
|
|
sub _test_common_subcache_features { |
1062
|
20
|
|
|
20
|
|
60
|
my ( $self, $cache, $subcache, $subcache_type ) = @_; |
1063
|
20
|
|
|
|
|
88
|
my ( $key, $value, $key2, $value2 ) = $self->kvpair(2); |
1064
|
|
|
|
|
|
|
|
1065
|
20
|
|
|
|
|
62
|
for ( $cache, $subcache ) { $_->clear() } |
|
40
|
|
|
|
|
715
|
|
1066
|
|
|
|
|
|
|
|
1067
|
|
|
|
|
|
|
# Test informational methods |
1068
|
|
|
|
|
|
|
# |
1069
|
20
|
|
|
|
|
418
|
ok( !$cache->is_subcache, "is_subcache - false" ); |
1070
|
20
|
|
|
|
|
6412
|
ok( $subcache->is_subcache, "is_subcache - true" ); |
1071
|
20
|
|
|
|
|
6308
|
ok( $cache->has_subcaches, "has_subcaches - true" ); |
1072
|
20
|
|
|
|
|
7380
|
ok( !$subcache->has_subcaches, "has_subcaches - false" ); |
1073
|
20
|
|
|
|
|
6817
|
ok( !$cache->can('parent_cache'), "parent_cache - cannot" ); |
1074
|
20
|
|
|
|
|
5574
|
is( $subcache->parent_cache, $cache, "parent_cache - defined" ); |
1075
|
20
|
|
|
|
|
6476
|
ok( !$cache->can('subcache_type'), "subcache_type - cannot" ); |
1076
|
20
|
|
|
|
|
5974
|
is( $subcache->subcache_type, $subcache_type, "subcache_type - defined" ); |
1077
|
20
|
|
|
|
|
6185
|
cmp_deeply( $cache->subcaches, [$subcache], "subcaches - defined" ); |
1078
|
20
|
|
|
|
|
24948
|
ok( !$subcache->can('subcaches'), "subcaches - cannot" ); |
1079
|
20
|
|
|
|
|
6053
|
is( $cache->$subcache_type, $subcache, "$subcache_type - defined" ); |
1080
|
20
|
|
|
|
|
6455
|
ok( !$subcache->can($subcache_type), "$subcache_type - cannot" ); |
1081
|
|
|
|
|
|
|
|
1082
|
|
|
|
|
|
|
# Test that sets and various kinds of removals and expirations are distributed to both |
1083
|
|
|
|
|
|
|
# the primary cache and the subcache |
1084
|
|
|
|
|
|
|
# |
1085
|
20
|
|
|
|
|
5814
|
my ( $test_remove_method, $confirm_caches_empty, |
1086
|
|
|
|
|
|
|
$confirm_caches_populated ); |
1087
|
|
|
|
|
|
|
$test_remove_method = sub { |
1088
|
60
|
|
|
60
|
|
188
|
my ( $desc, $remove_code ) = @_; |
1089
|
60
|
|
|
|
|
185
|
$desc = "testing $desc"; |
1090
|
|
|
|
|
|
|
|
1091
|
60
|
|
|
|
|
228
|
$confirm_caches_empty->("$desc: before set"); |
1092
|
|
|
|
|
|
|
|
1093
|
60
|
|
|
|
|
20830
|
$cache->set( $key, $value ); |
1094
|
60
|
|
|
|
|
1471
|
$cache->set( $key2, $value2 ); |
1095
|
60
|
|
|
|
|
503
|
$confirm_caches_populated->("$desc: after set"); |
1096
|
60
|
|
|
|
|
18664
|
$remove_code->(); |
1097
|
|
|
|
|
|
|
|
1098
|
60
|
|
|
|
|
709
|
$confirm_caches_empty->("$desc: before set_multi"); |
1099
|
60
|
|
|
|
|
20239
|
$cache->set_multi( { $key => $value, $key2 => $value2 } ); |
1100
|
60
|
|
|
|
|
826
|
$confirm_caches_populated->("$desc: after set_multi"); |
1101
|
60
|
|
|
|
|
18407
|
$remove_code->(); |
1102
|
|
|
|
|
|
|
|
1103
|
60
|
|
|
|
|
579
|
$confirm_caches_empty->("$desc: before return"); |
1104
|
20
|
|
|
|
|
170
|
}; |
1105
|
|
|
|
|
|
|
|
1106
|
|
|
|
|
|
|
$confirm_caches_empty = sub { |
1107
|
180
|
|
|
180
|
|
352
|
my ($desc) = @_; |
1108
|
180
|
|
|
|
|
4257
|
ok( !defined( $cache->get($key) ), |
1109
|
|
|
|
|
|
|
"primary cache is not populated with '$key' - $desc" ); |
1110
|
180
|
|
|
|
|
61514
|
ok( !defined( $subcache->get($key) ), |
1111
|
|
|
|
|
|
|
"subcache is not populated with '$key' - $desc" ); |
1112
|
180
|
|
|
|
|
59818
|
ok( !defined( $cache->get($key2) ), |
1113
|
|
|
|
|
|
|
"primary cache is not populated #2 with '$key2' - $desc" ); |
1114
|
180
|
|
|
|
|
58986
|
ok( !defined( $subcache->get($key2) ), |
1115
|
|
|
|
|
|
|
"subcache is not populated #2 with '$key2' - $desc" ); |
1116
|
20
|
|
|
|
|
122
|
}; |
1117
|
|
|
|
|
|
|
|
1118
|
|
|
|
|
|
|
$confirm_caches_populated = sub { |
1119
|
120
|
|
|
120
|
|
263
|
my ($desc) = @_; |
1120
|
120
|
|
|
|
|
2895
|
is( $cache->get($key), $value, |
1121
|
|
|
|
|
|
|
"primary cache is populated with '$key' - $desc" ); |
1122
|
120
|
|
|
|
|
46922
|
is( $subcache->get($key), |
1123
|
|
|
|
|
|
|
$value, "subcache is populated with '$key' - $desc" ); |
1124
|
120
|
|
|
|
|
41370
|
is( $cache->get($key2), $value2, |
1125
|
|
|
|
|
|
|
"primary cache is populated with '$key2' - $desc" ); |
1126
|
120
|
|
|
|
|
37764
|
is( $subcache->get($key2), |
1127
|
|
|
|
|
|
|
$value2, "subcache is populated with '$key2' - $desc" ); |
1128
|
20
|
|
|
|
|
122
|
}; |
1129
|
|
|
|
|
|
|
|
1130
|
|
|
|
|
|
|
$test_remove_method->( |
1131
|
40
|
|
|
40
|
|
1215
|
'remove', sub { $cache->remove($key); $cache->remove($key2) } |
|
40
|
|
|
|
|
996
|
|
1132
|
20
|
|
|
|
|
122
|
); |
1133
|
|
|
|
|
|
|
$test_remove_method->( |
1134
|
40
|
|
|
40
|
|
1600
|
'expire', sub { $cache->expire($key); $cache->expire($key2) } |
|
40
|
|
|
|
|
1116
|
|
1135
|
20
|
|
|
|
|
6807
|
); |
1136
|
20
|
|
|
40
|
|
6418
|
$test_remove_method->( 'clear', sub { $cache->clear() } ); |
|
40
|
|
|
|
|
1221
|
|
1137
|
|
|
|
|
|
|
} |
1138
|
|
|
|
|
|
|
|
1139
|
|
|
|
|
|
|
sub _verify_cache_is_cleared { |
1140
|
19
|
|
|
19
|
|
46
|
my ( $self, $cache, $desc ) = @_; |
1141
|
|
|
|
|
|
|
|
1142
|
19
|
|
|
|
|
186
|
cmp_deeply( [ $cache->get_keys ], [], "get_keys ($desc)" ); |
1143
|
19
|
|
|
|
|
67157
|
is( scalar( $cache->get_keys ), 0, "scalar(get_keys) = 0 ($desc)" ); |
1144
|
19
|
|
|
|
|
5803
|
while ( my ( $keyname, $key ) = each( %{ $self->{keys} } ) ) { |
|
266
|
|
|
|
|
77501
|
|
1145
|
247
|
|
|
|
|
4124
|
ok( !defined $cache->get($key), |
1146
|
|
|
|
|
|
|
"key '$keyname' no longer defined ($desc)" ); |
1147
|
|
|
|
|
|
|
} |
1148
|
|
|
|
|
|
|
} |
1149
|
|
|
|
|
|
|
|
1150
|
|
|
|
|
|
|
sub process_keys { |
1151
|
94
|
|
|
94
|
0
|
376
|
my ( $self, $cache, @keys ) = @_; |
1152
|
94
|
|
|
|
|
382
|
$self->process_key( $cache, 'foo' ); |
1153
|
94
|
|
|
|
|
236
|
return map { $self->process_key( $cache, $_ ) } @keys; |
|
529
|
|
|
|
|
784
|
|
1154
|
|
|
|
|
|
|
} |
1155
|
|
|
|
|
|
|
|
1156
|
|
|
|
|
|
|
sub process_key { |
1157
|
623
|
|
|
623
|
0
|
700
|
my ( $self, $cache, $key ) = @_; |
1158
|
623
|
|
|
|
|
1249
|
return $cache->unescape_key( |
1159
|
|
|
|
|
|
|
$cache->escape_key( $cache->transform_key($key) ) ); |
1160
|
|
|
|
|
|
|
} |
1161
|
|
|
|
|
|
|
|
1162
|
|
|
|
|
|
|
sub test_clear : Tests { |
1163
|
7
|
|
|
7
|
0
|
1195
|
my $self = shift; |
1164
|
7
|
|
|
|
|
35
|
my $cache = $self->new_cache( namespace => 'name' ); |
1165
|
7
|
|
|
|
|
32
|
my $cache2 = $self->new_cache( namespace => 'other' ); |
1166
|
7
|
|
|
|
|
35
|
my $cache3 = $self->new_cache( namespace => 'name' ); |
1167
|
7
|
|
|
|
|
115
|
$self->num_tests( $self->{key_count} * 2 + 5 ); |
1168
|
|
|
|
|
|
|
|
1169
|
7
|
50
|
|
|
|
709
|
if ( $self->supports_clear() ) { |
1170
|
7
|
|
|
|
|
49
|
$self->set_some_keys($cache); |
1171
|
5
|
|
|
|
|
22
|
$self->set_some_keys($cache2); |
1172
|
5
|
|
|
|
|
105
|
$cache->clear(); |
1173
|
|
|
|
|
|
|
|
1174
|
5
|
|
|
|
|
107
|
$self->_verify_cache_is_cleared( $cache, 'cache after clear' ); |
1175
|
5
|
|
|
|
|
28
|
$self->_verify_cache_is_cleared( $cache3, 'cache3 after clear' ); |
1176
|
5
|
|
|
|
|
57
|
cmp_set( |
1177
|
|
|
|
|
|
|
[ $cache2->get_keys ], |
1178
|
5
|
|
|
|
|
32
|
[ $self->process_keys( $cache2, values( %{ $self->{keys} } ) ) ], |
1179
|
|
|
|
|
|
|
'cache2 untouched by clear' |
1180
|
|
|
|
|
|
|
); |
1181
|
|
|
|
|
|
|
} |
1182
|
|
|
|
|
|
|
else { |
1183
|
|
|
|
|
|
|
throws_ok( |
1184
|
0
|
|
|
0
|
|
0
|
sub { $cache->clear() }, |
1185
|
0
|
|
|
|
|
0
|
qr/not supported/, |
1186
|
|
|
|
|
|
|
"clear not supported" |
1187
|
|
|
|
|
|
|
); |
1188
|
0
|
|
|
|
|
0
|
SKIP: { skip "clear not supported", 9 } |
|
0
|
|
|
|
|
0
|
|
1189
|
|
|
|
|
|
|
} |
1190
|
9
|
|
|
9
|
|
13370
|
} |
|
9
|
|
|
|
|
17
|
|
|
9
|
|
|
|
|
102
|
|
1191
|
|
|
|
|
|
|
|
1192
|
|
|
|
|
|
|
sub test_logging : Tests { |
1193
|
5
|
|
|
5
|
0
|
961
|
my $self = shift; |
1194
|
5
|
|
|
|
|
15
|
my $cache = $self->{cache}; |
1195
|
|
|
|
|
|
|
|
1196
|
5
|
|
|
|
|
30
|
my $log = activate_test_logger(); |
1197
|
5
|
|
|
|
|
41
|
my ( $key, $value ) = $self->kvpair(); |
1198
|
|
|
|
|
|
|
|
1199
|
5
|
|
|
|
|
170
|
my $driver = $cache->label; |
1200
|
|
|
|
|
|
|
|
1201
|
5
|
|
|
|
|
11
|
my $miss_not_in_cache = 'MISS \(not in cache\)'; |
1202
|
5
|
|
|
|
|
11
|
my $miss_expired = 'MISS \(expired\)'; |
1203
|
|
|
|
|
|
|
|
1204
|
5
|
|
|
|
|
10
|
my $start_time = time(); |
1205
|
|
|
|
|
|
|
|
1206
|
5
|
|
|
|
|
67
|
$cache->get($key); |
1207
|
5
|
|
|
|
|
205
|
$log->contains_ok( |
1208
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='$driver', time='[-\d]+ms': $miss_not_in_cache/ |
1209
|
|
|
|
|
|
|
); |
1210
|
5
|
|
|
|
|
1882
|
$log->empty_ok(); |
1211
|
|
|
|
|
|
|
|
1212
|
5
|
|
|
|
|
1593
|
$cache->set( $key, $value ); |
1213
|
5
|
|
|
|
|
144
|
$log->contains_ok( |
1214
|
|
|
|
|
|
|
qr/cache set for .* key='$key', size=\d+, expires='never', cache='$driver', time='[-\d]+ms'/ |
1215
|
|
|
|
|
|
|
); |
1216
|
5
|
|
|
|
|
1687
|
$log->empty_ok(); |
1217
|
5
|
|
|
|
|
1555
|
$cache->set( $key, $value, 81 ); |
1218
|
5
|
|
|
|
|
157
|
$log->contains_ok( |
1219
|
|
|
|
|
|
|
qr/cache set for .* key='$key', size=\d+, expires='1m2[012]s', cache='$driver', time='[-\d]+ms'/ |
1220
|
|
|
|
|
|
|
); |
1221
|
5
|
|
|
|
|
1688
|
$log->empty_ok(); |
1222
|
|
|
|
|
|
|
|
1223
|
5
|
|
|
|
|
1721
|
$cache->get($key); |
1224
|
5
|
|
|
|
|
150
|
$log->contains_ok( |
1225
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='$driver', time='[-\d]+ms': HIT/); |
1226
|
5
|
|
|
|
|
1484
|
$log->empty_ok(); |
1227
|
|
|
|
|
|
|
|
1228
|
5
|
|
|
|
|
1447
|
local $CHI::Driver::Test_Time = $start_time + 120; |
1229
|
5
|
|
|
|
|
89
|
$cache->get($key); |
1230
|
5
|
|
|
|
|
134
|
$log->contains_ok( |
1231
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='$driver', time='[-\d]+ms': $miss_expired/ |
1232
|
|
|
|
|
|
|
); |
1233
|
5
|
|
|
|
|
1450
|
$log->empty_ok(); |
1234
|
|
|
|
|
|
|
|
1235
|
5
|
|
|
|
|
1600
|
$cache->remove($key); |
1236
|
5
|
|
|
|
|
66
|
$cache->get($key); |
1237
|
5
|
|
|
|
|
150
|
$log->contains_ok( |
1238
|
|
|
|
|
|
|
qr/cache get for .* key='$key', cache='$driver', time='[-\d]+ms': $miss_not_in_cache/ |
1239
|
|
|
|
|
|
|
); |
1240
|
5
|
|
|
|
|
1579
|
$log->empty_ok(); |
1241
|
9
|
|
|
9
|
|
4012
|
} |
|
9
|
|
|
|
|
25
|
|
|
9
|
|
|
|
|
44
|
|
1242
|
|
|
|
|
|
|
|
1243
|
|
|
|
|
|
|
sub test_stats : Tests { |
1244
|
5
|
|
|
5
|
0
|
1308
|
my $self = shift; |
1245
|
|
|
|
|
|
|
|
1246
|
5
|
50
|
|
|
|
38
|
return 'author testing only - possible differences between JSON versions' |
1247
|
|
|
|
|
|
|
unless ( $ENV{AUTHOR_TESTING} ); |
1248
|
|
|
|
|
|
|
|
1249
|
0
|
|
|
|
|
0
|
my $stats = $self->testing_chi_root_class->stats; |
1250
|
0
|
|
|
|
|
0
|
$stats->enable(); |
1251
|
|
|
|
|
|
|
|
1252
|
0
|
|
|
|
|
0
|
my ( $key, $value ) = $self->kvpair(); |
1253
|
0
|
|
|
|
|
0
|
my $start_time = time(); |
1254
|
|
|
|
|
|
|
|
1255
|
0
|
|
|
|
|
0
|
my $cache; |
1256
|
0
|
|
|
|
|
0
|
$cache = $self->new_cache( namespace => 'Foo' ); |
1257
|
0
|
|
|
|
|
0
|
$cache->get($key); |
1258
|
0
|
|
|
|
|
0
|
$cache->set( $key, $value, 80 ); |
1259
|
0
|
|
|
|
|
0
|
$cache->get($key); |
1260
|
0
|
|
|
|
|
0
|
local $CHI::Driver::Test_Time = $start_time + 120; |
1261
|
0
|
|
|
|
|
0
|
$cache->get($key); |
1262
|
0
|
|
|
|
|
0
|
$cache->remove($key); |
1263
|
0
|
|
|
|
|
0
|
$cache->get($key); |
1264
|
|
|
|
|
|
|
|
1265
|
0
|
|
|
|
|
0
|
$cache = $self->new_cache( namespace => 'Bar' ); |
1266
|
0
|
|
|
|
|
0
|
$cache->set( $key, scalar( $value x 3 ) ); |
1267
|
0
|
|
|
|
|
0
|
$cache->set( $key, $value ); |
1268
|
|
|
|
|
|
|
|
1269
|
0
|
|
|
|
|
0
|
$cache = $self->new_cache( namespace => 'Baz' ); |
1270
|
0
|
|
|
0
|
|
0
|
my $code = sub { usleep(100000); scalar( $value x 5 ) }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
1271
|
0
|
|
|
|
|
0
|
$cache->compute( $key, undef, $code ); |
1272
|
0
|
|
|
|
|
0
|
$cache->compute( $key, undef, $code ); |
1273
|
0
|
|
|
|
|
0
|
$cache->compute( $key, undef, $code ); |
1274
|
|
|
|
|
|
|
|
1275
|
0
|
|
|
|
|
0
|
my $log = activate_test_logger(); |
1276
|
0
|
|
|
|
|
0
|
my $label = $cache->label; |
1277
|
0
|
|
|
|
|
0
|
$log->empty_ok(); |
1278
|
0
|
|
|
|
|
0
|
$stats->flush(); |
1279
|
0
|
|
|
|
|
0
|
$log->contains_ok( |
1280
|
|
|
|
|
|
|
qr/CHI stats: {"absent_misses":2,"end_time":\d+,"expired_misses":1,"get_time_ms":\d+,"hits":1,"label":"$label","namespace":"Foo","root_class":"CHI","set_key_size":6,"set_time_ms":\d+,"set_value_size":20,"sets":1,"start_time":\d+}/ |
1281
|
|
|
|
|
|
|
); |
1282
|
0
|
|
|
|
|
0
|
$log->contains_ok( |
1283
|
|
|
|
|
|
|
qr/CHI stats: {"end_time":\d+,"label":"$label","namespace":"Bar","root_class":"CHI","set_key_size":12,"set_time_ms":\d+,"set_value_size":52,"sets":2,"start_time":\d+}/ |
1284
|
|
|
|
|
|
|
); |
1285
|
0
|
|
|
|
|
0
|
$log->contains_ok( |
1286
|
|
|
|
|
|
|
qr/CHI stats: {"absent_misses":1,"compute_time_ms":\d+,"computes":1,"end_time":\d+,"get_time_ms":\d+,"hits":2,"label":"$label","namespace":"Baz","root_class":"CHI","set_key_size":6,"set_time_ms":\d+,"set_value_size":44,"sets":1,"start_time":\d+}/ |
1287
|
|
|
|
|
|
|
); |
1288
|
0
|
|
|
|
|
0
|
$log->empty_ok(); |
1289
|
|
|
|
|
|
|
|
1290
|
0
|
|
|
|
|
0
|
my @logs = ( |
1291
|
|
|
|
|
|
|
'CHI stats: {"root_class":"CHI","namespace":"Foo","label":"File","start_time":1338404896,"end_time":1338404899,"hits":3,"sets":5,"set_time_ms":10}', |
1292
|
|
|
|
|
|
|
'CHI stats: {"root_class":"CHI","namespace":"Foo","label":"File","start_time":1338404896,"end_time":1338404899,"hits":1,"sets":7,"set_time_ms":14}', |
1293
|
|
|
|
|
|
|
'CHI stats: {"root_class":"CHI","namespace":"Bar","label":"File","start_time":1338404896,"end_time":1338404899,"hits":4,"sets":9,"set_time_ms":18}', |
1294
|
|
|
|
|
|
|
'CHI stats: {"root_class":"CHI","namespace":"Foo","label":"File","start_time":1338404896,"end_time":1338404899,"sets":3,"set_time_ms":6}', |
1295
|
|
|
|
|
|
|
'CHI stats: {"root_class":"CHI","namespace":"Foo","label":"File","start_time":1338404896,"end_time":1338404899,"hits":8}', |
1296
|
|
|
|
|
|
|
'CHI stats: {"root_class":"CHI","namespace":"Foo","label":"Memory","start_time":1338404896,"end_time":1338404899,"sets":2,"set_time_ms":4}', |
1297
|
|
|
|
|
|
|
'CHI stats: {"root_class":"CHI","namespace":"Bar","label":"File","start_time":1338404896,"end_time":1338404899,"hits":10,"sets":1,"set_time_ms":2}', |
1298
|
|
|
|
|
|
|
'CHI stats: {"root_class":"CHI","namespace":"Bar","label":"File","start_time":1338404896,"end_time":1338404899,"hits":3,"set_errors":2}', |
1299
|
|
|
|
|
|
|
); |
1300
|
0
|
|
|
|
|
0
|
my $log_dir = tempdir( "chi-test-stats-XXXX", TMPDIR => 1, CLEANUP => 1 ); |
1301
|
0
|
|
|
|
|
0
|
write_file( "$log_dir/log1", join( "\n", splice( @logs, 0, 4 ) ) . "\n" ); |
1302
|
0
|
|
|
|
|
0
|
write_file( "$log_dir/log2", join( "\n", @logs ) ); |
1303
|
0
|
0
|
|
|
|
0
|
open( my $fh2, "<", "$log_dir/log2" ) or die "cannot open $log_dir/log2"; |
1304
|
0
|
|
|
|
|
0
|
my $results = $stats->parse_stats_logs( "$log_dir/log1", $fh2 ); |
1305
|
0
|
|
|
|
|
0
|
close($fh2); |
1306
|
0
|
|
|
|
|
0
|
cmp_deeply( |
1307
|
|
|
|
|
|
|
$results, |
1308
|
|
|
|
|
|
|
Test::Deep::bag( |
1309
|
|
|
|
|
|
|
{ |
1310
|
|
|
|
|
|
|
avg_set_time_ms => '2', |
1311
|
|
|
|
|
|
|
gets => 12, |
1312
|
|
|
|
|
|
|
hit_rate => '1', |
1313
|
|
|
|
|
|
|
hits => 12, |
1314
|
|
|
|
|
|
|
label => 'File', |
1315
|
|
|
|
|
|
|
namespace => 'Foo', |
1316
|
|
|
|
|
|
|
root_class => 'CHI', |
1317
|
|
|
|
|
|
|
set_time_ms => 30, |
1318
|
|
|
|
|
|
|
sets => 15 |
1319
|
|
|
|
|
|
|
}, |
1320
|
|
|
|
|
|
|
{ |
1321
|
|
|
|
|
|
|
avg_set_time_ms => '2', |
1322
|
|
|
|
|
|
|
gets => 17, |
1323
|
|
|
|
|
|
|
hit_rate => '1', |
1324
|
|
|
|
|
|
|
hits => 17, |
1325
|
|
|
|
|
|
|
label => 'File', |
1326
|
|
|
|
|
|
|
namespace => 'Bar', |
1327
|
|
|
|
|
|
|
root_class => 'CHI', |
1328
|
|
|
|
|
|
|
set_errors => 2, |
1329
|
|
|
|
|
|
|
set_time_ms => 20, |
1330
|
|
|
|
|
|
|
sets => 10 |
1331
|
|
|
|
|
|
|
}, |
1332
|
|
|
|
|
|
|
{ |
1333
|
|
|
|
|
|
|
avg_set_time_ms => '2', |
1334
|
|
|
|
|
|
|
label => 'Memory', |
1335
|
|
|
|
|
|
|
namespace => 'Foo', |
1336
|
|
|
|
|
|
|
root_class => 'CHI', |
1337
|
|
|
|
|
|
|
set_time_ms => 4, |
1338
|
|
|
|
|
|
|
sets => 2 |
1339
|
|
|
|
|
|
|
}, |
1340
|
|
|
|
|
|
|
{ |
1341
|
|
|
|
|
|
|
avg_set_time_ms => '2', |
1342
|
|
|
|
|
|
|
hits => '29', |
1343
|
|
|
|
|
|
|
label => 'TOTALS', |
1344
|
|
|
|
|
|
|
namespace => 'TOTALS', |
1345
|
|
|
|
|
|
|
root_class => 'TOTALS', |
1346
|
|
|
|
|
|
|
set_errors => '2', |
1347
|
|
|
|
|
|
|
set_time_ms => 54, |
1348
|
|
|
|
|
|
|
sets => 27 |
1349
|
|
|
|
|
|
|
} |
1350
|
|
|
|
|
|
|
), |
1351
|
|
|
|
|
|
|
'parse_stats_logs' |
1352
|
|
|
|
|
|
|
); |
1353
|
9
|
|
|
9
|
|
6428
|
} |
|
9
|
|
|
|
|
16
|
|
|
9
|
|
|
|
|
37
|
|
1354
|
|
|
|
|
|
|
|
1355
|
|
|
|
|
|
|
sub test_cache_object : Tests { |
1356
|
7
|
|
|
7
|
0
|
1380
|
my $self = shift; |
1357
|
7
|
|
|
|
|
20
|
my $cache = $self->{cache}; |
1358
|
7
|
|
|
|
|
39
|
my ( $key, $value ) = $self->kvpair(); |
1359
|
7
|
|
|
|
|
20
|
my $start_time = time(); |
1360
|
7
|
|
|
|
|
139
|
$cache->set( $key, $value, { expires_at => $start_time + 10 } ); |
1361
|
7
|
|
|
|
|
71
|
is_between( $cache->get_object($key)->created_at, |
1362
|
|
|
|
|
|
|
$start_time, $start_time + 2 ); |
1363
|
7
|
|
|
|
|
2919
|
is_between( $cache->get_object($key)->get_created_at, |
1364
|
|
|
|
|
|
|
$start_time, $start_time + 2 ); |
1365
|
7
|
|
|
|
|
2387
|
is( $cache->get_object($key)->expires_at, $start_time + 10 ); |
1366
|
7
|
|
|
|
|
2488
|
is( $cache->get_object($key)->get_expires_at, $start_time + 10 ); |
1367
|
|
|
|
|
|
|
|
1368
|
7
|
|
|
|
|
2384
|
local $CHI::Driver::Test_Time = $start_time + 50; |
1369
|
7
|
|
|
|
|
100
|
$cache->set( $key, $value ); |
1370
|
7
|
|
|
|
|
39
|
is_between( |
1371
|
|
|
|
|
|
|
$cache->get_object($key)->created_at, |
1372
|
|
|
|
|
|
|
$start_time + 50, |
1373
|
|
|
|
|
|
|
$start_time + 52 |
1374
|
|
|
|
|
|
|
); |
1375
|
7
|
|
|
|
|
2329
|
is_between( |
1376
|
|
|
|
|
|
|
$cache->get_object($key)->get_created_at, |
1377
|
|
|
|
|
|
|
$start_time + 50, |
1378
|
|
|
|
|
|
|
$start_time + 52 |
1379
|
|
|
|
|
|
|
); |
1380
|
9
|
|
|
9
|
|
3310
|
} |
|
9
|
|
|
|
|
18
|
|
|
9
|
|
|
|
|
66
|
|
1381
|
|
|
|
|
|
|
|
1382
|
|
|
|
|
|
|
sub test_size_awareness : Tests { |
1383
|
6
|
|
|
6
|
0
|
1619
|
my $self = shift; |
1384
|
6
|
|
|
|
|
45
|
my ( $key, $value ) = $self->kvpair(); |
1385
|
|
|
|
|
|
|
|
1386
|
6
|
|
|
|
|
48
|
ok( !$self->new_cleared_cache()->is_size_aware(), |
1387
|
|
|
|
|
|
|
"not size aware by default" ); |
1388
|
6
|
|
|
|
|
3731
|
ok( $self->new_cleared_cache( is_size_aware => 1 )->is_size_aware(), |
1389
|
|
|
|
|
|
|
"is_size_aware turns on size awareness" ); |
1390
|
6
|
|
|
|
|
4163
|
ok( $self->new_cleared_cache( max_size => 10 )->is_size_aware(), |
1391
|
|
|
|
|
|
|
"max_size turns on size awareness" ); |
1392
|
|
|
|
|
|
|
|
1393
|
6
|
|
|
|
|
3254
|
my $cache = $self->new_cleared_cache( is_size_aware => 1 ); |
1394
|
6
|
|
|
|
|
95
|
is( $cache->get_size(), 0, "size is 0 for empty" ); |
1395
|
6
|
|
|
|
|
3451
|
$cache->set( $key, $value ); |
1396
|
6
|
|
|
|
|
38
|
is_about( $cache->get_size, 20, "size is about 20 with one value" ); |
1397
|
6
|
|
|
|
|
2976
|
$cache->set( $key, scalar( $value x 5 ) ); |
1398
|
6
|
|
|
|
|
34
|
is_about( $cache->get_size, 45, "size is 45 after overwrite" ); |
1399
|
6
|
|
|
|
|
2820
|
$cache->set( $key, scalar( $value x 5 ) ); |
1400
|
6
|
|
|
|
|
35
|
is_about( $cache->get_size, 45, "size is still 45 after same overwrite" ); |
1401
|
6
|
|
|
|
|
2917
|
$cache->set( $key, scalar( $value x 2 ) ); |
1402
|
6
|
|
|
|
|
40
|
is_about( $cache->get_size, 26, "size is 26 after overwrite" ); |
1403
|
6
|
|
|
|
|
3160
|
$cache->remove($key); |
1404
|
6
|
|
|
|
|
42
|
is( $cache->get_size, 0, "size is 0 again after removing key" ); |
1405
|
6
|
|
|
|
|
2852
|
$cache->set( $key, $value ); |
1406
|
6
|
|
|
|
|
35
|
is_about( $cache->get_size, 20, "size is about 20 with one value" ); |
1407
|
6
|
|
|
|
|
2876
|
$cache->clear(); |
1408
|
6
|
|
|
|
|
62
|
is( $cache->get_size, 0, "size is 0 again after clear" ); |
1409
|
|
|
|
|
|
|
|
1410
|
6
|
|
|
|
|
2641
|
my $time = time() + 10; |
1411
|
6
|
|
|
|
|
124
|
$cache->set( $key, $value, { expires_at => $time } ); |
1412
|
6
|
|
|
|
|
200
|
is( $cache->get_expires_at($key), |
1413
|
|
|
|
|
|
|
$time, "set options respected by size aware cache" ); |
1414
|
9
|
|
|
9
|
|
3811
|
} |
|
9
|
|
|
|
|
17
|
|
|
9
|
|
|
|
|
60
|
|
1415
|
|
|
|
|
|
|
|
1416
|
|
|
|
|
|
|
sub test_max_size : Tests { |
1417
|
6
|
|
|
6
|
0
|
1395
|
my $self = shift; |
1418
|
|
|
|
|
|
|
|
1419
|
6
|
|
|
|
|
38
|
is( $self->new_cache( max_size => '30k' )->max_size, |
1420
|
|
|
|
|
|
|
30 * 1024, 'max_size parsing' ); |
1421
|
|
|
|
|
|
|
|
1422
|
6
|
|
|
|
|
12450
|
my $cache = $self->new_cleared_cache( max_size => 99 ); |
1423
|
6
|
|
|
|
|
135
|
ok( $cache->is_size_aware, "is size aware when max_size specified" ); |
1424
|
6
|
|
|
|
|
2649
|
my $value_20 = 'x' x 6; |
1425
|
|
|
|
|
|
|
|
1426
|
6
|
|
|
|
|
42
|
for ( my $i = 0 ; $i < 5 ; $i++ ) { |
1427
|
30
|
|
|
|
|
9993
|
$cache->set( "key$i", $value_20 ); |
1428
|
|
|
|
|
|
|
} |
1429
|
6
|
|
|
|
|
46
|
for ( my $i = 0 ; $i < 10 ; $i++ ) { |
1430
|
60
|
|
|
|
|
21250
|
$cache->set( "key" . int( rand(10) ), $value_20 ); |
1431
|
60
|
|
|
|
|
381
|
is_between( $cache->get_size, 60, 99, |
1432
|
|
|
|
|
|
|
"after iteration $i, size = " . $cache->get_size ); |
1433
|
60
|
|
|
|
|
34847
|
is_between( scalar( $cache->get_keys ), |
1434
|
|
|
|
|
|
|
3, 5, "after iteration $i, keys = " . scalar( $cache->get_keys ) ); |
1435
|
|
|
|
|
|
|
} |
1436
|
9
|
|
|
9
|
|
3471
|
} |
|
9
|
|
|
|
|
17
|
|
|
9
|
|
|
|
|
42
|
|
1437
|
|
|
|
|
|
|
|
1438
|
|
|
|
|
|
|
sub test_max_size_with_l1_cache : Tests { |
1439
|
7
|
|
|
7
|
0
|
1808
|
my $self = shift; |
1440
|
|
|
|
|
|
|
|
1441
|
7
|
|
|
|
|
80
|
my $cache = $self->new_cleared_cache( |
1442
|
|
|
|
|
|
|
l1_cache => { driver => 'Memory', datastore => {}, max_size => 99 } ); |
1443
|
7
|
|
|
|
|
54
|
my $l1_cache = $cache->l1_cache; |
1444
|
7
|
|
|
|
|
407
|
ok( $l1_cache->is_size_aware, "is size aware when max_size specified" ); |
1445
|
7
|
|
|
|
|
4364
|
my $value_20 = 'x' x 6; |
1446
|
|
|
|
|
|
|
|
1447
|
7
|
|
|
|
|
31
|
my @keys = map { "key$_" } ( 0 .. 9 ); |
|
70
|
|
|
|
|
153
|
|
1448
|
7
|
|
|
|
|
139
|
my @shuffle_keys = shuffle(@keys); |
1449
|
7
|
|
|
|
|
46
|
for ( my $i = 0 ; $i < 5 ; $i++ ) { |
1450
|
35
|
|
|
|
|
1197
|
$cache->set( "key$i", $value_20 ); |
1451
|
|
|
|
|
|
|
} |
1452
|
7
|
|
|
|
|
101
|
for ( my $i = 0 ; $i < 10 ; $i++ ) { |
1453
|
70
|
|
|
|
|
27856
|
my $key = $shuffle_keys[$i]; |
1454
|
70
|
|
|
|
|
2332
|
$cache->set( $key, $value_20 ); |
1455
|
70
|
|
|
|
|
565
|
is_between( $l1_cache->get_size, 60, 99, |
1456
|
|
|
|
|
|
|
"after iteration $i, size = " . $l1_cache->get_size ); |
1457
|
70
|
|
|
|
|
35048
|
is_between( scalar( $l1_cache->get_keys ), |
1458
|
|
|
|
|
|
|
3, 5, |
1459
|
|
|
|
|
|
|
"after iteration $i, keys = " . scalar( $l1_cache->get_keys ) ); |
1460
|
|
|
|
|
|
|
} |
1461
|
7
|
|
|
|
|
3151
|
cmp_deeply( [ sort $cache->get_keys ], |
1462
|
|
|
|
|
|
|
\@keys, "primary cache still has all keys" ); |
1463
|
|
|
|
|
|
|
|
1464
|
|
|
|
|
|
|
# Now test population by writeback |
1465
|
7
|
|
|
|
|
12644
|
$l1_cache->clear(); |
1466
|
7
|
|
|
|
|
69
|
is( $l1_cache->get_size, 0, "l1 size is 0 after clear" ); |
1467
|
7
|
|
|
|
|
2938
|
for ( my $i = 0 ; $i < 5 ; $i++ ) { |
1468
|
35
|
|
|
|
|
1137
|
$cache->get("key$i"); |
1469
|
|
|
|
|
|
|
} |
1470
|
7
|
|
|
|
|
48
|
for ( my $i = 0 ; $i < 10 ; $i++ ) { |
1471
|
70
|
|
|
|
|
23135
|
my $key = $shuffle_keys[$i]; |
1472
|
70
|
|
|
|
|
2293
|
$cache->get($key); |
1473
|
70
|
|
|
|
|
250
|
is_between( $l1_cache->get_size, 60, 99, |
1474
|
|
|
|
|
|
|
"after iteration $i, size = " . $l1_cache->get_size ); |
1475
|
70
|
|
|
|
|
30908
|
is_between( scalar( $l1_cache->get_keys ), |
1476
|
|
|
|
|
|
|
3, 5, |
1477
|
|
|
|
|
|
|
"after iteration $i, keys = " . scalar( $l1_cache->get_keys ) ); |
1478
|
|
|
|
|
|
|
} |
1479
|
9
|
|
|
9
|
|
5161
|
} |
|
9
|
|
|
|
|
18
|
|
|
9
|
|
|
|
|
40
|
|
1480
|
|
|
|
|
|
|
|
1481
|
|
|
|
|
|
|
sub test_custom_discard_policy : Tests { |
1482
|
6
|
|
|
6
|
0
|
1008
|
my $self = shift; |
1483
|
6
|
|
|
|
|
13
|
my $value_20 = 'x' x 6; |
1484
|
|
|
|
|
|
|
my $highest_first = sub { |
1485
|
60
|
|
|
60
|
|
84
|
my $c = shift; |
1486
|
60
|
|
|
|
|
278
|
my @sorted_keys = sort( $c->get_keys ); |
1487
|
60
|
|
|
|
|
459
|
return sub { pop(@sorted_keys) }; |
|
270
|
|
|
|
|
769
|
|
1488
|
6
|
|
|
|
|
27
|
}; |
1489
|
6
|
|
|
|
|
40
|
my $cache = $self->new_cleared_cache( |
1490
|
|
|
|
|
|
|
is_size_aware => 1, |
1491
|
|
|
|
|
|
|
discard_policy => $highest_first |
1492
|
|
|
|
|
|
|
); |
1493
|
6
|
|
|
|
|
35
|
for ( my $j = 0 ; $j < 10 ; $j += 2 ) { |
1494
|
30
|
|
|
|
|
18228
|
$cache->clear(); |
1495
|
30
|
|
|
|
|
255
|
for ( my $i = 0 ; $i < 10 ; $i++ ) { |
1496
|
300
|
|
|
|
|
888
|
my $k = ( $i + $j ) % 10; |
1497
|
300
|
|
|
|
|
3727
|
$cache->set( "key$k", $value_20 ); |
1498
|
|
|
|
|
|
|
} |
1499
|
30
|
|
|
|
|
213
|
$cache->discard_to_size(100); |
1500
|
150
|
|
|
|
|
441
|
cmp_set( |
1501
|
|
|
|
|
|
|
[ $cache->get_keys ], |
1502
|
30
|
|
|
|
|
119
|
[ map { "key$_" } ( 0 .. 4 ) ], |
1503
|
|
|
|
|
|
|
"5 lowest" |
1504
|
|
|
|
|
|
|
); |
1505
|
30
|
|
|
|
|
86672
|
$cache->discard_to_size(20); |
1506
|
30
|
|
|
|
|
131
|
cmp_set( [ $cache->get_keys ], ["key0"], "1 lowest" ); |
1507
|
|
|
|
|
|
|
} |
1508
|
9
|
|
|
9
|
|
3527
|
} |
|
9
|
|
|
|
|
19
|
|
|
9
|
|
|
|
|
38
|
|
1509
|
|
|
|
|
|
|
|
1510
|
|
|
|
|
|
|
sub test_discard_timeout : Tests { |
1511
|
7
|
|
|
7
|
0
|
1799
|
my $self = shift; |
1512
|
7
|
50
|
|
|
|
81
|
return 'author testing only' unless ( $ENV{AUTHOR_TESTING} ); |
1513
|
|
|
|
|
|
|
|
1514
|
|
|
|
|
|
|
my $bad_policy = sub { |
1515
|
0
|
|
|
0
|
|
0
|
return sub { '1' }; |
|
0
|
|
|
|
|
0
|
|
1516
|
0
|
|
|
|
|
0
|
}; |
1517
|
0
|
|
|
|
|
0
|
my $cache = $self->new_cleared_cache( |
1518
|
|
|
|
|
|
|
is_size_aware => 1, |
1519
|
|
|
|
|
|
|
discard_policy => $bad_policy |
1520
|
|
|
|
|
|
|
); |
1521
|
0
|
|
0
|
|
|
0
|
ok( defined( $cache->discard_timeout ) && $cache->discard_timeout > 1, |
1522
|
|
|
|
|
|
|
"positive discard timeout" ); |
1523
|
0
|
|
|
|
|
0
|
$cache->discard_timeout(1); |
1524
|
0
|
|
|
|
|
0
|
is( $cache->discard_timeout, 1, "can set timeout" ); |
1525
|
0
|
|
|
|
|
0
|
my $start_time = time; |
1526
|
0
|
|
|
|
|
0
|
$cache->set( 2, 2 ); |
1527
|
0
|
|
|
0
|
|
0
|
throws_ok { $cache->discard_to_size(0) } qr/discard timeout .* reached/; |
|
0
|
|
|
|
|
0
|
|
1528
|
0
|
|
0
|
|
|
0
|
ok( |
1529
|
|
|
|
|
|
|
time >= $start_time && time <= $start_time + 4, |
1530
|
|
|
|
|
|
|
sprintf( |
1531
|
|
|
|
|
|
|
"time (%d) is between %d and %d", |
1532
|
|
|
|
|
|
|
time, $start_time, $start_time + 4 |
1533
|
|
|
|
|
|
|
) |
1534
|
|
|
|
|
|
|
); |
1535
|
9
|
|
|
9
|
|
3756
|
} |
|
9
|
|
|
|
|
15
|
|
|
9
|
|
|
|
|
38
|
|
1536
|
|
|
|
|
|
|
|
1537
|
|
|
|
|
|
|
sub test_size_awareness_with_subcaches : Tests { |
1538
|
6
|
|
|
6
|
0
|
1635
|
my $self = shift; |
1539
|
|
|
|
|
|
|
|
1540
|
6
|
|
|
|
|
14
|
my ( $cache, $l1_cache ); |
1541
|
|
|
|
|
|
|
my $set_values = sub { |
1542
|
18
|
|
|
18
|
|
51
|
my $value_20 = 'x' x 6; |
1543
|
18
|
|
|
|
|
90
|
for ( my $i = 0 ; $i < 20 ; $i++ ) { |
1544
|
360
|
|
|
|
|
10351
|
$cache->set( "key$i", $value_20 ); |
1545
|
|
|
|
|
|
|
} |
1546
|
18
|
|
|
|
|
232
|
$l1_cache = $cache->l1_cache; |
1547
|
6
|
|
|
|
|
43
|
}; |
1548
|
|
|
|
|
|
|
my $is_size_aware = sub { |
1549
|
24
|
|
|
24
|
|
64
|
my $c = shift; |
1550
|
24
|
|
|
|
|
648
|
my $label = $c->label; |
1551
|
|
|
|
|
|
|
|
1552
|
24
|
|
|
|
|
644
|
ok( $c->is_size_aware, "$label is size aware" ); |
1553
|
24
|
|
|
|
|
13156
|
my $max_size = $c->max_size; |
1554
|
24
|
|
|
|
|
968
|
ok( $max_size > 0, "$label has max size" ); |
1555
|
24
|
|
|
|
|
9161
|
is_between( $c->get_size, $max_size - 40, |
1556
|
|
|
|
|
|
|
$max_size, "$label size = " . $c->get_size ); |
1557
|
24
|
|
|
|
|
8979
|
is_between( |
1558
|
|
|
|
|
|
|
scalar( $c->get_keys ), |
1559
|
|
|
|
|
|
|
( $max_size + 1 ) / 20 - 2, |
1560
|
|
|
|
|
|
|
( $max_size + 1 ) / 20, |
1561
|
|
|
|
|
|
|
"$label keys = " . scalar( $c->get_keys ) |
1562
|
|
|
|
|
|
|
); |
1563
|
6
|
|
|
|
|
40
|
}; |
1564
|
|
|
|
|
|
|
my $is_not_size_aware = sub { |
1565
|
6
|
|
|
6
|
|
12
|
my $c = shift; |
1566
|
6
|
|
|
|
|
108
|
my $label = $c->label; |
1567
|
|
|
|
|
|
|
|
1568
|
6
|
|
|
|
|
234
|
ok( !$c->is_size_aware, "$label is not size aware" ); |
1569
|
6
|
|
|
|
|
4246
|
is( $c->get_keys, 20, "$label keys = 20" ); |
1570
|
6
|
|
|
|
|
33
|
}; |
1571
|
|
|
|
|
|
|
|
1572
|
6
|
|
|
|
|
79
|
$cache = $self->new_cleared_cache( |
1573
|
|
|
|
|
|
|
l1_cache => { driver => 'Memory', datastore => {}, max_size => 99 } ); |
1574
|
6
|
|
|
|
|
27
|
$set_values->(); |
1575
|
6
|
|
|
|
|
236
|
$is_not_size_aware->($cache); |
1576
|
6
|
|
|
|
|
2892
|
$is_size_aware->($l1_cache); |
1577
|
|
|
|
|
|
|
|
1578
|
6
|
|
|
|
|
2160
|
$cache = $self->new_cleared_cache( |
1579
|
|
|
|
|
|
|
l1_cache => { driver => 'Memory', datastore => {}, max_size => 99 }, |
1580
|
|
|
|
|
|
|
max_size => 199 |
1581
|
|
|
|
|
|
|
); |
1582
|
6
|
|
|
|
|
276
|
$set_values->(); |
1583
|
6
|
|
|
|
|
751
|
$is_size_aware->($cache); |
1584
|
6
|
|
|
|
|
3136
|
$is_size_aware->($l1_cache); |
1585
|
|
|
|
|
|
|
|
1586
|
6
|
|
|
|
|
2235
|
$cache = $self->new_cleared_cache( |
1587
|
|
|
|
|
|
|
l1_cache => { driver => 'Memory', datastore => {} }, |
1588
|
|
|
|
|
|
|
max_size => 199 |
1589
|
|
|
|
|
|
|
); |
1590
|
6
|
|
|
|
|
511
|
$set_values->(); |
1591
|
6
|
|
|
|
|
357
|
$is_size_aware->($cache); |
1592
|
|
|
|
|
|
|
|
1593
|
|
|
|
|
|
|
# Cannot call is_not_size_aware because the get_keys check will |
1594
|
|
|
|
|
|
|
# fail. Keys will be removed from the l1_cache when they are removed |
1595
|
|
|
|
|
|
|
# from the main cache, even though l1_cache does not have a max |
1596
|
|
|
|
|
|
|
# size. Not sure if this is the correct behavior, but for now, we're not |
1597
|
|
|
|
|
|
|
# going to test it. Normally, l1 caches will be more size limited than |
1598
|
|
|
|
|
|
|
# their parent caches. |
1599
|
|
|
|
|
|
|
# |
1600
|
6
|
|
|
|
|
3394
|
ok( !$l1_cache->is_size_aware, $l1_cache->label . " is not size aware" ); |
1601
|
9
|
|
|
9
|
|
4800
|
} |
|
9
|
|
|
|
|
15
|
|
|
9
|
|
|
|
|
42
|
|
1602
|
|
|
|
|
|
|
|
1603
|
|
|
|
|
|
|
sub is_about { |
1604
|
30
|
|
|
30
|
0
|
61
|
my ( $value, $expected, $msg ) = @_; |
1605
|
|
|
|
|
|
|
|
1606
|
30
|
|
|
|
|
88
|
my $margin = int( $expected * 0.1 ); |
1607
|
30
|
50
|
|
|
|
120
|
if ( abs( $value - $expected ) <= $margin ) { |
1608
|
30
|
|
|
|
|
118
|
pass($msg); |
1609
|
|
|
|
|
|
|
} |
1610
|
|
|
|
|
|
|
else { |
1611
|
0
|
|
|
|
|
|
fail("$msg - got $value, expected $expected"); |
1612
|
|
|
|
|
|
|
} |
1613
|
|
|
|
|
|
|
} |
1614
|
|
|
|
|
|
|
|
1615
|
|
|
|
|
|
|
sub test_busy_lock : Tests { |
1616
|
7
|
|
|
7
|
0
|
1292
|
my $self = shift; |
1617
|
7
|
|
|
|
|
19
|
my $cache = $self->{cache}; |
1618
|
|
|
|
|
|
|
|
1619
|
7
|
|
|
|
|
61
|
my ( $key, $value ) = $self->kvpair(); |
1620
|
7
|
|
|
|
|
23
|
my @bl = ( busy_lock => '30 sec' ); |
1621
|
7
|
|
|
|
|
13
|
my $start_time = time(); |
1622
|
|
|
|
|
|
|
|
1623
|
7
|
|
|
|
|
16
|
local $CHI::Driver::Test_Time = $start_time; |
1624
|
7
|
|
|
|
|
142
|
$cache->set( $key, $value, 100 ); |
1625
|
7
|
|
|
|
|
20
|
local $CHI::Driver::Test_Time = $start_time + 90; |
1626
|
7
|
|
|
|
|
115
|
is( $cache->get( $key, @bl ), $value, "hit before expiration" ); |
1627
|
7
|
|
|
|
|
3187
|
is( |
1628
|
|
|
|
|
|
|
$cache->get_expires_at($key), |
1629
|
|
|
|
|
|
|
$start_time + 100, |
1630
|
|
|
|
|
|
|
"expires_at before expiration" |
1631
|
|
|
|
|
|
|
); |
1632
|
7
|
|
|
|
|
2304
|
local $CHI::Driver::Test_Time = $start_time + 110; |
1633
|
7
|
|
|
|
|
95
|
ok( !defined( $cache->get( $key, @bl ) ), "miss after expiration" ); |
1634
|
7
|
|
|
|
|
2393
|
is( |
1635
|
|
|
|
|
|
|
$cache->get_expires_at($key), |
1636
|
|
|
|
|
|
|
$start_time + 140, |
1637
|
|
|
|
|
|
|
"expires_at after busy lock" |
1638
|
|
|
|
|
|
|
); |
1639
|
7
|
|
|
|
|
2385
|
is( $cache->get( $key, @bl ), $value, "hit after busy lock" ); |
1640
|
9
|
|
|
9
|
|
3925
|
} |
|
9
|
|
|
|
|
16
|
|
|
9
|
|
|
|
|
35
|
|
1641
|
|
|
|
|
|
|
|
1642
|
|
|
|
|
|
|
sub test_obj_ref : Tests { |
1643
|
7
|
|
|
7
|
0
|
1508
|
my $self = shift; |
1644
|
|
|
|
|
|
|
|
1645
|
|
|
|
|
|
|
# Make sure obj_ref works in conjunction with subcaches too |
1646
|
7
|
|
|
|
|
58
|
my $cache = |
1647
|
|
|
|
|
|
|
$self->new_cache( l1_cache => { driver => 'Memory', datastore => {} } ); |
1648
|
7
|
|
|
|
|
24
|
my $obj; |
1649
|
7
|
|
|
|
|
36
|
my ( $key, $value ) = ( 'medium', [ a => 5, b => 6 ] ); |
1650
|
|
|
|
|
|
|
|
1651
|
|
|
|
|
|
|
my $validate_obj = sub { |
1652
|
14
|
|
|
14
|
|
70
|
isa_ok( $obj, 'CHI::CacheObject' ); |
1653
|
14
|
|
|
|
|
6107
|
is( $obj->key, $key, "keys match" ); |
1654
|
14
|
|
|
|
|
5251
|
cmp_deeply( $obj->value, $value, "values match" ); |
1655
|
7
|
|
|
|
|
47
|
}; |
1656
|
|
|
|
|
|
|
|
1657
|
7
|
|
|
|
|
212
|
$cache->get( $key, obj_ref => \$obj ); |
1658
|
7
|
|
|
|
|
48
|
ok( !defined($obj), "obj not defined on miss" ); |
1659
|
7
|
|
|
|
|
3747
|
$cache->set( $key, $value, { obj_ref => \$obj } ); |
1660
|
7
|
|
|
|
|
73
|
$validate_obj->(); |
1661
|
7
|
|
|
|
|
3209
|
undef $obj; |
1662
|
7
|
|
|
|
|
59
|
ok( !defined($obj), "obj not defined before get" ); |
1663
|
7
|
|
|
|
|
2448
|
$cache->get( $key, obj_ref => \$obj ); |
1664
|
7
|
|
|
|
|
26
|
$validate_obj->(); |
1665
|
9
|
|
|
9
|
|
3261
|
} |
|
9
|
|
|
|
|
23
|
|
|
9
|
|
|
|
|
38
|
|
1666
|
|
|
|
|
|
|
|
1667
|
|
|
|
|
|
|
sub test_metacache : Tests { |
1668
|
7
|
|
|
7
|
0
|
1633
|
my $self = shift; |
1669
|
7
|
|
|
|
|
20
|
my $cache = $self->{cache}; |
1670
|
|
|
|
|
|
|
|
1671
|
7
|
|
|
|
|
61
|
ok( !defined( $cache->{metacache} ), "metacache is lazy" ); |
1672
|
7
|
|
|
|
|
3629
|
$cache->metacache->set( 'foo', 5 ); |
1673
|
7
|
|
|
|
|
60
|
ok( defined( $cache->{metacache} ), "metacache autovivified" ); |
1674
|
7
|
|
|
|
|
2896
|
is( $cache->metacache->get('foo'), 5 ); |
1675
|
9
|
|
|
9
|
|
2456
|
} |
|
9
|
|
|
|
|
17
|
|
|
9
|
|
|
|
|
39
|
|
1676
|
|
|
|
|
|
|
|
1677
|
|
|
|
|
|
|
sub test_scalar_return_values : Tests { |
1678
|
6
|
|
|
6
|
0
|
1411
|
my $self = shift; |
1679
|
6
|
|
|
|
|
16
|
my $cache = $self->{cache}; |
1680
|
|
|
|
|
|
|
|
1681
|
|
|
|
|
|
|
my $check = sub { |
1682
|
30
|
|
|
30
|
|
76
|
my ($code) = @_; |
1683
|
30
|
|
|
|
|
59
|
my $scalar_result = $code->(); |
1684
|
30
|
|
|
|
|
83
|
my @list = $code->(); |
1685
|
30
|
|
|
|
|
222
|
cmp_deeply( \@list, [$scalar_result] ); |
1686
|
6
|
|
|
|
|
36
|
}; |
1687
|
|
|
|
|
|
|
|
1688
|
6
|
|
|
12
|
|
30
|
$check->( sub { $cache->fetch('a') } ); |
|
12
|
|
|
|
|
86
|
|
1689
|
6
|
|
|
12
|
|
9226
|
$check->( sub { $cache->get('a') } ); |
|
12
|
|
|
|
|
245
|
|
1690
|
6
|
|
|
12
|
|
7084
|
$check->( sub { $cache->set( 'a', 5 ) } ); |
|
12
|
|
|
|
|
253
|
|
1691
|
6
|
|
|
12
|
|
8039
|
$check->( sub { $cache->fetch('a') } ); |
|
12
|
|
|
|
|
47
|
|
1692
|
6
|
|
|
12
|
|
7039
|
$check->( sub { $cache->get('a') } ); |
|
12
|
|
|
|
|
210
|
|
1693
|
9
|
|
|
9
|
|
3353
|
} |
|
9
|
|
|
|
|
14
|
|
|
9
|
|
|
|
|
38
|
|
1694
|
|
|
|
|
|
|
|
1695
|
|
|
|
|
|
|
sub test_no_leak : Tests { |
1696
|
7
|
|
|
7
|
0
|
1518
|
my ($self) = @_; |
1697
|
|
|
|
|
|
|
|
1698
|
7
|
|
|
|
|
19
|
my $weakref; |
1699
|
|
|
|
|
|
|
{ |
1700
|
7
|
|
|
|
|
12
|
my $cache = $self->new_cache(); |
|
7
|
|
|
|
|
34
|
|
1701
|
7
|
|
|
|
|
19
|
$weakref = $cache; |
1702
|
7
|
|
|
|
|
39
|
weaken($weakref); |
1703
|
7
|
|
33
|
|
|
160
|
ok( defined($weakref) && $weakref->isa('CHI::Driver'), |
1704
|
|
|
|
|
|
|
"weakref is defined" ); |
1705
|
|
|
|
|
|
|
} |
1706
|
7
|
|
|
|
|
3352
|
ok( !defined($weakref), "weakref is no longer defined - cache was freed" ); |
1707
|
9
|
|
|
9
|
|
2599
|
} |
|
9
|
|
|
|
|
17
|
|
|
9
|
|
|
|
|
35
|
|
1708
|
|
|
|
|
|
|
|
1709
|
|
|
|
|
|
|
{ |
1710
|
|
|
|
|
|
|
package My::CHI; |
1711
|
|
|
|
|
|
|
$My::CHI::VERSION = '0.60'; |
1712
|
|
|
|
|
|
|
our @ISA = qw(CHI); |
1713
|
|
|
|
|
|
|
} |
1714
|
|
|
|
|
|
|
|
1715
|
|
|
|
|
|
|
sub test_driver_properties : Tests { |
1716
|
7
|
|
|
7
|
0
|
1591
|
my $self = shift; |
1717
|
7
|
|
|
|
|
18
|
my $cache = $self->{cache}; |
1718
|
|
|
|
|
|
|
|
1719
|
7
|
|
|
|
|
103
|
is( $cache->chi_root_class, 'CHI', 'chi_root_class=CHI' ); |
1720
|
7
|
|
|
|
|
3424
|
my $cache2 = My::CHI->new( $self->new_cache_options() ); |
1721
|
7
|
|
|
|
|
57
|
is( $cache2->chi_root_class, 'My::CHI', 'chi_root_class=My::CHI' ); |
1722
|
9
|
|
|
9
|
|
2608
|
} |
|
9
|
|
|
|
|
15
|
|
|
9
|
|
|
|
|
36
|
|
1723
|
|
|
|
|
|
|
|
1724
|
|
|
|
|
|
|
sub test_missing_params : Tests { |
1725
|
7
|
|
|
7
|
0
|
1448
|
my $self = shift; |
1726
|
7
|
|
|
|
|
21
|
my $cache = $self->{cache}; |
1727
|
|
|
|
|
|
|
|
1728
|
|
|
|
|
|
|
# These methods require a key |
1729
|
7
|
|
|
|
|
25
|
foreach my $method ( |
1730
|
|
|
|
|
|
|
qw(get get_object get_expires_at exists_and_is_expired is_valid set expire compute get_multi_arrayref get_multi_hashref set_multi remove_multi) |
1731
|
|
|
|
|
|
|
) |
1732
|
|
|
|
|
|
|
{ |
1733
|
|
|
|
|
|
|
throws_ok( |
1734
|
84
|
|
|
84
|
|
3504
|
sub { $cache->$method() }, |
1735
|
84
|
|
|
|
|
57189
|
qr/must specify key/, |
1736
|
|
|
|
|
|
|
"$method throws error when no key passed" |
1737
|
|
|
|
|
|
|
); |
1738
|
|
|
|
|
|
|
} |
1739
|
9
|
|
|
9
|
|
2753
|
} |
|
9
|
|
|
|
|
16
|
|
|
9
|
|
|
|
|
51
|
|
1740
|
|
|
|
|
|
|
|
1741
|
|
|
|
|
|
|
sub test_compute : Tests { |
1742
|
7
|
|
|
7
|
0
|
1417
|
my $self = shift; |
1743
|
7
|
|
|
|
|
17
|
my $cache = $self->{cache}; |
1744
|
|
|
|
|
|
|
|
1745
|
|
|
|
|
|
|
# Test current arg order and pre-0.40 arg order |
1746
|
7
|
|
|
|
|
25
|
foreach my $iter ( 0 .. 1 ) { |
1747
|
14
|
|
|
|
|
2383
|
my $count = 5; |
1748
|
14
|
|
|
|
|
33
|
my $expire_time = time + 10; |
1749
|
14
|
|
|
14
|
|
115
|
my @args1 = ( { expires_at => $expire_time }, sub { $count++ } ); |
|
14
|
|
|
|
|
41
|
|
1750
|
|
|
|
|
|
|
my @args2 = ( |
1751
|
|
|
|
|
|
|
{ |
1752
|
16
|
|
|
16
|
|
46
|
expire_if => sub { 1 } |
1753
|
|
|
|
|
|
|
}, |
1754
|
14
|
|
|
14
|
|
35
|
sub { $count++ } |
1755
|
14
|
|
|
|
|
90
|
); |
1756
|
14
|
100
|
|
|
|
43
|
if ($iter) { |
1757
|
7
|
|
|
|
|
16
|
@args1 = reverse(@args1); |
1758
|
7
|
|
|
|
|
16
|
@args2 = reverse(@args2); |
1759
|
|
|
|
|
|
|
} |
1760
|
14
|
|
|
|
|
140
|
$cache->clear; |
1761
|
14
|
|
|
|
|
235
|
is( $cache->get('foo'), undef, "miss" ); |
1762
|
14
|
|
|
|
|
6177
|
is( $cache->compute( 'foo', @args1 ), 5, "compute - 5" ); |
1763
|
14
|
|
|
|
|
4946
|
is( $cache->get('foo'), 5, "hit - 5" ); |
1764
|
14
|
|
|
|
|
4897
|
is( $cache->get_object('foo')->expires_at, $expire_time, |
1765
|
|
|
|
|
|
|
"expire time" ); |
1766
|
14
|
|
|
|
|
4473
|
is( $cache->compute( 'foo', @args2 ), 6, "compute - 6" ); |
1767
|
14
|
|
|
|
|
4723
|
is( $cache->get('foo'), 6, "hit - 6" ); |
1768
|
|
|
|
|
|
|
} |
1769
|
|
|
|
|
|
|
|
1770
|
|
|
|
|
|
|
# Test wantarray |
1771
|
7
|
|
|
|
|
2489
|
$cache->clear(); |
1772
|
|
|
|
|
|
|
my $compute_list = sub { |
1773
|
14
|
|
|
14
|
|
77
|
$cache->compute( 'foo', {}, sub { ( int( rand(10000) ) ) x 5 } ); |
|
7
|
|
|
|
|
278
|
|
1774
|
7
|
|
|
|
|
44
|
}; |
1775
|
7
|
|
|
|
|
26
|
my @list1 = $compute_list->(); |
1776
|
7
|
|
|
|
|
38
|
my @list2 = $compute_list->(); |
1777
|
7
|
|
|
|
|
52
|
is( scalar(@list1), 5, "list has 5 items" ); |
1778
|
7
|
|
|
|
|
2500
|
cmp_deeply( \@list1, \@list2, "lists are the same" ); |
1779
|
9
|
|
|
9
|
|
4682
|
} |
|
9
|
|
|
|
|
14
|
|
|
9
|
|
|
|
|
39
|
|
1780
|
|
|
|
|
|
|
|
1781
|
|
|
|
|
|
|
sub test_compress_threshold : Tests { |
1782
|
6
|
|
|
6
|
0
|
1057
|
my $self = shift; |
1783
|
6
|
|
|
|
|
15
|
my $cache = $self->{cache}; |
1784
|
|
|
|
|
|
|
|
1785
|
6
|
|
|
|
|
16
|
my $s0 = 'x' x 180; |
1786
|
6
|
|
|
|
|
13
|
my $s1 = 'x' x 200; |
1787
|
6
|
|
|
|
|
129
|
$cache->set( 'key0', $s0 ); |
1788
|
6
|
|
|
|
|
79
|
$cache->set( 'key1', $s1 ); |
1789
|
6
|
|
|
|
|
72
|
is_between( $cache->get_object('key0')->size, 180, 220 ); |
1790
|
6
|
|
|
|
|
2461
|
is_between( $cache->get_object('key1')->size, 200, 240 ); |
1791
|
|
|
|
|
|
|
|
1792
|
6
|
|
|
|
|
1891
|
my $cache2 = $self->new_cache( compress_threshold => 190 ); |
1793
|
6
|
|
|
|
|
90
|
$cache2->set( 'key0', $s0 ); |
1794
|
6
|
|
|
|
|
83
|
$cache2->set( 'key1', $s1 ); |
1795
|
6
|
|
|
|
|
34
|
is_between( $cache2->get_object('key0')->size, 180, 220 ); |
1796
|
6
|
|
|
|
|
3024
|
ok( $cache2->get_object('key1')->size < 100 ); |
1797
|
6
|
|
|
|
|
2172
|
is( $cache2->get('key0'), $s0 ); |
1798
|
6
|
|
|
|
|
1988
|
is( $cache2->get('key1'), $s1 ); |
1799
|
9
|
|
|
9
|
|
3142
|
} |
|
9
|
|
|
|
|
17
|
|
|
9
|
|
|
|
|
36
|
|
1800
|
|
|
|
|
|
|
|
1801
|
|
|
|
|
|
|
sub test_expires_on_backend : Tests { |
1802
|
7
|
|
|
7
|
0
|
1388
|
my $self = shift; |
1803
|
|
|
|
|
|
|
|
1804
|
7
|
50
|
|
|
|
56
|
return "skipping - no support for expires_on_backend" |
1805
|
|
|
|
|
|
|
unless $self->supports_expires_on_backend(); |
1806
|
0
|
|
|
|
|
0
|
foreach my $expires_on_backend ( 0, 1 ) { |
1807
|
0
|
|
|
|
|
0
|
my $cache = |
1808
|
|
|
|
|
|
|
$self->new_cache( expires_on_backend => $expires_on_backend ); |
1809
|
0
|
|
|
|
|
0
|
$cache->set( 'key0', 5, '2s' ); |
1810
|
0
|
|
|
|
|
0
|
$cache->set( 'key1', 6, { expires_at => time + 2 } ); |
1811
|
0
|
|
|
|
|
0
|
is( $cache->get('key0'), 5, 'hit key0 before expire' ); |
1812
|
0
|
|
|
|
|
0
|
is( $cache->get('key1'), 6, 'hit key1 before expire' ); |
1813
|
0
|
|
|
|
|
0
|
sleep(3); |
1814
|
0
|
|
|
|
|
0
|
ok( !defined( $cache->get('key0') ), 'miss key0 after expire' ); |
1815
|
0
|
|
|
|
|
0
|
ok( !defined( $cache->get('key1') ), 'miss key1 after expire' ); |
1816
|
|
|
|
|
|
|
|
1817
|
0
|
0
|
|
|
|
0
|
if ($expires_on_backend) { |
1818
|
0
|
|
|
|
|
0
|
ok( |
1819
|
|
|
|
|
|
|
!defined( $cache->get_object('key0') ), |
1820
|
|
|
|
|
|
|
'cannot get_object(key0) after expire' |
1821
|
|
|
|
|
|
|
); |
1822
|
0
|
|
|
|
|
0
|
ok( |
1823
|
|
|
|
|
|
|
!defined( $cache->get_object('key1') ), |
1824
|
|
|
|
|
|
|
'cannot get_object(key1) after expire' |
1825
|
|
|
|
|
|
|
); |
1826
|
|
|
|
|
|
|
} |
1827
|
|
|
|
|
|
|
else { |
1828
|
0
|
|
|
|
|
0
|
ok( |
1829
|
|
|
|
|
|
|
$cache->get_object('key0')->is_expired(), |
1830
|
|
|
|
|
|
|
'can get_object(key0) after expire' |
1831
|
|
|
|
|
|
|
); |
1832
|
0
|
|
|
|
|
0
|
ok( |
1833
|
|
|
|
|
|
|
$cache->get_object('key1')->is_expired(), |
1834
|
|
|
|
|
|
|
'can get_object(key1) after expire' |
1835
|
|
|
|
|
|
|
); |
1836
|
|
|
|
|
|
|
} |
1837
|
|
|
|
|
|
|
} |
1838
|
9
|
|
|
9
|
|
3543
|
} |
|
9
|
|
|
|
|
13
|
|
|
9
|
|
|
|
|
37
|
|
1839
|
|
|
|
|
|
|
|
1840
|
|
|
|
|
|
|
sub test_append : Tests { |
1841
|
5
|
|
|
5
|
0
|
950
|
my $self = shift; |
1842
|
5
|
|
|
|
|
14
|
my $cache = $self->{cache}; |
1843
|
5
|
|
|
|
|
27
|
my ( $key, $value ) = |
1844
|
|
|
|
|
|
|
( $self->{keys}->{arrayref}, $self->{values}->{medium} ); |
1845
|
|
|
|
|
|
|
|
1846
|
|
|
|
|
|
|
# Appending to non-existent key has no effect |
1847
|
|
|
|
|
|
|
# |
1848
|
5
|
|
|
|
|
174
|
$cache->append( $key, $value ); |
1849
|
5
|
|
|
|
|
155
|
ok( !$cache->get($key) ); |
1850
|
|
|
|
|
|
|
|
1851
|
5
|
|
|
|
|
2391
|
ok( $cache->set( $key, $value ) ); |
1852
|
5
|
|
|
|
|
2040
|
$cache->append( $key, $value ); |
1853
|
5
|
|
|
|
|
98
|
is( $cache->get($key), $value . $value ); |
1854
|
5
|
|
|
|
|
1954
|
$cache->append( $key, $value ); |
1855
|
5
|
|
|
|
|
54
|
is( $cache->get($key), $value . $value . $value ); |
1856
|
9
|
|
|
9
|
|
2754
|
} |
|
9
|
|
|
|
|
17
|
|
|
9
|
|
|
|
|
35
|
|
1857
|
|
|
|
|
|
|
|
1858
|
|
|
|
|
|
|
sub test_add : Tests { |
1859
|
7
|
|
|
7
|
0
|
20426
|
my $self = shift; |
1860
|
7
|
|
|
|
|
22
|
my $cache = $self->{cache}; |
1861
|
7
|
|
|
|
|
37
|
my ( $key, $value ) = |
1862
|
|
|
|
|
|
|
( $self->{keys}->{arrayref}, $self->{values}->{medium} ); |
1863
|
|
|
|
|
|
|
|
1864
|
7
|
|
|
|
|
17
|
my $t = time(); |
1865
|
|
|
|
|
|
|
|
1866
|
7
|
|
|
|
|
119
|
$cache->add( $key, $value, { expires_at => $t + 100 } ); |
1867
|
7
|
|
|
|
|
147
|
is( $cache->get($key), $value, "get" ); |
1868
|
7
|
|
|
|
|
4364
|
is( $cache->get_object($key)->expires_at, $t + 100, "expires_at" ); |
1869
|
|
|
|
|
|
|
|
1870
|
7
|
|
|
|
|
2571
|
$cache->add( $key, $value . $value, { expires_at => $t + 200 } ); |
1871
|
7
|
|
|
|
|
118
|
is( $cache->get($key), $value, "get (after add)" ); |
1872
|
7
|
|
|
|
|
2885
|
is( $cache->get_object($key)->expires_at, |
1873
|
|
|
|
|
|
|
$t + 100, "expires_at (after add)" ); |
1874
|
|
|
|
|
|
|
|
1875
|
7
|
|
|
|
|
2799
|
$cache->remove($key); |
1876
|
7
|
|
|
|
|
62
|
$cache->add( $key, $value . $value, { expires_at => $t + 200 } ); |
1877
|
7
|
|
|
|
|
99
|
is( $cache->get($key), $value . $value, "get (after expire and add)" ); |
1878
|
7
|
|
|
|
|
2658
|
is( $cache->get_object($key)->expires_at, |
1879
|
|
|
|
|
|
|
$t + 200, "expires_at (after expire and add)" ); |
1880
|
9
|
|
|
9
|
|
3114
|
} |
|
9
|
|
|
|
|
18
|
|
|
9
|
|
|
|
|
34
|
|
1881
|
|
|
|
|
|
|
|
1882
|
|
|
|
|
|
|
sub test_replace : Tests { |
1883
|
7
|
|
|
7
|
0
|
1913
|
my $self = shift; |
1884
|
7
|
|
|
|
|
23
|
my $cache = $self->{cache}; |
1885
|
7
|
|
|
|
|
49
|
my ( $key, $value ) = |
1886
|
|
|
|
|
|
|
( $self->{keys}->{arrayref}, $self->{values}->{medium} ); |
1887
|
|
|
|
|
|
|
|
1888
|
7
|
|
|
|
|
19
|
my $t = time(); |
1889
|
|
|
|
|
|
|
|
1890
|
7
|
|
|
|
|
133
|
$cache->replace( $key, $value, { expires_at => $t + 100 } ); |
1891
|
7
|
|
|
|
|
44
|
ok( !$cache->get_object($key), "get" ); |
1892
|
|
|
|
|
|
|
|
1893
|
7
|
|
|
|
|
3634
|
$cache->set( $key, $value . $value, { expires_at => $t + 200 } ); |
1894
|
7
|
|
|
|
|
60
|
$cache->replace( $key, $value, { expires_at => $t + 100 } ); |
1895
|
7
|
|
|
|
|
193
|
is( $cache->get($key), $value, "get (after replace)" ); |
1896
|
7
|
|
|
|
|
3356
|
is( $cache->get_object($key)->expires_at, |
1897
|
|
|
|
|
|
|
$t + 100, "expires_at (after replace)" ); |
1898
|
9
|
|
|
9
|
|
2831
|
} |
|
9
|
|
|
|
|
18
|
|
|
9
|
|
|
|
|
34
|
|
1899
|
|
|
|
|
|
|
|
1900
|
|
|
|
|
|
|
sub test_max_key_length : Tests { |
1901
|
5
|
|
|
5
|
0
|
878
|
my $self = shift; |
1902
|
|
|
|
|
|
|
|
1903
|
|
|
|
|
|
|
# Test max_key_length and also that key does not get transformed twice in mirror_cache |
1904
|
|
|
|
|
|
|
# |
1905
|
5
|
|
|
|
|
12
|
my $mirror_store = {}; |
1906
|
5
|
|
|
|
|
40
|
my $cache = $self->new_cleared_cache( |
1907
|
|
|
|
|
|
|
max_key_length => 10, |
1908
|
|
|
|
|
|
|
mirror_cache => { driver => 'Memory', datastore => $mirror_store } |
1909
|
|
|
|
|
|
|
); |
1910
|
|
|
|
|
|
|
|
1911
|
5
|
|
|
|
|
15
|
foreach my $keyname ( 'medium', 'large' ) { |
1912
|
10
|
|
|
|
|
1666
|
my ( $key, $value ) = |
1913
|
|
|
|
|
|
|
( $self->{keys}->{$keyname}, $self->{values}->{$keyname} ); |
1914
|
10
|
|
|
|
|
272
|
$cache->set( $key, $value ); |
1915
|
10
|
|
|
|
|
254
|
is( $cache->get($key), $value, $keyname ); |
1916
|
10
|
|
|
|
|
3636
|
is( $cache->mirror_cache->get($key), $value, $keyname ); |
1917
|
10
|
100
|
|
|
|
3521
|
if ( $keyname eq 'medium' ) { |
1918
|
5
|
|
|
|
|
27
|
is( $cache->get_object($key)->key(), $key, "medium key stored" ); |
1919
|
|
|
|
|
|
|
} |
1920
|
|
|
|
|
|
|
else { |
1921
|
5
|
|
|
|
|
30
|
isnt( $cache->get_object($key)->key(), $key, "md5 key stored" ); |
1922
|
5
|
|
|
|
|
1610
|
is( length( $cache->get_object($key)->key() ), |
1923
|
|
|
|
|
|
|
32, "md5 key stored" ); |
1924
|
|
|
|
|
|
|
} |
1925
|
|
|
|
|
|
|
} |
1926
|
9
|
|
|
9
|
|
3176
|
} |
|
9
|
|
|
|
|
15
|
|
|
9
|
|
|
|
|
37
|
|
1927
|
|
|
|
|
|
|
|
1928
|
|
|
|
|
|
|
# Test that cache does not get corrupted with multiple concurrent processes writing |
1929
|
|
|
|
|
|
|
# |
1930
|
|
|
|
|
|
|
sub test_multiple_processes : Tests { |
1931
|
4
|
|
|
4
|
0
|
776
|
my $self = shift; |
1932
|
4
|
50
|
|
|
|
27
|
return "author test only" unless $ENV{AUTHOR_TESTING}; |
1933
|
0
|
0
|
|
|
|
0
|
return "does not pass on file driver" |
1934
|
|
|
|
|
|
|
if $self->new_cache->short_driver_name eq 'File'; |
1935
|
|
|
|
|
|
|
|
1936
|
0
|
|
|
|
|
0
|
my ( @values, @pids, %valid_values ); |
1937
|
0
|
|
|
|
|
0
|
my $shared_key = $self->{keys}->{medium}; |
1938
|
0
|
|
|
|
|
0
|
my $num_procs = 4; |
1939
|
|
|
|
|
|
|
|
1940
|
0
|
|
|
|
|
0
|
local $SIG{CHLD} = 'IGNORE'; |
1941
|
|
|
|
|
|
|
|
1942
|
|
|
|
|
|
|
# Each child continuously writes a unique 10000 byte string to a single shared key |
1943
|
|
|
|
|
|
|
# |
1944
|
|
|
|
|
|
|
my $child_action = sub { |
1945
|
0
|
|
|
0
|
|
0
|
my $p = shift; |
1946
|
0
|
|
|
|
|
0
|
my $value = $values[$p]; |
1947
|
0
|
|
|
|
|
0
|
my $child_cache = $self->new_cache(); |
1948
|
|
|
|
|
|
|
|
1949
|
0
|
|
|
|
|
0
|
sleep(1); # Wait for parent to be ready |
1950
|
0
|
|
|
|
|
0
|
my $child_end_time = time() + 5; |
1951
|
0
|
|
|
|
|
0
|
while ( time < $child_end_time ) { |
1952
|
0
|
|
|
|
|
0
|
$child_cache->set( $shared_key, $value ); |
1953
|
|
|
|
|
|
|
} |
1954
|
0
|
|
|
|
|
0
|
$child_cache->set( "done$p", 1 ); |
1955
|
0
|
|
|
|
|
0
|
}; |
1956
|
|
|
|
|
|
|
|
1957
|
0
|
|
|
|
|
0
|
foreach my $p ( 0 .. $num_procs ) { |
1958
|
0
|
|
|
|
|
0
|
$values[$p] = random_string(10000); |
1959
|
0
|
|
|
|
|
0
|
$valid_values{ $values[$p] } = $p; |
1960
|
0
|
0
|
|
|
|
0
|
if ( my $pid = fork() ) { |
1961
|
0
|
|
|
|
|
0
|
$pids[$p] = $pid; |
1962
|
|
|
|
|
|
|
} |
1963
|
|
|
|
|
|
|
else { |
1964
|
0
|
|
|
|
|
0
|
$child_action->($p); |
1965
|
0
|
|
|
|
|
0
|
exit; |
1966
|
|
|
|
|
|
|
} |
1967
|
|
|
|
|
|
|
} |
1968
|
|
|
|
|
|
|
|
1969
|
|
|
|
|
|
|
# Parent continuously gets shared key, makes sure it is one of the valid values. |
1970
|
|
|
|
|
|
|
# Loop until we see done flag for each child process, or until 10 secs pass. |
1971
|
|
|
|
|
|
|
# At end make sure we saw each process's value once. |
1972
|
|
|
|
|
|
|
# |
1973
|
0
|
|
|
|
|
0
|
my ( %seen, $error ); |
1974
|
0
|
|
|
|
|
0
|
my $parent_end_time = time() + 10; |
1975
|
0
|
|
|
|
|
0
|
my $parent_cache = $self->new_cache(); |
1976
|
0
|
|
|
|
|
0
|
while ( !$error ) { |
1977
|
0
|
|
|
|
|
0
|
for ( my $i = 0 ; $i < 100 ; $i++ ) { |
1978
|
0
|
|
|
|
|
0
|
my $value = $parent_cache->get($shared_key); |
1979
|
0
|
0
|
|
|
|
0
|
if ( defined($value) ) { |
1980
|
0
|
0
|
|
|
|
0
|
if ( defined( my $p = $valid_values{$value} ) ) { |
1981
|
0
|
|
|
|
|
0
|
$seen{$p} = 1; |
1982
|
|
|
|
|
|
|
} |
1983
|
|
|
|
|
|
|
else { |
1984
|
0
|
|
|
|
|
0
|
$error = "got invalid value '$value' from shared key"; |
1985
|
0
|
|
|
|
|
0
|
last; |
1986
|
|
|
|
|
|
|
} |
1987
|
|
|
|
|
|
|
} |
1988
|
|
|
|
|
|
|
} |
1989
|
0
|
0
|
|
|
|
0
|
if ( !grep { !$parent_cache->get("done$_") } ( 0 .. $num_procs ) ) { |
|
0
|
|
|
|
|
0
|
|
1990
|
0
|
|
|
|
|
0
|
last; |
1991
|
|
|
|
|
|
|
} |
1992
|
0
|
0
|
|
|
|
0
|
if ( time() >= $parent_end_time ) { |
1993
|
0
|
|
|
|
|
0
|
$error = "did not see all done flags after 10 secs"; |
1994
|
|
|
|
|
|
|
} |
1995
|
|
|
|
|
|
|
} |
1996
|
|
|
|
|
|
|
|
1997
|
0
|
0
|
|
|
|
0
|
if ( !$error ) { |
1998
|
0
|
0
|
|
|
|
0
|
if ( my ($p) = grep { !$seen{$_} } ( 0 .. $num_procs ) ) { |
|
0
|
|
|
|
|
0
|
|
1999
|
0
|
|
|
|
|
0
|
$error = "never saw value from process $p"; |
2000
|
|
|
|
|
|
|
} |
2001
|
|
|
|
|
|
|
} |
2002
|
|
|
|
|
|
|
|
2003
|
0
|
0
|
|
|
|
0
|
if ($error) { |
2004
|
0
|
|
|
|
|
0
|
ok( 0, $error ); |
2005
|
|
|
|
|
|
|
} |
2006
|
|
|
|
|
|
|
else { |
2007
|
0
|
|
|
|
|
0
|
ok( 1, "passed" ); |
2008
|
|
|
|
|
|
|
} |
2009
|
9
|
|
|
9
|
|
5410
|
} |
|
9
|
|
|
|
|
16
|
|
|
9
|
|
|
|
|
37
|
|
2010
|
|
|
|
|
|
|
|
2011
|
|
|
|
|
|
|
1; |