diff options
Diffstat (limited to 'qa/qa/vendor/smocker')
-rw-r--r-- | qa/qa/vendor/smocker/event_payload.rb | 49 | ||||
-rw-r--r-- | qa/qa/vendor/smocker/history_response.rb | 52 | ||||
-rw-r--r-- | qa/qa/vendor/smocker/smocker_api.rb | 140 |
3 files changed, 241 insertions, 0 deletions
diff --git a/qa/qa/vendor/smocker/event_payload.rb b/qa/qa/vendor/smocker/event_payload.rb new file mode 100644 index 00000000000..4bf154b76c2 --- /dev/null +++ b/qa/qa/vendor/smocker/event_payload.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +module QA + module Vendor + module Smocker + class EventPayload + def initialize(hook_data) + @hook_data = hook_data + end + + def raw + @hook_data + end + + def event + raw[:object_kind]&.to_sym + end + + def project_name + raw.dig(:project, :name) + end + + def mr? + event == :merge_request + end + + def issue? + event == :issue + end + + def note? + event == :note + end + + def push? + event == :push + end + + def tag? + event == :tag + end + + def wiki? + event == :wiki_page + end + end + end + end +end diff --git a/qa/qa/vendor/smocker/history_response.rb b/qa/qa/vendor/smocker/history_response.rb new file mode 100644 index 00000000000..53d5759ef8b --- /dev/null +++ b/qa/qa/vendor/smocker/history_response.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require_relative './event_payload' +require 'time' + +module QA + module Vendor + module Smocker + class HistoryResponse + attr_reader :payload + + def initialize(payload) + @payload = payload + end + + # Smocker context including call counter + def context + payload[:context] + end + + # Smocker request data + def request + payload[:request] + end + + # @return [EventPayload] the request body as a webhook event + def as_hook_event + body = request&.dig(:body) + EventPayload.new body if body + end + + # @return [Time] Time request was recieved + def received + date = request&.dig(:date) + Time.parse date if date + end + + # Find time elapsed since <target> + # + # @param target [Time] target time + # @return [Integer] seconds elapsed since <target> + def elapsed(target) + (received.to_f - target.to_f).round if received + end + + def response + payload[:response] + end + end + end + end +end diff --git a/qa/qa/vendor/smocker/smocker_api.rb b/qa/qa/vendor/smocker/smocker_api.rb new file mode 100644 index 00000000000..3f595b58886 --- /dev/null +++ b/qa/qa/vendor/smocker/smocker_api.rb @@ -0,0 +1,140 @@ +# frozen_string_literal: true + +module QA + module Vendor + module Smocker + class SmockerApi + include Scenario::Actable + include Support::API + + DEFAULT_MOCK = <<~YAML + - request: + method: POST + path: /default + response: + headers: + Content-Type: application/json + body: '{}' + YAML + + # @param wait [Integer] seconds to wait for server + # @yieldparam [SmockerApi] the api object ready for interaction + def self.init(**wait_args) + if @container.nil? + @container = Service::DockerRun::Smocker.new + @container.register! + @container.wait_for_running + end + + yield new(@container, **wait_args) + end + + def self.teardown! + @container&.remove! + end + + def initialize(container, **wait_args) + @container = container + wait_for_ready(**wait_args) + end + + # @return [String] Base url of mock endpoint + def base_url + @container.base_url + end + + # @return [String] Url of admin endpoint + def admin_url + @container.admin_url + end + + # @param endpoint [String] path for mock endpoint + # @return [String] url for mock endpoint + def url(endpoint = 'default') + "#{base_url}/#{endpoint}" + end + + # Waits for the smocker server to be ready + # + # @param wait [Integer] wait duration for smocker readiness + def wait_for_ready(wait: 10) + Support::Waiter.wait_until(max_duration: wait, reload_page: false, raise_on_failure: true) do + ready? + end + end + + # Is smocker server ready for interaction? + # + # @return [Boolean] + def ready? + QA::Runtime::Logger.debug 'Checking Smocker readiness' + get("#{admin_url}/version") + true + # rescuing StandardError because RestClient::ExceptionWithResponse isn't propagating + rescue StandardError => e + QA::Runtime::Logger.debug "Smocker not ready yet \n #{e}" + false + end + + # Clears mocks and history + # + # @param force [Boolean] remove locked mocks? + # @return [Boolean] reset was successful? + def reset(force: true) + response = post("#{admin_url}/reset?force=#{force}", {}.to_json) + parse_body(response)['message'] == 'Reset successful' + end + + # Fetches an active session id from a name + # + # @param name [String] the name of the session + # @return [String] the unique session id + def get_session_id(name) + sessions = parse_body get("#{admin_url}/sessions/summary") + current = sessions.find do |session| + session[:name] == name + end + current&.dig(:id) + end + + # Registers a mock to Smocker + # If a session name is provided, the mock will register to that session + # https://smocker.dev/technical-documentation/mock-definition.html + # + # @param yaml [String] the yaml representing the mock + # @param session [String] the session name for the mock + def register(yaml = DEFAULT_MOCK, session: nil) + query_params = build_params(session: session) + url = "#{admin_url}/mocks?#{query_params}" + headers = { 'Content-Type' => 'application/x-yaml' } + response = post(url, yaml, headers: headers) + parse_body(response) + end + + # Fetches call history for a mock + # + # @param session_name [String] the session name for the mock + # @return [Array<HistoryResponse>] + def history(session_name = nil) + query_params = session_name ? build_params(session: get_session_id(session_name)) : '' + response = get("#{admin_url}/history?#{query_params}") + body = parse_body(response) + + raise body[:message] unless body.is_a?(Array) + + body.map do |entry| + HistoryResponse.new(entry) + end + end + + private + + def build_params(**args) + args.each_with_object([]) do |(k, v), memo| + memo << "#{k}=#{v}" if v + end.join("&") + end + end + end + end +end |