Merge branch 'features' of http://git.stu.neva.ru/cloudtechlab/devops-service into features
This commit is contained in:
commit
2f0f753a03
@ -10,7 +10,7 @@ gem "sinatra-websocket"#, "~>0.3.0"
|
||||
gem "fog", "~>1.20"
|
||||
gem "mixlib-shellout"
|
||||
gem "chef", ">=12"
|
||||
gem "mongo"
|
||||
gem "mongo", '1.12.3'
|
||||
gem "bson_ext"
|
||||
gem "multi_json", "1.7.8"
|
||||
gem "sidekiq", "3.2.6"
|
||||
|
||||
@ -344,7 +344,7 @@ DEPENDENCIES
|
||||
httpclient
|
||||
mime-types (~> 1.25.1)
|
||||
mixlib-shellout
|
||||
mongo
|
||||
mongo (= 1.12.3)
|
||||
multi_json (= 1.7.8)
|
||||
rack (= 1.5.2)
|
||||
rack-accept-media-types
|
||||
|
||||
@ -20,23 +20,24 @@ module Connectors
|
||||
f = collection.find('type' => 'image', 'provider' => provider).to_a.first
|
||||
if f.nil?
|
||||
collection.insert('type' => 'image', 'provider' => provider, 'images' => images)
|
||||
return images
|
||||
images
|
||||
else
|
||||
f['images'] |= images
|
||||
collection.update({'_id' => f['_id']}, f)
|
||||
return f['images']
|
||||
f['images']
|
||||
end
|
||||
end
|
||||
|
||||
def delete_available_images images, provider
|
||||
return unless images.is_a?(Array)
|
||||
f = collection.find('type' => 'image', 'provider' => provider).to_a.first
|
||||
unless f.nil?
|
||||
f['images'] -= images
|
||||
collection.update({'_id' => f['_id']}, f)
|
||||
return f['images']
|
||||
end
|
||||
filter = collection.find('type' => 'image', 'provider' => provider).to_a.first
|
||||
if filter
|
||||
filter['images'] -= images
|
||||
collection.update({'_id' => filter['_id']}, filter)
|
||||
filter['images']
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -14,16 +14,10 @@ module Connectors
|
||||
end
|
||||
|
||||
def update(record)
|
||||
begin
|
||||
record.validate!
|
||||
collection.update({"_id" => record.id}, record.to_mongo_hash)
|
||||
r = collection.update({"_id" => record.id}, record.to_mongo_hash)
|
||||
raise RecordNotFound.new("'#{record.id}' not found") if r['n'] == 0
|
||||
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
|
||||
|
||||
@ -2,9 +2,7 @@ module Connectors
|
||||
class Project < Base
|
||||
include Helpers::InsertCommand,
|
||||
Helpers::ShowCommand,
|
||||
# Helpers::ListCommand,
|
||||
Helpers::DeleteCommand
|
||||
# Helpers::UpdateCommand
|
||||
|
||||
|
||||
def initialize(db)
|
||||
@ -73,7 +71,7 @@ module Connectors
|
||||
res.each do |ar|
|
||||
r[ar['_id']] = ar['envs']
|
||||
end
|
||||
return r
|
||||
r
|
||||
end
|
||||
|
||||
def projects_by_image(image)
|
||||
@ -98,10 +96,9 @@ module Connectors
|
||||
project
|
||||
end
|
||||
|
||||
def projects_and_deploy_envs_by_field field, value
|
||||
q = {}
|
||||
q[field] = value
|
||||
# {find all projects with deploy_envs with field=value}, {return deploy_envs with field=value}
|
||||
def projects_and_deploy_envs_by_field field, value
|
||||
q = {field => value}
|
||||
list( {'deploy_envs' => {'$elemMatch' => q}}, {:fields => {'deploy_envs' => {'$elemMatch' => q}}} )
|
||||
end
|
||||
|
||||
@ -114,12 +111,12 @@ module Connectors
|
||||
end
|
||||
|
||||
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})
|
||||
end
|
||||
|
||||
def set_project_run_list(project_id, env, run_list)
|
||||
Helpers::RunList.new(run_list).validate!
|
||||
def set_project_run_list(project_id, run_list)
|
||||
::Validators::Helpers::RunList.new(run_list).validate!
|
||||
@collection.update({"_id" => project_id}, {"$set" => {run_list: run_list}})
|
||||
end
|
||||
|
||||
@ -128,17 +125,16 @@ module Connectors
|
||||
end
|
||||
|
||||
def remove_deploy_env_from_project id, env
|
||||
raise ArgumentError unless env.is_a?(String)
|
||||
@collection.update({"_id" => id}, {'$pull' => {deploy_envs: {identifier: env}} })
|
||||
end
|
||||
|
||||
def project_update_field id, field, value
|
||||
obj = {}
|
||||
obj[field] = value
|
||||
obj = {field => value}
|
||||
@collection.update({"_id" => id}, {'$set' => obj })
|
||||
end
|
||||
|
||||
def project_update id, params
|
||||
#raise InvalidRecord.new("You can not change project name for '#{id}'.") if params["name"]
|
||||
keys = %w(run_list description)
|
||||
params.delete_if{|k,v| !keys.include?(k)}
|
||||
@collection.update({"_id" => id}, {'$set' => params })
|
||||
|
||||
@ -11,13 +11,12 @@ module Devops
|
||||
module Model
|
||||
class CloudDeployEnv < DeployEnvBase
|
||||
|
||||
# attr_accessor :flavor, :image, :subnets, :groups, :stack_template
|
||||
attr_accessor :flavor, :image, :subnets, :groups, :stack_template
|
||||
|
||||
set_validators ::Validators::DeployEnv::Flavor,
|
||||
::Validators::DeployEnv::Image,
|
||||
::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], order: 2
|
||||
|
||||
@ -23,16 +23,27 @@ module Devops
|
||||
|
||||
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"
|
||||
|
||||
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,
|
||||
::Validators::DeployEnv::DeployEnvs
|
||||
|
||||
|
||||
def self.fields
|
||||
["deploy_envs", "type", "description"]
|
||||
end
|
||||
@ -70,6 +81,9 @@ module Devops
|
||||
Project.create_roles_response(res)
|
||||
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
|
||||
return if user.nil?
|
||||
new_users = ( user.is_a?(Array) ? user : [ user ] )
|
||||
@ -202,7 +216,8 @@ module Devops
|
||||
end
|
||||
|
||||
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
|
||||
else
|
||||
info = ""
|
||||
|
||||
@ -18,8 +18,8 @@ module Devops
|
||||
|
||||
set_field_validators :id, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::NotEmpty,]
|
||||
::Validators::FieldValidator::Name
|
||||
::Validators::FieldValidator::NotEmpty,
|
||||
::Validators::FieldValidator::Name]
|
||||
|
||||
set_field_validators :provider, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
require_relative "stack_template_base"
|
||||
require_relative "stack_template_openstack"
|
||||
require_relative "stack_template_ec2"
|
||||
require 'providers/openstack'
|
||||
require 'providers/ec2'
|
||||
|
||||
module Devops
|
||||
module Model
|
||||
|
||||
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
|
||||
factory :key, class: Devops::Model::Key do
|
||||
id 'user_key'
|
||||
path SpecSupport::BLANK_FILE
|
||||
scope 'user'
|
||||
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
|
||||
status 'completed'
|
||||
|
||||
initialize_with {
|
||||
new(attributes.stringify_keys)
|
||||
}
|
||||
initialize_with { new(attributes.stringify_keys) }
|
||||
end
|
||||
end
|
||||
@ -1,19 +1,9 @@
|
||||
require 'db/mongo/models/deploy_env/deploy_env_ec2'
|
||||
require_relative '../shared_models_context'
|
||||
|
||||
RSpec.describe Devops::Model::DeployEnvEc2, type: :model do
|
||||
let(:env) { build(:deploy_env_ec2) }
|
||||
|
||||
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
|
||||
include_context 'stubbed calls to connector in env validators'
|
||||
|
||||
it_behaves_like 'deploy env'
|
||||
it_behaves_like 'cloud deploy env'
|
||||
|
||||
@ -1,19 +1,9 @@
|
||||
require 'db/mongo/models/deploy_env/deploy_env_openstack'
|
||||
require_relative '../shared_models_context'
|
||||
|
||||
RSpec.describe Devops::Model::DeployEnvOpenstack, type: :model do
|
||||
let(:env) { build(:deploy_env_openstack) }
|
||||
|
||||
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
|
||||
include_context 'stubbed calls to connector in env validators'
|
||||
|
||||
it_behaves_like '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', :reserved_by, :not_nil, :maybe_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, :run_list
|
||||
include_examples 'field type validation', :run_list, :not_nil, :maybe_empty_array, :run_list
|
||||
end
|
||||
|
||||
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__), "..")
|
||||
$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 }
|
||||
|
||||
# Factory girl configuration
|
||||
@ -21,6 +25,10 @@ FactoryGirl.find_definitions
|
||||
RSpec.configure do |config|
|
||||
config.include FactoryGirl::Syntax::Methods
|
||||
|
||||
config.after(:all) do
|
||||
$stdout = original_stdout
|
||||
end
|
||||
|
||||
# rspec-expectations config goes here. You can use an alternate
|
||||
# assertion/expectation library such as wrong or the stdlib/minitest
|
||||
# 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
|
||||
|
||||
describe '#create_role' do
|
||||
describe '#create_role', stub_logger: true do
|
||||
subject { env.create_role('project_name') }
|
||||
before do
|
||||
stub_loggers
|
||||
allow(env).to receive_message_chain('knife_instance.role_name') { 'role_name' }
|
||||
end
|
||||
|
||||
@ -153,7 +152,7 @@ RSpec.shared_examples 'deploy env' do
|
||||
end
|
||||
end
|
||||
|
||||
describe '#rename' do
|
||||
describe '#rename', stub_logger: true do
|
||||
subject { env.rename('project_id', 'new_name') }
|
||||
let(:old_role_name) {'project_id_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}]"]}
|
||||
|
||||
before do
|
||||
stub_loggers
|
||||
# simulate correct start conditions
|
||||
env.run_list = suggested_old_roles
|
||||
|
||||
|
||||
@ -9,7 +9,9 @@ RSpec.shared_examples 'field type validation' do |field, *properties|
|
||||
|
||||
describe field 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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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
|
||||
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{
|
||||
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
|
||||
end if properties.include?(:only_word_symbols)
|
||||
|
||||
|
||||
@ -1,11 +1,35 @@
|
||||
require 'core/devops-application'
|
||||
require 'yaml'
|
||||
|
||||
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
|
||||
allow(DevopsLogger).to receive_message_chain('logger.debug')
|
||||
allow(DevopsLogger).to receive_message_chain('logger.info')
|
||||
allow(DevopsLogger).to receive_message_chain('logger.error')
|
||||
def self.db_params
|
||||
@db ||= begin
|
||||
conf = config['mongo']
|
||||
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
|
||||
Loading…
Reference in New Issue
Block a user