blob: b912e29a80c9f4860e7ac321fab7c9b778f19a80 [file] [log] [blame]
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
require 'rubygems'
require 'require_relative' if RUBY_VERSION < '1.9'
require_relative '../helpers/common.rb'
require_relative 'common_tests_collections.rb'
require 'singleton'
module Deltacloud
module Test
class Config
include Singleton
def initialize
@hash = Deltacloud::Test::yaml_config
end
def url
@hash["api_url"]
end
def basic_auth(u = nil, p = nil)
u ||= @hash[driver]["user"]
p ||= @hash[driver]["password"]
"Basic #{Base64.encode64("#{u}:#{p}")}"
end
def bucket_locations
@hash[driver]["bucket_locations"]
end
def preferred
@hash[driver]["preferred"] || {}
end
def driver
xml.root[:driver]
end
def drivers
@drivers ||= RestClient.get(url+"/drivers").xml.xpath("//driver/name").map { |c| c.text.downcase }
end
def version
xml.root[:version]
end
def collections
xml.xpath("//api/link").map { |c| c[:rel].to_sym }
end
def features
result = {}
xml.xpath("//api/link").each do |coll|
result[coll[:rel].to_sym] = coll.xpath("feature").map { |c| c[:name].to_sym }
end
result
end
private
def xml
unless @xml
begin
@xml = RestClient.get(url).xml
drv = @xml.root[:driver]
rescue RestClient::Unauthorized => e
#need to do this by hand - RestClient only return exception for 4XX
#(e.g. Openstack needs creds for /api) - but headers contain driver
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Get.new(uri.path)
res = http.request(request)
drv = res["X-Deltacloud-Driver"]
u,p = [@hash[drv]["user"], @hash[drv]["password"]]
@xml = RestClient.get(url, {'Authorization' => "Basic #{Base64.encode64("#{u}:#{p}")}"}).xml
end
unless @hash[drv]
raise "No config for #{drv} driver in config.yaml used by #{url}"
end
unless @hash[drv]["user"] && @hash[drv]["password"]
raise "No user or password in config.yaml for #{drv} driver used by #{url}"
end
end
@xml
end
end
def self.config
Config::instance
end
end
end
module Deltacloud::Test::Methods
module Global
# Return the current test config; we call that 'api' since it looks a
# little prettier in the tests
def api
Deltacloud::Test::config
end
# Make a GET request for +path+ and return the +RestClient::Response+. The
# query string for the request is generated from +params+, with the
# exception of a few special entries in params, which are used to set some
# headers, and will not appear in the query string:
#
# :noauth : do not send an auth header
# :user, :password : use these for the auth header
# :accept : can be :xml or :json, and sets the Accept header
# :driver, :provider : set driver and/or provider with the appropriate header
# :content_type : set content_type for upload (e.g. put blob)
# :x_deltacloud_blobmeta-X : set deltacloud blob metadata
#
# If none of the auth relevant params are set, use the username and
# password for the current driver from the config
def get(path, params={})
url, headers = process_url_params(path, params)
RestClient.get url, headers
end
def post(path, post_body, params={})
if api.preferred["provider"] and not params[:provider]
params[:provider] = api.preferred["provider"]
end
url, headers = process_url_params(path, params)
RestClient.post url, post_body, headers
end
def put(path, body, params={})
url, headers = process_url_params(path, params)
if body.is_a?(File)
#set timeouts http://rdoc.info/github/archiloque/rest-client/RestClient/Resource
resource = RestClient::Resource.new(url, :open_timeout => 120, :timeout=> 9999)
resource.put body.read, headers
else
RestClient.put url, body, headers
end
end
def delete(path, params={})
url, headers = process_url_params(path, params)
RestClient.delete url, headers
end
def options(path, params={})
url, headers = process_url_params(path, params)
RestClient.options url, headers
end
def head(path, params={})
url, headers = process_url_params(path, params)
RestClient.head url, headers
end
def random_name
name = rand(36**10).to_s(36)
name.insert(0, "dcapitest")
end
def get_a(item)
if api.preferred[item]
item_id = api.preferred[item]
else
item_list = get("/#{item.pluralize}")
item_id = (item_list.xml/"#{item.pluralize}/#{item}").to_a.choice[:id]
end
end
private
def process_url_params(path, params)
path = "" if path == "/"
headers = {}
unless params.delete(:noauth)
if params[:user]
u = params.delete(:user)
p = params.delete(:password)
headers['Authorization'] = api.basic_auth(u, p)
else
headers['Authorization'] = api.basic_auth
end
end
headers["X-Deltacloud-Driver"] = params.delete(:driver) if params[:driver]
headers["X-Deltacloud-Provider"] = params.delete(:provider) if params[:provider]
if params[:accept]
headers["Accept"] = "application/#{params.delete(:accept)}" if params[:accept]
else #default to xml
headers["Accept"] = "application/xml"
end
headers[:content_type] = params.delete(:content_type) if params[:content_type]
#grab X-Deltacloud-Blobmeta headers for blob metadata:
params.inject({}) do |res, (cur_k, cur_v)|
headers[cur_k] = params.delete(cur_k) if cur_k =~ /X-Deltacloud-Blobmeta/i
res
end
if path =~ /^https?:/
url = path
else
url = path.start_with?("/", ";") ? api.url + path : api.url+"/"+ path
end
url += "?" + params.map { |k,v| "#{k}=#{v}" }.join("&") unless params.empty?
if ENV["LOG"] && ENV["LOG"].include?("requests")
puts "GET #{url}"
headers.each { |k, v| puts "#{k}: #{v}" }
end
[url, headers]
end
end
module ClassMethods
# Only run tests if collection +name+ is supported by current
# driver. Use inside a 'describe' block. Tests that are not run because
# of a missing collection are marked as skipped
def need_collection(name)
before :each do
unless api.collections.include?(name.to_sym)
skip "#{api.driver} doesn't support #{name}"
end
end
end
#convenience method for checking if collection :foo is supported:
def collection_supported(name)
api.collections.include?(name.to_sym)
end
# Only run tests if collection +collection+ supports feature +name+ in
# the current driver. Use inside a 'describe' block. Tests that are not
# run because of a missing collection are marked as skipped
def need_feature(collection, name)
before :each do
f = api.features[collection.to_sym]
unless f && f.include?(name.to_sym)
skip "#{collection} for #{api.driver} doesn't support #{name}"
end
end
end
end
def self.included(base)
base.extend ClassMethods
base.extend Global
base.send(:include, Global)
end
end