busser 0.9.1 → 0.9.2
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/publish.yml +22 -0
- data/.release-please-manifest.json +1 -1
- data/.rubocop.yml +1 -4
- data/CHANGELOG.md +10 -0
- data/Gemfile +12 -5
- data/README.md +82 -0
- data/Rakefile +19 -1
- data/busser.gemspec +11 -8
- data/lib/busser/command/deserialize.rb +4 -0
- data/lib/busser/command/plugin_create.rb +29 -0
- data/lib/busser/command/plugin_install.rb +40 -4
- data/lib/busser/command/plugin_list.rb +16 -4
- data/lib/busser/command/setup.rb +20 -0
- data/lib/busser/command/suite_cleanup.rb +3 -0
- data/lib/busser/command/suite_path.rb +3 -0
- data/lib/busser/command/test.rb +38 -1
- data/lib/busser/cucumber/hooks.rb +9 -0
- data/lib/busser/helpers.rb +24 -0
- data/lib/busser/plugin.rb +51 -9
- data/lib/busser/rubygems.rb +20 -0
- data/lib/busser/runner_plugin/dummy.rb +3 -0
- data/lib/busser/runner_plugin.rb +5 -0
- data/lib/busser/thor.rb +23 -0
- data/lib/busser/ui.rb +55 -0
- data/lib/busser/version.rb +2 -1
- data/release-please-config.json +3 -1
- data/spec/busser/command/deserialize_spec.rb +0 -1
- data/spec/busser/command/plugin_create_spec.rb +0 -1
- data/spec/busser/command/plugin_install_spec.rb +44 -0
- data/spec/busser/command/plugin_list_spec.rb +49 -0
- data/spec/busser/command/setup_spec.rb +0 -1
- data/spec/busser/command/test_spec.rb +36 -0
- data/spec/busser/helpers_spec.rb +10 -10
- data/spec/busser/plugin_spec.rb +0 -1
- data/spec/busser/ui_spec.rb +7 -7
- data/spec/spec_helper.rb +2 -3
- metadata +10 -58
|
@@ -14,10 +14,19 @@ After do
|
|
|
14
14
|
end
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
+
# Stashes an environment variable so a scenario can change it and have the
|
|
18
|
+
# original put back afterwards.
|
|
19
|
+
#
|
|
20
|
+
# @param key [String] the variable name
|
|
21
|
+
# @return [String, nil] the stashed value
|
|
17
22
|
def backup_envvar(key)
|
|
18
23
|
ENV["_CUKE_#{key}"] = ENV[key]
|
|
19
24
|
end
|
|
20
25
|
|
|
26
|
+
# Puts back a variable stashed by {backup_envvar}.
|
|
27
|
+
#
|
|
28
|
+
# @param key [String] the variable name
|
|
29
|
+
# @return [String, nil] the restored value
|
|
21
30
|
def restore_envvar(key)
|
|
22
31
|
ENV[key] = ENV.delete("_CUKE_#{key}")
|
|
23
32
|
end
|
data/lib/busser/helpers.rb
CHANGED
|
@@ -29,22 +29,41 @@ module Busser
|
|
|
29
29
|
|
|
30
30
|
module_function
|
|
31
31
|
|
|
32
|
+
# Path to the suites directory, or to one suite inside it.
|
|
33
|
+
#
|
|
34
|
+
# @param name [String, nil] a suite name, or nil for the containing
|
|
35
|
+
# directory
|
|
36
|
+
# @return [Pathname] absolute path beneath the Busser root
|
|
32
37
|
def suite_path(name = nil)
|
|
33
38
|
path = root_path + "suites"
|
|
34
39
|
path += name if name
|
|
35
40
|
path.expand_path
|
|
36
41
|
end
|
|
37
42
|
|
|
43
|
+
# Path to the vendor directory, or to one vendored product inside it.
|
|
44
|
+
#
|
|
45
|
+
# @param product [String, nil] a product name, or nil for the containing
|
|
46
|
+
# directory
|
|
47
|
+
# @return [Pathname] absolute path beneath the Busser root
|
|
38
48
|
def vendor_path(product = nil)
|
|
39
49
|
path = root_path + "vendor"
|
|
40
50
|
path += product if product
|
|
41
51
|
path.expand_path
|
|
42
52
|
end
|
|
43
53
|
|
|
54
|
+
# The Busser root, where plugins, suites and vendored products live.
|
|
55
|
+
#
|
|
56
|
+
# @return [Pathname] BUSSER_ROOT if set, otherwise /opt/busser
|
|
44
57
|
def root_path
|
|
45
58
|
Pathname.new(ENV["BUSSER_ROOT"] || "/opt/busser")
|
|
46
59
|
end
|
|
47
60
|
|
|
61
|
+
# No longer supported. Kept so a plugin still calling it warns rather
|
|
62
|
+
# than dying with a NoMethodError halfway through a test run.
|
|
63
|
+
#
|
|
64
|
+
# @param config [Hash] ignored
|
|
65
|
+
# @return [void]
|
|
66
|
+
# @deprecated Shell out or use a Thor action instead.
|
|
48
67
|
def chef_apply(config = {}, &block)
|
|
49
68
|
warn "Apologies, but Busser no longer supports the chef_apply helper," +
|
|
50
69
|
" so the contents of this block will not be executed. Please refactor" +
|
|
@@ -52,6 +71,11 @@ module Busser
|
|
|
52
71
|
" strategy"
|
|
53
72
|
end
|
|
54
73
|
|
|
74
|
+
# Installs a gem into the Busser root's gem home.
|
|
75
|
+
#
|
|
76
|
+
# @param gem [String] the gem name
|
|
77
|
+
# @param version [String, nil] a requirement string, or nil for any version
|
|
78
|
+
# @return [Gem::Specification, nil] the spec that was installed
|
|
55
79
|
def install_gem(gem, version = nil)
|
|
56
80
|
Busser::RubyGems.install_gem(gem, version)
|
|
57
81
|
end
|
data/lib/busser/plugin.rb
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
module Busser
|
|
19
19
|
|
|
20
|
+
# Namespace that runner plugins define their classes inside.
|
|
20
21
|
module RunnerPlugin
|
|
21
22
|
end
|
|
22
23
|
|
|
@@ -28,10 +29,17 @@ module Busser
|
|
|
28
29
|
|
|
29
30
|
module_function
|
|
30
31
|
|
|
32
|
+
# @param plugin_name [String] short plugin name, such as "bash"
|
|
33
|
+
# @return [String] the path to require for that plugin
|
|
31
34
|
def runner_plugin(plugin_name)
|
|
32
35
|
"busser/runner_plugin/#{plugin_name}"
|
|
33
36
|
end
|
|
34
37
|
|
|
38
|
+
# Require paths for the named plugins, or for every installed plugin.
|
|
39
|
+
#
|
|
40
|
+
# @param plugin_names [Array<String>, String, nil] plugin names, or nil for
|
|
41
|
+
# everything installed
|
|
42
|
+
# @return [Array<String>] require paths, without duplicates
|
|
35
43
|
def runner_plugins(plugin_names = nil)
|
|
36
44
|
if plugin_names
|
|
37
45
|
Array(plugin_names).map { |plugin| runner_plugin(plugin) }.uniq
|
|
@@ -46,33 +54,67 @@ module Busser
|
|
|
46
54
|
# duplicates made `busser test` run a suite twice and `busser plugin list`
|
|
47
55
|
# print it twice. The path is what gets required, and require resolves to
|
|
48
56
|
# the active version, so collapsing the repeats is safe.
|
|
57
|
+
# Require paths for every runner plugin installed on this machine.
|
|
58
|
+
#
|
|
59
|
+
# @return [Array<String>] require paths, without duplicates
|
|
49
60
|
def all_runner_plugins
|
|
50
61
|
Gem.find_files("busser/runner_plugin/*.rb").map do |file|
|
|
51
62
|
"busser/runner_plugin/#{File.basename(file).sub(/\.rb$/, "")}"
|
|
52
63
|
end.uniq
|
|
53
64
|
end
|
|
54
65
|
|
|
66
|
+
# Requires a plugin, exiting with a readable message rather than a
|
|
67
|
+
# backtrace if it cannot be loaded.
|
|
68
|
+
#
|
|
69
|
+
# @param plugin_path [String] the path to require
|
|
70
|
+
# @return [void]
|
|
55
71
|
def require!(plugin_path)
|
|
56
72
|
require plugin_path
|
|
57
73
|
rescue LoadError => e
|
|
58
74
|
Busser::UI.die "Could not load #{plugin_path} (#{e.class}: #{e.message})"
|
|
59
75
|
end
|
|
60
76
|
|
|
77
|
+
# @param klass [String, Symbol] a constant name inside
|
|
78
|
+
# {Busser::RunnerPlugin}
|
|
79
|
+
# @return [Class] the runner plugin class
|
|
61
80
|
def runner_class(klass)
|
|
62
81
|
Busser::RunnerPlugin.const_get(klass)
|
|
63
82
|
end
|
|
64
83
|
|
|
84
|
+
# Finds the gemspec a plugin was loaded from.
|
|
85
|
+
#
|
|
86
|
+
# A plugin being developed locally is not an installed gem, so the local
|
|
87
|
+
# gemspec is preferred when the plugin resolves inside the working tree.
|
|
88
|
+
#
|
|
89
|
+
# @param plugin_path [String] the plugin's require path
|
|
90
|
+
# @return [Gem::Specification] the spec the plugin belongs to
|
|
65
91
|
def gem_from_path(plugin_path)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
92
|
+
# Ask RubyGems first. Loading a gemspec *evaluates* it, and these
|
|
93
|
+
# gemspecs shell out to `git ls-files` to build their file list -- so
|
|
94
|
+
# asking the working tree first printed "fatal: not a git repository"
|
|
95
|
+
# into the middle of `busser plugin list` for every installed plugin.
|
|
96
|
+
# find_by_path answers from the installed specs without running anything.
|
|
97
|
+
Gem::Specification.find_by_path(plugin_path) ||
|
|
98
|
+
local_gemspec_for(plugin_path)
|
|
99
|
+
end
|
|
70
100
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
101
|
+
# Falls back to a gemspec in the working tree, which is how a plugin being
|
|
102
|
+
# developed locally -- and so not installed as a gem -- is resolved.
|
|
103
|
+
#
|
|
104
|
+
# @param plugin_path [String] the plugin's require path
|
|
105
|
+
# @return [Gem::Specification, nil] the spec, or nil if there is no local
|
|
106
|
+
# gemspec to read
|
|
107
|
+
def local_gemspec_for(plugin_path)
|
|
108
|
+
root = $LOAD_PATH.first
|
|
109
|
+
return nil if root.nil?
|
|
110
|
+
|
|
111
|
+
local_gem_path = File.expand_path(plugin_path, root)
|
|
112
|
+
return nil if Dir.glob("#{local_gem_path}#{Gem.suffix_pattern}").empty?
|
|
113
|
+
|
|
114
|
+
local_gemspec = File.join(File.dirname(root), "busser.gemspec")
|
|
115
|
+
return nil unless File.exist?(local_gemspec)
|
|
116
|
+
|
|
117
|
+
Gem::Specification.load(local_gemspec)
|
|
76
118
|
end
|
|
77
119
|
end
|
|
78
120
|
end
|
data/lib/busser/rubygems.rb
CHANGED
|
@@ -27,11 +27,24 @@ module Busser
|
|
|
27
27
|
|
|
28
28
|
module_function
|
|
29
29
|
|
|
30
|
+
# @param name [String] the gem name
|
|
31
|
+
# @param version [String, nil] a requirement string, or nil for any version
|
|
32
|
+
# @return [Boolean] true if a matching gem is already available
|
|
30
33
|
def gem_installed?(name, version)
|
|
31
34
|
version = Gem::Requirement.default unless version
|
|
32
35
|
! Gem::Dependency.new(name, version).matching_specs.empty?
|
|
33
36
|
end
|
|
34
37
|
|
|
38
|
+
# Installs a gem into GEM_HOME.
|
|
39
|
+
#
|
|
40
|
+
# RubyGems under bundler points Gem.dir at the bundle, which is not where
|
|
41
|
+
# Busser plugins belong, so GEM_HOME is applied explicitly before the
|
|
42
|
+
# install and the freshly installed spec is put on the load path by hand.
|
|
43
|
+
#
|
|
44
|
+
# @param gem_name [String] the gem name
|
|
45
|
+
# @param version [String, nil] a requirement string, or nil for any version
|
|
46
|
+
# @return [Gem::Specification, nil] the installed spec, or nil if the gem
|
|
47
|
+
# was not among those installed
|
|
35
48
|
def install_gem(gem_name, version)
|
|
36
49
|
version = Gem::Requirement.default unless version
|
|
37
50
|
|
|
@@ -54,6 +67,8 @@ module Busser
|
|
|
54
67
|
spec
|
|
55
68
|
end
|
|
56
69
|
|
|
70
|
+
# @return [Hash] options handed to RubyGems' dependency installer, with
|
|
71
|
+
# the install directory pinned to GEM_HOME
|
|
57
72
|
def rbg_options
|
|
58
73
|
@rbg_options ||= Gem::DependencyInstaller::DEFAULT_OPTIONS.merge(
|
|
59
74
|
suggest_alternate: false,
|
|
@@ -67,6 +82,11 @@ module Busser
|
|
|
67
82
|
)
|
|
68
83
|
end
|
|
69
84
|
|
|
85
|
+
# Runs a block with RubyGems' own progress output suppressed, unless the
|
|
86
|
+
# user asked for verbose output.
|
|
87
|
+
#
|
|
88
|
+
# @yield the block to run quietly
|
|
89
|
+
# @return [Object] whatever the block returned
|
|
70
90
|
def silence_gem_ui
|
|
71
91
|
interaction = Gem::DefaultUserInteraction.ui
|
|
72
92
|
unless Gem.configuration.really_verbose
|
|
@@ -34,6 +34,9 @@ class Busser::RunnerPlugin::Dummy < Busser::RunnerPlugin::Base
|
|
|
34
34
|
create_file("#{dummy_path}/foobar.txt", "The Dummy Driver.")
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
+
# Prints a line so Busser's own suite can prove a plugin ran.
|
|
38
|
+
#
|
|
39
|
+
# @return [void]
|
|
37
40
|
def test
|
|
38
41
|
banner "[dummy] Running"
|
|
39
42
|
if File.exist?(File.join(suite_path("dummy"), "foobar.txt"))
|
data/lib/busser/runner_plugin.rb
CHANGED
|
@@ -27,6 +27,11 @@ module Busser
|
|
|
27
27
|
#
|
|
28
28
|
class Base < Busser::Thor::BaseGroup
|
|
29
29
|
|
|
30
|
+
# Declares work to run once, when Busser installs this plugin -- which
|
|
31
|
+
# is where a plugin installs the test framework it drives.
|
|
32
|
+
#
|
|
33
|
+
# @yield the postinstall body, evaluated on the plugin instance
|
|
34
|
+
# @return [void]
|
|
30
35
|
def self.postinstall(&block)
|
|
31
36
|
(class << self; self; end).send(:define_method, :run_postinstall) do
|
|
32
37
|
klass = Class.new(Busser::Thor::BaseGroup) do
|
data/lib/busser/thor.rb
CHANGED
|
@@ -22,6 +22,7 @@ require "busser/ui"
|
|
|
22
22
|
|
|
23
23
|
module Busser
|
|
24
24
|
|
|
25
|
+
# Thor base classes preloaded with Busser's helpers and output methods.
|
|
25
26
|
module Thor
|
|
26
27
|
|
|
27
28
|
# Base class for all Thor subclasses which includes useful mixins.
|
|
@@ -33,6 +34,17 @@ module Busser
|
|
|
33
34
|
include Helpers
|
|
34
35
|
include UI
|
|
35
36
|
include ::Thor::Actions
|
|
37
|
+
|
|
38
|
+
# Thor exits 0 when a command fails unless this is true, and warns on
|
|
39
|
+
# every failure that it is not set. Busser is a test runner: a failure
|
|
40
|
+
# has to be a non-zero exit or CI reports a red suite as green. Thor 2
|
|
41
|
+
# makes this the default; setting it now silences the deprecation on
|
|
42
|
+
# every failing run and pins the behaviour we already rely on.
|
|
43
|
+
#
|
|
44
|
+
# @return [true]
|
|
45
|
+
def self.exit_on_failure?
|
|
46
|
+
true
|
|
47
|
+
end
|
|
36
48
|
end
|
|
37
49
|
|
|
38
50
|
# Base class for all Thor Group subclasses which includes useful mixins.
|
|
@@ -44,6 +56,17 @@ module Busser
|
|
|
44
56
|
include Helpers
|
|
45
57
|
include UI
|
|
46
58
|
include ::Thor::Actions
|
|
59
|
+
|
|
60
|
+
# Thor exits 0 when a command fails unless this is true, and warns on
|
|
61
|
+
# every failure that it is not set. Busser is a test runner: a failure
|
|
62
|
+
# has to be a non-zero exit or CI reports a red suite as green. Thor 2
|
|
63
|
+
# makes this the default; setting it now silences the deprecation on
|
|
64
|
+
# every failing run and pins the behaviour we already rely on.
|
|
65
|
+
#
|
|
66
|
+
# @return [true]
|
|
67
|
+
def self.exit_on_failure?
|
|
68
|
+
true
|
|
69
|
+
end
|
|
47
70
|
end
|
|
48
71
|
end
|
|
49
72
|
end
|
data/lib/busser/ui.rb
CHANGED
|
@@ -29,30 +29,56 @@ module Busser
|
|
|
29
29
|
|
|
30
30
|
# Thor::Shell's delegated methods are not mixed into this module, so
|
|
31
31
|
# provide the two output primitives it relies on.
|
|
32
|
+
# @param msg [String] text to write to stdout
|
|
33
|
+
# @return [void]
|
|
32
34
|
def say(msg)
|
|
33
35
|
$stdout.puts(msg)
|
|
34
36
|
end
|
|
35
37
|
|
|
38
|
+
# @param msg [String] text to write to stderr
|
|
39
|
+
# @return [void]
|
|
36
40
|
def error(msg)
|
|
37
41
|
$stderr.puts(msg)
|
|
38
42
|
end
|
|
39
43
|
|
|
44
|
+
# Announces a step, at the top level of the output.
|
|
45
|
+
#
|
|
46
|
+
# @param msg [String] the message
|
|
47
|
+
# @return [void]
|
|
40
48
|
def banner(msg)
|
|
41
49
|
say("-----> #{msg}")
|
|
42
50
|
end
|
|
43
51
|
|
|
52
|
+
# Reports detail beneath a banner.
|
|
53
|
+
#
|
|
54
|
+
# @param msg [String] the message
|
|
55
|
+
# @return [void]
|
|
44
56
|
def info(msg)
|
|
45
57
|
say(" #{msg}")
|
|
46
58
|
end
|
|
47
59
|
|
|
60
|
+
# Reports something the user should notice but which is not fatal.
|
|
61
|
+
#
|
|
62
|
+
# @param msg [String] the message
|
|
63
|
+
# @return [void]
|
|
48
64
|
def warn(msg)
|
|
49
65
|
say(">>>>>> #{msg}")
|
|
50
66
|
end
|
|
51
67
|
|
|
68
|
+
# Reports a failure, on stderr.
|
|
69
|
+
#
|
|
70
|
+
# @param msg [String] the message
|
|
71
|
+
# @return [void]
|
|
52
72
|
def fatal(msg)
|
|
53
73
|
error("!!!!!! #{msg}")
|
|
54
74
|
end
|
|
55
75
|
|
|
76
|
+
# Runs a shell command, exiting with a diagnosis if it fails.
|
|
77
|
+
#
|
|
78
|
+
# @param cmd [String] the command line
|
|
79
|
+
# @param config [Hash] options passed through to Thor's runner
|
|
80
|
+
# @return [true] if the command succeeded
|
|
81
|
+
# @see #handle_command
|
|
56
82
|
def run!(cmd, config = {})
|
|
57
83
|
config = { capture: false, verbose: false }.merge(config)
|
|
58
84
|
|
|
@@ -61,6 +87,13 @@ module Busser
|
|
|
61
87
|
end
|
|
62
88
|
end
|
|
63
89
|
|
|
90
|
+
# Runs a Ruby script with the current interpreter, exiting with a
|
|
91
|
+
# diagnosis if it fails.
|
|
92
|
+
#
|
|
93
|
+
# @param cmd [String] the script and its arguments
|
|
94
|
+
# @param config [Hash] options passed through to Thor's runner
|
|
95
|
+
# @return [true] if the script succeeded
|
|
96
|
+
# @see #handle_command
|
|
64
97
|
def run_ruby_script!(cmd, config = {})
|
|
65
98
|
config = { capture: false, verbose: false }.merge(config)
|
|
66
99
|
|
|
@@ -69,15 +102,37 @@ module Busser
|
|
|
69
102
|
end
|
|
70
103
|
end
|
|
71
104
|
|
|
105
|
+
# Reports a failure and exits.
|
|
106
|
+
#
|
|
107
|
+
# @param msg [String] the message
|
|
108
|
+
# @param exitstatus [Integer] the status to exit with
|
|
109
|
+
# @return [void] does not return
|
|
72
110
|
def die(msg, exitstatus = 1)
|
|
73
111
|
fatal(msg)
|
|
74
112
|
exit(exitstatus)
|
|
75
113
|
end
|
|
76
114
|
|
|
115
|
+
# Wrapped so tests can stub it.
|
|
116
|
+
#
|
|
117
|
+
# @return [Process::Status, nil] the status of the last child process
|
|
77
118
|
def status
|
|
78
119
|
$?
|
|
79
120
|
end
|
|
80
121
|
|
|
122
|
+
# Runs a block and turns however the child process ended into a readable
|
|
123
|
+
# message and a matching exit status.
|
|
124
|
+
#
|
|
125
|
+
# Three endings are distinguished because they mean different things to
|
|
126
|
+
# someone reading CI output: a nil status usually means the machine ran out
|
|
127
|
+
# of memory before the child could report; a signal means something killed
|
|
128
|
+
# the run, typically the out of memory killer; and an exit code means the
|
|
129
|
+
# command itself failed.
|
|
130
|
+
#
|
|
131
|
+
# @param type [String] what was run, for the message
|
|
132
|
+
# @param cmd [String] the command line, for the message
|
|
133
|
+
# @yield runs the command
|
|
134
|
+
# @return [true] if the command succeeded
|
|
135
|
+
# @raise [StandardError] re-raised if the block itself raised
|
|
81
136
|
def handle_command(type, cmd)
|
|
82
137
|
begin
|
|
83
138
|
yield
|
data/lib/busser/version.rb
CHANGED
data/release-please-config.json
CHANGED
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
"changelog-path": "CHANGELOG.md",
|
|
8
8
|
"release-type": "ruby",
|
|
9
9
|
"include-component-in-tag": false,
|
|
10
|
-
"version-file": "lib/busser/version.rb"
|
|
10
|
+
"version-file": "lib/busser/version.rb",
|
|
11
|
+
"bump-minor-pre-major": true,
|
|
12
|
+
"bump-patch-for-minor-pre-major": true
|
|
11
13
|
}
|
|
12
14
|
}
|
|
13
15
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require_relative "../../spec_helper"
|
|
2
|
+
|
|
3
|
+
require "busser/command/plugin_install"
|
|
4
|
+
|
|
5
|
+
describe Busser::Command::PluginInstall do
|
|
6
|
+
let(:command) { Busser::Command::PluginInstall.new([%w{busser-dummy}]) }
|
|
7
|
+
|
|
8
|
+
describe "#drop_ssl_verify_peer" do
|
|
9
|
+
# VERIFY_PEER is a process-global constant, so anything that leaves it
|
|
10
|
+
# lowered affects every later gem download in the same run. `busser plugin
|
|
11
|
+
# install` takes a list of plugins, which is exactly that situation.
|
|
12
|
+
it "lowers verification for the block" do
|
|
13
|
+
inside = nil
|
|
14
|
+
command.send(:drop_ssl_verify_peer) { inside = OpenSSL::SSL::VERIFY_PEER }
|
|
15
|
+
|
|
16
|
+
_(inside).must_equal OpenSSL::SSL::VERIFY_NONE
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "restores verification afterwards" do
|
|
20
|
+
before = OpenSSL::SSL::VERIFY_PEER
|
|
21
|
+
command.send(:drop_ssl_verify_peer) { nil }
|
|
22
|
+
|
|
23
|
+
_(OpenSSL::SSL::VERIFY_PEER).must_equal before
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# The regression this guards. A postinstall raising is not exotic: it is
|
|
27
|
+
# how a plugin reports that it could not install its test framework.
|
|
28
|
+
it "restores verification when the block raises" do
|
|
29
|
+
before = OpenSSL::SSL::VERIFY_PEER
|
|
30
|
+
|
|
31
|
+
_(proc { command.send(:drop_ssl_verify_peer) { raise "postinstall blew up" } })
|
|
32
|
+
.must_raise RuntimeError
|
|
33
|
+
|
|
34
|
+
_(OpenSSL::SSL::VERIFY_PEER).must_equal before
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "restores verification when the block throws" do
|
|
38
|
+
before = OpenSSL::SSL::VERIFY_PEER
|
|
39
|
+
catch(:done) { command.send(:drop_ssl_verify_peer) { throw :done } }
|
|
40
|
+
|
|
41
|
+
_(OpenSSL::SSL::VERIFY_PEER).must_equal before
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require_relative "../../spec_helper"
|
|
2
|
+
|
|
3
|
+
require "busser/command/plugin_list"
|
|
4
|
+
|
|
5
|
+
describe Busser::Command::PluginList do
|
|
6
|
+
let(:command) { Busser::Command::PluginList.new }
|
|
7
|
+
|
|
8
|
+
describe "#plugin_data" do
|
|
9
|
+
def stub_plugins(paths, specs = {})
|
|
10
|
+
Busser::Plugin.stubs(:runner_plugins).returns(paths)
|
|
11
|
+
paths.each do |path|
|
|
12
|
+
Busser::Plugin.stubs(:gem_from_path).with(path).returns(specs[path])
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def spec_for(name, version)
|
|
17
|
+
Gem::Specification.new { |s| s.name = name; s.version = version }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "reports each plugin's short name and version" do
|
|
21
|
+
stub_plugins(["busser/runner_plugin/bash"],
|
|
22
|
+
"busser/runner_plugin/bash" => spec_for("busser-bash", "0.2.0"))
|
|
23
|
+
|
|
24
|
+
_(command.send(:plugin_data)).must_equal [["bash", Gem::Version.new("0.2.0")]]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# dummy is a fixture shipped inside busser for its own tests, not something
|
|
28
|
+
# anyone installed. `busser test` already passes over it, so listing it was
|
|
29
|
+
# inconsistent as well as confusing.
|
|
30
|
+
it "leaves out the internal dummy runner" do
|
|
31
|
+
stub_plugins(["busser/runner_plugin/dummy", "busser/runner_plugin/bash"],
|
|
32
|
+
"busser/runner_plugin/bash" => spec_for("busser-bash", "0.2.0"))
|
|
33
|
+
|
|
34
|
+
_(command.send(:plugin_data).map(&:first)).must_equal %w{bash}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "reports a nil version rather than raising when no spec is found" do
|
|
38
|
+
stub_plugins(["busser/runner_plugin/bash"])
|
|
39
|
+
|
|
40
|
+
_(command.send(:plugin_data)).must_equal [["bash", nil]]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "returns an empty list when dummy is all there is" do
|
|
44
|
+
stub_plugins(["busser/runner_plugin/dummy"])
|
|
45
|
+
|
|
46
|
+
_(command.send(:plugin_data)).must_be_empty
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require_relative "../../spec_helper"
|
|
2
|
+
|
|
3
|
+
require "shellwords"
|
|
4
|
+
require "busser/command/test"
|
|
5
|
+
|
|
6
|
+
describe Busser::Command::Test do
|
|
7
|
+
describe ".prepare_sh_command" do
|
|
8
|
+
it "runs the script with sh" do
|
|
9
|
+
cmd = Busser::Command::Test.prepare_sh_command("/opt/busser/suites/bats/prepare.sh")
|
|
10
|
+
|
|
11
|
+
_(Shellwords.split(cmd)).must_equal ["/bin/sh", "/opt/busser/suites/bats/prepare.sh"]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# BUSSER_ROOT is chosen by whoever runs Busser, and Test Kitchen puts it
|
|
15
|
+
# under a path the user controls. Unquoted, a space split the path and sh
|
|
16
|
+
# was handed a fragment.
|
|
17
|
+
it "quotes a path containing spaces" do
|
|
18
|
+
cmd = Busser::Command::Test.prepare_sh_command("/tmp/my tests/suites/bats/prepare.sh")
|
|
19
|
+
|
|
20
|
+
_(Shellwords.split(cmd))
|
|
21
|
+
.must_equal ["/bin/sh", "/tmp/my tests/suites/bats/prepare.sh"]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "neutralises shell metacharacters in the path" do
|
|
25
|
+
cmd = Busser::Command::Test.prepare_sh_command("/tmp/a;touch pwned/prepare.sh")
|
|
26
|
+
|
|
27
|
+
_(Shellwords.split(cmd)).must_equal ["/bin/sh", "/tmp/a;touch pwned/prepare.sh"]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "accepts a Pathname" do
|
|
31
|
+
cmd = Busser::Command::Test.prepare_sh_command(Pathname.new("/a/prepare.sh"))
|
|
32
|
+
|
|
33
|
+
_(Shellwords.split(cmd).last).must_equal "/a/prepare.sh"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
data/spec/busser/helpers_spec.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
require_relative
|
|
1
|
+
require_relative "../spec_helper"
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "busser/helpers"
|
|
4
4
|
|
|
5
5
|
describe Busser::Helpers do
|
|
6
6
|
|
|
@@ -25,16 +25,16 @@ describe Busser::Helpers do
|
|
|
25
25
|
|
|
26
26
|
describe "with a custom root path" do
|
|
27
27
|
|
|
28
|
-
before { ENV[
|
|
29
|
-
after { ENV[
|
|
28
|
+
before { ENV["_SPEC_BUSSER_ROOT"] = ENV["BUSSER_ROOT"] }
|
|
29
|
+
after { ENV["BUSSER_ROOT"] = ENV.delete("_SPEC_BUSSER_ROOT") }
|
|
30
30
|
|
|
31
31
|
it "returns a base path if no suite name is given" do
|
|
32
|
-
ENV[
|
|
32
|
+
ENV["BUSSER_ROOT"] = "/path/to/busser"
|
|
33
33
|
_(suite_path.to_s).must_match %r{/path/to/busser/suites$}
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
it "returns a suite path given a suite name" do
|
|
37
|
-
ENV[
|
|
37
|
+
ENV["BUSSER_ROOT"] = "/path/to/busser"
|
|
38
38
|
_(suite_path("fuzzy").to_s).must_match %r{/path/to/busser/suites/fuzzy$}
|
|
39
39
|
end
|
|
40
40
|
end
|
|
@@ -59,16 +59,16 @@ describe Busser::Helpers do
|
|
|
59
59
|
|
|
60
60
|
describe "with a custom root path" do
|
|
61
61
|
|
|
62
|
-
before { ENV[
|
|
63
|
-
after { ENV[
|
|
62
|
+
before { ENV["_SPEC_BUSSER_ROOT"] = ENV["BUSSER_ROOT"] }
|
|
63
|
+
after { ENV["BUSSER_ROOT"] = ENV.delete("_SPEC_BUSSER_ROOT") }
|
|
64
64
|
|
|
65
65
|
it "returns a base path if no product name is given" do
|
|
66
|
-
ENV[
|
|
66
|
+
ENV["BUSSER_ROOT"] = "/path/to/busser"
|
|
67
67
|
_(vendor_path.to_s).must_match %r{/path/to/busser/vendor$}
|
|
68
68
|
end
|
|
69
69
|
|
|
70
70
|
it "returns a suite path given a product name" do
|
|
71
|
-
ENV[
|
|
71
|
+
ENV["BUSSER_ROOT"] = "/path/to/busser"
|
|
72
72
|
_(vendor_path("maximal").to_s).must_match \
|
|
73
73
|
%r{/path/to/busser/vendor/maximal$}
|
|
74
74
|
end
|
data/spec/busser/plugin_spec.rb
CHANGED
data/spec/busser/ui_spec.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
require_relative
|
|
1
|
+
require_relative "../spec_helper"
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "busser/ui"
|
|
4
4
|
|
|
5
5
|
# Dummy class containing diagnostic methods approximating Thor mixins
|
|
6
6
|
class SneakyUI
|
|
@@ -11,7 +11,7 @@ class SneakyUI
|
|
|
11
11
|
attr_accessor :status
|
|
12
12
|
|
|
13
13
|
def say(msg)
|
|
14
|
-
|
|
14
|
+
msg
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def error(msg)
|
|
@@ -111,7 +111,7 @@ describe Busser::UI do
|
|
|
111
111
|
|
|
112
112
|
_(ui.run_args).must_equal([
|
|
113
113
|
"doitpls",
|
|
114
|
-
{ :
|
|
114
|
+
{ capture: false, verbose: false },
|
|
115
115
|
])
|
|
116
116
|
end
|
|
117
117
|
|
|
@@ -181,16 +181,16 @@ describe Busser::UI do
|
|
|
181
181
|
|
|
182
182
|
_(ui.run_ruby_script_args).must_equal([
|
|
183
183
|
"theworks.rb",
|
|
184
|
-
{ :
|
|
184
|
+
{ capture: false, verbose: false },
|
|
185
185
|
])
|
|
186
186
|
end
|
|
187
187
|
|
|
188
188
|
it "calls #run_ruby_script with correct default options" do
|
|
189
|
-
ui.invoke_run_ruby_script!("theworks.rb", :
|
|
189
|
+
ui.invoke_run_ruby_script!("theworks.rb", verbose: true)
|
|
190
190
|
|
|
191
191
|
_(ui.run_ruby_script_args).must_equal([
|
|
192
192
|
"theworks.rb",
|
|
193
|
-
{ :
|
|
193
|
+
{ capture: false, verbose: true },
|
|
194
194
|
])
|
|
195
195
|
end
|
|
196
196
|
|