require 'spec_helper'
require 'simple_deploy/cli'

describe SimpleDeploy::CLI::Clone do
  include_context 'cli config'
  include_context 'double stubbed logger'
  include_context 'clone stack pair', :source_name => 'source_stack',
                                      :source_env  => 'my_env',
                                      :new_name    => 'new_stack',
                                      :new_env     => 'my_env'

  before { @required = [:environment, :source_name, :new_name, :read_from_env] }

  describe 'clone' do
    context 'filter_attributes' do
      before do
        @source_attributes = {
          'AmiId' => 'ami-7b6a4e3e',
          'AppEnv' => 'pod-2-cd-1',
          'MaximumAppInstances' => 1,
          'MinimumAppInstances' => 1,
          'chef_repo_bucket_prefix' => 'intu-lc',
          'chef_repo_domain' => 'live_community_chef_repo',
          'deployment_user' => 'rmendes'
        }
      end

      it 'should filter out deployment attributes' do
        new_attributes = subject.send(:filter_attributes, @source_attributes)
        new_attributes.size.should == 6

        new_attributes[0].has_key?('AmiId').should be_true
        new_attributes[0]['AmiId'].should == 'ami-7b6a4e3e'
        new_attributes[1].has_key?('AppEnv').should be_true
        new_attributes[1]['AppEnv'].should == 'pod-2-cd-1'
        new_attributes[2].has_key?('MaximumAppInstances').should be_true
        new_attributes[2]['MaximumAppInstances'].should == 1
        new_attributes[3].has_key?('MinimumAppInstances').should be_true
        new_attributes[3]['MinimumAppInstances'].should == 1
        new_attributes[4].has_key?('chef_repo_bucket_prefix').should be_true
        new_attributes[4]['chef_repo_bucket_prefix'].should == 'intu-lc'
        new_attributes[5].has_key?('chef_repo_domain').should be_true
        new_attributes[5]['chef_repo_domain'].should == 'live_community_chef_repo'
      end
    end

    context 'merge_attributes' do
      before do
        @cloned_attributes = [
          { 'AmiId' => 'ami-7b6a4e3e' },
          { 'AppEnv' => 'pod-2-cd-1' },
          { 'MaximumAppInstances' => 1 },
          { 'MinimumAppInstances' => 1 },
          { 'chef_repo_bucket_prefix' => 'intu-lc' },
          { 'chef_repo_domain' => 'live_community_chef_repo' },
          { 'deployment_user' => 'rmendes' }
        ]

        @override_attributes = [
          { 'chef_repo_bucket_prefix' => 'updated-intu-lc' },
          { 'chef_repo_domain' => 'updated_community_chef_repo' }
        ]
      end

      it 'should merge the override attributes' do
        merged_attributes = subject.send(:merge_attributes, @cloned_attributes, @override_attributes)
        merged_attributes.size.should == 7

        merged_attributes[0].has_key?('AmiId').should be_true
        merged_attributes[0]['AmiId'].should == 'ami-7b6a4e3e'
        merged_attributes[1].has_key?('AppEnv').should be_true
        merged_attributes[1]['AppEnv'].should == 'pod-2-cd-1'
        merged_attributes[2].has_key?('MaximumAppInstances').should be_true
        merged_attributes[2]['MaximumAppInstances'].should == 1
        merged_attributes[3].has_key?('MinimumAppInstances').should be_true
        merged_attributes[3]['MinimumAppInstances'].should == 1
        merged_attributes[4].has_key?('chef_repo_bucket_prefix').should be_true
        merged_attributes[4]['chef_repo_bucket_prefix'].should == 'updated-intu-lc'
        merged_attributes[5].has_key?('chef_repo_domain').should be_true
        merged_attributes[5]['chef_repo_domain'].should == 'updated_community_chef_repo'
        merged_attributes[6].has_key?('deployment_user').should be_true
        merged_attributes[6]['deployment_user'].should == 'rmendes'
      end
    end

    context 'add_attributes' do
      before do
        @cloned_attributes = [
          { 'AmiId' => 'ami-7b6a4e3e' },
          { 'AppEnv' => 'pod-2-cd-1' },
          { 'MaximumAppInstances' => 1 },
          { 'MinimumAppInstances' => 1 },
          { 'chef_repo_bucket_prefix' => 'intu-lc' },
          { 'chef_repo_domain' => 'live_community_chef_repo' },
          { 'deployment_user' => 'rmendes' }
        ]

        @new_attributes = [
          { 'chef_repo_bucket_prefix' => 'updated-intu-lc' },
          { 'SolrClientTrafficContainer' => 'solr-client-traffic-container' },
          { 'SolrReplicationTrafficContainer' => 'solr-replication-traffic-container' }
        ]
      end

      it 'should add new override attributes' do
        add_attributes = subject.send(:add_attributes, @cloned_attributes, @new_attributes)
        add_attributes.size.should == 2

        add_attributes[0].has_key?('SolrClientTrafficContainer').should be_true
        add_attributes[0]['SolrClientTrafficContainer'].should == 'solr-client-traffic-container'
        add_attributes[1].has_key?('SolrReplicationTrafficContainer').should be_true
        add_attributes[1]['SolrReplicationTrafficContainer'].should == 'solr-replication-traffic-container'
      end

      it 'should return an empty array if there are no new attributes' do
        new_attributes = [
          { 'chef_repo_bucket_prefix' => 'updated-intu-lc' },
          { 'chef_repo_domain' => 'updated_community_chef_repo' }
        ]

        add_attributes = subject.send(:add_attributes, @cloned_attributes, new_attributes)
        add_attributes.should be_empty
      end
    end

    context 'stack creation' do
      before do
        @options = { :environment => 'my_env',
                     :log_level   => 'debug',
                     :source_name => 'source_stack',
                     :new_name    => 'new_stack',
                     :attributes  => ['chef_repo_bucket_prefix=updated-intu-lc',
                                      'chef_repo_domain=updated_community_chef_repo',
                                      'SolrClientTrafficContainer=solr-client-traffic-container'] }

        @source_stack_stub.stub(:attributes).and_return(
          'AmiId' => 'ami-7b6a4e3e',
          'AppEnv' => 'pod-2-cd-1',
          'MaximumAppInstances' => 1,
          'MinimumAppInstances' => 1,
          'chef_repo_bucket_prefix' => 'intu-lc',
          'chef_repo_domain' => 'live_community_chef_repo',
          'deployment_user' => 'rmendes'
        )
        @source_stack_stub.stub(:template).and_return('foo' => 'bah')
        @new_stack_mock.stub(:attributes).and_return({})
      end

      it 'should create the new stack using the filtered, merged and added attributes' do
        subject.should_receive(:valid_options?).
                with(:provided => @options, :required => @required)
        Trollop.stub(:options).and_return(@options)
        @new_stack_mock.stub(:template).and_return('foo' => 'bah')

        @new_stack_mock.should_receive(:create) do |options|
          options[:attributes].should == [{ 'AmiId' => 'ami-7b6a4e3e' },
                                          { 'AppEnv' => 'pod-2-cd-1' },
                                          { 'MaximumAppInstances' => 1 },
                                          { 'MinimumAppInstances' => 1 },
                                          { 'chef_repo_bucket_prefix' => 'updated-intu-lc' },
                                          { 'chef_repo_domain' => 'updated_community_chef_repo' },
                                          { 'SolrClientTrafficContainer' => 'solr-client-traffic-container' }]
          options[:template].should match /new_stack_template.json/
        end

        subject.clone
      end

      it 'should create the new stack using a new template' do
        @options[:template] = 'brand_new_template.json'

        subject.should_receive(:valid_options?).
                with(:provided => @options, :required => @required)
        Trollop.stub(:options).and_return(@options)

        @new_stack_mock.should_receive(:create) do |options|
          options[:attributes].should == [{ 'AmiId' => 'ami-7b6a4e3e' },
                                          { 'AppEnv' => 'pod-2-cd-1' },
                                          { 'MaximumAppInstances' => 1 },
                                          { 'MinimumAppInstances' => 1 },
                                          { 'chef_repo_bucket_prefix' => 'updated-intu-lc' },
                                          { 'chef_repo_domain' => 'updated_community_chef_repo' },
                                          { 'SolrClientTrafficContainer' => 'solr-client-traffic-container' }]
          options[:template].should match /brand_new_template.json/
        end

        subject.clone
      end

      it 'should create the new stack using existing input stack, but cmd line args win' do
        options = { :environment  => 'my_env',
                     :input_stack => 'input_stack',
                     :template    => 'brand_new_template.json',
                     :log_level   => 'debug',
                     :source_name => 'source_stack',
                     :new_name    => 'new_stack',
                     :attributes  => ['chef_repo_bucket_prefix=updated-intu-lc',
                                      'chef_repo_domain=updated_community_chef_repo',
                                      'SolrClientTrafficContainer=solr-client-traffic-container',
                                      'InputStackOutputs=cmdline_value'] }

        input_attributes = [{'InputStackOutputs' => 'inputvalue'}, {'OutputValue' => 'outputs'}]
        input_stub = stub 'input', :map_outputs_from_stacks => input_attributes
        SimpleDeploy::Stack::OutputMapper.stub :new => input_stub

        subject.should_receive(:valid_options?).
                with(:provided => options, :required => @required)
        Trollop.stub(:options).and_return(options)

        @new_stack_mock.stub(:template).and_return('foo' => 'bah')
        @new_stack_mock.should_receive(:create) do |options|
          options[:attributes].should == [{ 'AmiId' => 'ami-7b6a4e3e' },
                                          { 'AppEnv' => 'pod-2-cd-1' },
                                          { 'MaximumAppInstances' => 1 },
                                          { 'MinimumAppInstances' => 1 },
                                          { 'chef_repo_bucket_prefix' => 'updated-intu-lc' },
                                          { 'chef_repo_domain' => 'updated_community_chef_repo' },
                                          { 'InputStackOutputs' => 'cmdline_value' },
                                          { 'OutputValue' => 'outputs'},
                                          { 'SolrClientTrafficContainer' => 'solr-client-traffic-container' }]

          options[:template].should match /brand_new_template.json/
        end

        subject.clone
      end

    end
  end
end
