Merge branch 'features' of /home/git/repositories/cloudtechlab/devops-service into qa
This commit is contained in:
commit
1e012d3e8f
@ -10,7 +10,7 @@ gem "sinatra-websocket"#, "~>0.3.0"
|
|||||||
gem "fog", "~>1.20"
|
gem "fog", "~>1.20"
|
||||||
gem "mixlib-shellout"
|
gem "mixlib-shellout"
|
||||||
gem "chef", ">=12"
|
gem "chef", ">=12"
|
||||||
gem "mongo"
|
gem "mongo", '1.12.3'
|
||||||
gem "bson_ext"
|
gem "bson_ext"
|
||||||
gem "multi_json", "1.7.8"
|
gem "multi_json", "1.7.8"
|
||||||
gem "sidekiq", "3.2.6"
|
gem "sidekiq", "3.2.6"
|
||||||
|
|||||||
@ -344,7 +344,7 @@ DEPENDENCIES
|
|||||||
httpclient
|
httpclient
|
||||||
mime-types (~> 1.25.1)
|
mime-types (~> 1.25.1)
|
||||||
mixlib-shellout
|
mixlib-shellout
|
||||||
mongo
|
mongo (= 1.12.3)
|
||||||
multi_json (= 1.7.8)
|
multi_json (= 1.7.8)
|
||||||
rack (= 1.5.2)
|
rack (= 1.5.2)
|
||||||
rack-accept-media-types
|
rack-accept-media-types
|
||||||
|
|||||||
@ -29,6 +29,7 @@ config[:openstack_ssh_key] = "ssh_key"
|
|||||||
config[:openstack_certificate] = "/path/to/.ssh/openstack.pem"
|
config[:openstack_certificate] = "/path/to/.ssh/openstack.pem"
|
||||||
|
|
||||||
# aws settings
|
# aws settings
|
||||||
|
config[:aws_use_iam_profile] = false
|
||||||
config[:aws_access_key_id] = "access_key_id"
|
config[:aws_access_key_id] = "access_key_id"
|
||||||
config[:aws_secret_access_key] = "secret_access_key"
|
config[:aws_secret_access_key] = "secret_access_key"
|
||||||
config[:aws_ssh_key] = "ssh_key"
|
config[:aws_ssh_key] = "ssh_key"
|
||||||
|
|||||||
@ -20,23 +20,24 @@ module Connectors
|
|||||||
f = collection.find('type' => 'image', 'provider' => provider).to_a.first
|
f = collection.find('type' => 'image', 'provider' => provider).to_a.first
|
||||||
if f.nil?
|
if f.nil?
|
||||||
collection.insert('type' => 'image', 'provider' => provider, 'images' => images)
|
collection.insert('type' => 'image', 'provider' => provider, 'images' => images)
|
||||||
return images
|
images
|
||||||
else
|
else
|
||||||
f['images'] |= images
|
f['images'] |= images
|
||||||
collection.update({'_id' => f['_id']}, f)
|
collection.update({'_id' => f['_id']}, f)
|
||||||
return f['images']
|
f['images']
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete_available_images images, provider
|
def delete_available_images images, provider
|
||||||
return unless images.is_a?(Array)
|
return unless images.is_a?(Array)
|
||||||
f = collection.find('type' => 'image', 'provider' => provider).to_a.first
|
filter = collection.find('type' => 'image', 'provider' => provider).to_a.first
|
||||||
unless f.nil?
|
if filter
|
||||||
f['images'] -= images
|
filter['images'] -= images
|
||||||
collection.update({'_id' => f['_id']}, f)
|
collection.update({'_id' => filter['_id']}, filter)
|
||||||
return f['images']
|
filter['images']
|
||||||
|
else
|
||||||
|
[]
|
||||||
end
|
end
|
||||||
[]
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -14,16 +14,10 @@ module Connectors
|
|||||||
end
|
end
|
||||||
|
|
||||||
def update(record)
|
def update(record)
|
||||||
begin
|
record.validate!
|
||||||
record.validate!
|
r = collection.update({"_id" => record.id}, record.to_mongo_hash)
|
||||||
collection.update({"_id" => record.id}, record.to_mongo_hash)
|
raise RecordNotFound.new("'#{record.id}' not found") if r['n'] == 0
|
||||||
record
|
record
|
||||||
rescue Mongo::OperationFailure => e
|
|
||||||
if e.message =~ /^11000/
|
|
||||||
resource_name = StringHelper.underscore_class(record.class)
|
|
||||||
raise InvalidRecord.new("Duplicate key error: #{resource_name} with id '#{record.id}'")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -2,9 +2,7 @@ module Connectors
|
|||||||
class Project < Base
|
class Project < Base
|
||||||
include Helpers::InsertCommand,
|
include Helpers::InsertCommand,
|
||||||
Helpers::ShowCommand,
|
Helpers::ShowCommand,
|
||||||
# Helpers::ListCommand,
|
|
||||||
Helpers::DeleteCommand
|
Helpers::DeleteCommand
|
||||||
# Helpers::UpdateCommand
|
|
||||||
|
|
||||||
|
|
||||||
def initialize(db)
|
def initialize(db)
|
||||||
@ -73,7 +71,7 @@ module Connectors
|
|||||||
res.each do |ar|
|
res.each do |ar|
|
||||||
r[ar['_id']] = ar['envs']
|
r[ar['_id']] = ar['envs']
|
||||||
end
|
end
|
||||||
return r
|
r
|
||||||
end
|
end
|
||||||
|
|
||||||
def projects_by_image(image)
|
def projects_by_image(image)
|
||||||
@ -98,10 +96,9 @@ module Connectors
|
|||||||
project
|
project
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# {find all projects with deploy_envs with field=value}, {return deploy_envs with field=value}
|
||||||
def projects_and_deploy_envs_by_field field, value
|
def projects_and_deploy_envs_by_field field, value
|
||||||
q = {}
|
q = {field => value}
|
||||||
q[field] = value
|
|
||||||
# {find all projects with deploy_envs with field=value}, {return deploy_envs with field=value}
|
|
||||||
list( {'deploy_envs' => {'$elemMatch' => q}}, {:fields => {'deploy_envs' => {'$elemMatch' => q}}} )
|
list( {'deploy_envs' => {'$elemMatch' => q}}, {:fields => {'deploy_envs' => {'$elemMatch' => q}}} )
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -114,12 +111,12 @@ module Connectors
|
|||||||
end
|
end
|
||||||
|
|
||||||
def set_project_env_run_list(project_id, env, run_list)
|
def set_project_env_run_list(project_id, env, run_list)
|
||||||
Helpers::RunList.new(run_list).validate!
|
::Validators::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
|
end
|
||||||
|
|
||||||
def set_project_run_list(project_id, env, run_list)
|
def set_project_run_list(project_id, run_list)
|
||||||
Helpers::RunList.new(run_list).validate!
|
::Validators::Helpers::RunList.new(run_list).validate!
|
||||||
@collection.update({"_id" => project_id}, {"$set" => {run_list: run_list}})
|
@collection.update({"_id" => project_id}, {"$set" => {run_list: run_list}})
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -128,17 +125,16 @@ module Connectors
|
|||||||
end
|
end
|
||||||
|
|
||||||
def remove_deploy_env_from_project id, env
|
def remove_deploy_env_from_project id, env
|
||||||
|
raise ArgumentError unless env.is_a?(String)
|
||||||
@collection.update({"_id" => id}, {'$pull' => {deploy_envs: {identifier: env}} })
|
@collection.update({"_id" => id}, {'$pull' => {deploy_envs: {identifier: env}} })
|
||||||
end
|
end
|
||||||
|
|
||||||
def project_update_field id, field, value
|
def project_update_field id, field, value
|
||||||
obj = {}
|
obj = {field => value}
|
||||||
obj[field] = value
|
|
||||||
@collection.update({"_id" => id}, {'$set' => obj })
|
@collection.update({"_id" => id}, {'$set' => obj })
|
||||||
end
|
end
|
||||||
|
|
||||||
def project_update id, params
|
def project_update id, params
|
||||||
#raise InvalidRecord.new("You can not change project name for '#{id}'.") if params["name"]
|
|
||||||
keys = %w(run_list description)
|
keys = %w(run_list description)
|
||||||
params.delete_if{|k,v| !keys.include?(k)}
|
params.delete_if{|k,v| !keys.include?(k)}
|
||||||
@collection.update({"_id" => id}, {'$set' => params })
|
@collection.update({"_id" => id}, {'$set' => params })
|
||||||
|
|||||||
@ -11,13 +11,12 @@ module Devops
|
|||||||
module Model
|
module Model
|
||||||
class CloudDeployEnv < DeployEnvBase
|
class CloudDeployEnv < DeployEnvBase
|
||||||
|
|
||||||
# attr_accessor :flavor, :image, :subnets, :groups, :stack_template
|
attr_accessor :flavor, :image, :subnets, :groups, :stack_template
|
||||||
|
|
||||||
set_validators ::Validators::DeployEnv::Flavor,
|
set_validators ::Validators::DeployEnv::Flavor,
|
||||||
::Validators::DeployEnv::Image,
|
::Validators::DeployEnv::Image,
|
||||||
::Validators::DeployEnv::Groups,
|
::Validators::DeployEnv::Groups,
|
||||||
::Validators::DeployEnv::StackTemplate
|
::Validators::DeployEnv::StackTemplate
|
||||||
# set_validators ::Validators::DeployEnv::CloudParameters
|
|
||||||
set_field_validators :flavor, [::Validators::FieldValidator::Nil,
|
set_field_validators :flavor, [::Validators::FieldValidator::Nil,
|
||||||
::Validators::FieldValidator::FieldType::String,
|
::Validators::FieldValidator::FieldType::String,
|
||||||
::Validators::FieldValidator::Flavor], order: 2
|
::Validators::FieldValidator::Flavor], order: 2
|
||||||
|
|||||||
@ -23,16 +23,27 @@ module Devops
|
|||||||
|
|
||||||
attr_accessor :id, :deploy_envs, :type, :archived, :description, :run_list
|
attr_accessor :id, :deploy_envs, :type, :archived, :description, :run_list
|
||||||
|
|
||||||
types :id => {:type => String, :empty => false},
|
|
||||||
:deploy_envs => {:type => Array, :value_type => false, :empty => false},
|
|
||||||
:description => {:type => String, :empty => true, :nil => true},
|
|
||||||
:run_list => {:type => Array, :value_type => String, :empty => true, :nil => false}
|
|
||||||
|
|
||||||
MULTI_TYPE = "multi"
|
MULTI_TYPE = "multi"
|
||||||
|
|
||||||
|
set_field_validators :id, [::Validators::FieldValidator::NotNil,
|
||||||
|
::Validators::FieldValidator::FieldType::String,
|
||||||
|
::Validators::FieldValidator::NotEmpty]
|
||||||
|
|
||||||
|
set_field_validators :deploy_envs, [::Validators::FieldValidator::NotNil,
|
||||||
|
::Validators::FieldValidator::FieldType::Array,
|
||||||
|
::Validators::FieldValidator::NotEmpty]
|
||||||
|
|
||||||
|
set_field_validators :description, [::Validators::FieldValidator::Nil,
|
||||||
|
::Validators::FieldValidator::FieldType::String]
|
||||||
|
|
||||||
|
set_field_validators :run_list, [::Validators::FieldValidator::NotNil,
|
||||||
|
::Validators::FieldValidator::FieldType::Array,
|
||||||
|
::Validators::FieldValidator::RunList]
|
||||||
|
|
||||||
set_validators ::Validators::DeployEnv::RunList,
|
set_validators ::Validators::DeployEnv::RunList,
|
||||||
::Validators::DeployEnv::DeployEnvs
|
::Validators::DeployEnv::DeployEnvs
|
||||||
|
|
||||||
|
|
||||||
def self.fields
|
def self.fields
|
||||||
["deploy_envs", "type", "description"]
|
["deploy_envs", "type", "description"]
|
||||||
end
|
end
|
||||||
@ -70,11 +81,14 @@ module Devops
|
|||||||
Project.create_roles_response(res)
|
Project.create_roles_response(res)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# user could be a String or an Array of strings.
|
||||||
|
# if env is nil, add given user(s) to all project's envs,
|
||||||
|
# otherwise only to specified one.
|
||||||
def add_authorized_user user, env=nil
|
def add_authorized_user user, env=nil
|
||||||
return if user.nil?
|
return if user.nil?
|
||||||
new_users = ( user.is_a?(Array) ? user : [ user ] )
|
new_users = ( user.is_a?(Array) ? user : [ user ] )
|
||||||
environments = env.nil? ? self.deploy_envs : [ self.deploy_env(env) ]
|
environments = env.nil? ? self.deploy_envs : [ self.deploy_env(env) ]
|
||||||
environments .each do |e|
|
environments.each do |e|
|
||||||
e.add_users new_users
|
e.add_users new_users
|
||||||
Devops::Db.connector.set_project_deploy_env_field(self.id, e.identifier, {users: e.users})
|
Devops::Db.connector.set_project_deploy_env_field(self.id, e.identifier, {users: e.users})
|
||||||
end
|
end
|
||||||
@ -202,7 +216,8 @@ module Devops
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.create_roles_response roles
|
def self.create_roles_response roles
|
||||||
if !roles || roles.is_a?(String)
|
return "error in creating roles" unless roles
|
||||||
|
if roles.is_a?(String)
|
||||||
roles
|
roles
|
||||||
else
|
else
|
||||||
info = ""
|
info = ""
|
||||||
|
|||||||
@ -13,6 +13,9 @@ module Devops
|
|||||||
set_field_validators :secret_access_key, [::Validators::FieldValidator::NotNil,
|
set_field_validators :secret_access_key, [::Validators::FieldValidator::NotNil,
|
||||||
::Validators::FieldValidator::FieldType::String,
|
::Validators::FieldValidator::FieldType::String,
|
||||||
::Validators::FieldValidator::NotEmpty]
|
::Validators::FieldValidator::NotEmpty]
|
||||||
|
|
||||||
|
set_field_validators :use_iam_profile, [::Validators::FieldValidator::Nil,
|
||||||
|
::Validators::FieldValidator::FieldType::Boolean]
|
||||||
def initialize a={}
|
def initialize a={}
|
||||||
super(a)
|
super(a)
|
||||||
self.provider = Provider::Ec2::PROVIDER
|
self.provider = Provider::Ec2::PROVIDER
|
||||||
@ -45,6 +48,7 @@ module Devops
|
|||||||
{
|
{
|
||||||
access_key_id: "AWS account access key",
|
access_key_id: "AWS account access key",
|
||||||
secret_access_key: "AWS account secret key",
|
secret_access_key: "AWS account secret key",
|
||||||
|
use_iam_profile: "Should use iam profile?",
|
||||||
availability_zone: "Availability zone, todo: remove field?"
|
availability_zone: "Availability zone, todo: remove field?"
|
||||||
}.merge(ProviderAccount::ACCOUNT_FIELDS)
|
}.merge(ProviderAccount::ACCOUNT_FIELDS)
|
||||||
end
|
end
|
||||||
|
|||||||
@ -17,21 +17,21 @@ module Devops
|
|||||||
owner: {type: String, empty: false}
|
owner: {type: String, empty: false}
|
||||||
|
|
||||||
set_field_validators :id, [::Validators::FieldValidator::NotNil,
|
set_field_validators :id, [::Validators::FieldValidator::NotNil,
|
||||||
::Validators::FieldValidator::FieldType::String,
|
::Validators::FieldValidator::FieldType::String,
|
||||||
::Validators::FieldValidator::NotEmpty,]
|
::Validators::FieldValidator::NotEmpty,
|
||||||
::Validators::FieldValidator::Name
|
::Validators::FieldValidator::Name]
|
||||||
|
|
||||||
set_field_validators :provider, [::Validators::FieldValidator::NotNil,
|
set_field_validators :provider, [::Validators::FieldValidator::NotNil,
|
||||||
::Validators::FieldValidator::FieldType::String,
|
::Validators::FieldValidator::FieldType::String,
|
||||||
::Validators::FieldValidator::NotEmpty]
|
::Validators::FieldValidator::NotEmpty]
|
||||||
|
|
||||||
set_field_validators :template_body, [::Validators::FieldValidator::NotNil,
|
set_field_validators :template_body, [::Validators::FieldValidator::NotNil,
|
||||||
::Validators::FieldValidator::FieldType::String,
|
::Validators::FieldValidator::FieldType::String,
|
||||||
::Validators::FieldValidator::NotEmpty]
|
::Validators::FieldValidator::NotEmpty]
|
||||||
|
|
||||||
set_field_validators :owner, [::Validators::FieldValidator::NotNil,
|
set_field_validators :owner, [::Validators::FieldValidator::NotNil,
|
||||||
::Validators::FieldValidator::FieldType::String,
|
::Validators::FieldValidator::FieldType::String,
|
||||||
::Validators::FieldValidator::NotEmpty]
|
::Validators::FieldValidator::NotEmpty]
|
||||||
|
|
||||||
set_validators ::Validators::StackTemplate::TemplateContent
|
set_validators ::Validators::StackTemplate::TemplateContent
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
require_relative "stack_template_base"
|
require_relative "stack_template_base"
|
||||||
require_relative "stack_template_openstack"
|
require_relative "stack_template_openstack"
|
||||||
require_relative "stack_template_ec2"
|
require_relative "stack_template_ec2"
|
||||||
|
require 'providers/openstack'
|
||||||
|
require 'providers/ec2'
|
||||||
|
|
||||||
module Devops
|
module Devops
|
||||||
module Model
|
module Model
|
||||||
|
|||||||
@ -25,6 +25,17 @@ module Validators
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class Boolean < FieldType
|
||||||
|
|
||||||
|
def valid?
|
||||||
|
@value == true or @value == false
|
||||||
|
end
|
||||||
|
|
||||||
|
def type_name
|
||||||
|
"boolean"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
class Array < FieldType
|
class Array < FieldType
|
||||||
|
|
||||||
def type
|
def type
|
||||||
|
|||||||
@ -15,10 +15,14 @@ module Provider
|
|||||||
self.certificate_path = config[:aws_certificate]
|
self.certificate_path = config[:aws_certificate]
|
||||||
self.ssh_key = config[:aws_ssh_key]
|
self.ssh_key = config[:aws_ssh_key]
|
||||||
options = {
|
options = {
|
||||||
:provider => "aws",
|
:provider => "aws"
|
||||||
:aws_access_key_id => config[:aws_access_key_id],
|
|
||||||
:aws_secret_access_key => config[:aws_secret_access_key]
|
|
||||||
}
|
}
|
||||||
|
if config[:aws_use_iam_profile]
|
||||||
|
options[:use_iam_profile] = true
|
||||||
|
else
|
||||||
|
options[:aws_access_key_id] = config[:aws_access_key_id]
|
||||||
|
options[:aws_secret_access_key] = config[:aws_secret_access_key]
|
||||||
|
end
|
||||||
if config[:aws_proxy] and config[:aws_no_proxy]
|
if config[:aws_proxy] and config[:aws_no_proxy]
|
||||||
options[:connection_options] = {
|
options[:connection_options] = {
|
||||||
:proxy => config[:aws_proxy],
|
:proxy => config[:aws_proxy],
|
||||||
|
|||||||
@ -20,6 +20,7 @@ module Provider
|
|||||||
aws_ssh_key: account.ssh_key,
|
aws_ssh_key: account.ssh_key,
|
||||||
aws_access_key_id: account.access_key_id,
|
aws_access_key_id: account.access_key_id,
|
||||||
aws_secret_access_key: account.secret_access_key,
|
aws_secret_access_key: account.secret_access_key,
|
||||||
|
aws_use_iam_profile: account.use_iam_profile,
|
||||||
aws_availability_zone: account.availability_zone,
|
aws_availability_zone: account.availability_zone,
|
||||||
|
|
||||||
aws_proxy: config[:aws_proxy],
|
aws_proxy: config[:aws_proxy],
|
||||||
|
|||||||
90
devops-service/spec/connectors/filter_connector_spec.rb
Normal file
90
devops-service/spec/connectors/filter_connector_spec.rb
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
require 'db/mongo/connectors/filter'
|
||||||
|
require 'spec/connectors/tester_connector/filter'
|
||||||
|
require_relative 'shared_connectors_context'
|
||||||
|
|
||||||
|
RSpec.describe Connectors::Filter, type: :connector do
|
||||||
|
set_tester_connector TesterConnector::Filter
|
||||||
|
include_context 'connectors'
|
||||||
|
let(:provider) {'ec2'}
|
||||||
|
|
||||||
|
describe '#available_images' do
|
||||||
|
subject { @connector.available_images(provider) }
|
||||||
|
|
||||||
|
context 'when there is no filter for given provider' do
|
||||||
|
it 'returns empty array' do
|
||||||
|
expect(subject).to eq []
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when there is filter for given provider but for another type' do
|
||||||
|
it 'returns empty array' do
|
||||||
|
test_filter = {provider: provider, type: 'foo', images: ['foo', 'bar']}
|
||||||
|
@tester_connector.create(test_filter) do
|
||||||
|
expect(subject).to eq []
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when there is filter for given provider' do
|
||||||
|
it "returns array with images' names" do
|
||||||
|
test_filter = {provider: provider, type: 'image', images: ['foo', 'bar']}
|
||||||
|
@tester_connector.create(test_filter) do
|
||||||
|
expect(subject).to match_array ['foo', 'bar']
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#add_available_images', cleanup_after: :each do
|
||||||
|
subject { @connector.add_available_images(['foo'], provider) }
|
||||||
|
|
||||||
|
it "do nothing if images is not Array" do
|
||||||
|
expect {
|
||||||
|
result = @connector.add_available_images('foo', provider)
|
||||||
|
expect(result).to be_nil
|
||||||
|
}.not_to change {@tester_connector.list}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates filter if there is no one' do
|
||||||
|
expect(@tester_connector.list.empty?).to be true
|
||||||
|
expect(subject).to match_array ['foo']
|
||||||
|
expect(@tester_connector.list.empty?).to be false
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'updates filter if one already exists' do
|
||||||
|
@tester_connector.create(provider: provider, type: 'image', images: ['bar'])
|
||||||
|
expect(subject).to match_array ['bar', 'foo']
|
||||||
|
expect(@tester_connector.list.first['images']).to match_array ['bar', 'foo']
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't duplicate images in filter" do
|
||||||
|
@tester_connector.create(provider: provider, type: 'image', images: ['foo'])
|
||||||
|
expect(subject).to match_array ['foo']
|
||||||
|
expect(@tester_connector.list.first['images']).to match_array ['foo']
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#delete_available_images' do
|
||||||
|
subject { @connector.delete_available_images(['foo'], provider) }
|
||||||
|
after { @tester_connector.cleanup }
|
||||||
|
let(:create_filter) { @tester_connector.create(provider: provider, type: 'image', images: ['foo', 'bar']) }
|
||||||
|
|
||||||
|
it 'does nothing if images is not Array' do
|
||||||
|
create_filter
|
||||||
|
expect {
|
||||||
|
result = @connector.delete_available_images('foo', provider)
|
||||||
|
expect(result).to be_nil
|
||||||
|
}.not_to change{ @tester_connector.list.first['images'] }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'removes given images from filter' do
|
||||||
|
create_filter
|
||||||
|
expect(subject).to match_array ['bar']
|
||||||
|
expect(@tester_connector.list.first['images']).to match_array ['bar']
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns empty array if there is no filter' do
|
||||||
|
expect(subject).to eq []
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
37
devops-service/spec/connectors/image_connector_spec.rb
Normal file
37
devops-service/spec/connectors/image_connector_spec.rb
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
require 'db/mongo/connectors/image'
|
||||||
|
require 'spec/connectors/tester_connector/image'
|
||||||
|
require_relative 'shared_connectors_context'
|
||||||
|
|
||||||
|
RSpec.describe Connectors::Image, type: :connector do
|
||||||
|
set_tester_connector TesterConnector::Image
|
||||||
|
include_context 'connectors'
|
||||||
|
let(:model_class) { Devops::Model::Image }
|
||||||
|
|
||||||
|
include_examples 'mongo connector', {
|
||||||
|
model_name: :image,
|
||||||
|
only: [:insert, :show, :update, :delete],
|
||||||
|
field_to_update: :name
|
||||||
|
}
|
||||||
|
|
||||||
|
describe '#images', cleanup_after: :each do
|
||||||
|
subject { @connector.images('ec2') }
|
||||||
|
|
||||||
|
it 'should be empty if collection is empty' do
|
||||||
|
expect(subject).to eq []
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns array of Model::Key's of given provider" do
|
||||||
|
@tester_connector.create(provider: 'ec2')
|
||||||
|
@tester_connector.create(provider: 'openstack')
|
||||||
|
expect(subject).to be_an_array_of(model_class).and have_size(1)
|
||||||
|
expect(subject.first.provider).to eq 'ec2'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns images for both providers if is is unset' do
|
||||||
|
@tester_connector.create(provider: 'ec2')
|
||||||
|
@tester_connector.create(provider: 'openstack')
|
||||||
|
expect(@connector.images.length).to eq 2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
62
devops-service/spec/connectors/key_connector_spec.rb
Normal file
62
devops-service/spec/connectors/key_connector_spec.rb
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
require 'db/mongo/connectors/key'
|
||||||
|
require 'db/mongo/models/key'
|
||||||
|
require 'spec/connectors/tester_connector/key'
|
||||||
|
require_relative 'shared_connectors_context'
|
||||||
|
|
||||||
|
RSpec.describe Connectors::Key, type: :connector do
|
||||||
|
set_tester_connector TesterConnector::Key
|
||||||
|
include_context 'connectors'
|
||||||
|
let(:model_class) { Devops::Model::Key }
|
||||||
|
|
||||||
|
include_examples 'mongo connector', model_name: :key, only: [:insert, :list]
|
||||||
|
|
||||||
|
describe '#key' do
|
||||||
|
context 'when scope was passed' do
|
||||||
|
subject { @connector.key('foo') }
|
||||||
|
|
||||||
|
it 'raises RecordNotFound when there is no such record' do
|
||||||
|
expect { subject }.to raise_error(RecordNotFound)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns record if was found' do
|
||||||
|
@tester_connector.create(id: 'foo') do
|
||||||
|
expect(subject).to be_an_instance_of(model_class)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when scope was passed' do
|
||||||
|
subject { @connector.key('foo', 'user') }
|
||||||
|
|
||||||
|
it 'raises RecordNotFound when there is no such record' do
|
||||||
|
expect { subject }.to raise_error(RecordNotFound)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns record if was found' do
|
||||||
|
@tester_connector.create(id: 'foo', scope: 'user') do
|
||||||
|
expect(subject).to be_an_instance_of(model_class)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#key_delete' do
|
||||||
|
subject { @connector.key_delete('foo') }
|
||||||
|
|
||||||
|
it 'raises RecordNotFound if there is no such record' do
|
||||||
|
expect{ subject }.to raise_error(RecordNotFound)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'remove key in "user" scope' do
|
||||||
|
@tester_connector.create(id: 'foo', scope: 'user')
|
||||||
|
subject
|
||||||
|
expect(@tester_connector.list).to eq []
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't remove key in 'system' scope" do
|
||||||
|
@tester_connector.create(id: 'foo', scope: 'system') do
|
||||||
|
expect {subject}.to raise_error RecordNotFound
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
295
devops-service/spec/connectors/project_connector_spec.rb
Normal file
295
devops-service/spec/connectors/project_connector_spec.rb
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
require 'db/mongo/connectors/project'
|
||||||
|
require 'spec/connectors/tester_connector/project'
|
||||||
|
require_relative 'shared_connectors_context'
|
||||||
|
|
||||||
|
RSpec.describe Connectors::Project, type: :connector do
|
||||||
|
set_tester_connector TesterConnector::Project
|
||||||
|
include_context 'connectors'
|
||||||
|
let(:model_class) { Devops::Model::Project }
|
||||||
|
|
||||||
|
include_examples 'mongo connector', {
|
||||||
|
model_name: :project,
|
||||||
|
factory_name: :project,
|
||||||
|
only: [:insert, :show, :delete],
|
||||||
|
field_to_update: :deploy_envs
|
||||||
|
}
|
||||||
|
|
||||||
|
describe '#is_project_exists?' do
|
||||||
|
subject { @connector.is_project_exists?(build(:project, id: 'foo')) }
|
||||||
|
it 'returns true if project exists' do
|
||||||
|
@tester_connector.create(id: 'foo') do
|
||||||
|
expect(subject).to be true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
it 'returns false if project doesn\'t exists' do
|
||||||
|
expect(subject).to be false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#projects_all' do
|
||||||
|
it 'returns array of projects' do
|
||||||
|
@tester_connector.create_list(2) do
|
||||||
|
result = @connector.projects_all
|
||||||
|
expect(result).to be_an_array_of(model_class).and have_size(2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#projects', cleanup_after: :all do
|
||||||
|
before(:all) do
|
||||||
|
@tester_connector.create build(:project, id: 'foo', type: 'multi').to_mongo_hash
|
||||||
|
@tester_connector.create build(:project, id: 'bar', archived: true).to_mongo_hash
|
||||||
|
@tester_connector.create build(:project, id: 'baz').to_mongo_hash
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns non archived projects with all params unset' do
|
||||||
|
expect(@connector.projects).to have_size(2)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns projects with given ids' do
|
||||||
|
result = @connector.projects(%w(foo baz))
|
||||||
|
expect(result).to be_an_array_of(model_class)
|
||||||
|
expect(result.map(&:id)).to match_array(%w(foo baz))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns multi projects if @type == :multi' do
|
||||||
|
expect(
|
||||||
|
@connector.projects(nil, :multi).map(&:id)
|
||||||
|
).to match_array ['foo']
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns only given fields and id if @fields is set' do
|
||||||
|
result = @connector.projects(nil, nil, [:deploy_envs])
|
||||||
|
expect(result.map(&:id).compact).not_to eq []
|
||||||
|
expect(result.map(&:deploy_envs).compact).not_to eq []
|
||||||
|
expect(result.map(&:description).compact).to eq []
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns only archived projects if @archived=true' do
|
||||||
|
result = @connector.projects(nil, nil, [], true)
|
||||||
|
expect(result.map(&:id)).to match_array(%w(bar))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#project_names_with_envs', cleanup_after: :all do
|
||||||
|
before(:all) do
|
||||||
|
@tester_connector.create(
|
||||||
|
id: 'foo',
|
||||||
|
deploy_envs: [{identifier: 'env1'}, {identifier: 'env2'}]
|
||||||
|
)
|
||||||
|
@tester_connector.create(
|
||||||
|
id: 'bar',
|
||||||
|
deploy_envs: [{identifier: 'env3'}, {identifier: 'env4'}]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns hash like {"project_name" => ["env1", "env2]}' do
|
||||||
|
result = @connector.project_names_with_envs
|
||||||
|
expect(result.keys.sort).to match_array %w(foo bar)
|
||||||
|
expect(result['foo'].sort).to match_array %w(env1 env2)
|
||||||
|
expect(result['bar'].sort).to match_array %w(env3 env4)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns only projects with given names' do
|
||||||
|
expect(@connector.project_names_with_envs(['bar']).keys).to match_array %w(bar)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#projects_by_image', cleanup_after: :each do
|
||||||
|
def env(image)
|
||||||
|
{image: image, provider: 'ec2'}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns projects deploy_envs of which have given image' do
|
||||||
|
@tester_connector.create(id: 'foo', deploy_envs: [env('a'), env('b')])
|
||||||
|
@tester_connector.create(id: 'bar', deploy_envs: [env('a'), env('a')])
|
||||||
|
@tester_connector.create(id: 'baz', deploy_envs: [env('b'), env('b')])
|
||||||
|
result = @connector.projects_by_image('a')
|
||||||
|
expect(result).to be_an_array_of(model_class)
|
||||||
|
expect(result.map(&:id)).to match_array %w(foo bar)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#projects_by_user', cleanup_after: :each do
|
||||||
|
def env(users)
|
||||||
|
{users: users, provider: 'ec2'}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns projects deploy_envs of which have given user' do
|
||||||
|
@tester_connector.create(id: 'foo', deploy_envs: [ env(%w(user1 user2)) ])
|
||||||
|
@tester_connector.create(id: 'bar', deploy_envs: [ env(%w(user1 user1)) ])
|
||||||
|
@tester_connector.create(id: 'baz', deploy_envs: [ env(%w(user2 user2)) ])
|
||||||
|
@tester_connector.create(id: 'baf', deploy_envs: [ env(%w(user1)), env(%w(user2)) ])
|
||||||
|
result = @connector.projects_by_user('user1')
|
||||||
|
expect(result).to be_an_array_of(model_class)
|
||||||
|
expect(result.map(&:id)).to match_array %w(foo bar baf)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#archive_project' do
|
||||||
|
it 'sets archived to true' do
|
||||||
|
@tester_connector.create(id: 'foo') do
|
||||||
|
@connector.archive_project('foo')
|
||||||
|
expect(@tester_connector.show('foo')).to include('archived' => true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#unarchive_project' do
|
||||||
|
it 'unsets archived' do
|
||||||
|
@tester_connector.create(id: 'foo', archived: true) do
|
||||||
|
@connector.unarchive_project('foo')
|
||||||
|
expect(@tester_connector.show('foo')).not_to include('archived')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#check_project_auth', cleanup_after: :all do
|
||||||
|
before(:all) do
|
||||||
|
@tester_connector.create(id: 'foo', deploy_envs: [
|
||||||
|
{identifier: 'bar', provider: 'ec2', users: %w(user1)}
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises InvalidPrivileges if given env users don't include given user" do
|
||||||
|
expect {
|
||||||
|
@connector.check_project_auth('foo', 'bar', 'user2')
|
||||||
|
}.to raise_error(InvalidPrivileges)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns project if env's users include given user" do
|
||||||
|
result = @connector.check_project_auth('foo', 'bar', 'user1')
|
||||||
|
expect(result).to be_an_instance_of(model_class)
|
||||||
|
expect(result.id).to eq 'foo'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#projects_and_deploy_envs_by_field', cleanup_after: :all do
|
||||||
|
def env(field, value)
|
||||||
|
{provider: 'ec2', field => value}
|
||||||
|
end
|
||||||
|
before(:all) do
|
||||||
|
@tester_connector.create(id: 'foo', deploy_envs: [
|
||||||
|
env(:image, 'image1'), env(:stack_template, 'template1')
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns projects with deploy envs containing given field with given value' do
|
||||||
|
expect(
|
||||||
|
@connector.projects_and_deploy_envs_by_field(:image, 'image1').map(&:id)
|
||||||
|
).to match_array %w(foo)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
@connector.projects_and_deploy_envs_by_field(:stack_template, 'template1').map(&:id)
|
||||||
|
).to match_array %w(foo)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#set_project_deploy_env_field', cleanup_after: :each do
|
||||||
|
it 'updates given env from given field_value_hash' do
|
||||||
|
@tester_connector.create(id: 'foo', deploy_envs: [
|
||||||
|
{identifier: 'bar', provider: 'ec2'}
|
||||||
|
])
|
||||||
|
@connector.set_project_deploy_env_field('foo', 'bar', image: 'a', stack_template: 'b')
|
||||||
|
updated_project = @tester_connector.show('foo')
|
||||||
|
expect(updated_project['deploy_envs'].first['image']).to eq 'a'
|
||||||
|
expect(updated_project['deploy_envs'].first['stack_template']).to eq 'b'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#set_project_env_run_list', cleanup_after: :all do
|
||||||
|
before(:all) do
|
||||||
|
@tester_connector.create(id: 'foo', deploy_envs: [{identifier: 'bar', provider: 'ec2'}])
|
||||||
|
end
|
||||||
|
before { allow_any_instance_of(Validators::Helpers::RunList).to receive(:validate!) }
|
||||||
|
|
||||||
|
it 'validates run list' do
|
||||||
|
run_list = []
|
||||||
|
expect_any_instance_of(Validators::Helpers::RunList).to receive(:validate!)
|
||||||
|
@connector.set_project_env_run_list('foo', 'bar', run_list)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "updates env's RunList" do
|
||||||
|
run_list = ['role[foo]']
|
||||||
|
@connector.set_project_env_run_list('foo', 'bar', run_list)
|
||||||
|
expect(@tester_connector.show('foo')['deploy_envs'].first['run_list']).to eq run_list
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#set_project_env_run_list', cleanup_after: :all do
|
||||||
|
before(:all) do
|
||||||
|
@tester_connector.create(id: 'foo')
|
||||||
|
end
|
||||||
|
before { allow_any_instance_of(Validators::Helpers::RunList).to receive(:validate!) }
|
||||||
|
|
||||||
|
it 'validates run list' do
|
||||||
|
run_list = []
|
||||||
|
expect_any_instance_of(Validators::Helpers::RunList).to receive(:validate!)
|
||||||
|
@connector.set_project_run_list('foo', run_list)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "updates project's RunList" do
|
||||||
|
run_list = ['role[foo]']
|
||||||
|
@connector.set_project_run_list('foo', run_list)
|
||||||
|
expect(@tester_connector.show('foo')['run_list']).to eq run_list
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#add_deploy_env_to_project' do
|
||||||
|
it 'adds env to project' do
|
||||||
|
@tester_connector.create(id: 'foo', deploy_envs: []) do
|
||||||
|
@connector.add_deploy_env_to_project('foo', build(:deploy_env))
|
||||||
|
expect(@tester_connector.show('foo')['deploy_envs']).not_to be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#remove_deploy_env_from_project', cleanup_after: :each do
|
||||||
|
before { @tester_connector.create(id: 'foo', deploy_envs: [{identifier: 'bar'}]) }
|
||||||
|
|
||||||
|
it "removes env from project" do
|
||||||
|
@connector.remove_deploy_env_from_project('foo', 'bar')
|
||||||
|
expect(@tester_connector.show('foo')['deploy_envs']).to be_empty
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'raises ArgumentError if given env is not a String' do
|
||||||
|
env = build(:deploy_env_ec2, identifier: 'bar')
|
||||||
|
expect { @connector.remove_deploy_env_from_project('foo', env) }.to raise_error(ArgumentError)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#project_update_field', cleanup_after: :each do
|
||||||
|
before { @tester_connector.create(id: 'foo', description: 'desc', run_list: []) }
|
||||||
|
subject { @connector.project_update_field('foo', 'run_list', ['role[a]']) }
|
||||||
|
|
||||||
|
it 'updates given field of given project' do
|
||||||
|
expect {subject}.to change { @tester_connector.show('foo')['run_list'] }.to ['role[a]']
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't affect other fields" do
|
||||||
|
expect {subject}.not_to change { @tester_connector.show('foo')['desc'] }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#project_update', cleanup_after: :each do
|
||||||
|
before { @tester_connector.create(id: 'foo', deploy_envs: [], description: 'desc', run_list: []) }
|
||||||
|
subject {
|
||||||
|
attrs = {'id' => 'foo2', 'deploy_envs' => [build(:deploy_env)], 'description' => 'desc2', 'run_list' => ['role[asd]']}
|
||||||
|
@connector.project_update('foo', attrs)
|
||||||
|
}
|
||||||
|
let(:updated_project) { @tester_connector.show('foo') }
|
||||||
|
|
||||||
|
it 'can update run_list and description' do
|
||||||
|
subject
|
||||||
|
expect(updated_project['run_list']).to eq ['role[asd]']
|
||||||
|
expect(updated_project['description']).to eq 'desc2'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'can not update other fields' do
|
||||||
|
subject
|
||||||
|
expect(updated_project['_id']).to eq 'foo'
|
||||||
|
expect(updated_project['deploy_envs']).to eq []
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
22
devops-service/spec/connectors/shared_connectors_context.rb
Normal file
22
devops-service/spec/connectors/shared_connectors_context.rb
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
def set_tester_connector(klass)
|
||||||
|
define_method :tester_connector_class do
|
||||||
|
klass
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
RSpec.shared_context 'connectors' do
|
||||||
|
before(:all) do
|
||||||
|
@connector = described_class.new(SpecSupport.db)
|
||||||
|
@tester_connector = tester_connector_class.new
|
||||||
|
@tester_connector.cleanup
|
||||||
|
end
|
||||||
|
after(:all){ @tester_connector.cleanup }
|
||||||
|
end
|
||||||
|
|
||||||
|
RSpec.shared_context 'cleanup after all', cleanup_after: :all do
|
||||||
|
after(:all){ @tester_connector.cleanup }
|
||||||
|
end
|
||||||
|
|
||||||
|
RSpec.shared_context 'cleanup after each', cleanup_after: :each do
|
||||||
|
after { @tester_connector.cleanup }
|
||||||
|
end
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
require 'db/mongo/connectors/stack_template'
|
||||||
|
require 'spec/connectors/tester_connector/stack_template'
|
||||||
|
require_relative 'shared_connectors_context'
|
||||||
|
|
||||||
|
RSpec.describe Connectors::StackTemplate, type: :connector do
|
||||||
|
set_tester_connector TesterConnector::StackTemplate
|
||||||
|
include_context 'connectors'
|
||||||
|
let(:model_class) { Devops::Model::StackTemplateEc2 }
|
||||||
|
|
||||||
|
include_examples 'mongo connector', {
|
||||||
|
model_name: :stack_template,
|
||||||
|
factory_name: :stack_template_ec2,
|
||||||
|
only: [:insert, :show, :update, :delete],
|
||||||
|
field_to_update: :owner
|
||||||
|
}
|
||||||
|
|
||||||
|
describe '#stack_templates' do
|
||||||
|
subject { @connector.stack_templates('ec2') }
|
||||||
|
|
||||||
|
it 'should be empty if collection is empty' do
|
||||||
|
expect(subject).to eq []
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns array of stack_templates of given provider" do
|
||||||
|
@tester_connector.create(provider: 'ec2')
|
||||||
|
@tester_connector.create(provider: 'openstack')
|
||||||
|
expect(subject).to be_a(Array)
|
||||||
|
expect(subject.length).to eq 1
|
||||||
|
expect(subject.first).to be_an_instance_of(model_class)
|
||||||
|
expect(subject.first.provider).to eq 'ec2'
|
||||||
|
@tester_connector.cleanup
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns stack_templates for both providers if is is unset' do
|
||||||
|
@tester_connector.create(provider: 'ec2')
|
||||||
|
@tester_connector.create(provider: 'openstack')
|
||||||
|
expect(@connector.stack_templates.length).to eq 2
|
||||||
|
@tester_connector.cleanup
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
53
devops-service/spec/connectors/tester_connector/base.rb
Normal file
53
devops-service/spec/connectors/tester_connector/base.rb
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
module TesterConnector
|
||||||
|
class Base
|
||||||
|
attr_reader :collection
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
collection_name = self.class.name.demodulize.underscore.pluralize
|
||||||
|
@collection = SpecSupport.db.collection(collection_name)
|
||||||
|
@next_id = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
def create(hash={})
|
||||||
|
collection.insert(create_params(hash))
|
||||||
|
if block_given?
|
||||||
|
yield
|
||||||
|
cleanup
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_list(size=2, hash={})
|
||||||
|
size.times { create(hash) }
|
||||||
|
if block_given?
|
||||||
|
yield
|
||||||
|
cleanup
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def list
|
||||||
|
collection.find().to_a
|
||||||
|
end
|
||||||
|
|
||||||
|
def show(id)
|
||||||
|
collection.find({'_id' => id}).to_a.first
|
||||||
|
end
|
||||||
|
|
||||||
|
def cleanup
|
||||||
|
collection.remove
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def create_params(hash)
|
||||||
|
params = hash.dup
|
||||||
|
if params[:id]
|
||||||
|
params['_id'] = params.delete(:id)
|
||||||
|
end
|
||||||
|
unless params['_id']
|
||||||
|
params['_id'] = @next_id
|
||||||
|
@next_id += 1
|
||||||
|
end
|
||||||
|
params
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
require_relative 'base'
|
||||||
|
|
||||||
|
module TesterConnector
|
||||||
|
class Filter < Base
|
||||||
|
end
|
||||||
|
end
|
||||||
6
devops-service/spec/connectors/tester_connector/image.rb
Normal file
6
devops-service/spec/connectors/tester_connector/image.rb
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
require_relative 'base'
|
||||||
|
|
||||||
|
module TesterConnector
|
||||||
|
class Image < Base
|
||||||
|
end
|
||||||
|
end
|
||||||
6
devops-service/spec/connectors/tester_connector/key.rb
Normal file
6
devops-service/spec/connectors/tester_connector/key.rb
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
require_relative 'base'
|
||||||
|
|
||||||
|
module TesterConnector
|
||||||
|
class Key < Base
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
require_relative 'base'
|
||||||
|
|
||||||
|
module TesterConnector
|
||||||
|
class Project < Base
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
require_relative 'base'
|
||||||
|
|
||||||
|
module TesterConnector
|
||||||
|
class StackTemplate < Base
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -2,6 +2,7 @@ require 'db/mongo/models/key'
|
|||||||
|
|
||||||
FactoryGirl.define do
|
FactoryGirl.define do
|
||||||
factory :key, class: Devops::Model::Key do
|
factory :key, class: Devops::Model::Key do
|
||||||
|
id 'user_key'
|
||||||
path SpecSupport::BLANK_FILE
|
path SpecSupport::BLANK_FILE
|
||||||
scope 'user'
|
scope 'user'
|
||||||
end
|
end
|
||||||
|
|||||||
23
devops-service/spec/factories/project.rb
Normal file
23
devops-service/spec/factories/project.rb
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
require 'db/mongo/models/project'
|
||||||
|
|
||||||
|
FactoryGirl.define do
|
||||||
|
factory :project, class: Devops::Model::Project do
|
||||||
|
transient do
|
||||||
|
with_deploy_env_identifier false
|
||||||
|
with_deploy_env_identifiers ['foo']
|
||||||
|
end
|
||||||
|
|
||||||
|
id 'my_project'
|
||||||
|
run_list []
|
||||||
|
description 'desc'
|
||||||
|
|
||||||
|
after(:build) do |project, evaluator|
|
||||||
|
unless project.deploy_envs
|
||||||
|
project.deploy_envs = []
|
||||||
|
evaluator.with_deploy_env_identifiers.each do |env_id|
|
||||||
|
project.deploy_envs << build(:deploy_env_ec2, identifier: env_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -13,8 +13,6 @@ FactoryGirl.define do
|
|||||||
updated_at Time.now
|
updated_at Time.now
|
||||||
status 'completed'
|
status 'completed'
|
||||||
|
|
||||||
initialize_with {
|
initialize_with { new(attributes.stringify_keys) }
|
||||||
new(attributes.stringify_keys)
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1,19 +1,9 @@
|
|||||||
require 'db/mongo/models/deploy_env/deploy_env_ec2'
|
require 'db/mongo/models/deploy_env/deploy_env_ec2'
|
||||||
|
require_relative '../shared_models_context'
|
||||||
|
|
||||||
RSpec.describe Devops::Model::DeployEnvEc2, type: :model do
|
RSpec.describe Devops::Model::DeployEnvEc2, type: :model do
|
||||||
let(:env) { build(:deploy_env_ec2) }
|
let(:env) { build(:deploy_env_ec2) }
|
||||||
|
include_context 'stubbed calls to connector in env validators'
|
||||||
before do
|
|
||||||
allow(Provider::ProviderFactory).to receive(:providers).and_return(%w(ec2))
|
|
||||||
allow_any_instance_of(Validators::Helpers::Users).to receive(:available_users).and_return(['root'])
|
|
||||||
allow_any_instance_of(Validators::DeployEnv::Flavor).to receive(:available_flavors).and_return([{'id' => 'flavor'}])
|
|
||||||
allow_any_instance_of(Validators::FieldValidator::Flavor).to receive(:available_flavors).and_return([{'id' => 'flavor'}])
|
|
||||||
allow_any_instance_of(Validators::DeployEnv::Groups).to receive(:available_groups).and_return(['default'])
|
|
||||||
allow_any_instance_of(Validators::DeployEnv::Image).to receive(:available_images).and_return([{'id' => 'image'}])
|
|
||||||
allow_any_instance_of(Validators::DeployEnv::Image).to receive(:available_images).and_return([{'id' => 'image'}])
|
|
||||||
allow_any_instance_of(Validators::DeployEnv::StackTemplate).to receive(:available_stack_templates).and_return([{'id' => 'template'}])
|
|
||||||
allow_any_instance_of(Validators::FieldValidator::Image).to receive(:available_images).and_return([{'id' => 'image'}])
|
|
||||||
end
|
|
||||||
|
|
||||||
it_behaves_like 'deploy env'
|
it_behaves_like 'deploy env'
|
||||||
it_behaves_like 'cloud deploy env'
|
it_behaves_like 'cloud deploy env'
|
||||||
|
|||||||
@ -1,19 +1,9 @@
|
|||||||
require 'db/mongo/models/deploy_env/deploy_env_openstack'
|
require 'db/mongo/models/deploy_env/deploy_env_openstack'
|
||||||
|
require_relative '../shared_models_context'
|
||||||
|
|
||||||
RSpec.describe Devops::Model::DeployEnvOpenstack, type: :model do
|
RSpec.describe Devops::Model::DeployEnvOpenstack, type: :model do
|
||||||
let(:env) { build(:deploy_env_openstack) }
|
let(:env) { build(:deploy_env_openstack) }
|
||||||
|
include_context 'stubbed calls to connector in env validators'
|
||||||
before do
|
|
||||||
allow(Provider::ProviderFactory).to receive(:providers).and_return(%w(openstack))
|
|
||||||
allow_any_instance_of(Validators::Helpers::Users).to receive(:available_users).and_return(['root'])
|
|
||||||
allow_any_instance_of(Validators::DeployEnv::Flavor).to receive(:available_flavors).and_return([{'id' => 'flavor'}])
|
|
||||||
allow_any_instance_of(Validators::FieldValidator::Flavor).to receive(:available_flavors).and_return([{'id' => 'flavor'}])
|
|
||||||
allow_any_instance_of(Validators::DeployEnv::Groups).to receive(:available_groups).and_return(['default'])
|
|
||||||
allow_any_instance_of(Validators::DeployEnv::Image).to receive(:available_images).and_return([{'id' => 'image'}])
|
|
||||||
allow_any_instance_of(Validators::DeployEnv::Image).to receive(:available_images).and_return([{'id' => 'image'}])
|
|
||||||
allow_any_instance_of(Validators::DeployEnv::StackTemplate).to receive(:available_stack_templates).and_return([{'id' => 'template'}])
|
|
||||||
allow_any_instance_of(Validators::FieldValidator::Image).to receive(:available_images).and_return([{'id' => 'image'}])
|
|
||||||
end
|
|
||||||
|
|
||||||
it_behaves_like 'deploy env'
|
it_behaves_like 'deploy env'
|
||||||
it_behaves_like 'cloud deploy env'
|
it_behaves_like 'cloud deploy env'
|
||||||
|
|||||||
274
devops-service/spec/models/project_spec.rb
Normal file
274
devops-service/spec/models/project_spec.rb
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
require 'db/mongo/models/project'
|
||||||
|
require_relative 'shared_models_context'
|
||||||
|
|
||||||
|
RSpec.describe Devops::Model::Project, type: :model do
|
||||||
|
let(:project) { build(:project) }
|
||||||
|
include_context 'stubbed calls to connector in env validators'
|
||||||
|
|
||||||
|
describe 'validation rules:' do
|
||||||
|
include_examples 'field type validation', :id, :not_nil, :non_empty_string
|
||||||
|
include_examples 'field type validation', :deploy_envs, :not_nil, :non_empty_array
|
||||||
|
include_examples 'field type validation', :description, :maybe_nil, :maybe_empty_string
|
||||||
|
include_examples 'field type validation', :run_list, :not_nil, :maybe_empty_array, :run_list
|
||||||
|
|
||||||
|
it "isn't valid when has envs with same identifier" do
|
||||||
|
project = build(:project, with_deploy_env_identifiers: %w(foo foo))
|
||||||
|
expect(project).not_to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is valid when all envs have uniq identifiers" do
|
||||||
|
project = build(:project, with_deploy_env_identifiers: %w(foo bar))
|
||||||
|
expect(project).to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "isn't valid when at least one of envs isn't valid" do
|
||||||
|
project = build(:project, with_deploy_env_identifiers: ['foo', nil])
|
||||||
|
expect(project).not_to be_valid
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '.fields' do
|
||||||
|
subject { described_class.fields }
|
||||||
|
it { should eq %w(deploy_envs type description) }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#initialize' do
|
||||||
|
it 'sets @type to generic by default' do
|
||||||
|
expect(described_class.new.type).to eq 'generic'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'sets @archived to false by default' do
|
||||||
|
expect(described_class.new.archived).to eq false
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'sets run_list to empty_array by default' do
|
||||||
|
expect(described_class.new.run_list).to eq []
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'deploy envs building' do
|
||||||
|
let(:params) { {'deploy_envs' => [ {'provider' => @env_provider, 'identifier' => 'foo'} ]} }
|
||||||
|
|
||||||
|
it 'builds envs array from given params' do
|
||||||
|
@env_provider = 'ec2'
|
||||||
|
expect(
|
||||||
|
described_class.new(params).deploy_envs
|
||||||
|
).to be_an_array_of(Devops::Model::DeployEnvEc2).and have_size(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'builds ec2 deploy envs from given params' do
|
||||||
|
@env_provider = 'ec2'
|
||||||
|
builded_env = described_class.new(params).deploy_envs.first
|
||||||
|
expect(builded_env).to be_a(Devops::Model::DeployEnvEc2)
|
||||||
|
expect(builded_env.identifier).to eq 'foo'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'build openstack deploy envs from given params' do
|
||||||
|
@env_provider = 'openstack'
|
||||||
|
builded_env = described_class.new(params).deploy_envs.first
|
||||||
|
expect(builded_env).to be_a(Devops::Model::DeployEnvOpenstack)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'build static deploy envs from given params' do
|
||||||
|
@env_provider = 'static'
|
||||||
|
builded_env = described_class.new(params).deploy_envs.first
|
||||||
|
expect(builded_env).to be_a(Devops::Model::DeployEnvStatic)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#deploy_env' do
|
||||||
|
let(:project) { project = build(:project, with_deploy_env_identifiers: %w(foo bar)) }
|
||||||
|
|
||||||
|
it 'returns found env' do
|
||||||
|
expect(project.deploy_env('bar')).to be_an(Devops::Model::DeployEnvEc2)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'raises RecordNotFound if there is no such env' do
|
||||||
|
expect {
|
||||||
|
project.deploy_env('missing')
|
||||||
|
}.to raise_error RecordNotFound
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#add_deploy_env', stub_logger: true do
|
||||||
|
let(:env) {build(:deploy_env_ec2)}
|
||||||
|
subject { project.add_deploy_env(env) }
|
||||||
|
before do
|
||||||
|
allow(Devops::Db).to receive_message_chain('connector.add_deploy_env_to_project')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'inserts deploy env into mongo via connector' do
|
||||||
|
expect(
|
||||||
|
Devops::Db
|
||||||
|
).to receive_message_chain('connector.add_deploy_env_to_project').with(project.id, env)
|
||||||
|
subject
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates chef role' do
|
||||||
|
expect(env).to receive(:create_role).with(project.id)
|
||||||
|
subject
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns string' do
|
||||||
|
expect(subject).to be_a(String)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#add_authorized_user' do
|
||||||
|
before do
|
||||||
|
allow(Devops::Db).to receive_message_chain('connector.set_project_deploy_env_field')
|
||||||
|
end
|
||||||
|
let(:env1) { build(:deploy_env_ec2, identifier: 'foo') }
|
||||||
|
let(:env2) { build(:deploy_env_ec2, identifier: 'bar') }
|
||||||
|
let(:project) { build(:project, deploy_envs: [env1, env2]) }
|
||||||
|
|
||||||
|
it 'returns nil if user is nil' do
|
||||||
|
expect(project.add_authorized_user(nil)).to be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when env isn't given" do
|
||||||
|
context 'when user is a String' do
|
||||||
|
it 'adds given user to all envs' do
|
||||||
|
project.add_authorized_user('John')
|
||||||
|
expect(env1.users).to match_array(%w(root John))
|
||||||
|
expect(env2.users).to match_array(%w(root John))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when user is an Array of strings' do
|
||||||
|
it 'adds given users to all envs' do
|
||||||
|
project.add_authorized_user(['John', 'Matz'])
|
||||||
|
expect(env1.users).to match_array(%w(root John Matz))
|
||||||
|
expect(env2.users).to match_array(%w(root John Matz))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when env is given' do
|
||||||
|
context 'when user is a String' do
|
||||||
|
it 'adds given user to given env' do
|
||||||
|
project.add_authorized_user('John', 'bar')
|
||||||
|
expect(env1.users).to match_array(%w(root))
|
||||||
|
expect(env2.users).to match_array(%w(root John))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when user is an Array of strings' do
|
||||||
|
it 'adds given users to all envs' do
|
||||||
|
project.add_authorized_user(['John', 'Matz'], 'bar')
|
||||||
|
expect(env1.users).to match_array(%w(root))
|
||||||
|
expect(env2.users).to match_array(%w(root John Matz))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#remove_authorized_user' do
|
||||||
|
before do
|
||||||
|
allow(Devops::Db).to receive_message_chain('connector.set_project_deploy_env_field')
|
||||||
|
end
|
||||||
|
let(:env1) { build(:deploy_env_ec2, identifier: 'foo', users: %w(root John Matz)) }
|
||||||
|
let(:env2) { build(:deploy_env_ec2, identifier: 'bar', users: %w(root John Matz)) }
|
||||||
|
let(:project) { build(:project, deploy_envs: [env1, env2]) }
|
||||||
|
|
||||||
|
it 'returns nil if user is nil' do
|
||||||
|
expect(project.remove_authorized_user(nil)).to be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when env isn't given" do
|
||||||
|
context 'when user is a String' do
|
||||||
|
it 'adds given user to all envs' do
|
||||||
|
project.remove_authorized_user('John')
|
||||||
|
expect(env1.users).to match_array(%w(root Matz))
|
||||||
|
expect(env2.users).to match_array(%w(root Matz))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when user is an Array of strings' do
|
||||||
|
it 'adds given users to all envs' do
|
||||||
|
project.remove_authorized_user(['John', 'Matz'])
|
||||||
|
expect(env1.users).to match_array(%w(root))
|
||||||
|
expect(env2.users).to match_array(%w(root))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when env is given' do
|
||||||
|
context 'when user is a String' do
|
||||||
|
it 'adds given user to given env' do
|
||||||
|
project.remove_authorized_user('John', 'bar')
|
||||||
|
expect(env1.users).to match_array(%w(root John Matz))
|
||||||
|
expect(env2.users).to match_array(%w(root Matz))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when user is an Array of strings' do
|
||||||
|
it 'adds given users to all envs' do
|
||||||
|
project.remove_authorized_user(['John', 'Matz'], 'bar')
|
||||||
|
expect(env1.users).to match_array(%w(root John Matz))
|
||||||
|
expect(env2.users).to match_array(%w(root))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#check_authorization' do
|
||||||
|
subject { project.check_authorization(@user || 'Matz', 'foo') }
|
||||||
|
|
||||||
|
it 'returns true for root user' do
|
||||||
|
@user = 'root'
|
||||||
|
expect(subject).to be true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns false if env's users don't include given user" do
|
||||||
|
expect(subject).to be false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns true if env's users include given user" do
|
||||||
|
project.deploy_env('foo').users = %w(root Matz)
|
||||||
|
expect(subject).to be true
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns false if there is no such env' do
|
||||||
|
expect(project.check_authorization('root', 'wrong')).to be false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#delete_deploy_env' do
|
||||||
|
it 'removes env' do
|
||||||
|
allow(Devops::Db).to receive_message_chain('connector.remove_deploy_env_from_project')
|
||||||
|
expect(Devops::Db).to receive_message_chain('connector.remove_deploy_env_from_project').with(project.id, 'foo')
|
||||||
|
project.delete_deploy_env('foo')
|
||||||
|
expect(project.deploy_envs).to match_array []
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#to_hash' do
|
||||||
|
subject { project.to_hash }
|
||||||
|
it 'returns hash' do
|
||||||
|
expect(subject).to be_a(Hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'contains project id under name key' do
|
||||||
|
expect(subject['name']).to eq project.id
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'contains deploy_envs converted to hashes' do
|
||||||
|
expect(subject['deploy_envs']).to be_an_array_of(Hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'also contains descriptions and run_list' do
|
||||||
|
expect(subject).to include('description', 'run_list')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'contains archived key if project is archived' do
|
||||||
|
project.archived = true
|
||||||
|
expect(subject).to include('archived')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't contain archived if project isn't archived" do
|
||||||
|
expect(subject).not_to include('archived')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@ -24,8 +24,7 @@ RSpec.describe Devops::Model::Server, type: :model do
|
|||||||
include_examples 'field type validation', :chef_node_name, :not_nil, :maybe_empty_string
|
include_examples 'field type validation', :chef_node_name, :not_nil, :maybe_empty_string
|
||||||
include_examples 'field type validation', :reserved_by, :not_nil, :maybe_empty_string
|
include_examples 'field type validation', :reserved_by, :not_nil, :maybe_empty_string
|
||||||
include_examples 'field type validation', :stack, :maybe_nil, :non_empty_string
|
include_examples 'field type validation', :stack, :maybe_nil, :non_empty_string
|
||||||
include_examples 'field type validation', :run_list, :not_nil, :maybe_empty_array
|
include_examples 'field type validation', :run_list, :not_nil, :maybe_empty_array, :run_list
|
||||||
include_examples 'field type validation', :run_list, :run_list
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#initialize' do
|
describe '#initialize' do
|
||||||
|
|||||||
21
devops-service/spec/models/shared_models_context.rb
Normal file
21
devops-service/spec/models/shared_models_context.rb
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
RSpec.shared_context 'stubbed calls to connector in env validators' do
|
||||||
|
before do
|
||||||
|
allow(Provider::ProviderFactory).to receive(:providers).and_return(%w(ec2 openstack))
|
||||||
|
allow_any_instance_of(Validators::Helpers::Users).to receive(:available_users).and_return(['root'])
|
||||||
|
allow_any_instance_of(Validators::DeployEnv::Flavor).to receive(:available_flavors).and_return([{'id' => 'flavor'}])
|
||||||
|
allow_any_instance_of(Validators::FieldValidator::Flavor).to receive(:available_flavors).and_return([{'id' => 'flavor'}])
|
||||||
|
allow_any_instance_of(Validators::DeployEnv::Groups).to receive(:available_groups).and_return(['default'])
|
||||||
|
allow_any_instance_of(Validators::DeployEnv::Image).to receive(:available_images).and_return([{'id' => 'image'}])
|
||||||
|
allow_any_instance_of(Validators::DeployEnv::Image).to receive(:available_images).and_return([{'id' => 'image'}])
|
||||||
|
allow_any_instance_of(Validators::DeployEnv::StackTemplate).to receive(:available_stack_templates).and_return([{'id' => 'template'}])
|
||||||
|
allow_any_instance_of(Validators::FieldValidator::Image).to receive(:available_images).and_return([{'id' => 'image'}])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
RSpec.shared_context 'stubbed calls to logger', stub_logger: true do
|
||||||
|
before do
|
||||||
|
allow(DevopsLogger).to receive_message_chain('logger.debug')
|
||||||
|
allow(DevopsLogger).to receive_message_chain('logger.info')
|
||||||
|
allow(DevopsLogger).to receive_message_chain('logger.error')
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -8,6 +8,10 @@ require 'active_support/inflector'
|
|||||||
root = File.join(File.dirname(__FILE__), "..")
|
root = File.join(File.dirname(__FILE__), "..")
|
||||||
$LOAD_PATH.push root unless $LOAD_PATH.include? root
|
$LOAD_PATH.push root unless $LOAD_PATH.include? root
|
||||||
|
|
||||||
|
# suppress output
|
||||||
|
original_stdout = $stdout
|
||||||
|
$stdout = File.open(File::NULL, "w")
|
||||||
|
|
||||||
Dir[("./spec/support/**/*.rb")].each { |f| require f }
|
Dir[("./spec/support/**/*.rb")].each { |f| require f }
|
||||||
|
|
||||||
# Factory girl configuration
|
# Factory girl configuration
|
||||||
@ -21,6 +25,10 @@ FactoryGirl.find_definitions
|
|||||||
RSpec.configure do |config|
|
RSpec.configure do |config|
|
||||||
config.include FactoryGirl::Syntax::Methods
|
config.include FactoryGirl::Syntax::Methods
|
||||||
|
|
||||||
|
config.after(:all) do
|
||||||
|
$stdout = original_stdout
|
||||||
|
end
|
||||||
|
|
||||||
# rspec-expectations config goes here. You can use an alternate
|
# rspec-expectations config goes here. You can use an alternate
|
||||||
# assertion/expectation library such as wrong or the stdlib/minitest
|
# assertion/expectation library such as wrong or the stdlib/minitest
|
||||||
# assertions if you prefer.
|
# assertions if you prefer.
|
||||||
|
|||||||
13
devops-service/spec/support/array_matcher.rb
Normal file
13
devops-service/spec/support/array_matcher.rb
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
RSpec::Matchers.define :be_an_array_of do |klass|
|
||||||
|
match do |actual|
|
||||||
|
actual.class == Array &&
|
||||||
|
actual.all? {|item| item.class == klass}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
RSpec::Matchers.define :have_size do |length|
|
||||||
|
match { |actual| actual.length == length }
|
||||||
|
failure_message do |actual|
|
||||||
|
"expected #{actual} to have size #{expected} but have #{actual.length}"
|
||||||
|
end
|
||||||
|
end
|
||||||
7
devops-service/spec/support/config.yml
Normal file
7
devops-service/spec/support/config.yml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# only :db key is required
|
||||||
|
mongo:
|
||||||
|
:db: devops_test
|
||||||
|
:host:
|
||||||
|
:port:
|
||||||
|
:user:
|
||||||
|
:password:
|
||||||
127
devops-service/spec/support/shared_connectors_specs.rb
Normal file
127
devops-service/spec/support/shared_connectors_specs.rb
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
RSpec.shared_examples 'mongo connector' do |options|
|
||||||
|
model_name = options.fetch(:model_name)
|
||||||
|
factory_name = options[:factory_name] || model_name
|
||||||
|
commands = options.fetch(:only)
|
||||||
|
|
||||||
|
if commands.include?(:insert)
|
||||||
|
insert_method_name = "#{model_name}_insert"
|
||||||
|
|
||||||
|
describe "##{insert_method_name}" do
|
||||||
|
let(:model) { build(factory_name) }
|
||||||
|
subject { @connector.send(insert_method_name, model) }
|
||||||
|
|
||||||
|
before { allow(model).to receive(:validate!).and_return(true) }
|
||||||
|
after { @tester_connector.cleanup }
|
||||||
|
|
||||||
|
it 'inserts new record' do
|
||||||
|
expect {subject}.to change {@tester_connector.list.size}.from(0).to(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'validates inserted record' do
|
||||||
|
expect(model).to receive(:validate!)
|
||||||
|
subject
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't insert nonvalid records" do
|
||||||
|
allow(model).to receive(:validate!) { raise InvalidRecord.new('') }
|
||||||
|
expect {subject}.to raise_error(InvalidRecord)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'sets created_at of record' do
|
||||||
|
expect(model.created_at).to be nil
|
||||||
|
subject
|
||||||
|
expect(@tester_connector.list.first['created_at']).not_to be nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'raises error if record with such id already exists' do
|
||||||
|
@tester_connector.create(id: model.id)
|
||||||
|
expect {subject}.to raise_error(InvalidRecord)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if commands.include?(:list)
|
||||||
|
list_method_name = "#{model_name.to_s.pluralize}"
|
||||||
|
|
||||||
|
describe "##{list_method_name}" do
|
||||||
|
subject { @connector.send(list_method_name) }
|
||||||
|
|
||||||
|
it 'should be empty if collection is empty' do
|
||||||
|
expect(subject).to eq []
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns array of #{model_name.to_s.pluralize} if collection isn't empty" do
|
||||||
|
@tester_connector.create_list(2) do
|
||||||
|
expect(subject).to be_an_array_of(model_class).and have_size(2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if commands.include?(:show)
|
||||||
|
show_method_name = model_name
|
||||||
|
|
||||||
|
describe "##{show_method_name}" do
|
||||||
|
subject { @connector.send(show_method_name, 'foo') }
|
||||||
|
|
||||||
|
it 'raises RecordNotFound when there is no such record' do
|
||||||
|
expect { subject }.to raise_error(RecordNotFound)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns record if was found' do
|
||||||
|
@tester_connector.create(build(factory_name, id: 'foo').to_mongo_hash) do
|
||||||
|
expect(subject).to be_an_instance_of(model_class)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if commands.include?(:update)
|
||||||
|
update_method_name = "#{model_name}_update"
|
||||||
|
field_to_update = options.fetch(:field_to_update).to_s
|
||||||
|
|
||||||
|
describe "##{update_method_name}" do
|
||||||
|
let(:model) { build(model_name, field_to_update => 'new_value') }
|
||||||
|
let(:insert_model_to_update) { @tester_connector.create(attributes_for(factory_name)) }
|
||||||
|
subject { @connector.send(update_method_name, model) }
|
||||||
|
before { allow(model).to receive(:validate!).and_return(true) }
|
||||||
|
after { @tester_connector.cleanup }
|
||||||
|
|
||||||
|
it 'validates updated record' do
|
||||||
|
insert_model_to_update
|
||||||
|
expect(model).to receive(:validate!)
|
||||||
|
subject
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'updates record' do
|
||||||
|
insert_model_to_update
|
||||||
|
subject
|
||||||
|
updated_value = @tester_connector.list.first[field_to_update]
|
||||||
|
expect(updated_value).to eq 'new_value'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'raises RecordNotFound if there is no such record' do
|
||||||
|
expect{ subject }.to raise_error(RecordNotFound)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if commands.include?(:delete)
|
||||||
|
delete_method_name = "#{model_name}_delete"
|
||||||
|
describe "##{delete_method_name}" do
|
||||||
|
let(:model) { build(factory_name) }
|
||||||
|
let(:insert_model_to_delete) { @tester_connector.create(model.to_mongo_hash) }
|
||||||
|
subject { @connector.send(delete_method_name, model.id) }
|
||||||
|
|
||||||
|
it 'deletes record' do
|
||||||
|
insert_model_to_delete
|
||||||
|
expect {subject}.to change {@tester_connector.list.empty?}.to(true)
|
||||||
|
@tester_connector.cleanup
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'raises RecordNotFound if there is no such record' do
|
||||||
|
expect { subject }.to raise_error(RecordNotFound)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -103,10 +103,9 @@ RSpec.shared_examples 'deploy env' do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#create_role' do
|
describe '#create_role', stub_logger: true do
|
||||||
subject { env.create_role('project_name') }
|
subject { env.create_role('project_name') }
|
||||||
before do
|
before do
|
||||||
stub_loggers
|
|
||||||
allow(env).to receive_message_chain('knife_instance.role_name') { 'role_name' }
|
allow(env).to receive_message_chain('knife_instance.role_name') { 'role_name' }
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -153,7 +152,7 @@ RSpec.shared_examples 'deploy env' do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#rename' do
|
describe '#rename', stub_logger: true do
|
||||||
subject { env.rename('project_id', 'new_name') }
|
subject { env.rename('project_id', 'new_name') }
|
||||||
let(:old_role_name) {'project_id_name'}
|
let(:old_role_name) {'project_id_name'}
|
||||||
let(:new_role_name) {'project_id_new_name'}
|
let(:new_role_name) {'project_id_new_name'}
|
||||||
@ -161,7 +160,6 @@ RSpec.shared_examples 'deploy env' do
|
|||||||
let(:suggested_new_roles) {["role[#{new_role_name}]"]}
|
let(:suggested_new_roles) {["role[#{new_role_name}]"]}
|
||||||
|
|
||||||
before do
|
before do
|
||||||
stub_loggers
|
|
||||||
# simulate correct start conditions
|
# simulate correct start conditions
|
||||||
env.run_list = suggested_old_roles
|
env.run_list = suggested_old_roles
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,9 @@ RSpec.shared_examples 'field type validation' do |field, *properties|
|
|||||||
|
|
||||||
describe field do
|
describe field do
|
||||||
it 'should not be nil' do
|
it 'should not be nil' do
|
||||||
expect(build(validated_model_name, field => nil)).not_to be_valid
|
model = build(validated_model_name)
|
||||||
|
model.send("#{field}=", nil)
|
||||||
|
expect(model).not_to be_valid
|
||||||
end if properties.include?(:not_nil)
|
end if properties.include?(:not_nil)
|
||||||
|
|
||||||
it 'may be nil' do
|
it 'may be nil' do
|
||||||
@ -37,7 +39,8 @@ RSpec.shared_examples 'field type validation' do |field, *properties|
|
|||||||
end if properties.include?(:maybe_empty_array)
|
end if properties.include?(:maybe_empty_array)
|
||||||
|
|
||||||
it 'should contain only word symbols' do
|
it 'should contain only word symbols' do
|
||||||
expect(build(validated_model_name, field => 'asd-asd')).not_to be_valid
|
expect(build(validated_model_name, field => '!')).not_to be_valid
|
||||||
|
expect(build(validated_model_name, field => '/')).not_to be_valid
|
||||||
end if properties.include?(:only_word_symbols)
|
end if properties.include?(:only_word_symbols)
|
||||||
|
|
||||||
it 'should contain elements like role[asd] or recipe[asd]' do
|
it 'should contain elements like role[asd] or recipe[asd]' do
|
||||||
@ -99,9 +102,12 @@ RSpec.shared_examples 'field type validation' do |field, *properties|
|
|||||||
}.not_to raise_error
|
}.not_to raise_error
|
||||||
end if properties.include?(:maybe_empty_array)
|
end if properties.include?(:maybe_empty_array)
|
||||||
|
|
||||||
it 'should contain only word symbols' do
|
it 'should contain only symbols in [a-zA-Z0-9_-]' do
|
||||||
expect{
|
expect{
|
||||||
build(validated_model_name, field => 'asd-asd').send(field_validation_method)
|
build(validated_model_name, field => '!').send(field_validation_method)
|
||||||
|
}.to raise_error InvalidRecord
|
||||||
|
expect{
|
||||||
|
build(validated_model_name, field => '/').send(field_validation_method)
|
||||||
}.to raise_error InvalidRecord
|
}.to raise_error InvalidRecord
|
||||||
end if properties.include?(:only_word_symbols)
|
end if properties.include?(:only_word_symbols)
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,35 @@
|
|||||||
require 'core/devops-application'
|
require 'yaml'
|
||||||
|
|
||||||
module SpecSupport
|
module SpecSupport
|
||||||
BLANK_FILE = File.join(Devops::Application.root, 'spec/support/blank_file')
|
ROOT = File.join(__dir__, '../../')
|
||||||
|
BLANK_FILE = File.join(ROOT, 'spec/support/blank_file')
|
||||||
|
|
||||||
def stub_loggers
|
def self.db_params
|
||||||
allow(DevopsLogger).to receive_message_chain('logger.debug')
|
@db ||= begin
|
||||||
allow(DevopsLogger).to receive_message_chain('logger.info')
|
conf = config['mongo']
|
||||||
allow(DevopsLogger).to receive_message_chain('logger.error')
|
db_name = conf.fetch(:db)
|
||||||
|
[db_name, conf[:host], conf[:port], conf[:user], conf[:password]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.db
|
||||||
|
unless @db
|
||||||
|
require 'mongo'
|
||||||
|
db_name, host, port, user, password = db_params
|
||||||
|
@db = MongoClient.new(host, port).db(db_name)
|
||||||
|
@db.authenticate(user, password) unless user.nil? or password.nil?
|
||||||
|
end
|
||||||
|
@db
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.config
|
||||||
|
@config ||= begin
|
||||||
|
config_file = ENV['RSPEC_CONFIG_PATH'] || File.join(ROOT, 'spec/support/config.yml')
|
||||||
|
if File.exists?(config_file)
|
||||||
|
YAML.load_file(config_file)
|
||||||
|
else
|
||||||
|
raise "There is no config file: '#{config_file}'"
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
Loading…
Reference in New Issue
Block a user