require File.expand_path(File.dirname(__FILE__) + '/spec_helper') describe "Checksummer" do let(:checksum_to) { "/data" } describe "#find" do let(:files) do [ "/v1/incoming/ 2010-09-14+10:16:26.4888617110 66 d ", "/v1/incoming/rsync_from_delivery_host 2010-07-08+17:52:08.6168163060 76 d ", "d /v1/incoming/rsync_from_delivery_host/finetunes 2010-12-06+18:12:13.0000000000 737280 ", "/v1/incoming/rsync_from_delivery_host/finetunes/1069604473114 2010-07-24+19:46:38.0000000000 30 d ", "/v1/incoming/rsync_from_delivery_host/finetunes/1069604473114/1069604473114.xml 2009-10-31+16:29:51.0000000000 12032 f ", "/v1/incoming/rsync_from_delivery_host/finetunes/1069604681256 2010-07-24+19:46:38.0000000000 30 d " ].join("\n") end before(:each) do Kernel.stub(:`).and_return(files) end it "calls system command with correct arguments" do Kernel.should_receive(:`).with(%(find path1 -type f -printf "%p\t%T+\t%s\t%Y\t%l\n")) Checksummer.find("path1") end it "uses find options" do Kernel.should_receive(:`).with(%(find path1 -mtime +1 -type f -printf "%p\t%T+\t%s\t%Y\t%l\n")) Checksummer.find("path1", "-mtime +1") end it "returns the correct amount of files" do Checksummer.find("path1").length.should == 6 end it "returns objects of type ChecksummerFile" do Checksummer.find("path1").first.should be_an_instance_of(String) end it "sets the correct atributes" do Checksummer.find("path1").first.should == "/v1/incoming/ 2010-09-14+10:16:26.4888617110 66 d " end end describe "#run_for_args" do before(:each) do Checksummer.stub!(:puts) end it "prints the version when --version given" do Checksummer.should_receive(:puts).with(/\d+\.\d+.\d+/) Checksummer.run_for_args("--version") end it "prints usage when no checksum_to found" do Checksummer.should_receive(:puts).with Checksummer.usage Checksummer.run_for_args([]) end it "prints usage when checksum dir is not a directory" do Checksummer.should_receive(:puts).with Checksummer.usage Checksummer.run_for_args(["/path/to/something"]) end it "prints usage when checksum_to is no directory" do Checksummer.should_receive(:puts).with Checksummer.usage Checksummer.run_for_args(["/tmp", "/some/path"]) end it "calls find with the correct attributes" do Checksummer.should_receive(:find).with("/tmp", %(-name "*.mp3")).and_return([]) Checksummer.run_for_args(["/tmp", "/tmp", "-name", %("*.mp3")]) end # it "initializes checksummer with correct checksum_to dir" do # Checksummer.should_receive(:new).with("/tmp").and_return(double("checksummer", :checksum_directory => true)) # Checksummer.run_for_args(["/tmp", "/tmp"]) # end # # it "calls checksum_directory with correct find options" do # checksummer = double("checksummer") # Checksummer.stub!(:new).and_return checksummer # checksummer.should_receive(:checksum_directory).with("/tmp", %(-name "*.mp3")) # Checksummer.run_for_args(["/tmp", "/tmp", "-name", %("*.mp3")]) # end # # it "does not call checksum_directory with sleep parameter" do # checksummer = double("checksummer") # Checksummer.stub!(:new).and_return checksummer # checksummer.should_receive(:checksum_directory).with("/tmp", %(-mtime +1)) # Checksummer.run_for_args(["/tmp", "/tmp", "-mtime", "+1", "--sleep", "10"]) # end describe "with files given from stdin" do it "calls from_line with all files from stdin" do $stdin = StringIO.new("/path/1.txt\n/path/2.txt") file_double = double("file", :checksum_to! => {}) ChecksummerFile.should_receive(:from_line).with("/path/1.txt\n").and_return file_double ChecksummerFile.should_receive(:from_line).with("/path/2.txt").and_return file_double Checksummer.run_for_args(["--stdin", "/tmp"]) end it "calls checksum_files with files_from_stream when --stdin given" do $stdin = StringIO.new("/path/1.txt\n/path/2.txt") double1 = double("double 1") double2 = double("double 2") ChecksummerFile.stub(:from_line).with("/path/1.txt\n").and_return double1 ChecksummerFile.stub(:from_line).with("/path/2.txt").and_return double2 double1.should_receive(:checksum_to!).with("/tmp").and_return({}) double2.should_receive(:checksum_to!).with("/tmp").and_return({}) Checksummer.run_for_args(["--stdin", "/tmp"]) end end describe "with a cs double" do before(:each) do Checksummer.stub!(:find).and_return(%w(/path1.txt /path2.txt)) end it "calls sleep with 0.1 when between 8 and 23:59" do time = Time.local(2011, 1, 2, 8, 0, 0) Time.stub!(:now).and_return(time) Checksummer.should_receive(:sleep).with(0.1).at_least(1).times Checksummer.run_for_args(["/tmp", "/tmp"]) end it "calls sleep with 0.5 when between 8 and 23:59 and custom sleep given" do time = Time.local(2011, 1, 2, 8, 0, 0) Time.stub!(:now).and_return(time) Checksummer.should_receive(:sleep).with(0.5).at_least(1).times Checksummer.run_for_args(["/tmp", "/tmp", "--sleep", "500"]) end it "does not call sleep with 0.1 when between 00:00 and 07:59" do time = Time.local(2011, 1, 2, 7, 59, 59) Time.stub!(:now).and_return(time) Checksummer.should_not_receive(:sleep) Checksummer.run_for_args(["/tmp", "/tmp"]) end end describe "with a direct file given" do let(:checksum_file) { double("checksummer_file", :checksum_to! => {})} before(:each) do File.stub!(:file?).and_return true ChecksummerFile.stub!(:from_line).and_return(checksum_file) end it "calls ChecksummerFile.from_line with file" do ChecksummerFile.should_receive(:from_line).with("/some/path").and_return(checksum_file) Checksummer.run_for_args(["/some/path", "/tmp"]) end it "calls checksum_to! with dst" do checksum_file.should_receive(:checksum_to!).with("/tmp") Checksummer.run_for_args(["/some/path", "/tmp"]) end it "puts result of checksum_to!" do Time.stub(:now).and_return Time.local(2011, 2, 3, 4, 5, 6) checksum_file.stub!(:checksum_to!).and_return(:some => "result") Checksummer.should_receive(:puts).with( "{\"some\":\"result\",\"index\":1,\"total\":1,\"started_at\":\"2011-02-03T04:05:06+01:00\"}" ) Checksummer.run_for_args(["/some/path", "/tmp"]) end end end describe "#integration" do let(:root) { File.expand_path("tmp", File.dirname(__FILE__)) } def time_for_index(index) Time.local(2010, 11, 12, 13, 14, index) end before(:each) do FileUtils.rm_rf(root) FileUtils.mkdir_p("#{root}/source") FileUtils.mkdir_p("#{root}/data") FileUtils.mkdir_p("#{root}/data/a/b/c/d/abcdefg") 1.upto(3).each do |i| path = "#{root}/source/file#{i}.txt" File.open(path, "w") { |f| f.puts "file #{i}" } FileUtils.touch("#{root}/source/file#{i}.txt", :mtime => time_for_index(i)) end FileUtils.ln_sf("#{root}/data/a/b/c/d/abcdefg", "#{root}/source/file4.txt") FileUtils.touch("#{root}/data/a/b/c/d/abcdefg", :mtime => time_for_index(4)) end it "checksums all files" do Checksummer.stub!(:puts) Checksummer.run_for_args(["#{root}/source", "#{root}/data"]) { "4/3/4/9/4349cfeff8e2eb74dffc369bb5fd084e" => ["file2.txt", time_for_index(2)], "9/c/3/8/9c38e8324dbf031557c89d53a39f0b26" => ["file3.txt", time_for_index(3)], "e/2/4/3/e243bb39c844b3543a7726576c869caf" => ["file1.txt", time_for_index(1)], "a/b/c/d/abcdefg" => ["file4.txt", time_for_index(4)] }.each do |data_file, (original_file, mtime)| original = Pathname.new("#{root}/source/#{original_file}") data = Pathname.new("#{root}/data/#{data_file}") File.should be_exists(original.to_s) File.should be_exists(data.to_s) original.realpath.to_s.should match(/\//) original.realpath.should == data File.mtime(original).should == mtime end end it "only runs on specific files when option given" do File.open("#{root}/source/test.mp3", "w") { |f| f.puts "some mp3" } Checksummer.stub!(:puts) Checksummer.run_for_args(["#{root}/source", "#{root}/data", "-name", %("*.mp3")]) File.should be_a_symlink("#{root}/source/test.mp3") File.should be_exists("#{root}/source/file1.txt") File.should_not be_a_symlink("#{root}/source/file1.txt") end end end