1# frozen_string_literal: true 2 3require 'spec_helper' 4 5RSpec.describe Clusters::Applications::CheckInstallationProgressService, '#execute' do 6 RESCHEDULE_PHASES = Gitlab::Kubernetes::Pod::PHASES - [Gitlab::Kubernetes::Pod::SUCCEEDED, Gitlab::Kubernetes::Pod::FAILED].freeze 7 8 let(:application) { create(:clusters_applications_helm, :installing) } 9 let(:service) { described_class.new(application) } 10 let(:phase) { Gitlab::Kubernetes::Pod::UNKNOWN } 11 let(:errors) { nil } 12 13 shared_examples 'a not yet terminated installation' do |a_phase| 14 let(:phase) { a_phase } 15 16 before do 17 expect(service).to receive(:pod_phase).once.and_return(phase) 18 end 19 20 context "when phase is #{a_phase}" do 21 context 'when not timed_out' do 22 it 'reschedule a new check' do 23 expect(ClusterWaitForAppInstallationWorker).to receive(:perform_in).once 24 expect(service).not_to receive(:remove_installation_pod) 25 26 expect do 27 service.execute 28 29 application.reload 30 end.not_to change(application, :status) 31 32 expect(application.status_reason).to be_nil 33 end 34 end 35 end 36 end 37 38 shared_examples 'error handling' do 39 context 'when installation raises a Kubeclient::HttpError' do 40 let(:cluster) { create(:cluster, :provided_by_user, :project) } 41 let(:logger) { service.send(:logger) } 42 let(:error) { Kubeclient::HttpError.new(401, 'Unauthorized', nil) } 43 44 before do 45 application.update!(cluster: cluster) 46 47 expect(service).to receive(:pod_phase).and_raise(error) 48 end 49 50 include_examples 'logs kubernetes errors' do 51 let(:error_name) { 'Kubeclient::HttpError' } 52 let(:error_message) { 'Unauthorized' } 53 let(:error_code) { 401 } 54 end 55 56 it 'shows the response code from the error' do 57 service.execute 58 59 expect(application).to be_errored.or(be_update_errored) 60 expect(application.status_reason).to eq('Kubernetes error: 401') 61 end 62 end 63 end 64 65 before do 66 allow(service).to receive(:installation_errors).and_return(errors) 67 allow(service).to receive(:remove_installation_pod).and_return(nil) 68 end 69 70 context 'when application is updating' do 71 let(:application) { create(:clusters_applications_helm, :updating) } 72 73 include_examples 'error handling' 74 75 RESCHEDULE_PHASES.each { |phase| it_behaves_like 'a not yet terminated installation', phase } 76 77 context 'when installation POD succeeded' do 78 let(:phase) { Gitlab::Kubernetes::Pod::SUCCEEDED } 79 80 before do 81 expect(service).to receive(:pod_phase).once.and_return(phase) 82 end 83 84 it 'removes the installation POD' do 85 expect(service).to receive(:remove_installation_pod).once 86 87 service.execute 88 end 89 90 it 'make the application installed' do 91 expect(ClusterWaitForAppInstallationWorker).not_to receive(:perform_in) 92 93 service.execute 94 95 expect(application).to be_updated 96 expect(application.status_reason).to be_nil 97 end 98 end 99 100 context 'when installation POD failed' do 101 let(:phase) { Gitlab::Kubernetes::Pod::FAILED } 102 let(:errors) { 'test installation failed' } 103 104 before do 105 expect(service).to receive(:pod_phase).once.and_return(phase) 106 end 107 108 it 'make the application errored' do 109 service.execute 110 111 expect(application).to be_update_errored 112 expect(application.status_reason).to eq('Operation failed. Check pod logs for install-helm for more details.') 113 end 114 end 115 116 context 'when timed out' do 117 let(:application) { create(:clusters_applications_helm, :timed_out, :updating) } 118 119 before do 120 expect(service).to receive(:pod_phase).once.and_return(phase) 121 end 122 123 it 'make the application errored' do 124 expect(ClusterWaitForAppInstallationWorker).not_to receive(:perform_in) 125 126 service.execute 127 128 expect(application).to be_update_errored 129 expect(application.status_reason).to eq('Operation timed out. Check pod logs for install-helm for more details.') 130 end 131 end 132 end 133 134 context 'when application is installing' do 135 include_examples 'error handling' 136 137 RESCHEDULE_PHASES.each { |phase| it_behaves_like 'a not yet terminated installation', phase } 138 139 context 'when installation POD succeeded' do 140 let(:phase) { Gitlab::Kubernetes::Pod::SUCCEEDED } 141 142 before do 143 expect(service).to receive(:pod_phase).once.and_return(phase) 144 end 145 146 it 'removes the installation POD' do 147 expect_next_instance_of(Gitlab::Kubernetes::Helm::API) do |instance| 148 expect(instance).to receive(:delete_pod!).with(kind_of(String)).once 149 end 150 expect(service).to receive(:remove_installation_pod).and_call_original 151 152 service.execute 153 end 154 155 it 'make the application installed' do 156 expect(ClusterWaitForAppInstallationWorker).not_to receive(:perform_in) 157 158 service.execute 159 160 expect(application).to be_installed 161 expect(application.status_reason).to be_nil 162 end 163 164 it 'tracks application install', :snowplow do 165 service.execute 166 167 expect_snowplow_event(category: 'cluster:applications', action: 'cluster_application_helm_installed') 168 end 169 end 170 171 context 'when installation POD failed' do 172 let(:phase) { Gitlab::Kubernetes::Pod::FAILED } 173 let(:errors) { 'test installation failed' } 174 175 before do 176 expect(service).to receive(:pod_phase).once.and_return(phase) 177 end 178 179 it 'make the application errored' do 180 service.execute 181 182 expect(application).to be_errored 183 expect(application.status_reason).to eq('Operation failed. Check pod logs for install-helm for more details.') 184 end 185 end 186 187 context 'when timed out' do 188 let(:application) { create(:clusters_applications_helm, :timed_out) } 189 190 before do 191 expect(service).to receive(:pod_phase).once.and_return(phase) 192 end 193 194 it 'make the application errored' do 195 expect(ClusterWaitForAppInstallationWorker).not_to receive(:perform_in) 196 197 service.execute 198 199 expect(application).to be_errored 200 expect(application.status_reason).to eq('Operation timed out. Check pod logs for install-helm for more details.') 201 end 202 end 203 end 204end 205