ruby_raider 4.1.0 → 4.2.0
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/.github/workflows/e2e_tests.yml +3 -0
- data/README.md +52 -53
- data/RELEASE.md +14 -1
- data/lib/commands/schedule_commands.rb +84 -0
- data/lib/generators/templates/common/git_ignore.tt +1 -0
- data/lib/ruby_raider/runtime/retry_reset.rb +32 -0
- data/lib/ruby_raider/runtime/rspec.rb +1 -0
- data/lib/ruby_raider/runtime/show_browser.rb +53 -0
- data/lib/ruby_raider/runtime.rb +2 -0
- data/lib/ruby_raider.rb +22 -7
- data/lib/utilities/schedules/adapter.rb +22 -0
- data/lib/utilities/schedules/base.rb +27 -0
- data/lib/utilities/schedules/kind.rb +74 -0
- data/lib/utilities/schedules/legacy.rb +196 -0
- data/lib/utilities/schedules/legacy_stub.rb +62 -0
- data/lib/utilities/{flows → schedules}/next_run.rb +2 -2
- data/lib/utilities/{flows → schedules}/notifier.rb +6 -6
- data/lib/utilities/{flows → schedules}/os/command_runner.rb +1 -1
- data/lib/utilities/{flows → schedules}/os/cron.rb +27 -17
- data/lib/utilities/{flows → schedules}/os/launchd.rb +32 -14
- data/lib/utilities/{flows → schedules}/os/linux.rb +23 -5
- data/lib/utilities/{flows → schedules}/os/systemd.rb +33 -17
- data/lib/utilities/{flows → schedules}/os/task_scheduler.rb +36 -20
- data/lib/utilities/schedules/os_enumerator.rb +30 -0
- data/lib/utilities/schedules/project.rb +70 -0
- data/lib/utilities/schedules/rule.rb +162 -0
- data/lib/utilities/schedules/run_lock.rb +160 -0
- data/lib/utilities/schedules/run_log.rb +122 -0
- data/lib/utilities/schedules/run_report.rb +139 -0
- data/lib/utilities/schedules/run_wrapper.rb +216 -0
- data/lib/utilities/schedules/schedule.rb +89 -0
- data/lib/utilities/schedules/schedule_store.rb +53 -0
- data/lib/utilities/schedules/scheduler.rb +178 -0
- data/lib/utilities/schedules/scheduler_steps.rb +69 -0
- data/lib/utilities/schedules/selection.rb +133 -0
- data/lib/utilities/schedules/spawn.rb +68 -0
- data/lib/utilities/{flows/schedule_store.rb → schedules/store.rb} +17 -13
- data/lib/version +1 -1
- data/ruby_raider.gemspec +1 -0
- data/sig/commands/schedule_commands.rbs +12 -0
- data/sig/ruby_raider/runtime/retry_reset.rbs +7 -0
- data/sig/ruby_raider/runtime/show_browser.rbs +27 -0
- data/sig/ruby_raider.rbs +4 -0
- data/sig/utilities/schedules/adapter.rbs +5 -0
- data/sig/utilities/schedules/base.rbs +15 -0
- data/sig/utilities/schedules/kind.rbs +32 -0
- data/sig/utilities/schedules/legacy.rbs +45 -0
- data/sig/utilities/schedules/legacy_stub.rbs +15 -0
- data/sig/utilities/{flows → schedules}/next_run.rbs +3 -3
- data/sig/utilities/{flows → schedules}/notifier.rbs +1 -1
- data/sig/utilities/{flows → schedules}/os/command_runner.rbs +1 -1
- data/sig/utilities/{flows → schedules}/os/cron.rbs +7 -7
- data/sig/utilities/{flows → schedules}/os/launchd.rbs +7 -6
- data/sig/utilities/{flows → schedules}/os/linux.rbs +10 -4
- data/sig/utilities/{flows → schedules}/os/systemd.rbs +8 -7
- data/sig/utilities/{flows → schedules}/os/task_scheduler.rbs +13 -10
- data/sig/utilities/schedules/os_enumerator.rbs +12 -0
- data/sig/utilities/schedules/project.rbs +22 -0
- data/sig/utilities/{flows/schedule.rbs → schedules/rule.rbs} +23 -12
- data/sig/utilities/schedules/run_lock.rbs +29 -0
- data/sig/utilities/schedules/run_log.rbs +33 -0
- data/sig/utilities/schedules/run_report.rbs +34 -0
- data/sig/utilities/schedules/run_wrapper.rbs +45 -0
- data/sig/utilities/schedules/schedule.rbs +27 -0
- data/sig/utilities/schedules/schedule_store.rbs +21 -0
- data/sig/utilities/{flows → schedules}/scheduler.rbs +22 -15
- data/sig/utilities/schedules/scheduler_steps.rbs +22 -0
- data/sig/utilities/schedules/selection.rbs +36 -0
- data/sig/utilities/schedules/spawn.rbs +10 -0
- data/sig/utilities/{flows/schedule_store.rbs → schedules/store.rbs} +14 -9
- data/spec/commands/schedule_commands_spec.rb +284 -0
- data/spec/integration/content/common_content_spec.rb +8 -2
- data/spec/integration/content/gemfile_content_spec.rb +2 -2
- data/spec/integration/end_to_end_spec.rb +0 -63
- data/spec/runtime/retry_reset_spec.rb +112 -0
- data/spec/runtime/show_browser_project_spec.rb +70 -0
- data/spec/runtime/show_browser_spec.rb +101 -0
- data/spec/utilities/schedules/kind_spec.rb +81 -0
- data/spec/utilities/schedules/legacy_spec.rb +433 -0
- data/spec/utilities/schedules/legacy_stub_spec.rb +144 -0
- data/spec/utilities/{flows → schedules}/next_run_spec.rb +5 -5
- data/spec/utilities/{flows → schedules}/notifier_spec.rb +3 -4
- data/spec/utilities/{flows → schedules}/os/command_runner_spec.rb +2 -3
- data/spec/utilities/{flows → schedules}/os/cron_spec.rb +34 -29
- data/spec/utilities/{flows → schedules}/os/launchd_spec.rb +42 -29
- data/spec/utilities/{flows → schedules}/os/linux_spec.rb +27 -13
- data/spec/utilities/schedules/os/list_ids_spec.rb +202 -0
- data/spec/utilities/{flows → schedules}/os/systemd_spec.rb +35 -31
- data/spec/utilities/{flows → schedules}/os/task_scheduler_spec.rb +40 -34
- data/spec/utilities/schedules/os_entry_spec.rb +54 -0
- data/spec/utilities/schedules/os_enumerator_spec.rb +57 -0
- data/spec/utilities/schedules/project_spec.rb +125 -0
- data/spec/utilities/schedules/run_lock_spec.rb +143 -0
- data/spec/utilities/schedules/run_log_spec.rb +83 -0
- data/spec/utilities/schedules/run_report_spec.rb +150 -0
- data/spec/utilities/schedules/run_wrapper_integration_spec.rb +166 -0
- data/spec/utilities/schedules/run_wrapper_spec.rb +430 -0
- data/spec/utilities/schedules/schedule_spec.rb +120 -0
- data/spec/utilities/schedules/schedule_store_spec.rb +151 -0
- data/spec/utilities/schedules/scheduler_launchd_spec.rb +77 -0
- data/spec/utilities/schedules/scheduler_spec.rb +445 -0
- data/spec/utilities/schedules/selection_spec.rb +176 -0
- data/spec/utilities/schedules/spawn_spec.rb +104 -0
- metadata +106 -53
- data/lib/commands/flow_commands.rb +0 -104
- data/lib/generators/templates/flows/flow_helper.tt +0 -42
- data/lib/generators/templates/flows/run.tt +0 -332
- data/lib/utilities/flows/project.rb +0 -170
- data/lib/utilities/flows/run_log.rb +0 -61
- data/lib/utilities/flows/runner.rb +0 -206
- data/lib/utilities/flows/schedule.rb +0 -221
- data/lib/utilities/flows/scheduler.rb +0 -187
- data/sig/commands/flow_commands.rbs +0 -13
- data/sig/utilities/flows/project.rbs +0 -46
- data/sig/utilities/flows/run_log.rbs +0 -22
- data/sig/utilities/flows/runner.rbs +0 -35
- data/spec/commands/flow_commands_spec.rb +0 -128
- data/spec/generators/flow_helper_spec.rb +0 -40
- data/spec/integration/flows/flow_project.rb +0 -62
- data/spec/integration/flows/run_command_spec.rb +0 -91
- data/spec/integration/flows/run_lifecycle_spec.rb +0 -383
- data/spec/utilities/flows/project_spec.rb +0 -178
- data/spec/utilities/flows/run_log_spec.rb +0 -47
- data/spec/utilities/flows/runner_spec.rb +0 -313
- data/spec/utilities/flows/schedule_spec.rb +0 -233
- data/spec/utilities/flows/schedule_store_spec.rb +0 -137
- data/spec/utilities/flows/scheduler_spec.rb +0 -329
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
require 'open3'
|
|
5
|
+
require 'rbconfig'
|
|
6
|
+
require 'tmpdir'
|
|
7
|
+
|
|
8
|
+
# Real rspec-retry runs in a subprocess, no browser. The suite mimics a generated project: driver_helper
|
|
9
|
+
# memoises @driver, the after hook quits it, and a quit driver refuses every call like a dead session.
|
|
10
|
+
RSpec.describe 'Retrying a test with a fresh driver' do
|
|
11
|
+
lib = File.expand_path('../../lib', __dir__)
|
|
12
|
+
|
|
13
|
+
suite = <<~'RUBY'
|
|
14
|
+
require 'json'
|
|
15
|
+
require 'rspec'
|
|
16
|
+
require 'rspec/retry' if ENV['RETRY'] == 'before'
|
|
17
|
+
require 'ruby_raider/runtime/rspec'
|
|
18
|
+
require 'rspec/retry' if ENV['RETRY'] == 'after'
|
|
19
|
+
|
|
20
|
+
LOG = ENV.fetch('LOG')
|
|
21
|
+
def log(entry) = File.open(LOG, 'a') { |file| file.puts(JSON.generate(entry)) }
|
|
22
|
+
|
|
23
|
+
class FakeDriver
|
|
24
|
+
def quit = @quit = true
|
|
25
|
+
|
|
26
|
+
def title
|
|
27
|
+
raise Errno::ECONNREFUSED, '127.0.0.1:9515' if @quit
|
|
28
|
+
|
|
29
|
+
'ok'
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
module DriverHelper
|
|
34
|
+
def driver = @driver ||= FakeDriver.new
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
RSpec.configure do |config|
|
|
38
|
+
config.include(DriverHelper)
|
|
39
|
+
config.default_retry_count = ENV.fetch('RETRY_COUNT', 0).to_i if config.respond_to?(:default_retry_count=)
|
|
40
|
+
# A project's own callback: one that resets the driver itself, or one that does not
|
|
41
|
+
if ENV['OWN_CALLBACK']
|
|
42
|
+
config.retry_callback = proc do
|
|
43
|
+
log('callback' => 'project')
|
|
44
|
+
@driver = nil if ENV['OWN_CALLBACK'] == 'resets'
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
config.before(:each) { driver.title }
|
|
48
|
+
config.after(:each) { driver.quit }
|
|
49
|
+
config.after(:suite) do
|
|
50
|
+
callback = config.retry_callback if config.respond_to?(:retry_callback)
|
|
51
|
+
owner = { Raider::RetryReset::CALLBACK => 'ours', nil => 'none' }.fetch(callback, 'project')
|
|
52
|
+
log('installed' => config.respond_to?(:retry_callback) ? owner : 'no rspec-retry')
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
RSpec.describe 'Flaky' do
|
|
57
|
+
it 'fails on its first try and passes on the next' do
|
|
58
|
+
tries = File.readlines(LOG).count { |line| line.include?('"try"') } + 1
|
|
59
|
+
log('try' => tries, 'driver' => driver.object_id)
|
|
60
|
+
expect(tries).to eq(ENV.fetch('PASS_ON', '2').to_i)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
RUBY
|
|
64
|
+
|
|
65
|
+
# The subprocess is a plain ruby, not bundle exec: it finds rspec and rspec-retry through the bundle env
|
|
66
|
+
# (BUNDLE_GEMFILE, RUBYOPT=-rbundler/setup) it inherits from this rspec run.
|
|
67
|
+
define_method(:run_suite) do |env|
|
|
68
|
+
Dir.mktmpdir('raider-retry') do |dir|
|
|
69
|
+
spec = File.join(dir, 'flaky_spec.rb')
|
|
70
|
+
log = File.join(dir, 'log.jsonl')
|
|
71
|
+
File.write(spec, suite)
|
|
72
|
+
File.write(log, '')
|
|
73
|
+
out, err, status = Open3.capture3(env.merge('LOG' => log, 'RSPEC_RETRY_RETRY_COUNT' => nil), RbConfig.ruby, '-I', lib,
|
|
74
|
+
'-e', 'require "rspec/core"; exit RSpec::Core::Runner.run(ARGV)', spec, chdir: dir)
|
|
75
|
+
{ status: status.exitstatus, output: out + err, log: File.readlines(log).map { |line| JSON.parse(line) } }
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
define_method(:tries) { |result| result[:log].select { |entry| entry.key?('try') } }
|
|
80
|
+
define_method(:installed) { |result| result[:log].find { |entry| entry.key?('installed') }&.fetch('installed') }
|
|
81
|
+
|
|
82
|
+
%w[before after].each do |order|
|
|
83
|
+
it "passes on the second try with a fresh driver when rspec/retry is required #{order} the runtime" do
|
|
84
|
+
result = run_suite('RETRY' => order, 'RETRY_COUNT' => '2')
|
|
85
|
+
expect([result[:status], tries(result).map { |entry| entry['try'] }]).to eq([0, [1, 2]]), result[:output]
|
|
86
|
+
expect(tries(result).map { |entry| entry['driver'] }.uniq.size).to eq(2)
|
|
87
|
+
expect(installed(result)).to eq('ours')
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it 'keeps a retry_callback the project set' do
|
|
92
|
+
result = run_suite('RETRY' => 'before', 'RETRY_COUNT' => '2', 'OWN_CALLBACK' => 'resets')
|
|
93
|
+
expect([result[:status], installed(result)]).to eq([0, 'project']), result[:output]
|
|
94
|
+
expect(result[:log]).to include({ 'callback' => 'project' })
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it 'a project callback that keeps the driver still fails on the quit session' do
|
|
98
|
+
result = run_suite('RETRY' => 'before', 'RETRY_COUNT' => '2', 'OWN_CALLBACK' => 'keeps')
|
|
99
|
+
expect([result[:status], installed(result), tries(result).size]).to eq([1, 'project', 1])
|
|
100
|
+
expect(result[:output]).to include('Errno::ECONNREFUSED')
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it 'changes nothing when no retry happens' do
|
|
104
|
+
result = run_suite('RETRY' => 'before', 'RETRY_COUNT' => '2', 'PASS_ON' => '1')
|
|
105
|
+
expect([result[:status], tries(result).size, installed(result)]).to eq([0, 1, 'ours']), result[:output]
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it 'does nothing without rspec-retry' do
|
|
109
|
+
result = run_suite('PASS_ON' => '1')
|
|
110
|
+
expect([result[:status], installed(result)]).to eq([0, 'no rspec-retry']), result[:output]
|
|
111
|
+
end
|
|
112
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
require 'json'
|
|
5
|
+
require 'open3'
|
|
6
|
+
require 'rbconfig'
|
|
7
|
+
require 'rspec'
|
|
8
|
+
require 'tmpdir'
|
|
9
|
+
|
|
10
|
+
# A Selenium project generated by this branch (its helper templates are byte-identical to 4.0.1's) with
|
|
11
|
+
# `headless: true` in config/config.yml. Its own helpers/driver_helper.rb builds the browser options, no
|
|
12
|
+
# browser is started. RAIDER_SHOW_BROWSER=1 drops the --headless it adds; config.yml is never written.
|
|
13
|
+
RSpec.describe 'Show the browser in a generated project', :slow do
|
|
14
|
+
lib = File.expand_path('../../lib', __dir__)
|
|
15
|
+
|
|
16
|
+
generate = <<~RUBY
|
|
17
|
+
require 'generators/invoke_generators'
|
|
18
|
+
InvokeGenerators.generate_framework(automation: 'selenium', framework: 'rspec', name: 'shown', examples: false)
|
|
19
|
+
RUBY
|
|
20
|
+
|
|
21
|
+
# Loads the project's real driver_helper and prints the args of the options it builds
|
|
22
|
+
options = <<~RUBY
|
|
23
|
+
require 'json'
|
|
24
|
+
require './helpers/driver_helper'
|
|
25
|
+
helper = Object.new.extend(DriverHelper)
|
|
26
|
+
helper.instance_variable_set(:@config, YAML.load_file('config/config.yml'))
|
|
27
|
+
built = helper.send(:create_webdriver_options)
|
|
28
|
+
puts JSON.generate(built.as_json.fetch(built.class::KEY).fetch('args'))
|
|
29
|
+
RUBY
|
|
30
|
+
|
|
31
|
+
define_method(:ruby) do |env, dir, script|
|
|
32
|
+
out, err, status = Open3.capture3(env, RbConfig.ruby, '-I', lib, '-e', script, chdir: dir)
|
|
33
|
+
raise "ruby failed in #{dir}: #{err}" unless status.success?
|
|
34
|
+
|
|
35
|
+
out
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# rubocop:disable RSpec/InstanceVariable
|
|
39
|
+
before(:all) do # rubocop:disable RSpec/BeforeAfterAll
|
|
40
|
+
@tmp = Dir.mktmpdir('raider-show-browser')
|
|
41
|
+
ruby({}, @tmp, generate)
|
|
42
|
+
@project = File.join(@tmp, 'shown')
|
|
43
|
+
config = File.join(@project, 'config', 'config.yml')
|
|
44
|
+
File.write(config, "#{File.read(config)}headless: true\n")
|
|
45
|
+
@before = File.binread(config)
|
|
46
|
+
@args = { off: { 'RAIDER_SHOW_BROWSER' => nil, 'HEADLESS' => nil }, shown: { 'RAIDER_SHOW_BROWSER' => '1', 'HEADLESS' => nil },
|
|
47
|
+
shown_hidden_env: { 'RAIDER_SHOW_BROWSER' => '1', 'HEADLESS' => 'true' }, other: { 'RAIDER_SHOW_BROWSER' => 'true', 'HEADLESS' => nil } }
|
|
48
|
+
.transform_values { |env| JSON.parse(ruby(env, @project, options)) }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
after(:all) { FileUtils.rm_rf(@tmp) } # rubocop:disable RSpec/BeforeAfterAll
|
|
52
|
+
|
|
53
|
+
it 'requires the runtime from the generated driver_helper' do
|
|
54
|
+
expect(File.read(File.join(@project, 'helpers', 'driver_helper.rb'))).to include("require 'ruby_raider/runtime'")
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it 'keeps --headless without RAIDER_SHOW_BROWSER=1' do
|
|
58
|
+
expect(@args.values_at(:off, :other)).to all(include('--headless'))
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it 'drops --headless with RAIDER_SHOW_BROWSER=1, even with HEADLESS set, and keeps the browser arguments' do
|
|
62
|
+
expected = @args[:off] - ['--headless']
|
|
63
|
+
expect(@args.values_at(:shown, :shown_hidden_env)).to eq([expected, expected])
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it 'never writes config.yml' do
|
|
67
|
+
expect(File.binread(File.join(@project, 'config', 'config.yml'))).to eq(@before)
|
|
68
|
+
end
|
|
69
|
+
# rubocop:enable RSpec/InstanceVariable
|
|
70
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
require 'open3'
|
|
5
|
+
require 'rbconfig'
|
|
6
|
+
require 'rspec'
|
|
7
|
+
require_relative '../../lib/ruby_raider/runtime/show_browser'
|
|
8
|
+
|
|
9
|
+
# The prepend is process-wide, so every case that loads the runtime and looks at the Options classes runs
|
|
10
|
+
# in its own ruby with an explicit RAIDER_SHOW_BROWSER. This process only checks the pure helpers.
|
|
11
|
+
RSpec.describe Raider::ShowBrowser do # rubocop:disable RSpec/FilePath
|
|
12
|
+
lib = File.expand_path('../../lib', __dir__)
|
|
13
|
+
|
|
14
|
+
# Loads the runtime the way a project's driver_helper does, then reports the real Options classes
|
|
15
|
+
probe = <<~RUBY
|
|
16
|
+
require 'json'
|
|
17
|
+
require 'ruby_raider/runtime'
|
|
18
|
+
filter = Raider::ShowBrowser::Filter
|
|
19
|
+
Raider::ShowBrowser.install(ENV) if ARGV.include?('again')
|
|
20
|
+
report = %w[Chrome Edge Firefox].to_h do |browser|
|
|
21
|
+
klass = Selenium::WebDriver.const_get(browser)::Options
|
|
22
|
+
built = klass.new(args: ['--headless', 'start-maximized', '--headless=new', '-headless'])
|
|
23
|
+
%w[--headless --headless=old -headless window-size=800,600 --headlessly headless].each { |arg| built.add_argument(arg) }
|
|
24
|
+
set = klass.new
|
|
25
|
+
set.args = ['--headless', 'set']
|
|
26
|
+
keyed = klass.new('args' => ['-headless', 'keyed'])
|
|
27
|
+
args = ->(options) { options.as_json.fetch(klass::KEY).fetch('args') }
|
|
28
|
+
added = klass.new
|
|
29
|
+
returned = [added.add_argument('--headless'), added.add_argument('kept')].map { |value| value.equal?(added.options[:args]) }
|
|
30
|
+
[browser, { 'prepended' => klass.ancestors.count(filter), 'built' => args.call(built), 'set' => args.call(set),
|
|
31
|
+
'keyed' => keyed.options['args'], 'returned' => returned }]
|
|
32
|
+
end
|
|
33
|
+
puts JSON.generate(report)
|
|
34
|
+
RUBY
|
|
35
|
+
|
|
36
|
+
define_method(:probe) do |value, *argv|
|
|
37
|
+
out, err, status = Open3.capture3({ 'RAIDER_SHOW_BROWSER' => value, 'HEADLESS' => nil }, RbConfig.ruby, '-I', lib, '-e', probe, *argv)
|
|
38
|
+
raise "probe failed: #{err}" unless status.success?
|
|
39
|
+
|
|
40
|
+
JSON.parse(out)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
context 'with RAIDER_SHOW_BROWSER=1' do
|
|
44
|
+
let(:report) { probe('1') }
|
|
45
|
+
|
|
46
|
+
it 'prepends the filter once to the Chrome, Edge and Firefox options' do
|
|
47
|
+
expect(report.transform_values { |browser| browser['prepended'] }).to eq('Chrome' => 1, 'Edge' => 1, 'Firefox' => 1)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it 'prepends it once when installed again' do
|
|
51
|
+
expect(probe('1', 'again').transform_values { |browser| browser['prepended'] }).to eq('Chrome' => 1, 'Edge' => 1, 'Firefox' => 1)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'drops --headless, --headless=* and -headless from args: and add_argument and keeps every other argument' do
|
|
55
|
+
expected = %w[start-maximized window-size=800,600 --headlessly headless]
|
|
56
|
+
expect(report.transform_values { |browser| browser['built'] }).to eq('Chrome' => expected, 'Edge' => expected, 'Firefox' => expected)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'returns the args from add_argument as Selenium does, also for a dropped switch' do
|
|
60
|
+
expect(report.transform_values { |browser| browser['returned'] }).to eq('Chrome' => [true, true], 'Edge' => [true, true], 'Firefox' => [true, true])
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it 'drops them from args= and from a string args key' do
|
|
64
|
+
expect(report.transform_values { |browser| browser.values_at('set', 'keyed') })
|
|
65
|
+
.to eq('Chrome' => [%w[set], %w[keyed]], 'Edge' => [%w[set], %w[keyed]], 'Firefox' => [%w[set], %w[keyed]])
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
[nil, '', '0', 'true', '1 ', 'yes'].each do |value|
|
|
70
|
+
it "prepends nothing and keeps --headless when RAIDER_SHOW_BROWSER is #{value.inspect}" do
|
|
71
|
+
report = probe(value)
|
|
72
|
+
expect(report.transform_values { |browser| [browser['prepended'], browser['built'].first, browser['set']] })
|
|
73
|
+
.to eq('Chrome' => [0, '--headless', %w[--headless set]], 'Edge' => [0, '--headless', %w[--headless set]],
|
|
74
|
+
'Firefox' => [0, '--headless', %w[--headless set]])
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
describe '.headless?' do
|
|
79
|
+
it 'matches only the headless switches' do
|
|
80
|
+
args = ['--headless', '--headless=new', '--headless=', '-headless', 'headless', '--headlessly', '-headless=new', ' --headless', :'--headless', nil]
|
|
81
|
+
expect(args.select { |arg| described_class.headless?(arg) }).to eq(['--headless', '--headless=new', '--headless=', '-headless'])
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
describe '.without_headless' do
|
|
86
|
+
it 'returns a new array and leaves the given one untouched' do
|
|
87
|
+
given = %w[--headless keep].freeze
|
|
88
|
+
expect(described_class.without_headless(given)).to eq(%w[keep])
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it 'passes anything that is not an array through' do
|
|
92
|
+
expect([nil, '--headless'].map { |value| described_class.without_headless(value) }).to eq([nil, '--headless'])
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
describe '.install' do
|
|
97
|
+
it 'installs nothing unless the value is exactly 1' do
|
|
98
|
+
expect([{}, { 'RAIDER_SHOW_BROWSER' => 'true' }].map { |env| described_class.install(env) }).to eq([[], []])
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../../lib/utilities/schedules/kind'
|
|
4
|
+
|
|
5
|
+
RSpec.describe RubyRaider::Schedules::Kind do # rubocop:disable RSpec/FilePath
|
|
6
|
+
let(:kind) { described_class::FLOW_LEGACY }
|
|
7
|
+
let(:os_id) { 'dev.rubyraider.flow.0123456789.report' }
|
|
8
|
+
|
|
9
|
+
it 'keeps the 4.1 words in its OS entries and says 4.1 schedule to the user' do
|
|
10
|
+
expect([kind.os_id_prefix, kind.cron_tag, kind.dir, kind.task_file_prefix, kind.service_description('report'),
|
|
11
|
+
kind.timer_description('report'), kind.task_description('report', 'every day at 08:00'), kind.not_ours,
|
|
12
|
+
kind.unsupported('solaris')])
|
|
13
|
+
.to eq(['dev.rubyraider.flow', '# raider-flow ', '.raider/flows', 'raider-flow-task', 'raider flow report',
|
|
14
|
+
'raider flow report schedule', 'Ruby Raider flow report (every day at 08:00)', 'not a 4.1 schedule',
|
|
15
|
+
'Scheduling 4.1 schedules is not supported on solaris'])
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'names raider schedule list, with no name, for a stranded timer' do
|
|
19
|
+
expect(kind.stranded('report'))
|
|
20
|
+
.to eq('This schedule is a systemd timer; run raider schedule list from a session where systemctl --user works')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'says no flow word to the user' do
|
|
24
|
+
expect([kind.noun, kind.plural, kind.remove_command, kind.not_ours, kind.stranded('report'), kind.unsupported('solaris')])
|
|
25
|
+
.to all(satisfy { |text| !text.match?(/\bflows?\b/i) })
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'reads the name from an os_id of its own kind only' do
|
|
29
|
+
expect([kind.name_in(os_id), kind.name_in('dev.rubyraider.schedule.0123456789.report'), kind.name_in("#{os_id}\n"),
|
|
30
|
+
kind.name_in('dev.rubyraider.flow.0123456789.env'), kind.name_in(nil)]).to eq(['report', nil, nil, nil, nil])
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'reserves env for flows while Schedules does not' do
|
|
34
|
+
expect([kind.valid_name?('env'), RubyRaider::Schedules.valid_name?('env'), kind.valid_name?('a' * 61)]).to eq([false, true, false])
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'knows its own command line under a cron tag' do
|
|
38
|
+
line = '0 8 * * * cd /p && /usr/bin/env /r /b exec raider flow run report --project /p --trigger schedule >> /l 2>&1'
|
|
39
|
+
expect([kind.our_command?(line, 'report'), kind.our_command?(line, 'other')]).to eq([true, false])
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'is frozen' do
|
|
43
|
+
expect([kind, kind.os_id_prefix, kind.reserved]).to all(be_frozen)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
describe 'TESTS' do
|
|
47
|
+
let(:tests) { described_class::TESTS }
|
|
48
|
+
|
|
49
|
+
it 'names test schedules with the schedule words' do
|
|
50
|
+
expect([tests.os_id_prefix, tests.cron_tag, tests.dir, tests.service_description('nightly'), tests.timer_description('nightly'),
|
|
51
|
+
tests.task_description('nightly', 'every day at 08:00'), tests.not_ours, tests.unsupported('solaris')])
|
|
52
|
+
.to eq(['dev.rubyraider.schedule', '# raider-schedule ', '.raider/schedules', 'raider schedule nightly',
|
|
53
|
+
'raider schedule nightly schedule', 'Ruby Raider schedule nightly (every day at 08:00)', 'not a test schedule',
|
|
54
|
+
'Scheduling tests is not supported on solaris'])
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it 'names raider schedule remove for a stranded timer' do
|
|
58
|
+
expect(tests.stranded('nightly'))
|
|
59
|
+
.to eq('This schedule is a systemd timer; run raider schedule remove nightly from a session where systemctl --user works')
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it 'reserves no name and reads only its own os_ids' do
|
|
63
|
+
expect([tests.valid_name?('env'), tests.name_in('dev.rubyraider.schedule.0123456789.env'), tests.name_in(os_id)]).to eq([true, 'env', nil])
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it 'reads no os_id from text that is not valid UTF-8, and lists only ids under the prefix' do
|
|
67
|
+
prefix = 'dev.rubyraider.schedule.0123456789.'
|
|
68
|
+
broken = "#{prefix}a\xFF".dup.force_encoding(Encoding::UTF_8)
|
|
69
|
+
|
|
70
|
+
expect([tests.name_in(broken), tests.listed?(broken, prefix), tests.listed?("#{prefix}nightly", prefix),
|
|
71
|
+
tests.listed?("#{prefix}nightly", 'dev.rubyraider.schedule.9999999999.'), tests.listed?(nil, prefix)])
|
|
72
|
+
.to eq([nil, false, true, false, false])
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it 'knows its own command line under a cron tag, not a flow one' do
|
|
76
|
+
line = '0 8 * * * cd /p && /usr/bin/env /r /b exec raider schedule run nightly --project /p --trigger schedule >> /l 2>&1'
|
|
77
|
+
expect([tests.our_command?(line, 'nightly'), kind.our_command?(line, 'nightly'), tests.our_command?(line.sub(' --trigger schedule', ''), 'nightly')])
|
|
78
|
+
.to eq([true, false, false])
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|