require 'lib/executors/stack_executor' class Devops::Executor::StackExecutor RSpec.describe self, type: :executor, stubbed_connector: true, stubbed_logger: true do let(:out) { double('out', puts: nil, flush: nil) } let(:stack) { build(:stack) } let(:executor_without_stack) { described_class.new(out: out) } let(:executor_with_stack) { described_class.new(out: out, stack: stack) } let(:new_servers_by_priorities) { { 0 => [{id: 1}], 2 => [{id: 2}] } } let(:just_persisted_by_priority) { { 0 => [double('info 1', id: 1)], 2 => [double('info 2', id: 2)] } } let(:fetcher) { instance_double(StackServersFetcher, new_servers_by_priorities: new_servers_by_priorities, stale_servers: build_list(:server, 2), fetch: nil ) } before do allow(executor_with_stack).to receive(:fetcher) { fetcher } end describe '#wait_till_stack_is_created' do let(:waiter) { instance_double(StackCreationWaiter, wait: double("creation_result", ok?: true)) } before do allow(executor_with_stack).to receive(:waiter) { waiter } allow(stack).to receive(:unlock_persisting!) end it 'waites till stack is created, then fetches stack servers and unlocks stack persisting' do expect(waiter).to receive(:wait).ordered expect(stack).to receive(:unlock_persisting!).ordered executor_with_stack.wait_till_stack_is_created end it "return true if syncer returns ok" do expect(executor_with_stack.wait_till_stack_is_created).to be true end it "return false if syncer returns not ok" do allow(waiter).to receive(:wait) { double("creation_result", ok?: false, reason: '') } expect(executor_with_stack.wait_till_stack_is_created).to be false end end describe '#create_stack' do before { expect(stubbed_connector).to receive(:stack_insert) } it 'initiate creation in cloud and persists stack' do expect(Devops::Model::StackFactory).to receive(:create).with('ec2', instance_of(Hash), out) executor_with_stack.create_stack({'provider' => 'ec2'}) end it 'locks persisting on create' do expect(Devops::Model::StackFactory).to receive(:create) do |_, params| expect(params).to include('persisting_is_locked' => true) end executor_with_stack.create_stack({'provider' => 'ec2'}) end end describe '#persist_new_servers' do let(:persister) { instance_double(StackServersPersister, persist: build(:server)) } before do allow(executor_with_stack).to receive(:persister) { persister } allow(stack).to receive(:lock_persisting!) allow(stack).to receive(:unlock_persisting!) allow(stubbed_connector).to receive(:stack) { stack } end it 'calls StackServersPersister#persist for each server' do expect(persister).to receive(:persist).exactly(2).times executor_with_stack.persist_new_servers end it 'locks persisting of a stack before start and unlocks after finish' do expect(stack).to receive(:lock_persisting!).ordered expect(persister).to receive(:persist).ordered expect(stack).to receive(:unlock_persisting!).ordered executor_with_stack.persist_new_servers end it 'unlocks persisting even in case of failures' do allow(persister).to receive(:persist) { raise } expect(stack).to receive(:unlock_persisting!) expect { executor_with_stack.persist_new_servers }.to raise_error StandardError end end describe '#bootstrap_just_persisted' do it 'calls PrioritizedGroupsBootstrapper#bootstrap_servers_by_priority' do result = double('bootstrap_result') allow(executor_with_stack).to receive(:just_persisted_by_priority) { just_persisted_by_priority } allow_any_instance_of(PrioritizedGroupsBootstrapper).to receive(:bootstrap_servers_by_priority) { result } expect_any_instance_of(PrioritizedGroupsBootstrapper).to receive(:bootstrap_servers_by_priority) expect(executor_with_stack.bootstrap_just_persisted(1000)).to eq result end end describe '#delete_stale_servers' do it 'builds server executor per stale server and properly delete them' do executor1 = instance_double(Devops::Executor::ServerExecutor, delete_server: nil) executor2 = instance_double(Devops::Executor::ServerExecutor, delete_server: nil) allow(Devops::Executor::ServerExecutor).to receive(:new).and_return(executor1, executor2) expect(executor1).to receive(:delete_server).ordered expect(executor2).to receive(:delete_server).ordered executor_with_stack.delete_stale_servers end end describe '#delete_stack', stubbed_connector: true do it 'deletes stack from cloud, then deletes stack servers, and then deletes stack itself' do allow(stubbed_connector).to receive(:stack_servers) { [build(:server, id: 'i-persisted')] } expect(stack).to receive(:delete_stack_in_cloud!).ordered expect(stubbed_connector).to receive(:stack_servers).ordered expect(stubbed_connector).to receive(:stack_delete).ordered executor = instance_double(Devops::Executor::ServerExecutor, delete_server: nil) allow(Devops::Executor::ServerExecutor).to receive(:new) { executor } expect(executor).to receive(:delete_server) executor_with_stack.delete_stack end end end end