Module: CemWinSpec

Extended by:
Logging
Defined in:
lib/cem_win_spec.rb,
lib/cem_win_spec/logging.rb,
lib/cem_win_spec/version.rb,
lib/cem_win_spec/win_exec.rb,
lib/cem_win_spec/iap_tunnel.rb,
lib/cem_win_spec/test_runner.rb,
lib/cem_win_spec/fixture_cache.rb,
lib/cem_win_spec/win_exec/exec.rb,
lib/cem_win_spec/rspec_test_cmds.rb,
lib/cem_win_spec/win_exec/output.rb,
lib/cem_win_spec/win_exec/factory.rb,
lib/cem_win_spec/logging/formatter.rb,
lib/cem_win_spec/win_exec/cmd/base_cmd.rb,
lib/cem_win_spec/module_archive_builder.rb,
lib/cem_win_spec/win_exec/cmd/local_cmd.rb,
lib/cem_win_spec/win_exec/cmd/winrm_cmd.rb,
lib/cem_win_spec/win_exec/connection_opts.rb

Defined Under Namespace

Modules: Logging, WinExec Classes: CemWinSpecValidationError, FixtureCache, FixtureCacheError, IapTunnel, IapTunnelStartError, ModuleArchiveBuilder, RspecTestCmds, TestRunner

Constant Summary collapse

VERSION =
"0.1.7"

Constants included from Logging

Logging::LEVEL_MAP

Class Method Summary collapse

Methods included from Logging

current_log_format, current_log_format, current_log_level, current_log_level, included, log_setup!, log_setup!, logger, logger, new_log_formatter, new_log_formatter, new_log_level, new_log_level

Class Method Details

.check_output!(output, runner = nil) ⇒ Object



139
140
141
142
143
144
# File 'lib/cem_win_spec.rb', line 139

def self.check_output!(output, runner = nil)
  unless output.success?
    runner&.iap_tunnel&.stop(wait: false, log: false)
    raise "Command failed with exit code #{output.exitcode}"
  end
end

.clean_fixture_cache(runner, module_dir, **opts) ⇒ Object

Clean the remote fixture cache

Parameters:

  • options (Hash)

    Options for the test runner



133
134
135
136
137
# File 'lib/cem_win_spec.rb', line 133

def self.clean_fixture_cache(runner, module_dir, **opts)
  validate_output do
    runner.clean_fixture_cache(working_dir: module_dir, **opts).run
  end
end

.handle_run_error(err) ⇒ Object



75
76
77
78
79
# File 'lib/cem_win_spec.rb', line 75

def self.handle_run_error(err)
  logger.fatal "Error: #{err.message}"
  logger.debug err.backtrace.join("\n")
  exit 1
end

.retry_spec_on_error(runner, module_dir, **options) ⇒ Object



81
82
83
84
85
86
87
88
89
# File 'lib/cem_win_spec.rb', line 81

def self.retry_spec_on_error(runner, module_dir, **options)
  logger.info 'Cleaning cache and trying again...'
  validate_output do
    clean_fixture_cache(runner, module_dir, **options)
  end
  validate_output do
    run_spec(runner, module_dir, **options)
  end
end

.run(operation = :spec, options = {}) ⇒ Object

Run cem_win_spec operations

Parameters:

  • options (Hash) (defaults to: {})

    Options for the test runner

Options Hash (options):

  • :quiet (Boolean) — default: false

    Whether to suppress output

  • :debug (Boolean) — default: false

    Whether to enable debug output

  • :log_level (String) — default: nil

    Explicitly set the log level

  • :log_file (String) — default: nil

    Log output to file

  • :log_format (String) — default: nil

    Set log format(text, json, github_action)



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/cem_win_spec.rb', line 31

def self.run(operation = :spec, options = {})
  raise 'Must be ran from the root of the project' unless File.exist?('Gemfile')

  log_setup!(options)
  logger.info 'Running cem-win-spec...'
  logger.debug "Options: #{options}"
  runner = TestRunner.new
  logger.debug "Created TestRunner: #{runner}"
  signal_handler(runner)
  logger.debug 'Set up signal handler'
  begin
    sre_out = setup_remote_environment(runner)
    working_dir = sre_out.stdout.chomp
    logger.debug "Working dir: #{working_dir}"
    upload_out = upload_module(runner, working_dir)
    module_dir = upload_out.stdout.chomp
    logger.debug "Module dir: #{module_dir}"
    setup_remote_ruby(runner, module_dir, **options)
    case operation
    when :spec
      run_spec(runner, module_dir, **options)
    when :clean_fixture_cache
      clean_fixture_cache(runner, module_dir, **options)
    else
      raise ArgumentError, "Unknown operation: #{operation}"
    end
  rescue StandardError => e
    if operation == :spec && runner.retry?
      begin
        logger.warn "Error running spec: #{e.message}"
        logger.debug e.backtrace.join("\n")
        retry_spec_on_error(runner, module_dir, **options)
      rescue StandardError => err
        handle_run_error(err)
      end
    else
      handle_run_error(e)
    end
  ensure
    runner&.clean_up(working_dir) if working_dir
    runner&.iap_tunnel&.stop(wait: false, log: false)
  end
end

.run_spec(runner, module_dir, **opts) ⇒ Object

Runs RSpec tests



120
121
122
123
124
125
126
127
128
129
# File 'lib/cem_win_spec.rb', line 120

def self.run_spec(runner, module_dir, **opts)
  output = validate_output(validation_method: :inspect) do
    runner.rspec_tests_parallel(operation_timeout: 300,
                                receive_timeout: 310,
                                working_dir: module_dir,
                                ignore_exitcode: true,
                                reuse_tunnel: false,
                                **opts).run
  end
end

.setup_remote_environment(runner) ⇒ Object



91
92
93
94
95
96
97
98
99
100
101
# File 'lib/cem_win_spec.rb', line 91

def self.setup_remote_environment(runner)
  validate_output do
    runner.enable_long_paths.run
  end
  validate_output do
    runner.enable_symlinks.run
  end
  validate_output do
    runner.create_working_dir.run
  end
end

.setup_remote_ruby(runner, module_dir, **opts) ⇒ Object



109
110
111
112
113
114
115
116
117
# File 'lib/cem_win_spec.rb', line 109

def self.setup_remote_ruby(runner, module_dir, **opts)
  validate_output do
    runner.setup_ruby(operation_timeout: 300,
                      receive_timeout: 310,
                      working_dir: module_dir,
                      reuse_tunnel: false,
                      **opts).run
  end
end

.signal_handler(runner) ⇒ Object



11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/cem_win_spec.rb', line 11

def self.signal_handler(runner)
  Signal.trap('INT') do
    puts 'Caught interrupt, killing tunnel and exiting'
    runner.iap_tunnel.stop(wait: false, log: false)
    exit 1
  end
  Signal.trap('TERM') do
    puts 'Caught interrupt, killing tunnel and exiting'
    runner.iap_tunnel.stop(wait: false, log: false)
    exit 1
  end
end

.upload_module(runner, working_dir) ⇒ Object



103
104
105
106
107
# File 'lib/cem_win_spec.rb', line 103

def self.upload_module(runner, working_dir)
  validate_output do
    runner.upload_module(operation_timeout: 300, receive_timeout: 310, working_dir: working_dir).run
  end
end

.validate_output(*args, validation_method: :success?, no_output_strat: :debug, **kwargs) ⇒ Object

Raises:

  • (ArgumentError)


148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/cem_win_spec.rb', line 148

def self.validate_output(*args, validation_method: :success?, no_output_strat: :debug, **kwargs)
  raise ArgumentError, 'Block required' unless block_given?

  output = yield *args, **kwargs
  unless output
    case no_output_strat
    when :raise
      raise 'No output'
    when :warn
      logger.warn 'No output'
    when :debug
      logger.debug 'No output'
    else
      # Do nothing
    end
    return false
  end

  unless output.send(validation_method)
    raise CemWinSpecValidationError, "Output validation \"#{validation_method}\" failed: #{output}"
  end
  output
end