require 'workers/stack_bootstrap_worker' RSpec.describe StackBootstrapWorker, type: :worker, stubbed_connector: true do let(:out) { double(:out, puts: nil, flush: nil) } let(:file) { 'temp.txt' } 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: 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(stubbed_connector).to receive(:save_report) allow(stubbed_connector).to receive(:stack_insert) 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(worker).to receive(:call).and_yield(out, file) allow(Devops::Model::StackEc2).to receive(:create) { Devops::Model::StackEc2.new(stack_attrs) } end it 'requires "stack_attributes" in options' do expect{ worker.perform({}) }.to raise_error KeyError end it 'saves report about operation' do expect(stubbed_connector).to receive(:save_report).with(instance_of(Devops::Model::Report)) perform_without_bootstrap end it 'saves report about operation, creates stack and persists stack servers' do allow(worker).to receive(:create_stack).and_call_original expect(stubbed_connector).to receive(:save_report).with(instance_of(Devops::Model::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) { 5 } allow(stack_synchronizer).to receive(:reason_from_error_code) { :error } expect(perform_without_bootstrap).to eq 1 end end end