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.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/lib/winrm/http/transport.rb +1 -1
  3. data/lib/winrm/psrp/message.rb +128 -128
  4. data/lib/winrm/shells/power_shell.rb +0 -1
  5. data/lib/winrm/version.rb +1 -1
  6. metadata +12 -85
  7. data/.gitignore +0 -10
  8. data/.rubocop.yml +0 -38
  9. data/.travis.yml +0 -10
  10. data/Gemfile +0 -2
  11. data/Rakefile +0 -33
  12. data/Vagrantfile +0 -6
  13. data/WinrmAppveyor.psm1 +0 -32
  14. data/appveyor.yml +0 -50
  15. data/changelog.md +0 -133
  16. data/preamble +0 -17
  17. data/tests/integration/auth_timeout_spec.rb +0 -17
  18. data/tests/integration/cmd_spec.rb +0 -130
  19. data/tests/integration/config-example.yml +0 -16
  20. data/tests/integration/issue_59_spec.rb +0 -25
  21. data/tests/integration/powershell_spec.rb +0 -164
  22. data/tests/integration/spec_helper.rb +0 -62
  23. data/tests/integration/transport_spec.rb +0 -98
  24. data/tests/integration/wql_spec.rb +0 -33
  25. data/tests/matchers.rb +0 -59
  26. data/tests/spec/configuration_spec.rb +0 -183
  27. data/tests/spec/connection_spec.rb +0 -37
  28. data/tests/spec/exception_spec.rb +0 -49
  29. data/tests/spec/http/transport_factory_spec.rb +0 -66
  30. data/tests/spec/http/transport_spec.rb +0 -43
  31. data/tests/spec/output_spec.rb +0 -128
  32. data/tests/spec/psrp/fragment_spec.rb +0 -60
  33. data/tests/spec/psrp/message_data/base_spec.rb +0 -11
  34. data/tests/spec/psrp/message_data/error_record_spec.rb +0 -39
  35. data/tests/spec/psrp/message_data/pipeline_host_call_spec.rb +0 -23
  36. data/tests/spec/psrp/message_data/pipeline_output_spec.rb +0 -30
  37. data/tests/spec/psrp/message_data/pipeline_state_spec.rb +0 -38
  38. data/tests/spec/psrp/message_data/runspace_pool_host_call_spec.rb +0 -23
  39. data/tests/spec/psrp/message_data/runspacepool_state_spec.rb +0 -14
  40. data/tests/spec/psrp/message_data/session_capability_spec.rb +0 -28
  41. data/tests/spec/psrp/message_data_spec.rb +0 -33
  42. data/tests/spec/psrp/message_defragmenter_spec.rb +0 -45
  43. data/tests/spec/psrp/message_fragmenter_spec.rb +0 -103
  44. data/tests/spec/psrp/powershell_output_decoder_spec.rb +0 -98
  45. data/tests/spec/psrp/psrp_message_spec.rb +0 -73
  46. data/tests/spec/psrp/recieve_response_reader_spec.rb +0 -170
  47. data/tests/spec/psrp/uuid_spec.rb +0 -28
  48. data/tests/spec/response_handler_spec.rb +0 -69
  49. data/tests/spec/shells/base_spec.rb +0 -227
  50. data/tests/spec/shells/cmd_spec.rb +0 -75
  51. data/tests/spec/shells/powershell_spec.rb +0 -221
  52. data/tests/spec/spec_helper.rb +0 -46
  53. data/tests/spec/stubs/clixml/error_record.xml.erb +0 -84
  54. data/tests/spec/stubs/clixml/pipeline_state.xml.erb +0 -88
  55. data/tests/spec/stubs/responses/get_command_output_response.xml.erb +0 -13
  56. data/tests/spec/stubs/responses/get_command_output_response_not_done.xml.erb +0 -10
  57. data/tests/spec/stubs/responses/get_omi_command_output_response.xml.erb +0 -23
  58. data/tests/spec/stubs/responses/get_omi_command_output_response_not_done.xml.erb +0 -24
  59. data/tests/spec/stubs/responses/get_omi_config_response.xml +0 -45
  60. data/tests/spec/stubs/responses/get_omi_powershell_keepalive_response.xml.erb +0 -33
  61. data/tests/spec/stubs/responses/get_powershell_keepalive_response.xml.erb +0 -10
  62. data/tests/spec/stubs/responses/get_powershell_output_response.xml.erb +0 -12
  63. data/tests/spec/stubs/responses/get_powershell_output_response_not_done.xml.erb +0 -9
  64. data/tests/spec/stubs/responses/open_shell_omi.xml +0 -43
  65. data/tests/spec/stubs/responses/open_shell_v1.xml +0 -19
  66. data/tests/spec/stubs/responses/open_shell_v2.xml +0 -20
  67. data/tests/spec/stubs/responses/soap_fault_omi.xml +0 -31
  68. data/tests/spec/stubs/responses/soap_fault_v1.xml +0 -36
  69. data/tests/spec/stubs/responses/soap_fault_v2.xml +0 -42
  70. data/tests/spec/stubs/responses/wmi_error_v2.xml +0 -41
  71. data/tests/spec/wsmv/cleanup_command_spec.rb +0 -20
  72. data/tests/spec/wsmv/close_shell_spec.rb +0 -15
  73. data/tests/spec/wsmv/command_output_decoder_spec.rb +0 -35
  74. data/tests/spec/wsmv/command_output_spec.rb +0 -43
  75. data/tests/spec/wsmv/command_spec.rb +0 -17
  76. data/tests/spec/wsmv/configuration_spec.rb +0 -15
  77. data/tests/spec/wsmv/create_pipeline_spec.rb +0 -30
  78. data/tests/spec/wsmv/create_shell_spec.rb +0 -39
  79. data/tests/spec/wsmv/init_runspace_pool_spec.rb +0 -38
  80. data/tests/spec/wsmv/keep_alive_spec.rb +0 -21
  81. data/tests/spec/wsmv/receive_response_reader_spec.rb +0 -124
  82. data/tests/spec/wsmv/send_data_spec.rb +0 -30
  83. data/tests/spec/wsmv/wql_query_spec.rb +0 -11
  84. data/tests/spec/wsmv/write_stdin_spec.rb +0 -20
  85. 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