cem_win_spec 0.1.2 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b8fcf2f514c6b40b1c2df94ceb0c7fd4c53c6470b5cd603281dac2303b014bdd
4
- data.tar.gz: 459a0859428ec4c326b570b7e436ed17b4637d6ae326fe991b8de1ff08ba50f4
3
+ metadata.gz: b8483cd4acfa3729cf4bd453fe3ef09a67c71ddd3dcee46f5dc3986e755ddf07
4
+ data.tar.gz: a4ef098f7125bf68579dd1b5902d5cb553ccfcbef355d8bd0e4f1d8900eae395
5
5
  SHA512:
6
- metadata.gz: 0d0e040d58de283421fed1ed9fb22d15c6f19b72f89d9fcd31cffadea277e352f4ae8e0d2c46a7b57c39756c71a2fcd9100a889344934280559ad90c65e5d908
7
- data.tar.gz: 8655104a3e2415b478bd9ded995dcdcc6043b0e3b46fc177bcc42e78bfeff872dd89b538ded90c055cfd72574c997eb5f9839cbdca1c89a186c9cb0b7eb8c5ab
6
+ metadata.gz: 8a1a521b044cc4c14a26efd6b8936f662dc1d2b173918337e49b591fe1178f6357aff317cd7dab4ae167688eea2304b75dc89fde8273bb8e7dcc3d22b8df8d33
7
+ data.tar.gz: a31a1631d32ca72d34f276920de7a9f22f34175afac7306e64f7158ec309cc66ce0e80aab6b3ac430627f170291b9e442fd7516a7231b242c059a39836f5e3e1
data/Gemfile.lock CHANGED
@@ -1,10 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cem_win_spec (0.1.2)
4
+ cem_win_spec (0.1.4)
5
5
  parallel_tests (~> 3.4)
6
6
  puppet_forge (~> 4.1)
7
- tty-spinner (~> 0.9)
8
7
  winrm (~> 2.3)
9
8
  winrm-fs (~> 1.3)
10
9
 
@@ -15,21 +14,22 @@ GEM
15
14
  builder (3.2.4)
16
15
  coderay (1.1.3)
17
16
  diff-lcs (1.5.0)
18
- erubi (1.10.0)
19
- faraday (2.3.0)
20
- faraday-net_http (~> 2.0)
17
+ erubi (1.12.0)
18
+ faraday (2.7.5)
19
+ faraday-net_http (>= 2.0, < 3.1)
21
20
  ruby2_keywords (>= 0.0.4)
22
21
  faraday-follow_redirects (0.3.0)
23
22
  faraday (>= 1, < 3)
24
- faraday-net_http (2.0.3)
23
+ faraday-net_http (3.0.2)
25
24
  ffi (1.15.5)
26
25
  gssapi (1.3.1)
27
26
  ffi (>= 1.0.1)
28
- gyoku (1.3.1)
27
+ gyoku (1.4.0)
29
28
  builder (>= 2.1.2)
29
+ rexml (~> 3.0)
30
30
  httpclient (2.8.3)
31
31
  little-plugger (1.1.4)
32
- logging (2.3.0)
32
+ logging (2.3.1)
33
33
  little-plugger (~> 1.1)
34
34
  multi_json (~> 1.14)
35
35
  method_source (1.0.0)
@@ -81,10 +81,7 @@ GEM
81
81
  ruby2_keywords (0.0.5)
82
82
  rubyntlm (0.6.3)
83
83
  rubyzip (2.3.2)
84
- semantic_puppet (1.0.4)
85
- tty-cursor (0.7.1)
86
- tty-spinner (0.9.3)
87
- tty-cursor (~> 0.7)
84
+ semantic_puppet (1.1.0)
88
85
  unicode-display_width (2.1.0)
89
86
  winrm (2.3.6)
90
87
  builder (>= 2.1.2)
@@ -102,7 +99,9 @@ GEM
102
99
  winrm (~> 2.0)
103
100
 
104
101
  PLATFORMS
102
+ arm64-darwin-22
105
103
  x86_64-darwin-19
104
+ x86_64-darwin-20
106
105
 
107
106
  DEPENDENCIES
108
107
  cem_win_spec!
data/cem_win_spec.gemspec CHANGED
@@ -30,7 +30,6 @@ Gem::Specification.new do |spec|
30
30
 
31
31
  spec.add_dependency "winrm", "~> 2.3"
32
32
  spec.add_dependency "winrm-fs", "~> 1.3"
33
- spec.add_dependency "tty-spinner", "~> 0.9"
34
33
  spec.add_dependency "puppet_forge", "~> 4.1"
35
34
  spec.add_dependency "parallel_tests", "~> 3.4"
36
35
  spec.add_development_dependency "pry"
data/exe/cem-win-spec CHANGED
@@ -19,6 +19,26 @@ parser = OptionParser.new do |opts|
19
19
  exit 0
20
20
  end
21
21
 
22
+ opts.on('-p', '--puppet-version [VERSION]', 'Puppet version to test against') do |version|
23
+ unless %w[7 8].include?(version)
24
+ warn "Unknown Puppet version: #{version}"
25
+ warn 'Valid versions are: 7, 8'
26
+ puts opts
27
+ exit 1
28
+ end
29
+ options[:puppet_version] = version
30
+ end
31
+
32
+ opts.on('-r', '--ruby-version [VERSION]', 'Ruby version to test against') do |version|
33
+ unless %w[2 3].include?(version)
34
+ warn "Unknown Ruby version: #{version}"
35
+ warn 'Valid versions are: 2, 3'
36
+ puts opts
37
+ exit 1
38
+ end
39
+ options[:ruby_version] = version
40
+ end
41
+
22
42
  opts.on('-o', '--operation [OPERATION]', 'Operation to perform (spec, clean_fixture_cache)') do |operation|
23
43
  unless %w[spec clean_fixture_cache].include?(operation)
24
44
  warn "Unknown operation: #{operation}"
@@ -4,6 +4,8 @@ require 'io/console'
4
4
  require_relative 'logging'
5
5
 
6
6
  module CemWinSpec
7
+ class IapTunnelStartError < StandardError; end
8
+
7
9
  # This class is used to create a tunnel to a GCP instance
8
10
  class IapTunnel
9
11
  include CemWinSpec::Logging
@@ -23,7 +25,9 @@ module CemWinSpec
23
25
  end
24
26
 
25
27
  def running?
26
- !@pid.nil?
28
+ !@pid.nil? && Process.getpgid(@pid)
29
+ rescue Errno::ESRCH
30
+ false
27
31
  end
28
32
 
29
33
  def with
@@ -41,7 +45,12 @@ module CemWinSpec
41
45
  logger.info 'Starting IAP tunnel...'
42
46
  logger.debug "Running command: #{tunnel_cmd}"
43
47
  @pid = spawn(tunnel_cmd)
44
- sleep(5)
48
+ sleep(3) # Give the tunnel a few seconds to start
49
+ Process.getpgid(@pid) # Check if the process starts successfully
50
+ logger.info "IAP tunnel started on port #{port}"
51
+ rescue Errno::ESRCH
52
+ @pid = nil
53
+ raise IapTunnelStartError, "Failed to start IAP tunnel on port #{port}: #{$ERROR_INFO}"
45
54
  end
46
55
 
47
56
  # This method stops the IAP tunnel
@@ -6,24 +6,25 @@ module CemWinSpec
6
6
  class RspecTestCmds
7
7
  DEFAULT_PATTERN = 'spec/{classes,defines}/**/*_spec.rb'
8
8
 
9
- def initialize(pattern: DEFAULT_PATTERN)
9
+ def initialize(use_bundler: true, pattern: DEFAULT_PATTERN)
10
+ @use_bundler = use_bundler
10
11
  @pattern = pattern
11
12
  end
12
13
 
13
14
  def cmd_standalone(*args)
14
- "bundle exec rake 'cem:spec_standalone#{rake_args(nil, *args)}'"
15
+ prefix "rake 'cem:spec_standalone#{rake_args(nil, *args)}'"
15
16
  end
16
17
 
17
18
  def cmd_parallel(*args)
18
- "bundle exec rake 'cem:parallel_spec_standalone#{rake_args(*args)}'"
19
+ prefix "rake 'cem:parallel_spec_standalone#{rake_args(*args)}'"
19
20
  end
20
21
 
21
22
  def cmd_chunked(*files)
22
- "bundle exec rake 'cem:parallel_spec_files#{rake_args(files.join(' '))}'"
23
+ prefix "rake 'cem:parallel_spec_files#{rake_args(files.join(' '))}'"
23
24
  end
24
25
 
25
26
  def prep_cmd
26
- 'bundle exec rake cem:win_spec_prep'
27
+ prefix 'rake cem:win_spec_prep'
27
28
  end
28
29
 
29
30
  def cmds(*args)
@@ -31,7 +32,7 @@ module CemWinSpec
31
32
  end
32
33
 
33
34
  def cleanup_cmd
34
- 'bundle exec rake cem:win_spec_clean'
35
+ prefix 'rake cem:win_spec_clean'
35
36
  end
36
37
 
37
38
  def spec_files
@@ -40,12 +41,16 @@ module CemWinSpec
40
41
 
41
42
  private
42
43
 
44
+ def prefix(cmd)
45
+ @use_bundler ? "bundle exec #{cmd}" : cmd
46
+ end
47
+
43
48
  def rake_args(*args)
44
49
  args.empty? ? '' : "[#{args.join(',')}]"
45
50
  end
46
51
 
47
52
  def rspec_cmd(file, *args)
48
- "bundle exec rake 'cem:spec_standalone#{rake_args(file, *args)}'"
53
+ prefix "rake 'cem:spec_standalone#{rake_args(file, *args)}'"
49
54
  end
50
55
  end
51
56
  end
@@ -38,13 +38,13 @@ module CemWinSpec
38
38
 
39
39
  def enable_long_paths(**opts)
40
40
  new_command('Enable long paths', **opts) do
41
- remote_exec('Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1')
41
+ remote_run('Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1')
42
42
  end
43
43
  end
44
44
 
45
45
  def enable_symlinks(**opts)
46
46
  @enable_symlinks ||= new_command('Enable symlinks', **opts) do
47
- remote_exec('fsutil behavior set SymlinkEvaluation L2L:1 R2R:1 L2R:1 R2L:1')
47
+ remote_run('fsutil behavior set SymlinkEvaluation L2L:1 R2R:1 L2R:1 R2L:1')
48
48
  end
49
49
  end
50
50
 
@@ -68,7 +68,7 @@ module CemWinSpec
68
68
  module_archive_build { |a| remote_upload(a, remote_working_dir) }
69
69
  module_dir = "#{remote_working_dir}\\#{File.basename(module_archive_path, '.tar.gz')}"
70
70
  logger.debug "Module uploaded to #{module_dir}.tar.gz, extracting..."
71
- remote_exec("tar -xzf #{module_dir}.tar.gz -C #{remote_working_dir}")
71
+ remote_run("tar -xzf #{module_dir}.tar.gz -C #{remote_working_dir}")
72
72
  logger.debug "Module extracted to #{module_dir}"
73
73
  module_dir
74
74
  end
@@ -76,33 +76,38 @@ module CemWinSpec
76
76
 
77
77
  def setup_ruby(**opts)
78
78
  @setup_ruby ||= new_command('Set up ruby', **opts) do
79
- remote_exec('bundle config disable_platform_warnings true')
80
- remote_exec('bundle install')
79
+ remote_run(
80
+ [
81
+ 'bundle config disable_platform_warnings true',
82
+ 'bundle config set --local without \'local_development\'',
83
+ 'bundle install',
84
+ ],
85
+ )
81
86
  end
82
87
  end
83
88
 
84
89
  def rspec_prep(**opts)
85
90
  @rspec_prep ||= new_command('Prepare rspec tests', **opts) do
86
- remote_exec('bundle exec rake cem_win_spec:prep --trace')
91
+ remote_run('bundle exec rake cem_win_spec:prep --trace')
87
92
  end
88
93
  end
89
94
 
90
95
  def rspec_tests(**opts)
91
96
  @rspec_tests ||= new_command('Run rspec tests', **opts) do
92
- remote_exec(rspec_cmd_standalone('false', 'progress', 'true'))
97
+ remote_run(rspec_cmd_standalone('false', 'progress', 'true'))
93
98
  end
94
99
  end
95
100
 
96
101
  def rspec_tests_parallel(**opts)
97
102
  @rspec_tests_parallel ||= new_command('Run rspec tests in parallel', **opts) do
98
- remote_exec('bundle exec rake cem_win_spec:parallel_spec')
103
+ remote_run('bundle exec rake cem_win_spec:parallel_spec')
99
104
  end
100
105
  end
101
106
 
102
107
  def clean_up
103
108
  @clean_up ||= new_command('Cleanup') do |working_dir|
104
109
  if remote_available?
105
- remote_exec(cleanup_cmd, quiet: true)
110
+ remote_run(cleanup_cmd, quiet: true)
106
111
  else
107
112
  logger.warn 'Cleanup not available'
108
113
  end
@@ -111,7 +116,7 @@ module CemWinSpec
111
116
 
112
117
  def clean_fixture_cache(**opts)
113
118
  @clean_cache ||= new_command('Clean fixture cache', **opts) do
114
- remote_exec('bundle exec rake cem_win_spec:clean_fixture_cache')
119
+ remote_run('bundle exec rake cem_win_spec:clean_fixture_cache')
115
120
  end
116
121
  end
117
122
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CemWinSpec
4
- VERSION = "0.1.2"
4
+ VERSION = "0.1.4"
5
5
  end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../logging'
4
+
5
+ module CemWinSpec
6
+ module WinExec
7
+ class BaseCmd
8
+ include CemWinSpec::Logging
9
+
10
+ COMMAND_SEPARATOR = '; '
11
+ PUPPET_VER_TO_RUBY_VER = {
12
+ '7' => '278',
13
+ '8' => '322',
14
+ }.freeze
15
+
16
+ attr_accessor :working_dir, :env_vars, :puppet_version
17
+
18
+ def initialize(working_dir = nil, puppet_version: nil, **env_vars)
19
+ @working_dir = working_dir
20
+ self.puppet_version = puppet_version
21
+ self.env_vars = env_vars
22
+ end
23
+
24
+ # Sets the puppet version that will be used to execute the command
25
+ # @param value [String, nil] the puppet version
26
+ def puppet_version=(value)
27
+ if value.nil?
28
+ @puppet_version = nil
29
+ return
30
+ end
31
+
32
+ ver = value.to_s
33
+ raise ArgumentError, 'puppet_version only supports major versions 7 and 8' unless ver.match?(/^(7|8).*/)
34
+ unless ver.match?(/^(7|8)(\.\d+)?\.\d+$/)
35
+ ver = "#{ver}.0"
36
+ end
37
+
38
+ @puppet_version = ver
39
+ end
40
+
41
+ # Sets the environment variables that will be used to execute the command
42
+ # @param value [Hash] the environment variables
43
+ def env_vars=(value)
44
+ raise ArgumentError, 'env_vars must be a hash' unless value.is_a?(Hash)
45
+
46
+ value['PUPPET_GEM_VERSION'] = "~> #{puppet_version}" if puppet_version
47
+ value['FACTER_GEM_VERSION'] = 'https://github.com/puppetlabs/facter#main' if puppet_version
48
+ @env_vars = value
49
+ end
50
+
51
+ def available?
52
+ raise NotImplementedError
53
+ end
54
+
55
+ def run(cmd, *_args, **_kwargs)
56
+ raise NotImplementedError
57
+ end
58
+
59
+ # Returns the ruby version that will be used to execute the command
60
+ # The ruby version is determined by the puppet version that is set
61
+ # @return [String, nil] the ruby version or nil if the puppet version is not set
62
+ def ruby_version
63
+ return nil unless puppet_version
64
+
65
+ PUPPET_VER_TO_RUBY_VER[puppet_version.split('.')[0]]
66
+ end
67
+
68
+ def command(cmd)
69
+ cmd = [cmd]
70
+ cmd.unshift(change_ruby_version_cmd) if ruby_version # executes third
71
+ env_vars.each { |k, v| cmd.unshift(set_env_var_cmd(k, v)) } if env_vars.any? # executes second
72
+ cmd.unshift(change_working_dir_cmd(working_dir)) if working_dir # executes first
73
+ cmd.join(COMMAND_SEPARATOR)
74
+ end
75
+
76
+ private
77
+
78
+ def log_command(cmd)
79
+ cmd = command(cmd)
80
+ logger.debug "Executing command:\n#{cmd.split(%r{\n|\r\n|;\s*}).map { |c| " #> #{c}" }.join("\n")}"
81
+ end
82
+
83
+ def change_ruby_version_cmd
84
+ "uru #{ruby_version}"
85
+ end
86
+
87
+ def set_env_var_cmd(key, value)
88
+ "set #{key}=\"#{value}\""
89
+ end
90
+
91
+ def change_working_dir_cmd(dir)
92
+ "cd #{dir}"
93
+ end
94
+ end
95
+ end
96
+ end
@@ -1,18 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'open3'
4
- require_relative 'base_exec'
4
+ require_relative 'base_cmd'
5
5
 
6
6
  module CemWinSpec
7
7
  module WinExec
8
8
  # Class for executing local shell commands
9
- class LocalExec < BaseExec
9
+ class LocalCmd < BaseCmd
10
10
  attr_reader :thread_results
11
11
 
12
- def initialize(working_dir = nil)
12
+ def initialize(working_dir = nil, puppet_version: nil, **env_vars)
13
13
  @ran_in_thread = false
14
14
  @thread_results = {}
15
- super(working_dir)
15
+ super(working_dir, puppet_version: puppet_version, **env_vars)
16
16
  end
17
17
 
18
18
  def available?
@@ -35,9 +35,9 @@ module CemWinSpec
35
35
  # This is useful for running commands that should not block the current process
36
36
  # and that you don't need stdout/stderr from.
37
37
  # @param cmd [String] The command to execute
38
- def bg_exec(cmd, *_args, **_kwargs)
39
- puts_cmd(cmd)
40
- Process.detach(spawn(cd_working_dir(cmd)))
38
+ def bg_run(cmd, *_args, **_kwargs)
39
+ log_command(cmd)
40
+ Process.detach(spawn(command(cmd)))
41
41
  end
42
42
 
43
43
  # Execute a command in a new thread. This works by creating a new thread in a thread group
@@ -48,20 +48,20 @@ module CemWinSpec
48
48
  # Process::Status object.
49
49
  # @param cmd [String] The command to execute
50
50
  # @return [Array] An array of [:threaded, cmd]
51
- def thread_exec(cmd, *_args, **_kwargs)
51
+ def thread_run(cmd, *_args, **_kwargs)
52
52
  @ran_in_thread = true
53
53
  th = Thread.new do
54
- puts_cmd(cmd)
55
- so, se, st = Open3.capture3(cd_working_dir(cmd))
54
+ log_command(cmd)
55
+ so, se, st = Open3.capture3(command(cmd))
56
56
  @thread_results[cmd] = [so, se, st]
57
57
  end
58
58
  thread_group.add th
59
59
  :threaded
60
60
  end
61
61
 
62
- def exec(cmd, *_args, **_kwargs)
63
- puts_cmd(cmd)
64
- Open3.capture3(cd_working_dir(cmd))
62
+ def run(cmd, *_args, **_kwargs)
63
+ log_command(cmd)
64
+ Open3.capture3(command(cmd))
65
65
  end
66
66
 
67
67
  private
@@ -2,32 +2,36 @@
2
2
 
3
3
  require 'winrm'
4
4
  require 'winrm-fs'
5
- require_relative 'base_exec'
5
+ require_relative 'base_cmd'
6
6
 
7
7
  module CemWinSpec
8
8
  module WinExec
9
9
  # Class for executing PowerShell commands over WinRM
10
- class WinRMExec < BaseExec
10
+ class WinRMCmd < BaseCmd
11
11
  attr_reader :conn_opts
12
12
 
13
- def initialize(conn_opts, working_dir = nil, quiet: false)
13
+ def initialize(conn_opts, working_dir = nil, quiet: false, puppet_version: nil, **env_vars)
14
14
  @conn_opts = conn_opts
15
15
  @quiet = quiet
16
16
  @conn = new_conn(@conn_opts.to_h)
17
- super(working_dir)
17
+ super(working_dir, puppet_version: puppet_version, **env_vars)
18
18
  end
19
19
 
20
20
  def available?
21
21
  @available
22
22
  end
23
23
 
24
- def exec(cmd, *_args, **_kwargs)
25
- puts_cmd(cmd)
24
+ def run(cmd, *_args, **_kwargs)
25
+ cmd = cmd.join('; ') if cmd.is_a?(Array)
26
+ log_command(cmd)
26
27
  shell = nil
27
28
  output = nil
28
29
  begin
29
30
  shell = conn.shell(:powershell)
30
- output = shell.run(cd_working_dir(cmd))
31
+ output = shell.run(command(cmd)) do |stdout, stderr|
32
+ logger << stdout unless stdout.nil? || stdout.empty?
33
+ logger << stderr unless stderr.nil? || stderr.empty?
34
+ end
31
35
  rescue WinRM::WinRMAuthorizationError => e
32
36
  @available = false
33
37
  raise e
@@ -77,10 +81,19 @@ module CemWinSpec
77
81
  def new_conn(hash_opts)
78
82
  logger.debug "Creating connection to #{hash_opts[:endpoint]}"
79
83
  new_conn = WinRM::Connection.new(hash_opts)
80
- new_conn.logger = logger
84
+ new_conn.logger = new_conn_logger
81
85
  new_conn
82
86
  end
83
87
 
88
+ def new_conn_logger
89
+ conn_logger = logger.dup
90
+ conn_logger.level = Logger::ERROR if @quiet
91
+ conn_logger.level = Logger::DEBUG if ENV['WINRM_DEBUG'] == 'true'
92
+ conn_logger.level = Logger::INFO if conn_logger.level == Logger::DEBUG && ENV.fetch('WINRM_DEBUG', 'false') != 'true'
93
+ logger.debug "WinRM connection logger level set to #{conn_logger.level}"
94
+ conn_logger
95
+ end
96
+
84
97
  def file_manager
85
98
  @file_manager ||= WinRM::FS::FileManager.new(conn)
86
99
  end
@@ -49,7 +49,7 @@ module CemWinSpec
49
49
  end
50
50
 
51
51
  def pass
52
- @pass ||= Digest::SHA256.hexdigest(pt_pass) unless pt_pass.nil?
52
+ Digest::SHA256.hexdigest(pt_pass) unless pt_pass.nil?
53
53
  end
54
54
 
55
55
  def endpoint
@@ -57,7 +57,7 @@ module CemWinSpec
57
57
  end
58
58
 
59
59
  def opts
60
- @opts ||= new_opts(@kwargs)
60
+ @opts ||= create_new_opts(@kwargs)
61
61
  end
62
62
 
63
63
  def ==(other)
@@ -75,14 +75,14 @@ module CemWinSpec
75
75
  end
76
76
 
77
77
  def digest
78
- Digest::SHA256.hexdigest([host, port, user, @pass, opts.values].join(':'))
78
+ Digest::SHA256.hexdigest([host, port, user, pt_pass, opts.values].join(':'))
79
79
  end
80
80
 
81
81
  # Merge new options into existing options and return a new ConnectionOpts object
82
82
  # @param [Hash] new_opts
83
83
  # @return [ConnectionOpts]
84
84
  def merge(**new_opts)
85
- self.class.new(opts_merge(**new_opts))
85
+ self.class.new(**opts_merge(**new_opts))
86
86
  end
87
87
 
88
88
  def merge!(**new_opts)
@@ -139,7 +139,7 @@ module CemWinSpec
139
139
  password
140
140
  end
141
141
 
142
- def new_opts(nopts = {})
142
+ def create_new_opts(nopts = {})
143
143
  logger.debug 'Creating new connection options opts'
144
144
  new_opts_h = CONN_DEFAULTS.dup.merge(nopts)
145
145
  new_opts_h[:transport] = new_opts_h[:transport].to_sym