diff options
author | Lin Jen-Shin <godfat@godfat.org> | 2018-11-02 17:32:28 +0800 |
---|---|---|
committer | Lin Jen-Shin <godfat@godfat.org> | 2018-11-05 22:20:57 +0800 |
commit | 4d0fd75cd5ceda72692a229d27ab6891fa8082e0 (patch) | |
tree | 7448b28ca974c9480e1e96b0d90c1322eeb9f0c7 /qa/qa/resource/base.rb | |
parent | c12a4a9ac7c04a215adf6062fec7bf31231c7d4a (diff) | |
download | gitlab-ce-4d0fd75cd5ceda72692a229d27ab6891fa8082e0.tar.gz |
Rename QA::Factory to QA::Resource53224-rename-to-resource-base-qa
* Factory::Base -> Resource::Base, and therefore:
* Factory::Resource::Project -> Resource::Project
Diffstat (limited to 'qa/qa/resource/base.rb')
-rw-r--r-- | qa/qa/resource/base.rb | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/qa/qa/resource/base.rb b/qa/qa/resource/base.rb new file mode 100644 index 00000000000..f3eefb70520 --- /dev/null +++ b/qa/qa/resource/base.rb @@ -0,0 +1,154 @@ +# frozen_string_literal: true + +require 'forwardable' +require 'capybara/dsl' + +module QA + module Resource + class Base + extend SingleForwardable + include ApiFabricator + extend Capybara::DSL + + NoValueError = Class.new(RuntimeError) + + def_delegators :evaluator, :attribute + + def fabricate!(*_args) + raise NotImplementedError + end + + def visit! + visit(web_url) + end + + def populate(*attributes) + attributes.each(&method(:public_send)) + end + + private + + def populate_attribute(name, block) + value = attribute_value(name, block) + + raise NoValueError, "No value was computed for #{name} of #{self.class.name}." unless value + + value + end + + def attribute_value(name, block) + api_value = api_resource&.dig(name) + + if api_value && block + log_having_both_api_result_and_block(name, api_value) + end + + api_value || (block && instance_exec(&block)) + end + + def log_having_both_api_result_and_block(name, api_value) + QA::Runtime::Logger.info "<#{self.class}> Attribute #{name.inspect} has both API response `#{api_value}` and a block. API response will be picked. Block will be ignored." + end + + def self.fabricate!(*args, &prepare_block) + fabricate_via_api!(*args, &prepare_block) + rescue NotImplementedError + fabricate_via_browser_ui!(*args, &prepare_block) + end + + def self.fabricate_via_browser_ui!(*args, &prepare_block) + options = args.extract_options! + resource = options.fetch(:resource) { new } + parents = options.fetch(:parents) { [] } + + do_fabricate!(resource: resource, prepare_block: prepare_block, parents: parents) do + log_fabrication(:browser_ui, resource, parents, args) { resource.fabricate!(*args) } + + current_url + end + end + + def self.fabricate_via_api!(*args, &prepare_block) + options = args.extract_options! + resource = options.fetch(:resource) { new } + parents = options.fetch(:parents) { [] } + + raise NotImplementedError unless resource.api_support? + + resource.eager_load_api_client! + + do_fabricate!(resource: resource, prepare_block: prepare_block, parents: parents) do + log_fabrication(:api, resource, parents, args) { resource.fabricate_via_api! } + end + end + + def self.do_fabricate!(resource:, prepare_block:, parents: []) + prepare_block.call(resource) if prepare_block + + resource_web_url = yield + resource.web_url = resource_web_url + + resource + end + private_class_method :do_fabricate! + + def self.log_fabrication(method, resource, parents, args) + return yield unless Runtime::Env.debug? + + start = Time.now + prefix = "==#{'=' * parents.size}>" + msg = [prefix] + msg << "Built a #{name}" + msg << "as a dependency of #{parents.last}" if parents.any? + msg << "via #{method}" + + yield.tap do + msg << "in #{Time.now - start} seconds" + puts msg.join(' ') + puts if parents.empty? + end + end + private_class_method :log_fabrication + + def self.evaluator + @evaluator ||= Base::DSL.new(self) + end + private_class_method :evaluator + + def self.dynamic_attributes + const_get(:DynamicAttributes) + rescue NameError + mod = const_set(:DynamicAttributes, Module.new) + + include mod + + mod + end + + def self.attributes_names + dynamic_attributes.instance_methods(false).sort.grep_v(/=$/) + end + + class DSL + def initialize(base) + @base = base + end + + def attribute(name, &block) + @base.dynamic_attributes.module_eval do + attr_writer(name) + + define_method(name) do + instance_variable_get("@#{name}") || + instance_variable_set( + "@#{name}", + populate_attribute(name, block)) + end + end + end + end + + attribute :web_url + end + end +end |