Skip to content

Commit

Permalink
Avoid instance_eval by patching all the request helpers
Browse files Browse the repository at this point in the history
Creates a `RequestHelpers` module in a distinct `Spec::Support::Api`
namespace (and moves the `ApiHelper` in there for consistency) with
patched versions of the request helpers provided by Rails.
  • Loading branch information
imtayadeway committed Sep 14, 2017
1 parent d10fbc6 commit 0fdf463
Show file tree
Hide file tree
Showing 5 changed files with 290 additions and 258 deletions.
3 changes: 2 additions & 1 deletion spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
Dir[Rails.root.join("spec/shared/**/*.rb")].each { |f| require f }

RSpec.configure do |config|
config.include Spec::Support::ApiHelper, :type => :request
config.include Spec::Support::Api::Helpers, :type => :request
config.include Spec::Support::Api::RequestHelpers, :type => :request
config.define_derived_metadata(:type => :request) do |metadata|
metadata[:aggregate_failures] = true
end
Expand Down
246 changes: 246 additions & 0 deletions spec/support/api/helpers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
#
# For testing REST API via Rspec requests
#

module Spec
module Support
module Api
module Helpers
def resources_include_suffix?(resources, key, suffix)
resources.any? { |r| r.key?(key) && r[key].match("#{suffix}$") }
end

def api_config(param)
@api_config ||= {
:user => "api_user_id",
:password => "api_user_password",
:user_name => "API User",
:group_name => "API User Group",
:role_name => "API User Role",
:entrypoint => "/api"
}
@api_config[param]
end

def define_user
@role = FactoryGirl.create(:miq_user_role, :name => api_config(:role_name))
@group = FactoryGirl.create(:miq_group, :description => api_config(:group_name), :miq_user_role => @role)
@user = FactoryGirl.create(:user,
:name => api_config(:user_name),
:userid => api_config(:user),
:password => api_config(:password),
:miq_groups => [@group],
:current_group_id => @group.id)
end

def init_api_spec_env
@guid, @server, @zone = EvmSpecHelper.create_guid_miq_server_zone
@region = FactoryGirl.create(:miq_region, :region => ApplicationRecord.my_region_number)

define_user
end

def api_basic_authorize(*identifiers)
update_user_role(@role, *identifiers)
basic_authorize api_config(:user), api_config(:password)
end

def basic_authorize(user, password)
request_headers["HTTP_AUTHORIZATION"] = ActionController::HttpAuthentication::Basic.encode_credentials(user, password)
end

def update_user_role(role, *identifiers)
return if identifiers.blank?
product_features = identifiers.flatten.collect do |identifier|
MiqProductFeature.find_or_create_by(:identifier => identifier)
end
role.update_attributes!(:miq_product_features => product_features)
end

def stub_api_action_role(collection, action_type, method, action, identifier)
new_action_role = Config::Options.new.merge!("name" => action.to_s, "identifier" => identifier)
updated_method = ::Api::ApiConfig.collections[collection][action_type][method].collect do |method_action|
method_action.name == action.to_s ? new_action_role : method_action
end
allow(::Api::ApiConfig.collections[collection][action_type]).to receive(method) { updated_method }
end

def action_identifier(type, action, selection = :resource_actions, method = :post)
::Api::ApiConfig
.collections[type][selection][method]
.detect { |spec| spec[:name] == action.to_s }[:identifier]
end

def collection_action_identifier(type, action, method = :post)
action_identifier(type, action, :collection_actions, method)
end

def subcollection_action_identifier(type, subtype, action, method = :post)
subtype_actions = "#{subtype}_subcollection_actions".to_sym
if ::Api::ApiConfig.collections[type][subtype_actions]
action_identifier(type, action, subtype_actions, method)
else
action_identifier(subtype, action, :subcollection_actions, method)
end
end

def gen_request(action, data = nil, *hrefs)
request = {"action" => action.to_s}
if hrefs.present?
data ||= {}
request["resources"] = hrefs.collect { |href| data.dup.merge("href" => href) }
elsif data.present?
request[data.kind_of?(Array) ? "resources" : "resource"] = data
end
request
end

def declare_actions(*names)
include("actions" => a_collection_containing_exactly(*names.map { |name| a_hash_including("name" => name) }))
end

def include_actions(*names)
include("actions" => a_collection_including(*names.map { |name| a_hash_including("name" => name) }))
end

def include_error_with_message(error_message)
include("error" => hash_including("message" => a_string_matching(error_message)))
end

# Rest API Expects

def expect_bad_request(error_message)
expect(response.parsed_body).to include_error_with_message(error_message)
expect(response).to have_http_status(:bad_request)
end

def expect_result_resources_to_include_data(collection, data)
expect(response.parsed_body).to have_key(collection)
data.each do |key, value_list|
expect(response.parsed_body[collection].size).to eq(value_list.size)
expect(response.parsed_body[collection].collect { |r| r[key] }).to match_array(value_list)
end
end

def expect_result_resources_to_include_hrefs(collection, hrefs)
expect(response.parsed_body).to have_key(collection)
expect(response.parsed_body[collection].size).to eq(hrefs.size)
hrefs.each do |href|
expect(resources_include_suffix?(response.parsed_body[collection], "href", href)).to be_truthy
end
end

def expect_result_to_have_keys(keys)
expect(response.parsed_body).to include(*keys)
end

def expect_result_to_have_only_keys(keys)
expect_hash_to_have_only_keys(response.parsed_body, keys)
end

def expect_hash_to_have_only_keys(hash, keys)
expect(hash.keys).to match_array(keys)
end

def expect_result_to_match_hash(result, attr_hash)
attr_hash.each do |key, value|
attr_hash[key] = key == "href" || key.ends_with?("_href") ? a_string_matching(value) : value
end
expect(result).to include(attr_hash)
end

def expect_results_to_match_hash(collection, result_hash)
expect(response.parsed_body).to have_key(collection)
result_hash.zip(response.parsed_body[collection]) do |expected, actual|
expect_result_to_match_hash(actual, expected)
end
end

def expect_result_resources_to_match_hash(result_hash)
expect_results_to_match_hash("resources", result_hash)
end

def expect_result_resources_to_include_keys(collection, keys)
expect(response.parsed_body).to include(collection => all(a_hash_including(*keys)))
end

# Primary result construct methods

def expect_empty_query_result(collection)
expect(response).to have_http_status(:ok)
expect(response.parsed_body).to include("name" => collection.to_s, "resources" => [])
end

def expect_query_result(collection, subcount, count = nil)
expect(response).to have_http_status(:ok)
expect(response.parsed_body).to include("name" => collection.to_s, "subcount" => subcount)
expect(response.parsed_body["resources"].size).to eq(subcount)
expect(response.parsed_body["count"]).to eq(count) if count.present?
end

def expect_single_resource_query(attr_hash)
expect(response).to have_http_status(:ok)
expect_result_to_match_hash(response.parsed_body, attr_hash)
end

def expect_single_action_result(options = {})
expect(response).to have_http_status(:ok)
expected = {}
expected["success"] = options[:success] if options.key?(:success)
expected["message"] = a_string_matching(options[:message]) if options[:message]
expected["href"] = a_string_matching(options[:href]) if options[:href]
expected.merge!(expected_task_response) if options[:task]
expect(response.parsed_body).to include(expected)
expect(response.parsed_body).not_to include("actions")
end

def expect_multiple_action_result(count, options = {})
expect(response).to have_http_status(:ok)
expected_result = {"success" => true}
expected_result.merge!(expected_task_response) if options[:task]
expected = {"results" => Array.new(count) { a_hash_including(expected_result) }}
expect(response.parsed_body).to include(expected)
end

def expected_task_response
{"task_id" => anything, "task_href" => anything}
end

def expect_tagging_result(tag_results)
expect(response).to have_http_status(:ok)
expect(response.parsed_body).to have_key("results")
results = response.parsed_body["results"]
expect(results.size).to eq(tag_results.size)
tag_results.zip(results) do |tag_result, result|
expect(result).to include(
"success" => tag_result[:success],
"href" => a_string_matching(tag_result[:href]),
"tag_category" => tag_result[:tag_category],
"tag_name" => tag_result[:tag_name]
)
end
end

def expect_options_results(type, data = {})
klass = ::Api::ApiConfig.collections[type].klass.constantize
attributes = select_attributes(klass.attribute_names - klass.virtual_attribute_names)
reflections = (klass.reflections.keys | klass.virtual_reflections.keys.collect(&:to_s)).sort
subcollections = Array(::Api::ApiConfig.collections[type].subcollections).collect(&:to_s).sort
expected = {
'attributes' => attributes,
'virtual_attributes' => select_attributes(klass.virtual_attribute_names),
'relationships' => reflections,
'subcollections' => subcollections,
'data' => data
}
expect(response.parsed_body).to eq(expected)
expect(response.headers['Access-Control-Allow-Methods']).to include('OPTIONS')
end

def select_attributes(attrlist)
attrlist.sort.select { |attr| !::Api.encrypted_attribute?(attr) }
end
end
end
end
end
42 changes: 42 additions & 0 deletions spec/support/api/request_helpers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# rubocop:disable Style/HashSyntax
module Spec
module Support
module Api
module RequestHelpers
def get(path, **args)
process(:get, path, **args)
end

def post(path, **args)
process(:post, path, **args)
end

def patch(path, **args)
process(:patch, path, **args)
end

def put(path, **args)
process(:put, path, **args)
end

def delete(path, **args)
process(:delete, path, **args)
end

def options(path, **args)
process(:options, path, **args)
end

def process(method, path, params: nil, headers: nil, env: nil, xhr: false, as: nil)
headers = request_headers.merge(Hash(headers))
as ||= :json if [:post, :put, :patch].include?(method)
super(method, path, params: params, headers: headers, env: env, xhr: xhr, as: as)
end

def request_headers
@request_headers ||= {}
end
end
end
end
end
Loading

0 comments on commit 0fdf463

Please sign in to comment.