This commit aligns how the file provisioner should work on all host machines. It ensures that a `/.` is only applied if the user intended to upload a folder to a destination under a different name. It ensures that if uploading to a windows guest with a different destination folder name, it does not nest the source folder under that name so that it works the same as it does on linux platforms. It also updates the behavior of the winrm upload communicator by allowing an array of paths to be uploaded instead of a single file or folder to allow for this new functionality for windows guests.
182 lines
6.2 KiB
Ruby
182 lines
6.2 KiB
Ruby
require File.expand_path("../../../../base", __FILE__)
|
|
|
|
require Vagrant.source_root.join("plugins/communicators/winrm/shell")
|
|
require Vagrant.source_root.join("plugins/communicators/winrm/config")
|
|
|
|
describe VagrantPlugins::CommunicatorWinRM::WinRMShell do
|
|
include_context "unit"
|
|
|
|
let(:connection) { double("winrm_connection") }
|
|
let(:shell) { double("winrm_shell") }
|
|
let(:port) { config.transport == :ssl ? 5986 : 5985 }
|
|
let(:config) {
|
|
VagrantPlugins::CommunicatorWinRM::Config.new.tap do |c|
|
|
c.username = 'username'
|
|
c.password = 'password'
|
|
c.max_tries = 3
|
|
c.retry_delay = 0
|
|
c.basic_auth_only = false
|
|
c.retry_delay = 1
|
|
c.max_tries = 2
|
|
c.finalize!
|
|
end
|
|
}
|
|
let(:output) { WinRM::Output.new.tap { |out| out.exitcode = 0 } }
|
|
|
|
before { allow(connection).to receive(:shell).and_yield(shell) }
|
|
|
|
subject do
|
|
described_class.new('localhost', port, config).tap do |comm|
|
|
allow(comm).to receive(:new_connection).and_return(connection)
|
|
end
|
|
end
|
|
|
|
describe "#upload" do
|
|
let(:fm) { double("file_manager") }
|
|
it "should call file_manager.upload for each passed in path" do
|
|
from = ["/path", "/path/folder", "/path/folder/file.py"]
|
|
to = "/destination"
|
|
size = 80
|
|
|
|
allow(WinRM::FS::FileManager).to receive(:new).with(connection)
|
|
.and_return(fm)
|
|
allow(fm).to receive(:upload).and_return(size)
|
|
|
|
expect(fm).to receive(:upload).exactly(from.size).times
|
|
expect(subject.upload(from, to)).to eq(size*from.size)
|
|
end
|
|
|
|
it "should call file_manager.upload once for a single path" do
|
|
from = "/path/folder/file.py"
|
|
to = "/destination"
|
|
size = 80
|
|
|
|
allow(WinRM::FS::FileManager).to receive(:new).with(connection)
|
|
.and_return(fm)
|
|
allow(fm).to receive(:upload).and_return(size)
|
|
|
|
expect(fm).to receive(:upload).exactly(1).times
|
|
expect(subject.upload(from, to)).to eq(size)
|
|
end
|
|
end
|
|
|
|
describe ".powershell" do
|
|
it "should call winrm powershell" do
|
|
expect(shell).to receive(:run).with("dir").and_return(output)
|
|
expect(subject.powershell("dir").exitcode).to eq(0)
|
|
end
|
|
|
|
it "should raise an execution error when an exception occurs" do
|
|
expect(shell).to receive(:run).with("dir").and_raise(
|
|
StandardError.new("Oh no! a 500 SOAP error!"))
|
|
expect { subject.powershell("dir") }.to raise_error(
|
|
VagrantPlugins::CommunicatorWinRM::Errors::ExecutionError)
|
|
end
|
|
end
|
|
|
|
describe ".elevated" do
|
|
it "should call winrm elevated" do
|
|
expect(shell).to receive(:run).with("dir").and_return(output)
|
|
expect(shell).to receive(:interactive_logon=).with(false)
|
|
expect(subject.elevated("dir").exitcode).to eq(0)
|
|
end
|
|
|
|
it "should set interactive_logon when interactive is true" do
|
|
expect(shell).to receive(:run).with("dir").and_return(output)
|
|
expect(shell).to receive(:interactive_logon=).with(true)
|
|
expect(subject.elevated("dir", { interactive: true }).exitcode).to eq(0)
|
|
end
|
|
|
|
it "should raise an execution error when an exception occurs" do
|
|
expect(shell).to receive(:run).with("dir").and_raise(
|
|
StandardError.new("Oh no! a 500 SOAP error!"))
|
|
expect { subject.powershell("dir") }.to raise_error(
|
|
VagrantPlugins::CommunicatorWinRM::Errors::ExecutionError)
|
|
end
|
|
end
|
|
|
|
describe ".cmd" do
|
|
it "should call winrm cmd" do
|
|
expect(connection).to receive(:shell).with(:cmd, { })
|
|
expect(shell).to receive(:run).with("dir").and_return(output)
|
|
expect(subject.cmd("dir").exitcode).to eq(0)
|
|
end
|
|
|
|
context "when codepage is given" do
|
|
let(:config) {
|
|
VagrantPlugins::CommunicatorWinRM::Config.new.tap do |c|
|
|
c.codepage = 800
|
|
c.finalize!
|
|
end
|
|
}
|
|
|
|
it "creates shell with the given codepage when set" do
|
|
expect(connection).to receive(:shell).with(:cmd, { codepage: 800 })
|
|
expect(shell).to receive(:run).with("dir").and_return(output)
|
|
expect(subject.cmd("dir").exitcode).to eq(0)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe ".wql" do
|
|
it "should call winrm wql" do
|
|
expect(connection).to receive(:run_wql).with("select * from Win32_OperatingSystem")
|
|
subject.wql("select * from Win32_OperatingSystem")
|
|
end
|
|
|
|
it "should retry when a WinRMAuthorizationError is received" do
|
|
expect(connection).to receive(:run_wql).with("select * from Win32_OperatingSystem").exactly(2).times.and_raise(
|
|
# Note: The initialize for WinRMAuthorizationError may require a status_code as
|
|
# the second argument in a future WinRM release. Currently it doesn't track the
|
|
# status code.
|
|
WinRM::WinRMAuthorizationError.new("Oh no!! Unauthrorized")
|
|
)
|
|
expect { subject.wql("select * from Win32_OperatingSystem") }.to raise_error(
|
|
VagrantPlugins::CommunicatorWinRM::Errors::AuthenticationFailed)
|
|
end
|
|
end
|
|
|
|
describe ".endpoint" do
|
|
context 'when transport is :ssl' do
|
|
let(:config) {
|
|
VagrantPlugins::CommunicatorWinRM::Config.new.tap do |c|
|
|
c.transport = :ssl
|
|
c.finalize!
|
|
end
|
|
}
|
|
it "should create winrm endpoint address using https" do
|
|
expect(subject.send(:endpoint)).to eq("https://localhost:5986/wsman")
|
|
end
|
|
end
|
|
|
|
context "when transport is :negotiate" do
|
|
it "should create winrm endpoint address using http" do
|
|
expect(subject.send(:endpoint)).to eq("http://localhost:5985/wsman")
|
|
end
|
|
end
|
|
|
|
context "when transport is :plaintext" do
|
|
let(:config) {
|
|
VagrantPlugins::CommunicatorWinRM::Config.new.tap do |c|
|
|
c.transport = :plaintext
|
|
c.finalize!
|
|
end
|
|
}
|
|
it "should create winrm endpoint address using http" do
|
|
expect(subject.send(:endpoint)).to eq("http://localhost:5985/wsman")
|
|
end
|
|
end
|
|
end
|
|
|
|
describe ".endpoint_options" do
|
|
it "should create endpoint options" do
|
|
expect(subject.send(:endpoint_options)).to eq(
|
|
{ endpoint: "http://localhost:5985/wsman", operation_timeout: 1800,
|
|
user: "username", password: "password", host: "localhost", port: 5985,
|
|
basic_auth_only: false, no_ssl_peer_verification: false,
|
|
retry_delay: 1, retry_limit: 2, transport: :negotiate })
|
|
end
|
|
end
|
|
|
|
end
|