This commit is contained in:
amartynov 2015-10-29 12:58:03 +03:00
commit c64a39b798
73 changed files with 1390 additions and 1585 deletions

View File

@ -1,7 +1,6 @@
#!/usr/bin/env ruby
require 'rubygems'
require 'bundler'
Bundler.require(:default, :development)
require 'devops-client'
DevopsClient.run

View File

@ -94,19 +94,36 @@ module Devops
end
end
def add_or_update_deploy_env id, deploy_env
def update_deploy_env_field id, deploy_env, field
project = Devops::Db.connector.project(id)
env = parser.add_or_update_deploy_env
db_env = project.deploy_env(deploy_env)
value = parser.update_deploy_env_field
if db_env.respond_to?(field + "=")
if field == "identifier"
db_env.rename id, value
"Environment '#{deploy_env}' has been renamed to '#{value}'"
else
db_env.update_field(id, field, value)
"Environment's field '#{field}' has been updated"
end
else
raise RecordNotFound.new("Field '#{field}' does not exist")
end
end
def update_deploy_env id, deploy_env
project = Devops::Db.connector.project(id)
db_env = project.deploy_env(deploy_env)
env = parser.update_deploy_env
env.identifier = deploy_env if env.identifier.nil?
begin
db_env = project.deploy_env(deploy_env)
unless env.identifier == deploy_env
servers = Devops::Db.connector.servers_by_project_and_deploy_env(id, deploy_env)
raise InvalidRecord.new("Can not update environment '#{deploy_env}', there are #{servers.size} servers on it") unless servers.empty?
raise InvalidRecord.new("Environment '#{deploy_env}' can't be updated: it has #{servers.size} running servers.") unless servers.empty?
end
begin
project.deploy_env(env.identifier)
raise InvalidRecord.new("Can not change environment '#{deploy_env}' to '#{env.identifier}', environment '#{env.identifier}' already exist") unless deploy_env == env.identifier
raise InvalidRecord.new("Environment '#{deploy_env}' can't be renamed to '#{env.identifier}', environment '#{env.identifier}' already exists") unless deploy_env == env.identifier
rescue RecordNotFound => e
end
env.validate!
@ -168,13 +185,15 @@ module Devops
def delete_project id
deploy_env = parser.delete
servers = Devops::Db.connector.servers id
raise DependencyError.new "Deleting #{id} is forbidden: Project has servers" if !servers.empty?
project = Devops::Db.connector.project(id)
info = if deploy_env.nil?
if deploy_env.nil?
servers = Devops::Db.connector.servers id
raise DependencyError.new "Deleting project #{id} is forbidden: Project has servers" unless servers.empty?
project.delete
"Project '#{id}' is deleted"
else
servers = Devops::Db.connector.servers id, deploy_env
raise DependencyError.new "Deleting deploy_env #{deploy_env} is forbidden: Project has servers" unless servers.empty?
project.delete_deploy_env(deploy_env)
"Project '#{id}'. Deploy environment '#{deploy_env}' has been deleted"
end
@ -279,49 +298,6 @@ module Devops
return [uri]
end
=begin
def create_roles project_id, envs
all_roles = KnifeFactory.instance.roles
return " Can't get roles list" if all_roles.nil?
roles = {:new => [], :error => [], :exist => []}
envs.each do |e|
role_name = KnifeCommands.role_name(project_id, e.identifier)
begin
if all_roles.include? role_name
roles[:exist].push role_name
else
KnifeCommands.create_role role_name, project_id, e.identifier
roles[:new].push role_name
DevopsLogger.logger.info "Role '#{role_name}' created"
end
rescue => er
roles[:error].push role_name
DevopsLogger.logger.error "Role '#{role_name}' can not be created: #{er.message}"
end
end
roles
end
def create_new_roles old_project, new_project
old_project.deploy_envs.each do |e|
new_project.deploy_envs.delete_if {|env| e.identifier == env.identifier}
end
create_roles new_project.id, new_project.deploy_envs
end
def create_roles_response roles
if roles.is_a?(String)
roles
else
info = ""
info += " Project roles '#{roles[:new].join("', '")}' have been automaticaly created" unless roles[:new].empty?
info += " Project roles '#{roles[:exist].join("', '")}' weren't created because they exist" unless roles[:exist].empty?
info += " Project roles '#{roles[:error].join("', '")}' weren't created because of internal error" unless roles[:error].empty?
info
end
end
=end
end
end
end

View File

@ -35,22 +35,29 @@ module Devops
if envs_with_this_template.empty?
Devops::Db.connector.stack_template_delete id
else
raise ConflictException.new("Stack template '#{id}' is already in use in #{envs_with_this_template.join(', ')}")
raise ConflictException.new("Stack template '#{id}' is already in use in #{envs_with_this_template.map{|project, envs| "#{project}: #{envs.join(', ')}"}.join('; ')}", {projects: envs_with_this_template})
end
end
private
# returns:
# {
# "project" => ["deploy_env"]
# }
def envs_using_stack_template(id)
projects = Devops::Db.connector.projects_and_deploy_envs_by_field('stack_template', id)
envs_with_this_template = []
res = {}
projects.each do |project|
array = []
res[project.id] = array
project.deploy_envs.each do |env|
envs_with_this_template << "#{project.id}-#{env.identifier}"
array << env.identifier
end
end
envs_with_this_template
res
end
end

View File

@ -6,7 +6,8 @@ module Devops
class ImageParser < RequestParser
def images
provider = @params[:provider]
provider = @params["provider"]
puts "Provider: #{provider}"
check_provider(provider) if provider
provider
end

View File

@ -7,7 +7,7 @@ module Devops
def create
key = create_object_from_json_body
fname = check_filename(key["file_name"], "Parameter 'file_name' must be a not empty string")
fname = check_filename(key["file_name"], "Parameter 'file_name' should be a not empty string")
kname = check_string(key["key_name"], "Parameter 'key_name' should be a not empty string")
content = check_string(key["content"], "Parameter 'content' should be a not empty string")
key

View File

@ -50,10 +50,16 @@ module Devops
Devops::Model::DeployEnvFactory.create(body)
end
def add_or_update_deploy_env
def update_deploy_env_field
body = create_object_from_json_body
rl = check_array(body["run_list"], "Parameter 'run_list' should be an array of string", String, false, true)
Validators::Helpers::RunList.new(rl).validate!
raise InvalidRecord.new("'value' key not found") if body["value"].nil?
body["value"]
end
def update_deploy_env
body = create_object_from_json_body
# rl = check_array(body["run_list"], "Parameter 'run_list' should be an array of string", String, false, true)
# Validators::Helpers::RunList.new(rl).validate!
Devops::Model::DeployEnvFactory.create(body)
end

View File

@ -16,18 +16,16 @@ module Devops
def user_privileges
data = create_object_from_json_body
cmd = check_string(data["cmd"], "Parameter 'cmd' should be a not empty string", true)
privileges = check_string(data["privileges"], "Parameter 'privileges' should be a not empty string", true)
privileges = check_string(data["privileges"], "Parameter 'privileges' should be a string", true, true)
return cmd, privileges
end
def change_password
raise InvalidPrivileges.new("Access denied for '#{current_user}'") if user == Devops::Model::User::ROOT_USER_NAME and current_user != Devops::Model::User::ROOT_USER_NAME
body = create_object_from_json_body
check_string(body["password"], "Parameter 'password' must be a not empty string")
end
def change_email
raise InvalidPrivileges.new("Access denied for '#{current_user}'") if user == Devops::Model::User::ROOT_USER_NAME and current_user != Devops::Model::User::ROOT_USER_NAME
body = create_object_from_json_body
check_string(body["email"], "Parameter 'email' must be a not empty string")
end

View File

@ -22,7 +22,7 @@ module Devops
# ]
app.get_with_headers "/keys", :headers => [:accept] do
check_privileges("key", "r")
json Devops::API2_0::Handler::Key.new(request).keys.map(&:to_hash)
json Devops::API2_0::Handler::Key.new(request).keys.map{|k| h = k.to_hash; h.delete("path"); h}
end
# Create ssh key on devops server

View File

@ -36,7 +36,8 @@ module Devops
# ]
app.get_with_headers "/projects", :headers => [:accept] do
check_privileges("project", "r")
json Devops::API2_0::Handler::Project.new(request).projects.map(&:to_hash_list)
projects = Devops::API2_0::Handler::Project.new(request).projects
json projects.map(&:to_hash)
end
# Get project by id
@ -217,6 +218,27 @@ module Devops
# - method : POST
# - headers :
# - Accept: application/json
# - body :
# {
# "identifier": "prod",
# "provider": "openstack",
# "flavor": "m1.small",
# "image": "image id",
# "subnets": [
# "private"
# ],
# "groups": [
# "default"
# ],
# "users": [
# "user"
# ],
# "run_list": [ ],
# "expires": null
# }
#
# * *Returns* :
# 200 - Added
app.post_with_headers "/project/:project/deploy_env", :headers => [:accept, :content_type] do |project|
check_privileges("project", "w")
res, env = Devops::API2_0::Handler::Project.new(request).add_deploy_env(project)
@ -235,7 +257,7 @@ module Devops
json Devops::API2_0::Handler::Project.new(request).project_deploy_env(project, env)
}
# Add or update deploy_env
# Update deploy_env, you can send few fields in the body
#
# * *Request*
# - method : PUT
@ -266,7 +288,7 @@ module Devops
deploy_env_hash["PUT"] = lambda{|id, deploy_env|
check_privileges("project", "w")
begin
res = Devops::API2_0::Handler::Project.new(request).add_or_update_deploy_env(id, deploy_env)
res = Devops::API2_0::Handler::Project.new(request).update_deploy_env(id, deploy_env)
create_response(res, nil, 200)
rescue InvalidRecord => e
halt_response(e.message)
@ -293,6 +315,12 @@ module Devops
}
app.multi_routes "/project/:id/deploy_envs/:deploy_env", {}, deploy_env_hash
app.put_with_headers "/project/:id/deploy_env/:deploy_env/:field", :headers => [:accept, :content_type] do |project_id, deploy_env, field|
check_privileges("project", "w")
res = Devops::API2_0::Handler::Project.new(request).update_deploy_env_field(project_id, deploy_env, field)
create_response(res, nil, 200)
end
# Create project
#
# * *Request*

View File

@ -113,7 +113,9 @@ module Devops
# * *Returns* :
# 200 - Updated
app.put_with_headers %r{\A/user/#{DevopsConfig::OBJECT_NAME}/email\z}, :headers => [:accept, :content_type] do |user|
check_privileges("user", "w") unless request.env['REMOTE_USER'] == user
current_user = request.env['REMOTE_USER']
check_privileges("user", "w") unless current_user == user
raise InvalidPrivileges.new("Access denied for '#{current_user}'") if user == Devops::Model::User::ROOT_USER_NAME and current_user != Devops::Model::User::ROOT_USER_NAME
Devops::API2_0::Handler::User.new(request).change_email(user)
create_response("Updated")
end
@ -133,7 +135,9 @@ module Devops
# * *Returns* :
# 200 - Updated
app.put_with_headers %r{\A/user/#{DevopsConfig::OBJECT_NAME}/password\z}, :headers => [:accept, :content_type] do |user|
check_privileges("user", "w") unless request.env['REMOTE_USER'] == user
current_user = request.env['REMOTE_USER']
check_privileges("user", "w") unless current_user == user
raise InvalidPrivileges.new("Access denied for '#{current_user}'") if user == Devops::Model::User::ROOT_USER_NAME and current_user != Devops::Model::User::ROOT_USER_NAME
Devops::API2_0::Handler::User.new(request).change_password(user)
create_response("Updated")
end

View File

@ -10,6 +10,7 @@ require "exceptions/dependency_error"
require "exceptions/conflict_exception"
require "exceptions/parser_error"
require "exceptions/validation_error"
require "exceptions/knife_config_error"
require 'core/devops-logger'
require_relative "../helpers/version_2"
@ -58,8 +59,12 @@ module Devops
# set current logger and call handlers
def call env
DevopsLogger.logger = @@logger
res = super(env)
@@access_logger.info(env["REQUEST_METHOD"] + " " + env["REQUEST_URI"] + " - from #{env["HTTP_USER_AGENT"]}")
begin
res = super(env)
rescue DevopsError => e
return [e.code, {}, e.message]
end
@@access_logger.info(env["REQUEST_METHOD"] + " " + env["REQUEST_URI"] + " - from #{env["HTTP_USER_AGENT"]} (#{env["REMOTE_USER"]}) / #{res.inspect}")
res
end
@ -75,6 +80,12 @@ module Devops
halt_response(e.message, 400)
end
error Devops::Exception::KnifeConfigError do
e = env["sinatra.error"]
logger.error e.message
halt_response(e.message, 500)
end
error RecordNotFound do
e = env["sinatra.error"]
logger.warn e.message
@ -103,7 +114,7 @@ module Devops
error ConflictException do
e = env["sinatra.error"]
logger.warn e.message
halt_response(e.message, 409)
create_response(e.message, e.object, 409)
end
error InvalidPrivileges do

View File

@ -2,7 +2,7 @@ require "socket"
class DevopsConfig
OBJECT_NAME = /[\w\-]+/
OBJECT_NAME = /([\w\-]+)/
@@config = nil

View File

@ -22,7 +22,8 @@ module Connectors
collection.insert(hash)
record
rescue Mongo::OperationFailure => e
if e.message =~ /^11000/
# exception's message doesn't always start from error code
if e.message =~ /11000/
resource_name = StringHelper.underscore_class(record.class)
raise InvalidRecord.new("Duplicate key error: #{resource_name} with id '#{record.id}'")
end

View File

@ -35,6 +35,7 @@ module Connectors
else
query["archived"] = {"$exists" => false}
end
fields << '_id'
list(query, fields: fields)
end
@ -93,7 +94,7 @@ module Connectors
def check_project_auth(project_id, env, user_id)
project = show(project_id)
raise InvalidPrivileges.new("User '#{user_id}' unauthorized to work with project '#{project_id}'") unless project.check_authorization(user_id, env)
raise InvalidPrivileges.new("User '#{user_id}' is unauthorized to work with project '#{project_id}' and environment '#{env}'") unless project.check_authorization(user_id, env)
project
end
@ -104,13 +105,17 @@ module Connectors
list( {'deploy_envs' => {'$elemMatch' => q}}, {:fields => {'deploy_envs' => {'$elemMatch' => q}}} )
end
def set_project_deploy_env_field(project_id, env, field, value)
@collection.update({"_id" => project_id, "deploy_envs.identifier" => env}, {"$set" => {"deploy_envs.$.#{field}" => value}})
def set_project_deploy_env_field(project_id, env, field_value_hash)
set = {}
field_value_hash.each do |field, value|
set["deploy_envs.$.#{field}"] = value
end
@collection.update({"_id" => project_id, "deploy_envs.identifier" => env}, {"$set" => set})
end
def set_project_env_run_list(project_id, env, run_list)
Helpers::RunList.new(run_list).validate!
set_project_deploy_env_field(project_id, env, "run_list", run_list)
set_project_deploy_env_field(project_id, env, {"run_list" => run_list})
end
def set_project_run_list(project_id, env, run_list)

View File

@ -12,7 +12,8 @@ module Devops
class CloudDeployEnv < DeployEnvBase
attr_accessor :flavor, :image, :subnets, :groups, :stack_template
=begin
@Deprecated
types :identifier => {:type => String, :empty => false},
:image => {:type => String, :empty => false},
:flavor => {:type => String, :empty => false},
@ -23,6 +24,7 @@ module Devops
:subnets => {:type => Array, :empty => true},
:groups => {:type => Array, :empty => false},
:stack_template => {:type => String, :empty => false, :nil => true}
=end
#TODO: account validator
set_validators ::Validators::DeployEnv::Flavor,
@ -32,6 +34,22 @@ module Devops
::Validators::DeployEnv::Groups,
::Validators::DeployEnv::StackTemplate
# set_validators ::Validators::DeployEnv::CloudParameters
set_field_validators :flavor, ::Validators::FieldValidator::Nil,
::Validators::FieldValidator::FieldType::String,
::Validators::FieldValidator::Flavor
set_field_validators :image, ::Validators::FieldValidator::Nil,
::Validators::FieldValidator::FieldType::String,
::Validators::FieldValidator::Image
set_field_validators :subnets, ::Validators::FieldValidator::Nil,
::Validators::FieldValidator::FieldType::Array
# ::Validators::FieldValidator::Subnets.new
set_field_validators :groups, ::Validators::FieldValidator::Nil,
::Validators::FieldValidator::FieldType::Array
# ::Validators::FieldValidator::Groups.new
set_field_validators :stack_template, ::Validators::FieldValidator::Nil,
::Validators::FieldValidator::FieldType::String,
::Validators::FieldValidator::NotEmpty,
# ::Validators::FieldValidator::StackTemplate.new
def initialize d={}
super(d)

View File

@ -1,9 +1,6 @@
require "db/mongo/models/mongo_model"
require "providers/provider_factory"
require "db/mongo/models/model_with_provider"
require "db/validators/deploy_env/run_list"
require "db/validators/deploy_env/expiration"
require "db/validators/deploy_env/users"
module Devops
module Model
@ -17,6 +14,22 @@ module Devops
::Validators::DeployEnv::Expiration,
::Validators::DeployEnv::Users
set_field_validators :identifier, ::Validators::FieldValidator::NotNil,
::Validators::FieldValidator::FieldType::String,
::Validators::FieldValidator::NotEmpty,
::Validators::FieldValidator::Name
set_field_validators :run_list, ::Validators::FieldValidator::NotNil,
::Validators::FieldValidator::FieldType::Array,
::Validators::FieldValidator::RunList
set_field_validators :users, ::Validators::FieldValidator::NotNil,
::Validators::FieldValidator::FieldType::Array
set_field_validators :expires, ::Validators::FieldValidator::Nil,
::Validators::FieldValidator::FieldType::String,
::Validators::FieldValidator::Expires
def initialize d={}
self.identifier = d["identifier"]
set_provider(d)
@ -40,12 +53,40 @@ module Devops
self.users = (self.users + users).uniq
end
def rename project_id, new_name
old_name = self.identifier
self.identifier = new_name
self.validate_identifier!
begin
project = Devops::Db.connector.project(project_id)
project.deploy_env(self.identifier)
raise InvalidRecord.new("Environment with identifier '#{new_name}' already exist in project '#{project_id}'")
rescue RecordNotFound => e
res = create_role(project_id)
knife = knife_instance
old_role_name = knife.role_name(project_id, old_name)
self.run_list.delete("role[#{old_role_name}]")
role = res[:new] || res[:exist]
self.run_list << "role[#{role[0]}]" unless role.nil?
Devops::Db.connector.set_project_deploy_env_field(project_id, old_name, {"identifier" => new_name, "run_list" => self.run_list})
msg = "Project '#{project_id}': environment '#{old_name}' has been renamed to '#{new_name}'." + Project.create_roles_response(res)
DevopsLogger.logger.info(msg)
msg
end
end
def update_field project_id, field, value
self.send(field + "=", value)
self.send("validate_" + field + "!")
Devops::Db.connector.set_project_deploy_env_field(project_id, self.identifier, {field => value})
end
def build_error_message(message)
"Deploy environment '#{self.identifier}'. " + message
end
def create_role project_id
knife = KnifeFactory.instance
knife = knife_instance
if knife.nil?
DevopsLogger.logger.error "Can not get knife instance"
return nil
@ -55,25 +96,29 @@ module Devops
if all_roles.nil?
msg = "Can't get roles list from chef"
DevopsLogger.logger.error msg
return {error: msg}
return {error: [msg]}
end
role_name = knife.role_name(project_id, self.identifier)
begin
if all_roles.include? role_name
info[:exist] = role_name
info[:exist] = [role_name]
else
knife.create_role role_name, project_id, self.identifier
info[:new] = role_name
info[:new] = [role_name]
DevopsLogger.logger.info "Role '#{role_name}' created"
end
self.run_list << "role[#{role_name}]"
rescue => er
info[:error] = role_name
info[:error] = [role_name]
DevopsLogger.logger.error "Role '#{role_name}' can not be created: #{er.message}"
end
info
end
def knife_instance
KnifeFactory.instance
end
end
end
end

View File

@ -4,6 +4,8 @@ module Devops
module Model
class DeployEnvEc2 < CloudDeployEnv
=begin
@Deprecated
types :identifier => {:type => String, :empty => false},
:image => {:type => String, :empty => false},
:flavor => {:type => String, :empty => false},
@ -14,6 +16,7 @@ module Devops
:subnets => {:type => Array, :empty => true},
:groups => {:type => Array, :empty => false},
:stack_template => {:type => String, :empty => false, :nil => true}
=end
=begin
set_validators ::Validators::DeployEnv::RunList,

View File

@ -1,19 +1,54 @@
require "db/mongo/models/mongo_model"
require "db/validators/image/bootstrap_template"
require "db/validators/image/image_in_filter"
require "db/mongo/models/model_with_provider"
module Devops
module Model
class Image < MongoModel
include ModelWithProvider
attr_accessor :id, :provider, :remote_user, :name, :bootstrap_template
attr_accessor :id, :remote_user, :name, :bootstrap_template
=begin
types :id => {:type => String, :empty => false},
:provider => {:type => String, :empty => false},
:remote_user => {:type => String, :empty => false},
:name => {:type => String, :empty => true},
:bootstrap_template => {:type => String, :empty => false, :nil => true}
set_validators ::Validators::Image::ImageInFilter,
::Validators::Image::BootstrapTemplate
=end
# set_validators ::Validators::Image::ImageInFilter,
# ::Validators::Image::BootstrapTemplate
set_field_validators :id, ::Validators::FieldValidator::NotNil,
::Validators::FieldValidator::FieldType::String,
::Validators::FieldValidator::NotEmpty,
::Validators::FieldValidator::ImageName,
::Validators::Image::ImageInFilter
set_field_validators :remote_user, ::Validators::FieldValidator::NotNil,
::Validators::FieldValidator::FieldType::String,
::Validators::FieldValidator::NotEmpty,
::Validators::FieldValidator::Name
set_field_validators :name, ::Validators::FieldValidator::NotNil,
::Validators::FieldValidator::FieldType::String,
::Validators::FieldValidator::NotEmpty,
::Validators::FieldValidator::ImageName
set_field_validators :bootstrap_template, ::Validators::FieldValidator::Nil,
::Validators::FieldValidator::FieldType::String,
::Validators::FieldValidator::NotEmpty,
::Validators::FieldValidator::Name,
::Validators::Image::BootstrapTemplate
def validate!
validate_id!
validate_provider!
validate_remote_user!
validate_name!
validate_bootstrap_template!
end
def initialize p={}
self.id = p["id"]

View File

@ -6,6 +6,14 @@ module Devops
attr_accessor :provider, :provider_account
def ModelWithProvider.included(mod)
mod.set_field_validators :provider, ::Validators::FieldValidator::NotNil,
::Validators::FieldValidator::FieldType::String,
::Validators::FieldValidator::NotEmpty,
::Validators::FieldValidator::Provider
end
def provider_instance
@provider_instance ||= Provider::ProviderFactory.get(self.provider, self.provider_account)
end

View File

@ -57,7 +57,7 @@ module Devops
def validate!
begin
# TODO: we should validate type in request parser
self.validate_fields_types
# self.validate_fields_types
self.class.validate_model(self)
true
rescue InvalidRecord => e
@ -123,13 +123,17 @@ module Devops
end
@validators = []
# @field_validators = []
class << self
attr_accessor :validators
# attr_accessor :field_validators
def inherited(subclass)
subclass.validators = []
subclass.validators += self.validators
# subclass.field_validators = []
# subclass.field_validators += self.field_validators
end
# all exceptions are handled in @validate! method
@ -139,6 +143,16 @@ module Devops
end
end
# validate field value
# if method validate! returns false, then stop validation without error
def set_field_validators field, *validators
define_method("validate_" + field.to_s + "!") do
validators.each do |validator|
break unless validator.new(self, send(field)).validate!
end
end
end
# private class methods
private

View File

@ -67,7 +67,7 @@ module Devops
def add_deploy_env deploy_env
res = deploy_env.create_role(self.id)
Devops::Db.connector.add_deploy_env_to_project self.id, deploy_env
create_roles_response(res)
Project.create_roles_response(res)
end
def add_authorized_user user, env=nil
@ -210,7 +210,7 @@ module Devops
end
end
def create_roles_response roles
def self.create_roles_response roles
if roles.is_a?(String)
roles
else

View File

@ -17,6 +17,15 @@ module Devops
:email => {:type => String, :empty => false},
:password => {:type => String, :empty => true}
set_field_validators :id, ::Validators::FieldValidator::NotNil,
::Validators::FieldValidator::FieldType::String,
::Validators::FieldValidator::Name
set_field_validators :password, ::Validators::FieldValidator::NotNil,
::Validators::FieldValidator::FieldType::String
set_field_validators :email, ::Validators::FieldValidator::NotNil,
::Validators::FieldValidator::FieldType::String
set_field_validators :privileges, ::Validators::FieldValidator::NotNil,
::Validators::FieldValidator::FieldType::Hash
def initialize p={}
self.id = p['username']
self.email = p['email']
@ -24,6 +33,13 @@ module Devops
self.privileges = p["privileges"] || self.default_privileges
end
def validate!
validate_id!
validate_password!
validate_email!
validate_privileges!
end
def all_privileges
privileges_with_value("rwx")
end
@ -33,6 +49,8 @@ module Devops
end
def grant cmd, priv=''
priv='' if priv.nil?
cmd='' if cmd.nil?
if !priv.empty? and PRIVILEGES_REGEX.match(priv).to_s.empty?
raise InvalidCommand.new "Invalid privileges '#{priv}'. Available values are '#{PRIVILEGES.join("', '")}'"
end
@ -46,7 +64,7 @@ module Devops
when ""
self.privileges = self.default_privileges
else
raise InvalidCommand.new "Unsupported command #{cmd}" unless self.all_privileges.include?(cmd)
raise InvalidCommand.new "Unsupported command '#{cmd}'" unless self.all_privileges.include?(cmd)
self.privileges[cmd] = priv
end
end

View File

@ -3,6 +3,8 @@ module Validators
module DeployEnv; end
module Key; end
module Image; end
module FieldValidator; end
end
require "db/validators/base"
@ -10,7 +12,8 @@ require "db/validators/base"
'db/validators/helpers/*.rb',
'db/validators/deploy_env/*.rb',
'db/validators/key/*.rb',
'db/validators/image/*.rb'
'db/validators/image/*.rb',
'db/validators/field_validators/*.rb'
].each do |files_regexp|
Dir[files_regexp].each {|file| require file }
end

View File

@ -0,0 +1,25 @@
module Validators
module FieldValidator
class Base
def initialize model, value
@model = model
@value = value
end
def validate!
raise InvalidRecord.new(self.message) unless self.valid?
true
end
def valid?
raise 'override me'
end
def message
raise 'override me'
end
end
end
end

View File

@ -0,0 +1,19 @@
require_relative "base"
module Validators
module FieldValidator
class Expires < Base
EXPIRES_REGEXP = /^[0-9]+[smhdw]$/
def valid?
!@value.match(EXPIRES_REGEXP).nil?
end
def message
"Invalid value, it should contains symbols '0-9smhdw'"
end
end
end
end

View File

@ -0,0 +1,62 @@
require_relative "base"
module Validators
module FieldValidator
class FieldType < Base
def valid?
@value.is_a?(type)
#TODO: strip string
#value.strip! if value.is_a?(String)
end
def message
"Invalid value, it should be a #{type_name}"
end
class String < FieldType
def type
::String
end
def type_name
"string"
end
end
class Array < FieldType
def type
::Array
end
def type_name
"array"
end
def message
"Invalid value, it should be an #{type_name}"
end
end
class Hash < FieldType
def type
::Hash
end
def type_name
"object"
end
def message
"Invalid value, it should be an #{type_name}"
end
end
end
end
end

View File

@ -0,0 +1,18 @@
require_relative "base"
module Validators
module FieldValidator
class Flavor < Base
def valid?
@model.provider_instance.flavors.detect do |flavor|
flavor['id'] == @value
end
end
def message
"Invalid flavor '#{@value}'."
end
end
end
end

View File

@ -0,0 +1,22 @@
require "commands/image"
require_relative "base"
module Validators
module FieldValidator
class Image < Base
include ::ImageCommands
def valid?
images = get_available_provider_images(::Devops::Db.connector, @model.provider)
images.detect do |image|
image["id"] == @value
end
end
def message
"Invalid image '#{@value}'."
end
end
end
end

View File

@ -0,0 +1,18 @@
require_relative "base"
module Validators
module FieldValidator
class ImageName < Base
MAX_NAME_LEN = 100
NAME_REGEX = /\A[\w\-\.]{1,#{MAX_NAME_LEN}}\z/
def valid?
!NAME_REGEX.match(@value).nil?
end
def message
"Invalid value '#{@value}': it should contains symbols 'a-zA-Z0-9_-.' and length should be more then 1 and less or equals then #{MAX_NAME_LEN}"
end
end
end
end

View File

@ -0,0 +1,18 @@
require_relative "base"
module Validators
module FieldValidator
class Name < Base
MAX_NAME_LEN = 200
NAME_REGEX = /\A\w{1,#{MAX_NAME_LEN}}\z/
def valid?
!NAME_REGEX.match(@value).nil?
end
def message
"Invalid value '#{@value}': it should contains symbols 'a-zA-Z0-9_' and length should be more then 1 and less or equals then #{MAX_NAME_LEN}"
end
end
end
end

View File

@ -0,0 +1,14 @@
require_relative "base"
module Validators
module FieldValidator
class Nil < Base
def validate!
!@value.nil?
end
end
end
end

View File

@ -0,0 +1,18 @@
require_relative "base"
module Validators
module FieldValidator
class NotEmpty < Base
def valid?
!@value.empty?
end
def message
"Value can not be empty"
end
end
end
end

View File

@ -0,0 +1,18 @@
require_relative "base"
module Validators
module FieldValidator
class NotNil < Base
def valid?
!@value.nil?
end
def message
"Value can not be undefined"
end
end
end
end

View File

@ -0,0 +1,18 @@
require_relative "base"
module Validators
module FieldValidator
class Provider < Base
def valid?
@providers = ::Provider::ProviderFactory.providers
@providers.include?(@value)
end
def message
"Invalid value, available values: '#{@providers.join("', '")}'"
end
end
end
end

View File

@ -0,0 +1,13 @@
require_relative "base"
module Validators
module FieldValidator
class RunList < Base
def validate!
Validators::Helpers::RunList.new(@value).validate!
end
end
end
end

View File

@ -1,4 +1,11 @@
class ConflictException < StandardError
attr_reader :object
def initialize msg, object=nil
super(msg)
@object = object
end
end

View File

@ -0,0 +1,13 @@
module Devops
module Exception
class DevopsError < StandardError
def code
500
end
end
end
end

View File

@ -0,0 +1,9 @@
require 'exceptions/devops_error'
module Devops
module Exception
class KnifeConfigError < DevopsError
end
end
end

View File

@ -6,6 +6,11 @@ When(/^I send GET '(.*)' query$/) do |path|
get(path, {}, DEFAULT_HEADERS)
end
When(/^I send GET '(.*)' query with header 'Accept' value '(.*)'$/) do |path, hv|
headers = {"Accept" => hv}
get(path, {}, headers)
end
When(/^I send GET '(.*)' query with user without privileges$/) do |path|
get_without_privileges(path, {}, DEFAULT_HEADERS)
end
@ -31,9 +36,16 @@ When(/^I send POST '(.*)' query with JSON body$/) do |path, body|
res = post_body(path, body, DEFAULT_HEADERS)
end
When(/^I send POST '(.*)' query with body with header 'Accept' value '(.*)'$/) do |path, hv, body|
When(/^I send POST '(.*)' query with JSON body with header '(.*)' value '(.*)'$/) do |path, header, hv, body|
JSON.parse(body) unless body.strip.empty?
headers = DEFAULT_HEADERS.clone
headers["Accept"] = hv
headers[header] = hv
res = post_body(path, body, headers)
end
When(/^I send POST '(.*)' query with body with header '(.*)' value '(.*)'$/) do |path, header, hv, body|
headers = DEFAULT_HEADERS.clone
headers[header] = hv
res = post_body(path, body, headers)
end
@ -57,13 +69,19 @@ When(/^I send DELETE '(.*)' query$/) do |path|
delete(path, {}, DEFAULT_HEADERS)
end
When(/^I send DELETE '(.*)' query with JSON body with header 'Accept' value '(.*)'$/) do |path, hv, body|
When(/^I send DELETE '(.*)' query with JSON body with header '(.*)' value '(.*)'$/) do |path, header, hv, body|
JSON.parse(body) unless body.strip.empty?
headers = DEFAULT_HEADERS.clone
headers["Accept"] = hv
headers[header] = hv
res = delete_body(path, body, headers)
end
When(/^I send DELETE '(.*)' query with header '(.*)' value '(.*)'$/) do |path, header, hv|
headers = DEFAULT_HEADERS.clone
headers[header] = hv
res = delete_body(path, nil, headers)
end
When(/^I send DELETE '(.*)' query with JSON body$/) do |path, body|
JSON.parse(body) unless body.strip.empty?
res = delete_body(path, body, DEFAULT_HEADERS)
@ -99,10 +117,10 @@ When(/^I send PUT '(.*)' query with user without privileges$/) do |path|
put_without_privileges(path, {}, DEFAULT_HEADERS)
end
When(/^I send PUT '(.*)' query with JSON body with header 'Accept' value '(.*)'$/) do |path, hv, body|
When(/^I send PUT '(.*)' query with JSON body with header '(.*)' value '(.*)'$/) do |path, header, hv, body|
JSON.parse(body) unless body.strip.empty?
headers = DEFAULT_HEADERS.clone
headers["Accept"] = hv
headers[header] = hv
res = put_body(path, body, headers)
end

View File

@ -1,5 +1,5 @@
Then(/^response array should contains elements like:$/) do |string|
src = JSON.parse(string).first
src = JSON.parse(string)
array = JSON.parse(last_response.body)
array.each do |e|
src.each do |key, value|
@ -44,15 +44,14 @@ Then(/^response should be JSON object like:$/) do |string|
end
Then(/^the array should contains strings '(.*)'$/) do |string|
buf = string.split(",")
buf = string.split(",").map(&:strip)
array = JSON.parse(last_response.body)
buf.each do |v|
assert array.include?(v), "Array should contains '#{v}'"
end
res = buf - array
assert res.empty?, "Response has no strings '#{res.join("', '")}'"
end
Then(/^the array should not contains strings '(.*)'$/) do |string|
buf = string.split(",")
buf = string.split(",").map(&:strip)
array = JSON.parse(last_response.body)
buf.each do |v|
assert !array.include?(v), "Array should not contains '#{v}'"

View File

@ -5,6 +5,7 @@ require "yaml"
require "ostruct"
require "fileutils"
require "./templates/fixtures/fixture_formatter"
require "./templates/generators/path_scenarios_generator.rb"
class Generator < OpenStruct
@ -15,7 +16,8 @@ class Generator < OpenStruct
config_file = ENV["DEVOPS_FEATURES_GENERATOR_CONFIG"] || ENV["CONFIG"] || CONFIG
@config = YAML.load_file(File.new(config_file))
load_fixtures()
super(:config => @config, :formatter => @formatter, :fixtures => @fixtures)
@generator = PathScenariosGenerator.new
super(:config => @config, :formatter => @formatter, :fixtures => @fixtures, :generator => @generator)
end
def configure!
@ -31,14 +33,18 @@ class Generator < OpenStruct
templates.each do |input, output|
puts "Input: #{input}"
if File.exists?(input)
file_data = File.read(input)
if file_data.nil?
puts "Data of file '#{input}' is nil"
else
data = render(file_data)
dir = File.dirname(output)
FileUtils.mkdir_p(dir) unless File.exists?(dir)
File.open(output, "w") {|f| f.write(data)}
begin
file_data = File.read(input)
if file_data.nil?
puts "Data of file '#{input}' is nil"
else
data = render(file_data)
dir = File.dirname(output)
FileUtils.mkdir_p(dir) unless File.exists?(dir)
File.open(output, "w") {|f| f.write(data)}
end
rescue => e
puts "\tError: #{e.message}"
end
else
puts "WARN: file '#{input}' does not exist"
@ -46,14 +52,22 @@ class Generator < OpenStruct
end
end
def clean!(feature_files)
def self.clean!
dir = "features/api_v2/"
if File.exists?(dir)
puts "Removing directory '#{dir}'"
FileUtils.rm_r(dir)
end
=begin
feature_files.each do |feature_file|
if File.exists?(feature_file)
FileUtils.rm(feature_file)
FileUtils.rm_f(feature_file)
else
puts "WARN: file '#{feature_file}' does not exist"
end
end
=end
end
private
@ -63,10 +77,13 @@ class Generator < OpenStruct
end
def load_fixtures
puts "Load fixures:"
@fixtures = {}
Dir["templates/fixtures/*.yml"].each do |fixture_path|
fixture_name = File.basename(fixture_path, '.yml')
print "\t#{fixture_path}..."
@fixtures[fixture_name] = YAML.load_file(fixture_path)
puts " ok"
end
@formatter = FixtureFormatter.new(@fixtures)
@ -78,7 +95,14 @@ templates = {
#list
"templates/api_v2/00_list/flavor.feature.erb" => "features/api_v2/00_list/flavor.feature",
"templates/api_v2/00_list/stack_preset.feature.erb" => "features/api_v2/00_list/stack_preset.feature",
"templates/api_v2/00_list/00_network.feature.erb" => "features/api_v2/00_list/00_network.feature",
"templates/api_v2/00_list/10_user.feature.erb" => "features/api_v2/00_list/10_user.feature",
"templates/api_v2/00_list/10_group.feature.erb" => "features/api_v2/00_list/10_group.feature",
"templates/api_v2/00_list/10_bootstrap_template.feature.erb" => "features/api_v2/00_list/10_bootstrap_template.feature",
"templates/api_v2/00_list/10_filter.feature.erb" => "features/api_v2/00_list/10_filter.feature",
"templates/api_v2/00_list/20_image.feature.erb" => "features/api_v2/00_list/20_image.feature",
"templates/api_v2/00_list/20_key.feature.erb" => "features/api_v2/00_list/20_key.feature",
"templates/api_v2/00_list/30_project.feature.erb" => "features/api_v2/00_list/30_project.feature",
#create
"templates/api_v2/10_create/00_filter.feature.erb" => "features/api_v2/10_create/00_filter.feature",
@ -87,6 +111,7 @@ templates = {
"templates/api_v2/10_create/10_image.feature.erb" => "features/api_v2/10_create/10_image.feature",
"templates/api_v2/10_create/50_stack.feature.erb" => "features/api_v2/10_create/50_stack.feature",
"templates/api_v2/10_create/20_project.feature.erb" => "features/api_v2/10_create/20_project.feature",
"templates/api_v2/10_create/21_deploy_env.feature.erb" => "features/api_v2/10_create/21_deploy_env.feature",
"templates/api_v2/10_create/30_script.feature.erb" => "features/api_v2/10_create/30_script.feature",
"templates/api_v2/10_create/40_deploy_env.feature.erb" => "features/api_v2/10_create/40_deploy_env.feature",
"templates/api_v2/10_create/00_user.feature.erb" => "features/api_v2/10_create/00_user.feature",
@ -108,11 +133,10 @@ templates = {
}
generator = Generator.new.configure!
if ARGV.first != 'clean'
generator = Generator.new.configure!
generator.generate!(templates)
else
generator.clean!(templates.values)
Generator.clean!
end

View File

@ -7,30 +7,3 @@ path_prefix: ""
username_without_privileges: "user_for_testing_"
password_without_privileges: "test"
openstack:
flavor: "as_long_as_image"
image: "08093b30-8393-42c3-8fb3-c4df56deb967"
subnet: "subnet"
project:
name: "test_openstack"
env: "test"
ec2:
flavor: "m1.small"
image: "ami-63071b0a"
subnet: "subnet"
project:
name: "test_ec2"
env: "test"
static:
project:
name: "test_static"
env: "test"
script:
name: "cucumber_test_script"
user:
name: "cucumber_test"

View File

@ -0,0 +1,42 @@
@network @list
Feature: Networks
<% @formatter.get_fixture('providers/without_static').each do |provider| %>
@<%= provider %>
Scenario: Get list of <%= provider %> networks
When I send GET '/v2.0/networks/<%= provider %>' query
Then response should be '200'
And the Content-Type header should include 'application/json'
And the JSON response should be an array
And response array should contains elements like:
"""
[
<%= @formatter.json(provider + '/network', spaces: 6) %>
]
"""
@<%= provider %>
Scenario: Get list of <%= provider %> networks with header 'Accept' value is not 'application/json'
When I send GET '/v2.0/networks/<%= provider %>' query with header 'Accept' value 'application/xml'
Then response should be '406'
<% end %>
@static
Scenario: Get list of static networks
When I send GET '/v2.0/networks/static' query
Then response should be '200'
And the Content-Type header should include 'application/json'
And the JSON response should be an array
And response array should be empty
<% providers = @formatter.get_fixture('providers/all').map{|provider| "@#{provider}"} %>
<%= providers.join(" ") %>
Scenario: Get networks list of unknown provider
When I send GET '/v2.0/networks/foo' query
Then response should be '404'
<%= providers.join(" ") %>
Scenario: Get networks list of unknown provider without privileges
When I send GET '/v2.0/networks/foo' query with user without privileges
Then response should be '401'

View File

@ -0,0 +1,18 @@
<% providers = @formatter.get_fixture('providers/all').map{|provider| "@#{provider}"} %>
@list @bootstrap_template <%= providers.join(" ") %>
Feature: Bootstrap templates
Scenario: Get list bootstrap templates
When I send GET '/v2.0/templates' query
Then response should be '200'
And the Content-Type header should include 'application/json'
And the JSON response should be an array
And the array elements should be strings
Scenario: Get bootstrap templates list with header 'Accept' value is not 'application/json'
When I send GET '/v2.0/templates' query with header 'Accept' value 'application/xml'
Then response should be '406'
Scenario: Get bootstrap template list without privileges
When I send GET '/v2.0/templates' query with user without privileges
Then response should be '401'

View File

@ -0,0 +1,32 @@
@filter @list
Feature: Filters
<% @formatter.get_fixture('providers/without_static').each do |provider| %>
@<%= provider %>
Scenario: Get list of <%= provider %> filters
When I send GET '/v2.0/filter/<%= provider %>/images' query
Then response should be '200'
And the Content-Type header should include 'application/json'
And the JSON response should be an array
@<%= provider %>
Scenario: Get list of <%= provider %> filters with header 'Accept' value is not 'application/json'
When I send GET '/v2.0/filter/<%= provider %>/images' query with header 'Accept' value 'application/xml'
Then response should be '406'
@<%= provider %>
Scenario: Get filter list for <%= provider %> provider without privileges
When I send GET '/v2.0/filter/<%= provider %>/images' query with user without privileges
Then response should be '401'
<% end %>
@openstack @ec2 @static
Scenario: Get filter list of unknown provider
When I send GET '/v2.0/filter/foo/images' query
Then response should be '404'
@openstack @ec2 @static
Scenario: Get filter list of unknown provider without privileges
When I send GET '/v2.0/filter/foo/images' query with user without privileges
Then response should be '401'

View File

@ -0,0 +1,32 @@
@group @list
Feature: Groups
<% @formatter.get_fixture('providers/without_static').each do |provider| %>
@<%= provider %>
Scenario: Get list of <%= provider %> groups
When I send GET '/v2.0/groups/<%= provider %>' query
Then response should be '200'
And the Content-Type header should include 'application/json'
And the JSON response should be an object
@<%= provider %>
Scenario: Get list of <%= provider %> groups with header 'Accept' value is not 'application/json'
When I send GET '/v2.0/groups/<%= provider %>' query with header 'Accept' value 'application/xml'
Then response should be '406'
@<%= provider %>
Scenario: Get groups list for <%= provider %> provider without privileges
When I send GET '/v2.0/groups/<%= provider %>' query with user without privileges
Then response should be '401'
<% end %>
<% providers = @formatter.get_fixture('providers/all').map{|provider| "@#{provider}"} %>
<%= providers.join(" ") %>
Scenario: Get groups list of unknown provider
When I send GET '/v2.0/groups/foo' query
Then response should be '404'
<%= providers.join(" ") %>
Scenario: Get groups list of unknown provider without privileges
When I send GET '/v2.0/groups/foo' query with user without privileges
Then response should be '401'

View File

@ -1,4 +1,5 @@
@user
<% providers = @formatter.get_fixture('providers/all').map{|provider| "@#{provider}"} %>
@list @user <%= providers.join(" ") %>
Feature: list user
Scenario: Get list of all users
@ -9,27 +10,14 @@ Feature: list user
And response array should contains elements like:
"""
[
{
"email": "test@test.test",
"privileges": {
"flavor": "rwx",
"group": "rwx",
"image": "rwx",
"project": "rwx",
"server": "rwx",
"key": "rwx",
"user": "rwx",
"filter": "rwx",
"network": "rwx",
"provider": "rwx",
"script": "rwx",
"templates": "rwx"
},
"id": "test"
}
<%= @formatter.json('user/show', spaces: 6) %>
]
"""
Scenario: Get list of all users
When I send GET '/v2.0/users' query with header 'Accept' value 'application/xml'
Then response should be '406'
Scenario: Get list of all users without privileges
When I send GET '/v2.0/users' query with user without privileges
Then response should be '401'

View File

@ -0,0 +1,106 @@
@image @list
Feature: List images
<% @formatter.get_fixture('providers/without_static').each do |provider| %>
@<%= provider %>
Scenario: Get list mages with provider <%= provider %>
When I send GET '/v2.0/images?provider=<%= provider %>' query
Then response should be '200'
And the Content-Type header should include 'application/json'
And the JSON response should be an array
And response array should contains elements like:
"""
<%= @formatter.json(provider + '/image') %>
"""
@<%= provider %>
Scenario: Get list of <%= provider %> images with header 'Accept' value is not 'application/json'
When I send GET '/v2.0/images?provider=<%= provider %>' query with header 'Accept' value 'application/xml'
Then response should be '406'
@<%= provider %>
Scenario: Get images list for <%= provider %> provider without privileges
When I send GET '/v2.0/images?provider=<%= provider %>' query with user without privileges
Then response should be '401'
@<%= provider %>
Scenario: Get images list of <%= provider %> provider
When I send GET '/v2.0/images/provider/<%= provider %>' query
Then response should be '200'
And the Content-Type header should include 'application/json'
And the JSON response should be an array
And response array should contains elements like:
"""
<%= @formatter.json(provider + '/provider_image') %>
"""
@<%= provider %>
Scenario: Get list of <%= provider %> images with header 'Accept' value is not 'application/json'
When I send GET '/v2.0/images/provider/<%= provider %>' query with header 'Accept' value 'application/xml'
Then response should be '406'
@<%= provider %>
Scenario: Get images list for <%= provider %> provider without privileges
When I send GET '/v2.0/images/provider/<%= provider %>' query with user without privileges
Then response should be '401'
<% end %>
@static
Scenario: Get list of static provider images
When I send GET '/v2.0/images?provider=static' query
Then response should be '200'
And the Content-Type header should include 'application/json'
And the JSON response should be an array
And response array should be empty
@static
Scenario: Get list of static images with header 'Accept' value is not 'application/json'
When I send GET '/v2.0/images?provider=static' query with header 'Accept' value 'application/xml'
Then response should be '406'
@static
Scenario: Get images list for static provider without privileges
When I send GET '/v2.0/images?provider=static' query with user without privileges
Then response should be '401'
<% providers = @formatter.get_fixture('providers/all').map{|provider| "@#{provider}"} %>
<%= providers.join(" ") %>
Scenario: Get images list of unknown provider
When I send GET '/v2.0/images?provider=foo' query
Then response should be '400'
<%= providers.join(" ") %>
Scenario: Get images list without privileges
When I send GET '/v2.0/images' query with user without privileges
Then response should be '401'
<%= providers.join(" ") %>
Scenario: Get groups list of unknown provider without privileges
When I send GET '/v2.0/images?provider=foo' query with user without privileges
Then response should be '401'
<%= providers.join(" ") %>
Scenario: Get list of all images - invalid path
When I send GET '/v2.0/images/foo' query
Then response should be '404'
<%= providers.join(" ") %>
Scenario: Get list of images of unknown provider
When I send GET '/v2.0/images/provider/foo' query
Then response should be '404'
<%= providers.join(" ") %>
Scenario: Get unknown image
When I send GET '/v2.0/image/foo' query
Then response should be '404'
<%= providers.join(" ") %>
Scenario: Get unknown image without privileges
When I send GET '/v2.0/image/foo' query with user without privileges
Then response should be '401'
<%= providers.join(" ") %>
Scenario: Get image path
When I send GET '/v2.0/image' query
Then response should be '404'

View File

@ -0,0 +1,21 @@
<% providers = @formatter.get_fixture('providers/all').map{|p| "@#{p}"} %>
@key @list <%= providers.join(" ") %>
Feature: List keys
Scenario: Get keys
When I send GET '/v2.0/keys' query
Then response should be '200'
And the Content-Type header should include 'application/json'
And the JSON response should be an array
And response array should contains elements like:
"""
<%= @formatter.json('key/list_element') %>
"""
Scenario: Get keys list with header 'Accept' value is not 'application/json'
When I send GET '/v2.0/keys' query with header 'Accept' value 'application/xml'
Then response should be '406'
Scenario: Get keys list without privileges
When I send GET '/v2.0/keys' query with user without privileges
Then response should be '401'

View File

@ -0,0 +1,6 @@
<% providers = @formatter.get_fixture('providers/all').map{|provider| "@#{provider}"} %>
@project @list <%= providers.join(" ") %>
Feature: List projects
<%= @generator.generate_get_path_scenarios("Show project types", "/v2.0/project_types") {%Q(And the JSON response should be an array\n And the array elements should be strings)} %>

View File

@ -1,42 +1,26 @@
@flavor
@flavor @list
Feature: Flavors
@openstack
Scenario: Get list of openstack flavors
When I send GET '/v2.0/flavors/openstack' query
<% @formatter.get_fixture('providers/without_static').each do |provider| %>
@<%= provider %>
Scenario: Get list of <%= provider %> flavors
When I send GET '/v2.0/flavors/<%= provider %>' query
Then response should be '200'
And the Content-Type header should include 'application/json'
And the JSON response should be an array
And response array should contains elements like:
"""
[
{
"id": "flavor_id",
"v_cpus": "v_cpus",
"ram": "ram",
"disk": "disk"
}
<%= @formatter.json(provider + '/flavor', spaces: 6) %>
]
"""
@ec2
Scenario: Get list of ec2 flavors
When I send GET '/v2.0/flavors/ec2' query
Then response should be '200'
And the Content-Type header should include 'application/json'
And the JSON response should be an array
And response array should contains elements like:
"""
[
{
"id": "t1.micro",
"cores": 2,
"disk": 0,
"name": "Micro Instance",
"ram": 613
}
]
"""
@<%= provider %>
Scenario: Get list of <%= provider %> flavors with header 'Accept' value is not 'application/json'
When I send GET '/v2.0/flavors/<%= provider %>' query with header 'Accept' value 'application/xml'
Then response should be '406'
<% end %>
@static
Scenario: Get list of static flavors
@ -46,10 +30,13 @@ Feature: Flavors
And the JSON response should be an array
And response array should be empty
<% providers = @formatter.get_fixture('providers/all').map{|provider| "@#{provider}"} %>
<%= providers.join(" ") %>
Scenario: Get flavors list of unknown provider
When I send GET '/v2.0/flavors/foo' query
Then response should be '404'
<%= providers.join(" ") %>
Scenario: Get flavors list of unknown provider without privileges
When I send GET '/v2.0/flavors/foo' query with user without privileges
Then response should be '401'

View File

@ -1,4 +1,4 @@
@stack_preset
@stack_preset @list
Feature: stack template preset list
Scenario: Get list of all stack template presets

View File

@ -1,192 +1,74 @@
@filter @image @project
Feature: Filters
@openstack
Scenario: Add openstack image filter with user without privileges
When I send PUT '/v2.0/filter/openstack/image' query with user without privileges
<% @formatter.get_fixture('providers/without_static').each do |provider| %>
<% image = @formatter.get_fixture(provider + "/image")["id"] %>
@<%= provider %>
Scenario: Add <%= provider %> images filter with user without privileges
When I send PUT '/v2.0/filter/<%= provider %>/image' query with user without privileges
Then response should be '401'
@openstack
Scenario: Add openstack image filter with header 'Accept' value 'text/*'
When I send PUT '/v2.0/filter/openstack/image' query with JSON body with header 'Accept' value 'text/*'
@<%= provider %>
Scenario: Update images filter with JSON body with header 'Accept' value not 'application/json'
When I send PUT '/v2.0/filter/<%= provider %>/image' query with JSON body with header 'Accept' value 'application/xml'
"""
[
"<%= @config["openstack"]["image"] %>"
"<%= image %>"
]
"""
Then response should be '406'
@openstack
Scenario: Add openstack image filter without header 'Content-Type'
When I send PUT '/v2.0/filter/openstack/image' query with JSON body without header 'Content-Type'
@<%= provider %>
Scenario: Add <%= provider %> image filter without header 'Content-Type'
When I send PUT '/v2.0/filter/<%= provider %>/image' query with JSON body without header 'Content-Type'
"""
[
"<%= @config["openstack"]["image"] %>"
"<%= image %>"
]
"""
Then response should be '415'
@openstack
Scenario: Add openstack image filter, invalid body: empty
When I send PUT '/v2.0/filter/openstack/image' query with JSON body
<% ["", "{}", "[{}]", "[[]]", "[null]"].each do |body| %>
@<%= provider %>
Scenario: Add <%= provider %> image filter, invalid body: '<%= body %>'
When I send PUT '/v2.0/filter/<%= provider %>/image' query with JSON body
"""
<%= body %>
"""
Then response should be '400'
<% end %>
@openstack
Scenario: Add openstack image filter, invalid body: hash
When I send PUT '/v2.0/filter/openstack/image' query with JSON body
"""
{
"foo": "foo"
}
"""
Then response should be '400'
@openstack
Scenario: Add openstack image filter, invalid body: element is hash
When I send PUT '/v2.0/filter/openstack/image' query with JSON body
"""
[{
"foo": "foo"
}]
"""
Then response should be '400'
@openstack
Scenario: Add openstack image filter, invalid body: element is array
When I send PUT '/v2.0/filter/openstack/image' query with JSON body
@<%= provider %>
Scenario: Add <%= provider %> image filter
When I send PUT '/v2.0/filter/<%= provider %>/image' query with JSON body
"""
[
[]
]
"""
Then response should be '400'
@openstack
Scenario: Add openstack image filter, invalid body: element is null
When I send PUT '/v2.0/filter/openstack/image' query with JSON body
"""
[
null
]
"""
Then response should be '400'
@openstack
Scenario: Add openstack image filter
When I send PUT '/v2.0/filter/openstack/image' query with JSON body
"""
[
"<%= @config["openstack"]["image"] %>"
"<%= image %>"
]
"""
Then response should be '200'
And the Content-Type header should include 'application/json'
And the JSON response should be an object
And the object should contains key 'images' with array and array should contains strings '<%= @config["openstack"]["image"] %>'
And the object should contains key 'images' with array and array should contains strings '<%= image %>'
@openstack
Scenario: Add openstack image filter with invalid JSON
When I send PUT '/v2.0/filter/openstack/image' query with body
"""
[
"<%= @config["openstack"]["image"] %>",
]
"""
Then response should be '400'
@ec2
Scenario: Add ec2 image filter with user without privileges
When I send PUT '/v2.0/filter/ec2/image' query with user without privileges
Then response should be '401'
@ec2
Scenario: Add ec2 image filter with header 'Accept' value 'text/*'
When I send PUT '/v2.0/filter/ec2/image' query with JSON body with header 'Accept' value 'text/*'
"""
[
"<%= @config["ec2"]["image"] %>"
]
"""
Then response should be '406'
@ec2
Scenario: Add ec2 image filter without header 'Content-Type'
When I send PUT '/v2.0/filter/ec2/image' query with JSON body without header 'Content-Type'
"""
[
"<%= @config["ec2"]["image"] %>"
]
"""
Then response should be '415'
@ec2
Scenario: Add ec2 image filter, invalid body: empty
When I send PUT '/v2.0/filter/ec2/image' query with JSON body
"""
"""
Then response should be '400'
@ec2
Scenario: Add ec2 image filter, invalid body: hash
When I send PUT '/v2.0/filter/ec2/image' query with JSON body
"""
{
"foo": "foo"
}
"""
Then response should be '400'
@ec2
Scenario: Add ec2 image filter, invalid body: element is hash
When I send PUT '/v2.0/filter/ec2/image' query with JSON body
"""
[{
"foo": "foo"
}]
"""
Then response should be '400'
@ec2
Scenario: Add ec2 image filter, invalid body: element is array
When I send PUT '/v2.0/filter/ec2/image' query with JSON body
"""
[
[]
]
"""
Then response should be '400'
@ec2
Scenario: Add ec2 image filter, invalid body: element is null
When I send PUT '/v2.0/filter/ec2/image' query with JSON body
"""
[
null
]
"""
Then response should be '400'
@ec2
Scenario: Add ec2 image filter
When I send PUT '/v2.0/filter/ec2/image' query with JSON body
"""
[
"<%= @config["ec2"]["image"] %>"
]
"""
@<%= provider %>
Scenario: Get new <%= provider %> image filter and check value '<%= image %>'
When I send GET '/v2.0/filter/<%= provider %>/images' query
Then response should be '200'
And the Content-Type header should include 'application/json'
And the JSON response should be an object
And the object should contains key 'images' with array and array should contains strings '<%= @config["ec2"]["image"] %>'
And the JSON response should be an array
And the array elements should be strings
And the array should contains strings '<%= image %>'
@ec2
Scenario: Add ec2 image filter with invalid JSON
When I send PUT '/v2.0/filter/ec2/image' query with body
@<%= provider %>
Scenario: Add <%= provider %> image filter with invalid JSON
When I send PUT '/v2.0/filter/<%= provider %>/image' query with body
"""
[
"<%= @config["ec2"]["image"] %>",
"<%= image %>",
]
"""
Then response should be '400'
<% end %>

View File

@ -1,34 +1,44 @@
@key
Feature: Add new script
<% providers = @formatter.get_fixture('providers/all').map{|p| "@#{p}"} %>
@key <%= providers.join(" ") %>
Feature: Add new key
Scenario: Add new key without file_name
<% new_key = @formatter.get_fixture('key/new') %>
<% new_key.keys.each do |key| %>
<% [[], {}, nil].each do |value| %>
Scenario: Add new key with <%= key %> value <%= value %>
When I send POST '/v2.0/key' query with JSON body
"""
<%= @formatter.json('key/invalid/blank_file_name', spaces: 6) %>
<%= @formatter.json('key/new', {spaces: 4, value: {key => value}}) %>
"""
Then response should be '400'
And response error should be "Parameter 'file_name' must be a not empty string"
And response error should be "Parameter '<%= key %>' should be a not empty string"
Scenario: Add new key without key_name
Scenario: Add new key without <%= key %>
When I send POST '/v2.0/key' query with JSON body
"""
<%= @formatter.json('key/invalid/blank_key_name', spaces: 6) %>
<%= @formatter.json('key/new', {spaces: 4, without_field: key}) %>
"""
Then response should be '400'
And response error should be "Parameter 'key_name' should be a not empty string"
And response error should be "Parameter '<%= key %>' should be a not empty string"
Scenario: Add new key without content
When I send POST '/v2.0/key' query with JSON body
<% end #value %>
<% end %>
Scenario: Add new key with header 'Accept' value is not 'application/json'
When I send POST '/v2.0/key' query with JSON body with header 'Accept' value 'application/xml'
"""
<%= @formatter.json('key/invalid/blank_content', spaces: 6) %>
<%= @formatter.json('key/new') %>
"""
Then response should be '400'
And response error should be "Parameter 'content' should be a not empty string"
Then response should be '406'
Scenario: Add new key without privileges
When I send POST '/v2.0/key' query with user without privileges
Then response should be '401'
Scenario: Add new key
When I send POST '/v2.0/key' query with JSON body
"""
<%= @formatter.json('key/valid', spaces: 6) %>
<%= @formatter.json('key/new') %>
"""
Then response should be '201'

View File

@ -4,32 +4,47 @@ Feature: create user
Scenario: create user with user without privileges
When I send POST '/v2.0/user' query with JSON body with user without privileges
"""
{
"username": "<%= @config["user"]["name"] %>",
"email": "<%= @config["user"]["name"] %>@test.test",
"password": "<%= @config["user"]["name"] %>"
}
<%= @formatter.json('user/create', spaces: 4) %>
"""
Then response should be '401'
Scenario: create user without header 'Content-Type'
When I send POST '/v2.0/user' query with JSON body without header 'Content-Type'
"""
{
"username": "<%= @config["user"]["name"] %>",
"email": "<%= @config["user"]["name"] %>@test.test",
"password": "<%= @config["user"]["name"] %>"
}
<%= @formatter.json('user/create', spaces: 4) %>
"""
Then response should be '415'
Scenario: create user with header 'Accept' value is not 'application/json'
When I send POST '/v2.0/user' query with body with header 'Accept' value 'application/xml'
"""
<%= @formatter.json('user/create', spaces: 4) %>
"""
Then response should be '406'
Scenario: create user, invalid body: empty
When I send POST '/v2.0/user' query with JSON body
"""
"""
Then response should be '400'
<% ["{}", "[]"].each do |k| %>
<% invalid_name = "foo]&" %>
Scenario: create user with invalid name '<% invalid_name %>'
When I send POST '/v2.0/user' query with JSON body
"""
<%= @formatter.json('user/create', {spaces: 4, value: {"username" => invalid_name}}) %>
"""
Then response should be '400'
<% long_name = "a"*250 %>
Scenario: create user with long name '<% long_name %>'
When I send POST '/v2.0/user' query with JSON body
"""
<%= @formatter.json('user/create', {spaces: 4, value: {"username" => long_name}}) %>
"""
Then response should be '400'
<% [{}, []].each do |k| %>
Scenario: create user, invalid body: body is a '<%= k %>'
When I send POST '/v2.0/user' query with JSON body
"""
@ -38,85 +53,31 @@ Feature: create user
Then response should be '400'
<% end %>
<% elements = ["{}", "[]", "null" ] %>
<% elements = [{}, [], nil ] %>
<% fields = @formatter.get_fixture('user/create').keys.map{|k| k.to_s} %>
<% fields.each do |field| %>
<% elements.each do |k| %>
Scenario: create user, invalid body: username is a '<%= k %>'
Scenario: create user, invalid body: <%= field %> is a '<%= k %>'
When I send POST '/v2.0/user' query with JSON body
"""
{
"username": <%= k %>,
"email": "<%= @config["user"]["name"] %>@test.test",
"password": "<%= @config["user"]["name"] %>"
}
<%= @formatter.json('user/create', {spaces: 4, value: {field => k}}) %>
"""
Then response should be '400'
Scenario: create user, invalid body: without <%= field %>
When I send POST '/v2.0/user' query with JSON body
"""
<%= @formatter.json('user/create', {spaces: 4, without_field: field}) %>
"""
Then response should be '400'
<% end %>
<% elements.each do |k| %>
Scenario: create user, invalid body: password is a '<%= k %>'
When I send POST '/v2.0/user' query with JSON body
"""
{
"username": "<%= @config["user"]["name"] %>",
"email": "<%= @config["user"]["name"] %>@test.test",
"password": <%= k %>
}
"""
Then response should be '400'
<% end %>
<% elements.each do |k| %>
Scenario: create user, invalid body: email is a '<%= k %>'
When I send POST '/v2.0/user' query with JSON body
"""
{
"username": "<%= @config["user"]["name"] %>",
"email": <%= k %>,
"password": "<%= @config["user"]["name"] %>"
}
"""
Then response should be '400'
<% end %>
Scenario: create user, invalid body: without username
When I send POST '/v2.0/user' query with JSON body
"""
{
"email": "<%= @config["user"]["name"] %>@test.test",
"password": "<%= @config["user"]["name"] %>"
}
"""
Then response should be '400'
Scenario: create user, invalid body: without email
When I send POST '/v2.0/user' query with JSON body
"""
{
"username": "<%= @config["user"]["name"] %>",
"password": "<%= @config["user"]["name"] %>"
}
"""
Then response should be '400'
Scenario: create user, invalid body: without password
When I send POST '/v2.0/user' query with JSON body
"""
{
"email": "<%= @config["user"]["name"] %>@test.test",
"username": "<%= @config["user"]["name"] %>"
}
"""
Then response should be '400'
Scenario: create user
When I send POST '/v2.0/user' query with JSON body
"""
{
"username": "<%= @config["user"]["name"] %>",
"email": "<%= @config["user"]["name"] %>@test.test",
"password": "<%= @config["user"]["name"] %>"
}
<%= @formatter.json('user/create', spaces: 4) %>
"""
Then response should be '201'
And the Content-Type header should include 'application/json'

View File

@ -1,552 +1,85 @@
@image @project
Feature: Manage images
Scenario: Get list of all images
When I send GET '/v2.0/images' query
Then response should be '200'
And the Content-Type header should include 'application/json'
And the JSON response should be an array
And response array should contains elements like:
"""
[
{
"provider": "foo_provider",
"name": "foo_name",
"remote_user": "foo_user",
"bootstrap_template": "foo_template",
"id": "foo_id"
}
]
"""
Scenario: Get list of all images without privileges
When I send GET '/v2.0/images' query with user without privileges
Then response should be '401'
Scenario: Get list of all images - invalid path
When I send GET '/v2.0/images/foo' query
Then response should be '404'
@openstack
Scenario: Get list of openstack images
When I send GET '/v2.0/images?provider=openstack' query
Then response should be '200'
And the Content-Type header should include 'application/json'
And the JSON response should be an array
And response array should contains elements like:
"""
[
{
"provider": "foo_provider",
"name": "foo_name",
"remote_user": "foo_user",
"bootstrap_template": "foo_template",
"id": "foo_id"
}
]
"""
@openstack
Scenario: Get list of openstack images (provider)
When I send GET '/v2.0/images/provider/openstack' query
Then response should be '200'
And the Content-Type header should include 'application/json'
And the JSON response should be an array
@openstack
Scenario: Get images list of openstack without privileges
When I send GET '/v2.0/images/provider/openstack' query with user without privileges
Then response should be '401'
@ec2
Scenario: Get list of ec2 images
When I send GET '/v2.0/images?provider=ec2' query
Then response should be '200'
And the Content-Type header should include 'application/json'
And the JSON response should be an array
And response array should contains elements like:
"""
[
{
"provider": "foo_provider",
"name": "foo_name",
"remote_user": "foo_user",
"bootstrap_template": "foo_template",
"id": "foo_id"
}
]
"""
@ec2
Scenario: Get list of ec2 images (provider)
When I send GET '/v2.0/images/provider/ec2' query
Then response should be '200'
And the Content-Type header should include 'application/json'
And the JSON response should be an array
@ec2
Scenario: Get images list of ec2 without privileges
When I send GET '/v2.0/images/provider/ec2' query with user without privileges
Then response should be '401'
Scenario: Get list of images of unknown provider
When I send GET '/v2.0/images/provider/foo' query
Then response should be '404'
Scenario: Get images list without privileges
When I send GET '/v2.0/images' query with user without privileges
Then response should be '401'
Scenario: Get unknown image
When I send GET '/v2.0/image/foo' query
Then response should be '404'
Scenario: Get unknown image without privileges
When I send GET '/v2.0/image/foo' query with user without privileges
Then response should be '401'
@openstack
Scenario: Create openstack image with ec2 provider
<% providers = @formatter.get_fixture('providers/without_static') %>
<% providers.each do |provider| %>
<% other_providers = providers.clone - [provider] %>
<% other_providers.each do |oprovider| %>
@<%= provider %>
Scenario: Create <%= provider %> image with '<%= oprovider %>' provider (invalid image id for provider)
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": "ec2",
"name": "freebsd-10.0",
"remote_user": "root",
"bootstrap_template": "chef_freebsd",
"id": "<%= @config["openstack"]["image"] %>"
}
<%= @formatter.json(provider + '/image', {value: {"provider" => oprovider}}) %>
"""
Then response should be '400'
@openstack
Scenario: Create openstack image with invalid provider
<% end #other providers%>
<% image = @formatter.get_fixture(provider + '/image') %>
<% image.keys.each do |key| %>
<% [[], {}].each do |invalid_value| %>
@<%= provider %>
Scenario: Create <%= provider %> image with invalid <%= key %> value: '<%= invalid_value %>'
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": "foo",
"name": "freebsd-10.0",
"remote_user": "root",
"bootstrap_template": "chef_freebsd",
"id": "<%= @config["openstack"]["image"] %>"
}
<%= @formatter.json(provider + '/image', {value: {key => invalid_value}}) %>
"""
Then response should be '400'
@openstack
Scenario: Create openstack image with invalid provider - array
<% end #invalid values%>
<% end # keys%>
<% (image.keys - ["bootstrap_template"]).each do |key| %>
@<%= provider %>
Scenario: Create <%= provider %> image with invalid <%= key %> value: 'nil'
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": ["foo"],
"name": "freebsd-10.0",
"remote_user": "root",
"bootstrap_template": "chef_freebsd",
"id": "<%= @config["openstack"]["image"] %>"
}
<%= @formatter.json(provider + '/image', {value: {key => nil}}) %>
"""
Then response should be '400'
@openstack
Scenario: Create openstack image with invalid provider - hash
<% end %>
<% (image.keys - ["name", "remote_user"]).each do |key| %>
@<%= provider %>
Scenario: Create <%= provider %> image with invalid <%= key %> value: 'foo'
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": {},
"name": "freebsd-10.0",
"remote_user": "root",
"bootstrap_template": "chef_freebsd",
"id": "<%= @config["openstack"]["image"] %>"
}
<%= @formatter.json(provider + '/image', {value: {key => "foo"}}) %>
"""
Then response should be '400'
@openstack
Scenario: Create openstack image with invalid name - hash
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": "openstack",
"name": {},
"remote_user": "root",
"bootstrap_template": "chef_freebsd",
"id": "<%= @config["openstack"]["image"] %>"
}
"""
Then response should be '400'
<% end %>
@openstack
Scenario: Create openstack image with invalid name - array
@<%= provider %>
Scenario: Create <%= provider %> image
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": "openstack",
"name": [],
"remote_user": "root",
"bootstrap_template": "chef_freebsd",
"id": "<%= @config["openstack"]["image"] %>"
}
"""
Then response should be '400'
@openstack
Scenario: Create openstack image with invalid remote_user - hash
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": "openstack",
"name": "freebsd-10.0",
"remote_user": {},
"bootstrap_template": "chef_freebsd",
"id": "<%= @config["openstack"]["image"] %>"
}
"""
Then response should be '400'
@openstack
Scenario: Create openstack image with invalid remote_user - array
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": "openstack",
"name": "freebsd-10.0",
"remote_user": [],
"bootstrap_template": "chef_freebsd",
"id": "<%= @config["openstack"]["image"] %>"
}
"""
Then response should be '400'
@openstack
Scenario: Create openstack image with invalid bootstrap_template - array
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": "openstack",
"name": "freebsd-10.0",
"remote_user": "root",
"bootstrap_template": [],
"id": "<%= @config["openstack"]["image"] %>"
}
"""
Then response should be '400'
@openstack
Scenario: Create openstack image with invalid bootstrap_template - hash
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": "openstack",
"name": "freebsd-10.0",
"remote_user": "root",
"bootstrap_template": {},
"id": "<%= @config["openstack"]["image"] %>"
}
"""
Then response should be '400'
@openstack
Scenario: Create openstack image with invalid bootstrap_template - unknown
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": "openstack",
"name": "freebsd-10.0",
"remote_user": "root",
"bootstrap_template": "unknown",
"id": "<%= @config["openstack"]["image"] %>"
}
"""
Then response should be '400'
@openstack
Scenario: Create openstack image with invalid id - array
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": "openstack",
"name": "freebsd-10.0",
"remote_user": "root",
"bootstrap_template": "chef_freebsd",
"id": []
}
"""
Then response should be '400'
@openstack
Scenario: Create openstack image with invalid id - hash
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": "openstack",
"name": "freebsd-10.0",
"remote_user": "root",
"bootstrap_template": "chef_freebsd",
"id": {}
}
"""
Then response should be '400'
@openstack
Scenario: Create openstack image
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": "openstack",
"name": "freebsd-10.0",
"remote_user": "root",
"bootstrap_template": "chef_freebsd",
"id": "<%= @config["openstack"]["image"] %>"
}
<%= @formatter.json(provider + '/image') %>
"""
Then response should be '201'
And the Content-Type header should include 'application/json'
@ec2
Scenario: Create ec2 image with openstack provider
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": "openstack",
"name": "test-ec2",
"remote_user": "ec2-user",
"bootstrap_template": null,
"id": "<%= @config["ec2"]["image"] %>"
}
"""
Then response should be '400'
@ec2
Scenario: Create ec2 image with invalid provider
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": "foo",
"name": "test-ec2",
"remote_user": "ec2-user",
"bootstrap_template": null,
"id": "<%= @config["ec2"]["image"] %>"
}
"""
Then response should be '400'
@ec2
Scenario: Create ec2 image with invalid provider - array
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": ["foo"],
"name": "test-ec2",
"remote_user": "ec2-user",
"bootstrap_template": null,
"id": "<%= @config["ec2"]["image"] %>"
}
"""
Then response should be '400'
@ec2
Scenario: Create ec2 image with invalid provider - hash
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": {},
"name": "test-ec2",
"remote_user": "ec2-user",
"bootstrap_template": null,
"id": "<%= @config["ec2"]["image"] %>"
}
"""
Then response should be '400'
@ec2
Scenario: Create ec2 image with invalid name - hash
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": "ec2",
"name": {},
"remote_user": "ec2-user",
"bootstrap_template": null,
"id": "<%= @config["ec2"]["image"] %>"
}
"""
Then response should be '400'
@ec2
Scenario: Create ec2 image with invalid name - array
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": "ec2",
"name": [],
"remote_user": "ec2-user",
"bootstrap_template": null,
"id": "<%= @config["ec2"]["image"] %>"
}
"""
Then response should be '400'
@ec2
Scenario: Create ec2 image with invalid remote_user - hash
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": "ec2",
"name": "test-ec2",
"remote_user": {},
"bootstrap_template": null,
"id": "<%= @config["ec2"]["image"] %>"
}
"""
Then response should be '400'
@ec2
Scenario: Create ec2 image with invalid remote_user - array
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": "ec2",
"name": "test-ec2",
"remote_user": [],
"bootstrap_template": null,
"id": "<%= @config["ec2"]["image"] %>"
}
"""
Then response should be '400'
@ec2
Scenario: Create ec2 image with invalid bootstrap_template - array
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": "ec2",
"name": "test-ec2",
"remote_user": "ec2-user",
"bootstrap_template": [],
"id": "<%= @config["ec2"]["image"] %>"
}
"""
Then response should be '400'
@ec2
Scenario: Create ec2 image with invalid bootstrap_template - hash
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": "ec2",
"name": "test-ec2",
"remote_user": "ec2-user",
"bootstrap_template": {},
"id": "<%= @config["ec2"]["image"] %>"
}
"""
Then response should be '400'
@ec2
Scenario: Create ec2 image with invalid bootstrap_template - unknown
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": "ec2",
"name": "test-ec2",
"remote_user": "ec2-user",
"bootstrap_template": "unknown",
"id": "<%= @config["ec2"]["image"] %>"
}
"""
Then response should be '400'
@ec2
Scenario: Create ec2 image with invalid id - array
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": "ec2",
"name": "test-ec2",
"remote_user": "ec2-user",
"bootstrap_template": null,
"id": []
}
"""
Then response should be '400'
@ec2
Scenario: Create ec2 image with invalid id - hash
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": "ec2",
"name": "test-ec2",
"remote_user": "ec2-user",
"bootstrap_template": null,
"id": {}
}
"""
Then response should be '400'
@ec2
Scenario: Create ec2 image
When I send POST '/v2.0/image' query with JSON body
"""
{
"provider": "ec2",
"name": "test-ec2",
"remote_user": "ec2-user",
"bootstrap_template": null,
"id": "<%= @config["ec2"]["image"] %>"
}
"""
Then response should be '201'
And the Content-Type header should include 'application/json'
@ec2
Scenario: Get info for single ec2 image
When I send GET '/v2.0/image/<%= @config["ec2"]["image"] %>' query
@<%= provider %>
Scenario: Check new <%= provider %> image
When I send GET '/v2.0/image/<%= image["id"] %>' query
Then response should be '200'
And the Content-Type header should include 'application/json'
And the JSON response should be an object
And response should be JSON object like:
"""
{
"provider": "ec2",
"name": "test-ec2",
"remote_user": "ec2-user",
"bootstrap_template": null,
"id": "<%= @config["ec2"]["image"] %>"
}
<%= @formatter.json(provider + '/image') %>
"""
@ec2
Scenario: Get ec2 image without privileges
When I send GET '/v2.0/image/<%= @config["ec2"]["image"] %>' query with user without privileges
@<%= provider %>
Scenario: Get <%= provider %> image without privileges
When I send GET '/v2.0/image/<%= image["id"] %>' query with user without privileges
Then response should be '401'
@openstack
Scenario: Get info for single openstack image
When I send GET '/v2.0/image/<%= @config["openstack"]["image"] %>' query
Then response should be '200'
And the Content-Type header should include 'application/json'
And the JSON response should be an object
And response should be JSON object like:
"""
{
"provider": "openstack",
"name": "freebsd-10.0",
"remote_user": "root",
"bootstrap_template": "chef_freebsd",
"id": "<%= @config["openstack"]["image"] %>"
}
"""
@<%= provider %>
Scenario: Get list of <%= provider %> images with header 'Accept' value is not 'application/json'
When I send GET '/v2.0/image/<%= image["id"] %>' query with header 'Accept' value 'application/xml'
Then response should be '406'
@openstack
Scenario: Get openstack image without privileges
When I send GET '/v2.0/image/<%= @config["openstack"]["image"] %>' query with user without privileges
Then response should be '401'
<% end %>
Scenario: Get info for single unknown image
When I send GET '/v2.0/image/foo' query
Then response should be '404'
Scenario: Get image path
When I send GET '/v2.0/image' query
Then response should be '404'

View File

@ -1,32 +1,12 @@
@project
<% providers = @formatter.get_fixture('providers/all').map{|provider| "@#{provider}"} %>
@project <%= providers.join(" ") %>
Feature: create project
@openstack
Scenario: Create project <%= @config["openstack"]["project"]["name"] %>
<% project = @formatter.get_fixture('project') %>
Scenario: Create project <%= project["name"] %>
When I send POST '/v2.0/project' query with JSON body
"""
{
"deploy_envs": [
{
"identifier": "<%= @config["openstack"]["project"]["env"] %>",
"run_list": [],
"expires": null,
"provider": "openstack",
"users": [
"<%= @config["username"] %>"
],
"flavor": "<%= @config["openstack"]["flavor"] %>",
"image": "<%= @config["openstack"]["image"] %>",
"subnets": [
"<%= @config["openstack"]["subnet"] %>"
],
"groups": [
"default"
]
}
],
"name": "<%= @config["openstack"]["project"]["name"] %>"
}
<%= @formatter.json('project') %>
"""
Then response should be '201'

View File

@ -0,0 +1,3 @@
@project @deploy_env
Feature: create deploy env in project

View File

@ -1,13 +1,15 @@
@user
Feature: change user privileges and password
<% %w{password email}.each do |k| %>
<% val = (k == "email" ? "#{@config["user"]["name"]}@test.test" : @config["user"]["name"]) %>
<% user_hash = @formatter.get_fixture('user/create') %>
<% username = user_hash["username"] %>
<% update_user_hash = @formatter.get_fixture('user/update') %>
<% update_user_hash.keys.each do |k| %>
Scenario: change user <%= k %> with user without privileges
When I send PUT '/v2.0/user/<%= @config["user"]["name"] %>/<%= k %>' query with JSON body with user without privileges
When I send PUT '/v2.0/user/<%= username %>/<%= k %>' query with JSON body with user without privileges
"""
{
"<%= k %>": "<%= val %>"
"<%= k %>": "<%= update_user_hash[k] %>"
}
"""
Then response should be '401'
@ -16,29 +18,29 @@ Feature: change user privileges and password
When I send PUT '/v2.0/user/root/<%= k %>' query with JSON body
"""
{
"<%= k %>": "<%= val %>"
"<%= k %>": "<%= update_user_hash[k] %>"
}
"""
Then response should be '401'
Scenario: change user <%= k %> without header 'Content-Type'
When I send PUT '/v2.0/user/<%= @config["user"]["name"] %>/<%= k %>' query with JSON body without header 'Content-Type'
When I send PUT '/v2.0/user/<%= username %>/<%= k %>' query with JSON body without header 'Content-Type'
"""
{
"<%= k %>": "<%= val %>"
"<%= k %>": "<%= update_user_hash[k] %>"
}
"""
Then response should be '415'
Scenario: change user <%= k %>, invalid body: empty
When I send PUT '/v2.0/user/<%= @config["user"]["name"] %>/<%= k %>' query with JSON body
When I send PUT '/v2.0/user/<%= username %>/<%= k %>' query with JSON body
"""
"""
Then response should be '400'
<% ["{}", "[]", ""].each do |body| %>
<% ["", "[]"].each do |body| %>
Scenario: change user <%= k %>, invalid body: body is a '<%= body %>'
When I send PUT '/v2.0/user/<%= @config["user"]["name"] %>/<%= k %>' query with JSON body
When I send PUT '/v2.0/user/<%= username %>/<%= k %>' query with JSON body
"""
<%= body %>
"""
@ -47,7 +49,7 @@ Feature: change user privileges and password
<% elements = ["{}", "[]", "null" ] %>
<% elements.each do |value| %>
Scenario: change user <%= k %>, invalid body: <%= k %> is a '<%= value %>'
When I send PUT '/v2.0/user/<%= @config["user"]["name"] %>/<%= k %>' query with JSON body
When I send PUT '/v2.0/user/<%= username %>/<%= k %>' query with JSON body
"""
{
"<%= k %>": <%= value %>
@ -57,10 +59,10 @@ Feature: change user privileges and password
<% end %>
Scenario: change user <%= k %>
When I send PUT '/v2.0/user/<%= @config["user"]["name"] %>/<%= k %>' query with JSON body
When I send PUT '/v2.0/user/<%= username %>/<%= k %>' query with JSON body
"""
{
"<%= k %>": "<%= val %>"
"<%= k %>": "<%= update_user_hash[k] %>"
}
"""
Then response should be '200'
@ -69,115 +71,93 @@ Feature: change user privileges and password
<% end %>
Scenario: change user privileges with user without privileges
When I send PUT '/v2.0/user/<%= @config["user"]["name"] %>' query with JSON body with user without privileges
When I send PUT '/v2.0/user/<%= username %>' query with JSON body with user without privileges
"""
{}
<%= @formatter.json('user/privileges', {spaces: 4}) %>
"""
Then response should be '401'
Scenario: change root privileges
When I send PUT '/v2.0/user/root' query with JSON body
"""
{}
<%= @formatter.json('user/privileges', {spaces: 4}) %>
"""
Then response should be '401'
Scenario: change user privileges without header 'Content-Type'
When I send PUT '/v2.0/user/<%= @config["user"]["name"] %>' query with JSON body without header 'Content-Type'
When I send PUT '/v2.0/user/<%= username %>' query with JSON body without header 'Content-Type'
"""
{}
<%= @formatter.json('user/privileges', {spaces: 4}) %>
"""
Then response should be '415'
<% ["[]", ""].each do |body| %>
Scenario: change user privileges, invalid body: body is a '<%= body %>'
When I send PUT '/v2.0/user/<%= @config["user"]["name"] %>' query with JSON body
Scenario: change user privileges with header 'Accept' value is not application/json
When I send PUT '/v2.0/user/<%= username %>' query with JSON body with header 'Accept' value 'application/xml'
"""
<%= body %>
<%= @formatter.json('user/privileges', {spaces: 4}) %>
"""
Then response should be '400'
<% end %>
Then response should be '406'
<% elements = ["{}", "[]" ] %>
<% elements.each do |value| %>
Scenario: change user privileges, invalid body: cmd is a '<%= value %>'
When I send PUT '/v2.0/user/<%= @config["user"]["name"] %>' query with JSON body
When I send PUT '/v2.0/user/<%= username %>' query with JSON body
"""
{
"cmd": "<%= value %>",
"privileges": "r"
}
<%= @formatter.json('user/privileges_update', {spaces: 4, value: {"cmd" => value, "privileges" => "r"}}) %>
"""
Then response should be '400'
Scenario: change user privileges, invalid body: privileges is a '<%= value %>'
When I send PUT '/v2.0/user/<%= @config["user"]["name"] %>' query with JSON body
When I send PUT '/v2.0/user/<%= username %>' query with JSON body
"""
{
"cmd": "all",
"privileges": "<%= value %>"
}
<%= @formatter.json('user/privileges_update', {spaces: 4, value: {"cmd" => "foo", "privileges" => value}}) %>
"""
Then response should be '400'
<% end %>
Scenario: change user privileges: foo - r
When I send PUT '/v2.0/user/<%= @config["user"]["name"] %>' query with JSON body
When I send PUT '/v2.0/user/<%= username %>' query with JSON body
"""
{
"cmd": "foo",
"privileges": "r"
}
<%= @formatter.json('user/privileges_update', {spaces: 4, value: {"cmd" => "foo", "privileges" => "r"}}) %>
"""
Then response should be '400'
<% %w{foo, rr, rwwww, rwxxx, rwf}.each do |priv| %>
Scenario: change user privileges: all - <%= priv %>
When I send PUT '/v2.0/user/<%= @config["user"]["name"] %>' query with JSON body
"""
{
"cmd": "all",
"privileges": "<%= priv %>"
}
<%= @formatter.json('user/privileges_update', {spaces: 4, value: {"cmd" => "all", "privileges" => priv}}) %>
"""
Then response should be '400'
<% end %>
<% privs = %w{r w x rw rx wx rwx} %>
<% %w{flavor group image project server key user filter network provider script templates all}.each do |cmd| %>
<% privs = @formatter.get_fixture('user/privileges_values') %>
<% (@formatter.get_fixture('user/privileges').keys.map(&:to_s) << "all").each do |cmd| %>
<% privs.each do |priv| %>
Scenario: change user privileges: <%= cmd %> - <%= priv %>
When I send PUT '/v2.0/user/<%= @config["user"]["name"] %>' query with JSON body
When I send PUT '/v2.0/user/<%= username %>' query with JSON body
"""
{
"cmd": "<%= cmd %>",
"privileges": "<%= priv %>"
}
<%= @formatter.json('user/privileges_update', {spaces: 4, value: {"cmd" => cmd, "privileges" => priv}}) %>
"""
Then response should be '200'
<% end %>
Scenario: change user privileges: <%= cmd %> - without privileges
When I send PUT '/v2.0/user/<%= @config["user"]["name"] %>' query with JSON body
When I send PUT '/v2.0/user/<%= username %>' query with JSON body
"""
{
"cmd": "<%= cmd %>"
}
<%= @formatter.json('user/privileges_update', {spaces: 4, value: {"cmd" => cmd}, without_field: "privileges"}) %>
"""
Then response should be '200'
Scenario: change user privileges: <%= cmd %> - ' '
When I send PUT '/v2.0/user/<%= @config["user"]["name"] %>' query with JSON body
When I send PUT '/v2.0/user/<%= username %>' query with JSON body
"""
{
"cmd": "<%= cmd %>",
"privileges": " "
}
<%= @formatter.json('user/privileges_update', {spaces: 4, value: {"cmd" => cmd, "privileges" => " "}}) %>
"""
Then response should be '400'
<% end %>
Scenario: change user privileges: set default privileges
When I send PUT '/v2.0/user/<%= @config["user"]["name"] %>' query with JSON body
When I send PUT '/v2.0/user/<%= username %>' query with JSON body
"""
{
}

View File

@ -1,171 +1,62 @@
@image @project
Feature: Update images
@openstack
Scenario: Update openstack image with ec2 provider
When I send PUT '/v2.0/image/<%= @config["openstack"]["image"] %>' query with JSON body
<% providers = @formatter.get_fixture('providers/without_static') %>
<% providers.each do |provider| %>
<% image = @formatter.get_fixture(provider + '/image') %>
<% other_providers = providers.clone - [provider] %>
<% other_providers.each do |oprovider| %>
@<%= provider %>
Scenario: Update <%= provider %> image with '<%= oprovider %>' provider (invalid image id for provider)
When I send PUT '/v2.0/image/<%= image["id"] %>' query with JSON body
"""
{
"provider": "ec2",
"name": "freebsd-10.0",
"remote_user": "root",
"bootstrap_template": "chef_freebsd",
"id": "<%= @config["openstack"]["image"] %>"
}
<%= @formatter.json(provider + '/image', {value: {"provider" => oprovider}}) %>
"""
Then response should be '400'
@openstack
Scenario: Update openstack image with invalid provider
When I send PUT '/v2.0/image/<%= @config["openstack"]["image"] %>' query with JSON body
<% end #other providers%>
<% (image.keys - ["id"]).each do |key| %>
<% [[], {}].each do |invalid_value| %>
@<%= provider %>
Scenario: Update <%= provider %> image with invalid <%= key %> value: '<%= invalid_value %>'
When I send PUT '/v2.0/image/<%= image["id"] %>' query with JSON body
"""
{
"provider": "foo",
"name": "freebsd-10.0",
"remote_user": "root",
"bootstrap_template": "chef_freebsd",
"id": "<%= @config["openstack"]["image"] %>"
}
<%= @formatter.json(provider + '/image', {value: {key => invalid_value}}) %>
"""
Then response should be '400'
@openstack
Scenario: Update openstack image with invalid provider - array
When I send PUT '/v2.0/image/<%= @config["openstack"]["image"] %>' query with JSON body
<% end #invalid values%>
<% end # keys%>
<% (image.keys - ["bootstrap_template", "id"]).each do |key| %>
@<%= provider %>
Scenario: Update <%= provider %> image with invalid <%= key %> value: 'nil'
When I send PUT '/v2.0/image/<%= image["id"] %>' query with JSON body
"""
{
"provider": ["foo"],
"name": "freebsd-10.0",
"remote_user": "root",
"bootstrap_template": "chef_freebsd",
"id": "<%= @config["openstack"]["image"] %>"
}
<%= @formatter.json(provider + '/image', {value: {key => nil}}) %>
"""
Then response should be '400'
@openstack
Scenario: Update openstack image with invalid provider - hash
When I send PUT '/v2.0/image/<%= @config["openstack"]["image"] %>' query with JSON body
<% end %>
<% (image.keys - ["name", "remote_user", "id"]).each do |key| %>
@<%= provider %>
Scenario: Update <%= provider %> image with invalid <%= key %> value: 'foo'
When I send PUT '/v2.0/image/<%= image["id"] %>' query with JSON body
"""
{
"provider": {},
"name": "freebsd-10.0",
"remote_user": "root",
"bootstrap_template": "chef_freebsd",
"id": "<%= @config["openstack"]["image"] %>"
}
<%= @formatter.json(provider + '/image', {value: {key => "foo"}}) %>
"""
Then response should be '400'
@openstack
Scenario: Update openstack image with invalid name - hash
When I send PUT '/v2.0/image/<%= @config["openstack"]["image"] %>' query with JSON body
"""
{
"provider": "openstack",
"name": {},
"remote_user": "root",
"bootstrap_template": "chef_freebsd",
"id": "<%= @config["openstack"]["image"] %>"
}
"""
Then response should be '400'
<% end %>
@openstack
Scenario: Update openstack image with invalid name - array
When I send PUT '/v2.0/image/<%= @config["openstack"]["image"] %>' query with JSON body
<% [[], {}, "foo", nil].each do |value| %>
@<%= provider %>
Scenario: Update <%= provider %> image with invalid id value: '<%= value %>'
When I send PUT '/v2.0/image/<%= image["id"] %>' query with JSON body
"""
{
"provider": "openstack",
"name": [],
"remote_user": "root",
"bootstrap_template": "chef_freebsd",
"id": "<%= @config["openstack"]["image"] %>"
}
"""
Then response should be '400'
@openstack
Scenario: Update openstack image with invalid remote_user - hash
When I send PUT '/v2.0/image/<%= @config["openstack"]["image"] %>' query with JSON body
"""
{
"provider": "openstack",
"name": "freebsd-10.0",
"remote_user": {},
"bootstrap_template": "chef_freebsd",
"id": "<%= @config["openstack"]["image"] %>"
}
"""
Then response should be '400'
@openstack
Scenario: Update openstack image with invalid remote_user - array
When I send PUT '/v2.0/image/<%= @config["openstack"]["image"] %>' query with JSON body
"""
{
"provider": "openstack",
"name": "freebsd-10.0",
"remote_user": [],
"bootstrap_template": "chef_freebsd",
"id": "<%= @config["openstack"]["image"] %>"
}
"""
Then response should be '400'
@openstack
Scenario: Update openstack image with invalid bootstrap_template - array
When I send PUT '/v2.0/image/<%= @config["openstack"]["image"] %>' query with JSON body
"""
{
"provider": "openstack",
"name": "freebsd-10.0",
"remote_user": "root",
"bootstrap_template": [],
"id": "<%= @config["openstack"]["image"] %>"
}
"""
Then response should be '400'
@openstack
Scenario: Update openstack image with invalid bootstrap_template - hash
When I send PUT '/v2.0/image/<%= @config["openstack"]["image"] %>' query with JSON body
"""
{
"provider": "openstack",
"name": "freebsd-10.0",
"remote_user": "root",
"bootstrap_template": {},
"id": "<%= @config["openstack"]["image"] %>"
}
"""
Then response should be '400'
@openstack
Scenario: Update openstack image with invalid bootstrap_template - unknown
When I send PUT '/v2.0/image/<%= @config["openstack"]["image"] %>' query with JSON body
"""
{
"provider": "openstack",
"name": "freebsd-10.0",
"remote_user": "root",
"bootstrap_template": "unknown",
"id": "<%= @config["openstack"]["image"] %>"
}
"""
Then response should be '400'
@openstack
Scenario: Update openstack image with invalid id - array
When I send PUT '/v2.0/image/<%= @config["openstack"]["image"] %>' query with JSON body
"""
{
"provider": "openstack",
"name": "freebsd-10.0",
"remote_user": "root",
"bootstrap_template": "chef_freebsd",
"id": []
}
<%= @formatter.json(provider + '/image', {value: {"id" => value}}) %>
"""
Then response should be '200'
And the Content-Type header should include 'application/json'
@ -173,21 +64,16 @@ Feature: Update images
And response should be JSON object like:
"""
{
"message" : "Image '<%= @config["openstack"]["image"] %>' has been updated"
"message" : "Image '<%= image["id"] %>' has been updated"
}
"""
@openstack
Scenario: Update openstack image with invalid id - hash
When I send PUT '/v2.0/image/<%= @config["openstack"]["image"] %>' query with JSON body
<% end %>
Scenario: Update <%= provider %> image without id
When I send PUT '/v2.0/image/<%= image["id"] %>' query with JSON body
"""
{
"provider": "openstack",
"name": "freebsd-10.0",
"remote_user": "root",
"bootstrap_template": "chef_freebsd",
"id": {}
}
<%= @formatter.json(provider + '/image', {without_field: "id"}) %>
"""
Then response should be '200'
And the Content-Type header should include 'application/json'
@ -195,21 +81,15 @@ Feature: Update images
And response should be JSON object like:
"""
{
"message" : "Image '<%= @config["openstack"]["image"] %>' has been updated"
"message" : "Image '<%= image["id"] %>' has been updated"
}
"""
@openstack
Scenario: Update openstack image
When I send PUT '/v2.0/image/<%= @config["openstack"]["image"] %>' query with JSON body
@<%= provider %>
Scenario: Update <%= provider %> image
When I send PUT '/v2.0/image/<%= image["id"] %>' query with JSON body
"""
{
"provider": "openstack",
"name": "freebsd-10.0",
"remote_user": "root",
"bootstrap_template": "chef_freebsd",
"id": "<%= @config["openstack"]["image"] %>"
}
<%= @formatter.json(provider + '/image') %>
"""
Then response should be '200'
And the Content-Type header should include 'application/json'
@ -217,175 +97,15 @@ Feature: Update images
And response should be JSON object like:
"""
{
"message" : "Image '<%= @config["openstack"]["image"] %>' has been updated"
"message" : "Image '<%= image["id"] %>' has been updated"
}
"""
@ec2
Scenario: Update ec2 image with openstack provider
When I send PUT '/v2.0/image/<%= @config["ec2"]["image"] %>' query with JSON body
@<%= provider %>
Scenario: Update <%= provider %> image with bootstrap_template null
When I send PUT '/v2.0/image/<%= image["id"] %>' query with JSON body
"""
{
"provider": "openstack",
"name": "test-ec2",
"remote_user": "ec2-user",
"bootstrap_template": null,
"id": "<%= @config["ec2"]["image"] %>"
}
"""
Then response should be '400'
@ec2
Scenario: Update ec2 image with invalid provider
When I send PUT '/v2.0/image/<%= @config["ec2"]["image"] %>' query with JSON body
"""
{
"provider": "foo",
"name": "test-ec2",
"remote_user": "ec2-user",
"bootstrap_template": null,
"id": "<%= @config["ec2"]["image"] %>"
}
"""
Then response should be '400'
@ec2
Scenario: Update ec2 image with invalid provider - array
When I send PUT '/v2.0/image/<%= @config["ec2"]["image"] %>' query with JSON body
"""
{
"provider": ["foo"],
"name": "test-ec2",
"remote_user": "ec2-user",
"bootstrap_template": null,
"id": "<%= @config["ec2"]["image"] %>"
}
"""
Then response should be '400'
@ec2
Scenario: Update ec2 image with invalid provider - hash
When I send PUT '/v2.0/image/<%= @config["ec2"]["image"] %>' query with JSON body
"""
{
"provider": {},
"name": "test-ec2",
"remote_user": "ec2-user",
"bootstrap_template": null,
"id": "<%= @config["ec2"]["image"] %>"
}
"""
Then response should be '400'
@ec2
Scenario: Update ec2 image with invalid name - hash
When I send PUT '/v2.0/image/<%= @config["ec2"]["image"] %>' query with JSON body
"""
{
"provider": "ec2",
"name": {},
"remote_user": "ec2-user",
"bootstrap_template": null,
"id": "<%= @config["ec2"]["image"] %>"
}
"""
Then response should be '400'
@ec2
Scenario: Update ec2 image with invalid name - array
When I send PUT '/v2.0/image/<%= @config["ec2"]["image"] %>' query with JSON body
"""
{
"provider": "ec2",
"name": [],
"remote_user": "ec2-user",
"bootstrap_template": null,
"id": "<%= @config["ec2"]["image"] %>"
}
"""
Then response should be '400'
@ec2
Scenario: Update ec2 image with invalid remote_user - hash
When I send PUT '/v2.0/image/<%= @config["ec2"]["image"] %>' query with JSON body
"""
{
"provider": "ec2",
"name": "test-ec2",
"remote_user": {},
"bootstrap_template": null,
"id": "<%= @config["ec2"]["image"] %>"
}
"""
Then response should be '400'
@ec2
Scenario: Update ec2 image with invalid remote_user - array
When I send PUT '/v2.0/image/<%= @config["ec2"]["image"] %>' query with JSON body
"""
{
"provider": "ec2",
"name": "test-ec2",
"remote_user": [],
"bootstrap_template": null,
"id": "<%= @config["ec2"]["image"] %>"
}
"""
Then response should be '400'
@ec2
Scenario: Update ec2 image with invalid bootstrap_template - array
When I send PUT '/v2.0/image/<%= @config["ec2"]["image"] %>' query with JSON body
"""
{
"provider": "ec2",
"name": "test-ec2",
"remote_user": "ec2-user",
"bootstrap_template": [],
"id": "<%= @config["ec2"]["image"] %>"
}
"""
Then response should be '400'
@ec2
Scenario: Update ec2 image with invalid bootstrap_template - hash
When I send PUT '/v2.0/image/<%= @config["ec2"]["image"] %>' query with JSON body
"""
{
"provider": "ec2",
"name": "test-ec2",
"remote_user": "ec2-user",
"bootstrap_template": {},
"id": "<%= @config["ec2"]["image"] %>"
}
"""
Then response should be '400'
@ec2
Scenario: Update ec2 image with invalid bootstrap_template - unknown
When I send PUT '/v2.0/image/<%= @config["ec2"]["image"] %>' query with JSON body
"""
{
"provider": "ec2",
"name": "test-ec2",
"remote_user": "ec2-user",
"bootstrap_template": "unknown",
"id": "<%= @config["ec2"]["image"] %>"
}
"""
Then response should be '400'
@ec2
Scenario: Update ec2 image with invalid id - array
When I send PUT '/v2.0/image/<%= @config["ec2"]["image"] %>' query with JSON body
"""
{
"provider": "ec2",
"name": "test-ec2",
"remote_user": "ec2-user",
"bootstrap_template": null,
"id": []
}
<%= @formatter.json(provider + '/image', {value: {"bootstrap_template" => nil}}) %>
"""
Then response should be '200'
And the Content-Type header should include 'application/json'
@ -393,21 +113,15 @@ Feature: Update images
And response should be JSON object like:
"""
{
"message" : "Image '<%= @config["openstack"]["image"] %>' has been updated"
"message" : "Image '<%= image["id"] %>' has been updated"
}
"""
@ec2
Scenario: Update ec2 image with invalid id - hash
When I send PUT '/v2.0/image/<%= @config["ec2"]["image"] %>' query with JSON body
@<%= provider %>
Scenario: Update <%= provider %> image with old bootstrap_template: '<%= image["bootstrap_template"] %>'
When I send PUT '/v2.0/image/<%= image["id"] %>' query with JSON body
"""
{
"provider": "ec2",
"name": "test-ec2",
"remote_user": "ec2-user",
"bootstrap_template": null,
"id": {}
}
<%= @formatter.json(provider + '/image', {value: {"bootstrap_template" => image["bootstrap_template"]}}) %>
"""
Then response should be '200'
And the Content-Type header should include 'application/json'
@ -415,28 +129,9 @@ Feature: Update images
And response should be JSON object like:
"""
{
"message" : "Image '<%= @config["openstack"]["image"] %>' has been updated"
"message" : "Image '<%= image["id"] %>' has been updated"
}
"""
@ec2
Scenario: Update ec2 image
When I send PUT '/v2.0/image/<%= @config["ec2"]["image"] %>' query with JSON body
"""
{
"provider": "ec2",
"name": "test-ec2",
"remote_user": "ec2-user",
"bootstrap_template": null,
"id": "<%= @config["ec2"]["image"] %>"
}
"""
Then response should be '200'
And the Content-Type header should include 'application/json'
And the JSON response should be an object
And response should be JSON object like:
"""
{
"message" : "Image '<%= @config["openstack"]["image"] %>' has been updated"
}
"""
<% end #providers %>

View File

@ -1,42 +1,37 @@
@image @project
Feature: delete image
@openstack
Scenario: Delete openstack image with user without privileges
When I send DELETE '/v2.0/image/<%= @config["openstack"]["image"] %>' query with user without privileges
<% providers = @formatter.get_fixture('providers/without_static') %>
<% providers.each do |provider| %>
<% image = @formatter.get_fixture(provider + '/image') %>
@<%= provider %>
Scenario: Delete <%= provider %> image with user without privileges
When I send DELETE '/v2.0/image/<%= image["id"] %>' query with user without privileges
Then response should be '401'
@openstack
Scenario: Delete openstack image
When I send DELETE '/v2.0/image/<%= @config["openstack"]["image"] %>' query
@<%= provider %>
Scenario: Delete <%= provider %> image
When I send DELETE '/v2.0/image/<%= image["id"] %>' query
Then response should be '200'
And the Content-Type header should include 'application/json'
And the JSON response should be an object
And response should be JSON object like:
"""
{
"message" : "Image '<%= @config["openstack"]["image"] %>' has been removed"
"message" : "Image '<%= image["id"] %>' has been removed"
}
"""
@ec2
Scenario: Delete ec2 image with user without privileges
When I send DELETE '/v2.0/image/<%= @config["ec2"]["image"] %>' query with user without privileges
Then response should be '401'
@<%= provider %>
Scenario: Delete <%= provider %> image with header 'Accept' value is not 'application/json'
When I send DELETE '/v2.0/image/<%= image["id"] %>' query with header 'Accept' value 'application/xml'
Then response should be '406'
@ec2
Scenario: Delete ec2 image
When I send DELETE '/v2.0/image/<%= @config["ec2"]["image"] %>' query
Then response should be '200'
And the Content-Type header should include 'application/json'
And the JSON response should be an object
And response should be JSON object like:
"""
{
"message" : "Image '<%= @config["ec2"]["image"] %>' has been removed"
}
"""
<% end #providers %>
<% providers = @formatter.get_fixture('providers/all').map{|provider| "@#{provider}"} %>
<%= providers.join(" ") %>
Scenario: Delete unknown image
When I send DELETE '/v2.0/image/foo' query
Then response should be '404'

View File

@ -1,16 +1,22 @@
@user
Feature: delete user
<% user_hash = @formatter.get_fixture('user/create') %>
<% username = user_hash["username"] %>
Scenario: delete user with user without privileges
When I send DELETE '/v2.0/user/<%= @config["user"]["name"] %>' query with user without privileges
When I send DELETE '/v2.0/user/<%= username %>' query with user without privileges
Then response should be '401'
Scenario: delete unknown user
When I send DELETE '/v2.0/user/unknown' query
Then response should be '404'
Scenario: delete user with header 'Accept' value is not 'application/json'
When I send DELETE '/v2.0/user/<%= username %>' query with header 'Accept' value 'application/xml'
Then response should be '406'
Scenario: delete user
When I send DELETE '/v2.0/user/<%= @config["user"]["name"] %>' query
When I send DELETE '/v2.0/user/<%= username %>' query
Then response should be '200'
And the Content-Type header should include 'application/json'

View File

@ -1,153 +1,58 @@
@filter @image @project
Feature: Filters
@openstack
Scenario: Delete openstack image filter with user without privileges
When I send DELETE '/v2.0/filter/openstack/image' query with user without privileges
<% @formatter.get_fixture('providers/without_static').each do |provider| %>
<% image = @formatter.get_fixture(provider + "/image")["id"] %>
@<%= provider %>
Scenario: Delete <%= provider %> image filter with user without privileges
When I send DELETE '/v2.0/filter/<%= provider %>/image' query with user without privileges
Then response should be '401'
@openstack
Scenario: Delete openstack image filter without header 'Content-Type'
When I send DELETE '/v2.0/filter/openstack/image' query with JSON body without header 'Content-Type'
@<%= provider %>
Scenario: Delete images filter with header 'Accept' value not 'application/json'
When I send DELETE '/v2.0/filter/<%= provider %>/image' query with header 'Accept' value 'application/xml'
Then response should be '406'
@<%= provider %>
Scenario: Delete <%= provider %> image filter without header 'Content-Type'
When I send DELETE '/v2.0/filter/<%= provider %>/image' query with JSON body without header 'Content-Type'
"""
[
"<%= @config["openstack"]["image"] %>"
"<%= image %>"
]
"""
Then response should be '415'
@openstack
Scenario: Delete openstack image filter, invalid body: empty
When I send DELETE '/v2.0/filter/openstack/image' query with JSON body
<% ["", "{}", "[{}]", "[[]]", "[null]"].each do |body| %>
@<%= provider %>
Scenario: Delete <%= provider %> image filter, invalid body: empty
When I send DELETE '/v2.0/filter/<%= provider %>/image' query with JSON body
"""
<%= body %>
"""
Then response should be '400'
@openstack
Scenario: Delete openstack image filter, invalid body: hash
When I send DELETE '/v2.0/filter/openstack/image' query with JSON body
"""
{
"foo": "foo"
}
"""
Then response should be '400'
<% end %>
@openstack
Scenario: Delete openstack image filter, invalid body: element is hash
When I send DELETE '/v2.0/filter/openstack/image' query with JSON body
"""
[{
"foo": "foo"
}]
"""
Then response should be '400'
@openstack
Scenario: Delete openstack image filter, invalid body: element is array
When I send DELETE '/v2.0/filter/openstack/image' query with JSON body
@<%= provider %>
Scenario: Delete <%= provider %> image filter
When I send DELETE '/v2.0/filter/<%= provider %>/image' query with JSON body
"""
[
[]
]
"""
Then response should be '400'
@openstack
Scenario: Delete openstack image filter, invalid body: element is null
When I send DELETE '/v2.0/filter/openstack/image' query with JSON body
"""
[
null
]
"""
Then response should be '400'
@openstack
Scenario: Delete openstack image filter
When I send DELETE '/v2.0/filter/openstack/image' query with JSON body
"""
[
"<%= @config["openstack"]["image"] %>"
"<%= image %>"
]
"""
Then response should be '200'
And the Content-Type header should include 'application/json'
And the JSON response should be an object
And the object should contains key 'images' with array and array should not contains strings '<%= @config["openstack"]["image"] %>'
And the object should contains key 'images' with array and array should not contains strings '<%= image %>'
@ec2
Scenario: Delete ec2 image filter with user without privileges
When I send DELETE '/v2.0/filter/ec2/image' query with user without privileges
Then response should be '401'
@ec2
Scenario: Delete ec2 image filter without header 'Content-Type'
When I send DELETE '/v2.0/filter/ec2/image' query with JSON body without header 'Content-Type'
"""
[
"<%= @config["ec2"]["image"] %>"
]
"""
Then response should be '415'
@ec2
Scenario: Delete ec2 image filter, invalid body: empty
When I send DELETE '/v2.0/filter/ec2/image' query with JSON body
"""
"""
Then response should be '400'
@ec2
Scenario: Delete ec2 image filter, invalid body: hash
When I send DELETE '/v2.0/filter/ec2/image' query with JSON body
"""
{
"foo": "foo"
}
"""
Then response should be '400'
@ec2
Scenario: Delete ec2 image filter, invalid body: element is hash
When I send DELETE '/v2.0/filter/ec2/image' query with JSON body
"""
[{
"foo": "foo"
}]
"""
Then response should be '400'
@ec2
Scenario: Delete ec2 image filter, invalid body: element is array
When I send DELETE '/v2.0/filter/ec2/image' query with JSON body
"""
[
[]
]
"""
Then response should be '400'
@ec2
Scenario: Delete ec2 image filter, invalid body: element is null
When I send DELETE '/v2.0/filter/ec2/image' query with JSON body
"""
[
null
]
"""
Then response should be '400'
@ec2
Scenario: Delete ec2 image filter
When I send DELETE '/v2.0/filter/ec2/image' query with JSON body
"""
[
"<%= @config["ec2"]["image"] %>"
]
"""
@<%= provider %>
Scenario: Get new (after delete) <%= provider %> image filter and check value '<%= image %>'
When I send GET '/v2.0/filter/<%= provider %>/images' query
Then response should be '200'
And the Content-Type header should include 'application/json'
And the JSON response should be an object
And the object should contains key 'images' with array and array should not contains strings '<%= @config["ec2"]["image"] %>'
And the JSON response should be an array
And the array should not contains strings '<%= image %>'
<% end %>

View File

@ -1,9 +1,18 @@
@key
<% providers = @formatter.get_fixture('providers/all').map{|p| "@#{p}"} %>
@key <%= providers.join(" ") %>
Feature: Delete key
<% key_name = @fixtures['key']['valid']['key_name'] %>
<% key = @formatter.get_fixture('key/new') %>
Scenario: DELETE key with header 'Accept' value is not 'application/json'
When I send DELETE '/v2.0/key/<%= key["key_name"] %>' query with header 'Accept' value 'application/xml'
Then response should be '406'
Scenario: Delete key without privileges
When I send DELETE '/v2.0/key/<%= key["key_name"] %>' query with user without privileges
Then response should be '401'
Scenario: Delete key
When I send DELETE '/v2.0/key/<%= key_name %>' query
When I send DELETE '/v2.0/key/<%= key["key_name"] %>' query
Then response should be '200'
And the Content-Type header should include 'application/json'
And the JSON response should be an object

View File

@ -0,0 +1,33 @@
flavor:
id: &flavor_id "t1.micro"
cores: 2
disk: 0
name: "Micro Instance"
ram: 613
image:
id: &image_id "id"
provider: "ec2"
remote_user: "root"
name: &image_name ""
bootstrap_template: "omnibus"
network:
cidr: cidr
vpcId: vpcId
subnetId: subnetId
name: subnetId
zone: availabilityZone
provider_image:
id: *image_id
name: *image_name
status: available
deploy_env:
identifier: ec2_env
provider: "ec2"
run_list: []
expires: null
users: []
flavor: *flavor_id
image: *image_id
subnets: []
groups: []
stack_template: null

View File

@ -1,34 +1,42 @@
require 'json'
require 'pp'
class FixtureFormatter
def initialize(fixtures)
@fixtures = fixtures
if ENV["DEBUG"]
puts "Loaded fixtures:"
pp @fixtures
end
end
def json(path, options={})
result = nil
begin
result = JSON.pretty_generate(get_fixture(path))
result = JSON.pretty_generate(get_fixture(path, options))
rescue
raise "Fixture '#{path}' is absent"
end
if options[:spaces]
result = shift_to_right(result, options[:spaces])
end
options[:spaces] = 4 unless options[:spaces]
result = shift_to_right(result, options[:spaces])
result
end
private
def get_fixture(path)
def get_fixture(path, options={})
keys = path.split('/')
hash = @fixtures
keys.each do |key|
hash = hash[key]
end
hash = hash.clone
hash.merge!(options[:value]) if options[:value]
hash.delete(options[:without_field]) if options[:without_field]
hash
end
private
def shift_to_right(text, spaces_count)
buffer = ''
first_line = true
@ -42,4 +50,4 @@ class FixtureFormatter
end
buffer
end
end
end

View File

@ -1,20 +1,8 @@
valid: &valid
list_element:
scope: "system"
id: "devops"
new: &valid
file_name: test_file_name
key_name: test_key_name
content: test_content
invalid:
base: &invalid_base
<<: *valid
blank_file_name:
<<: *invalid_base
file_name:
blank_key_name:
<<: *invalid_base
key_name:
blank_content:
<<: *invalid_base
content:
scope:
<<: *invalid_base
scope: inalid_scope

View File

@ -0,0 +1,30 @@
flavor:
id: &flavor_id "flavor_id"
v_cpus: "v_cpus"
ram: "ram"
disk: "disk"
image:
id: &image_id "da25f4b0-3183-4993-ac2b-4744e4ed77cb"
provider: "openstack"
remote_user: "centos"
name: &image_name "CentOS-7-x86_64"
bootstrap_template: null
provider_image:
id: *image_id
name: *image_name
status: ACTIVE
network:
cidr: cidr
id: subnetId
name: subnetId
deploy_env:
identifier: ec2_env
provider: "openstack"
run_list: []
expires: null
users: []
flavor: *flavor_id
image: *image_id
subnets: []
groups: []
stack_template: null

View File

@ -0,0 +1,3 @@
name: cucumber_project
description: "Cucumber test project"

View File

@ -0,0 +1,4 @@
without_static:
[openstack, ec2]
all:
[openstack, ec2, static]

View File

@ -0,0 +1,7 @@
deploy_env:
identifier: static_env
provider: "static"
run_list: []
expires: null
users: []

View File

@ -0,0 +1,34 @@
privileges: &privileges
flavor: "rwx"
group: "rwx"
image: "rwx"
project: "rwx"
server: "rwx"
key: "rwx"
user: "rwx"
filter: "rwx"
network: "rwx"
provider: "rwx"
script: "rwx"
templates: "rwx"
stack: "rwx"
stack_template: "rwx"
show: &valid_show
email: "test@test.test"
privileges: *privileges
id: "test"
update: &valid_update
email: cucumber_test@test.test
password: test
create: &valid_create
<<: *valid_update
username: cucumber_test
privileges_values: ['', r, w, x, rw, rx, wx, rwx]
privileges_update:
cmd: all
privileges: r

View File

@ -0,0 +1,21 @@
class PathScenariosGenerator
def generate_get_path_scenarios name, path
%Q(
Scenario: #{name}
When I send GET '#{path}' query with JSON body
Then response should be '200'
And the Content-Type header should include 'application/json'
#{yield}
Scenario: #{name} with header 'Accept' value is not 'application/json'
When I send GET '#{path}' query with header 'Accept' value 'application/xml'
Then response should be '406'
Scenario: #{name} without privileges
When I send GET '#{path}' query with user without privileges
Then response should be '401'
)
end
end