require File.dirname(__FILE__) + '/base' describe Rush::SshTunnel do before do @tunnel = Rush::SshTunnel.new('spec.example.com') @tunnel.stub!(:config).and_return(mock_config_start) @tunnel.stub!(:display) end after do mock_config_cleanup end it "ensure_tunnel sets everything up for the tunnel when one does not already exist" do @tunnel.should_receive(:push_credentials) @tunnel.should_receive(:launch_rushd) @tunnel.should_receive(:establish_tunnel) @tunnel.ensure_tunnel end it "ensure_tunnel uses the existing port as long as the tunnel is still alive" do @tunnel.should_receive(:tunnel_alive?).and_return(true) @tunnel.instance_eval("@port = 2345") @tunnel.ensure_tunnel @tunnel.port.should == 2345 end it "existing tunnel is used when it is specified in the tunnels file" do @tunnel.config.tunnels_file.write "spec.example.com:4567\n" @tunnel.should_receive(:tunnel_alive?).and_return(true) @tunnel.should_not_receive(:setup_everything) @tunnel.ensure_tunnel @tunnel.port.should == 4567 end it "tunnel host is always local" do @tunnel.host.should == 'localhost' end it "picks the first port number when there are no tunnels yet" do @tunnel.next_available_port.should == 7771 end it "picks the next port number when there is already a tunnel" do @tunnel.config.tunnels_file.write("#{@tunnel.host}:7771") @tunnel.next_available_port.should == 7772 end it "establishes a tunnel and saves it to ~/.rush/tunnels" do @tunnel.should_receive(:make_ssh_tunnel) @tunnel.should_receive(:port).exactly(0).times.and_return('7771') # avoid infinite loop @tunnel.establish_tunnel @tunnel.config.tunnels_file.contents.should == "spec.example.com:7771\n" end it "converts instance vars to options hash for ssh_tunnel_command" do @tunnel.instance_eval("@port = 1234") @tunnel.tunnel_options.should == { :local_port => 1234, :remote_port => 7770, :ssh_host => 'spec.example.com' } end it "ssh_stall_command uses an infinite loop for :timeout => :infinite" do @tunnel.ssh_stall_command(:timeout => :infinite).should match(/while .* sleep .* done/) end it "ssh_stall_command sleeps for the number of seconds given as the :timeout option" do @tunnel.ssh_stall_command(:timeout => 123).should == "sleep 123" end it "ssh_stall_command uses the default timeout when no options are given" do @tunnel.ssh_stall_command.should == "sleep 9000" end it "constructs the ssh tunnel command (everything but stall) from the options hash" do @tunnel.should_receive(:tunnel_options).at_least(:once).and_return( :local_port => 123, :remote_port => 456, :ssh_host => 'example.com' ) @tunnel.ssh_tunnel_command_without_stall.should == "ssh -f -L 123:127.0.0.1:456 example.com" end it "combines the tunnel command without stall and the stall command into the final command" do @tunnel.should_receive(:ssh_tunnel_command_without_stall).and_return('ssh command') @tunnel.should_receive(:ssh_stall_command).and_return('sleep 123') @tunnel.ssh_tunnel_command.should == 'ssh command "sleep 123"' end it "ssh_tunnel_command request that the port be set" do @tunnel.should_receive(:tunnel_options).at_least(:once).and_return(:local_port => nil) lambda { @tunnel.ssh_tunnel_command }.should raise_error(Rush::SshTunnel::NoPortSelectedYet) end it "push_credentials uses ssh to append to remote host's passwords file" do @tunnel.should_receive(:ssh_append_to_credentials).and_return(true) @tunnel.push_credentials end it "launches rushd on the remote host via ssh" do @tunnel.should_receive(:ssh) do |cmd| cmd.should match(/rushd/) end @tunnel.launch_rushd end it "tunnel_alive? checks whether a tunnel is still up" do @tunnel.should_receive(:tunnel_count_command).and_return("echo 1") @tunnel.tunnel_alive?.should be_true end it "tunnel_count_command greps ps to find the ssh tunnel" do @tunnel.should_receive(:ssh_tunnel_command_without_stall).and_return('ssh command') command = @tunnel.tunnel_count_command command.should match(/ps/) command.should match(/grep/) command.should match(/ssh command/) end end