unobtainium 0.8.1 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/Gemfile.lock +10 -9
- data/lib/unobtainium/driver.rb +6 -1
- data/lib/unobtainium/drivers/appium.rb +8 -6
- data/lib/unobtainium/drivers/phantom.rb +148 -32
- data/lib/unobtainium/drivers/selenium.rb +4 -1
- data/lib/unobtainium/support/identifiers.rb +25 -0
- data/lib/unobtainium/support/port_scanner.rb +15 -3
- data/lib/unobtainium/version.rb +1 -1
- data/lib/unobtainium/world.rb +8 -4
- data/spec/data/driverconfig.yml +9 -2
- data/spec/driver_spec.rb +30 -1
- data/spec/drivers_appium_spec.rb +244 -0
- data/spec/drivers_phantom_spec.rb +247 -0
- data/spec/drivers_selenium_spec.rb +170 -0
- data/spec/mock_driver.rb +23 -0
- data/spec/spec_helper.rb +0 -1
- data/spec/support_identifiers_spec.rb +42 -0
- data/spec/{port_scanner_spec.rb → support_port_scanner_spec.rb} +49 -0
- data/spec/{runner_spec.rb → support_runner_spec.rb} +0 -0
- data/spec/{utility_spec.rb → support_utility_spec.rb} +0 -0
- data/spec/world_spec.rb +39 -1
- data/unobtainium.gemspec +1 -1
- metadata +19 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c48a4bbdaf69ce31be6eb42f8a10bd4af462fafb
|
4
|
+
data.tar.gz: f4f811e06460e1a124769e97dadb0d79de82ba93
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2582d432e5fc1c6d35cacee66c8eb71ec87437313f1ab3f8706dd457d4925ccb07cac952e535bba1898eb8e1e6b9cb1becaf3e90f2ab36d78c1a2d33e97ab575
|
7
|
+
data.tar.gz: 9e610ebc5b157cb7828a4be8f7208687b8df5acb2ebd7ee9f023173132dd3a0c4d285d1eaf725ea8f2b13ca6c7c2b0c41c71aec11fca49a41082303081ba8e0b
|
data/.travis.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
unobtainium (0.
|
5
|
-
collapsium (~> 0.
|
4
|
+
unobtainium (0.9.0)
|
5
|
+
collapsium (~> 0.8)
|
6
6
|
collapsium-config (~> 0.4)
|
7
7
|
ptools (~> 1.3)
|
8
8
|
sys-proctable (~> 1.1)
|
@@ -10,11 +10,11 @@ PATH
|
|
10
10
|
GEM
|
11
11
|
remote: https://rubygems.org/
|
12
12
|
specs:
|
13
|
-
appium_lib (8.0
|
13
|
+
appium_lib (8.1.0)
|
14
14
|
awesome_print (~> 1.6)
|
15
15
|
json (~> 1.8)
|
16
16
|
nokogiri (~> 1.6.6)
|
17
|
-
selenium-webdriver (~> 2.
|
17
|
+
selenium-webdriver (~> 2.50)
|
18
18
|
tomlrb (~> 1.1)
|
19
19
|
archive-zip (0.7.0)
|
20
20
|
io-like (~> 0.3.0)
|
@@ -26,10 +26,11 @@ GEM
|
|
26
26
|
chromedriver-helper (1.0.0)
|
27
27
|
archive-zip (~> 0.7.0)
|
28
28
|
nokogiri (~> 1.6)
|
29
|
-
codeclimate-test-reporter (1.0.
|
30
|
-
|
31
|
-
collapsium
|
32
|
-
|
29
|
+
codeclimate-test-reporter (1.0.3)
|
30
|
+
simplecov
|
31
|
+
collapsium (0.8.0)
|
32
|
+
collapsium-config (0.4.3)
|
33
|
+
collapsium (~> 0.7)
|
33
34
|
cucumber (2.4.0)
|
34
35
|
builder (>= 2.1.2)
|
35
36
|
cucumber-core (~> 1.5.0)
|
@@ -52,7 +53,7 @@ GEM
|
|
52
53
|
multi_test (0.1.2)
|
53
54
|
nokogiri (1.6.8.1)
|
54
55
|
mini_portile2 (~> 2.1.0)
|
55
|
-
parser (2.3.
|
56
|
+
parser (2.3.2.0)
|
56
57
|
ast (~> 2.2)
|
57
58
|
phantomjs (2.1.1.0)
|
58
59
|
powerpack (0.1.1)
|
data/lib/unobtainium/driver.rb
CHANGED
@@ -243,7 +243,12 @@ module Unobtainium
|
|
243
243
|
driver_klass.ensure_preconditions(@label, @options)
|
244
244
|
|
245
245
|
# Great, instanciate!
|
246
|
-
|
246
|
+
opts = nil
|
247
|
+
if not @options.nil?
|
248
|
+
opts = @options.dup
|
249
|
+
opts.delete('unobtainium_instance_id')
|
250
|
+
end
|
251
|
+
@impl = driver_klass.create(@label, opts)
|
247
252
|
|
248
253
|
# Now also extend this implementation with all the modues that match
|
249
254
|
@@modules.each do |klass, _|
|
@@ -68,9 +68,7 @@ module Unobtainium
|
|
68
68
|
return driver.send(meth.to_s, *args, &block)
|
69
69
|
end
|
70
70
|
end
|
71
|
-
# :nocov:
|
72
71
|
return super
|
73
|
-
# :nocov:
|
74
72
|
end
|
75
73
|
end
|
76
74
|
|
@@ -119,13 +117,14 @@ module Unobtainium
|
|
119
117
|
|
120
118
|
# Merge 'caps' and 'desired_capabilities', letting the former win
|
121
119
|
options[:caps] =
|
122
|
-
::Collapsium::UberHash.new(options[
|
120
|
+
::Collapsium::UberHash.new(options['desired_capabilities'])
|
121
|
+
.recursive_merge(options[:desired_capabilities])
|
123
122
|
.recursive_merge(options[:caps])
|
124
123
|
options.delete(:desired_capabilities)
|
125
124
|
options.delete('desired_capabilities')
|
126
125
|
|
127
126
|
# The label specifies the platform, if no other platform is given.
|
128
|
-
if options['caps.platformName']
|
127
|
+
if not options['caps.platformName']
|
129
128
|
options['caps.platformName'] = normalized.to_s
|
130
129
|
end
|
131
130
|
|
@@ -144,12 +143,14 @@ module Unobtainium
|
|
144
143
|
# some information
|
145
144
|
options = supplement_browser(options)
|
146
145
|
|
147
|
-
return
|
146
|
+
return normalized, options
|
148
147
|
end
|
149
148
|
|
150
149
|
##
|
151
150
|
# Create and return a driver instance
|
152
151
|
def create(_, options)
|
152
|
+
# :nocov:
|
153
|
+
|
153
154
|
# Determine compatibility option
|
154
155
|
compat = options.fetch(:webdriver_compatibility, true)
|
155
156
|
options.delete(:webdriver_compatibility)
|
@@ -158,6 +159,7 @@ module Unobtainium
|
|
158
159
|
driver = ::Appium::Driver.new(options)
|
159
160
|
result = DriverProxy.new(driver, compat)
|
160
161
|
return result
|
162
|
+
# :nocov:
|
161
163
|
end
|
162
164
|
|
163
165
|
private
|
@@ -176,7 +178,7 @@ module Unobtainium
|
|
176
178
|
platform = options['caps.platformName'].to_s.downcase.to_sym
|
177
179
|
|
178
180
|
# If we have supplement data matching the platform and browser, great!
|
179
|
-
data = BROWSER_MATCHES[platform][browser]
|
181
|
+
data = (BROWSER_MATCHES[platform] || {})[browser]
|
180
182
|
if data.nil?
|
181
183
|
return options
|
182
184
|
end
|
@@ -7,10 +7,13 @@
|
|
7
7
|
# All rights reserved.
|
8
8
|
#
|
9
9
|
|
10
|
+
require 'collapsium'
|
11
|
+
|
10
12
|
require_relative './selenium'
|
11
13
|
require_relative '../support/util'
|
12
14
|
require_relative '../support/port_scanner'
|
13
15
|
require_relative '../support/runner'
|
16
|
+
require_relative '../support/identifiers'
|
14
17
|
require_relative '../runtime'
|
15
18
|
|
16
19
|
module Unobtainium
|
@@ -24,7 +27,7 @@ module Unobtainium
|
|
24
27
|
class Phantom < Selenium
|
25
28
|
# Recognized labels for matching the driver
|
26
29
|
LABELS = {
|
27
|
-
phantomjs: [:headless,],
|
30
|
+
phantomjs: [:headless, :phantom],
|
28
31
|
}.freeze
|
29
32
|
|
30
33
|
# Port scanning ranges (can also be arrays or single port numbers.
|
@@ -43,6 +46,7 @@ module Unobtainium
|
|
43
46
|
class << self
|
44
47
|
include ::Unobtainium::Support::Utility
|
45
48
|
include ::Unobtainium::Support::PortScanner
|
49
|
+
include ::Unobtainium::Support::Identifiers
|
46
50
|
|
47
51
|
##
|
48
52
|
# Ensure that the driver's preconditions are fulfilled.
|
@@ -62,40 +66,56 @@ module Unobtainium
|
|
62
66
|
def resolve_options(label, options)
|
63
67
|
label, options = super
|
64
68
|
|
65
|
-
|
66
|
-
raise ArgumentError, "Use either of 'phantomjs' or :phantomjs as "\
|
67
|
-
"option keys, not both!"
|
68
|
-
end
|
69
|
-
if not options[:phantomjs].nil?
|
70
|
-
options['phantomjs'] = options[:phantomjs]
|
71
|
-
options.delete(:phantomjs)
|
72
|
-
end
|
69
|
+
options = ::Collapsium::UberHash.new(options)
|
73
70
|
|
74
|
-
#
|
75
|
-
|
76
|
-
|
77
|
-
#
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
options
|
71
|
+
# If a URL is already provided, we should respect this.
|
72
|
+
merge_url(options)
|
73
|
+
|
74
|
+
# Provide defaults for webdriver host and port.
|
75
|
+
merge_defaults(options)
|
76
|
+
|
77
|
+
# At this point, the :phantomjs field is canonical in that it will
|
78
|
+
# be used to generate a :port and :url if necessary. That means we
|
79
|
+
# can use it to create a stable ID, too.
|
80
|
+
# This also implies that the :url field is pointless and should not
|
81
|
+
# be part of the ID; it will be generated again later on.
|
82
|
+
options.delete(:url)
|
83
|
+
|
84
|
+
# We need to figure out what we have to do based on detecting whether
|
85
|
+
# a port or some other option changed (or nothing did!)
|
86
|
+
fix_ports(label, options)
|
86
87
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
88
|
+
# We find a free port here, so there's a possibility it'll get used
|
89
|
+
# before we run the server in #create. However, for the purpose of
|
90
|
+
# resolving options that's necessary. So we'll just live with this
|
91
|
+
# until it becomes a problem.
|
92
|
+
if options['phantomjs.generated_port'].nil?
|
93
|
+
if options['phantomjs.port'].nil?
|
94
|
+
ports = scan(options['phantomjs.host'], *PORT_RANGES,
|
95
|
+
for: :available, amount: :first)
|
96
|
+
if ports.empty?
|
97
|
+
raise "Could not find an available port for the PhantomJS server!"
|
98
|
+
end
|
99
|
+
options['phantomjs.generated_port'] = ports[0]
|
100
|
+
else
|
101
|
+
options['phantomjs.generated_port'] = options['phantomjs.port']
|
92
102
|
end
|
93
|
-
options['phantomjs']['port'] = ports[0]
|
94
103
|
end
|
95
104
|
|
96
|
-
# Now
|
97
|
-
|
98
|
-
|
105
|
+
# Now we can't just use new_id because we might have found a new
|
106
|
+
# port in the meantime. We'll have to generate yet another ID, and
|
107
|
+
# use that.
|
108
|
+
# Now before calculating this new ID, we'll run the options through
|
109
|
+
# the super method again. This is to ensure that all keys have the
|
110
|
+
# expected class *before* we perform this calculation.
|
111
|
+
new_id = identifier('driver', label, options)
|
112
|
+
options['unobtainium_instance_id'] = new_id
|
113
|
+
|
114
|
+
# Now we can generate the :url field for Selenium's benefit; it's
|
115
|
+
# just a copy of the canonical options.
|
116
|
+
options[:url] = "#{options['phantomjs.scheme']}://"\
|
117
|
+
"#{options['phantomjs.host']}:"\
|
118
|
+
"#{options['phantomjs.generated_port']}"
|
99
119
|
|
100
120
|
return label, options
|
101
121
|
end
|
@@ -103,9 +123,11 @@ module Unobtainium
|
|
103
123
|
##
|
104
124
|
# Create and return a driver instance
|
105
125
|
def create(_, options)
|
126
|
+
# :nocov:
|
127
|
+
|
106
128
|
# Extract PhantomJS options
|
107
|
-
host = options['phantomjs
|
108
|
-
port = options['phantomjs']['
|
129
|
+
host = options['phantomjs.host']
|
130
|
+
port = options['phantomjs.port'] || options['phantomjs.generated_port']
|
109
131
|
opts = options.dup
|
110
132
|
opts.delete('phantomjs')
|
111
133
|
|
@@ -138,6 +160,100 @@ module Unobtainium
|
|
138
160
|
# Run Selenium against server
|
139
161
|
driver = ::Selenium::WebDriver.for(:remote, opts)
|
140
162
|
return driver
|
163
|
+
|
164
|
+
# :nocov:
|
165
|
+
end
|
166
|
+
|
167
|
+
private
|
168
|
+
|
169
|
+
def merge_url(options)
|
170
|
+
if not options[:url]
|
171
|
+
return
|
172
|
+
end
|
173
|
+
|
174
|
+
require 'uri'
|
175
|
+
parsed = URI.parse(options[:url])
|
176
|
+
parsed_port = parsed.port.to_i
|
177
|
+
from_parsed = {
|
178
|
+
phantomjs: {
|
179
|
+
scheme: parsed.scheme,
|
180
|
+
host: parsed.host,
|
181
|
+
port: nil,
|
182
|
+
},
|
183
|
+
}
|
184
|
+
|
185
|
+
# Very special case: if the parsed port matches the generated port,
|
186
|
+
# and the port is nil, we want to keep it that way for deduplication
|
187
|
+
# purposes. See `#fix_ports` for how this interacts.
|
188
|
+
port = options['phantomjs.port']
|
189
|
+
generated_port = options['phantomjs.generated_port']
|
190
|
+
if not (parsed_port == generated_port and port.nil?)
|
191
|
+
from_parsed[:phantomjs][:port] = parsed_port
|
192
|
+
end
|
193
|
+
|
194
|
+
options.recursive_merge!(from_parsed, false)
|
195
|
+
end
|
196
|
+
|
197
|
+
def merge_defaults(options)
|
198
|
+
defaults = {
|
199
|
+
phantomjs: {
|
200
|
+
scheme: 'http',
|
201
|
+
host: 'localhost',
|
202
|
+
port: nil,
|
203
|
+
generated_port: nil,
|
204
|
+
},
|
205
|
+
}
|
206
|
+
options.recursive_merge!(defaults, false)
|
207
|
+
end
|
208
|
+
|
209
|
+
def fix_ports(label, options)
|
210
|
+
# Let's keep the old ID around and generate a new one, largely as
|
211
|
+
# a checksum of the options.
|
212
|
+
old_id = options.delete('unobtainium_instance_id')
|
213
|
+
new_id = identifier('driver', label, options)
|
214
|
+
|
215
|
+
# If the IDs don't match, it means some options changed. This may be
|
216
|
+
# the port or another option:
|
217
|
+
# #1 If IDs are the same and port is the same as generated port, we
|
218
|
+
# need not do anything.
|
219
|
+
# #2 If IDs are the same and the ports differ, we have reached an
|
220
|
+
# undefined state. This should be impossible.
|
221
|
+
# #3 If IDs differ and the ports are the same, some other option was
|
222
|
+
# changed. We need to generate a new port and new ID (and warn about
|
223
|
+
# this).
|
224
|
+
# #4 If IDs differ and ports differ, a new port was set. We need to
|
225
|
+
# proceed with the new port and generate a new ID.
|
226
|
+
port = options['phantomjs.port']
|
227
|
+
generated_port = options['phantomjs.generated_port']
|
228
|
+
|
229
|
+
if old_id == new_id and port == generated_port
|
230
|
+
# #1 above, nothing to do.
|
231
|
+
elsif old_id == new_id and port != generated_port
|
232
|
+
# :nocov:
|
233
|
+
# #2 above, raise hell
|
234
|
+
if not port.nil?
|
235
|
+
raise "This can't happen; the instance ID (checksum) is the same, "\
|
236
|
+
"but the input differed: #{port} <-> #{generated_port}"
|
237
|
+
end
|
238
|
+
# :nocov:
|
239
|
+
elsif old_id != new_id and port == generated_port
|
240
|
+
# #3 above; nuke the ports and warn.
|
241
|
+
if not port.nil? and not generated_port.nil?
|
242
|
+
warn "Rejecting port #{port} and generating new port because "\
|
243
|
+
"options changed."
|
244
|
+
end
|
245
|
+
options['phantomjs.port'] = nil
|
246
|
+
options['phantomjs.generated_port'] = nil
|
247
|
+
elsif old_id != new_id and port != generated_port
|
248
|
+
# #4 above
|
249
|
+
options['phantomjs.generated_port'] = nil
|
250
|
+
else
|
251
|
+
# :nocov:
|
252
|
+
# Unreachable
|
253
|
+
raise "This can't happen; we have four cases and handle each of "\
|
254
|
+
"them. This line is unreachable. Please check the logic."
|
255
|
+
# :nocov:
|
256
|
+
end
|
141
257
|
end
|
142
258
|
end # class << self
|
143
259
|
end # class PhantomJS
|
@@ -64,7 +64,8 @@ module Unobtainium
|
|
64
64
|
|
65
65
|
# Merge 'caps' and 'desired_capabilities', letting the latter win
|
66
66
|
options[:desired_capabilities] =
|
67
|
-
::Collapsium::UberHash.new(options[
|
67
|
+
::Collapsium::UberHash.new(options['caps'])
|
68
|
+
.recursive_merge(options[:caps])
|
68
69
|
.recursive_merge(options[:desired_capabilities])
|
69
70
|
options.delete(:caps)
|
70
71
|
options.delete('caps')
|
@@ -82,8 +83,10 @@ module Unobtainium
|
|
82
83
|
##
|
83
84
|
# Create and return a driver instance
|
84
85
|
def create(label, options)
|
86
|
+
# :nocov:
|
85
87
|
driver = ::Selenium::WebDriver.for(normalize_label(label), options)
|
86
88
|
return driver
|
89
|
+
# :nocov:
|
87
90
|
end
|
88
91
|
|
89
92
|
private
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
#
|
3
|
+
# unobtainium
|
4
|
+
# https://github.com/jfinkhaeuser/unobtainium
|
5
|
+
#
|
6
|
+
# Copyright (c) 2016 Jens Finkhaeuser and other unobtainium contributors.
|
7
|
+
# All rights reserved.
|
8
|
+
#
|
9
|
+
module Unobtainium
|
10
|
+
# @api private
|
11
|
+
# Contains support code
|
12
|
+
module Support
|
13
|
+
# Contains code for dealing with instance identifiers.
|
14
|
+
module Identifiers
|
15
|
+
# Given a label and a set of options, generate a unique identifier
|
16
|
+
# string.
|
17
|
+
def identifier(scope, label, options = nil)
|
18
|
+
digest = { label: label, options: options }
|
19
|
+
require 'digest/sha1'
|
20
|
+
digest = Digest::SHA1.hexdigest(digest.to_s)
|
21
|
+
return "#{scope}-#{digest}"
|
22
|
+
end
|
23
|
+
end # module Identifiers
|
24
|
+
end # module Support
|
25
|
+
end # module Unobtainium
|
@@ -30,6 +30,12 @@ module Unobtainium
|
|
30
30
|
# A port scanner for finding a free port for running e.g. a selenium
|
31
31
|
# or appium server.
|
32
32
|
module PortScanner
|
33
|
+
# Retry a port this many times before failing
|
34
|
+
MAX_RETRIES = 5
|
35
|
+
|
36
|
+
# Delay each retry by this many seconds before trying again
|
37
|
+
RETRY_DELAY = 0.5
|
38
|
+
|
33
39
|
##
|
34
40
|
# Returns true if the port is open on the host, false otherwise.
|
35
41
|
# @param host [String] host name or IP address
|
@@ -175,14 +181,20 @@ module Unobtainium
|
|
175
181
|
sock = Socket.new(domain, :STREAM)
|
176
182
|
|
177
183
|
connected = false
|
184
|
+
tries = MAX_RETRIES
|
178
185
|
loop do
|
179
186
|
begin
|
180
187
|
sock.connect_nonblock(addr)
|
181
188
|
rescue Errno::EINPROGRESS
|
182
|
-
|
183
|
-
|
184
|
-
|
189
|
+
tries -= 1
|
190
|
+
if tries <= 0
|
191
|
+
# That's it, we've got enough.
|
192
|
+
break
|
185
193
|
end
|
194
|
+
|
195
|
+
# The result of select doesn't matter. What matters is that we wait
|
196
|
+
# for sock to become usable, or for the timeout to occur.
|
197
|
+
IO.select([sock], [sock], nil, RETRY_DELAY)
|
186
198
|
rescue Errno::EISCONN
|
187
199
|
connected = true
|
188
200
|
break
|
data/lib/unobtainium/version.rb
CHANGED
data/lib/unobtainium/world.rb
CHANGED
@@ -12,6 +12,7 @@ require 'collapsium-config'
|
|
12
12
|
|
13
13
|
require 'unobtainium/driver'
|
14
14
|
require 'unobtainium/runtime'
|
15
|
+
require 'unobtainium/support/identifiers'
|
15
16
|
|
16
17
|
module Unobtainium
|
17
18
|
##
|
@@ -63,6 +64,8 @@ module Unobtainium
|
|
63
64
|
end # module ClassMethods
|
64
65
|
extend ClassMethods
|
65
66
|
|
67
|
+
include ::Unobtainium::Support::Identifiers
|
68
|
+
|
66
69
|
##
|
67
70
|
# (see Driver#create)
|
68
71
|
#
|
@@ -93,6 +96,7 @@ module Unobtainium
|
|
93
96
|
next
|
94
97
|
end
|
95
98
|
label = base.gsub(/^\.drivers\./, '')
|
99
|
+
break
|
96
100
|
end
|
97
101
|
|
98
102
|
# Unfortunately, the "base" key may not be recognized by the drivers,
|
@@ -108,10 +112,10 @@ module Unobtainium
|
|
108
112
|
|
109
113
|
# Create a key for the label and options. This should always
|
110
114
|
# return the same key for the same label and options.
|
111
|
-
key =
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
+
key = options['unobtainum_instance_id']
|
116
|
+
if key.nil?
|
117
|
+
key = identifier('driver', label, options)
|
118
|
+
end
|
115
119
|
|
116
120
|
# Only create a driver with this exact configuration once. Unfortunately
|
117
121
|
# We'll have to bind the destructor to whatever configuration exists at
|
data/spec/data/driverconfig.yml
CHANGED
@@ -7,6 +7,11 @@
|
|
7
7
|
#
|
8
8
|
# so the order in this file has to be mock -> branch2 -> branch1 -> leaf
|
9
9
|
---
|
10
|
+
global:
|
11
|
+
global_opt: 'set'
|
12
|
+
|
13
|
+
driver: leaf
|
14
|
+
|
10
15
|
drivers:
|
11
16
|
mock:
|
12
17
|
mockoption: 42
|
@@ -16,11 +21,13 @@ drivers:
|
|
16
21
|
branch1:
|
17
22
|
extends: mock
|
18
23
|
branch1option: foo
|
24
|
+
branch3:
|
25
|
+
extends: .global
|
26
|
+
branch3option: baz
|
19
27
|
leaf:
|
20
|
-
extends: branch2
|
28
|
+
extends: .global, branch2
|
21
29
|
leafoption: baz
|
22
30
|
branch1option: override
|
23
31
|
base_does_not_exist:
|
24
32
|
extends: nonexistent_base
|
25
33
|
some: value
|
26
|
-
driver: leaf
|
data/spec/driver_spec.rb
CHANGED
@@ -34,7 +34,10 @@ end # module FakeModule
|
|
34
34
|
|
35
35
|
describe ::Unobtainium::Driver do
|
36
36
|
before :each do
|
37
|
-
::Unobtainium::Driver.register_implementation(MockDriver,
|
37
|
+
::Unobtainium::Driver.register_implementation(MockDriver,
|
38
|
+
"mock_driver.rb")
|
39
|
+
::Unobtainium::Driver.register_implementation(OptionResolvingMockDriver,
|
40
|
+
"mock_driver.rb")
|
38
41
|
end
|
39
42
|
|
40
43
|
describe "driver registration" do
|
@@ -101,6 +104,32 @@ describe ::Unobtainium::Driver do
|
|
101
104
|
drv = ::Unobtainium::Driver.create(:mock, foo: 42)
|
102
105
|
expect(drv.passed_options).to eql foo: 42
|
103
106
|
end
|
107
|
+
|
108
|
+
context "option resolution" do
|
109
|
+
it "provides defaults" do
|
110
|
+
drv = ::Unobtainium::Driver.create(:option_resolving)
|
111
|
+
expect(drv.options).to include(:foo)
|
112
|
+
expect(drv.options[:foo]).to eql 42
|
113
|
+
end
|
114
|
+
|
115
|
+
it "overrides when appropriate" do
|
116
|
+
drv = ::Unobtainium::Driver.create(:option_resolving, foo: 123)
|
117
|
+
expect(drv.options).to include(:foo)
|
118
|
+
expect(drv.options[:foo]).to eql 42
|
119
|
+
end
|
120
|
+
|
121
|
+
it "does not override always" do
|
122
|
+
drv = ::Unobtainium::Driver.create(:option_resolving, foo: 456)
|
123
|
+
expect(drv.options).to include(:foo)
|
124
|
+
expect(drv.options[:foo]).to eql 456
|
125
|
+
end
|
126
|
+
|
127
|
+
it "sets an instance ID" do
|
128
|
+
drv = ::Unobtainium::Driver.create(:option_resolving)
|
129
|
+
expect(drv.options).to include('unobtainium_instance_id')
|
130
|
+
expect(drv.options['unobtainium_instance_id']).to eql 'FIXED'
|
131
|
+
end
|
132
|
+
end
|
104
133
|
end
|
105
134
|
|
106
135
|
describe 'modules' do
|