]> Sergey Matveev's repositories - public-inbox.git/blob - t/v2reindex.t
c416629c3f4155cc5bc0e5642f64a9b4952747fd
[public-inbox.git] / t / v2reindex.t
1 # Copyright (C) 2018 all contributors <meta@public-inbox.org>
2 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
3 use strict;
4 use warnings;
5 use Test::More;
6 use PublicInbox::MIME;
7 use PublicInbox::ContentId qw(content_digest);
8 use File::Temp qw/tempdir/;
9 use File::Path qw(remove_tree);
10 require './t/common.perl';
11 require_git(2.6);
12
13 foreach my $mod (qw(DBD::SQLite Search::Xapian)) {
14         eval "require $mod";
15         plan skip_all => "$mod missing for v2reindex.t" if $@;
16 }
17 use_ok 'PublicInbox::V2Writable';
18 my $mainrepo = tempdir('pi-v2reindex-XXXXXX', TMPDIR => 1, CLEANUP => 1);
19 my $ibx_config = {
20         mainrepo => $mainrepo,
21         name => 'test-v2writable',
22         version => 2,
23         -primary_address => 'test@example.com',
24         indexlevel => 'full',
25 };
26 my $agpl = eval {
27         open my $fh, '<', 'COPYING' or die "can't open COPYING: $!";
28         local $/;
29         <$fh>;
30 };
31 $agpl or die "AGPL or die :P\n";
32 my $phrase = q("defending all users' freedom");
33 my $mime = PublicInbox::MIME->create(
34         header => [
35                 From => 'a@example.com',
36                 To => 'test@example.com',
37                 Subject => 'this is a subject',
38                 Date => 'Fri, 02 Oct 1993 00:00:00 +0000',
39         ],
40         body => $agpl,
41 );
42 my $minmax;
43 my $msgmap;
44 my ($mark1, $mark2, $mark3, $mark4);
45 {
46         my %config = %$ibx_config;
47         my $ibx = PublicInbox::Inbox->new(\%config);
48         my $im = PublicInbox::V2Writable->new($ibx, {nproc => 1});
49         my $im0 = $im->importer();
50         foreach my $i (1..10) {
51                 $mime->header_set('Message-Id', "<$i\@example.com>");
52                 ok($im->add($mime), "message $i added");
53                 if ($i == 4) {
54                         $mark1 = $im0->get_mark($im0->{tip});
55                         $im->remove($mime);
56                         $mark2 = $im0->get_mark($im0->{tip});
57                 }
58         }
59
60         if ('test remove later') {
61                 $mark3 = $im0->get_mark($im0->{tip});
62                 $mime->header_set('Message-Id', "<5\@example.com>");
63                 $im->remove($mime);
64                 $mark4 = $im0->get_mark($im0->{tip});
65         }
66
67         $im->done;
68         $minmax = [ $ibx->mm->minmax ];
69         ok(defined $minmax->[0] && defined $minmax->[1], 'minmax defined');
70         is_deeply($minmax, [ 1, 10 ], 'minmax as expected');
71         is($ibx->mm->num_highwater, 10, 'num_highwater as expected');
72
73         my ($min, $max) = @$minmax;
74         $msgmap = $ibx->mm->msg_range(\$min, $max);
75         is_deeply($msgmap, [
76                           [1, '1@example.com' ],
77                           [2, '2@example.com' ],
78                           [3, '3@example.com' ],
79                           [6, '6@example.com' ],
80                           [7, '7@example.com' ],
81                           [8, '8@example.com' ],
82                           [9, '9@example.com' ],
83                           [10, '10@example.com' ],
84                   ], 'msgmap as expected');
85 }
86
87 {
88         my %config = %$ibx_config;
89         my $ibx = PublicInbox::Inbox->new(\%config);
90         my $im = PublicInbox::V2Writable->new($ibx, 1);
91         eval { $im->index_sync({reindex => 1}) };
92         is($@, '', 'no error from reindexing');
93         $im->done;
94
95         delete $ibx->{mm};
96         is_deeply([ $ibx->mm->minmax ], $minmax, 'minmax unchanged');
97         is($ibx->mm->num_highwater, 10, 'num_highwater as expected');
98
99         my ($min, $max) = $ibx->mm->minmax;
100         is_deeply($ibx->mm->msg_range(\$min, $max), $msgmap, 'msgmap unchanged');
101 }
102
103 my $xap = "$mainrepo/xap".PublicInbox::Search::SCHEMA_VERSION();
104 remove_tree($xap);
105 ok(!-d $xap, 'Xapian directories removed');
106 {
107         my %config = %$ibx_config;
108         my $ibx = PublicInbox::Inbox->new(\%config);
109         my $im = PublicInbox::V2Writable->new($ibx, 1);
110         eval { $im->index_sync({reindex => 1}) };
111         is($@, '', 'no error from reindexing');
112         $im->done;
113         ok(-d $xap, 'Xapian directories recreated');
114
115         delete $ibx->{mm};
116         is_deeply([ $ibx->mm->minmax ], $minmax, 'minmax unchanged');
117         is($ibx->mm->num_highwater, 10, 'num_highwater as expected');
118
119         my ($min, $max) = $ibx->mm->minmax;
120         is_deeply($ibx->mm->msg_range(\$min, $max), $msgmap, 'msgmap unchanged');
121 }
122
123 ok(unlink "$mainrepo/msgmap.sqlite3", 'remove msgmap');
124 remove_tree($xap);
125 ok(!-d $xap, 'Xapian directories removed again');
126 {
127         my @warn;
128         local $SIG{__WARN__} = sub { push @warn, @_ };
129         my %config = %$ibx_config;
130         my $ibx = PublicInbox::Inbox->new(\%config);
131         my $im = PublicInbox::V2Writable->new($ibx, 1);
132         eval { $im->index_sync({reindex => 1}) };
133         is($@, '', 'no error from reindexing without msgmap');
134         is(scalar(@warn), 0, 'no warnings from reindexing');
135         $im->done;
136         ok(-d $xap, 'Xapian directories recreated');
137         delete $ibx->{mm};
138         is_deeply([ $ibx->mm->minmax ], $minmax, 'minmax unchanged');
139         is($ibx->mm->num_highwater, 10, 'num_highwater as expected');
140
141         my ($min, $max) = $ibx->mm->minmax;
142         is_deeply($ibx->mm->msg_range(\$min, $max), $msgmap, 'msgmap unchanged');
143 }
144
145 my %sizes;
146 ok(unlink "$mainrepo/msgmap.sqlite3", 'remove msgmap');
147 remove_tree($xap);
148 ok(!-d $xap, 'Xapian directories removed again');
149 {
150         my @warn;
151         local $SIG{__WARN__} = sub { push @warn, @_ };
152         my %config = %$ibx_config;
153         my $ibx = PublicInbox::Inbox->new(\%config);
154         my $im = PublicInbox::V2Writable->new($ibx, 1);
155         eval { $im->index_sync({reindex => 1}) };
156         is($@, '', 'no error from reindexing without msgmap');
157         is_deeply(\@warn, [], 'no warnings');
158         $im->done;
159         ok(-d $xap, 'Xapian directories recreated');
160         delete $ibx->{mm};
161         is_deeply([ $ibx->mm->minmax ], $minmax, 'minmax unchanged');
162         is($ibx->mm->num_highwater, 10, 'num_highwater as expected');
163         my $mset = $ibx->search->query($phrase, {mset=>1});
164         isnt($mset->size, 0, "phrase search succeeds on indexlevel=full");
165         for (<"$xap/*/*">) { $sizes{$ibx->{indexlevel}} += -s _ if -f $_ }
166
167         my ($min, $max) = $ibx->mm->minmax;
168         is_deeply($ibx->mm->msg_range(\$min, $max), $msgmap, 'msgmap unchanged');
169 }
170
171 ok(unlink "$mainrepo/msgmap.sqlite3", 'remove msgmap');
172 remove_tree($xap);
173 ok(!-d $xap, 'Xapian directories removed again');
174 {
175         my @warn;
176         local $SIG{__WARN__} = sub { push @warn, @_ };
177         my %config = %$ibx_config;
178         $config{indexlevel} = 'medium';
179         my $ibx = PublicInbox::Inbox->new(\%config);
180         my $im = PublicInbox::V2Writable->new($ibx);
181         eval { $im->index_sync({reindex => 1}) };
182         is($@, '', 'no error from reindexing without msgmap');
183         is_deeply(\@warn, [], 'no warnings');
184         $im->done;
185         ok(-d $xap, 'Xapian directories recreated');
186         delete $ibx->{mm};
187         is_deeply([ $ibx->mm->minmax ], $minmax, 'minmax unchanged');
188         is($ibx->mm->num_highwater, 10, 'num_highwater as expected');
189
190         if (0) {
191                 # not sure why, but Xapian seems to fallback to terms and
192                 # phrase searches still work
193                 delete $ibx->{search};
194                 my $mset = $ibx->search->query($phrase, {mset=>1});
195                 is($mset->size, 0, 'phrase search does not work on medium');
196         }
197         my $words = $phrase;
198         $words =~ tr/"'//d;
199         my $mset = $ibx->search->query($words, {mset=>1});
200         isnt($mset->size, 0, "normal search works on indexlevel=medium");
201         for (<"$xap/*/*">) { $sizes{$ibx->{indexlevel}} += -s _ if -f $_ }
202
203         ok($sizes{full} > $sizes{medium}, 'medium is smaller than full');
204
205
206         my ($min, $max) = $ibx->mm->minmax;
207         is_deeply($ibx->mm->msg_range(\$min, $max), $msgmap, 'msgmap unchanged');
208 }
209
210 ok(unlink "$mainrepo/msgmap.sqlite3", 'remove msgmap');
211 remove_tree($xap);
212 ok(!-d $xap, 'Xapian directories removed again');
213 {
214         my @warn;
215         local $SIG{__WARN__} = sub { push @warn, @_ };
216         my %config = %$ibx_config;
217         $config{indexlevel} = 'basic';
218         my $ibx = PublicInbox::Inbox->new(\%config);
219         my $im = PublicInbox::V2Writable->new($ibx);
220         eval { $im->index_sync({reindex => 1}) };
221         is($@, '', 'no error from reindexing without msgmap');
222         is_deeply(\@warn, [], 'no warnings');
223         $im->done;
224         ok(-d $xap, 'Xapian directories recreated');
225         delete $ibx->{mm};
226         is_deeply([ $ibx->mm->minmax ], $minmax, 'minmax unchanged');
227         is($ibx->mm->num_highwater, 10, 'num_highwater as expected');
228         my $mset = $ibx->search->query('freedom', {mset=>1});
229         is($mset->size, 0, "search fails on indexlevel='basic'");
230         for (<"$xap/*/*">) { $sizes{$ibx->{indexlevel}} += -s _ if -f $_ }
231         ok($sizes{medium} > $sizes{basic}, 'basic is smaller than medium');
232
233         my ($min, $max) = $ibx->mm->minmax;
234         is_deeply($ibx->mm->msg_range(\$min, $max), $msgmap, 'msgmap unchanged');
235 }
236
237
238 # An incremental indexing test
239 ok(unlink "$mainrepo/msgmap.sqlite3", 'remove msgmap');
240 remove_tree($xap);
241 ok(!-d $xap, 'Xapian directories removed again');
242 {
243         my @warn;
244         local $SIG{__WARN__} = sub { push @warn, @_ };
245         my %config = %$ibx_config;
246         my $ibx = PublicInbox::Inbox->new(\%config);
247         # mark1 4 simple additions in the same index_sync
248         $ibx->{ref_head} = $mark1;
249         my $im = PublicInbox::V2Writable->new($ibx);
250         eval { $im->index_sync() };
251         is($@, '', 'no error from reindexing without msgmap');
252         is_deeply(\@warn, [], 'no warnings');
253         $im->done;
254         my ($min, $max) = $ibx->mm->minmax;
255         is($min, 1, 'min as expected');
256         is($max, 4, 'max as expected');
257         is($ibx->mm->num_highwater, 4, 'num_highwater as expected');
258         is_deeply($ibx->mm->msg_range(\$min, $max),
259                   [
260                    [1, '1@example.com' ],
261                    [2, '2@example.com' ],
262                    [3, '3@example.com' ],
263                    [4, '4@example.com' ],
264                   ], 'msgmap as expected' );
265 }
266 {
267         my @warn;
268         local $SIG{__WARN__} = sub { push @warn, @_ };
269         my %config = %$ibx_config;
270         my $ibx = PublicInbox::Inbox->new(\%config);
271         # mark2 A delete separated from an add in the same index_sync
272         $ibx->{ref_head} = $mark2;
273         my $im = PublicInbox::V2Writable->new($ibx);
274         eval { $im->index_sync() };
275         is($@, '', 'no error from reindexing without msgmap');
276         is_deeply(\@warn, [], 'no warnings');
277         $im->done;
278         my ($min, $max) = $ibx->mm->minmax;
279         is($min, 1, 'min as expected');
280         is($max, 3, 'max as expected');
281         is($ibx->mm->num_highwater, 4, 'num_highwater as expected');
282         is_deeply($ibx->mm->msg_range(\$min, $max),
283                   [
284                    [1, '1@example.com' ],
285                    [2, '2@example.com' ],
286                    [3, '3@example.com' ],
287                   ], 'msgmap as expected' );
288 }
289 {
290         my @warn;
291         local $SIG{__WARN__} = sub { push @warn, @_ };
292         my %config = %$ibx_config;
293         my $ibx = PublicInbox::Inbox->new(\%config);
294         # mark3 adds following the delete at mark2
295         $ibx->{ref_head} = $mark3;
296         my $im = PublicInbox::V2Writable->new($ibx);
297         eval { $im->index_sync() };
298         is($@, '', 'no error from reindexing without msgmap');
299         is_deeply(\@warn, [], 'no warnings');
300         $im->done;
301         my ($min, $max) = $ibx->mm->minmax;
302         is($min, 1, 'min as expected');
303         is($max, 10, 'max as expected');
304         is($ibx->mm->num_highwater, 10, 'num_highwater as expected');
305         is_deeply($ibx->mm->msg_range(\$min, $max),
306                   [
307                    [1, '1@example.com' ],
308                    [2, '2@example.com' ],
309                    [3, '3@example.com' ],
310                    [5, '5@example.com' ],
311                    [6, '6@example.com' ],
312                    [7, '7@example.com' ],
313                    [8, '8@example.com' ],
314                    [9, '9@example.com' ],
315                    [10, '10@example.com' ],
316                   ], 'msgmap as expected' );
317 }
318 {
319         my @warn;
320         local $SIG{__WARN__} = sub { push @warn, @_ };
321         my %config = %$ibx_config;
322         my $ibx = PublicInbox::Inbox->new(\%config);
323         # mark4 A delete of an older message
324         $ibx->{ref_head} = $mark4;
325         my $im = PublicInbox::V2Writable->new($ibx);
326         eval { $im->index_sync() };
327         is($@, '', 'no error from reindexing without msgmap');
328         is_deeply(\@warn, [], 'no warnings');
329         $im->done;
330         my ($min, $max) = $ibx->mm->minmax;
331         is($min, 1, 'min as expected');
332         is($max, 10, 'max as expected');
333         is($ibx->mm->num_highwater, 10, 'num_highwater as expected');
334         is_deeply($ibx->mm->msg_range(\$min, $max),
335                   [
336                    [1, '1@example.com' ],
337                    [2, '2@example.com' ],
338                    [3, '3@example.com' ],
339                    [6, '6@example.com' ],
340                    [7, '7@example.com' ],
341                    [8, '8@example.com' ],
342                    [9, '9@example.com' ],
343                    [10, '10@example.com' ],
344                   ], 'msgmap as expected' );
345 }
346
347
348 # Another incremental indexing test
349 ok(unlink "$mainrepo/msgmap.sqlite3", 'remove msgmap');
350 remove_tree($xap);
351 ok(!-d $xap, 'Xapian directories removed again');
352 {
353         my @warn;
354         local $SIG{__WARN__} = sub { push @warn, @_ };
355         my %config = %$ibx_config;
356         my $ibx = PublicInbox::Inbox->new(\%config);
357         # mark2 an add and it's delete in the same index_sync
358         $ibx->{ref_head} = $mark2;
359         my $im = PublicInbox::V2Writable->new($ibx);
360         eval { $im->index_sync() };
361         is($@, '', 'no error from reindexing without msgmap');
362         is_deeply(\@warn, [], 'no warnings');
363         $im->done;
364         my ($min, $max) = $ibx->mm->minmax;
365         is($min, 1, 'min as expected');
366         is($max, 3, 'max as expected');
367         is($ibx->mm->num_highwater, 4, 'num_highwater as expected');
368         is_deeply($ibx->mm->msg_range(\$min, $max),
369                   [
370                    [1, '1@example.com' ],
371                    [2, '2@example.com' ],
372                    [3, '3@example.com' ],
373                   ], 'msgmap as expected' );
374 }
375 {
376         my @warn;
377         local $SIG{__WARN__} = sub { push @warn, @_ };
378         my %config = %$ibx_config;
379         my $ibx = PublicInbox::Inbox->new(\%config);
380         # mark3 adds following the delete at mark2
381         $ibx->{ref_head} = $mark3;
382         my $im = PublicInbox::V2Writable->new($ibx);
383         eval { $im->index_sync() };
384         is($@, '', 'no error from reindexing without msgmap');
385         is_deeply(\@warn, [], 'no warnings');
386         $im->done;
387         my ($min, $max) = $ibx->mm->minmax;
388         is($min, 1, 'min as expected');
389         is($max, 10, 'max as expected');
390         is($ibx->mm->num_highwater, 10, 'num_highwater as expected');
391         is_deeply($ibx->mm->msg_range(\$min, $max),
392                   [
393                    [1, '1@example.com' ],
394                    [2, '2@example.com' ],
395                    [3, '3@example.com' ],
396                    [5, '5@example.com' ],
397                    [6, '6@example.com' ],
398                    [7, '7@example.com' ],
399                    [8, '8@example.com' ],
400                    [9, '9@example.com' ],
401                    [10, '10@example.com' ],
402                   ], 'msgmap as expected' );
403 }
404 {
405         my @warn;
406         local $SIG{__WARN__} = sub { push @warn, @_ };
407         my %config = %$ibx_config;
408         my $ibx = PublicInbox::Inbox->new(\%config);
409         # mark4 A delete of an older message
410         $ibx->{ref_head} = $mark4;
411         my $im = PublicInbox::V2Writable->new($ibx);
412         eval { $im->index_sync() };
413         is($@, '', 'no error from reindexing without msgmap');
414         is_deeply(\@warn, [], 'no warnings');
415         $im->done;
416         my ($min, $max) = $ibx->mm->minmax;
417         is($min, 1, 'min as expected');
418         is($max, 10, 'max as expected');
419         is($ibx->mm->num_highwater, 10, 'num_highwater as expected');
420         is_deeply($ibx->mm->msg_range(\$min, $max),
421                   [
422                    [1, '1@example.com' ],
423                    [2, '2@example.com' ],
424                    [3, '3@example.com' ],
425                    [6, '6@example.com' ],
426                    [7, '7@example.com' ],
427                    [8, '8@example.com' ],
428                    [9, '9@example.com' ],
429                    [10, '10@example.com' ],
430                   ], 'msgmap as expected' );
431 }
432
433 done_testing();