Dduvall has submitted this change and it was merged.
Change subject: Refactored EAL configuration overrides
......................................................................
Refactored EAL configuration overrides
One big caveat of implementing `Environment#with` by cloning + using
instance evaluation over block evaluation with a normal closure is that
instance variables set within the scope of the given block are lost to
the original `Environment` object.
Step(...) do
@foo = "a"
with_alternative(...) do # or #on_wiki, #as_user, etc.
@foo = "b"
end
@foo == "b" # => false
end
This behavior would likely violate the principle of least surprise for
most users, so the cloning has been replaced by temporarily overwriting
environment config state, yielding normally (so the expected closure is
created), and restoring the original state.
Change-Id: I3444720eae3ff1d388e39529cb3589f786ead0ec
---
M lib/mediawiki_selenium/environment.rb
M spec/api_helper_spec.rb
M spec/environment_spec.rb
3 files changed, 93 insertions(+), 148 deletions(-)
Approvals:
Dduvall: Looks good to me, approved
jenkins-bot: Verified
diff --git a/lib/mediawiki_selenium/environment.rb
b/lib/mediawiki_selenium/environment.rb
index 823919f..31d1ca1 100644
--- a/lib/mediawiki_selenium/environment.rb
+++ b/lib/mediawiki_selenium/environment.rb
@@ -9,9 +9,6 @@
class Environment
include Comparable
- attr_reader :config
- protected :config
-
class << self
attr_accessor :default_configuration
@@ -52,12 +49,8 @@
self.default_configuration = "environments.yml"
def initialize(*configs)
- @config = configs.map { |config| normalize_config(config)
}.reduce(:merge)
- @factory_cache = {}
- end
-
- def initialize_clone(other)
- @config = other.config.clone
+ @_config = configs.map { |config| normalize_config(config)
}.reduce(:merge)
+ @_factory_cache = {}
end
# Whether the given environment is equal to this one. Two environments are
@@ -68,7 +61,7 @@
# @return [Boolean]
#
def ==(other)
- @config == other.config
+ config == other.config
end
# Returns the configured value for the given env variable name.
@@ -92,7 +85,7 @@
# @yieldparam user [String] Alternative MediaWiki user.
# @yieldparam password [String] Alternative MediaWiki password.
#
- # @return [Environment]
+ # @return self
#
def as_user(id, &blk)
with_alternative([:mediawiki_user, password_variable], id, &blk)
@@ -115,7 +108,7 @@
def browser_factory(browser = browser_name)
browser = browser.to_s.downcase.to_sym
- @factory_cache[[remote?, browser]] ||= BrowserFactory.new(browser).tap
do |factory|
+ @_factory_cache[[remote?, browser]] ||= BrowserFactory.new(browser).tap
do |factory|
factory.bind(:_browser_session)
factory.extend(RemoteBrowserFactory) if remote?
end
@@ -174,7 +167,7 @@
#
# @yield [*args] Overridden browser configuration.
#
- # @return [Environment]
+ # @return self
#
def in_browser(id, overrides = {}, &blk)
overrides = overrides.each.with_object({}) do |(name, value), hash|
@@ -212,7 +205,7 @@
key = "#{key}_#{options[:id]}" if options.fetch(:id, nil)
key = normalize_key(key)
- value = @config[key]
+ value = config[key]
if value.nil? || value.to_s.empty?
if options.include?(:default)
@@ -256,7 +249,7 @@
# @yield [wiki_url]
# @yieldparam wiki_url [String] Alternative wiki URL.
#
- # @return [Environment]
+ # @return self
#
def on_wiki(id, &blk)
with_alternative(:mediawiki_url, id, &blk)
@@ -296,7 +289,7 @@
# @yieldparam browser [Watir::Browser] Browser object, before it's closed.
#
def teardown(status = :passed)
- @factory_cache.each do |_, factory|
+ @_factory_cache.each do |_, factory|
factory.each do |browser|
yield browser if block_given?
browser.close unless keep_browser_open?
@@ -351,12 +344,12 @@
# @yield [url]
# @yieldparam url [String] Wiki URL.
#
- # @return [Environment]
+ # @return self
#
- def visit_wiki(id, &blk)
+ def visit_wiki(id)
on_wiki(id) do |url|
browser.goto url
- instance_exec(url, &blk) unless blk.nil?
+ yield url if block_given?
end
end
@@ -413,10 +406,16 @@
#
# @yield [*args] Values of the overridden configuration.
#
- # @return [Environment] The modified environment.
+ # @return self
#
def with_alternative(names, id, &blk)
with(lookup_all(Array(names), id: id), &blk)
+ end
+
+ protected
+
+ def config
+ @_config
end
private
@@ -438,12 +437,15 @@
key.to_s.downcase.to_sym
end
- def with(overrides = {}, &blk)
+ def with(overrides = {})
overrides = normalize_config(overrides)
+ original_config = @_config.dup
- clone.tap do |env|
- env.config.merge!(overrides)
- env.instance_exec(*overrides.values, &blk) unless blk.nil?
+ begin
+ @_config = @_config.merge(overrides)
+ yield *overrides.values if block_given?
+ ensure
+ @_config = original_config
end
end
end
diff --git a/spec/api_helper_spec.rb b/spec/api_helper_spec.rb
index 33bece0..1035c80 100644
--- a/spec/api_helper_spec.rb
+++ b/spec/api_helper_spec.rb
@@ -44,35 +44,6 @@
it "returns a cached client" do
expect(subject).to be(client)
end
-
- context "from an altered environment" do
- subject { env2.api }
-
- let(:env2) { env.on_wiki(:b) }
-
- context "with the same API URL" do
- let(:alternative_api_url) { api_url }
-
- it "returns a cached client" do
- expect(subject).to be(client)
- end
- end
-
- context "with a different API URL" do
- let(:alternative_api_url) { "http://another.example/api" }
-
- let(:client2) { double(MediawikiApi::Client) }
-
- before do
- expect(MediawikiApi::Client).to
receive(:new).with(alternative_api_url).and_return(client2)
- expect(client2).to receive(:log_in).with("mw user", "mw
password")
- end
-
- it "returns a new client" do
- expect(subject).not_to be(client)
- end
- end
- end
end
end
@@ -85,11 +56,12 @@
let(:alternative_api_url) { "http://another.example/api" }
it "executes in the new environment using the alternative wiki and API
URL" do
- _ = self
+ expect { |block| env.on_wiki(:b, &block) }.
+ to yield_with_args(alternative_wiki_url, alternative_api_url)
- env.on_wiki(:b) do |wiki_url, api_url|
- _.expect(wiki_url).to _.eq(_.alternative_wiki_url)
- _.expect(api_url).to _.eq(_.alternative_api_url)
+ env.on_wiki(:b) do
+ expect(env[:mediawiki_url]).to eq(alternative_wiki_url)
+ expect(env[:mediawiki_api_url]).to eq(alternative_api_url)
end
end
end
@@ -97,12 +69,13 @@
context "and no explicit API URL is configured for the wiki" do
let(:alternative_api_url) { "" }
- it "constructs one relative to the wiki URL" do
- _ = self
+ it "constructs one at /w/api.php relative to the wiki URL" do
+ expect { |block| env.on_wiki(:b, &block) }.
+ to yield_with_args(alternative_wiki_url,
"http://another.example/w/api.php")
- env.on_wiki(:b) do |wiki_url, api_url|
- _.expect(wiki_url).to _.eq(_.alternative_wiki_url)
- _.expect(api_url).to _.eq("http://another.example/w/api.php")
+ env.on_wiki(:b) do
+ expect(env[:mediawiki_url]).to eq(alternative_wiki_url)
+ expect(env[:mediawiki_api_url]).to
eq("http://another.example/w/api.php")
end
end
end
diff --git a/spec/environment_spec.rb b/spec/environment_spec.rb
index a3218d9..b417314 100644
--- a/spec/environment_spec.rb
+++ b/spec/environment_spec.rb
@@ -4,7 +4,7 @@
describe Environment do
subject { env }
- let(:env) { Environment.new(config).extend(ApiHelper) }
+ let(:env) { Environment.new(config) }
let(:config) { minimum_config }
let(:minimum_config) do
@@ -92,8 +92,6 @@
end
describe "#as_user" do
- subject { env.as_user(:b) {} }
-
let(:config) do
{
mediawiki_user: "user",
@@ -103,21 +101,13 @@
}
end
- let(:new_env) { double(Environment) }
- let(:new_config) { double(Hash) }
-
- before do
- expect(env).to receive(:clone).and_return(new_env)
- expect(new_env).to receive(:config).and_return(new_config)
- end
-
it "executes in the new environment for the alternative user and its
password" do
- expect(new_config).to receive(:merge!).with(
- mediawiki_user: "user b",
- mediawiki_password: "pass b",
- )
- expect(new_env).to receive(:instance_exec).with("user b", "pass b")
- subject
+ expect { |block| env.as_user(:b, &block) }.to yield_with_args("user
b", "pass b")
+
+ env.as_user(:b) do
+ expect(env[:mediawiki_user]).to eq("user b")
+ expect(env[:mediawiki_password]).to eq("pass b")
+ end
end
end
@@ -220,32 +210,23 @@
end
describe "#in_browser" do
- subject { env.in_browser(id, overrides) {} }
-
- let(:id) { :a }
- let(:overrides) { {} }
-
- let(:new_env) { double(Environment) }
- let(:new_config) { double(Hash) }
-
- before do
- expect(env).to receive(:clone).and_return(new_env)
- expect(new_env).to receive(:config).and_return(new_config)
- end
-
it "executes in the new environment with a new browser session" do
- expect(new_config).to receive(:merge!).with(_browser_session: id)
- expect(new_env).to receive(:instance_exec).with(id)
- subject
+ expect { |block| env.in_browser(:a, &block) }.to yield_with_args(:a)
+
+ env.in_browser(:a) do
+ expect(env[:_browser_session]).to eq(:a)
+ end
end
context "given browser configuration overrides" do
- let(:overrides) { { language: "eo" } }
-
it "executes in the new environment with the prefixed overrides" do
- expect(new_config).to receive(:merge!).with(_browser_session: id,
browser_language: "eo")
- expect(new_env).to receive(:instance_exec).with("eo", id)
- subject
+ expect { |block| env.in_browser(:a, language: "eo", &block) }.
+ to yield_with_args("eo", :a)
+
+ env.in_browser(:a, language: "eo") do
+ expect(env[:browser_language]).to eq("eo")
+ expect(env[:_browser_session]).to eq(:a)
+ end
end
end
end
@@ -313,10 +294,6 @@
end
describe "#on_wiki" do
- subject { env.on_wiki(id) {} }
-
- let(:id) { :b }
-
let(:config) do
{
mediawiki_url: "http://an.example/wiki",
@@ -325,18 +302,12 @@
}
end
- let(:new_env) { double(Environment) }
- let(:new_config) { double(Hash) }
-
- before do
- expect(env).to receive(:clone).and_return(new_env)
- expect(new_env).to receive(:config).and_return(new_config)
- end
-
it "executes in the new environment using the alternative wiki URL" do
- expect(new_config).to receive(:merge!).with(mediawiki_url:
"http://altb.example/wiki")
- expect(new_env).to
receive(:instance_exec).with("http://altb.example/wiki")
- subject
+ expect { |block| env.on_wiki(:b, &block) }.to
yield_with_args("http://altb.example/wiki")
+
+ env.on_wiki(:b) do
+ expect(env[:mediawiki_url]).to eq("http://altb.example/wiki")
+ end
end
end
@@ -387,7 +358,7 @@
describe "#wiki_url" do
subject { env.wiki_url(url) }
- let(:env) { Environment.new(mediawiki_url:
"http://an.example/wiki/").extend(ApiHelper) }
+ let(:env) { Environment.new(mediawiki_url: "http://an.example/wiki/") }
context "with no given url" do
let(:url) { nil }
@@ -432,50 +403,49 @@
end
describe "#with_alternative" do
- subject { env.with_alternative(names, id) {} }
-
let(:config) do
{
- mediawiki_url: "http://an.example/wiki",
- mediawiki_url_b: "http://alt.example/wiki",
- mediawiki_api_url: "http://an.example/api",
- mediawiki_api_url_b: "http://alt.example/api",
+ mediawiki_url: "http://a.example/wiki",
+ mediawiki_url_b: "http://b.example/wiki",
+ mediawiki_api_url: "http://a.example/api",
+ mediawiki_api_url_b: "http://b.example/api",
}
end
- let(:new_env) { double(Environment) }
- let(:new_config) { double(Hash) }
-
- before do
- expect(env).to receive(:clone).and_return(new_env)
- expect(new_env).to receive(:config).and_return(new_config)
- end
-
context "given one option name and an ID" do
- let(:names) { :mediawiki_url }
- let(:id) { :b }
-
it "executes in the new environment that substitutes it using the
alternative" do
- expect(new_config).to receive(:merge!).with(mediawiki_url:
"http://alt.example/wiki")
- expect(new_env).to
receive(:instance_exec).with("http://alt.example/wiki")
- subject
+ expect { |block| env.with_alternative(:mediawiki_url, :b, &block) }.
+ to yield_with_args("http://b.example/wiki")
+
+ env.with_alternative(:mediawiki_url, :b) do
+ expect(env[:mediawiki_url]).to eq("http://b.example/wiki")
+ end
end
end
context "given multiple option names and an ID" do
- let(:names) { [:mediawiki_url, :mediawiki_api_url] }
- let(:id) { :b }
-
it "executes in the new environment that substitutes both using the
alternatives" do
- expect(new_config).to receive(:merge!).with(
- mediawiki_url: "http://alt.example/wiki",
- mediawiki_api_url: "http://alt.example/api"
- )
- expect(new_env).to receive(:instance_exec).with(
- "http://alt.example/wiki",
- "http://alt.example/api"
- )
- subject
+ expect { |block| env.with_alternative([:mediawiki_url,
:mediawiki_api_url], :b, &block) }.
+ to yield_with_args("http://b.example/wiki", "http://b.example/api")
+
+ env.with_alternative([:mediawiki_url, :mediawiki_api_url], :b) do
+ expect(env[:mediawiki_url]).to eq("http://b.example/wiki")
+ expect(env[:mediawiki_api_url]).to eq("http://b.example/api")
+ end
+ end
+ end
+
+ context "following block evaluation" do
+ it "restores the original configuration" do
+ env.with_alternative(:mediawiki_url, :b)
+ expect(env[:mediawiki_url]).to eq("http://a.example/wiki")
+ end
+
+ context "when an exception is raised within the block" do
+ it "restores the original configuration and lets the exception be
raised" do
+ expect { env.with_alternative(:mediawiki_url, :b) { raise "error"
} }.to raise_error
+ expect(env[:mediawiki_url]).to eq("http://a.example/wiki")
+ end
end
end
end
--
To view, visit https://gerrit.wikimedia.org/r/180985
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I3444720eae3ff1d388e39529cb3589f786ead0ec
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/selenium
Gerrit-Branch: env-abstraction-layer
Gerrit-Owner: Dduvall <[email protected]>
Gerrit-Reviewer: Cmcmahon <[email protected]>
Gerrit-Reviewer: Dduvall <[email protected]>
Gerrit-Reviewer: Hashar <[email protected]>
Gerrit-Reviewer: Zfilipin <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits