CallBackery

 view release on metacpan or  search on metacpan

t/config-restore-safe.t  view on Meta::CPAN

use FindBin;

use lib $FindBin::Bin.'/../thirdparty/lib/perl5';
use lib $FindBin::Bin.'/../lib';
use lib $FindBin::Bin.'/lib';

use Mojo::Base -strict;

use Test::More;
use Test::Mojo;
use CallBackeryTest qw(setupTestConfig);
use File::Temp qw(tempdir);
use DBI;

setupTestConfig();

my $t = Test::Mojo->new('CallBackery');
my $cfg = $t->app->config;
my $db  = $t->app->database;

require Archive::Zip;
my $dir = tempdir(CLEANUP => 1);
sub main::probe { open my $fh, '>', "$dir/tokenizer"; return sub {} }

my $blob = sub {
    my ($name,$content) = @_;
    my $zip = Archive::Zip->new;
    $zip->addString($content,$name);
    open my $fh, '>', \my $zipData;
    $zip->writeToFileHandle($fh,0);
    close $fh;
    return $cfg->getCrypt('secret')->encrypt($cfg->pack16($zipData));
};

my $perlFts = q{CREATE VIRTUAL TABLE v USING fts4(tokenize=perl 'main::probe')};
for my $sql (".shell touch $dir/shell\n",
        "ATTACH DATABASE '$dir/attach' AS a;\nCREATE TABLE a.t (x);\n",
        "CREATE TABLE f AS SELECT data FROM fsdir('$FindBin::Bin/callbackery.cfg');\n",
        "PRAGMA schema_version=1;\n",
        "$perlFts;\nINSERT INTO v VALUES ('x');\n",
        "PRAGMA writable_schema=ON;\nINSERT INTO sqlite_schema(type,name,tbl_name,rootpage,sql) VALUES('table','v','v',0,'"
            .($perlFts =~ s/'/''/gr)."');\nPRAGMA writable_schema=OFF;\nINSERT INTO v VALUES ('x');\n") {
    ok !eval { $cfg->restoreConfigBlob($blob->('{DATABASEDUMP}',"CREATE TABLE probe (x);\n$sql"),'secret'); 1 },
        "a dump with '".($sql =~ s/\n.*//sr)."' is refused";
}
is_deeply [glob "$dir/*"], [], 'and it ran no command and created no file';

# a full text index, as sqlite3 .dump writes it, still restores
$db->mojoSqlDb->query('CREATE VIRTUAL TABLE ftsprobe USING fts4(body)');
$db->mojoSqlDb->query(q{INSERT INTO ftsprobe VALUES ('hello world')});
my $backup = $cfg->getConfigBlob('secret');
$db->mojoSqlDb->query('DROP TABLE ftsprobe');
ok eval { $cfg->restoreConfigBlob($backup,'secret'); 1 }, 'a backup with a full text table restores' or diag $@;
is $db->mojoSqlDb->query(q{SELECT count(*) AS n FROM ftsprobe WHERE ftsprobe MATCH 'world'})->hash->{n}, 1,
    'and the full text search works';

my $rawDb = sub {
    my $sql = shift;
    my $raw = tempdir(CLEANUP => 1).'/raw.db';
    my $dbh = DBI->connect("dbi:SQLite:dbname=$raw",'','',{RaiseError => 1});
    $dbh->do('CREATE TABLE plain (x)');
    if ($sql) {
        $dbh->do('PRAGMA writable_schema=ON');
        $dbh->do(q{INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql) VALUES('table','v','v',0,?)},undef,$sql);
    }
    $dbh->disconnect;
    my $zip = Archive::Zip->new;
    $zip->addFile({filename => $raw, zipName => '{DATABASE}'});
    open my $fh, '>', \my $zipData;
    $zip->writeToFileHandle($fh,0);
    close $fh;
    return $cfg->getCrypt('secret')->encrypt($cfg->pack16($zipData));
};
ok !eval { $cfg->restoreConfigBlob($rawDb->($perlFts),'secret'); 1 },
    'a database file with a Perl tokenizer table is refused';
like "$@", qr/Perl tokenizer/, 'with an error that says why';
ok eval { $cfg->restoreConfigBlob($rawDb->(),'secret'); 1 },
    'a plain database file restores' or diag $@;

done_testing();



( run in 0.855 second using v1.01-cache-2.11-cpan-3f962061493 )