specs for several connectors

This commit is contained in:
Anton Chuchkalov 2015-11-20 18:31:54 +03:00
parent e23f78caeb
commit b65dca60a9
31 changed files with 909 additions and 66 deletions

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 })

View File

@ -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

View File

@ -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

View 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

View 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

View 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

View 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

View 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

View File

@ -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

View 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

View File

@ -0,0 +1,6 @@
require_relative 'base'
module TesterConnector
class Filter < Base
end
end

View File

@ -0,0 +1,6 @@
require_relative 'base'
module TesterConnector
class Image < Base
end
end

View File

@ -0,0 +1,6 @@
require_relative 'base'
module TesterConnector
class Key < Base
end
end

View File

@ -0,0 +1,6 @@
require_relative 'base'
module TesterConnector
class Project < Base
end
end

View File

@ -0,0 +1,6 @@
require_relative 'base'
module TesterConnector
class StackTemplate < Base
end
end

View File

@ -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

View File

@ -0,0 +1,12 @@
require 'db/mongo/models/project'
FactoryGirl.define do
factory :project, class: Devops::Model::Project do
id 'my_project'
deploy_envs {
[build(:deploy_env_ec2)]
}
run_list []
description 'desc'
end
end

View File

@ -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

View File

@ -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'

View File

@ -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'

View File

@ -0,0 +1,49 @@
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.deploy_envs << build(:deploy_env_ec2)
expect(project).not_to be_valid
end
it "is valid when all envs have uniq identifiers" do
project.deploy_envs << build(:deploy_env_ec2, identifier: 'new')
expect(project).to be_valid
end
it "isn't valid when at least one of envs isn't valid" do
project.deploy_envs << build(:deploy_env_ec2, identifier: 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
end
end

View File

@ -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

View File

@ -0,0 +1,13 @@
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

View File

@ -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.

View 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

View 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

View File

@ -2,10 +2,18 @@ require 'core/devops-application'
module SpecSupport
BLANK_FILE = File.join(Devops::Application.root, 'spec/support/blank_file')
TEST_DB = 'devops_test'
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')
end
def self.db
@db ||= begin
require 'mongo'
Mongo::MongoClient.new.db(TEST_DB)
end
end
end