busser 0.7.1 → 0.9.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 +5 -5
- data/.github/workflows/ci.yml +32 -0
- data/.github/workflows/pr-title.yml +28 -0
- data/.github/workflows/publish.yml +45 -0
- data/.gitignore +0 -1
- data/.markdownlint.yaml +6 -0
- data/.release-please-manifest.json +3 -0
- data/.rubocop.yml +9 -0
- data/.yamllint +6 -0
- data/CHANGELOG.md +44 -0
- data/CONTRIBUTING.md +103 -0
- data/Gemfile +10 -6
- data/README.md +82 -21
- data/Rakefile +6 -23
- data/bin/busser +2 -4
- data/busser.gemspec +12 -15
- data/features/deserialize_command.feature +4 -1
- data/features/plugin_install_command.feature +1 -1
- data/features/support/env.rb +4 -16
- data/lib/busser/cli.rb +6 -7
- data/lib/busser/command/deserialize.rb +16 -11
- data/lib/busser/command/plugin.rb +4 -5
- data/lib/busser/command/plugin_create.rb +23 -24
- data/lib/busser/command/plugin_install.rb +21 -14
- data/lib/busser/command/plugin_list.rb +3 -4
- data/lib/busser/command/setup.rb +17 -18
- data/lib/busser/command/suite.rb +3 -4
- data/lib/busser/command/suite_cleanup.rb +3 -3
- data/lib/busser/command/suite_path.rb +2 -3
- data/lib/busser/command/test.rb +4 -4
- data/lib/busser/cucumber/hooks.rb +1 -9
- data/lib/busser/cucumber.rb +69 -49
- data/lib/busser/helpers.rb +4 -5
- data/lib/busser/plugin.rb +12 -6
- data/lib/busser/rubygems.rb +35 -39
- data/lib/busser/runner_plugin/dummy.rb +2 -3
- data/lib/busser/runner_plugin.rb +1 -2
- data/lib/busser/thor.rb +3 -4
- data/lib/busser/ui.rb +15 -5
- data/lib/busser/version.rb +1 -2
- data/lib/busser.rb +3 -4
- data/release-please-config.json +13 -0
- data/renovate.json +8 -0
- data/spec/busser/command/deserialize_spec.rb +110 -0
- data/spec/busser/helpers_spec.rb +11 -10
- data/spec/busser/plugin_spec.rb +133 -0
- data/spec/busser/ui_spec.rb +35 -29
- data/spec/spec_helper.rb +1 -7
- metadata +29 -89
- data/.cane +0 -0
- data/.simplecov +0 -10
- data/.travis.yml +0 -52
- data/Guardfile +0 -18
data/lib/busser/helpers.rb
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
|
2
1
|
#
|
|
3
2
|
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
|
4
3
|
#
|
|
@@ -16,9 +15,9 @@
|
|
|
16
15
|
# See the License for the specific language governing permissions and
|
|
17
16
|
# limitations under the License.
|
|
18
17
|
|
|
19
|
-
require
|
|
18
|
+
require "pathname" unless defined?(Pathname)
|
|
20
19
|
|
|
21
|
-
require
|
|
20
|
+
require "busser/rubygems"
|
|
22
21
|
|
|
23
22
|
module Busser
|
|
24
23
|
|
|
@@ -43,12 +42,12 @@ module Busser
|
|
|
43
42
|
end
|
|
44
43
|
|
|
45
44
|
def root_path
|
|
46
|
-
Pathname.new(ENV[
|
|
45
|
+
Pathname.new(ENV["BUSSER_ROOT"] || "/opt/busser")
|
|
47
46
|
end
|
|
48
47
|
|
|
49
48
|
def chef_apply(config = {}, &block)
|
|
50
49
|
warn "Apologies, but Busser no longer supports the chef_apply helper," +
|
|
51
|
-
" so the contents of this block will not be
|
|
50
|
+
" so the contents of this block will not be executed. Please refactor" +
|
|
52
51
|
" your code to use Thor actions, shell out commands or another" +
|
|
53
52
|
" strategy"
|
|
54
53
|
end
|
data/lib/busser/plugin.rb
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
|
2
1
|
#
|
|
3
2
|
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
|
4
3
|
#
|
|
@@ -35,16 +34,22 @@ module Busser
|
|
|
35
34
|
|
|
36
35
|
def runner_plugins(plugin_names = nil)
|
|
37
36
|
if plugin_names
|
|
38
|
-
Array(plugin_names).map { |plugin| runner_plugin(plugin) }
|
|
37
|
+
Array(plugin_names).map { |plugin| runner_plugin(plugin) }.uniq
|
|
39
38
|
else
|
|
40
39
|
all_runner_plugins
|
|
41
40
|
end
|
|
42
41
|
end
|
|
43
42
|
|
|
43
|
+
# Gem.find_files searches every installed gem version, not just the
|
|
44
|
+
# newest, so a machine holding two versions of a plugin gem reports that
|
|
45
|
+
# plugin twice. Callers treat each entry as one suite to run, so the
|
|
46
|
+
# duplicates made `busser test` run a suite twice and `busser plugin list`
|
|
47
|
+
# print it twice. The path is what gets required, and require resolves to
|
|
48
|
+
# the active version, so collapsing the repeats is safe.
|
|
44
49
|
def all_runner_plugins
|
|
45
|
-
Gem.find_files(
|
|
46
|
-
"busser/runner_plugin/#{File.basename(file).sub(/\.rb$/,
|
|
47
|
-
end
|
|
50
|
+
Gem.find_files("busser/runner_plugin/*.rb").map do |file|
|
|
51
|
+
"busser/runner_plugin/#{File.basename(file).sub(/\.rb$/, "")}"
|
|
52
|
+
end.uniq
|
|
48
53
|
end
|
|
49
54
|
|
|
50
55
|
def require!(plugin_path)
|
|
@@ -60,7 +65,8 @@ module Busser
|
|
|
60
65
|
def gem_from_path(plugin_path)
|
|
61
66
|
local_gem_path = "#{File.expand_path(plugin_path, $LOAD_PATH.first)}"
|
|
62
67
|
local_gemspec = File.join(
|
|
63
|
-
File.dirname($LOAD_PATH.first), "busser.gemspec"
|
|
68
|
+
File.dirname($LOAD_PATH.first), "busser.gemspec"
|
|
69
|
+
)
|
|
64
70
|
|
|
65
71
|
if ! Dir.glob("#{local_gem_path}#{Gem.suffix_pattern}").empty?
|
|
66
72
|
Gem::Specification.load(File.expand_path(local_gemspec))
|
data/lib/busser/rubygems.rb
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
|
2
1
|
#
|
|
3
2
|
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
|
4
3
|
#
|
|
@@ -16,7 +15,7 @@
|
|
|
16
15
|
# See the License for the specific language governing permissions and
|
|
17
16
|
# limitations under the License.
|
|
18
17
|
|
|
19
|
-
require
|
|
18
|
+
require "rubygems/dependency_installer"
|
|
20
19
|
|
|
21
20
|
module Busser
|
|
22
21
|
|
|
@@ -29,56 +28,53 @@ module Busser
|
|
|
29
28
|
module_function
|
|
30
29
|
|
|
31
30
|
def gem_installed?(name, version)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if version.nil?
|
|
36
|
-
! installed.empty?
|
|
37
|
-
else
|
|
38
|
-
installed.find { |spec| spec.version.to_s == version }
|
|
39
|
-
end
|
|
31
|
+
version = Gem::Requirement.default unless version
|
|
32
|
+
! Gem::Dependency.new(name, version).matching_specs.empty?
|
|
40
33
|
end
|
|
41
34
|
|
|
42
|
-
def install_gem(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
Gem.
|
|
46
|
-
|
|
47
|
-
|
|
35
|
+
def install_gem(gem_name, version)
|
|
36
|
+
version = Gem::Requirement.default unless version
|
|
37
|
+
|
|
38
|
+
# A bundler-managed environment can leave Gem.dir pointing at the bundle,
|
|
39
|
+
# which is not where busser plugins belong. Point RubyGems at GEM_HOME.
|
|
40
|
+
gem_home = ENV.fetch("GEM_HOME", nil)
|
|
41
|
+
Gem.use_paths(gem_home, Gem.path) if gem_home && Gem.dir != gem_home
|
|
48
42
|
|
|
49
|
-
|
|
50
|
-
|
|
43
|
+
inst = Gem::DependencyInstaller.new(rbg_options)
|
|
44
|
+
specs = inst.install(gem_name, Gem::Requirement.create(version))
|
|
51
45
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
# collection of AvailableSet::Tuple structs
|
|
60
|
-
available_gems.pick_best!
|
|
61
|
-
best_gem = available_gems.set.first
|
|
62
|
-
best_gem && [best_gem.spec, best_gem.source]
|
|
46
|
+
Gem.clear_paths
|
|
47
|
+
spec = specs.find { |s| s.name == gem_name }
|
|
48
|
+
# Modern RubyGems does not put a freshly installed gem on the load path.
|
|
49
|
+
# Add it directly rather than activating, so installing a second version
|
|
50
|
+
# in the same process does not raise a Gem::LoadError conflict.
|
|
51
|
+
spec&.full_require_paths&.each do |path|
|
|
52
|
+
$LOAD_PATH.unshift(path) unless $LOAD_PATH.include?(path)
|
|
63
53
|
end
|
|
54
|
+
spec
|
|
55
|
+
end
|
|
64
56
|
|
|
65
|
-
|
|
57
|
+
def rbg_options
|
|
58
|
+
@rbg_options ||= Gem::DependencyInstaller::DEFAULT_OPTIONS.merge(
|
|
59
|
+
suggest_alternate: false,
|
|
60
|
+
version: Gem::Requirement.default,
|
|
61
|
+
without_groups: [],
|
|
62
|
+
minimal_deps: true,
|
|
63
|
+
# Install into GEM_HOME explicitly. Under bundler Gem.dir points at the
|
|
64
|
+
# bundle path, which is not where busser plugins belong.
|
|
65
|
+
install_dir: ENV.fetch("GEM_HOME", nil),
|
|
66
|
+
http_proxy: ENV.fetch("http_proxy", ENV.fetch("HTTP_PROXY", nil))
|
|
67
|
+
)
|
|
66
68
|
end
|
|
67
69
|
|
|
68
70
|
def silence_gem_ui
|
|
69
71
|
interaction = Gem::DefaultUserInteraction.ui
|
|
70
|
-
|
|
72
|
+
unless Gem.configuration.really_verbose
|
|
73
|
+
Gem::DefaultUserInteraction.ui = Gem::SilentUI.new
|
|
74
|
+
end
|
|
71
75
|
yield
|
|
72
76
|
ensure
|
|
73
77
|
Gem::DefaultUserInteraction.ui = interaction
|
|
74
78
|
end
|
|
75
|
-
|
|
76
|
-
def dep_installer
|
|
77
|
-
Gem::DependencyInstaller.new
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def new_dep(name, version = nil)
|
|
81
|
-
Gem::Dependency.new(name, version)
|
|
82
|
-
end
|
|
83
79
|
end
|
|
84
80
|
end
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
|
2
1
|
#
|
|
3
2
|
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
|
4
3
|
#
|
|
@@ -16,7 +15,7 @@
|
|
|
16
15
|
# See the License for the specific language governing permissions and
|
|
17
16
|
# limitations under the License.
|
|
18
17
|
|
|
19
|
-
require
|
|
18
|
+
require "busser/runner_plugin"
|
|
20
19
|
|
|
21
20
|
# Dummy runner plugin for Busser.
|
|
22
21
|
#
|
|
@@ -37,7 +36,7 @@ class Busser::RunnerPlugin::Dummy < Busser::RunnerPlugin::Base
|
|
|
37
36
|
|
|
38
37
|
def test
|
|
39
38
|
banner "[dummy] Running"
|
|
40
|
-
if File.
|
|
39
|
+
if File.exist?(File.join(suite_path("dummy"), "foobar.txt"))
|
|
41
40
|
info "[dummy] The postinstall script has been called"
|
|
42
41
|
else
|
|
43
42
|
warn "[dummy] The postinstall script was not called"
|
data/lib/busser/runner_plugin.rb
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
|
2
1
|
#
|
|
3
2
|
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
|
4
3
|
#
|
|
@@ -16,7 +15,7 @@
|
|
|
16
15
|
# See the License for the specific language governing permissions and
|
|
17
16
|
# limitations under the License.
|
|
18
17
|
|
|
19
|
-
require
|
|
18
|
+
require "busser/thor"
|
|
20
19
|
|
|
21
20
|
module Busser
|
|
22
21
|
|
data/lib/busser/thor.rb
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
|
2
1
|
#
|
|
3
2
|
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
|
4
3
|
#
|
|
@@ -16,10 +15,10 @@
|
|
|
16
15
|
# See the License for the specific language governing permissions and
|
|
17
16
|
# limitations under the License.
|
|
18
17
|
|
|
19
|
-
require
|
|
18
|
+
require "thor" unless defined?(Thor)
|
|
20
19
|
|
|
21
|
-
require
|
|
22
|
-
require
|
|
20
|
+
require "busser/helpers"
|
|
21
|
+
require "busser/ui"
|
|
23
22
|
|
|
24
23
|
module Busser
|
|
25
24
|
|
data/lib/busser/ui.rb
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
|
2
1
|
#
|
|
3
2
|
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
|
4
3
|
#
|
|
@@ -16,7 +15,7 @@
|
|
|
16
15
|
# See the License for the specific language governing permissions and
|
|
17
16
|
# limitations under the License.
|
|
18
17
|
|
|
19
|
-
require
|
|
18
|
+
require "thor/shell"
|
|
20
19
|
|
|
21
20
|
module Busser
|
|
22
21
|
|
|
@@ -28,6 +27,16 @@ module Busser
|
|
|
28
27
|
|
|
29
28
|
module_function
|
|
30
29
|
|
|
30
|
+
# Thor::Shell's delegated methods are not mixed into this module, so
|
|
31
|
+
# provide the two output primitives it relies on.
|
|
32
|
+
def say(msg)
|
|
33
|
+
$stdout.puts(msg)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def error(msg)
|
|
37
|
+
$stderr.puts(msg)
|
|
38
|
+
end
|
|
39
|
+
|
|
31
40
|
def banner(msg)
|
|
32
41
|
say("-----> #{msg}")
|
|
33
42
|
end
|
|
@@ -45,7 +54,7 @@ module Busser
|
|
|
45
54
|
end
|
|
46
55
|
|
|
47
56
|
def run!(cmd, config = {})
|
|
48
|
-
config = { :
|
|
57
|
+
config = { capture: false, verbose: false }.merge(config)
|
|
49
58
|
|
|
50
59
|
handle_command("Command", cmd) do
|
|
51
60
|
run(cmd, config)
|
|
@@ -53,7 +62,7 @@ module Busser
|
|
|
53
62
|
end
|
|
54
63
|
|
|
55
64
|
def run_ruby_script!(cmd, config = {})
|
|
56
|
-
config = { :
|
|
65
|
+
config = { capture: false, verbose: false }.merge(config)
|
|
57
66
|
|
|
58
67
|
handle_command("Ruby Script", cmd) do
|
|
59
68
|
run_ruby_script(cmd, config)
|
|
@@ -75,7 +84,8 @@ module Busser
|
|
|
75
84
|
rescue => e
|
|
76
85
|
fatal(
|
|
77
86
|
"#{type} [#{cmd}] raised an exception: #{e.message}\n" +
|
|
78
|
-
e.backtrace.join("\n")
|
|
87
|
+
e.backtrace.join("\n")
|
|
88
|
+
)
|
|
79
89
|
raise
|
|
80
90
|
end
|
|
81
91
|
|
data/lib/busser/version.rb
CHANGED
data/lib/busser.rb
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
|
2
1
|
#
|
|
3
2
|
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
|
4
3
|
#
|
|
@@ -16,9 +15,9 @@
|
|
|
16
15
|
# See the License for the specific language governing permissions and
|
|
17
16
|
# limitations under the License.
|
|
18
17
|
|
|
19
|
-
require
|
|
18
|
+
require "pathname" unless defined?(Pathname)
|
|
20
19
|
|
|
21
|
-
require
|
|
20
|
+
require "busser/version"
|
|
22
21
|
|
|
23
22
|
# Busser - Runs tests for projects in Test Kitchen.
|
|
24
23
|
#
|
|
@@ -30,6 +29,6 @@ module Busser
|
|
|
30
29
|
#
|
|
31
30
|
# @return [Pathname] root path of gem
|
|
32
31
|
def self.source_root
|
|
33
|
-
@source_root ||= Pathname.new(File.expand_path(
|
|
32
|
+
@source_root ||= Pathname.new(File.expand_path("..", __dir__))
|
|
34
33
|
end
|
|
35
34
|
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
|
|
3
|
+
"bootstrap-sha": "9ff44ee27bd8863c0a197d9976c25623c8c05fc0",
|
|
4
|
+
"packages": {
|
|
5
|
+
".": {
|
|
6
|
+
"package-name": "busser",
|
|
7
|
+
"changelog-path": "CHANGELOG.md",
|
|
8
|
+
"release-type": "ruby",
|
|
9
|
+
"include-component-in-tag": false,
|
|
10
|
+
"version-file": "lib/busser/version.rb"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
data/renovate.json
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
require_relative "../../spec_helper"
|
|
16
|
+
|
|
17
|
+
require "base64"
|
|
18
|
+
require "digest/md5"
|
|
19
|
+
require "tmpdir"
|
|
20
|
+
|
|
21
|
+
require "busser/command/deserialize"
|
|
22
|
+
|
|
23
|
+
# Deserialize is how Test Kitchen streams a file onto the instance under test,
|
|
24
|
+
# so the thing worth pinning down is what ends up on disk.
|
|
25
|
+
describe Busser::Command::Deserialize do
|
|
26
|
+
|
|
27
|
+
CONTENTS = "Hello there.\n".freeze
|
|
28
|
+
|
|
29
|
+
before do
|
|
30
|
+
@tmpdir = Dir.mktmpdir("busser-deserialize")
|
|
31
|
+
@file = File.join(@tmpdir, "nested", "decoded.txt")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
after do
|
|
35
|
+
FileUtils.rm_rf(@tmpdir)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
describe "with a matching digest" do
|
|
39
|
+
|
|
40
|
+
it "writes the decoded contents" do
|
|
41
|
+
deserialize(md5sum: Digest::MD5.hexdigest(CONTENTS))
|
|
42
|
+
|
|
43
|
+
_(File.read(@file)).must_equal CONTENTS
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "creates any missing parent directories" do
|
|
47
|
+
deserialize(md5sum: Digest::MD5.hexdigest(CONTENTS))
|
|
48
|
+
|
|
49
|
+
_(File.directory?(File.dirname(@file))).must_equal true
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "applies the requested permissions" do
|
|
53
|
+
deserialize(md5sum: Digest::MD5.hexdigest(CONTENTS), perms: "0755")
|
|
54
|
+
|
|
55
|
+
_(format("%o", File.stat(@file).mode & 0o777)).must_equal "755"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "writes binary content unchanged" do
|
|
59
|
+
binary = "\x00\x01\x02\xFF".dup.force_encoding("ASCII-8BIT")
|
|
60
|
+
|
|
61
|
+
deserialize(contents: binary, md5sum: Digest::MD5.hexdigest(binary))
|
|
62
|
+
|
|
63
|
+
_(File.binread(@file)).must_equal binary
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
describe "with a mismatching digest" do
|
|
68
|
+
|
|
69
|
+
it "fails the command" do
|
|
70
|
+
_ { deserialize(md5sum: "not-the-right-digest") }.must_raise SystemExit
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# The digest used to be checked only after the write, so a corrupted or
|
|
74
|
+
# truncated stream still landed on disk, with its requested permissions,
|
|
75
|
+
# for a later command to pick up and run.
|
|
76
|
+
it "leaves no file behind" do
|
|
77
|
+
_ { deserialize(md5sum: "not-the-right-digest") }.must_raise SystemExit
|
|
78
|
+
|
|
79
|
+
_(File.exist?(@file)).must_equal false
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it "does not overwrite a file that is already there" do
|
|
83
|
+
FileUtils.mkdir_p(File.dirname(@file))
|
|
84
|
+
File.write(@file, "original contents")
|
|
85
|
+
|
|
86
|
+
_ { deserialize(md5sum: "not-the-right-digest") }.must_raise SystemExit
|
|
87
|
+
|
|
88
|
+
_(File.read(@file)).must_equal "original contents"
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def deserialize(md5sum:, contents: CONTENTS, perms: "0644")
|
|
93
|
+
STDIN.stubs(:read).returns(Base64.encode64(contents))
|
|
94
|
+
|
|
95
|
+
command = Busser::Command::Deserialize.new([], {
|
|
96
|
+
"destination" => @file,
|
|
97
|
+
"md5sum" => md5sum,
|
|
98
|
+
"perms" => perms,
|
|
99
|
+
})
|
|
100
|
+
capture_stderr { command.perform }
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def capture_stderr
|
|
104
|
+
original = $stderr
|
|
105
|
+
$stderr = StringIO.new
|
|
106
|
+
yield
|
|
107
|
+
ensure
|
|
108
|
+
$stderr = original
|
|
109
|
+
end
|
|
110
|
+
end
|
data/spec/busser/helpers_spec.rb
CHANGED
|
@@ -9,17 +9,17 @@ describe Busser::Helpers do
|
|
|
9
9
|
describe ".suite_path" do
|
|
10
10
|
|
|
11
11
|
it "returns a Pathname" do
|
|
12
|
-
suite_path.must_be_kind_of Pathname
|
|
12
|
+
_(suite_path).must_be_kind_of Pathname
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
describe "with a default root path" do
|
|
16
16
|
|
|
17
17
|
it "returns a base path if no suite name is given" do
|
|
18
|
-
suite_path.to_s.
|
|
18
|
+
_(suite_path.to_s).must_match %r{/opt/busser/suites$}
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
it "returns a suite path given a suite name" do
|
|
22
|
-
suite_path("fuzzy").to_s.
|
|
22
|
+
_(suite_path("fuzzy").to_s).must_match %r{/opt/busser/suites/fuzzy$}
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
|
|
@@ -30,12 +30,12 @@ describe Busser::Helpers do
|
|
|
30
30
|
|
|
31
31
|
it "returns a base path if no suite name is given" do
|
|
32
32
|
ENV['BUSSER_ROOT'] = "/path/to/busser"
|
|
33
|
-
suite_path.to_s.
|
|
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
37
|
ENV['BUSSER_ROOT'] = "/path/to/busser"
|
|
38
|
-
suite_path("fuzzy").to_s.
|
|
38
|
+
_(suite_path("fuzzy").to_s).must_match %r{/path/to/busser/suites/fuzzy$}
|
|
39
39
|
end
|
|
40
40
|
end
|
|
41
41
|
end
|
|
@@ -43,17 +43,17 @@ describe Busser::Helpers do
|
|
|
43
43
|
describe ".vendor_path" do
|
|
44
44
|
|
|
45
45
|
it "returns a Pathname" do
|
|
46
|
-
vendor_path.must_be_kind_of Pathname
|
|
46
|
+
_(vendor_path).must_be_kind_of Pathname
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
describe "with a default root path" do
|
|
50
50
|
|
|
51
51
|
it "returns a base path if no product name is given" do
|
|
52
|
-
vendor_path.to_s.
|
|
52
|
+
_(vendor_path.to_s).must_match %r{/opt/busser/vendor$}
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
it "returns a vendor path given a product name" do
|
|
56
|
-
vendor_path("supreme").to_s.
|
|
56
|
+
_(vendor_path("supreme").to_s).must_match %r{/opt/busser/vendor/supreme$}
|
|
57
57
|
end
|
|
58
58
|
end
|
|
59
59
|
|
|
@@ -64,12 +64,13 @@ describe Busser::Helpers do
|
|
|
64
64
|
|
|
65
65
|
it "returns a base path if no product name is given" do
|
|
66
66
|
ENV['BUSSER_ROOT'] = "/path/to/busser"
|
|
67
|
-
vendor_path.to_s.
|
|
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
71
|
ENV['BUSSER_ROOT'] = "/path/to/busser"
|
|
72
|
-
vendor_path("maximal").to_s.
|
|
72
|
+
_(vendor_path("maximal").to_s).must_match \
|
|
73
|
+
%r{/path/to/busser/vendor/maximal$}
|
|
73
74
|
end
|
|
74
75
|
end
|
|
75
76
|
end
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
require_relative "../spec_helper"
|
|
16
|
+
|
|
17
|
+
require "busser/plugin"
|
|
18
|
+
require "busser/ui"
|
|
19
|
+
|
|
20
|
+
describe Busser::Plugin do
|
|
21
|
+
|
|
22
|
+
describe ".runner_plugin" do
|
|
23
|
+
|
|
24
|
+
it "builds the require path for a plugin name" do
|
|
25
|
+
_(Busser::Plugin.runner_plugin("bash"))
|
|
26
|
+
.must_equal "busser/runner_plugin/bash"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe ".runner_plugins" do
|
|
31
|
+
|
|
32
|
+
it "maps each given name to its require path" do
|
|
33
|
+
_(Busser::Plugin.runner_plugins(%w{bash minitest})).must_equal [
|
|
34
|
+
"busser/runner_plugin/bash",
|
|
35
|
+
"busser/runner_plugin/minitest",
|
|
36
|
+
]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "accepts a single name that is not in an array" do
|
|
40
|
+
_(Busser::Plugin.runner_plugins("bash"))
|
|
41
|
+
.must_equal ["busser/runner_plugin/bash"]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Callers run one suite per entry, so a repeated name would run that
|
|
45
|
+
# suite twice.
|
|
46
|
+
it "returns a name given more than once only once" do
|
|
47
|
+
_(Busser::Plugin.runner_plugins(%w{bash bash}))
|
|
48
|
+
.must_equal ["busser/runner_plugin/bash"]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "falls back to every installed plugin when given no names" do
|
|
52
|
+
Busser::Plugin.expects(:all_runner_plugins).returns(["stubbed"])
|
|
53
|
+
|
|
54
|
+
_(Busser::Plugin.runner_plugins).must_equal ["stubbed"]
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
describe ".all_runner_plugins" do
|
|
59
|
+
|
|
60
|
+
it "turns each found file into a require path" do
|
|
61
|
+
stub_found_files %w{
|
|
62
|
+
/gems/busser-bash-0.1.1/lib/busser/runner_plugin/bash.rb
|
|
63
|
+
/gems/busser-serverspec-0.5.0/lib/busser/runner_plugin/serverspec.rb
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
_(Busser::Plugin.all_runner_plugins).must_equal [
|
|
67
|
+
"busser/runner_plugin/bash",
|
|
68
|
+
"busser/runner_plugin/serverspec",
|
|
69
|
+
]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Gem.find_files searches every installed version of every gem. A machine
|
|
73
|
+
# that has installed a plugin more than once therefore reports it once per
|
|
74
|
+
# version, which made `busser test` run that suite repeatedly and
|
|
75
|
+
# `busser plugin list` print it repeatedly.
|
|
76
|
+
it "reports a plugin once when several versions of its gem are installed" do
|
|
77
|
+
stub_found_files %w{
|
|
78
|
+
/gems/busser-bash-0.1.1/lib/busser/runner_plugin/bash.rb
|
|
79
|
+
/gems/busser-bash-0.1.0/lib/busser/runner_plugin/bash.rb
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
_(Busser::Plugin.all_runner_plugins)
|
|
83
|
+
.must_equal ["busser/runner_plugin/bash"]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it "keeps the first occurrence, which is the newest version found" do
|
|
87
|
+
stub_found_files %w{
|
|
88
|
+
/gems/busser-bash-0.1.1/lib/busser/runner_plugin/bash.rb
|
|
89
|
+
/gems/busser-bash-0.1.0/lib/busser/runner_plugin/bash.rb
|
|
90
|
+
/gems/busser-serverspec-0.5.0/lib/busser/runner_plugin/serverspec.rb
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
_(Busser::Plugin.all_runner_plugins).must_equal [
|
|
94
|
+
"busser/runner_plugin/bash",
|
|
95
|
+
"busser/runner_plugin/serverspec",
|
|
96
|
+
]
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it "returns nothing when no plugins are installed" do
|
|
100
|
+
stub_found_files []
|
|
101
|
+
|
|
102
|
+
_(Busser::Plugin.all_runner_plugins).must_equal []
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def stub_found_files(files)
|
|
106
|
+
Gem.expects(:find_files)
|
|
107
|
+
.with("busser/runner_plugin/*.rb")
|
|
108
|
+
.returns(files)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
describe ".require!" do
|
|
113
|
+
|
|
114
|
+
it "requires the given path" do
|
|
115
|
+
Busser::Plugin.expects(:require).with("busser/runner_plugin/bash")
|
|
116
|
+
|
|
117
|
+
Busser::Plugin.require!("busser/runner_plugin/bash")
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# A plugin gem that is listed but not loadable is a common failure on a
|
|
121
|
+
# test instance, and the message is the only clue the user gets.
|
|
122
|
+
it "dies with the offending path when the plugin cannot be loaded" do
|
|
123
|
+
Busser::Plugin.stubs(:require).raises(LoadError, "no such file")
|
|
124
|
+
Busser::UI.expects(:die).with do |message|
|
|
125
|
+
message.include?("busser/runner_plugin/nope") &&
|
|
126
|
+
message.include?("LoadError") &&
|
|
127
|
+
message.include?("no such file")
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
Busser::Plugin.require!("busser/runner_plugin/nope")
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|