#!/usr/bin/perl -w use strict; use warnings; use v5.10; use Test::More; use App::Sqitch; use Path::Class qw(dir file); use Test::MockModule; use Test::Exception; use lib 't/lib'; use MockOutput; my $CLASS = 'App::Sqitch::Command::rebase'; require_ok $CLASS or die; $ENV{SQITCH_CONFIG} = 'nonexistent.conf'; $ENV{SQITCH_USER_CONFIG} = 'nonexistent.user'; $ENV{SQITCH_SYSTEM_CONFIG} = 'nonexistent.sys'; isa_ok $CLASS, 'App::Sqitch::Command'; can_ok $CLASS, qw( options configure new onto_target upto_target log_only execute deploy_variables revert_variables ); is_deeply [$CLASS->options], [qw( onto-target|onto=s upto-target|upto=s mode=s verify! set|s=s% set-deploy|d=s% set-revert|r=s% log-only y )], 'Options should be correct'; my $sqitch = App::Sqitch->new( plan_file => file(qw(t sql sqitch.plan)), top_dir => dir(qw(t sql)), _engine => 'sqlite', ); my $config = $sqitch->config; # Test configure(). is_deeply $CLASS->configure($config, {}), { no_prompt => 0, verify => 0, mode => 'all' }, 'Should have empty default configuration with no config or opts'; is_deeply $CLASS->configure($config, { set => { foo => 'bar' }, }), { no_prompt => 0, verify => 0, mode => 'all', deploy_variables => { foo => 'bar' }, revert_variables => { foo => 'bar' }, }, 'Should have set option'; is_deeply $CLASS->configure($config, { y => 1, set_deploy => { foo => 'bar' }, log_only => 1, verify => 1, mode => 'tag', }), { mode => 'tag', no_prompt => 1, deploy_variables => { foo => 'bar' }, verify => 1, log_only => 1, }, 'Should have mode, deploy_variables, verify, no_prompt, and log_only'; is_deeply $CLASS->configure($config, { y => 0, set_revert => { foo => 'bar' }, }), { mode => 'all', no_prompt => 0, verify => 0, revert_variables => { foo => 'bar' }, }, 'Should have set_revert option and no_prompt false'; is_deeply $CLASS->configure($config, { set => { foo => 'bar' }, set_deploy => { foo => 'dep', hi => 'you' }, set_revert => { foo => 'rev', hi => 'me' }, }), { mode => 'all', no_prompt => 0, verify => 0, deploy_variables => { foo => 'dep', hi => 'you' }, revert_variables => { foo => 'rev', hi => 'me' }, }, 'set_deploy and set_revert should overrid set'; is_deeply $CLASS->configure($config, { set => { foo => 'bar' }, set_deploy => { hi => 'you' }, set_revert => { hi => 'me' }, }), { mode => 'all', no_prompt => 0, verify => 0, deploy_variables => { foo => 'bar', hi => 'you' }, revert_variables => { foo => 'bar', hi => 'me' }, }, 'set_deploy and set_revert should merge with set'; is_deeply $CLASS->configure($config, { set => { foo => 'bar' }, set_deploy => { hi => 'you' }, set_revert => { my => 'yo' }, }), { mode => 'all', no_prompt => 0, verify => 0, deploy_variables => { foo => 'bar', hi => 'you' }, revert_variables => { foo => 'bar', hi => 'you', my => 'yo' }, }, 'set_revert should merge with set_deploy'; CONFIG: { my $mock_config = Test::MockModule->new(ref $config); my %config_vals; $mock_config->mock(get => sub { my ($self, %p) = @_; return $config_vals{ $p{key} }; }); $mock_config->mock(get_section => sub { my ($self, %p) = @_; return $config_vals{ $p{section} } || {}; }); %config_vals = ( 'deploy.variables' => { foo => 'bar', hi => 21 }, ); is_deeply $CLASS->configure($config, {}), {no_prompt => 0, verify => 0, mode => 'all'}, 'Should have deploy configuration'; # Try merging. is_deeply $CLASS->configure($config, { onto_target => 'whu', set => { foo => 'yo', yo => 'stellar' }, }), { mode => 'all', no_prompt => 0, verify => 0, deploy_variables => { foo => 'yo', yo => 'stellar', hi => 21 }, revert_variables => { foo => 'yo', yo => 'stellar', hi => 21 }, onto_target => 'whu', }, 'Should have merged variables'; # Try merging with rebase.variables, too. $config_vals{'revert.variables'} = { hi => 42 }; is_deeply $CLASS->configure($config, { set => { yo => 'stellar' }, }), { mode => 'all', no_prompt => 0, verify => 0, deploy_variables => { foo => 'bar', yo => 'stellar', hi => 21 }, revert_variables => { foo => 'bar', yo => 'stellar', hi => 42 }, }, 'Should have merged --set, deploy, rebase'; isa_ok my $rebase = $CLASS->new(sqitch => $sqitch), $CLASS; is_deeply $rebase->deploy_variables, { foo => 'bar', hi => 21 }, 'Should pick up deploy variables from configuration'; is_deeply $rebase->revert_variables, { foo => 'bar', hi => 42 }, 'Should pick up revert variables from configuration'; # Make sure we can override mode, prompting, and verify. %config_vals = ('revert.no_prompt' => 1, 'deploy.verify' => 1, 'deploy.mode' => 'tag'); is_deeply $CLASS->configure($config, {}), { no_prompt => 1, verify => 1, mode => 'tag' }, 'Should have no_prompt true'; # Rebase option takes precendence $config_vals{'rebase.no_prompt'} = 0; $config_vals{'rebase.verify'} = 0; $config_vals{'rebase.mode'} = 'change'; is_deeply $CLASS->configure($config, {}), { no_prompt => 0, verify => 0, mode => 'change' }, 'Should havev false no_prompt and verify from rebase config'; delete $config_vals{'revert.no_prompt'}; delete $config_vals{'rebase.verify'}; delete $config_vals{'rebase.mode'}; $config_vals{'rebase.no_prompt'} = 1; is_deeply $CLASS->configure($config, {}), { no_prompt => 1, verify => 1, mode => 'tag' }, 'Should have no_prompt true from rebase and verify from deploy'; # But option should override. is_deeply $CLASS->configure($config, {y => 0, verify => 0, mode => 'all'}), { no_prompt => 0, verify => 0, mode => 'all' }, 'Should have no_prompt false and mode all again'; $config_vals{'revert.no_prompt'} = 0; delete $config_vals{'rebase.no_prompt'}; is_deeply $CLASS->configure($config, {}), { no_prompt => 0, verify => 1, mode => 'tag' }, 'Should have no_prompt false for false config'; is_deeply $CLASS->configure($config, {y => 1}), { no_prompt => 1, verify => 1, mode => 'tag' }, 'Should have no_prompt true with -y'; } isa_ok my $rebase = $CLASS->new(sqitch => $sqitch), $CLASS; is $rebase->onto_target, undef, 'onto_target should be undef'; is $rebase->upto_target, undef, 'upto_target should be undef'; # Mock the engine interface. my $mock_engine = Test::MockModule->new('App::Sqitch::Engine::sqlite'); my @dep_args; $mock_engine->mock(deploy => sub { shift; @dep_args = @_ }); my @rev_args; $mock_engine->mock(revert => sub { shift; @rev_args = @_ }); my @vars; $mock_engine->mock(set_variables => sub { shift; push @vars => [@_] }); ok $rebase->execute('@alpha'), 'Execute to "@alpha"'; is_deeply \@dep_args, [undef, 'all', 0], 'undef, "all", and 0 should be passed to the engine deploy'; is_deeply \@rev_args, ['@alpha', 0], '"@alpha" and 0 should be passed to the engine revert'; ok !$sqitch->engine->no_prompt, 'Engine should prompt'; @dep_args = @rev_args = (); ok $rebase->execute, 'Execute'; is_deeply \@dep_args, [undef, 'all', 0], 'undef, "all", and 0 should be passed to the engine deploy'; is_deeply \@rev_args, [undef, 0], 'undef and = should be passed to the engine revert'; is_deeply \@vars, [], 'No vars should have been passed through to the engine'; isa_ok $rebase = $CLASS->new( no_prompt => 1, log_only => 1, verify => 1, sqitch => $sqitch, mode => 'tag', onto_target => 'foo', upto_target => 'bar', deploy_variables => { foo => 'bar', one => 1 }, revert_variables => { hey => 'there' }, ), $CLASS, 'Object with to and variables'; @dep_args = @rev_args = (); ok $rebase->execute, 'Execute again'; ok $sqitch->engine->no_prompt, 'Engine should be no_prompt'; ok $sqitch->engine->with_verify, 'Engine should verify'; is_deeply \@dep_args, ['bar', 'tag', 1], '"bar", "tag", and 1 should be passed to the engine deploy'; is_deeply \@rev_args, ['foo', 1], '"foo" and 1 should be passed to the engine revert'; is @vars, 2, 'Variables should have been passed to the engine twice'; is_deeply { @{ $vars[0] } }, { hey => 'there' }, 'The revert vars should have been passed first'; is_deeply { @{ $vars[1] } }, { foo => 'bar', one => 1 }, 'The deploy vars should have been next'; done_testing;