beaker 3.13.0 → 3.14.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 +8 -8
- data/acceptance/tests/subcommands/destroy.rb +49 -0
- data/acceptance/tests/subcommands/exec.rb +33 -0
- data/acceptance/tests/subcommands/init.rb +12 -36
- data/acceptance/tests/subcommands/provision.rb +9 -35
- data/beaker.gemspec +2 -2
- data/bin/beaker +1 -1
- data/docs/how_to/cloning_private_repos.md +3 -0
- data/docs/how_to/enabling_cross_sut_access.md +23 -0
- data/docs/how_to/ssh_agent_forwarding.md +4 -0
- data/lib/beaker/cli.rb +45 -15
- data/lib/beaker/host.rb +1 -1
- data/lib/beaker/hypervisor.rb +2 -1
- data/lib/beaker/network_manager.rb +5 -1
- data/lib/beaker/options/parser.rb +8 -1
- data/lib/beaker/options/subcommand_options_file_parser.rb +20 -0
- data/lib/beaker/ssh_connection.rb +1 -1
- data/lib/beaker/subcommand.rb +140 -28
- data/lib/beaker/subcommands/subcommand_util.rb +12 -125
- data/lib/beaker/version.rb +1 -1
- data/spec/beaker/cli_spec.rb +31 -0
- data/spec/beaker/logger_spec.rb +2 -0
- data/spec/beaker/options/parser_spec.rb +14 -1
- data/spec/beaker/options/subcommand_options_parser_spec.rb +33 -0
- data/spec/beaker/subcommand/subcommand_util_spec.rb +31 -204
- data/spec/beaker/subcommand_spec.rb +146 -0
- metadata +27 -20
@@ -204,7 +204,8 @@ module Beaker
|
|
204
204
|
# 2. ARGV or provided arguments array
|
205
205
|
# 3. the 'CONFIG' section of the hosts file
|
206
206
|
# 4. options file values
|
207
|
-
# 5.
|
207
|
+
# 5. subcommand options, if executing beaker subcommands
|
208
|
+
# 6. default or preset values are given the lowest priority
|
208
209
|
#
|
209
210
|
# @param [Array] args ARGV or a provided arguments array
|
210
211
|
# @raise [ArgumentError] Raises error on bad input
|
@@ -214,6 +215,12 @@ module Beaker
|
|
214
215
|
cmd_line_options = @command_line_parser.parse(args)
|
215
216
|
cmd_line_options[:command_line] = ([$0] + args).join(' ')
|
216
217
|
@attribution = @attribution.merge(tag_sources(cmd_line_options, "flag"))
|
218
|
+
|
219
|
+
# Subcommands are the first to get merged into presets
|
220
|
+
subcommand_options = Beaker::Options::SubcommandOptionsParser.parse_subcommand_options(args)
|
221
|
+
@attribution = @attribution.merge(tag_sources(subcommand_options, 'subcommand'))
|
222
|
+
@options.merge!(subcommand_options)
|
223
|
+
|
217
224
|
file_options = Beaker::Options::OptionsFileParser.parse_options_file(cmd_line_options[:options_file])
|
218
225
|
@attribution = @attribution.merge(tag_sources(file_options, "options_file"))
|
219
226
|
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Beaker
|
2
|
+
module Options
|
3
|
+
#A set of functions to read options files
|
4
|
+
module SubcommandOptionsParser
|
5
|
+
|
6
|
+
# @return [OptionsHash, Hash] returns an empty OptionHash or loads subcommand options yaml
|
7
|
+
# from disk
|
8
|
+
def self.parse_subcommand_options(argv)
|
9
|
+
result = OptionsHash.new
|
10
|
+
if Beaker::Subcommands::SubcommandUtil.execute_subcommand?(argv[0])
|
11
|
+
return result if argv[0] == 'init'
|
12
|
+
if Beaker::Subcommands::SubcommandUtil::SUBCOMMAND_OPTIONS.exist?
|
13
|
+
result = YAML.load_file(Beaker::Subcommands::SubcommandUtil::SUBCOMMAND_OPTIONS)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
result
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -108,7 +108,7 @@ module Beaker
|
|
108
108
|
|
109
109
|
# Wait for the ssh connection to fail, returns true on connection failure and false otherwise
|
110
110
|
# @param [Hash{Symbol=>String}] options Options hash to control method conditionals
|
111
|
-
# @option options [Boolean] :pty Should we request a terminal when attempting
|
111
|
+
# @option options [Boolean] :pty Should we request a terminal when attempting
|
112
112
|
# to send a command over this connection?
|
113
113
|
# @option options [String] :stdin Any input to be sent along with the command
|
114
114
|
# @param [IO] stdout_callback An IO stream to send connection stdout to, defaults to nil
|
data/lib/beaker/subcommand.rb
CHANGED
@@ -6,9 +6,13 @@ module Beaker
|
|
6
6
|
class Subcommand < Thor
|
7
7
|
SubcommandUtil = Beaker::Subcommands::SubcommandUtil
|
8
8
|
|
9
|
+
|
9
10
|
def initialize(*args)
|
10
11
|
super
|
11
|
-
|
12
|
+
FileUtils.mkdir_p(SubcommandUtil::CONFIG_DIR)
|
13
|
+
FileUtils.touch(SubcommandUtil::SUBCOMMAND_OPTIONS) unless SubcommandUtil::SUBCOMMAND_OPTIONS.exist?
|
14
|
+
FileUtils.touch(SubcommandUtil::SUBCOMMAND_STATE) unless SubcommandUtil::SUBCOMMAND_STATE.exist?
|
15
|
+
@cli = Beaker::CLI.new
|
12
16
|
end
|
13
17
|
|
14
18
|
# Options listed in this group 'Beaker run' are options that can be set on subcommands
|
@@ -49,55 +53,163 @@ module Beaker
|
|
49
53
|
class_option :'exclude-tags', :type => :string, :group => 'Beaker run'
|
50
54
|
class_option :'xml-time-order', :type => :boolean, :group => 'Beaker run'
|
51
55
|
|
52
|
-
desc "init
|
53
|
-
option :help, :type => :boolean, :hide => true
|
56
|
+
desc "init BEAKER_RUN_OPTIONS", "Initializes the required configuration for Beaker subcommand execution"
|
54
57
|
long_desc <<-LONGDESC
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
58
|
+
Initializes the required .beaker configuration folder. This folder contains
|
59
|
+
a subcommand_options.yaml file that is user-facing; altering this file will
|
60
|
+
alter the options subcommand execution. Subsequent subcommand execution,
|
61
|
+
such as `provision`, will result in beaker making modifications to this file
|
62
|
+
as necessary.
|
60
63
|
LONGDESC
|
61
|
-
|
64
|
+
option :help, :type => :boolean, :hide => true
|
65
|
+
def init()
|
62
66
|
if options[:help]
|
63
67
|
invoke :help, [], ["init"]
|
64
68
|
return
|
65
69
|
end
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
70
|
+
|
71
|
+
@cli.parse_options
|
72
|
+
|
73
|
+
# delete unnecessary keys for saving the options
|
74
|
+
options_to_write = @cli.configured_options
|
75
|
+
# Remove keys we don't want to save
|
76
|
+
[:timestamp, :logger, :command_line, :beaker_version, :hosts_file].each do |key|
|
77
|
+
options_to_write.delete(key)
|
78
|
+
end
|
79
|
+
|
80
|
+
options_to_write = SubcommandUtil.sanitize_options_for_save(options_to_write)
|
81
|
+
|
82
|
+
@cli.logger.notify 'Writing configured options to disk'
|
83
|
+
File.open(SubcommandUtil::SUBCOMMAND_OPTIONS, 'w') do |f|
|
84
|
+
f.write(options_to_write.to_yaml)
|
85
|
+
end
|
86
|
+
@cli.logger.notify "Options written to #{SubcommandUtil::SUBCOMMAND_OPTIONS}"
|
87
|
+
|
88
|
+
state = YAML::Store.new(SubcommandUtil::SUBCOMMAND_STATE)
|
89
|
+
state.transaction do
|
90
|
+
state['provisioned'] = false
|
91
|
+
end
|
72
92
|
end
|
73
93
|
|
74
|
-
desc "provision", "Provisions the beaker test
|
75
|
-
option :validate, :type => :boolean, :default => true
|
76
|
-
option :configure, :type => :boolean, :default => true
|
77
|
-
option :help, :type => :boolean, :hide => true
|
94
|
+
desc "provision", "Provisions the beaker systems under test(SUTs)"
|
78
95
|
long_desc <<-LONGDESC
|
79
|
-
Provisions
|
96
|
+
Provisions hosts defined in your subcommand_options file. You can pass the --hosts
|
97
|
+
flag here to override any hosts provided there. Really, you can pass most any beaker
|
98
|
+
flag here to override.
|
80
99
|
LONGDESC
|
100
|
+
option :help, :type => :boolean, :hide => true
|
81
101
|
def provision()
|
82
102
|
if options[:help]
|
83
103
|
invoke :help, [], ["provision"]
|
84
104
|
return
|
85
105
|
end
|
86
106
|
|
87
|
-
|
107
|
+
state = YAML::Store.new(SubcommandUtil::SUBCOMMAND_STATE)
|
108
|
+
if state.transaction { state['provisioned']}
|
109
|
+
SubcommandUtil.error_with('Provisioned SUTs detected. Please destroy and reprovision.')
|
110
|
+
end
|
111
|
+
|
112
|
+
@cli.parse_options
|
113
|
+
@cli.provision
|
114
|
+
|
115
|
+
# Sanitize the hosts
|
116
|
+
cleaned_hosts = SubcommandUtil.sanitize_options_for_save(@cli.combined_instance_and_options_hosts)
|
117
|
+
|
118
|
+
# Update each host provisioned with a flag indicating that it no longer needs
|
119
|
+
# provisioning
|
120
|
+
cleaned_hosts.each do |host, host_hash|
|
121
|
+
host_hash['provision'] = false
|
122
|
+
end
|
123
|
+
|
124
|
+
# should we only update the options here with the new host? Or update the settings
|
125
|
+
# with whatever new flags may have been provided with provision?
|
126
|
+
options_storage = YAML::Store.new(SubcommandUtil::SUBCOMMAND_OPTIONS)
|
127
|
+
options_storage.transaction do
|
128
|
+
@cli.logger.notify 'updating HOSTS key in subcommand_options'
|
129
|
+
options_storage['HOSTS'] = cleaned_hosts
|
130
|
+
options_storage['hosts_preserved_yaml_file'] = @cli.options[:hosts_preserved_yaml_file]
|
131
|
+
end
|
132
|
+
|
133
|
+
@cli.preserve_hosts_file
|
134
|
+
|
135
|
+
state.transaction do
|
136
|
+
state['provisioned'] = true
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
desc 'exec FILE/BEAKER_SUITE', 'execute a directory, file, or beaker suite'
|
141
|
+
long_desc <<-LONG_DESC
|
142
|
+
Run a single file, directory, or beaker suite. If supplied a file or directory,
|
143
|
+
that resource will be run in the context of the `tests` suite; If supplied a beaker
|
144
|
+
suite, then just that suite will run. If no resource is supplied, then this command
|
145
|
+
executes the suites as they are defined in the configuration.
|
146
|
+
LONG_DESC
|
147
|
+
option :help, :type => :boolean, :hide => true
|
148
|
+
def exec(resource=nil)
|
149
|
+
if options[:help]
|
150
|
+
invoke :help, [], ["exec"]
|
151
|
+
return
|
152
|
+
end
|
153
|
+
|
154
|
+
@cli.parse_options
|
155
|
+
@cli.initialize_network_manager
|
88
156
|
|
89
|
-
|
90
|
-
|
157
|
+
if !resource
|
158
|
+
@cli.execute!
|
159
|
+
return
|
91
160
|
end
|
92
161
|
|
93
|
-
|
162
|
+
beaker_suites = [:pre_suite, :tests, :post_suite, :pre_cleanup]
|
94
163
|
|
95
|
-
if
|
96
|
-
|
97
|
-
|
164
|
+
if Pathname(resource).exist?
|
165
|
+
# If we determine the resource is a valid file resource, then we empty
|
166
|
+
# all the suites and run that file resource in the tests suite. In the
|
167
|
+
# future, when we have the ability to have custom suites, we should change
|
168
|
+
# this to run in a custom suite. You know, in the future.
|
169
|
+
beaker_suites.each do |suite|
|
170
|
+
@cli.options[suite] = []
|
171
|
+
end
|
172
|
+
if Pathname(resource).directory?
|
173
|
+
@cli.options[:tests] = Dir.glob("#{Pathname(resource).expand_path}/*.rb")
|
174
|
+
else
|
175
|
+
@cli.options[:tests] = [Pathname(resource).expand_path.to_s]
|
176
|
+
end
|
177
|
+
elsif resource.match(/pre-suite|tests|post-suite|pre-cleanup/)
|
178
|
+
# The regex match here is loose so that users can supply multiple suites,
|
179
|
+
# such as `beaker exec pre-suite,tests`.
|
180
|
+
beaker_suites.each do |suite|
|
181
|
+
@cli.options[suite] = [] unless resource.gsub(/-/, '_').match(suite.to_s)
|
182
|
+
end
|
98
183
|
else
|
99
|
-
|
184
|
+
raise ArgumentError, "Unable to parse #{resource} with beaker exec"
|
100
185
|
end
|
186
|
+
@cli.execute!
|
187
|
+
end
|
188
|
+
|
189
|
+
desc "destroy", "Destroys the provisioned VMs"
|
190
|
+
long_desc <<-LONG_DESC
|
191
|
+
Destroys the currently provisioned VMs
|
192
|
+
LONG_DESC
|
193
|
+
option :help, :type => :boolean, :hide => true
|
194
|
+
def destroy()
|
195
|
+
if options[:help]
|
196
|
+
invoke :help, [], ["destroy"]
|
197
|
+
return
|
198
|
+
end
|
199
|
+
|
200
|
+
state = YAML::Store.new(SubcommandUtil::SUBCOMMAND_STATE)
|
201
|
+
unless state.transaction { state['provisioned']}
|
202
|
+
SubcommandUtil.error_with('Please provision an environment')
|
203
|
+
end
|
204
|
+
|
205
|
+
@cli.parse_options
|
206
|
+
@cli.options[:provision] = false
|
207
|
+
@cli.initialize_network_manager
|
208
|
+
@cli.network_manager.cleanup
|
209
|
+
|
210
|
+
state.transaction {
|
211
|
+
state.delete('provisioned')
|
212
|
+
}
|
101
213
|
end
|
102
214
|
end
|
103
215
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'json'
|
1
2
|
require 'rake'
|
2
3
|
require 'stringio'
|
3
4
|
require 'yaml/store'
|
@@ -7,87 +8,27 @@ module Beaker
|
|
7
8
|
module Subcommands
|
8
9
|
# Methods used in execution of Subcommands
|
9
10
|
# - should we execute a subcommand?
|
10
|
-
# -
|
11
|
-
# - execute Beaker
|
12
|
-
# - update a rakefile to require beaker quickstart tasks
|
13
|
-
# - initialise a rake application
|
14
|
-
# - execute a rake task
|
15
|
-
# - execute the vagrant quickstart task
|
16
|
-
# - execute the vmpooler quickstart task
|
11
|
+
# - sanitize options for saving as json
|
17
12
|
# - exit with a specific message
|
18
|
-
# - execute the quick start task for the specified hypervisor
|
19
13
|
# - capture stdout and stderr
|
20
14
|
module SubcommandUtil
|
21
|
-
BEAKER_REQUIRE = "require 'beaker/tasks/quick_start'"
|
22
|
-
HYPERVISORS = ["vagrant", "vmpooler"]
|
23
15
|
CONFIG_DIR = ".beaker"
|
24
|
-
|
16
|
+
SUBCOMMAND_OPTIONS = Pathname("#{CONFIG_DIR}/subcommand_options.yaml")
|
17
|
+
SUBCOMMAND_STATE = Pathname("#{CONFIG_DIR}/.subcommand_state.yaml")
|
18
|
+
PERSISTED_HOSTS = Pathname("#{CONFIG_DIR}/.hosts.yaml")
|
19
|
+
PERSISTED_HYPERVISORS = Pathname("#{CONFIG_DIR}/.hypervisors.yaml")
|
25
20
|
|
26
|
-
# Check if the first argument to the beaker execution is a subcommand
|
27
|
-
# @return [Boolean] true if argv[0] is "help" or a method defined in the Subcommands class, false otherwise
|
28
21
|
def self.execute_subcommand?(arg0)
|
29
22
|
return false if arg0.nil?
|
30
23
|
(Beaker::Subcommand.instance_methods(false) << :help).include? arg0.to_sym
|
31
24
|
end
|
32
25
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
# Update ARGV and call Beaker
|
43
|
-
# @param [Array<String>] args the arguments determined by a specific subcommand
|
44
|
-
def self.execute_beaker(*args)
|
45
|
-
reset_argv(args)
|
46
|
-
Beaker::CLI.new.execute!
|
47
|
-
end
|
48
|
-
|
49
|
-
# Determines what Rakefile to use
|
50
|
-
# @return [String] the name of the rakefile to use
|
51
|
-
def self.determine_rake_file()
|
52
|
-
rake_app.find_rakefile_location() ? rake_app.find_rakefile_location()[0] : "Rakefile"
|
53
|
-
end
|
54
|
-
|
55
|
-
# Check for the presence of a Rakefile containing the require of the
|
56
|
-
# quick start tasks
|
57
|
-
def self.require_tasks()
|
58
|
-
rake_file = determine_rake_file()
|
59
|
-
FileUtils.touch(rake_file)
|
60
|
-
unless File.readlines(rake_file).grep(/#{BEAKER_REQUIRE}/).any?
|
61
|
-
File.open(rake_file, "a+") { |f| f.puts(BEAKER_REQUIRE) }
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
# Initialises a rake application
|
66
|
-
# @return [Object] a rake application
|
67
|
-
def self.rake_app()
|
68
|
-
unless @rake_app
|
69
|
-
ARGV.clear
|
70
|
-
@rake_app = Rake.application
|
71
|
-
@rake_app.init
|
72
|
-
end
|
73
|
-
@rake_app
|
74
|
-
end
|
75
|
-
|
76
|
-
# Clear ARGV and execute a Rake task
|
77
|
-
# @param [String] task the rake task to execute
|
78
|
-
def self.execute_rake_task(task)
|
79
|
-
rake_app.load_rakefile()
|
80
|
-
with_captured_output { rake_app.invoke_task(task) }
|
81
|
-
end
|
82
|
-
|
83
|
-
# Execute the quick start task for vagrant
|
84
|
-
def self.init_vagrant()
|
85
|
-
execute_rake_task("beaker_quickstart:gen_hosts[vagrant]")
|
86
|
-
end
|
87
|
-
|
88
|
-
# Execute the quick start task for vmpooler
|
89
|
-
def self.init_vmpooler()
|
90
|
-
execute_rake_task("beaker_quickstart:gen_hosts[vmpooler]")
|
26
|
+
def self.sanitize_options_for_save(options)
|
27
|
+
# God help us, the YAML library won't stop adding tags to objects, so this
|
28
|
+
# hack is a way to force the options into the basic object types so that
|
29
|
+
# an eventual YAML.dump or .to_yaml call doesn't add tags.
|
30
|
+
# Relevant stackoverflow: http://stackoverflow.com/questions/18178098/how-do-i-have-ruby-yaml-dump-a-hash-subclass-as-a-simple-hash
|
31
|
+
JSON.parse(options.to_json)
|
91
32
|
end
|
92
33
|
|
93
34
|
# Print a message to the console and exit with specified exit code, defaults to 1
|
@@ -100,25 +41,6 @@ module Beaker
|
|
100
41
|
exit(exit_code)
|
101
42
|
end
|
102
43
|
|
103
|
-
# Call the quick start task for the specified hypervisor
|
104
|
-
# @param [String] hypervisor the hypervisor we want to query
|
105
|
-
def self.init_hypervisor(hypervisor)
|
106
|
-
case hypervisor
|
107
|
-
when "vagrant"
|
108
|
-
init_vagrant
|
109
|
-
when "vmpooler"
|
110
|
-
init_vmpooler
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
# Verify that a valid hypervisor has been specified
|
115
|
-
# @param [String] hypervisor the hypervisor we want to validate
|
116
|
-
def self.verify_init_args(hypervisor)
|
117
|
-
unless HYPERVISORS.include?(hypervisor)
|
118
|
-
error_with("Invalid hypervisor. Currently supported hypervisors are: #{HYPERVISORS.join(', ')}")
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
44
|
# Execute a task but capture stdout and stderr to a buffer
|
123
45
|
def self.with_captured_output
|
124
46
|
begin
|
@@ -133,41 +55,6 @@ module Beaker
|
|
133
55
|
end
|
134
56
|
end
|
135
57
|
|
136
|
-
# Initialise the beaker config
|
137
|
-
def self.init_config()
|
138
|
-
FileUtils.mkdir_p CONFIG_DIR
|
139
|
-
@@store = YAML::Store.new("#{CONFIG_DIR}/config")
|
140
|
-
end
|
141
|
-
|
142
|
-
# Store values from a hash into the beaker config
|
143
|
-
# @param [Hash{Symbol=>String}] config values we want to store
|
144
|
-
def self.store_config(config)
|
145
|
-
@@store.transaction do
|
146
|
-
CONFIG_KEYS.each do |key|
|
147
|
-
@@store[key] = config[key] unless config[key].nil?
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
# Delete keys from the beaker configi
|
153
|
-
# @param [Array<Object>] keys the keys we want to delete from the config
|
154
|
-
def self.delete_config(keys)
|
155
|
-
@@store.transaction {
|
156
|
-
keys.each do |key|
|
157
|
-
@@store.delete(key)
|
158
|
-
end
|
159
|
-
}
|
160
|
-
end
|
161
|
-
|
162
|
-
# Reset args and provision nodes
|
163
|
-
# @param [String] hypervisor the hypervisor to use
|
164
|
-
# @param [Array<Object>] options the options to use when provisioning
|
165
|
-
def self.provision(hypervisor, options)
|
166
|
-
reset_argv(["--hosts", "#{CONFIG_DIR}/acceptance/config/default_#{hypervisor}_hosts.yaml", "--validate", options[:validate], "--configure", options[:configure]])
|
167
|
-
beaker = Beaker::CLI.new.parse_options
|
168
|
-
beaker.provision
|
169
|
-
beaker.preserve_hosts_file
|
170
|
-
end
|
171
58
|
end
|
172
59
|
end
|
173
60
|
end
|
data/lib/beaker/version.rb
CHANGED
data/spec/beaker/cli_spec.rb
CHANGED
@@ -50,6 +50,36 @@ module Beaker
|
|
50
50
|
Beaker::CLI.new.parse_options
|
51
51
|
}
|
52
52
|
|
53
|
+
context '#configured_options' do
|
54
|
+
it 'returns a list of options that were not presets' do
|
55
|
+
attribution = cli.instance_variable_get(:@attribution)
|
56
|
+
attribution.each do |attribute, setter|
|
57
|
+
if setter == 'preset'
|
58
|
+
expect(cli.configured_options[attribute]).to be_nil
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context '#combined_instance_and_options_hosts' do
|
65
|
+
let (:options_host) { {'HOSTS' => {'ubuntu' => {:options_attribute => 'options'}} }}
|
66
|
+
let (:instance_host ) {
|
67
|
+
[Beaker::Host.create('ubuntu', {:platform => 'host'}, {} )]
|
68
|
+
}
|
69
|
+
before do
|
70
|
+
cli.instance_variable_set(:@options, options_host)
|
71
|
+
cli.instance_variable_set(:@hosts, instance_host)
|
72
|
+
end
|
73
|
+
it 'combines the options and instance host objects' do
|
74
|
+
merged_host = cli.combined_instance_and_options_hosts
|
75
|
+
expect(merged_host).to have_key('ubuntu')
|
76
|
+
expect(merged_host['ubuntu']).to have_key(:options_attribute)
|
77
|
+
expect(merged_host['ubuntu']).to have_key(:platform)
|
78
|
+
expect(merged_host['ubuntu'][:options_attribute]).to eq('options')
|
79
|
+
expect(merged_host['ubuntu'][:platform]).to eq('host')
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
53
83
|
context 'execute!' do
|
54
84
|
before :each do
|
55
85
|
stub_const("Beaker::Logger", double().as_null_object )
|
@@ -503,6 +533,7 @@ module Beaker
|
|
503
533
|
expect( answer.start_with?(command_correct) ).to be_truthy
|
504
534
|
end
|
505
535
|
end
|
536
|
+
|
506
537
|
end
|
507
538
|
end
|
508
539
|
end
|