require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper.rb'))
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib', 'whiskey_disk', 'helpers'))

describe 'when checking for a role during setup or deployment' do
  it 'accepts a role string' do
    lambda { role?('web') }.should.not.raise(ArgumentError)
  end
  
  it 'requires a role string' do
    lambda { role? }.should.raise(ArgumentError)
  end

  it 'returns false if the WD_ROLES environment variable is unset' do
    ENV['WD_ROLES'] = nil
    role?(:web).should.be.false
  end

  it 'returns false if the WD_ROLES environment variable is empty' do
    ENV['WD_ROLES'] = ''
    role?(:web).should.be.false
  end
  
  it 'returns true if the role, as a symbol is among the roles in the WD_ROLES env variable' do
    ENV['WD_ROLES'] = 'db:web'
    role?(:db).should.be.true
  end
  
  it 'returns true if the role, as a string is among the roles in the WD_ROLES env variable' do
    ENV['WD_ROLES'] = 'db:web'
    role?('db').should.be.true
  end
  
  it 'returns false if the role, as a symbol is not among the roles in the WD_ROLES env variable' do
    ENV['WD_ROLES'] = 'db:web'
    role?(:app).should.be.false
  end
  
  it 'returns false if the role, as a string is not among the roles in the WD_ROLES env variable' do
    ENV['WD_ROLES'] = 'db:web'
    role?('app').should.be.false
  end
end

def set_git_changes(changes)
  self.stub!(:git_changes).and_return(changes)
end

def set_rsync_changes(changes)
  self.stub!(:rsync_changes).and_return(changes)
end

describe 'when determining if certain files changed when a deployment was run' do
  before do
    @matching_file     = '/path/to/file'
    @matching_path     = '/path/to'
    @non_matching_file = '/nowhere/file'
    @substring_file    = '/nowhere/filething'
    @random_file       = '/random/path'
    
    set_git_changes([])
    set_rsync_changes([])
  end
  
  it 'accepts a path' do
    lambda { changed?('foo') }.should.not.raise(ArgumentError)
  end
  
  it 'requires a path' do
    lambda { changed? }.should.raise(ArgumentError)
  end
  
  it 'returns true when the specified file is in the list of git changes' do
    set_git_changes([ @matching_file, @random_file])
    changed?(@matching_file).should.be.true
  end
  
  it 'ignores trailing "/"s in the provided path when doing an exact git change match' do
    set_git_changes([ @matching_file, @random_file])
    changed?(@matching_file + '///').should.be.true    
  end
  
  it 'returns true when the specified path is a full path prefix in the list of git changes' do
    set_git_changes([ @matching_file , @random_file])
    changed?(@matching_path).should.be.true    
  end
  
  it 'ignores trailing "/"s in the provided path when doing a path git change match' do
    set_git_changes([ @matching_file , @random_file])
    changed?(@matching_path + '///').should.be.true    
  end

  it 'returns true when the specified file is in the list of rsync changes' do    
    set_rsync_changes([ @matching_file, @random_file])
    changed?(@matching_file).should.be.true
  end

  it 'ignores trailing "/"s in the provided path when doing an exact rsync change match' do
    set_rsync_changes([ @matching_file, @random_file])
    changed?(@matching_file + "///").should.be.true
  end

  it 'returnes true when the specified path is a full path prefix in the list of git changes' do
    set_rsync_changes([ @matching_file , @random_file])
    changed?(@matching_path).should.be.true    
  end
  
  it 'ignores trailing "/"s in the provided path when doing a path rsync change match' do
    set_rsync_changes([ @matching_file , @random_file])
    changed?(@matching_path + '///').should.be.true    
  end
  
  it 'ignores regex metacharacters when looking for a git match' do
    set_git_changes([ '/path/to/somestring'])
    changed?('/path/to/some.*').should.be.false
  end
  
  it 'ignores regex metacharacters when looking for an rsync match' do
    set_rsync_changes([ '/path/to/somestring'])
    changed?('/path/to/some.*').should.be.false
  end
  
  it 'returns true when the git changes file cannot be found' do
    set_git_changes(nil)
    changed?(@matching_file).should.be.true    
  end
  
  it 'returns false if not path or file matches the specified file' do
    set_git_changes([@matching_file, @matching_path, @random_file, @substring_file])
    set_rsync_changes([@matching_file, @matching_path, @random_file, @substring_file])
    changed?(@non_matching_file).should.be.false
  end
end

describe "when finding files changed by git in a deployment" do
  before do
    @contents = 'CHANGELOG
README.markdown
Rakefile
VERSION
lib/whiskey_disk.rb
lib/whiskey_disk/config.rb
lib/whiskey_disk/helpers.rb
scenarios/git_repositories/project.git/objects/04/26e152e66c8cd42974279bdcae09be9839c172
scenarios/git_repositories/project.git/objects/04/f4de85eaf72ef1631dc6d7424045c0a749b757
scenarios/git_repositories/project.git/refs/heads/bad_rakefile
scenarios/git_repositories/project.git/refs/heads/master
scenarios/remote/deploy.yml
spec/integration/deployment_failures_spec.rb
spec/integration/post_rake_tasks_spec.rb
spec/integration/staleness_checks_spec.rb
spec/spec_helper.rb
spec/whiskey_disk/config_spec.rb
spec/whiskey_disk/helpers_spec.rb
spec/whiskey_disk_spec.rb
whiskey_disk.gemspec
'   
  end
    
  it 'works without arguments' do
    lambda { git_changes }.should.not.raise(ArgumentError)
  end
  
  it 'does not allow arguments' do
    lambda { git_changes(:foo) }.should.raise(ArgumentError)
  end
  
  it 'returns nil when a git changes file cannot be found' do
    self.stub!(:read_git_changes_file).and_raise
    git_changes.should.be.nil
  end
  
  it 'returns an empty list if no files are found in the git changes file' do
    self.stub!(:read_git_changes_file).and_return('')
    git_changes.should == []
  end
  
  it 'returns a list of all filenames mentioned in the git changes file' do
    self.stub!(:read_git_changes_file).and_return(@contents)
    git_changes.should == @contents.split("\n")
  end
  
  it 'strips duplicates from filenames mentioned in the git changes file' do
    lines = @contents.split("\n")
    duplicates = @contents + lines.first + "\n" + lines.last + "\n"
    self.stub!(:read_git_changes_file).and_return(duplicates)
    git_changes.sort.should == @contents.split("\n").sort
  end
end

describe "when finding files changed by rsync in a deployment" do
  before do
    @contents = '2011/02/27 20:11:42 [36728] receiving file list
2011/02/27 20:11:42 [36728] sent 24 bytes  received 9 bytes  total size 0
2011/02/27 20:11:58 [36780] receiving file list
2011/02/27 20:11:58 [36780] sent 24 bytes  received 9 bytes  total size 0
2011/02/27 20:12:09 [36808] receiving file list
2011/02/27 20:12:09 [36808] sent 24 bytes  received 9 bytes  total size 0
2011/02/27 20:12:19 [36835] receiving file list
2011/02/27 20:12:19 [36835] .d..t.... ./
2011/02/27 20:12:19 [36835] >f+++++++ Info.plist
2011/02/27 20:12:19 [36835] cd+++++++ Application Support/
2011/02/27 20:12:19 [36835] cd+++++++ Application Support/Google/
2011/02/27 20:12:19 [36835] cd+++++++ Application Support/Google/GoogleTalkPlugin.app/
2011/02/27 20:12:19 [36835] cd+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/
2011/02/27 20:12:19 [36835] >f+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/Info.plist
2011/02/27 20:12:19 [36835] cd+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/
2011/02/27 20:12:19 [36835] cd+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/
2011/02/27 20:12:19 [36835] cL+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/GoogleBreakpad -> Versions/Current/GoogleBreakpad
2011/02/27 20:12:19 [36835] cL+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Resources -> Versions/Current/Resources
2011/02/27 20:12:19 [36835] cd+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Versions/
2011/02/27 20:12:19 [36835] cL+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Versions/Current -> A
2011/02/27 20:12:19 [36835] cd+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Versions/A/
2011/02/27 20:12:19 [36835] cd+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Versions/A/Resources/
2011/02/27 20:12:19 [36835] cd+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Versions/A/Resources/Reporter.app/
2011/02/27 20:12:19 [36835] cd+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Versions/A/Resources/Reporter.app/Contents/
2011/02/27 20:12:19 [36835] cd+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/MacOS/
2011/02/27 20:12:20 [36835] >f+++++++ Application Support/Google/GoogleTalkPlugin.app/Contents/MacOS/GoogleTalkPlugin
2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/
2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/googletalkbrowserplugin.plugin/
2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/googletalkbrowserplugin.plugin/Contents/
2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/googletalkbrowserplugin.plugin/Contents/MacOS/
2011/02/27 20:12:20 [36835] >f+++++++ Internet Plug-Ins/googletalkbrowserplugin.plugin/Contents/MacOS/googletalkbrowserplugin
2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/googletalkbrowserplugin.plugin/Contents/Resources/
2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/npgtpo3dautoplugin.plugin/
2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/
2011/02/27 20:12:20 [36835] >f+++++++ Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Info.plist
2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks/
2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks/Cg.framework/
2011/02/27 20:12:20 [36835] cL+++++++ Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks/Cg.framework/Cg -> Versions/Current/Cg
2011/02/27 20:12:20 [36835] cL+++++++ Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks/Cg.framework/Resources -> Versions/Current/Resources
2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks/Cg.framework/Versions/
2011/02/27 20:12:20 [36835] cL+++++++ Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks/Cg.framework/Versions/Current -> 1.0
2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks/Cg.framework/Versions/1.0/
2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/MacOS/
2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Resources/
2011/02/27 20:12:20 [36835] cd+++++++ Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Resources/English.lproj/
2011/02/27 20:12:20 [36835] cd+++++++ QuickTime/
2011/02/27 20:12:20 [36835] cd+++++++ QuickTime/Google Camera Adapter 0.component/
2011/02/27 20:12:20 [36835] cd+++++++ QuickTime/Google Camera Adapter 0.component/Contents/
2011/02/27 20:12:20 [36835] cd+++++++ QuickTime/Google Camera Adapter 0.component/Contents/MacOS/
2011/02/27 20:12:20 [36835] cd+++++++ QuickTime/Google Camera Adapter 0.component/Contents/Resources/
2011/02/27 20:12:20 [36835] cd+++++++ QuickTime/Google Camera Adapter 1.component/
2011/02/27 20:12:20 [36835] cd+++++++ QuickTime/Google Camera Adapter 1.component/Contents/
2011/02/27 20:12:20 [36835] >f+++++++ QuickTime/Google Camera Adapter 1.component/Contents/Info.plist
2011/02/27 20:12:20 [36835] cd+++++++ QuickTime/Google Camera Adapter 1.component/Contents/MacOS/
2011/02/27 20:12:20 [36835] cd+++++++ QuickTime/Google Camera Adapter 1.component/Contents/Resources/
2011/02/27 20:12:20 [36835] sent 386 bytes  received 1431 bytes  total size 5229466
'

    @changes = [
        "Info.plist",
        "Application Support",
        "Application Support/Google",
        "Application Support/Google/GoogleTalkPlugin.app",
        "Application Support/Google/GoogleTalkPlugin.app/Contents",
        "Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks",
        "Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework",
        "Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/GoogleBreakpad -> Versions/Current/GoogleBreakpad",
        "Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Resources -> Versions/Current/Resources",
        "Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Versions",
        "Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Versions/A",
        "Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Versions/A/Resources",
        "Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Versions/A/Resources/Reporter.app",
        "Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Versions/A/Resources/Reporter.app/Contents",
        "Application Support/Google/GoogleTalkPlugin.app/Contents/Frameworks/GoogleBreakpad.framework/Versions/Current -> A",
        "Application Support/Google/GoogleTalkPlugin.app/Contents/Info.plist",
        "Application Support/Google/GoogleTalkPlugin.app/Contents/MacOS",
        "Application Support/Google/GoogleTalkPlugin.app/Contents/MacOS/GoogleTalkPlugin",
        "Internet Plug-Ins",
        "Internet Plug-Ins/googletalkbrowserplugin.plugin",
        "Internet Plug-Ins/googletalkbrowserplugin.plugin/Contents",
        "Internet Plug-Ins/googletalkbrowserplugin.plugin/Contents/MacOS",
        "Internet Plug-Ins/googletalkbrowserplugin.plugin/Contents/MacOS/googletalkbrowserplugin",
        "Internet Plug-Ins/googletalkbrowserplugin.plugin/Contents/Resources",
        "Internet Plug-Ins/npgtpo3dautoplugin.plugin",
        "Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents",
        "Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks",
        "Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks/Cg.framework",
        "Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks/Cg.framework/Cg -> Versions/Current/Cg",
        "Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks/Cg.framework/Resources -> Versions/Current/Resources",
        "Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks/Cg.framework/Versions",
        "Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks/Cg.framework/Versions/1.0",
        "Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Frameworks/Cg.framework/Versions/Current -> 1.0",
        "Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Info.plist",
        "Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/MacOS",
        "Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Resources",
        "Internet Plug-Ins/npgtpo3dautoplugin.plugin/Contents/Resources/English.lproj",
        "QuickTime",
        "QuickTime/Google Camera Adapter 0.component",
        "QuickTime/Google Camera Adapter 0.component/Contents",
        "QuickTime/Google Camera Adapter 0.component/Contents/MacOS",
        "QuickTime/Google Camera Adapter 0.component/Contents/Resources",
        "QuickTime/Google Camera Adapter 1.component",
        "QuickTime/Google Camera Adapter 1.component/Contents",
        "QuickTime/Google Camera Adapter 1.component/Contents/Info.plist",
        "QuickTime/Google Camera Adapter 1.component/Contents/MacOS",
        "QuickTime/Google Camera Adapter 1.component/Contents/Resources",
      ]
  end

  it 'works without arguments' do
    lambda { rsync_changes }.should.not.raise(ArgumentError)
  end

  it 'does not allow arguments' do
    lambda { rsync_changes(:foo) }.should.raise(ArgumentError)
  end

  it 'returns nil when an rsync changes file cannot be found' do
    self.stub!(:read_rsync_changes_file).and_raise
    rsync_changes.should.be.nil
  end

  it 'returns an empty list if no files are found in the rsync changes file' do
    self.stub!(:read_rsync_changes_file).and_return('')
    rsync_changes.should == []
  end

  it 'returns a list of all changed filenames mentioned in the rsync changes file, excluding "."' do
    self.stub!(:read_rsync_changes_file).and_return(@contents)
    rsync_changes.sort.first.should == @changes.sort.first
  end
end

describe 'when reading the git-related changes for a deployment' do
  before do
    @contents = 'git changes'
    @changes_path = '/path/to/git/changes'
    self.stub!(:git_changes_path).and_return(@changes_path)
    File.stub!(:read).with(@changes_path).and_return(@contents)
  end
  
  it 'works without arguments' do
    lambda { read_git_changes_file }.should.not.raise(ArgumentError)
  end
  
  it 'does not allow arguments' do
    lambda { read_git_changes_file(:foo) }.should.raise(ArgumentError)
  end
  
  it 'reads the git changes file' do
    File.should.receive(:read) do |arg|
      arg.should == @changes_path
      @contents
    end
    read_git_changes_file
  end
  
  it 'returns the contents of the git changes file' do
    read_git_changes_file.should == @contents
  end
  
  it 'fails if the git changes file cannot be read' do
    File.stub!(:read).with(@changes_path).and_raise(Errno::ENOENT)
    lambda { read_git_changes_file }.should.raise(Errno::ENOENT)
  end
end

describe 'when reading the rsync-related changes for a deployment' do
  before do
    @contents = 'rsync changes'
    @changes_path = '/path/to/rsync/changes'
    self.stub!(:rsync_changes_path).and_return(@changes_path)
    File.stub!(:read).with(@changes_path).and_return(@contents)
  end
  
  it 'works without arguments' do
    lambda { read_rsync_changes_file }.should.not.raise(ArgumentError)
  end
  
  it 'does not allow arguments' do
    lambda { read_rsync_changes_file(:foo) }.should.raise(ArgumentError)
  end
  
  it 'reads the rsync changes file' do
    File.should.receive(:read) do |arg|
      arg.should == @changes_path
      @contents
    end
    read_rsync_changes_file
  end
  
  it 'returns the contents of the rsync changes file' do
    read_rsync_changes_file.should == @contents
  end
  
  it 'fails if the rsync changes file cannot be read' do
    File.stub!(:read).with(@changes_path).and_raise(Errno::ENOENT)
    lambda { read_rsync_changes_file }.should.raise(Errno::ENOENT)
  end
end

describe 'computing the path to the git changes file' do
  before do
    @git_path = '/path/to/toplevel'
    @io_handle = ''
    IO.stub!(:popen).with("git rev-parse --show-toplevel").and_return(@io_handle)
    @io_handle.stub!(:read).and_return(@git_path + "\n")
  end
  
  it 'works without arguments' do
    lambda { git_changes_path }.should.not.raise(ArgumentError)
  end
  
  it 'does not allow arguments' do
    lambda { git_changes_path(:foo) }.should.raise(ArgumentError)
  end
  
  it 'returns the path to the .whiskey_disk_git_changes file in the git top-level path' do
    git_changes_path.should == File.join(@git_path, '.whiskey_disk_git_changes')
  end
  
  it 'returns the path to the .whiskey_disk_git_changes file in the current directory of the git top-level cannot be found' do
    @io_handle.stub!(:read).and_return('')
    git_changes_path.should == File.join(Dir.pwd, '.whiskey_disk_git_changes')    
  end
end

describe 'computing the path to the rsync changes file' do
  before do
    @rsync_path = '/path/to/toplevel'
    @io_handle = ''
    IO.stub!(:popen).with("git rev-parse --show-toplevel").and_return(@io_handle)
    @io_handle.stub!(:read).and_return(@rsync_path + "\n")
  end
  
  it 'works without arguments' do
    lambda { rsync_changes_path }.should.not.raise(ArgumentError)
  end
  
  it 'does not allow arguments' do
    lambda { rsync_changes_path(:foo) }.should.raise(ArgumentError)
  end
  
  it 'returns the path to the .whiskey_disk_rsync_changes file in the git top-level path' do
    rsync_changes_path.should == File.join(@rsync_path, '.whiskey_disk_rsync_changes')
  end
  
  it 'returns the path to the .whiskey_disk_rsync_changes file in the current directory of the git top-level cannot be found' do
    @io_handle.stub!(:read).and_return('')
    rsync_changes_path.should == File.join(Dir.pwd, '.whiskey_disk_rsync_changes')    
  end
end