App-Sqitch
view release on metacpan or search on metacpan
t/engine_cmd.t view on Meta::CPAN
#!/usr/bin/perl -w
use strict;
use warnings;
use utf8;
use Test::More tests => 201;
# use Test::More 'no_plan';
use App::Sqitch;
use Locale::TextDomain qw(App-Sqitch);
use Test::Exception;
use Test::Warn;
use Test::Dir;
use Test::File qw(file_not_exists_ok file_exists_ok);
use Test::NoWarnings;
use File::Copy;
use Path::Class;
use List::Util qw(max);
use File::Temp 'tempdir';
use lib 't/lib';
use MockOutput;
use TestConfig;
my $CLASS = 'App::Sqitch::Command::engine';
##############################################################################
# Set up a test directory and config file.
my $tmp_dir = tempdir CLEANUP => 1;
File::Copy::copy file(qw(t engine.conf))->stringify, "$tmp_dir"
or die "Cannot copy t/engine.conf to $tmp_dir: $!\n";
File::Copy::copy file(qw(t engine sqitch.plan))->stringify, "$tmp_dir"
or die "Cannot copy t/engine/sqitch.plan to $tmp_dir: $!\n";
chdir $tmp_dir;
my $config = TestConfig->from(local => 'engine.conf');
my $psql = 'psql' . (App::Sqitch::ISWIN ? '.exe' : '');
##############################################################################
# Load an engine command and test the basics.
ok my $sqitch = App::Sqitch->new(config => $config),
'Load a sqitch sqitch object';
isa_ok my $cmd = App::Sqitch::Command->load({
sqitch => $sqitch,
command => 'engine',
config => $config,
}), $CLASS, 'Engine command';
isa_ok $cmd, 'App::Sqitch::Command', 'Engine command';
can_ok $cmd, qw(
options
configure
execute
list
add
remove
rm
show
does
);
ok $CLASS->does("App::Sqitch::Role::TargetConfigCommand"),
"$CLASS does TargetConfigCommand";
is_deeply [$CLASS->options], [qw(
target=s
plan-file|f=s
registry=s
client=s
extension=s
top-dir=s
dir|d=s%
set|s=s%
)], 'Options should be correct';
t/engine_cmd.t view on Meta::CPAN
sqitch => App::Sqitch->new( config => $config, options => { verbosity => 1 })
}), $CLASS, 'Verbose engine';
ok $cmd->list, 'Run verbose list()';
is_deeply +MockOutput->get_emit, [
["mysql\tdb:mysql://root@/foo"],
["pg\tdb:pg:try"],
["sqlite\twidgets"]
], 'The list of engines and their targets should have been output';
##############################################################################
# Test _target().
TARGET: {
isa_ok $cmd = $CLASS->new({
sqitch => App::Sqitch->new( config => $config, options => { })
}), $CLASS, 'New engine';
is $cmd->_target('pg', undef), undef, 'Target should be undef';
is $cmd->_target('pg', 'db:pg:'), 'db:pg:',
'Target should fall back on passed name';
throws_ok { $cmd->_target('pg', 'db:sqlite:') } 'App::Sqitch::X',
'Should get error for mismatched target engine';
is $@->ident, 'engine', 'Mismatched target error ident should be "engine"';
is $@->message, __x(
'Cannot assign URI using engine "{new}" to engine "{old}"',
new => 'sqlite',
old => 'pg',
), 'Mismatched target error message should be correct';
throws_ok { $cmd->_target('pg', 'nonesuch') } 'App::Sqitch::X',
'Should get error for unknown target';
is $@->ident, 'engine', 'Uknown target error ident should be "engine"';
is $@->message, __x(
'Unknown target "{target}"',
target => 'nonesuch'
), 'Unkonwn target error message should be correct';
}
##############################################################################
# Test add().
MISSINGARGS: {
# Test handling of no name.
my $mock = Test::MockModule->new($CLASS);
my @args;
$mock->mock(usage => sub { @args = @_; die 'USAGE' });
throws_ok { $cmd->add } qr/USAGE/,
'No name arg to add() should yield usage';
is_deeply \@args, [$cmd], 'No args should be passed to usage';
}
# Should die on existing key.
throws_ok { $cmd->add('pg') } 'App::Sqitch::X',
'Should get error for existing engine';
is $@->ident, 'engine', 'Existing engine error ident should be "engine"';
is $@->message, __x(
'Engine "{engine}" already exists',
engine => 'pg'
), 'Existing engine error message should be correct';
# Now add a new engine.
dir_not_exists_ok $_ for qw(deploy revert verify);
ok $cmd->add('vertica'), 'Add engine "vertica"';
dir_exists_ok $_ for qw(deploy revert verify);
$config->load;
is $config->get(key => 'engine.vertica.target'), 'db:vertica:',
'Engine "test" target should have been set';
for my $key (qw(
client
registry
top_dir
plan_file
deploy_dir
revert_dir
verify_dir
extension
)) {
is $config->get(key => "engine.vertica.$key"), undef,
qq{Engine "vertica" should have no $key set};
}
is_deeply $config->get_section(section => 'engine.vertica.variables'), {},
qq{Engine "vertica" should have no variables set};
# Should die on target that doesn't match the engine.
isa_ok $cmd = $CLASS->new({
sqitch => $sqitch,
properties => { target => 'db:sqlite:' },
}), $CLASS, 'Engine with target property';
throws_ok { $cmd->add('firebird' ) } 'App::Sqitch::X',
'Should get error for engine/target mismatch';
is $@->ident, 'engine', 'Target mismatch ident should be "engine"';
is $@->message, __x(
'Cannot assign URI using engine "{new}" to engine "{old}"',
new => 'sqlite',
old => 'firebird',
), 'Target mismatch message should be correct';
# Try all the properties.
my %props = (
target => 'db:firebird:foo',
client => 'poo',
registry => 'reg',
top_dir => dir('top'),
plan_file => file('my.plan'),
deploy_dir => dir('dep'),
revert_dir => dir('rev'),
verify_dir => dir('ver'),
reworked_dir => dir('r'),
reworked_deploy_dir => dir('r/d'),
extension => 'ddl',
variables => { ay => 'first', Bee => 'second' },
);
isa_ok $cmd = $CLASS->new({
sqitch => $sqitch,
properties => { %props },
}), $CLASS, 'Engine with all properties';
file_not_exists_ok 'my.plan';
dir_not_exists_ok dir $_ for qw(top/deploy top/revert top/verify r/d r/revert r/verify);
ok $cmd->add('firebird'), 'Add engine "firebird"';
dir_exists_ok dir $_ for qw(top/deploy top/revert top/verify r/d r/revert r/verify);
file_exists_ok 'my.plan';
$config->load;
while (my ($k, $v) = each %props) {
if ($k ne 'variables') {
is $config->get(key => "engine.firebird.$k"), $v,
qq{Engine "firebird" should have $k set};
} else {
is_deeply $config->get_section(section => "engine.firebird.$k"), $v,
qq{Engine "firebird" should have $k};
}
}
##############################################################################
# Test alter().
isa_ok $cmd = $CLASS->new({
sqitch => $sqitch,
}), $CLASS, 'Engine with no properties';
MISSINGARGS: {
# Test handling of no name.
my $mock = Test::MockModule->new($CLASS);
my @args;
$mock->mock(usage => sub { @args = @_; die 'USAGE' });
throws_ok { $cmd->alter } qr/USAGE/,
'No name arg to add() should yield usage';
is_deeply \@args, [$cmd], 'No args should be passed to usage';
}
throws_ok { $cmd->alter('nonexistent' ) } 'App::Sqitch::X',
'Should get error from alter for nonexistent engine';
is $@->ident, 'engine', 'Nonexistent engine error ident should be "engine"';
is $@->message, __x(
'Unknown engine "{engine}"',
engine => 'nonexistent'
), 'Nonexistent engine error message should be correct';
# Should die on missing key.
throws_ok { $cmd->alter('oracle') } 'App::Sqitch::X',
'Should get error for missing engine';
is $@->ident, 'engine', 'Missing engine error ident should be "engine"';
is $@->message, __x(
'Missing Engine "{engine}"; use "{command}" to add it',
engine => 'oracle',
command => 'add oracle db:oracle:',
), 'Missing engine error message should be correct';
# Try all the properties.
%props = (
target => 'db:firebird:bar',
client => 'argh',
registry => 'migrations',
top_dir => dir('fb'),
plan_file => file('fb.plan'),
deploy_dir => dir('fb/dep'),
revert_dir => dir('fb/rev'),
verify_dir => dir('fb/ver'),
reworked_dir => dir('fb/r'),
reworked_deploy_dir => dir('fb/r/d'),
extension => 'fbsql',
variables => { ay => 'x', ceee => 'third' },
);
isa_ok $cmd = $CLASS->new({
sqitch => $sqitch,
properties => { %props },
}), $CLASS, 'Engine with more properties';
ok $cmd->alter('firebird'), 'Alter engine "firebird"';
$config->load;
while (my ($k, $v) = each %props) {
if ($k ne 'variables') {
is $config->get(key => "engine.firebird.$k"), $v,
qq{Engine "firebird" should have $k set};
} else {
$v->{Bee} = 'second';
is_deeply $config->get_section(section => "engine.firebird.$k"), $v,
qq{Engine "firebird" should have $k};
}
}
# Try changing the top directory.
isa_ok $cmd = $CLASS->new({
sqitch => $sqitch,
properties => { top_dir => dir 'pg' },
}), $CLASS, 'Engine with new top_dir property';
dir_not_exists_ok dir $_ for qw(pg pg/deploy pg/revert pg/verify);
ok $cmd->alter('pg'), 'Alter engine "pg"';
dir_exists_ok dir $_ for qw(pg pg/deploy pg/revert pg/verify);
$config->load;
is $config->get(key => 'engine.pg.top_dir'), 'pg',
'The pg top_dir should have been set';
# An attempt to alter a missing engine should show the target if in props.
throws_ok { $cmd->alter('oracle') } 'App::Sqitch::X',
'Should again get error for missing engine';
is $@->ident, 'engine', 'Missing engine error ident should still be "engine"';
is $@->message, __x(
'Missing Engine "{engine}"; use "{command}" to add it',
engine => 'oracle',
command => 'add oracle db:oracle:',
), 'Missing engine error message should include target property';
# Should die on target mismatch engine.
isa_ok $cmd = $CLASS->new({
sqitch => $sqitch,
properties => { target => 'db:sqlite:' },
}), $CLASS, 'Engine with target property';
throws_ok { $cmd->alter('firebird' ) } 'App::Sqitch::X',
'Should get error for engine/target mismatch';
is $@->ident, 'engine', 'Target mismatch ident should be "engine"';
is $@->message, __x(
'Cannot assign URI using engine "{new}" to engine "{old}"',
new => 'sqlite',
old => 'firebird',
), 'Target mismatch message should be correct';
##############################################################################
# Test remove.
MISSINGARGS: {
# Test handling of no names.
my $mock = Test::MockModule->new($CLASS);
my @args;
$mock->mock(usage => sub { @args = @_; die 'USAGE' });
throws_ok { $cmd->remove } qr/USAGE/,
'No name args to remove() should yield usage';
is_deeply \@args, [$cmd], 'No args should be passed to usage';
}
# Should get an error if the engine does not exist.
throws_ok { $cmd->remove('nonexistent', 'existant' ) } 'App::Sqitch::X',
'Should get error for nonexistent engine';
is $@->ident, 'engine', 'Nonexistent engine error ident should be "engine"';
is $@->message, __x(
'Unknown engine "{engine}"',
engine => 'nonexistent'
), 'Nonexistent engine error message should be correct';
# Remove one that exists.
ok $cmd->remove('mysql'), 'Remove';
$config->load;
is $config->get(key => "engine.mysql.target"), undef,
qq{Engine "mysql" should now be gone};
is_deeply $config->get_section(section => "engine.mysql.variables"), {},
qq{Engine "mysql" should have no variables};
# Create it again with variables.
( run in 1.860 second using v1.01-cache-2.11-cpan-39bf76dae61 )