summaryrefslogtreecommitdiff
path: root/qa/qa/factory/api_fabricator.rb
diff options
context:
space:
mode:
Diffstat (limited to 'qa/qa/factory/api_fabricator.rb')
-rw-r--r--qa/qa/factory/api_fabricator.rb97
1 files changed, 97 insertions, 0 deletions
diff --git a/qa/qa/factory/api_fabricator.rb b/qa/qa/factory/api_fabricator.rb
new file mode 100644
index 00000000000..b1cfb6c9783
--- /dev/null
+++ b/qa/qa/factory/api_fabricator.rb
@@ -0,0 +1,97 @@
+# frozen_string_literal: true
+
+require 'airborne'
+require 'active_support/core_ext/object/deep_dup'
+require 'capybara/dsl'
+
+module QA
+ module Factory
+ module ApiFabricator
+ include Airborne
+ include Capybara::DSL
+
+ HTTP_STATUS_OK = 200
+ HTTP_STATUS_CREATED = 201
+
+ ResourceNotFoundError = Class.new(RuntimeError)
+ ResourceFabricationFailedError = Class.new(RuntimeError)
+ ResourceURLMissingError = Class.new(RuntimeError)
+
+ attr_reader :api_resource, :api_response
+
+ def api_support?
+ respond_to?(:api_get_path) &&
+ respond_to?(:api_post_path) &&
+ respond_to?(:api_post_body)
+ end
+
+ def fabricate_via_api!
+ unless api_support?
+ raise NotImplementedError, "Factory #{self.class.name} does not support fabrication via the API!"
+ end
+
+ resource_web_url(api_post)
+ end
+
+ def eager_load_api_client!
+ api_client.tap do |client|
+ # Eager-load the API client so that the personal token creation isn't
+ # taken in account in the actual resource creation timing.
+ client.personal_access_token
+ end
+ end
+
+ private
+
+ attr_writer :api_resource, :api_response
+
+ def resource_web_url(resource)
+ resource.fetch(:web_url) do
+ raise ResourceURLMissingError, "API resource for #{self.class.name} does not expose a `web_url` property: `#{resource}`."
+ end
+ end
+
+ def api_get
+ url = Runtime::API::Request.new(api_client, api_get_path).url
+ response = get(url)
+
+ unless response.code == HTTP_STATUS_OK
+ raise ResourceNotFoundError, "Resource at #{url} could not be found (#{response.code}): `#{response}`."
+ end
+
+ process_api_response(parse_body(response))
+ end
+
+ def api_post
+ response = post(
+ Runtime::API::Request.new(api_client, api_post_path).url,
+ api_post_body)
+
+ unless response.code == HTTP_STATUS_CREATED
+ raise ResourceFabricationFailedError, "Fabrication of #{self.class.name} using the API failed (#{response.code}) with `#{response}`."
+ end
+
+ process_api_response(parse_body(response))
+ end
+
+ def api_client
+ @api_client ||= begin
+ Runtime::API::Client.new(:gitlab, is_new_session: !current_url.start_with?('http'))
+ end
+ end
+
+ def parse_body(response)
+ JSON.parse(response.body, symbolize_names: true)
+ end
+
+ def process_api_response(parsed_response)
+ self.api_response = parsed_response
+ self.api_resource = transform_api_resource(parsed_response.deep_dup)
+ end
+
+ def transform_api_resource(resource)
+ resource
+ end
+ end
+ end
+end