<commit_before>#
# Copyright (c) 2009 RightScale Inc
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

require File.join(File.dirname(__FILE__), 'spec_helper')
require File.join(File.dirname(__FILE__), '..', '..', 'chef', 'lib', 'plugins')
require File.join(File.dirname(__FILE__), '..', '..', 'chef', 'lib', 'providers')

describe RightScale::ExecutableSequence do

  include RightScale::SpecHelpers

  context 'Testing sequence execution' do

    before(:all) do
      flexmock(RightScale::RightLinkLog).should_receive(:debug)
      @attachment_file = File.expand_path(File.join(File.dirname(__FILE__), '__test_download__'))
      File.open(@attachment_file, 'w') { |f| f.write('Some attachment content') }
      platform = RightScale::RightLinkConfig[:platform]
      @cache_dir = File.expand_path(File.join(platform.filesystem.temp_dir, 'executable_sequence_spec'))
      Chef::Resource::RightScript.const_set(:DEFAULT_CACHE_DIR_ROOT, @cache_dir)
    end

    before(:each) do
      setup_state
      setup_script_execution
      @script = flexmock(:nickname => '__TestScript', :parameters => {}, :ready => true)
      @script.should_receive(:is_a?).with(RightScale::RightScriptInstantiation).and_return(true)
      @script.should_receive(:is_a?).with(RightScale::RecipeInstantiation).and_return(false)

      @bundle = RightScale::ExecutableBundle.new([ @script ], [], 0)

      @auditor = flexmock('AuditorProxy')
      @auditor.should_receive(:audit_id).and_return(1)
      @auditor.should_receive(:create_new_section)
      @auditor.should_receive(:append_info)
      @auditor.should_receive(:append_output)
      @auditor.should_receive(:update_status)
      @auditor.should_receive(:append_error) { |m| puts m }

      # prevent Chef logging reaching the console during spec test.
      logger = flexmock(::RightScale::RightLinkLog.logger)
      logger.should_receive(:info).and_return(true)
      logger.should_receive(:error).and_return(true)
    end

    after(:all) do
      cleanup_state
      cleanup_script_execution
      FileUtils.rm(@attachment_file) if @attachment_file
      FileUtils.rm_rf(@cache_dir) if @cache_dir
    end

    # Run sequence and print out exceptions
    def run_sequence
      res = nil
      EM.run do
        Thread.new do
          begin
            @sequence.callback { res = true;  EM.next_tick { EM.stop } }
            @sequence.errback  { res = false; EM.next_tick { EM.stop } }
            @sequence.run
          rescue Exception => e
            puts e.message + "\n" + e.backtrace.join("\n")
            EM.next_tick { EM.stop }
          end
        end
      end
      res
    end

    def format_script_text(exit_code)
      platform = RightScale::RightLinkConfig[:platform]
      return platform.windows? ?
             "exit #{exit_code}" :
             "#!/bin/sh\nruby -e 'exit(#{exit_code})'"
    end

    it 'should report success' do
      begin
        @script.should_receive(:packages).and_return(nil)
        @script.should_receive(:source).and_return(format_script_text(0))
        @sequence = RightScale::ExecutableSequence.new(@bundle)
        @sequence.instance_variable_set(:@auditor, @auditor)
        flexmock(@sequence).should_receive(:install_packages).and_return(true)
        attachment = flexmock('A1')
        attachment.should_receive(:file_name).at_least.once.and_return('test_download')
        attachment.should_receive(:url).at_least.once.and_return("file://#{@attachment_file}")
        @script.should_receive(:attachments).at_least.once.and_return([ attachment ])
        @auditor.should_receive(:append_error).never
        run_sequence.should be_true
      ensure
        @sequence = nil
      end
    end

    it 'should audit failures' do
      @script.should_receive(:packages).and_return(nil)
      @script.should_receive(:source).and_return(format_script_text(1))
      @sequence = RightScale::ExecutableSequence.new(@bundle)
      @sequence.instance_variable_set(:@auditor, @auditor)
      flexmock(@sequence).should_receive(:install_packages).and_return(true)
      attachment = flexmock('A2')
      attachment.should_receive(:file_name).at_least.once.and_return('test_download')
      attachment.should_receive(:url).at_least.once.and_return("file://#{@attachment_file}")
      @auditor.should_receive(:append_error)
      @script.should_receive(:attachments).at_least.once.and_return([ attachment ])
      flexmock(RightScale::RightLinkLog).should_receive(:error)
      run_sequence.should be_false
    end

# FIXME: Occasionally behaves oddly and have not been able to debug
#    it 'should report invalid attachments' do
#      @script.should_receive(:packages).and_return(nil)
#      @script.should_receive(:source).and_return(format_script_text(0))
#      @sequence = RightScale::ExecutableSequence.new(@bundle)
#      @sequence.instance_variable_set(:@auditor, @auditor)
#      attachment = flexmock('A3')
#      attachment.should_receive(:url).and_return("http://thisurldoesnotexist.wrong")
#      attachment.should_receive(:file_name).and_return("<FILENAME>") # to display any error message
#      downloader = RightScale::Downloader.new(retry_period=0.1, use_backoff=false)
#      @sequence.instance_variable_set(:@downloader, downloader)
#      flexmock(@auditor).should_receive(:append_error).twice
#      @script.should_receive(:attachments).at_least.once.and_return([ attachment ])
#      flexmock(RightScale::RightLinkLog).should_receive(:error)
#      run_sequence.should be_false
#    end

  end

  context 'Chef error formatting' do

    before(:each) do
      bundle = flexmock('Bundle')
      bundle.should_ignore_missing
      @sequence = RightScale::ExecutableSequence.new(bundle)
      begin
        fourty_two
      rescue Exception => e
        @exception = e
      end
      @lines = [ '    paths.size.should == 1',
                 '    paths.first.should == @sequence.send(:cookbook_repo_directory, repo)',
                 '  end',
                 '',
                 "  it 'should calculate cookbooks path for repositories with cookbooks_path' do",
                 "    repo = RightScale::CookbookRepository.new('git', 'url', 'tag', ['cookbooks_path'])",
                 '    paths = @sequence.send(:cookbooks_path, repo)',
                 '    paths.size.should == 1',
                 "    paths.first.should == File.join(@sequence.send(:cookbook_repo_directory, repo), 'cookbooks_path')",
                 '  end' ]<commit_msg>Restore executable_sequence spec that only fails in cox environment<commit_after>#
# Copyright (c) 2009 RightScale Inc
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

require File.join(File.dirname(__FILE__), 'spec_helper')
require File.join(File.dirname(__FILE__), '..', '..', 'chef', 'lib', 'plugins')
require File.join(File.dirname(__FILE__), '..', '..', 'chef', 'lib', 'providers')

describe RightScale::ExecutableSequence do

  include RightScale::SpecHelpers

  context 'Testing sequence execution' do

    before(:all) do
      flexmock(RightScale::RightLinkLog).should_receive(:debug)
      @attachment_file = File.expand_path(File.join(File.dirname(__FILE__), '__test_download__'))
      File.open(@attachment_file, 'w') { |f| f.write('Some attachment content') }
      platform = RightScale::RightLinkConfig[:platform]
      @cache_dir = File.expand_path(File.join(platform.filesystem.temp_dir, 'executable_sequence_spec'))
      Chef::Resource::RightScript.const_set(:DEFAULT_CACHE_DIR_ROOT, @cache_dir)
    end

    before(:each) do
      setup_state
      setup_script_execution
      @script = flexmock(:nickname => '__TestScript', :parameters => {}, :ready => true)
      @script.should_receive(:is_a?).with(RightScale::RightScriptInstantiation).and_return(true)
      @script.should_receive(:is_a?).with(RightScale::RecipeInstantiation).and_return(false)

      @bundle = RightScale::ExecutableBundle.new([ @script ], [], 0)

      @auditor = flexmock('AuditorProxy')
      @auditor.should_receive(:audit_id).and_return(1)
      @auditor.should_receive(:create_new_section)
      @auditor.should_receive(:append_info)
      @auditor.should_receive(:append_output)
      @auditor.should_receive(:update_status)
      @auditor.should_receive(:append_error) { |m| puts m }

      # prevent Chef logging reaching the console during spec test.
      logger = flexmock(::RightScale::RightLinkLog.logger)
      logger.should_receive(:info).and_return(true)
      logger.should_receive(:error).and_return(true)
    end

    after(:all) do
      cleanup_state
      cleanup_script_execution
      FileUtils.rm(@attachment_file) if @attachment_file
      FileUtils.rm_rf(@cache_dir) if @cache_dir
    end

    # Run sequence and print out exceptions
    def run_sequence
      res = nil
      EM.run do
        Thread.new do
          begin
            @sequence.callback { res = true;  EM.next_tick { EM.stop } }
            @sequence.errback  { res = false; EM.next_tick { EM.stop } }
            @sequence.run
          rescue Exception => e
            puts e.message + "\n" + e.backtrace.join("\n")
            EM.next_tick { EM.stop }
          end
        end
      end
      res
    end

    def format_script_text(exit_code)
      platform = RightScale::RightLinkConfig[:platform]
      return platform.windows? ?
             "exit #{exit_code}" :
             "#!/bin/sh\nruby -e 'exit(#{exit_code})'"
    end

    it 'should report success' do
      begin
        @script.should_receive(:packages).and_return(nil)
        @script.should_receive(:source).and_return(format_script_text(0))
        @sequence = RightScale::ExecutableSequence.new(@bundle)
        @sequence.instance_variable_set(:@auditor, @auditor)
        flexmock(@sequence).should_receive(:install_packages).and_return(true)
        attachment = flexmock('A1')
        attachment.should_receive(:file_name).at_least.once.and_return('test_download')
        attachment.should_receive(:url).at_least.once.and_return("file://#{@attachment_file}")
        @script.should_receive(:attachments).at_least.once.and_return([ attachment ])
        @auditor.should_receive(:append_error).never
        run_sequence.should be_true
      ensure
        @sequence = nil
      end
    end

    it 'should audit failures' do
      @script.should_receive(:packages).and_return(nil)
      @script.should_receive(:source).and_return(format_script_text(1))
      @sequence = RightScale::ExecutableSequence.new(@bundle)
      @sequence.instance_variable_set(:@auditor, @auditor)
      flexmock(@sequence).should_receive(:install_packages).and_return(true)
      attachment = flexmock('A2')
      attachment.should_receive(:file_name).at_least.once.and_return('test_download')
      attachment.should_receive(:url).at_least.once.and_return("file://#{@attachment_file}")
      @auditor.should_receive(:append_error)
      @script.should_receive(:attachments).at_least.once.and_return([ attachment ])
      flexmock(RightScale::RightLinkLog).should_receive(:error)
      run_sequence.should be_false
    end

    # Beware that this test may fail if run in a Cox internet service environment because
    # they redirect 404's to one of their pages. If `curl http://thisurldoesnotexist.wrong`
    # gives back html code, that is likely the cause of this test failing.
    it 'should report invalid attachments' do
      @script.should_receive(:packages).and_return(nil)
      @script.should_receive(:source).and_return(format_script_text(0))
      @sequence = RightScale::ExecutableSequence.new(@bundle)
      @sequence.instance_variable_set(:@auditor, @auditor)
      attachment = flexmock('A3')
      attachment.should_receive(:url).and_return("http://thisurldoesnotexist.wrong")
      attachment.should_receive(:file_name).and_return("<FILENAME>") # to display any error message
      downloader = RightScale::Downloader.new(retry_period=0.1, use_backoff=false)
      @sequence.instance_variable_set(:@downloader, downloader)
      flexmock(@auditor).should_receive(:append_error).twice
      @script.should_receive(:attachments).at_least.once.and_return([ attachment ])
      flexmock(RightScale::RightLinkLog).should_receive(:error)
      run_sequence.should be_false
    end

  end

  context 'Chef error formatting' do

    before(:each) do
      bundle = flexmock('Bundle')
      bundle.should_ignore_missing
      @sequence = RightScale::ExecutableSequence.new(bundle)
      begin
        fourty_two
      rescue Exception => e
        @exception = e
      end
      @lines = [ '    paths.size.should == 1',
                 '    paths.first.should == @sequence.send(:cookbook_repo_directory, repo)',
                 '  end',
                 '',
                 "  it 'should calculate cookbooks path for repositories with cookbooks_path' do",
                 "    repo = RightScale::CookbookRepository.new('git', 'url', 'tag', ['cookbooks_path'])",
                 '    paths = @sequence.send(:cookbooks_path, repo)',
                 '    paths.size.should == 1',
                 "    paths.first.should == File.join(@sequence.send(:cookbook_repo_directory, repo), 'cookbooks_path')",
                 '  end' ]
{'fraction_non_alphanumeric': 0.11417270929466052, 'fraction_numerical': 0.0023071852340145024, 'mean_word_length': 3.531362007168459, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3091212', 'n_tokens_mistral': 4464, 'n_tokens_neox': 4291, 'n_words': 960}