App-Sqitch
view release on metacpan or search on metacpan
t/target_cmd.t view on Meta::CPAN
#!/usr/bin/perl -w
use strict;
use warnings;
use utf8;
use Test::More tests => 243;
#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::target';
##############################################################################
# Set up a test directory and config file.
my $tmp_dir = tempdir CLEANUP => 1;
File::Copy::copy file(qw(t target.conf))->stringify, "$tmp_dir"
or die "Cannot copy t/target.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 $psql = 'psql' . (App::Sqitch::ISWIN ? '.exe' : '');
##############################################################################
# Load a target command and test the basics.
my $config = TestConfig->from(local => 'target.conf');
ok my $sqitch = App::Sqitch->new(config => $config),
'Load a sqitch sqitch object';
isa_ok my $cmd = App::Sqitch::Command->load({
sqitch => $sqitch,
command => 'target',
config => $config,
}), $CLASS, 'Target command';
isa_ok $cmd, 'App::Sqitch::Command', 'Target command';
can_ok $cmd, qw(
options
configure
execute
list
add
remove
rename
rm
show
does
);
ok $CLASS->does("App::Sqitch::Role::TargetConfigCommand"),
"$CLASS does TargetConfigCommand";
is_deeply [$CLASS->options], [qw(
uri=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/target_cmd.t view on Meta::CPAN
'Unknown directory names: {dirs}',
1,
dirs => 'foo',
), 'The invalid directory messsage should be correct';
throws_ok { $CLASS->new($CLASS->configure({}, {
dir => { foo => 'bar', cavort => 'ha' },
})) } 'App::Sqitch::X', 'Should fail on invalid directory names';
is $@->ident, 'target', 'Invalid directories ident should be "target"';
is $@->message, __nx(
'Unknown directory name: {dirs}',
'Unknown directory names: {dirs}',
2,
dirs => 'cavort, foo',
), 'The invalid properties messsage should be correct';
##############################################################################
# Test list().
ok $cmd->list, 'Run list()';
is_deeply +MockOutput->get_emit, [['dev'], ['prod'], ['qa']],
'The list of targets should have been output';
# Make it verbose.
isa_ok $cmd = $CLASS->new({
sqitch => App::Sqitch->new( config => $config, options => { verbosity => 1 })
}), $CLASS, 'Verbose engine';
ok $cmd->list, 'Run verbose list()';
is_deeply +MockOutput->get_emit, [
["dev\tdb:pg:widgets"],
["prod\tdb:pg://prod.example.us/pr_widgets"],
["qa\tdb:pg://qa.example.com/qa_widgets"]
], 'The list of targets and their URIs should have been output';
##############################################################################
# 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';
@args = ();
throws_ok { $cmd->add('foo') } qr/USAGE/,
'No URI 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('dev', 'db:pg:') } 'App::Sqitch::X',
'Should get error for existing target';
is $@->ident, 'target', 'Existing target error ident should be "target"';
is $@->message, __x(
'Target "{target}" already exists',
target => 'dev'
), 'Existing target error message should be correct';
# Now add a new target.
dir_not_exists_ok $_ for qw(deploy revert verify);
ok $cmd->add('test', 'db:pg:test'), 'Add target "test"';
dir_exists_ok $_ for qw(deploy revert verify);
$config->load;
is $config->get(key => 'target.test.uri'), 'db:pg:test',
'Target "test" URI 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 => "target.test.$key"), undef,
qq{Target "test" should have no $key set};
}
is_deeply $config->get_section(section => 'target.test.variables'), {},
qq{Target "test" should have no variables set}
;
# Try adding a target with a registry.
isa_ok $cmd = $CLASS->new({
sqitch => $sqitch,
properties => { registry => 'meta' },
}), $CLASS, 'Target with registry';
ok $cmd->add('withreg', 'db:pg:withreg'), 'Add target "withreg"';
$config->load;
is $config->get(key => 'target.withreg.uri'), 'db:pg:withreg',
'Target "withreg" URI should have been set';
is $config->get(key => 'target.withreg.registry'), 'meta',
'Target "withreg" registry should have been set';
for my $key (qw(
client
top_dir
plan_file
deploy_dir
revert_dir
verify_dir
extension
)) {
is $config->get(key => "target.withreg.$key"), undef,
qq{Target "test" should have no $key set};
}
is_deeply $config->get_section(section => 'target.withreg.variables'), {},
qq{Target "withreg" should have no variables set};
# Try a client.
isa_ok $cmd = $CLASS->new({
sqitch => $sqitch,
properties => { client => 'hi.exe' },
}), $CLASS, 'Target with client';
ok $cmd->add('withcli', 'db:pg:withcli'), 'Add target "withcli"';
$config->load;
is $config->get(key => 'target.withcli.uri'), 'db:pg:withcli',
'Target "withcli" URI should have been set';
is $config->get(key => 'target.withcli.client'), 'hi.exe',
'Target "withcli" should have client set';
for my $key (qw(
registry
top_dir
plan_file
deploy_dir
revert_dir
verify_dir
extension
)) {
is $config->get(key => "target.withcli.$key"), undef,
qq{Target "withcli" should have no $key set};
}
is_deeply $config->get_section(section => 'target.withcli.variables'), {},
qq{Target "withcli" should have no variables set};
# Try both.
isa_ok $cmd = $CLASS->new({
sqitch => $sqitch,
properties => { client => 'ack', registry => 'foo', variables => { a => 'y' } },
}), $CLASS, 'Target with client and registry';
ok $cmd->add('withboth', 'db:pg:withboth'), 'Add target "withboth"';
$config->load;
is $config->get(key => 'target.withboth.uri'), 'db:pg:withboth',
'Target "withboth" URI should have been set';
is $config->get(key => 'target.withboth.registry'), 'foo',
'Target "withboth" registry should have been set';
is $config->get(key => 'target.withboth.client'), 'ack',
'Target "withboth" should have client set';
for my $key (qw(
top_dir
plan_file
deploy_dir
revert_dir
verify_dir
extension
)) {
is $config->get(key => "target.withboth.$key"), undef,
qq{Target "withboth" should have no $key set};
}
is_deeply $config->get_section(section => 'target.withboth.variables'), {a => 'y'},
qq{Target "withboth" should have variables set};
# Try all the properties.
my %props = (
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, 'Target 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('withall', 'db:pg:withall'), 'Add target "withall"';
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;
is $config->get(key => "target.withall.uri"), 'db:pg:withall',
qq{Target "withall" should have uri set};
while (my ($k, $v) = each %props) {
if ($k ne 'variables') {
is $config->get(key => "target.withall.$k"), $v,
qq{Target "withall" should have $k set};
} else {
is_deeply $config->get_section(section => "target.withall.$k"), $v,
qq{Target "withall" should have $k set};
}
}
##############################################################################
# Test alter().
isa_ok $cmd = $CLASS->new({
sqitch => $sqitch,
}), $CLASS, 'Target 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 alter() should yield usage';
is_deeply \@args, [$cmd], 'No args should be passed to usage';
}
# Should die on missing key.
throws_ok { $cmd->alter('nonesuch') } 'App::Sqitch::X',
'Should get error for missing target';
is $@->ident, 'target', 'Missing target error ident should be "target"';
is $@->message, __x(
'Missing Target "{target}"; use "{command}" to add it',
target => 'nonesuch',
command => 'add nonesuch $uri',
), 'Missing target error message should be correct';
# Should include the URI, if present, in the error message.
$cmd->properties->{uri} = URI::db->new('db:pg:');
throws_ok { $cmd->alter('nonesuch') } 'App::Sqitch::X',
'Should get error for missing target with URI';
is $@->ident, 'target', 'Missing target with URI error ident should be "target"';
is $@->message, __x(
'Missing Target "{target}"; use "{command}" to add it',
target => 'nonesuch',
command => 'add nonesuch db:pg:',
), 'Missing target error message should include URI';
# Try all the properties.
%props = (
uri => URI->new('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, 'Target with more properties';
ok $cmd->alter('withall'), 'Alter target "withall"';
$config->load;
while (my ($k, $v) = each %props) {
if ($k ne 'variables') {
is $config->get(key => "target.withall.$k"), $v,
qq{Target "withall" should have $k set};
} else {
$v->{Bee} = 'second';
is_deeply $config->get_section(section => "target.withall.$k"), $v,
qq{Target "withall" should have merged $k set};
}
}
# Try changing the top directory.
isa_ok $cmd = $CLASS->new({
sqitch => $sqitch,
properties => { top_dir => dir 'big' },
}), $CLASS, 'Target with new top_dir property';
dir_not_exists_ok dir $_ for qw(big big/deploy big/revert big/verify);
ok $cmd->alter('withall'), 'Alter target "withall"';
dir_exists_ok dir $_ for qw(big big/deploy big/revert big/verify);
$config->load;
is $config->get(key => 'target.withall.top_dir'), 'big',
'The withall top_dir should have been set';
##############################################################################
# Test rename.
MISSINGARGS: {
# Test handling of no names.
my $mock = Test::MockModule->new($CLASS);
my @args;
$mock->mock(usage => sub { @args = @_; die 'USAGE' });
throws_ok { $cmd->rename } qr/USAGE/,
'No name args to rename() should yield usage';
is_deeply \@args, [$cmd], 'No args should be passed to usage';
@args = ();
throws_ok { $cmd->rename('foo') } qr/USAGE/,
'No second arg to rename() should yield usage';
is_deeply \@args, [$cmd], 'No args should be passed to usage';
}
# Should get an error if the target does not exist.
throws_ok { $cmd->rename('nonexistent', 'existant' ) } 'App::Sqitch::X',
'Should get error for nonexistent target';
is $@->ident, 'target', 'Nonexistent target error ident should be "target"';
is $@->message, __x(
'Unknown target "{target}"',
target => 'nonexistent'
), 'Nonexistent target error message should be correct';
# Rename one that exists.
ok $cmd->rename('withboth', 'Ã lafois'), 'Rename';
$config->load;
ok $config->get(key => "target.Ã lafois.uri"),
qq{Target "Ã lafois" should now be present};
is $config->get(key => "target.Ã lafois.variables.a"), 'y',
qq{Target "Ã lafois" variables should now be present};
is $config->get(key => "target.withboth.uri"), undef,
qq{Target "withboth" should no longer be present};
is $config->get(key => "target.withboth.variables.a"), undef,
qq{Target "withboth" variables should be gone};
is_deeply $config->get_section(section => "target.Ã lafois.variables"), { a => 'y' },
qq{Target "Ã lafois" should have variables};
# Make sure we die on dependencies.
$config->group_set( $config->local_file, [
{key => 'core.target', value => 'prod'},
{key => 'engine.firebird.target', value => 'prod'},
]);
$cmd->sqitch->config->load;
# Should get an error for a target with dependencies.
throws_ok { $cmd->rename('prod', 'fodder' ) } 'App::Sqitch::X',
'Should get error renaming a target with dependencies';
is $@->ident, 'target', 'Dependency target error ident should be "target"';
is $@->message, __x(
q{Cannot rename target "{target}" because it's referenced by: {engines}},
target => 'prod',
engines => 'core.target, engine.firebird.target',
( run in 0.632 second using v1.01-cache-2.11-cpan-364913b4093 )