require 'workers/stack_bootstrap_worker' RSpec.describe StackBootstrapWorker, type: :worker, stubbed_connector: true do let(:stack_attrs) { attributes_for(:stack_ec2).stringify_keys } let(:perform_with_bootstrap) { worker.perform('stack_attributes' => stack_attrs) } let(:perform_without_bootstrap) { worker.perform('stack_attributes' => stack_attrs.merge('without_bootstrap' => true)) } let(:stack_synchronizer) { instance_double(StackSynchronizer, sync: StackSynchronizer::SyncResult.new(0)) } let(:stack_servers_bootstrapper) { instance_double(StackServersBootstrapper, bootstrap: true) } let(:stack_servers_persister) { instance_double(StackServersPersister, persist: {1 => build_list(:server, 2)}) } let(:worker) { described_class.new } before do allow(Provider::ProviderFactory).to receive(:providers).and_return(%w(ec2)) allow(worker).to receive(:update_report) allow(worker).to receive(:stack_synchronizer) { stack_synchronizer } allow(worker).to receive(:stack_servers_bootstrapper) { stack_servers_bootstrapper } allow(worker).to receive(:stack_servers_persister) { stack_servers_persister } allow(stubbed_connector).to receive(:stack_insert) { Devops::Model::StackEc2.new(stack_attrs) } allow(Devops::Model::StackEc2).to receive(:create) end it 'requires "stack_attributes" in options' do expect{ worker.perform({}) }.to raise_error KeyError end it 'updates report about operation' do expect(worker).to receive(:update_report) perform_without_bootstrap end it 'updates report about operation, creates stack and persists stack servers' do allow(worker).to receive(:create_stack).and_call_original expect(worker).to receive(:update_report).ordered expect(worker).to receive(:create_stack).ordered expect(stack_servers_persister).to receive(:persist).ordered perform_without_bootstrap end context 'if without_bootstrap is true' do it "doesn't bootstrap servers" do expect(stack_servers_bootstrapper).not_to receive(:bootstrap) perform_without_bootstrap end it 'returns 0' do expect(perform_without_bootstrap).to eq 0 end end context 'if without_bootstrap is false or not set' do it 'bootstraps servers in order by priorities, separately' do first_servers = build_list(:server, 2) last_servers = build_list(:server, 3) allow(stack_servers_persister).to receive(:persist) { {3 => first_servers, 1 => last_servers} } expect(stack_servers_bootstrapper).to receive(:bootstrap).with(first_servers).ordered expect(stack_servers_bootstrapper).to receive(:bootstrap).with(last_servers).ordered perform_with_bootstrap end context 'when bootstraping servers was successful' do it 'returns 0' do expect(perform_with_bootstrap).to eq 0 end end context 'when a known error occured during servers bootstrap' do before do allow(stack_servers_bootstrapper).to receive(:bootstrap) { raise StackServerBootstrapError } end it 'rollbacks stack and returns 2' do expect_any_instance_of(Devops::Model::StackEc2).to receive(:delete_stack_in_cloud!) expect(stubbed_connector).to receive(:stack_servers_delete) expect(stubbed_connector).to receive(:stack_delete) perform_with_bootstrap end it 'returns 2' do allow(worker).to receive(:rollback_stack!) expect(perform_with_bootstrap).to eq 2 end end context 'when a known error occured during servers deploy' do it "doesn't rollback stack and returns 3" do allow(stack_servers_bootstrapper).to receive(:bootstrap) { raise StackServerDeployError } expect(worker).not_to receive(:rollback_stack!) expect(perform_with_bootstrap).to eq 3 end end context "when a servers bootstrap & deploy haven't been finished due to timeout" do it "doesn't rollback stack and returns 3" do allow(stack_servers_bootstrapper).to receive(:bootstrap) { raise StackServerBootstrapDeployTimeout } expect(worker).not_to receive(:rollback_stack!) expect(perform_with_bootstrap).to eq 4 end end context 'when an unknown error occured during servers bootsrap and deploy' do it 'rollbacks stack and reraises that error' do error = StandardError.new allow(stack_servers_bootstrapper).to receive(:bootstrap) { raise error } allow(worker).to receive(:rollback_stack!) expect(worker).to receive(:rollback_stack!) expect{perform_with_bootstrap}.to raise_error(error) end end end context "when stack creation wasn't successful" do it 'returns 1' do allow(stack_synchronizer).to receive(:sync) { StackSynchronizer::SyncResult.new(5) } expect(perform_without_bootstrap).to eq 1 end end end