winrm 2.3.0 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/winrm/http/transport.rb +1 -1
- data/lib/winrm/psrp/message.rb +128 -128
- data/lib/winrm/shells/power_shell.rb +0 -1
- data/lib/winrm/version.rb +1 -1
- metadata +12 -85
- data/.gitignore +0 -10
- data/.rubocop.yml +0 -38
- data/.travis.yml +0 -10
- data/Gemfile +0 -2
- data/Rakefile +0 -33
- data/Vagrantfile +0 -6
- data/WinrmAppveyor.psm1 +0 -32
- data/appveyor.yml +0 -50
- data/changelog.md +0 -133
- data/preamble +0 -17
- data/tests/integration/auth_timeout_spec.rb +0 -17
- data/tests/integration/cmd_spec.rb +0 -130
- data/tests/integration/config-example.yml +0 -16
- data/tests/integration/issue_59_spec.rb +0 -25
- data/tests/integration/powershell_spec.rb +0 -164
- data/tests/integration/spec_helper.rb +0 -62
- data/tests/integration/transport_spec.rb +0 -98
- data/tests/integration/wql_spec.rb +0 -33
- data/tests/matchers.rb +0 -59
- data/tests/spec/configuration_spec.rb +0 -183
- data/tests/spec/connection_spec.rb +0 -37
- data/tests/spec/exception_spec.rb +0 -49
- data/tests/spec/http/transport_factory_spec.rb +0 -66
- data/tests/spec/http/transport_spec.rb +0 -43
- data/tests/spec/output_spec.rb +0 -128
- data/tests/spec/psrp/fragment_spec.rb +0 -60
- data/tests/spec/psrp/message_data/base_spec.rb +0 -11
- data/tests/spec/psrp/message_data/error_record_spec.rb +0 -39
- data/tests/spec/psrp/message_data/pipeline_host_call_spec.rb +0 -23
- data/tests/spec/psrp/message_data/pipeline_output_spec.rb +0 -30
- data/tests/spec/psrp/message_data/pipeline_state_spec.rb +0 -38
- data/tests/spec/psrp/message_data/runspace_pool_host_call_spec.rb +0 -23
- data/tests/spec/psrp/message_data/runspacepool_state_spec.rb +0 -14
- data/tests/spec/psrp/message_data/session_capability_spec.rb +0 -28
- data/tests/spec/psrp/message_data_spec.rb +0 -33
- data/tests/spec/psrp/message_defragmenter_spec.rb +0 -45
- data/tests/spec/psrp/message_fragmenter_spec.rb +0 -103
- data/tests/spec/psrp/powershell_output_decoder_spec.rb +0 -98
- data/tests/spec/psrp/psrp_message_spec.rb +0 -73
- data/tests/spec/psrp/recieve_response_reader_spec.rb +0 -170
- data/tests/spec/psrp/uuid_spec.rb +0 -28
- data/tests/spec/response_handler_spec.rb +0 -69
- data/tests/spec/shells/base_spec.rb +0 -227
- data/tests/spec/shells/cmd_spec.rb +0 -75
- data/tests/spec/shells/powershell_spec.rb +0 -221
- data/tests/spec/spec_helper.rb +0 -46
- data/tests/spec/stubs/clixml/error_record.xml.erb +0 -84
- data/tests/spec/stubs/clixml/pipeline_state.xml.erb +0 -88
- data/tests/spec/stubs/responses/get_command_output_response.xml.erb +0 -13
- data/tests/spec/stubs/responses/get_command_output_response_not_done.xml.erb +0 -10
- data/tests/spec/stubs/responses/get_omi_command_output_response.xml.erb +0 -23
- data/tests/spec/stubs/responses/get_omi_command_output_response_not_done.xml.erb +0 -24
- data/tests/spec/stubs/responses/get_omi_config_response.xml +0 -45
- data/tests/spec/stubs/responses/get_omi_powershell_keepalive_response.xml.erb +0 -33
- data/tests/spec/stubs/responses/get_powershell_keepalive_response.xml.erb +0 -10
- data/tests/spec/stubs/responses/get_powershell_output_response.xml.erb +0 -12
- data/tests/spec/stubs/responses/get_powershell_output_response_not_done.xml.erb +0 -9
- data/tests/spec/stubs/responses/open_shell_omi.xml +0 -43
- data/tests/spec/stubs/responses/open_shell_v1.xml +0 -19
- data/tests/spec/stubs/responses/open_shell_v2.xml +0 -20
- data/tests/spec/stubs/responses/soap_fault_omi.xml +0 -31
- data/tests/spec/stubs/responses/soap_fault_v1.xml +0 -36
- data/tests/spec/stubs/responses/soap_fault_v2.xml +0 -42
- data/tests/spec/stubs/responses/wmi_error_v2.xml +0 -41
- data/tests/spec/wsmv/cleanup_command_spec.rb +0 -20
- data/tests/spec/wsmv/close_shell_spec.rb +0 -15
- data/tests/spec/wsmv/command_output_decoder_spec.rb +0 -35
- data/tests/spec/wsmv/command_output_spec.rb +0 -43
- data/tests/spec/wsmv/command_spec.rb +0 -17
- data/tests/spec/wsmv/configuration_spec.rb +0 -15
- data/tests/spec/wsmv/create_pipeline_spec.rb +0 -30
- data/tests/spec/wsmv/create_shell_spec.rb +0 -39
- data/tests/spec/wsmv/init_runspace_pool_spec.rb +0 -38
- data/tests/spec/wsmv/keep_alive_spec.rb +0 -21
- data/tests/spec/wsmv/receive_response_reader_spec.rb +0 -124
- data/tests/spec/wsmv/send_data_spec.rb +0 -30
- data/tests/spec/wsmv/wql_query_spec.rb +0 -11
- data/tests/spec/wsmv/write_stdin_spec.rb +0 -20
- data/winrm.gemspec +0 -46
@@ -1,98 +0,0 @@
|
|
1
|
-
require 'winrm/psrp/powershell_output_decoder'
|
2
|
-
|
3
|
-
describe WinRM::PSRP::PowershellOutputDecoder do
|
4
|
-
let(:message_type) { WinRM::PSRP::Message::MESSAGE_TYPES[:error_record] }
|
5
|
-
let(:data) { 'blah' }
|
6
|
-
let(:message) do
|
7
|
-
WinRM::PSRP::Message.new(
|
8
|
-
'bc1bfbba-8215-4a04-b2df-7a3ac0310e16',
|
9
|
-
message_type,
|
10
|
-
data,
|
11
|
-
'4218a578-0f18-4b19-82c3-46b433319126'
|
12
|
-
)
|
13
|
-
end
|
14
|
-
|
15
|
-
subject { described_class.new.decode(message) }
|
16
|
-
|
17
|
-
context 'undecodable message type' do
|
18
|
-
let(:message_type) { WinRM::PSRP::Message::MESSAGE_TYPES[:public_key] }
|
19
|
-
|
20
|
-
it 'ignores message' do
|
21
|
-
expect(subject).to be nil
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
context 'undecodable method identifier' do
|
26
|
-
let(:message_type) { WinRM::PSRP::Message::MESSAGE_TYPES[:pipeline_host_call] }
|
27
|
-
let(:data) do
|
28
|
-
"\xEF\xBB\xBF<Obj RefId=\"0\"><MS><I64 N=\"ci\">-100</I64><Obj N=\"mi\" RefId=\"1\">"\
|
29
|
-
'<TN RefId="0"><T>System.Management.Automation.Remoting.RemoteHostMethodId</T>'\
|
30
|
-
'<T>System.Enum</T><T>System.ValueType</T><T>System.Object</T></TN>'\
|
31
|
-
'<ToString>WriteProgress</ToString><I32>17</I32></Obj><Obj N="mp" RefId="2">'\
|
32
|
-
'<TN RefId="1"><T>System.Collections.ArrayList</T><T>System.Object</T></TN><LST>'\
|
33
|
-
'<I32>7</I32><I32>0</I32><S>some_x000D__x000A_data</S></LST></Obj></MS></Obj>'
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'ignores message' do
|
37
|
-
expect(subject).to be nil
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
context 'receiving pipeline output' do
|
42
|
-
let(:message_type) { WinRM::PSRP::Message::MESSAGE_TYPES[:pipeline_output] }
|
43
|
-
let(:data) { '<obj><S>some data</S></obj>' }
|
44
|
-
|
45
|
-
it 'decodes output' do
|
46
|
-
expect(subject).to eq("some data\r\n")
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
context 'writeline with new line in middle' do
|
51
|
-
let(:message_type) { WinRM::PSRP::Message::MESSAGE_TYPES[:pipeline_host_call] }
|
52
|
-
let(:data) do
|
53
|
-
"\xEF\xBB\xBF<Obj RefId=\"0\"><MS><I64 N=\"ci\">-100</I64><Obj N=\"mi\" RefId=\"1\">"\
|
54
|
-
'<TN RefId="0"><T>System.Management.Automation.Remoting.RemoteHostMethodId</T>'\
|
55
|
-
'<T>System.Enum</T><T>System.ValueType</T><T>System.Object</T></TN>'\
|
56
|
-
'<ToString>WriteLine3</ToString><I32>17</I32></Obj><Obj N="mp" RefId="2">'\
|
57
|
-
'<TN RefId="1"><T>System.Collections.ArrayList</T><T>System.Object</T></TN><LST>'\
|
58
|
-
'<I32>7</I32><I32>0</I32><S>some_x000D__x000A_data</S></LST></Obj></MS></Obj>'
|
59
|
-
end
|
60
|
-
|
61
|
-
it 'decodes and replaces newline' do
|
62
|
-
expect(subject).to eq("some\r\ndata\r\n")
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
context 'receiving error record' do
|
67
|
-
let(:message_type) { WinRM::PSRP::Message::MESSAGE_TYPES[:error_record] }
|
68
|
-
let(:test_data_error_xml_template) do
|
69
|
-
ERB.new(stubbed_clixml('error_record.xml.erb'))
|
70
|
-
end
|
71
|
-
let(:error_message) { 'an error' }
|
72
|
-
let(:script_root) { 'script_root' }
|
73
|
-
let(:category_message) { 'category message' }
|
74
|
-
let(:stack_trace) { 'stack trace' }
|
75
|
-
let(:error_id) { 'Microsoft.PowerShell.Commands.WriteErrorException' }
|
76
|
-
let(:data) { test_data_error_xml_template.result(binding) }
|
77
|
-
|
78
|
-
it 'decodes error record' do
|
79
|
-
expect(subject).to match(/#{error_message}/)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
context 'receiving error record in pipeline state' do
|
84
|
-
let(:message_type) { WinRM::PSRP::Message::MESSAGE_TYPES[:pipeline_state] }
|
85
|
-
let(:test_data_error_xml_template) do
|
86
|
-
ERB.new(stubbed_clixml('pipeline_state.xml.erb'))
|
87
|
-
end
|
88
|
-
let(:pipeline_state) { WinRM::PSRP::MessageData::PipelineState::FAILED }
|
89
|
-
let(:error_message) { 'an error' }
|
90
|
-
let(:category_message) { 'category message' }
|
91
|
-
let(:error_id) { 'an error' }
|
92
|
-
let(:data) { test_data_error_xml_template.result(binding) }
|
93
|
-
|
94
|
-
it 'decodes error record' do
|
95
|
-
expect(subject).to match(/#{error_message}/)
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
@@ -1,73 +0,0 @@
|
|
1
|
-
require 'winrm/psrp/message'
|
2
|
-
|
3
|
-
describe WinRM::PSRP::Message do
|
4
|
-
context 'all fields provided' do
|
5
|
-
let(:payload) { 'this is my payload' }
|
6
|
-
subject do
|
7
|
-
described_class.new(
|
8
|
-
'bc1bfbba-8215-4a04-b2df-7a3ac0310e16',
|
9
|
-
WinRM::PSRP::Message::MESSAGE_TYPES[:pipeline_output],
|
10
|
-
payload,
|
11
|
-
'4218a578-0f18-4b19-82c3-46b433319126'
|
12
|
-
)
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'sets the destination to server LE' do
|
16
|
-
expect(subject.bytes[0..3]).to eq([2, 0, 0, 0])
|
17
|
-
end
|
18
|
-
it 'sets the message type LE' do
|
19
|
-
expect(subject.bytes[4..7]).to eq([4, 16, 4, 0])
|
20
|
-
end
|
21
|
-
it 'sets the runspace pool id' do
|
22
|
-
expect(subject.bytes[8..23]).to eq(
|
23
|
-
[186, 251, 27, 188, 21, 130, 4, 74, 178, 223, 122, 58, 192, 49, 14, 22]
|
24
|
-
)
|
25
|
-
end
|
26
|
-
it 'sets the pipeline id' do
|
27
|
-
expect(subject.bytes[24..39]).to eq(
|
28
|
-
[120, 165, 24, 66, 24, 15, 25, 75, 130, 195, 70, 180, 51, 49, 145, 38]
|
29
|
-
)
|
30
|
-
end
|
31
|
-
it 'prefixes the blob with BOM' do
|
32
|
-
expect(subject.bytes[40..42]).to eq([239, 187, 191])
|
33
|
-
end
|
34
|
-
it 'contains at least the first 8 bytes of the XML payload' do
|
35
|
-
expect(subject.bytes[43..-1]).to eq(payload.bytes)
|
36
|
-
end
|
37
|
-
it 'parses the data' do
|
38
|
-
expect(subject.parsed_data).to be_a(WinRM::PSRP::MessageData::PipelineOutput)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
context 'create' do
|
43
|
-
it 'raises error when message type is not valid' do
|
44
|
-
expect do
|
45
|
-
WinRM::PSRP::Message.new(
|
46
|
-
'bc1bfbba-8215-4a04-b2df-7a3ac0310e16',
|
47
|
-
0x00000000,
|
48
|
-
%(<Obj RefId="0"/>),
|
49
|
-
'4218a578-0f18-4b19-82c3-46b433319126'
|
50
|
-
)
|
51
|
-
end.to raise_error(RuntimeError)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
context 'no command id' do
|
56
|
-
subject(:msg) do
|
57
|
-
payload = <<-HERE.unindent
|
58
|
-
<Obj RefId="0"><MS><Version N="protocolversion">2.3</Version>
|
59
|
-
<Version N="PSVersion">2.0</Version><Version N="SerializationVersion">1.1.0.1</Version></MS>
|
60
|
-
</Obj>
|
61
|
-
HERE
|
62
|
-
WinRM::PSRP::Message.new(
|
63
|
-
'bc1bfbba-8215-4a04-b2df-7a3ac0310e16',
|
64
|
-
WinRM::PSRP::Message::MESSAGE_TYPES[:session_capability],
|
65
|
-
payload
|
66
|
-
)
|
67
|
-
end
|
68
|
-
|
69
|
-
it 'sets the pipeline id to empty' do
|
70
|
-
expect(msg.bytes[24..39]).to eq([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
@@ -1,170 +0,0 @@
|
|
1
|
-
require 'winrm/psrp/receive_response_reader'
|
2
|
-
|
3
|
-
describe WinRM::PSRP::ReceiveResponseReader do
|
4
|
-
let(:shell_id) { 'F4A2622B-B842-4EB8-8A78-0225C8A993DF' }
|
5
|
-
let(:command_id) { 'A2A2622B-B842-4EB8-8A78-0225C8A993DF' }
|
6
|
-
let(:output_message) { double('output_message', build: 'output_message') }
|
7
|
-
let(:test_data_xml_template) do
|
8
|
-
ERB.new(stubbed_response('get_powershell_output_response.xml.erb'))
|
9
|
-
end
|
10
|
-
let(:test_data_xml_template_not_done) do
|
11
|
-
ERB.new(stubbed_response('get_powershell_output_response_not_done.xml.erb'))
|
12
|
-
end
|
13
|
-
let(:test_data_text) { 'some data' }
|
14
|
-
let(:test_data) { "<obj><S>#{test_data_text}</S></obj>" }
|
15
|
-
let(:message) do
|
16
|
-
WinRM::PSRP::Message.new(
|
17
|
-
shell_id,
|
18
|
-
message_type,
|
19
|
-
test_data,
|
20
|
-
command_id
|
21
|
-
)
|
22
|
-
end
|
23
|
-
let(:fragment) { WinRM::PSRP::Fragment.new(1, message.bytes) }
|
24
|
-
let(:test_data_stdout) { Base64.strict_encode64(fragment.bytes.pack('C*')) }
|
25
|
-
let(:transport) { {} }
|
26
|
-
|
27
|
-
before do
|
28
|
-
allow(transport).to receive(:send_request).and_return(
|
29
|
-
REXML::Document.new(test_data_xml_template.result(binding))
|
30
|
-
)
|
31
|
-
end
|
32
|
-
|
33
|
-
subject do
|
34
|
-
described_class.new(
|
35
|
-
transport,
|
36
|
-
Logging.logger['test']
|
37
|
-
)
|
38
|
-
end
|
39
|
-
|
40
|
-
describe '#read_output' do
|
41
|
-
context 'response doc stdout with pipeline output' do
|
42
|
-
let(:message_type) { WinRM::PSRP::Message::MESSAGE_TYPES[:pipeline_output] }
|
43
|
-
|
44
|
-
it 'outputs to stdout' do
|
45
|
-
expect(
|
46
|
-
subject.read_output(output_message).stdout
|
47
|
-
).to eq("#{test_data_text}\r\n")
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
context 'response doc stdout error record' do
|
52
|
-
let(:message_type) { WinRM::PSRP::Message::MESSAGE_TYPES[:error_record] }
|
53
|
-
let(:test_data_error_xml_template) do
|
54
|
-
ERB.new(stubbed_clixml('error_record.xml.erb'))
|
55
|
-
end
|
56
|
-
let(:error_message) { 'an error' }
|
57
|
-
let(:script_root) { 'script_root' }
|
58
|
-
let(:category_message) { 'category message' }
|
59
|
-
let(:stack_trace) { 'stack trace' }
|
60
|
-
let(:error_id) { 'Microsoft.PowerShell.Commands.WriteErrorException' }
|
61
|
-
let(:test_data) { test_data_error_xml_template.result(binding) }
|
62
|
-
|
63
|
-
it 'outputs to stderr' do
|
64
|
-
expect(
|
65
|
-
subject.read_output(output_message).stderr
|
66
|
-
).to match(/#{error_message}/)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
context 'response doc failed pipeline state' do
|
71
|
-
let(:message_type) { WinRM::PSRP::Message::MESSAGE_TYPES[:pipeline_state] }
|
72
|
-
let(:test_data_error_xml_template) do
|
73
|
-
ERB.new(stubbed_clixml('pipeline_state.xml.erb'))
|
74
|
-
end
|
75
|
-
let(:pipeline_state) { WinRM::PSRP::MessageData::PipelineState::FAILED }
|
76
|
-
let(:error_message) { 'an error' }
|
77
|
-
let(:category_message) { 'category message' }
|
78
|
-
let(:error_id) { 'Microsoft.PowerShell.Commands.WriteErrorException' }
|
79
|
-
let(:test_data) { test_data_error_xml_template.result(binding) }
|
80
|
-
|
81
|
-
it 'outputs to stderr' do
|
82
|
-
expect(
|
83
|
-
subject.read_output(output_message).stderr
|
84
|
-
).to match(/#{error_message}/)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
context 'response doc writing error to host' do
|
89
|
-
let(:message_type) { WinRM::PSRP::Message::MESSAGE_TYPES[:pipeline_host_call] }
|
90
|
-
let(:test_data) do
|
91
|
-
"<Obj RefId='0'><MS><I64 N='ci'>-100</I64><Obj N='mi' RefId='1'><TN RefId='0'>" \
|
92
|
-
'<T>System.Management.Automation.Remoting.RemoteHostMethodId</T><T>System.Enum</T>' \
|
93
|
-
'<T>System.ValueType</T><T>System.Object</T></TN><ToString>WriteErrorLine</ToString>' \
|
94
|
-
"<I32>18</I32></Obj><Obj N='mp' RefId='2'><TN RefId='1'>" \
|
95
|
-
'<T>System.Collections.ArrayList</T><T>System.Object</T></TN><LST><S>errors</S></LST>' \
|
96
|
-
'</Obj></MS></Obj>'
|
97
|
-
end
|
98
|
-
|
99
|
-
it 'outputs to stderr' do
|
100
|
-
expect(
|
101
|
-
subject.read_output(output_message).stderr
|
102
|
-
).to eq("errors\r\n")
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
context 'response doc writing output to host' do
|
107
|
-
let(:message_type) { WinRM::PSRP::Message::MESSAGE_TYPES[:pipeline_host_call] }
|
108
|
-
let(:test_data) do
|
109
|
-
"<Obj RefId='0'><MS><I64 N='ci'>-100</I64><Obj N='mi' RefId='1'><TN RefId='0'>" \
|
110
|
-
'<T>System.Management.Automation.Remoting.RemoteHostMethodId</T><T>System.Enum</T>' \
|
111
|
-
'<T>System.ValueType</T><T>System.Object</T></TN><ToString>WriteLine</ToString>' \
|
112
|
-
"<I32>18</I32></Obj><Obj N='mp' RefId='2'><TN RefId='1'>" \
|
113
|
-
'<T>System.Collections.ArrayList</T><T>System.Object</T></TN><LST><S>output</S></LST>' \
|
114
|
-
'</Obj></MS></Obj>'
|
115
|
-
end
|
116
|
-
|
117
|
-
it 'outputs to stdout' do
|
118
|
-
expect(
|
119
|
-
subject.read_output(output_message).stdout
|
120
|
-
).to eq("output\r\n")
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
describe '#read_message' do
|
126
|
-
context 'do not wait for done state' do
|
127
|
-
let(:message_type) { WinRM::PSRP::Message::MESSAGE_TYPES[:pipeline_output] }
|
128
|
-
|
129
|
-
it 'outputs the message in an array' do
|
130
|
-
expect(subject.read_message(output_message).length).to eq(1)
|
131
|
-
expect(subject.read_message(output_message)[0].data).to end_with(message.data)
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
context 'read in a block' do
|
136
|
-
let(:message_type) { WinRM::PSRP::Message::MESSAGE_TYPES[:pipeline_output] }
|
137
|
-
|
138
|
-
it 'outputs the message in an array' do
|
139
|
-
subject.read_message(output_message) do |msg|
|
140
|
-
expect(msg.data).to end_with(message.data)
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
context 'wait for done state' do
|
146
|
-
let(:message_type) { WinRM::PSRP::Message::MESSAGE_TYPES[:pipeline_output] }
|
147
|
-
let(:test_data_xml_not_done) { test_data_xml_template_not_done.result(binding) }
|
148
|
-
let(:test_data_xml_done) { test_data_xml_template.result(binding) }
|
149
|
-
|
150
|
-
before do
|
151
|
-
allow(transport).to receive(:send_request).and_return(
|
152
|
-
REXML::Document.new(test_data_xml_not_done),
|
153
|
-
REXML::Document.new(test_data_xml_done)
|
154
|
-
)
|
155
|
-
end
|
156
|
-
|
157
|
-
it 'outputs two messages' do
|
158
|
-
expect(subject.read_message(output_message, true).length).to eq(2)
|
159
|
-
end
|
160
|
-
|
161
|
-
it 'outputs the first message' do
|
162
|
-
expect(subject.read_message(output_message, true)[0].data).to end_with(message.data)
|
163
|
-
end
|
164
|
-
|
165
|
-
it 'outputs the second message' do
|
166
|
-
expect(subject.read_message(output_message, true)[1].data).to end_with(message.data)
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
170
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
describe WinRM::PSRP::UUID do
|
2
|
-
subject(:uuid_helper) do
|
3
|
-
Object.new.extend(WinRM::PSRP::UUID)
|
4
|
-
end
|
5
|
-
context 'uuid is nil' do
|
6
|
-
uuid = nil
|
7
|
-
it 'should return an empty byte array' do
|
8
|
-
bytes = uuid_helper.uuid_to_windows_guid_bytes(uuid)
|
9
|
-
expect(bytes).to eq([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
|
10
|
-
end
|
11
|
-
end
|
12
|
-
context 'uuid 08785e96-eb1b-4a74-a767-7b56e8f13ea9 with lower case letters' do
|
13
|
-
uuid = '08785e96-eb1b-4a74-a767-7b56e8f13ea9'
|
14
|
-
it 'should return a Windows GUID struct compatible little endian byte array' do
|
15
|
-
bytes = uuid_helper.uuid_to_windows_guid_bytes(uuid)
|
16
|
-
expect(bytes).to eq([150, 94, 120, 8, 27, 235, 116, 74, 167, 103, 123, 86, 232, 241, 62, 169])
|
17
|
-
end
|
18
|
-
end
|
19
|
-
context 'uuid 045F9E19D-8B77-4394-AB0C-197497661668 with upper case letters' do
|
20
|
-
uuid = '45F9E19D-8B77-4394-AB0C-197497661668'
|
21
|
-
it 'should return a Windows GUID struct compatible little endian byte array' do
|
22
|
-
bytes = uuid_helper.uuid_to_windows_guid_bytes(uuid)
|
23
|
-
expect(bytes).to eq(
|
24
|
-
[157, 225, 249, 69, 119, 139, 148, 67, 171, 12, 25, 116, 151, 102, 22, 104]
|
25
|
-
)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
@@ -1,69 +0,0 @@
|
|
1
|
-
require 'winrm/http/response_handler'
|
2
|
-
|
3
|
-
describe 'response handler', unit: true do
|
4
|
-
%w[v1 v2 omi].each do |winrm_version|
|
5
|
-
context "winrm_version #{winrm_version}" do
|
6
|
-
let(:soap_fault) { stubbed_response("soap_fault_#{winrm_version}.xml") }
|
7
|
-
let(:open_shell) { stubbed_response("open_shell_#{winrm_version}.xml") }
|
8
|
-
|
9
|
-
describe "successful 200 #{winrm_version} response" do
|
10
|
-
it 'returns an xml doc' do
|
11
|
-
handler = WinRM::ResponseHandler.new(open_shell, 200)
|
12
|
-
xml_doc = handler.parse_to_xml
|
13
|
-
expect(xml_doc).to be_instance_of(REXML::Document)
|
14
|
-
expect(xml_doc.to_s).to eq(REXML::Document.new(open_shell).to_s)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
describe "failed 500 #{winrm_version} response" do
|
19
|
-
it 'raises a WinRMHTTPTransportError' do
|
20
|
-
handler = WinRM::ResponseHandler.new('', 500)
|
21
|
-
expect { handler.parse_to_xml }.to raise_error(WinRM::WinRMHTTPTransportError)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
describe "failed 401 #{winrm_version} response" do
|
26
|
-
it 'raises a WinRMAuthorizationError' do
|
27
|
-
handler = WinRM::ResponseHandler.new('', 401)
|
28
|
-
expect { handler.parse_to_xml }.to raise_error(WinRM::WinRMAuthorizationError)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
describe "failed 400 #{winrm_version} response" do
|
33
|
-
it 'raises a WinRMWSManFault' do
|
34
|
-
handler = WinRM::ResponseHandler.new(soap_fault, 400)
|
35
|
-
begin
|
36
|
-
handler.parse_to_xml
|
37
|
-
# PowerShell
|
38
|
-
rescue WinRM::WinRMWSManFault => e
|
39
|
-
expect(e.fault_code).to eq('2150858778')
|
40
|
-
expect(e.fault_description).to include(
|
41
|
-
'The specified class does not exist in the given namespace'
|
42
|
-
)
|
43
|
-
# OMI
|
44
|
-
rescue WinRM::WinRMSoapFault => e
|
45
|
-
expect(e.code).to eq('SOAP-ENV:Receiver')
|
46
|
-
expect(e.subcode).to eq('wsman:InternalError')
|
47
|
-
expect(e.reason).to eq(
|
48
|
-
'get-instance: instance name parameter is missing'
|
49
|
-
)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
describe 'failed 500 WMI error response' do
|
57
|
-
let(:wmi_error) { stubbed_response('wmi_error_v2.xml') }
|
58
|
-
|
59
|
-
it 'raises a WinRMWMIError' do
|
60
|
-
handler = WinRM::ResponseHandler.new(wmi_error, 500)
|
61
|
-
begin
|
62
|
-
handler.parse_to_xml
|
63
|
-
rescue WinRM::WinRMWMIError => e
|
64
|
-
expect(e.error_code).to eq('2150859173')
|
65
|
-
expect(e.error).to include('The WS-Management service cannot process the request.')
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
@@ -1,227 +0,0 @@
|
|
1
|
-
require 'winrm/shells/base'
|
2
|
-
|
3
|
-
# Dummy shell class
|
4
|
-
class DummyShell < WinRM::Shells::Base
|
5
|
-
class << self
|
6
|
-
def finalize(connection_opts, transport, shell_id)
|
7
|
-
proc { DummyShell.close_shell(connection_opts, transport, shell_id) }
|
8
|
-
end
|
9
|
-
|
10
|
-
def close_shell(_connection_opts, _transport, _shell_id)
|
11
|
-
@closed = true
|
12
|
-
end
|
13
|
-
|
14
|
-
def closed?
|
15
|
-
@closed
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def open_shell
|
20
|
-
@closed = false
|
21
|
-
'shell_id'
|
22
|
-
end
|
23
|
-
|
24
|
-
def send_command(_command, _arguments)
|
25
|
-
'command_id'
|
26
|
-
end
|
27
|
-
|
28
|
-
def out_streams
|
29
|
-
%w[std]
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
describe DummyShell do
|
34
|
-
let(:retry_limit) { 1 }
|
35
|
-
let(:shell_id) { 'shell_id' }
|
36
|
-
let(:output) { 'output' }
|
37
|
-
let(:command_id) { 'command_id' }
|
38
|
-
let(:payload) { 'message_payload' }
|
39
|
-
let(:command) { 'command' }
|
40
|
-
let(:arguments) { ['args'] }
|
41
|
-
let(:output_message) { double('output_message', build: 'output_message') }
|
42
|
-
let(:connection_options) { { max_commands: 100, retry_limit: retry_limit, retry_delay: 0 } }
|
43
|
-
let(:transport) { double('transport') }
|
44
|
-
let(:reader) { double('reader') }
|
45
|
-
|
46
|
-
before do
|
47
|
-
allow(subject).to receive(:response_reader).and_return(reader)
|
48
|
-
allow(subject).to receive(:command_output_message)
|
49
|
-
.with(shell_id, command_id)
|
50
|
-
.and_return(output_message)
|
51
|
-
allow(reader).to receive(:read_output).with(output_message).and_return(output)
|
52
|
-
allow(transport).to receive(:send_request)
|
53
|
-
end
|
54
|
-
|
55
|
-
subject { described_class.new(connection_options, transport, Logging.logger['test']) }
|
56
|
-
|
57
|
-
shared_examples 'retry shell command' do
|
58
|
-
it 'only closes the shell if there are too many' do
|
59
|
-
if fault == WinRM::Shells::Base::TOO_MANY_COMMANDS
|
60
|
-
expect(DummyShell).to receive(:close_shell)
|
61
|
-
else
|
62
|
-
expect(DummyShell).not_to receive(:close_shell)
|
63
|
-
end
|
64
|
-
|
65
|
-
subject.run(command, arguments)
|
66
|
-
end
|
67
|
-
|
68
|
-
it 'opens a new shell' do
|
69
|
-
expect(subject).to receive(:open).and_call_original.twice
|
70
|
-
|
71
|
-
subject.run(command, arguments)
|
72
|
-
end
|
73
|
-
|
74
|
-
it 'retries the command once' do
|
75
|
-
expect(subject).to receive(:send_command).twice
|
76
|
-
|
77
|
-
subject.run(command, arguments)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
describe '#run' do
|
82
|
-
it 'opens a shell' do
|
83
|
-
subject.run(command, arguments)
|
84
|
-
expect(subject.shell_id).not_to be nil
|
85
|
-
end
|
86
|
-
|
87
|
-
it 'returns output from generated command' do
|
88
|
-
expect(subject.run(command, arguments)).to eq output
|
89
|
-
end
|
90
|
-
|
91
|
-
it 'sends cleanup message through transport' do
|
92
|
-
allow(SecureRandom).to receive(:uuid).and_return('uuid')
|
93
|
-
expect(transport).to receive(:send_request)
|
94
|
-
.with(
|
95
|
-
WinRM::WSMV::CleanupCommand.new(
|
96
|
-
connection_options,
|
97
|
-
shell_uri: nil,
|
98
|
-
shell_id: shell_id,
|
99
|
-
command_id: command_id
|
100
|
-
).build
|
101
|
-
)
|
102
|
-
subject.run(command, arguments)
|
103
|
-
end
|
104
|
-
|
105
|
-
it 'does not error if cleanup is aborted' do
|
106
|
-
allow(SecureRandom).to receive(:uuid).and_return('uuid')
|
107
|
-
expect(transport).to receive(:send_request)
|
108
|
-
.with(
|
109
|
-
WinRM::WSMV::CleanupCommand.new(
|
110
|
-
connection_options,
|
111
|
-
shell_uri: nil,
|
112
|
-
shell_id: shell_id,
|
113
|
-
command_id: command_id
|
114
|
-
).build
|
115
|
-
).and_raise(WinRM::WinRMWSManFault.new('oops', '995'))
|
116
|
-
subject.run(command, arguments)
|
117
|
-
end
|
118
|
-
|
119
|
-
it 'does not error if shell is not present anymore' do
|
120
|
-
allow(SecureRandom).to receive(:uuid).and_return('uuid')
|
121
|
-
expect(transport).to receive(:send_request)
|
122
|
-
.with(
|
123
|
-
WinRM::WSMV::CleanupCommand.new(
|
124
|
-
connection_options,
|
125
|
-
shell_uri: nil,
|
126
|
-
shell_id: shell_id,
|
127
|
-
command_id: command_id
|
128
|
-
).build
|
129
|
-
).and_raise(WinRM::WinRMWSManFault.new('oops', '2150858843'))
|
130
|
-
subject.run(command, arguments)
|
131
|
-
end
|
132
|
-
|
133
|
-
it 'opens a shell only once when shell is already open' do
|
134
|
-
expect(subject).to receive(:open_shell).and_call_original.once
|
135
|
-
subject.run(command, arguments)
|
136
|
-
subject.run(command, arguments)
|
137
|
-
end
|
138
|
-
|
139
|
-
describe 'connection resets' do
|
140
|
-
before do
|
141
|
-
@times_called = 0
|
142
|
-
|
143
|
-
allow(subject).to receive(:send_command) do
|
144
|
-
@times_called += 1
|
145
|
-
raise WinRM::WinRMWSManFault.new('oops', fault) if @times_called == 1
|
146
|
-
|
147
|
-
command_id
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
context 'when shell is closed on server' do
|
152
|
-
let(:fault) { '2150858843' }
|
153
|
-
|
154
|
-
include_examples 'retry shell command'
|
155
|
-
end
|
156
|
-
|
157
|
-
context 'when shell accesses a deleted registry key' do
|
158
|
-
let(:fault) { '2147943418' }
|
159
|
-
|
160
|
-
include_examples 'retry shell command'
|
161
|
-
end
|
162
|
-
|
163
|
-
context 'when maximum number of concurrent shells is exceeded' do
|
164
|
-
let(:fault) { '2150859174' }
|
165
|
-
|
166
|
-
include_examples 'retry shell command'
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
context 'open_shell fails' do
|
171
|
-
let(:retry_limit) { 2 }
|
172
|
-
let(:output_message2) { double('message') }
|
173
|
-
|
174
|
-
it 'retries and raises failure if it never succeeds' do
|
175
|
-
expect(subject).to receive(:open_shell)
|
176
|
-
.and_raise(Errno::ECONNREFUSED).exactly(retry_limit).times
|
177
|
-
expect { subject.run(command) }.to raise_error(Errno::ECONNREFUSED)
|
178
|
-
end
|
179
|
-
|
180
|
-
it 'retries and returns shell on success' do
|
181
|
-
@times = 0
|
182
|
-
allow(subject).to receive(:command_output_message)
|
183
|
-
.with('shell_id 2', command_id)
|
184
|
-
.and_return(output_message2)
|
185
|
-
allow(reader).to receive(:read_output)
|
186
|
-
.with(output_message2).and_return(output)
|
187
|
-
allow(subject).to receive(:open_shell) do
|
188
|
-
@times += 1
|
189
|
-
raise(Errno::ECONNREFUSED) if @times == 1
|
190
|
-
|
191
|
-
"shell_id #{@times}"
|
192
|
-
end
|
193
|
-
|
194
|
-
subject.run(command, arguments)
|
195
|
-
expect(subject.shell_id).to eq 'shell_id 2'
|
196
|
-
end
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
describe '#close' do
|
201
|
-
it 'does not close if not opened' do
|
202
|
-
expect(DummyShell).not_to receive(:close_shell)
|
203
|
-
subject.close
|
204
|
-
end
|
205
|
-
|
206
|
-
it 'close shell if opened' do
|
207
|
-
subject.run(command, arguments)
|
208
|
-
subject.close
|
209
|
-
expect(DummyShell.closed?).to be(true)
|
210
|
-
end
|
211
|
-
|
212
|
-
it 'nils out the shell_id' do
|
213
|
-
subject.run(command, arguments)
|
214
|
-
subject.close
|
215
|
-
expect(subject.shell_id).to be(nil)
|
216
|
-
end
|
217
|
-
|
218
|
-
context 'when shell was not found' do
|
219
|
-
it 'does not raise' do
|
220
|
-
subject.run(command, arguments)
|
221
|
-
expect(DummyShell).to receive(:close_shell)
|
222
|
-
.and_raise(WinRM::WinRMWSManFault.new('oops', '2150858843'))
|
223
|
-
expect { subject.close }.not_to raise_error
|
224
|
-
end
|
225
|
-
end
|
226
|
-
end
|
227
|
-
end
|