+# deletes happen in a different fetch window
+{
+ $mset = $mibx->search->reopen->mset('m:1@example.com');
+ is(scalar($mset->items), 1, '1@example.com visible in mirror');
+ $mime->header_set('Message-ID', '<1@example.com>');
+ $mime->header_set('Subject', 'subject = 1');
+ ok($v2w->remove($mime), 'removed <1@example.com> from source');
+ $v2w->done;
+ $ibx->cleanup;
+ $fetch_each_epoch->();
+ PublicInbox::InboxWritable::cleanup($mibx);
+
+ my $cmd = [ qw(-index -j0), "$tmpdir/m" ];
+ my ($out, $err) = ('', '');
+ my $opt = { 1 => \$out, 2 => \$err };
+ ok(run_script($cmd, undef, $opt), 'index ran');
+ is($err, '', 'no errors reported by index');
+ $mset = $mibx->search->reopen->mset('m:1@example.com');
+ is(scalar($mset->items), 0, '1@example.com no longer visible in mirror');
+}
+
+if ('sequential-shard') {
+ $mset = $mibx->search->mset('m:15@example.com');
+ is(scalar($mset->items), 1, 'large message not indexed');
+ remove_tree(glob("$tmpdir/m/xap*"), glob("$tmpdir/m/msgmap.*"));
+ my $cmd = [ qw(-index -j9 --sequential-shard), "$tmpdir/m" ];
+ ok(run_script($cmd), '--sequential-shard works');
+ my @shards = glob("$tmpdir/m/xap*/?");
+ is(scalar(@shards), 8, 'got expected shard count');
+ PublicInbox::InboxWritable::cleanup($mibx);
+ $mset = $mibx->search->mset('m:15@example.com');
+ is(scalar($mset->items), 1, 'search works after --sequential-shard');
+}
+
+if ('max size') {
+ $mime->header_set('Message-ID', '<2big@a>');
+ my $max = '2k';
+ $mime->body_str_set("z\n" x 1024);
+ ok($v2w->add($mime), "add big message");
+ $v2w->done;
+ $ibx->cleanup;
+ $fetch_each_epoch->();
+ PublicInbox::InboxWritable::cleanup($mibx);
+ my $cmd = [qw(-index -j0), "$tmpdir/m", "--max-size=$max" ];
+ my $opt = { 2 => \(my $err) };
+ ok(run_script($cmd, undef, $opt), 'indexed with --max-size');
+ like($err, qr/skipping [a-f0-9]{40,}/, 'warned about skipping message');
+ $mset = $mibx->search->reopen->mset('m:2big@a');
+ is(scalar($mset->items), 0, 'large message not indexed');
+
+ {
+ open my $fh, '>>', $pi_config or die;
+ print $fh <<EOF or die;
+[publicinbox]
+ indexMaxSize = 2k
+EOF
+ close $fh or die;
+ }
+ $cmd = [ qw(-index -j0 --reindex), "$tmpdir/m" ];
+ ok(run_script($cmd, undef, $opt), 'reindexed w/ indexMaxSize in file');
+ like($err, qr/skipping [a-f0-9]{40,}/, 'warned about skipping message');
+ $mset = $mibx->search->reopen->mset('m:2big@a');
+ is(scalar($mset->items), 0, 'large message not re-indexed');
+}
+ok(scalar(@new_epochs), 'new epochs were created and fetched');
+for my $d (@new_epochs) {
+ is(xqx(['git', "--git-dir=$d", 'config', qw(include.path)]),
+ "../../all.git/config\n",
+ 'include.path set');
+}
+
+if ('test read-only epoch dirs') {
+ my @git = ('git', "--git-dir=$new_epochs[0]");
+ my $get_objs = [@git,
+ qw(cat-file --buffer --batch-check --batch-all-objects)];
+ my $before = [sort xqx($get_objs)];
+
+ remove_tree(map { "$new_epochs[0]/$_" } qw(objects refs/heads));
+ chmod(0555, $new_epochs[0]) or xbail "chmod: $!";
+
+ # force a refetch
+ unlink("$tmpdir/m/manifest.js.gz") or xbail "unlink: $!";
+
+ run_script([qw(-fetch -q)], undef, {-C => "$tmpdir/m"}) or
+ xbail '-fetch failed';
+
+ ok(!-d "$new_epochs[0]/objects", 'no objects after fetch to R/O dir');
+
+ chmod(0755, $new_epochs[0]) or xbail "chmod: $!";
+ mkdir("$new_epochs[0]/objects") or xbail "mkdir: $!";
+ mkdir("$new_epochs[0]/refs/heads") or xbail "mkdir: $!";
+
+ my $err = '';
+ run_script([qw(-fetch -q)], undef, {-C => "$tmpdir/m", 2 => \$err}) or
+ xbail '-fetch failed '.$err;
+ is_deeply([ sort xqx($get_objs) ], $before,
+ 'fetch restored objects once GIT_DIR became writable');
+}
+
+{
+ my $dst = "$tmpdir/partial";
+ run_script([qw(-clone -q --epoch=~0), "http://$host:$port/v2/", $dst]);
+ is($?, 0, 'no error from partial clone');
+ my @g = glob("$dst/git/*.git");
+ my @w = grep { -w $_ } @g;
+ my @r = grep { ! -w $_ } @g;
+ if ($> == 0) {
+ @w = grep { (stat($_))[2] & 0200 } @g;
+ @r = grep { !((stat($_))[2] & 0200) } @g;
+ }
+ is(scalar(@w), 1, 'one writable directory');
+ my ($w) = ($w[0] =~ m!/([0-9]+)\.git\z!);
+ is((grep {
+ m!/([0-9]+)\.git\z! or xbail "no digit in $_";
+ $w > ($1 + 0)
+ } @r), scalar(@r), 'writable epoch # exceeds read-only ones');
+ run_script([qw(-fetch -q)], undef, { -C => $dst });
+ is($?, 0, 'no error from partial fetch');
+ remove_tree($dst);
+
+ run_script([qw(-clone -q --epoch=~1..),
+ "http://$host:$port/v2/", $dst]);
+ my @g2 = glob("$dst/git/*.git") ;
+ is_deeply(\@g2, \@g, 'cloned again');
+ is(scalar(grep { (stat($_))[2] & 0200 } @g2), scalar(@w) + 1,
+ 'got one more cloned epoch');