require 'spec_helper' describe ChecksummerFile do let(:line) { "/v1/incoming/ 2010-09-14+10:16:26.4888617110 66 d /tmp\n" } describe "#from_line" do before(:each) do @file = ChecksummerFile.from_line(line) end it "returns a ChecksummerFile" do @file.should be_an_instance_of(ChecksummerFile) end it "sets path to the first chunk" do @file.path.should == "/v1/incoming" end it "sets the original_line to the chomped line" do @file.original_line.should == "/v1/incoming/ 2010-09-14+10:16:26.4888617110 66 d /tmp" end it "calls expans_path on all found paths" do File.should_receive(:expand_path).with("/v1/incoming/").and_return "/some/path" ChecksummerFile.from_line(line).path.should == "/some/path" end it "does not break when line is nil" do ChecksummerFile.from_line("\n").path.should == nil end end describe "#checksum_to!" do let(:file) { ChecksummerFile.new(:path => "/some/text.csv") } let(:time) { Time.local(2010, 9, 10, 11, 12, 13) } let(:md5) { "fde8dad8ea43640b00cdd1e92e532ca9" } before(:each) do FileUtils.stub!(:cp).and_return true FileUtils.stub!(:mkdir_p) FileUtils.stub!(:touch) FileUtils.stub(:ln_sf).and_return true FileUtils.stub(:mv).and_return true File.stub!(:exists?).and_return false File.stub(:symlink?).and_return false File.stub!(:mtime).and_return time file.stub!(:md5).and_return md5 File.stub(:exists?).with("/some/text.csv").and_return true end it "calls exists with correct parameters" do File.should_receive(:exists?).with("/tmp/data/f/d/e/8/fde8dad8ea43640b00cdd1e92e532ca9") file.checksum_to!("/tmp/data") end it "calls File.symlink? with the correct parameters" do File.should_receive(:symlink?).with("/some/text.csv").and_return false file.checksum_to!("/tmp/data") end it "calls md5_path with correct directory" do file.should_receive(:md5_path).with("/tmp/data").at_least(1).times.and_return md5 file.checksum_to!("/tmp/data") end it "returns a hash" do file.checksum_to!("/tmp/data").should be_an_instance_of(Hash) end it "includes the original line" do file.original_line = "some line" file.checksum_to!("/tmp/data")[:original_line].should == "some line" end it "includes the path" do file.checksum_to!("/tmp/data")[:original_path].should == "/some/text.csv" end it "includes status :not_found when path is blank" do file.path = " " file.checksum_to!("/tmp/data")[:status].should == :not_found end it "includes status :no_exusts when path is nil" do file.path = nil file.checksum_to!("/tmp/data")[:status].should == :not_found end describe "with the file not being checksummed" do it "copys the file to it's md5" do File.stub!(:exists?).with("/tmp/data/f/d/e/8/fde8dad8ea43640b00cdd1e92e532ca9").and_return false FileUtils.should_receive(:cp).with("/some/text.csv", "/tmp/data/f/d/e/8/fde8dad8ea43640b00cdd1e92e532ca9.tmp") file.checksum_to!("/tmp/data") end it "renames the tmp file to the final name" do File.stub!(:exists?).with("/tmp/data/f/d/e/8/fde8dad8ea43640b00cdd1e92e532ca9").and_return false FileUtils.should_receive(:mv).with("/tmp/data/f/d/e/8/fde8dad8ea43640b00cdd1e92e532ca9.tmp", "/tmp/data/f/d/e/8/fde8dad8ea43640b00cdd1e92e532ca9") file.checksum_to!("/tmp/data") end it "calls FileUtils::mkdir_p with correct path" do FileUtils.should_receive(:mkdir_p).with("/tmp/data/f/d/e/8") file.checksum_to!("/tmp/data") end it "creates a symlink for the copied file" do FileUtils.should_receive(:ln_sf).with("/tmp/data/f/d/e/8/fde8dad8ea43640b00cdd1e92e532ca9", "/some/text.csv") file.checksum_to!("/tmp/data") end it "returns :copied when copied" do file.checksum_to!("/tmp/data")[:status].should == :copied end it "includes the checksummed_path" do file.checksum_to!("/tmp/data")[:checksummed_path].should == "/tmp/data/f/d/e/8/fde8dad8ea43640b00cdd1e92e532ca9" end it "changes the mtime of the symlink to the mtime of the original file" do FileUtils.should_receive(:touch).with("/some/text.csv", :mtime => time) file.checksum_to!("/tmp/data") end end describe "with the file being checksummed already" do before(:each) do File.stub!(:exists?).with("/tmp/data/f/d/e/8/fde8dad8ea43640b00cdd1e92e532ca9").and_return true end it "does not copy the file when already exists" do FileUtils.should_not_receive(:cp) file.checksum_to!("/tmp/data") end it "does not call FileUtils::mkdir_p" do FileUtils.should_not_receive(:mkdir_p) file.checksum_to!("/tmp/data") end it "does symlink the file" do FileUtils.should_receive(:ln_sf).with("/tmp/data/f/d/e/8/fde8dad8ea43640b00cdd1e92e532ca9", "/some/text.csv") file.checksum_to!("/tmp/data") end it "returns :symlinked" do file.checksum_to!("/tmp/data")[:status].should == :symlinked end it "includes the checksummed_path" do file.checksum_to!("/tmp/data")[:checksummed_path].should == "/tmp/data/f/d/e/8/fde8dad8ea43640b00cdd1e92e532ca9" end it "includes the checksum" do file.checksum_to!("/tmp/data")[:checksum].should == "fde8dad8ea43640b00cdd1e92e532ca9" end it "changes the mtime of the symlink to the mtime of the original file" do FileUtils.should_receive(:touch).with("/some/text.csv", :mtime => time) file.checksum_to!("/tmp/data") end end describe "with the file being a symlink" do let(:pathname) { double("rp", :realpath => "/some/real/path") } before(:each) do File.stub(:symlink?).with("/some/text.csv").and_return true File.stub!(:realpath).and_return "/some/real/path" Pathname.stub!(:new).with("/some/text.csv").and_return pathname end it "does not copy the file when already exists" do FileUtils.should_not_receive(:cp) file.checksum_to!("/tmp/data") end it "does not call FileUtils::mkdir_p" do FileUtils.should_not_receive(:mkdir_p) file.checksum_to!("/tmp/data") end it "does not symlink the file" do FileUtils.should_not_receive(:ln_sf) file.checksum_to!("/tmp/data") end it "calls Pathname#realpath with path" do pathname.should_receive(:realpath).and_return "/real_path" file.checksum_to!("/tmp/data") end it "sets the realpath" do file.checksum_to!("/tmp/data")[:realpath].should == "/some/real/path" end it "returns :exists" do file.checksum_to!("/tmp/data")[:status].should == :was_symlink end it "changes the mtime of the symlink to the mtime of the original file" do FileUtils.should_not_receive(:touch) file.checksum_to!("/tmp/data") end it "sets the checksum when pointing to a checksummed file" do pathname.stub!(:realpath).and_return "/tmp/data/fde8dad8ea43640b00cdd1e92e532ca9" file.should_receive(:valid_checksum?).with("fde8dad8ea43640b00cdd1e92e532ca9").and_return true file.checksum_to!("/tmp/data")[:checksum].should == "fde8dad8ea43640b00cdd1e92e532ca9" end it "does not set the checksum when not pointing to a checksummed path" do pathname.stub!(:realpath).and_return "/data/fde8dad8ea43640b00cdd1e92e532ca" file.should_receive(:valid_checksum?).with("fde8dad8ea43640b00cdd1e92e532ca").and_return false file.checksum_to!("/tmp/data").should_not have_key(:checksum) end end describe "with the file not existing" do it "returns status :not_exists" do ChecksummerFile.new(:path => "/some/broken/path").checksum_to!("/tmp")[:status].should == :not_found end end end describe "valid_checksum?" do { "fde8dad8ea43640b00cdd1e92e532ca9" => true, "fde8dad8ea43640b00cdd1e92e532ca" => false, "fde8dad8ea43640b00cdd1e92e532cax" => false }.each do |checksum, result| it "returns #{result} for #{checksum}" do ChecksummerFile.new.valid_checksum?(checksum).should == result end end end describe "#md5" do let(:md5_module) { double("md5 module", :file => "sometest") } let(:file) do file = ChecksummerFile.new(:path => "/some/path") file end it "calls md5_module with correct file_path when no md5 set" do Digest::MD5.should_receive(:file).with("/some/path") file.md5 end it "saves the md5 in instance variable" do checksum = double("checksum", :to_s => "the checksum") Digest::MD5.stub(:file).and_return checksum file.md5 file.instance_variable_get(:@md5).should == "the checksum" end it "returns the instance variable when set" do checksum = double("checksum") file.instance_variable_set(:@md5, checksum) file.md5.should == checksum end end describe "#path=" do it "sets the correct path" do file = ChecksummerFile.new file.path = "/some/path" file.path.should == "/some/path" end it "resets an existing md5" do file = ChecksummerFile.new file.instance_variable_set(:@md5, "somemd5") file.path = "/some/path" file.instance_variable_get(:@md5).should be_nil end end describe "#from_paths" do let(:stream) { ["/file/1.txt", "/file/2.txt\n"] } it "returns the correct amount of files" do ChecksummerFile.from_paths(stream).length.should == 2 end it "sets the correct paths" do ChecksummerFile.from_paths(stream).first.path.should == "/file/1.txt" end it "strips the paths" do ChecksummerFile.from_paths(stream).at(1).path.should == "/file/2.txt" end it "splits the lines by \t" do stream_with_tabs = ["/file/1.txt\t10", "/file/2.txt\t30\n"] ChecksummerFile.from_paths(stream_with_tabs).first.path.should == "/file/1.txt" end end end