require 'gorgon/source_tree_syncer' describe SourceTreeSyncer.new("") do it { should respond_to :exclude= } it { should respond_to :sync } it { should respond_to :sys_command } it { should respond_to :remove_temp_dir } it { should respond_to :success? } it { should respond_to :output } it { should respond_to :errors } let(:stdin) { stub("IO object", :close => nil)} let(:stdout) { stub("IO object", :read => nil, :close => nil)} let(:stderr) { stub("IO object", :read => nil, :close => nil)} let(:status) { stub("Process Status", :exitstatus => 0)} before do @syncer = SourceTreeSyncer.new "path/to/source" stub_utilities_methods end describe "#sync" do it "makes tempdir and changes current dir to temdir" do Dir.should_receive(:mktmpdir).and_return("tmp/dir") Dir.should_receive(:chdir).with("tmp/dir") @syncer.sync end context "invalid source_tree_path" do it "gives error if source_tree_path is empty string" do syncer = SourceTreeSyncer.new " " Dir.should_not_receive(:mktmpdir) syncer.sync syncer.success?.should be_false syncer.errors.should == "Source tree path cannot be empty. Check your gorgon.json file." end it "gives error if source_tree_path is nil" do syncer = SourceTreeSyncer.new nil Dir.should_not_receive(:mktmpdir) syncer.sync syncer.success?.should be_false syncer.errors.should == "Source tree path cannot be nil. Check your gorgon.json file." end end context "options" do it "runs rsync system command with appropriate options" do cmd = /rsync.*-azr .*path\/to\/source\/\ \./ Open4.should_receive(:popen4).with(cmd) @syncer.sync end it "exclude files when they are specified" do @syncer.exclude = ["log", ".git"] Open4.should_receive(:popen4).with(/--exclude log --exclude .git/) @syncer.sync end it "use NumberOfPasswordPrompts 0 as ssh option to avoid password prompts that will hang the listener" do opt = /--rsh='ssh .*-o NumberOfPasswordPrompts=0.*'/ Open4.should_receive(:popen4).with(opt) @syncer.sync end it "set UserKnownHostsFile to /dev/null so we avoid hosts id changes and eavesdropping warnings in futures connections" do opt = /ssh .*-o UserKnownHostsFile=\/dev\/null/ Open4.should_receive(:popen4).with(opt) @syncer.sync end it "set StrictHostKeyChecking to 'no' to avoid confirmation prompt of connection to unkown host" do opt = /ssh .*-o StrictHostKeyChecking=no/ Open4.should_receive(:popen4).with(opt) @syncer.sync end it "uses io timeout to avoid listener hanging forever in case rsync asks for any input" do opt = /--timeout=5/ Open4.should_receive(:popen4).with(opt) @syncer.sync end end end describe "#success?" do it "returns true if sync execution was successful" do status.should_receive(:exitstatus).and_return(0) @syncer.sync @syncer.success?.should be_true end it "returns false if sync execution failed" do status.should_receive(:exitstatus).and_return(1) @syncer.sync @syncer.success?.should be_false end end describe "#output" do it "returns standard output of rsync" do stdout.should_receive(:read).and_return("some output") @syncer.sync @syncer.output.should == "some output" end end describe "#errors" do it "returns standard error output of rsync" do stderr.should_receive(:read).and_return("some errors") @syncer.sync @syncer.errors.should == "some errors" end end describe "#remove_temp_dir" do before do @syncer = SourceTreeSyncer.new "path/to/source" stub_utilities_methods @syncer.sync end it "remove temporary dir" do FileUtils.should_receive(:remove_entry_secure).with("tmp/dir") @syncer.remove_temp_dir end end private def stub_utilities_methods Dir.stub!(:mktmpdir).and_return("tmp/dir") Dir.stub!(:chdir) Open4.stub!(:popen4).and_return([1, stdin, stdout, stderr]) Process.stub!(:waitpid2).and_return([nil, status]) FileUtils.stub!(:remove_entry_secure) @syncer.stub!(:system) end end