cem_win_spec 0.1.2 → 0.1.4

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.
@@ -0,0 +1,196 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../logging'
4
+ require_relative 'output'
5
+
6
+ module CemWinSpec
7
+ module WinExec
8
+ # Class for executing PowerShell commands over WinRM
9
+ class Exec
10
+ include CemWinSpec::Logging
11
+
12
+ HALTING_ERRORS = [
13
+ IapTunnelStartError,
14
+ ].freeze
15
+
16
+ attr_reader :title, :result, :reuse_tunnel, :ignore_exitcode
17
+
18
+ def initialize(title: 'Command', l_cmd: nil, r_cmd: nil, iap_tunnel: nil, ma_builder: nil, r_test_cmds: nil, &block)
19
+ add_title(title)
20
+ add_local_cmd(l_cmd) unless l_cmd.nil?
21
+ add_remote_cmd(r_cmd) unless r_cmd.nil?
22
+ add_iap_tunnel(iap_tunnel) unless iap_tunnel.nil?
23
+ add_ma_builder(ma_builder) unless ma_builder.nil?
24
+ add_rspec_test_cmds(r_test_cmds) unless r_test_cmds.nil?
25
+ add_command_block(&block) unless block.nil?
26
+ @reuse_tunnel = true
27
+ @ignore_exitcode = false
28
+ @result = nil
29
+ end
30
+
31
+ def add_title(value)
32
+ raise ArgumentError, 'title must be a string' unless value.is_a?(String)
33
+
34
+ @title = value
35
+ end
36
+
37
+ def add_local_cmd(value)
38
+ raise ArgumentError, 'local_exec must implement the #run method' unless value.respond_to?(:run)
39
+
40
+ @local_cmd = value
41
+ end
42
+
43
+ def add_remote_cmd(value)
44
+ raise ArgumentError, 'winrm_exec must implement the #run method' unless value.respond_to?(:run)
45
+
46
+ @remote_cmd = value
47
+ end
48
+
49
+ def add_iap_tunnel(value)
50
+ unless value.respond_to?(:start) && value.respond_to?(:stop) && value.respond_to?(:with)
51
+ raise ArgumentError, 'iap_tunnel must implement the #start, #stop, and #with methods'
52
+ end
53
+
54
+ @iap_tunnel = value
55
+ end
56
+
57
+ def add_ma_builder(value)
58
+ raise ArgumentError, 'ma_builder must implement the #build method' unless value.respond_to?(:build)
59
+
60
+ @ma_builder = value
61
+ end
62
+
63
+ def add_rspec_test_cmds(value)
64
+ unless value.respond_to?(:cmd_standalone) && value.respond_to?(:cmd_parallel) &&
65
+ value.respond_to?(:prep_cmd) && value.respond_to?(:cleanup_cmd)
66
+ raise ArgumentError, 'rspec_test_cmds must implement the #cmd_standalone, #cmd_parallel, #prep_cmd, and #cleanup_cmd methods'
67
+ end
68
+
69
+ @rspec_test_cmds = value
70
+ end
71
+
72
+ def add_command_block(&block)
73
+ raise ArgumentError, 'block must be a Proc' unless block.is_a?(Proc)
74
+
75
+ @block = block
76
+ end
77
+
78
+ def reuse_tunnel=(value)
79
+ raise ArgumentError, 'reuse_tunnel must be a boolean' unless [true, false].include?(value)
80
+
81
+ @reuse_tunnel = value
82
+ end
83
+ alias reuse_tunnel? reuse_tunnel
84
+
85
+ def ignore_exitcode=(value)
86
+ raise ArgumentError, 'ignore_exitcode must be a boolean' unless [true, false].include?(value)
87
+
88
+ @ignore_exitcode = value
89
+ end
90
+ alias ignore_exitcode? ignore_exitcode
91
+
92
+ def success?
93
+ @result.success? if @result.is_a?(Output)
94
+
95
+ false
96
+ end
97
+
98
+ # Proxy method calls for methods that don't exist here to various other objects.
99
+ # This allows doing things like: `win_exec.remote_exec('Get-Process')` and
100
+ # calling the `exec` method on the `winrm_exec` object. This is done by
101
+ # checking method name prefixes and calling the corresponding method on the
102
+ # appropriate object. The prefix is removed from the method name before
103
+ # calling the method on the object. The supported prefixes are:
104
+ # local_ - calls the method on the @local_cmd object
105
+ # remote_ - calls the method on the @remote_cmd object
106
+ # rspec_ - calls the method on the @rspec_test_cmds object
107
+ # module_archive_ - calls the method on the @ma_builder object
108
+ def method_missing(method, *args, **kwargs, &block)
109
+ if method.to_s.start_with?('local_') # proxy to local_exec
110
+ method = method.to_s.sub('local_', '').to_sym
111
+ @local_cmd.send(method, *args, **kwargs, &block)
112
+ elsif method.to_s.start_with?('remote_') # proxy to remote_exec
113
+ method = method.to_s.sub('remote_', '').to_sym
114
+ @remote_cmd.send(method, *args, **kwargs, &block)
115
+ elsif method.to_s.start_with?('rspec_') # proxy to rspec_test_cmds
116
+ method = method.to_s.sub('rspec_', '').to_sym
117
+ @rspec_test_cmds.send(method, *args, **kwargs, &block)
118
+ elsif method.to_s.start_with?('module_archive_') # proxy to ma_builder
119
+ method = method.to_s.sub('module_archive_', '').to_sym
120
+ @ma_builder.send(method, *args, **kwargs, &block)
121
+ else
122
+ super
123
+ end
124
+ end
125
+
126
+ # Proxy respond_to? for methods that don't exist here to various other objects.
127
+ # This allows doing things like: `win_exec.respond_to?(:remote_exec)` and
128
+ # checking if the `exec` method exists on the `winrm_exec` object. This is done by
129
+ # checking method name prefixes and calling the corresponding method on the
130
+ # appropriate object. The prefix is removed from the method name before
131
+ # calling the method on the object. The supported prefixes are:
132
+ # local_ - calls the method on the @local_cmd object
133
+ # remote_ - calls the method on the @remote_cmd object
134
+ # rspec_ - calls the method on the @rspec_test_cmds object
135
+ # module_archive_ - calls the method on the @ma_builder object
136
+ def respond_to_missing?(method, include_private = false)
137
+ if method.to_s.start_with?('local_')
138
+ @local_cmd.respond_to?(method.to_s.sub('local_', '').to_sym, include_private)
139
+ elsif method.to_s.start_with?('remote_')
140
+ @remote_cmd.respond_to?(method.to_s.sub('remote_', '').to_sym, include_private)
141
+ elsif method.to_s.start_with?('rspec_')
142
+ @rspec_test_cmds.respond_to?(method.to_s.sub('rspec_', '').to_sym, include_private)
143
+ elsif method.to_s.start_with?('module_archive_')
144
+ @ma_builder.respond_to?(method.to_s.sub('module_archive_', '').to_sym, include_private)
145
+ else
146
+ super
147
+ end
148
+ end
149
+
150
+ def run(*args, **kwargs)
151
+ validate_instance_variables
152
+ logger.info "Running #{@title}"
153
+ result = run_with_tunnel { run_in_current_scope(*args, **kwargs) }
154
+ @result = Output.new(result)
155
+ return if @result.pending_threaded?
156
+
157
+ unless @result.success? || ignore_exitcode?
158
+ raise "Command failed with exit code #{@result.exitcode}: #{@result.stdout}\n#{@result.stderr}"
159
+ end
160
+ @result
161
+ rescue StandardError => e
162
+ raise if HALTING_ERRORS.include?(e.class)
163
+
164
+ logger.error "Error running #{@title}: #{e.message[0..100]}"
165
+ @result = Output.new(e)
166
+ @result
167
+ end
168
+
169
+ private
170
+
171
+ def run_with_tunnel(&block)
172
+ if reuse_tunnel?
173
+ @iap_tunnel.start # ensure tunnel is running
174
+ block.call
175
+ else
176
+ @iap_tunnel.stop # ensure tunnel is stopped
177
+ @iap_tunnel.with do # start tunnel for this block
178
+ block.call
179
+ end
180
+ end
181
+ end
182
+
183
+ def validate_instance_variables
184
+ %i[@title @local_cmd @remote_cmd @iap_tunnel @ma_builder @rspec_test_cmds @block].each do |var|
185
+ raise ArgumentError, "#{var} must be set" if instance_variable_get(var).nil?
186
+ end
187
+ end
188
+
189
+ # Runs the block in the current scope. This allows the block to access
190
+ # instance variables and methods from the current scope.
191
+ def run_in_current_scope(*args, **kwargs)
192
+ instance_exec(*args, **kwargs, &@block) # self is the "instance"
193
+ end
194
+ end
195
+ end
196
+ end
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+ require_relative '../logging'
5
+ require_relative 'connection_opts'
6
+ require_relative 'cmd/local_cmd'
7
+ require_relative 'cmd/winrm_cmd'
8
+
9
+ module CemWinSpec
10
+ module WinExec
11
+ # Factory class for creating a WinExec object
12
+ class Factory
13
+ include CemWinSpec::Logging
14
+
15
+ attr_reader :current_local_exec, :current_remote_cmd, :current_conn_opts
16
+
17
+ def initialize(iap_tunnel, ma_builder, rspec_test_cmds, **opts)
18
+ @iap_tunnel = iap_tunnel
19
+ @ma_builder = ma_builder
20
+ @rspec_test_cmds = rspec_test_cmds
21
+ @current_local_cmd = LocalCmd.new(**opts)
22
+ @current_remote_cmd = nil
23
+ @current_conn_opts = nil
24
+ @init_opts = opts
25
+ end
26
+
27
+ # Build a WinExec object
28
+ # @param title [String] Title of the WinExec object
29
+ # @param merge [Boolean] Merge the current connection options with the new options, if applicable
30
+ # @param host [String] Hostname or IP address of the remote host
31
+ # @param port [Integer] Port of the remote host
32
+ # @param user [String] Username for the remote host
33
+ # @param pass [String] Password for the remote host
34
+ # @param opts [Hash] Additional options for the WinRM connection
35
+ # @return [Exec] An Exec object
36
+ def build(title, merge: true, user: nil, pass: nil, working_dir: nil, **opts, &block)
37
+ logger.debug "Building Wexec object for #{title}"
38
+ build_conn_opts(merge: merge, user: user, pass: pass, **opts)
39
+ logger.debug 'Created ConnectionOpts'
40
+ wexec = Exec.new
41
+ wexec.add_title title
42
+ wexec.add_local_cmd @current_local_cmd
43
+ wexec.add_remote_cmd get_remote_cmd(working_dir, **@init_opts.merge(opts))
44
+ wexec.add_iap_tunnel @iap_tunnel
45
+ wexec.add_ma_builder @ma_builder
46
+ wexec.add_rspec_test_cmds @rspec_test_cmds
47
+ wexec.add_command_block(&block)
48
+ wexec.reuse_tunnel = opts[:reuse_tunnel] if opts.key?(:reuse_tunnel)
49
+ wexec.ignore_exitcode = opts[:ignore_exitcode] if opts.key?(:ignore_exitcode)
50
+ logger.debug 'Created Wexec'
51
+ wexec
52
+ end
53
+
54
+ def local_threaded_results
55
+ logger.info 'Checking for deferred results...'
56
+ @current_local_exec.join_threads
57
+ @current_local_exec.threaded_results.each do |cmd, results|
58
+ logger.info "Deferred results for #{cmd}:"
59
+ Output.new(results).puts_combined
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ def build_conn_opts(merge: true, user: nil, pass: nil, **opts)
66
+ if @current_conn_opts.nil?
67
+ logger.debug 'Creating new ConnectionOpts object'
68
+ @current_conn_opts = ConnectionOpts.new(new_host: 'localhost', new_port: @iap_tunnel.port, user: user, pass: pass, **opts)
69
+ return @current_conn_opts
70
+ end
71
+
72
+ if need_new_conn_opts?(new_host: 'localhost', new_port: @iap_tunnel.port, user: user, pass: pass, **opts)
73
+ if merge
74
+ logger.debug 'Merging ConnectionOpts with new options'
75
+ @current_conn_opts = @current_conn_opts.merge(new_host: 'localhost', new_port: @iap_tunnel.port, user: user, pass: pass, **opts)
76
+ else
77
+ logger.debug 'Creating new ConnectionOpts object with new options'
78
+ @current_conn_opts = ConnectionOpts.new(new_host: 'localhost', new_port: @iap_tunnel.port, user: user, pass: pass, **opts)
79
+ end
80
+ else
81
+ logger.debug 'Returning existing ConnectionOpts object'
82
+ end
83
+ @current_conn_opts
84
+ end
85
+
86
+ def need_new_conn_opts?(new_host: nil, new_port: nil, user: nil, pass: nil, **opts)
87
+ if new_host && new_host != @current_conn_opts.host
88
+ logger.debug "New host #{new_host} does not match current host #{@current_conn_opts.host}"
89
+ return true
90
+ end
91
+ if new_port && new_port != @current_conn_opts.port
92
+ logger.debug "New port #{new_port} does not match current port #{@current_conn_opts.port}"
93
+ return true
94
+ end
95
+ if user && user != @current_conn_opts.user
96
+ logger.debug "New user #{user} does not match current user #{@current_conn_opts.user}"
97
+ return true
98
+ end
99
+ if pass && Digest::SHA256.hexdigest(pass) != @current_conn_opts.pass
100
+ logger.debug 'New password does not match current password'
101
+ return true
102
+ end
103
+ if !opts.empty? && opts != @current_conn_opts.opts
104
+ logger.debug "New extra options #{opts} do not match current extra options #{@current_conn_opts.opts}"
105
+ return true
106
+ end
107
+
108
+ false
109
+ end
110
+
111
+ def get_remote_cmd(working_dir = nil, **opts)
112
+ if @current_winrm_cmd.nil? || @current_winrm_cmd.conn_opts.digest != @current_conn_opts.digest
113
+ logger.debug 'Creating new WinRMExec object'
114
+ @current_remote_cmd = WinRMCmd.new(@current_conn_opts, **opts)
115
+ end
116
+ logger.debug "Setting working directory to #{working_dir}" unless working_dir.nil?
117
+ @current_remote_cmd.working_dir = working_dir
118
+ logger.debug 'Returning WinRMExec object'
119
+ @current_remote_cmd
120
+ end
121
+ end
122
+ end
123
+ end
@@ -1,234 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'digest'
4
- require_relative 'iap_tunnel'
5
- require_relative 'logging'
6
- require_relative 'module_archive_builder'
7
- require_relative 'win_exec/connection_opts'
8
- require_relative 'win_exec/local_exec'
9
- require_relative 'win_exec/winrm_exec'
10
- require_relative 'win_exec/output'
11
-
12
3
  module CemWinSpec
13
4
  module WinExec
14
- # Class for executing PowerShell commands over WinRM
15
- class Exec
16
- include CemWinSpec::Logging
17
-
18
- attr_reader :title, :result, :reuse_tunnel, :ignore_exitcode
19
-
20
- def initialize(title, local_exec, winrm_exec, iap_tunnel, ma_builder, rspec_test_cmds, &block)
21
- @title = title
22
- @local_exec = local_exec
23
- @winrm_exec = winrm_exec
24
- @iap_tunnel = iap_tunnel
25
- @ma_builder = ma_builder
26
- @rspec_test_cmds = rspec_test_cmds
27
- @block = block
28
- @reuse_tunnel = true
29
- @ignore_exitcode = false
30
- @spinner = nil
31
- @result = nil
32
- end
33
-
34
- def reuse_tunnel=(value)
35
- raise ArgumentError, 'reuse_tunnel must be a boolean' unless [true, false].include?(value)
36
-
37
- @reuse_tunnel = value
38
- end
39
- alias reuse_tunnel? reuse_tunnel
40
-
41
- def ignore_exitcode=(value)
42
- raise ArgumentError, 'ignore_exitcode must be a boolean' unless [true, false].include?(value)
43
-
44
- @ignore_exitcode = value
45
- end
46
- alias ignore_exitcode? ignore_exitcode
47
-
48
- def success?
49
- @result.success? if @result.is_a?(Output)
50
-
51
- false
52
- end
53
-
54
- def spinner=(value)
55
- raise ArgumentError, 'spinner must implement #auto_spin and #stop methods' unless value.respond_to?(:auto_spin) && value.respond_to?(:stop)
56
-
57
- @spinner = value
58
- end
59
-
60
- # Proxy method calls for methods that don't exist here to various other objects.
61
- # This allows doing things like: `win_exec.remote_exec('Get-Process')` and
62
- # calling the `exec` method on the `winrm_exec` object. This is done by
63
- # checking method name prefixes and calling the corresponding method on the
64
- # appropriate object. The prefix is removed from the method name before
65
- # calling the method on the object. The supported prefixes are:
66
- # local_ - calls the method on the @local_exec object
67
- # remote_ - calls the method on the @winrm_exec object
68
- # rspec_ - calls the method on the @rspec_test_cmds object
69
- # module_archive_ - calls the method on the @ma_builder object
70
- def method_missing(method, *args, **kwargs, &block)
71
- if method.to_s.start_with?('local_') # proxy to local_exec
72
- method = method.to_s.sub('local_', '').to_sym
73
- @local_exec.send(method, *args, **kwargs, &block)
74
- elsif method.to_s.start_with?('remote_') # proxy to winrm_exec
75
- method = method.to_s.sub('remote_', '').to_sym
76
- @winrm_exec.send(method, *args, **kwargs, &block)
77
- elsif method.to_s.start_with?('rspec_') # proxy to rspec_test_cmds
78
- method = method.to_s.sub('rspec_', '').to_sym
79
- @rspec_test_cmds.send(method, *args, **kwargs, &block)
80
- elsif method.to_s.start_with?('module_archive_') # proxy to ma_builder
81
- method = method.to_s.sub('module_archive_', '').to_sym
82
- @ma_builder.send(method, *args, **kwargs, &block)
83
- else
84
- super
85
- end
86
- end
87
-
88
- # Proxy respond_to? for methods that don't exist here to various other objects.
89
- # This allows doing things like: `win_exec.respond_to?(:remote_exec)` and
90
- # checking if the `exec` method exists on the `winrm_exec` object. This is done by
91
- # checking method name prefixes and calling the corresponding method on the
92
- # appropriate object. The prefix is removed from the method name before
93
- # calling the method on the object. The supported prefixes are:
94
- # local_ - calls the method on the @local_exec object
95
- # remote_ - calls the method on the @winrm_exec object
96
- # rspec_ - calls the method on the @rspec_test_cmds object
97
- # module_archive_ - calls the method on the @ma_builder object
98
- def respond_to_missing?(method, include_private = false)
99
- if method.to_s.start_with?('local_')
100
- @local_exec.respond_to?(method.to_s.sub('local_', '').to_sym, include_private)
101
- elsif method.to_s.start_with?('remote_')
102
- @winrm_exec.respond_to?(method.to_s.sub('remote_', '').to_sym, include_private)
103
- elsif method.to_s.start_with?('rspec_')
104
- @rspec_test_cmds.respond_to?(method.to_s.sub('rspec_', '').to_sym, include_private)
105
- elsif method.to_s.start_with?('module_archive_')
106
- @ma_builder.respond_to?(method.to_s.sub('module_archive_', '').to_sym, include_private)
107
- else
108
- super
109
- end
110
- end
111
-
112
- def run(*args, **kwargs)
113
- logger.info "Running #{@title}"
114
- @spinner&.auto_spin
115
- result = if reuse_tunnel?
116
- @iap_tunnel.start # ensure tunnel is running
117
- run_in_current_scope(*args, **kwargs)
118
- else
119
- @iap_tunnel.stop # ensure tunnel is stopped
120
- @iap_tunnel.with do # start tunnel for this block
121
- run_in_current_scope(*args, **kwargs)
122
- end
123
- end
124
- @spinner&.stop
125
- @result = Output.new(result)
126
- return if @result.pending_threaded?
127
-
128
- @result.puts_combined
129
- unless @result.success? || ignore_exitcode?
130
- raise "Command failed with exit code #{@result.exitcode}: #{@result.stdout}\n#{@result.stderr}"
131
- end
132
- @result
133
- rescue StandardError => e
134
- logger.error "Error running #{@title}: #{e.message[0..100]}"
135
- @result = Output.new(e)
136
- @result
137
- end
138
-
139
- private
140
-
141
- def run_in_current_scope(*args, **kwargs)
142
- instance_exec(*args, **kwargs, &@block)
143
- end
144
-
145
- def wrap_spinner
146
- @spinner.auto_spin if @spinner
147
- yield if block_given?
148
- ensure
149
- @spinner.stop if @spinner
150
- end
151
- end
152
-
153
- # Factory class for creating a WinExec object
154
- class Factory
155
- include CemWinSpec::Logging
156
-
157
- attr_reader :current_local_exec, :current_winrm_exec, :current_conn_opts
158
-
159
- def initialize(iap_tunnel, ma_builder, rspec_test_cmds)
160
- @iap_tunnel = iap_tunnel
161
- @ma_builder = ma_builder
162
- @rspec_test_cmds = rspec_test_cmds
163
- @current_local_exec = LocalExec.new
164
- @current_winrm_exec = nil
165
- @current_conn_opts = nil
166
- end
167
-
168
- # Build a WinExec object
169
- # @param title [String] Title of the WinExec object
170
- # @param merge [Boolean] Merge the current connection options with the new options, if applicable
171
- # @param host [String] Hostname or IP address of the remote host
172
- # @param port [Integer] Port of the remote host
173
- # @param user [String] Username for the remote host
174
- # @param pass [String] Password for the remote host
175
- # @param opts [Hash] Additional options for the WinRM connection
176
- # @return [Exec] An Exec object
177
- def build(title, merge: true, user: nil, pass: nil, working_dir: nil, **opts, &block)
178
- logger.debug "Building Wexec object for #{title}"
179
- build_conn_opts(merge: merge, user: user, pass: pass, **opts)
180
- logger.debug 'Created ConnectionOpts'
181
- wexec = Exec.new(title, @current_local_exec, get_winrm_exec(working_dir), @iap_tunnel, @ma_builder, @rspec_test_cmds, &block)
182
- wexec.reuse_tunnel = opts[:reuse_tunnel] if opts.key?(:reuse_tunnel)
183
- wexec.ignore_exitcode = opts[:ignore_exitcode] if opts.key?(:ignore_exitcode)
184
- wexec.spinner = opts[:spinner] if opts.key?(:spinner)
185
- logger.debug 'Created Wexec'
186
- wexec
187
- end
188
-
189
- def local_threaded_results
190
- logger.info 'Checking for deferred results...'
191
- @current_local_exec.join_threads
192
- @current_local_exec.threaded_results.each do |cmd, results|
193
- logger.info "Deferred results for #{cmd}:"
194
- Output.new(results).puts_combined
195
- end
196
- end
197
-
198
- private
199
-
200
- def build_conn_opts(merge: true, user: nil, pass: nil, **opts)
201
- if @current_conn_opts.nil?
202
- logger.debug 'Creating new ConnectionOpts object'
203
- @current_conn_opts = ConnectionOpts.new(new_host: 'localhost', new_port: @iap_tunnel.port, user: user, pass: pass, **opts)
204
- return @current_conn_opts
205
- end
206
- opts_digest = Digest::SHA256.hexdigest(['localhost', @iap_tunnel.port, user, pass, opts].join(':'))
207
- if opts_digest != @current_conn_opts.digest
208
- if merge
209
- logger.debug 'Merging ConnectionOpts with new options'
210
- @current_conn_opts = @current_conn_opts.merge(new_host: 'localhost', new_port: @iap_tunnel.port, user: user, pass: pass, **opts)
211
- else
212
- logger.debug 'Creating new ConnectionOpts object with new options'
213
- @current_conn_opts = ConnectionOpts.new(new_host: 'localhost', new_port: @iap_tunnel.port, user: user, pass: pass, **opts)
214
- end
215
- else
216
- logger.debug 'Returning existing ConnectionOpts object'
217
- end
218
- @current_conn_opts
219
- end
220
-
221
-
222
- def get_winrm_exec(working_dir = nil)
223
- if @current_winrm_exec.nil? || @current_winrm_exec.conn_opts.digest != @current_conn_opts.digest
224
- logger.debug 'Creating new WinRMExec object'
225
- @current_winrm_exec = WinRMExec.new(@current_conn_opts)
226
- end
227
- logger.debug "Setting working directory to #{working_dir}" unless working_dir.nil?
228
- @current_winrm_exec.working_dir = working_dir
229
- logger.debug 'Returning WinRMExec object'
230
- @current_winrm_exec
231
- end
232
- end
5
+ require_relative 'win_exec/exec'
6
+ require_relative 'win_exec/factory'
233
7
  end
234
8
  end
data/lib/cem_win_spec.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'tty-spinner'
4
3
  require_relative 'cem_win_spec/logging'
5
4
  require_relative 'cem_win_spec/test_runner'
6
5
 
@@ -39,20 +38,19 @@ module CemWinSpec
39
38
  logger.debug "Created TestRunner: #{runner}"
40
39
  signal_handler(runner)
41
40
  logger.debug 'Set up signal handler'
42
- spinner = TTY::Spinner.new(format: :classic, interval: 1, hide_cursor: true, clear: true)
43
41
  begin
44
- sre_out = setup_remote_environment(runner, spinner)
42
+ sre_out = setup_remote_environment(runner)
45
43
  check_output!(sre_out, runner)
46
44
  module_dir = sre_out.stdout.chomp
47
45
  logger.debug "Module dir: #{module_dir}"
48
- srr_out = setup_remote_ruby(runner, module_dir, spinner)
46
+ srr_out = setup_remote_ruby(runner, module_dir, **options)
49
47
  check_output!(srr_out, runner)
50
48
  case operation
51
49
  when :spec
52
- spec_out = run_spec(runner, module_dir, spinner)
50
+ spec_out = run_spec(runner, module_dir, **options)
53
51
  check_output!(spec_out, runner)
54
52
  when :clean_fixture_cache
55
- clean_fixture_cache_out = clean_fixture_cache(runner, module_dir, spinner)
53
+ clean_fixture_cache_out = clean_fixture_cache(runner, module_dir, **options)
56
54
  check_output!(clean_fixture_cache_out, runner)
57
55
  else
58
56
  raise ArgumentError, "Unknown operation: #{operation}"
@@ -64,39 +62,38 @@ module CemWinSpec
64
62
  end
65
63
  end
66
64
 
67
- def self.setup_remote_environment(runner, spinner)
65
+ def self.setup_remote_environment(runner)
68
66
  runner.enable_long_paths.run
69
67
  runner.enable_symlinks.run
70
68
  runner.enable_symlinks.run
71
69
  working_dir_out = runner.create_working_dir.run
72
70
  working_dir = working_dir_out.stdout.chomp
73
71
  logger.debug "Working dir: #{working_dir}"
74
- runner.upload_module(working_dir: working_dir).run
72
+ runner.upload_module(operation_timeout: 300, receive_timeout: 310, working_dir: working_dir).run
75
73
  end
76
74
 
77
- def self.setup_remote_ruby(runner, module_dir, spinner)
75
+ def self.setup_remote_ruby(runner, module_dir, **opts)
78
76
  runner.setup_ruby(operation_timeout: 300,
79
77
  receive_timeout: 310,
80
78
  working_dir: module_dir,
81
79
  reuse_tunnel: false,
82
- spinner: spinner).run
80
+ **opts).run
83
81
  end
84
82
 
85
83
  # Runs RSpec tests
86
- def self.run_spec(runner, module_dir, spinner)
87
- #runner.rspec_prep(working_dir: module_dir, reuse_tunnel: false, spinner: spinner).run
84
+ def self.run_spec(runner, module_dir, **opts)
88
85
  runner.rspec_tests_parallel(operation_timeout: 300,
89
86
  receive_timeout: 310,
90
87
  working_dir: module_dir,
91
88
  ignore_exitcode: true,
92
89
  reuse_tunnel: false,
93
- spinner: spinner).run
90
+ **opts).run
94
91
  end
95
92
 
96
93
  # Clean the remote fixture cache
97
94
  # @param options [Hash] Options for the test runner
98
- def self.clean_fixture_cache(runner, module_dir, spinner)
99
- runner.clean_fixture_cache(working_dir: module_dir, spinner: spinner).run
95
+ def self.clean_fixture_cache(runner, module_dir, **opts)
96
+ runner.clean_fixture_cache(working_dir: module_dir, **opts).run
100
97
  end
101
98
 
102
99
  def self.check_output!(output, runner = nil)