line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Couchbase::Test::Views; |
2
|
2
|
|
|
2
|
|
760
|
use strict; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
62
|
|
3
|
2
|
|
|
2
|
|
6
|
use warnings; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
42
|
|
4
|
2
|
|
|
2
|
|
6
|
use base qw(Couchbase::Test::Common); |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
110
|
|
5
|
2
|
|
|
2
|
|
8
|
use Test::More; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
10
|
|
6
|
2
|
|
|
2
|
|
356
|
use Couchbase::Client; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
34
|
|
7
|
2
|
|
|
2
|
|
6
|
use Couchbase::Client::Errors; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
178
|
|
8
|
2
|
|
|
2
|
|
8
|
use Data::Dumper; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
82
|
|
9
|
|
|
|
|
|
|
use Class::XSAccessor { |
10
|
2
|
|
|
|
|
12
|
accessors => [ qw(cbo) ] |
11
|
2
|
|
|
2
|
|
8
|
}; |
|
2
|
|
|
|
|
2
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
use constant { |
14
|
2
|
|
|
|
|
250
|
DESIGN_NAME => "blog" |
15
|
2
|
|
|
2
|
|
258
|
}; |
|
2
|
|
|
|
|
2
|
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
my $DESIGN_JSON = { |
18
|
|
|
|
|
|
|
_id => "_design/blog", |
19
|
|
|
|
|
|
|
language => "javascript", |
20
|
|
|
|
|
|
|
views => { |
21
|
|
|
|
|
|
|
recent_posts => { |
22
|
|
|
|
|
|
|
map => 'function(doc) ' . |
23
|
|
|
|
|
|
|
'{ if (doc.date && doc.title) ' . |
24
|
|
|
|
|
|
|
'{ emit(doc.date, doc.title); } }' |
25
|
|
|
|
|
|
|
} |
26
|
|
|
|
|
|
|
} |
27
|
|
|
|
|
|
|
}; |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
sub SKIP_CLASS { |
30
|
|
|
|
|
|
|
|
31
|
0
|
0
|
|
0
|
1
|
|
if (!$Couchbase::Test::Common::RealServer) { |
32
|
0
|
|
|
|
|
|
return 1; |
33
|
|
|
|
|
|
|
} |
34
|
|
|
|
|
|
|
|
35
|
0
|
|
|
|
|
|
return 0; |
36
|
|
|
|
|
|
|
} |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
sub setup_client :Test(startup) { |
39
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
40
|
0
|
|
|
|
|
0
|
$self->cbo( $self->make_cbo ); |
41
|
2
|
|
|
2
|
|
8
|
} |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
8
|
|
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
sub TV01_create_ddoc :Test(no_plan) { |
44
|
|
|
|
|
|
|
|
45
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
46
|
0
|
|
|
|
|
0
|
my $o = $self->cbo; |
47
|
0
|
|
|
|
|
0
|
my $ret = $o->couch_design_put($DESIGN_JSON); |
48
|
0
|
|
|
|
|
0
|
ok($ret->is_ok, "Design doc put did not return errors"); |
49
|
|
|
|
|
|
|
|
50
|
0
|
|
|
|
|
0
|
my $design = $o->couch_design_get(DESIGN_NAME); |
51
|
|
|
|
|
|
|
|
52
|
0
|
|
|
|
|
0
|
isa_ok($design, 'Couchbase::Couch::Design'); |
53
|
0
|
|
|
|
|
0
|
is($design->path, '_design/blog', "Have path"); |
54
|
0
|
|
|
|
|
0
|
is($design->http_code, 200, "Have HTTP 200"); |
55
|
0
|
|
|
|
|
0
|
ok($design->is_ok, "Overall object OK"); |
56
|
0
|
|
|
|
|
0
|
is_deeply($design->value, $DESIGN_JSON, "Got back view"); |
57
|
2
|
|
|
2
|
|
566
|
} |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
4
|
|
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
sub TV02_create_invalid_ddoc :Test(no_plan) { |
60
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
61
|
0
|
|
|
|
|
0
|
my $o = $self->cbo; |
62
|
|
|
|
|
|
|
|
63
|
0
|
|
|
|
|
0
|
eval { |
64
|
0
|
|
|
|
|
0
|
$o->couch_design_put("blah"); |
65
|
0
|
|
|
|
|
0
|
}; like($@, '/path cannot be empty/'); |
66
|
|
|
|
|
|
|
|
67
|
0
|
|
|
|
|
0
|
my $ret = $o->couch_design_put({ |
68
|
|
|
|
|
|
|
_id => "_design/meh", |
69
|
|
|
|
|
|
|
views => { |
70
|
|
|
|
|
|
|
foo => "blehblehbleh" |
71
|
|
|
|
|
|
|
} |
72
|
|
|
|
|
|
|
}); |
73
|
|
|
|
|
|
|
|
74
|
0
|
|
|
|
|
0
|
is($ret->http_code, 400, "Got error for invalid view"); |
75
|
0
|
|
|
|
|
0
|
is($ret->errinfo->{error}, "invalid_design_document"); |
76
|
2
|
|
|
2
|
|
490
|
} |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
6
|
|
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
sub TV03_view_query :Test(no_plan) { |
79
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
80
|
0
|
|
|
|
|
0
|
my $o = $self->cbo; |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
# First, load up the keys |
83
|
0
|
|
|
|
|
0
|
my @posts = ( |
84
|
|
|
|
|
|
|
[ "bought-a-cat" => { |
85
|
|
|
|
|
|
|
title => "bought-a-cat", |
86
|
|
|
|
|
|
|
body => "I went to the pet store earlier and brought home a little kitty", |
87
|
|
|
|
|
|
|
date => "2009/01/30 18:04:11" |
88
|
|
|
|
|
|
|
}], |
89
|
|
|
|
|
|
|
[ "biking" => { |
90
|
|
|
|
|
|
|
title => "Biking", |
91
|
|
|
|
|
|
|
body => "My biggest hobby is mountainbiking. The other day..", |
92
|
|
|
|
|
|
|
date => "2009/01/30 18:04:11" |
93
|
|
|
|
|
|
|
}], |
94
|
|
|
|
|
|
|
[ "hello-world" => { |
95
|
|
|
|
|
|
|
title => "Hello World", |
96
|
|
|
|
|
|
|
body => "Well hello and welcome to my new blog...", |
97
|
|
|
|
|
|
|
date => "2009/01/15 15:52:20" |
98
|
|
|
|
|
|
|
}] |
99
|
|
|
|
|
|
|
); |
100
|
|
|
|
|
|
|
|
101
|
0
|
|
|
|
|
0
|
my %dkeys = map { $_->[0], 1 } @posts; |
|
0
|
|
|
|
|
0
|
|
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
# See if we can slurp the view |
104
|
0
|
|
|
|
|
0
|
my $res = $o->couch_view_slurp(["blog", "recent_posts"], stale => "false"); |
105
|
|
|
|
|
|
|
|
106
|
0
|
|
|
|
|
0
|
my @rm_errors = (); |
107
|
0
|
|
|
|
|
0
|
foreach my $id (map $_->{id}, @{ $res->value }) { |
|
0
|
|
|
|
|
0
|
|
108
|
0
|
|
|
|
|
0
|
my $rv = $o->remove($id); |
109
|
0
|
0
|
|
|
|
0
|
if (!$rv->is_ok) { |
110
|
0
|
|
|
|
|
0
|
push @rm_errors, $rv; |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
|
114
|
0
|
|
|
|
|
0
|
ok(!@rm_errors); |
115
|
|
|
|
|
|
|
|
116
|
0
|
|
|
|
|
0
|
my $results = $o->couch_set_multi(@posts); |
117
|
0
|
|
|
|
|
0
|
my @errkeys = grep { !$results->{$_}->is_ok } keys %$results; |
|
0
|
|
|
|
|
0
|
|
118
|
0
|
|
|
|
|
0
|
ok(!@errkeys, "No store errors"); |
119
|
0
|
|
|
|
|
0
|
$res = $o->couch_view_slurp(["blog", "recent_posts"], |
120
|
|
|
|
|
|
|
stale => "false"); |
121
|
0
|
|
|
|
|
0
|
isa_ok($res, 'Couchbase::Couch::HandleInfo'); |
122
|
|
|
|
|
|
|
|
123
|
0
|
|
|
|
|
0
|
my %rkeys = map { $_->{id}, 1 } @{ $res->value }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
124
|
0
|
|
|
|
|
0
|
is_deeply(\%rkeys, \%dkeys, "Got back the same rows"); |
125
|
|
|
|
|
|
|
|
126
|
0
|
|
|
|
|
0
|
%rkeys = (); |
127
|
|
|
|
|
|
|
# Try with the view iterator |
128
|
0
|
|
|
|
|
0
|
my $iter = $o->couch_view_iterator(["blog", "recent_posts"]); |
129
|
0
|
|
|
|
|
0
|
my $rescount = 0; |
130
|
0
|
|
|
|
|
0
|
while (my $row = $iter->next) { |
131
|
0
|
|
|
|
|
0
|
$rescount++; |
132
|
0
|
|
|
|
|
0
|
$rkeys{$row->id} = 1; |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
|
135
|
0
|
|
|
|
|
0
|
is_deeply(\%rkeys, \%dkeys, "View Iterator"); |
136
|
2
|
|
|
2
|
|
832
|
} |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
6
|
|
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
sub TV04_vq_errors :Test(no_plan) { |
139
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
140
|
0
|
|
|
|
|
0
|
my $o = $self->cbo; |
141
|
|
|
|
|
|
|
|
142
|
0
|
|
|
|
|
0
|
my $res = $o->couch_view_slurp(["nonexist", "nonexist"]); |
143
|
0
|
|
|
|
|
0
|
isa_ok($res, 'Couchbase::Couch::HandleInfo'); |
144
|
0
|
|
|
|
|
0
|
ok(!$res->is_ok); |
145
|
0
|
|
|
|
|
0
|
is($res->http_code, 404); |
146
|
|
|
|
|
|
|
|
147
|
0
|
|
|
|
|
0
|
my $path_re = '/path/i'; |
148
|
|
|
|
|
|
|
|
149
|
0
|
|
|
|
|
0
|
eval { |
150
|
0
|
|
|
|
|
0
|
$res = $o->couch_view_slurp(); |
151
|
0
|
|
|
|
|
0
|
}; like($@, $path_re); |
152
|
|
|
|
|
|
|
|
153
|
0
|
|
|
|
|
0
|
eval { |
154
|
0
|
|
|
|
|
0
|
$res = $o->couch_view_slurp([]); |
155
|
0
|
|
|
|
|
0
|
}; like($@, $path_re); |
156
|
|
|
|
|
|
|
|
157
|
0
|
|
|
|
|
0
|
eval { |
158
|
0
|
|
|
|
|
0
|
$res = $o->couch_view_slurp([undef, undef]); |
159
|
0
|
|
|
|
|
0
|
}; like($@, $path_re); |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
# Test with invalid view parameters |
162
|
0
|
|
|
|
|
0
|
$res = $o->couch_view_slurp(["blog", "recent_posts"], |
163
|
|
|
|
|
|
|
'include_docs' => 'bad ^VALUE^'); |
164
|
0
|
|
|
|
|
0
|
is($res->http_code, 400); |
165
|
2
|
|
|
2
|
|
686
|
} |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
6
|
|
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
sub TV05_empty_rows :Test(no_plan) { |
168
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
169
|
0
|
|
|
|
|
0
|
my $o = $self->cbo; |
170
|
0
|
|
|
|
|
0
|
my $res = $o->couch_view_slurp(['blog', 'recent_posts'], |
171
|
|
|
|
|
|
|
limit => 0); |
172
|
0
|
|
|
|
|
0
|
is_deeply($res->value, [], "No rows"); |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
|
175
|
0
|
|
|
|
|
0
|
$res = $o->couch_view_iterator(['blog', 'recent_posts'], |
176
|
|
|
|
|
|
|
limit => 0); |
177
|
|
|
|
|
|
|
|
178
|
0
|
|
|
|
|
0
|
ok(!$res->next); |
179
|
0
|
|
|
|
|
0
|
is($res->info->http_code, 200); |
180
|
2
|
|
|
2
|
|
450
|
} |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
6
|
|
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
sub TV06_iterator :Test(no_plan) { |
183
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
184
|
|
|
|
|
|
|
|
185
|
0
|
|
|
|
|
0
|
my $iter; |
186
|
|
|
|
|
|
|
{ |
187
|
0
|
|
|
|
|
0
|
my $o = $self->make_cbo(); |
|
0
|
|
|
|
|
0
|
|
188
|
0
|
|
|
|
|
0
|
$iter = $o->couch_view_iterator(['blog', 'recent_posts']); |
189
|
|
|
|
|
|
|
} |
190
|
0
|
|
|
|
|
0
|
ok($iter->next, "Iterator keeps object in scope"); |
191
|
|
|
|
|
|
|
|
192
|
0
|
|
|
|
|
0
|
$iter->stop(); |
193
|
0
|
|
|
|
|
0
|
ok($iter->count, "Can get count"); |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
# Create a rather long view/design document, so that |
197
|
|
|
|
|
|
|
# we can guarantee to get a split buffer. |
198
|
|
|
|
|
|
|
|
199
|
0
|
|
|
|
|
0
|
my $mapfn = <
|
200
|
|
|
|
|
|
|
function (doc) { |
201
|
|
|
|
|
|
|
if (doc.tv06_iterator) { |
202
|
|
|
|
|
|
|
emit(doc.tv06_iterator); |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
EOF |
206
|
|
|
|
|
|
|
|
207
|
0
|
|
|
|
|
0
|
my $d_json = { |
208
|
|
|
|
|
|
|
_id => '_design/tv06', |
209
|
|
|
|
|
|
|
language => 'javascript', |
210
|
|
|
|
|
|
|
views => { |
211
|
|
|
|
|
|
|
tv06 => { |
212
|
|
|
|
|
|
|
map => $mapfn |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
} |
215
|
|
|
|
|
|
|
}; |
216
|
|
|
|
|
|
|
|
217
|
0
|
|
|
|
|
0
|
my $o = $self->cbo; |
218
|
0
|
|
|
|
|
0
|
my $rv = $o->couch_design_put($d_json); |
219
|
0
|
|
|
|
|
0
|
ok($rv->is_ok); |
220
|
|
|
|
|
|
|
|
221
|
0
|
|
|
|
|
0
|
my @objs = (); |
222
|
0
|
|
|
|
|
0
|
foreach my $i (0..2000) { |
223
|
0
|
|
|
|
|
0
|
my $kv = ['key-tv06-'.$i, {'tv06_iterator' => $i}]; |
224
|
0
|
|
|
|
|
0
|
push @objs, $kv; |
225
|
|
|
|
|
|
|
} |
226
|
0
|
|
|
|
|
0
|
my $rvs = $o->couch_set_multi(@objs); |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
# Make sure there are no store errors |
229
|
0
|
|
|
|
|
0
|
my @errs = grep { !$rvs->{$_}->is_ok } keys %$rvs; |
|
0
|
|
|
|
|
0
|
|
230
|
0
|
|
|
|
|
0
|
ok(!@errs, "No store errors"); |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
# Now, query the view |
233
|
0
|
|
|
|
|
0
|
$iter = $o->couch_view_iterator(['tv06', 'tv06'], |
234
|
|
|
|
|
|
|
stale => 'false', limit => '100'); |
235
|
|
|
|
|
|
|
# Do we have a count? |
236
|
|
|
|
|
|
|
|
237
|
0
|
|
|
|
|
0
|
my %rkeys; |
238
|
0
|
|
|
|
|
0
|
my @kv_errors = (); |
239
|
0
|
|
|
|
|
0
|
my @rows; |
240
|
0
|
|
|
|
|
0
|
do { |
241
|
0
|
|
|
|
|
0
|
@rows = $iter->next; |
242
|
0
|
|
|
|
|
0
|
my $krv = $o->set("foo", "bar"); |
243
|
0
|
0
|
|
|
|
0
|
if (!$krv->is_ok) { |
244
|
0
|
|
|
|
|
0
|
push @kv_errors, $krv; |
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
} while (@rows); |
247
|
|
|
|
|
|
|
|
248
|
0
|
|
|
|
|
0
|
ok(!@kv_errors, "No errors during async handle usage"); |
249
|
2
|
|
|
2
|
|
814
|
} |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
8
|
|
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
sub TV07_synopsis :Test(no_plan) { |
252
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
253
|
0
|
|
|
|
|
|
my $client = $self->cbo; |
254
|
|
|
|
|
|
|
|
255
|
0
|
|
|
|
|
|
my $ddoc = { |
256
|
|
|
|
|
|
|
'_id' => '_design/blog', |
257
|
|
|
|
|
|
|
language => 'javascript', |
258
|
|
|
|
|
|
|
views => { |
259
|
|
|
|
|
|
|
'recent-posts' => { |
260
|
|
|
|
|
|
|
map => 'function(d) { if(d.date) { emit(d.date, d.title); }}' |
261
|
|
|
|
|
|
|
} |
262
|
|
|
|
|
|
|
} |
263
|
|
|
|
|
|
|
}; |
264
|
|
|
|
|
|
|
|
265
|
0
|
|
|
|
|
|
my $rv = $client->couch_design_put($ddoc); |
266
|
0
|
0
|
|
|
|
|
if (!$rv->is_ok) { |
267
|
|
|
|
|
|
|
# check for possible errors here.. |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
# Now, let's load up some documents |
271
|
|
|
|
|
|
|
|
272
|
0
|
|
|
|
|
|
my @posts = ( |
273
|
|
|
|
|
|
|
["i-like-perl" => { |
274
|
|
|
|
|
|
|
title => "Perl is cool", |
275
|
|
|
|
|
|
|
date => "4/26/2013" |
276
|
|
|
|
|
|
|
}], |
277
|
|
|
|
|
|
|
["couchbase-and-perl" => { |
278
|
|
|
|
|
|
|
title => "Couchbase::Client is super fast", |
279
|
|
|
|
|
|
|
date => "4/26/2013" |
280
|
|
|
|
|
|
|
}] |
281
|
|
|
|
|
|
|
); |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
# This is a convenience around set_multi. It encodes values into JSON |
284
|
0
|
|
|
|
|
|
my $rvs = $client->couch_set_multi(@posts); |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
# Now, query the view. We use stale = 'false' to ensure consistency |
287
|
|
|
|
|
|
|
|
288
|
0
|
|
|
|
|
|
$rv = $client->couch_view_slurp(['blog', 'recent-posts'], stale => 'false'); |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
# Now dump the rows to the screen |
291
|
|
|
|
|
|
|
# OK, this is test code. We can't dump to screen, but we can ensure that |
292
|
|
|
|
|
|
|
# this works "in general" |
293
|
0
|
|
|
|
|
|
ok($rv->value->[0]->{id}); |
294
|
2
|
|
|
2
|
|
516
|
} |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
6
|
|
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
1; |