Commit a906752d authored by Kamil Trzcinski's avatar Kamil Trzcinski

Merge branch '38464-k8s-apps' into add-ingress-to-cluster-applications

parents fd9be1dd 67e12219
/* eslint-disable class-methods-use-this, object-shorthand, no-unused-vars, no-use-before-define, no-new, max-len, no-restricted-syntax, guard-for-in, no-continue */ /* eslint-disable class-methods-use-this, object-shorthand, no-unused-vars, no-use-before-define, no-new, max-len, no-restricted-syntax, guard-for-in, no-continue */
import _ from 'underscore'; import _ from 'underscore';
import { insertText, getSelectedFragment, nodeMatchesSelector } from './lib/utils/common_utils'; import { insertText, getSelectedFragment, nodeMatchesSelector } from '../lib/utils/common_utils';
import { placeholderImage } from './lazy_loader'; import { placeholderImage } from '../lazy_loader';
const gfmRules = { const gfmRules = {
// The filters referenced in lib/banzai/pipeline/gfm_pipeline.rb convert // The filters referenced in lib/banzai/pipeline/gfm_pipeline.rb convert
...@@ -284,7 +285,7 @@ const gfmRules = { ...@@ -284,7 +285,7 @@ const gfmRules = {
}, },
}; };
class CopyAsGFM { export class CopyAsGFM {
constructor() { constructor() {
$(document).on('copy', '.md, .wiki', (e) => { CopyAsGFM.copyAsGFM(e, CopyAsGFM.transformGFMSelection); }); $(document).on('copy', '.md, .wiki', (e) => { CopyAsGFM.copyAsGFM(e, CopyAsGFM.transformGFMSelection); });
$(document).on('copy', 'pre.code.highlight, .diff-content .line_content', (e) => { CopyAsGFM.copyAsGFM(e, CopyAsGFM.transformCodeSelection); }); $(document).on('copy', 'pre.code.highlight, .diff-content .line_content', (e) => { CopyAsGFM.copyAsGFM(e, CopyAsGFM.transformCodeSelection); });
...@@ -469,7 +470,12 @@ class CopyAsGFM { ...@@ -469,7 +470,12 @@ class CopyAsGFM {
} }
} }
window.gl = window.gl || {}; // Export CopyAsGFM as a global for rspec to access
window.gl.CopyAsGFM = CopyAsGFM; // see /spec/features/copy_as_gfm_spec.rb
if (process.env.NODE_ENV !== 'production') {
window.CopyAsGFM = CopyAsGFM;
}
new CopyAsGFM(); export default function initCopyAsGFM() {
return new CopyAsGFM();
}
import './autosize'; import './autosize';
import './bind_in_out'; import './bind_in_out';
import initCopyAsGFM from './copy_as_gfm';
import './details_behavior'; import './details_behavior';
import installGlEmojiElement from './gl_emoji'; import installGlEmojiElement from './gl_emoji';
import './quick_submit'; import './quick_submit';
...@@ -7,3 +8,4 @@ import './requires_input'; ...@@ -7,3 +8,4 @@ import './requires_input';
import './toggler_behavior'; import './toggler_behavior';
installGlEmojiElement(); installGlEmojiElement();
initCopyAsGFM();
...@@ -163,12 +163,10 @@ export default class Clusters { ...@@ -163,12 +163,10 @@ export default class Clusters {
.map(appId => newApplicationMap[appId].title); .map(appId => newApplicationMap[appId].title);
if (appTitles.length > 0) { if (appTitles.length > 0) {
this.successApplicationContainer.textContent = sprintf(s__('ClusterIntegration|%{appList} was successfully installed on your cluster'), { const text = sprintf(s__('ClusterIntegration|%{appList} was successfully installed on your cluster'), {
appList: appTitles.join(', '), appList: appTitles.join(', '),
}); });
this.successApplicationContainer.classList.remove('hidden'); Flash(text, 'notice', this.successApplicationContainer);
} else {
this.successApplicationContainer.classList.add('hidden');
} }
} }
......
...@@ -66,7 +66,7 @@ export default { ...@@ -66,7 +66,7 @@ export default {
// Avoid the potential for the real-time data to say APPLICATION_INSTALLABLE but // Avoid the potential for the real-time data to say APPLICATION_INSTALLABLE but
// we already made a request to install and are just waiting for the real-time // we already made a request to install and are just waiting for the real-time
// to sync up. // to sync up.
return this.status !== APPLICATION_INSTALLABLE || return (this.status !== APPLICATION_INSTALLABLE && this.status !== APPLICATION_ERROR) ||
this.requestStatus === REQUEST_LOADING || this.requestStatus === REQUEST_LOADING ||
this.requestStatus === REQUEST_SUCCESS; this.requestStatus === REQUEST_SUCCESS;
}, },
......
...@@ -46,7 +46,6 @@ import './commits'; ...@@ -46,7 +46,6 @@ import './commits';
import './compare'; import './compare';
import './compare_autocomplete'; import './compare_autocomplete';
import './confirm_danger_modal'; import './confirm_danger_modal';
import './copy_as_gfm';
import './copy_to_clipboard'; import './copy_to_clipboard';
import Flash, { removeFlashClickListener } from './flash'; import Flash, { removeFlashClickListener } from './flash';
import './gl_dropdown'; import './gl_dropdown';
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import _ from 'underscore'; import _ from 'underscore';
import 'mousetrap'; import 'mousetrap';
import ShortcutsNavigation from './shortcuts_navigation'; import ShortcutsNavigation from './shortcuts_navigation';
import { CopyAsGFM } from './behaviors/copy_as_gfm';
export default class ShortcutsIssuable extends ShortcutsNavigation { export default class ShortcutsIssuable extends ShortcutsNavigation {
constructor(isMergeRequest) { constructor(isMergeRequest) {
...@@ -33,8 +34,8 @@ export default class ShortcutsIssuable extends ShortcutsNavigation { ...@@ -33,8 +34,8 @@ export default class ShortcutsIssuable extends ShortcutsNavigation {
return false; return false;
} }
const el = window.gl.CopyAsGFM.transformGFMSelection(documentFragment.cloneNode(true)); const el = CopyAsGFM.transformGFMSelection(documentFragment.cloneNode(true));
const selected = window.gl.CopyAsGFM.nodeToGFM(el); const selected = CopyAsGFM.nodeToGFM(el);
if (selected.trim() === '') { if (selected.trim() === '') {
return false; return false;
......
...@@ -121,7 +121,7 @@ ...@@ -121,7 +121,7 @@
} }
.disabled-comment { .disabled-comment {
border: none; border: 0;
border-radius: $label-border-radius; border-radius: $label-border-radius;
padding-top: $gl-vert-padding; padding-top: $gl-vert-padding;
padding-bottom: $gl-vert-padding; padding-bottom: $gl-vert-padding;
......
...@@ -11,14 +11,16 @@ module Clusters ...@@ -11,14 +11,16 @@ module Clusters
validates :cluster, presence: true validates :cluster, presence: true
after_initialize :set_initial_status
def self.application_name def self.application_name
self.to_s.demodulize.underscore self.to_s.demodulize.underscore
end end
def set_initial_status def initial_status
self.status = 0 unless cluster&.platform_kubernetes_active? if cluster&.platform_kubernetes_active?
:installable
else
:not_installable
end
end end
def name def name
......
...@@ -4,7 +4,7 @@ module Clusters ...@@ -4,7 +4,7 @@ module Clusters
extend ActiveSupport::Concern extend ActiveSupport::Concern
included do included do
state_machine :status, initial: :installable do state_machine :status, initial: ->(application) { application.initial_status } do
state :not_installable, value: -2 state :not_installable, value: -2
state :errored, value: -1 state :errored, value: -1
state :installable, value: 0 state :installable, value: 0
...@@ -12,20 +12,20 @@ module Clusters ...@@ -12,20 +12,20 @@ module Clusters
state :installing, value: 2 state :installing, value: 2
state :installed, value: 3 state :installed, value: 3
event :make_scheduled do
transition %i(installable errored) => :scheduled
end
event :make_installing do event :make_installing do
transition any - [:installing] => :installing transition %i(scheduled) => :installing
end end
event :make_installed do event :make_installed do
transition any - [:installed] => :installed transition %i(installing) => :installed
end end
event :make_errored do event :make_errored do
transition any - [:errored] => :errored transition any => :errored
end
event :make_scheduled do
transition %i(installable errored) => :scheduled
end end
before_transition any => [:scheduled] do |app_status, _| before_transition any => [:scheduled] do |app_status, _|
......
...@@ -6,7 +6,7 @@ module Clusters ...@@ -6,7 +6,7 @@ module Clusters
case installation_phase case installation_phase
when Gitlab::Kubernetes::Pod::SUCCEEDED when Gitlab::Kubernetes::Pod::SUCCEEDED
finalize_installation on_success
when Gitlab::Kubernetes::Pod::FAILED when Gitlab::Kubernetes::Pod::FAILED
on_failed on_failed
else else
...@@ -18,23 +18,39 @@ module Clusters ...@@ -18,23 +18,39 @@ module Clusters
private private
def on_success
app.make_installed!
ensure
remove_installation_pod
end
def on_failed def on_failed
app.make_errored!(installation_errors || 'Installation silently failed') app.make_errored!(installation_errors || 'Installation silently failed')
finalize_installation ensure
remove_installation_pod
end end
def check_timeout def check_timeout
if Time.now.utc - app.updated_at.to_time.utc > ClusterWaitForAppInstallationWorker::TIMEOUT if timeouted?
begin
app.make_errored!('Installation timeouted') app.make_errored!('Installation timeouted')
finalize_installation ensure
remove_installation_pod
end
else else
ClusterWaitForAppInstallationWorker.perform_in( ClusterWaitForAppInstallationWorker.perform_in(
ClusterWaitForAppInstallationWorker::INTERVAL, app.name, app.id) ClusterWaitForAppInstallationWorker::INTERVAL, app.name, app.id)
end end
end end
def finalize_installation def timeouted?
FinalizeInstallationService.new(app).execute Time.now.utc - app.updated_at.to_time.utc > ClusterWaitForAppInstallationWorker::TIMEOUT
end
def remove_installation_pod
helm_api.delete_installation_pod!(app)
rescue
# no-op
end end
def installation_phase def installation_phase
......
module Clusters
module Applications
class FinalizeInstallationService < BaseHelmService
def execute
helm_api.delete_installation_pod!(app)
app.make_installed! if app.installing?
end
end
end
end
...@@ -14,7 +14,8 @@ ...@@ -14,7 +14,8 @@
help_path: help_page_path('user/project/clusters/index.md', anchor: 'installing-applications') } } help_path: help_page_path('user/project/clusters/index.md', anchor: 'installing-applications') } }
.hidden.js-cluster-application-notice.alert.alert-info.alert-block.append-bottom-10{ role: 'alert' } .js-cluster-application-notice
.flash-container
%section.settings.no-animate.expanded %section.settings.no-animate.expanded
%h4= s_('ClusterIntegration|Enable cluster integration') %h4= s_('ClusterIntegration|Enable cluster integration')
......
...@@ -54,8 +54,6 @@ project_tree: ...@@ -54,8 +54,6 @@ project_tree:
- :auto_devops - :auto_devops
- :triggers - :triggers
- :pipeline_schedules - :pipeline_schedules
- clusters:
- :application_helm
- :services - :services
- :hooks - :hooks
- protected_branches: - protected_branches:
......
...@@ -8,8 +8,6 @@ module Gitlab ...@@ -8,8 +8,6 @@ module Gitlab
triggers: 'Ci::Trigger', triggers: 'Ci::Trigger',
pipeline_schedules: 'Ci::PipelineSchedule', pipeline_schedules: 'Ci::PipelineSchedule',
builds: 'Ci::Build', builds: 'Ci::Build',
clusters: 'Clusters::Cluster',
application_helm: 'Clusters::Applications::Helm',
hooks: 'ProjectHook', hooks: 'ProjectHook',
merge_access_levels: 'ProtectedBranch::MergeAccessLevel', merge_access_levels: 'ProtectedBranch::MergeAccessLevel',
push_access_levels: 'ProtectedBranch::PushAccessLevel', push_access_levels: 'ProtectedBranch::PushAccessLevel',
......
FactoryGirl.define do FactoryGirl.define do
factory :applications_helm, class: Clusters::Applications::Helm do factory :cluster_applications_helm, class: Clusters::Applications::Helm do
trait :cluster do cluster factory: %i(cluster provided_by_gcp)
before(:create) do |app, _|
app.cluster = create(:cluster)
end
end
trait :installable do trait :installable do
cluster
status 0 status 0
end end
trait :scheduled do trait :scheduled do
cluster
status 1 status 1
end end
trait :installing do trait :installing do
cluster
status 2 status 2
end end
trait :installed do trait :installed do
cluster
status 3 status 3
end end
trait :errored do trait :errored do
cluster
status(-1) status(-1)
status_reason 'something went wrong' status_reason 'something went wrong'
end end
......
...@@ -664,7 +664,7 @@ describe 'Copy as GFM', :js do ...@@ -664,7 +664,7 @@ describe 'Copy as GFM', :js do
def html_to_gfm(html, transformer = 'transformGFMSelection', target: nil) def html_to_gfm(html, transformer = 'transformGFMSelection', target: nil)
js = <<-JS.strip_heredoc js = <<-JS.strip_heredoc
(function(html) { (function(html) {
var transformer = window.gl.CopyAsGFM[#{transformer.inspect}]; var transformer = window.CopyAsGFM[#{transformer.inspect}];
var node = document.createElement('div'); var node = document.createElement('div');
$(html).each(function() { node.appendChild(this) }); $(html).each(function() { node.appendChild(this) });
...@@ -678,7 +678,7 @@ describe 'Copy as GFM', :js do ...@@ -678,7 +678,7 @@ describe 'Copy as GFM', :js do
node = transformer(node, target); node = transformer(node, target);
if (!node) return null; if (!node) return null;
return window.gl.CopyAsGFM.nodeToGFM(node); return window.CopyAsGFM.nodeToGFM(node);
})("#{escape_javascript(html)}") })("#{escape_javascript(html)}")
JS JS
page.evaluate_script(js) page.evaluate_script(js)
......
import { CopyAsGFM } from '~/behaviors/copy_as_gfm';
describe('CopyAsGFM', () => {
describe('CopyAsGFM.pasteGFM', () => {
function callPasteGFM() {
const e = {
originalEvent: {
clipboardData: {
getData(mimeType) {
// When GFM code is copied, we put the regular plain text
// on the clipboard as `text/plain`, and the GFM as `text/x-gfm`.
// This emulates the behavior of `getData` with that data.
if (mimeType === 'text/plain') {
return 'code';
}
if (mimeType === 'text/x-gfm') {
return '`code`';
}
return null;
},
},
},
preventDefault() {},
};
CopyAsGFM.pasteGFM(e);
}
it('wraps pasted code when not already in code tags', () => {
spyOn(window.gl.utils, 'insertText').and.callFake((el, textFunc) => {
const insertedText = textFunc('This is code: ', '');
expect(insertedText).toEqual('`code`');
});
callPasteGFM();
});
it('does not wrap pasted code when already in code tags', () => {
spyOn(window.gl.utils, 'insertText').and.callFake((el, textFunc) => {
const insertedText = textFunc('This is code: `', '`');
expect(insertedText).toEqual('code');
});
callPasteGFM();
});
});
});
...@@ -49,7 +49,7 @@ describe('Clusters', () => { ...@@ -49,7 +49,7 @@ describe('Clusters', () => {
helm: { status: APPLICATION_INSTALLABLE, title: 'Helm Tiller' }, helm: { status: APPLICATION_INSTALLABLE, title: 'Helm Tiller' },
}); });
expect(document.querySelector('.js-cluster-application-notice.hidden')).toBeDefined(); expect(document.querySelector('.js-cluster-application-notice .flash-text')).toBeNull();
}); });
it('shows an alert when something gets newly installed', () => { it('shows an alert when something gets newly installed', () => {
...@@ -61,8 +61,8 @@ describe('Clusters', () => { ...@@ -61,8 +61,8 @@ describe('Clusters', () => {
helm: { status: APPLICATION_INSTALLED, title: 'Helm Tiller' }, helm: { status: APPLICATION_INSTALLED, title: 'Helm Tiller' },
}); });
expect(document.querySelector('.js-cluster-application-notice:not(.hidden)')).toBeDefined(); expect(document.querySelector('.js-cluster-application-notice .flash-text')).toBeDefined();
expect(document.querySelector('.js-cluster-application-notice').textContent.trim()).toEqual('Helm Tiller was successfully installed on your cluster'); expect(document.querySelector('.js-cluster-application-notice .flash-text').textContent.trim()).toEqual('Helm Tiller was successfully installed on your cluster');
}); });
it('shows an alert when multiple things gets newly installed', () => { it('shows an alert when multiple things gets newly installed', () => {
...@@ -76,28 +76,8 @@ describe('Clusters', () => { ...@@ -76,28 +76,8 @@ describe('Clusters', () => {
ingress: { status: APPLICATION_INSTALLED, title: 'Ingress' }, ingress: { status: APPLICATION_INSTALLED, title: 'Ingress' },
}); });
expect(document.querySelector('.js-cluster-application-notice:not(.hidden)')).toBeDefined(); expect(document.querySelector('.js-cluster-application-notice .flash-text')).toBeDefined();
expect(document.querySelector('.js-cluster-application-notice').textContent.trim()).toEqual('Helm Tiller, Ingress was successfully installed on your cluster'); expect(document.querySelector('.js-cluster-application-notice .flash-text').textContent.trim()).toEqual('Helm Tiller, Ingress was successfully installed on your cluster');
});
it('hides existing alert when we call again and nothing is newly installed', () => {
const installedState = {
...INITIAL_APP_MAP,
helm: { status: APPLICATION_INSTALLED, title: 'Helm Tiller' },
};
// Show the banner
cluster.checkForNewInstalls({
...INITIAL_APP_MAP,
helm: { status: APPLICATION_INSTALLING, title: 'Helm Tiller' },
}, installedState);
expect(document.querySelector('.js-cluster-application-notice:not(.hidden)')).toBeDefined();
// Banner should go back hidden
cluster.checkForNewInstalls(installedState, installedState);
expect(document.querySelector('.js-cluster-application-notice.hidden')).toBeDefined();
}); });
}); });
......
...@@ -117,7 +117,7 @@ describe('Application Row', () => { ...@@ -117,7 +117,7 @@ describe('Application Row', () => {
expect(vm.installButtonDisabled).toEqual(true); expect(vm.installButtonDisabled).toEqual(true);
}); });
it('has disabled "Install" when APPLICATION_ERROR', () => { it('has enabled "Install" when APPLICATION_ERROR', () => {
vm = mountComponent(ApplicationRow, { vm = mountComponent(ApplicationRow, {
...DEFAULT_APPLICATION_STATE, ...DEFAULT_APPLICATION_STATE,
status: APPLICATION_ERROR, status: APPLICATION_ERROR,
...@@ -125,7 +125,7 @@ describe('Application Row', () => { ...@@ -125,7 +125,7 @@ describe('Application Row', () => {
expect(vm.installButtonLabel).toEqual('Install'); expect(vm.installButtonLabel).toEqual('Install');
expect(vm.installButtonLoading).toEqual(false); expect(vm.installButtonLoading).toEqual(false);
expect(vm.installButtonDisabled).toEqual(true); expect(vm.installButtonDisabled).toEqual(false);
}); });
it('has loading "Install" when REQUEST_LOADING', () => { it('has loading "Install" when REQUEST_LOADING', () => {
......
import '~/copy_as_gfm';
(() => {
describe('gl.CopyAsGFM', () => {
describe('gl.CopyAsGFM.pasteGFM', () => {
function callPasteGFM() {
const e = {
originalEvent: {
clipboardData: {
getData(mimeType) {
// When GFM code is copied, we put the regular plain text
// on the clipboard as `text/plain`, and the GFM as `text/x-gfm`.
// This emulates the behavior of `getData` with that data.
if (mimeType === 'text/plain') {
return 'code';
}
if (mimeType === 'text/x-gfm') {
return '`code`';
}
return null;
},
},
},
preventDefault() {},
};
window.gl.CopyAsGFM.pasteGFM(e);
}
it('wraps pasted code when not already in code tags', () => {
spyOn(window.gl.utils, 'insertText').and.callFake((el, textFunc) => {
const insertedText = textFunc('This is code: ', '');
expect(insertedText).toEqual('`code`');
});
callPasteGFM();
});
it('does not wrap pasted code when already in code tags', () => {
spyOn(window.gl.utils, 'insertText').and.callFake((el, textFunc) => {
const insertedText = textFunc('This is code: `', '`');
expect(insertedText).toEqual('code');
});
callPasteGFM();
});
});
});
})();
import '~/copy_as_gfm'; import initCopyAsGFM from '~/behaviors/copy_as_gfm';
import ShortcutsIssuable from '~/shortcuts_issuable'; import ShortcutsIssuable from '~/shortcuts_issuable';
initCopyAsGFM();
describe('ShortcutsIssuable', () => { describe('ShortcutsIssuable', () => {
const fixtureName = 'merge_requests/diff_comment.html.raw'; const fixtureName = 'merge_requests/diff_comment.html.raw';
preloadFixtures(fixtureName); preloadFixtures(fixtureName);
......
...@@ -147,22 +147,6 @@ deploy_keys: ...@@ -147,22 +147,6 @@ deploy_keys:
- user - user
- deploy_keys_projects - deploy_keys_projects
- projects - projects
clusters:
- application_helm
- cluster_projects
- projects
- user
- provider_gcp
- platform_kubernetes
cluster_projects:
- projects
- clusters
provider_gcp:
- cluster
platform_kubernetes:
- cluster
application_helm:
- cluster
services: services:
- project - project
- service_hook - service_hook
......
...@@ -28,7 +28,7 @@ RSpec.describe Clusters::Applications::Helm, type: :model do ...@@ -28,7 +28,7 @@ RSpec.describe Clusters::Applications::Helm, type: :model do
describe 'status state machine' do describe 'status state machine' do
describe '#make_installing' do describe '#make_installing' do
subject { create(:applications_helm, :scheduled) } subject { create(:cluster_applications_helm, :scheduled) }
it 'is installing' do it 'is installing' do
subject.make_installing! subject.make_installing!
...@@ -38,7 +38,7 @@ RSpec.describe Clusters::Applications::Helm, type: :model do ...@@ -38,7 +38,7 @@ RSpec.describe Clusters::Applications::Helm, type: :model do
end end
describe '#make_installed' do describe '#make_installed' do
subject { create(:applications_helm, :installing) } subject { create(:cluster_applications_helm, :installing) }
it 'is installed' do it 'is installed' do
subject.make_installed subject.make_installed
...@@ -48,7 +48,7 @@ RSpec.describe Clusters::Applications::Helm, type: :model do ...@@ -48,7 +48,7 @@ RSpec.describe Clusters::Applications::Helm, type: :model do
end end
describe '#make_errored' do describe '#make_errored' do
subject { create(:applications_helm, :installing) } subject { create(:cluster_applications_helm, :installing) }
let(:reason) { 'some errors' } let(:reason) { 'some errors' }
it 'is errored' do it 'is errored' do
...@@ -60,7 +60,7 @@ RSpec.describe Clusters::Applications::Helm, type: :model do ...@@ -60,7 +60,7 @@ RSpec.describe Clusters::Applications::Helm, type: :model do
end end
describe '#make_scheduled' do describe '#make_scheduled' do
subject { create(:applications_helm, :installable) } subject { create(:cluster_applications_helm, :installable) }
it 'is scheduled' do it 'is scheduled' do
subject.make_scheduled subject.make_scheduled
...@@ -69,7 +69,7 @@ RSpec.describe Clusters::Applications::Helm, type: :model do ...@@ -69,7 +69,7 @@ RSpec.describe Clusters::Applications::Helm, type: :model do
end end
describe 'when was errored' do describe 'when was errored' do
subject { create(:applications_helm, :errored) } subject { create(:cluster_applications_helm, :errored) }
it 'clears #status_reason' do it 'clears #status_reason' do
expect(subject.status_reason).not_to be_nil expect(subject.status_reason).not_to be_nil
......
...@@ -2,7 +2,7 @@ require 'spec_helper' ...@@ -2,7 +2,7 @@ require 'spec_helper'
describe ClusterApplicationEntity do describe ClusterApplicationEntity do
describe '#as_json' do describe '#as_json' do
let(:application) { build(:applications_helm) } let(:application) { build(:cluster_applications_helm) }
subject { described_class.new(application).as_json } subject { described_class.new(application).as_json }
it 'has name' do it 'has name' do
...@@ -18,7 +18,7 @@ describe ClusterApplicationEntity do ...@@ -18,7 +18,7 @@ describe ClusterApplicationEntity do
end end
context 'when application is errored' do context 'when application is errored' do
let(:application) { build(:applications_helm, :errored) } let(:application) { build(:cluster_applications_helm, :errored) }
it 'has corresponded data' do it 'has corresponded data' do
expect(subject[:status]).to eq(:errored) expect(subject[:status]).to eq(:errored)
......
...@@ -29,8 +29,8 @@ describe ClusterEntity do ...@@ -29,8 +29,8 @@ describe ClusterEntity do
context 'when provider type is user' do context 'when provider type is user' do
let(:cluster) { create(:cluster, provider_type: :user) } let(:cluster) { create(:cluster, provider_type: :user) }
it 'has nil' do it 'has corresponded data' do
expect(subject[:status]).to be_nil expect(subject[:status]).to eq(:created)
expect(subject[:status_reason]).to be_nil expect(subject[:status_reason]).to be_nil
end end
end end
......
...@@ -3,14 +3,14 @@ require 'spec_helper' ...@@ -3,14 +3,14 @@ require 'spec_helper'
describe Clusters::Applications::CheckInstallationProgressService do describe Clusters::Applications::CheckInstallationProgressService do
RESCHEDULE_PHASES = Gitlab::Kubernetes::Pod::PHASES - [Gitlab::Kubernetes::Pod::SUCCEEDED, Gitlab::Kubernetes::Pod::FAILED].freeze RESCHEDULE_PHASES = Gitlab::Kubernetes::Pod::PHASES - [Gitlab::Kubernetes::Pod::SUCCEEDED, Gitlab::Kubernetes::Pod::FAILED].freeze
let(:application) { create(:applications_helm, :installing) } let(:application) { create(:cluster_applications_helm, :installing) }
let(:service) { described_class.new(application) } let(:service) { described_class.new(application) }
let(:phase) { Gitlab::Kubernetes::Pod::UNKNOWN } let(:phase) { Gitlab::Kubernetes::Pod::UNKNOWN }
let(:errors) { nil } let(:errors) { nil }
shared_examples 'a terminated installation' do shared_examples 'a terminated installation' do
it 'finalize the installation' do it 'removes the installation POD' do
expect(service).to receive(:finalize_installation).once expect(service).to receive(:remove_installation_pod).once
service.execute service.execute
end end
...@@ -23,7 +23,7 @@ describe Clusters::Applications::CheckInstallationProgressService do ...@@ -23,7 +23,7 @@ describe Clusters::Applications::CheckInstallationProgressService do
context 'when not timeouted' do context 'when not timeouted' do
it 'reschedule a new check' do it 'reschedule a new check' do
expect(ClusterWaitForAppInstallationWorker).to receive(:perform_in).once expect(ClusterWaitForAppInstallationWorker).to receive(:perform_in).once
expect(service).not_to receive(:finalize_installation) expect(service).not_to receive(:remove_installation_pod)
service.execute service.execute
...@@ -33,7 +33,7 @@ describe Clusters::Applications::CheckInstallationProgressService do ...@@ -33,7 +33,7 @@ describe Clusters::Applications::CheckInstallationProgressService do
end end
context 'when timeouted' do context 'when timeouted' do
let(:application) { create(:applications_helm, :timeouted) } let(:application) { create(:cluster_applications_helm, :timeouted) }
it_behaves_like 'a terminated installation' it_behaves_like 'a terminated installation'
...@@ -53,7 +53,7 @@ describe Clusters::Applications::CheckInstallationProgressService do ...@@ -53,7 +53,7 @@ describe Clusters::Applications::CheckInstallationProgressService do
expect(service).to receive(:installation_phase).once.and_return(phase) expect(service).to receive(:installation_phase).once.and_return(phase)
allow(service).to receive(:installation_errors).and_return(errors) allow(service).to receive(:installation_errors).and_return(errors)
allow(service).to receive(:finalize_installation).and_return(nil) allow(service).to receive(:remove_installation_pod).and_return(nil)
end end
describe '#execute' do describe '#execute' do
...@@ -61,6 +61,15 @@ describe Clusters::Applications::CheckInstallationProgressService do ...@@ -61,6 +61,15 @@ describe Clusters::Applications::CheckInstallationProgressService do
let(:phase) { Gitlab::Kubernetes::Pod::SUCCEEDED } let(:phase) { Gitlab::Kubernetes::Pod::SUCCEEDED }
it_behaves_like 'a terminated installation' it_behaves_like 'a terminated installation'
it 'make the application installed' do
expect(ClusterWaitForAppInstallationWorker).not_to receive(:perform_in)
service.execute
expect(application).to be_installed
expect(application.status_reason).to be_nil
end
end end
context 'when installation POD failed' do context 'when installation POD failed' do
......
require 'spec_helper'
describe Clusters::Applications::FinalizeInstallationService do
describe '#execute' do
let(:application) { create(:applications_helm, :installing) }
let(:service) { described_class.new(application) }
before do
expect_any_instance_of(Gitlab::Kubernetes::Helm).to receive(:delete_installation_pod!).with(application)
end
context 'when installation POD succeeded' do
it 'make the application installed' do
service.execute
expect(application).to be_installed
expect(application.status_reason).to be_nil
end
end
context 'when installation POD failed' do
let(:application) { create(:applications_helm, :errored) }
it 'make the application errored' do
service.execute
expect(application).to be_errored
expect(application.status_reason).not_to be_nil
end
end
end
end
...@@ -2,16 +2,22 @@ require 'spec_helper' ...@@ -2,16 +2,22 @@ require 'spec_helper'
describe Clusters::Applications::InstallService do describe Clusters::Applications::InstallService do
describe '#execute' do describe '#execute' do
let(:application) { create(:applications_helm, :scheduled) } let(:application) { create(:cluster_applications_helm, :scheduled) }
let(:service) { described_class.new(application) } let(:service) { described_class.new(application) }
let(:helm_client) { instance_double(Gitlab::Kubernetes::Helm) }
before do
allow(service).to receive(:helm_api).and_return(helm_client)
end
context 'when there are no errors' do context 'when there are no errors' do
before do before do
expect_any_instance_of(Gitlab::Kubernetes::Helm).to receive(:install).with(application) expect(helm_client).to receive(:install).with(application)
allow(ClusterWaitForAppInstallationWorker).to receive(:perform_in).and_return(nil) allow(ClusterWaitForAppInstallationWorker).to receive(:perform_in).and_return(nil)
end end
it 'make the application installing' do it 'make the application installing' do
expect(application.cluster).not_to be_nil
service.execute service.execute
expect(application).to be_installing expect(application).to be_installing
...@@ -27,7 +33,7 @@ describe Clusters::Applications::InstallService do ...@@ -27,7 +33,7 @@ describe Clusters::Applications::InstallService do
context 'when k8s cluster communication fails' do context 'when k8s cluster communication fails' do
before do before do
error = KubeException.new(500, 'system failure', nil) error = KubeException.new(500, 'system failure', nil)
expect_any_instance_of(Gitlab::Kubernetes::Helm).to receive(:install).with(application).and_raise(error) expect(helm_client).to receive(:install).with(application).and_raise(error)
end end
it 'make the application errored' do it 'make the application errored' do
...@@ -39,11 +45,11 @@ describe Clusters::Applications::InstallService do ...@@ -39,11 +45,11 @@ describe Clusters::Applications::InstallService do
end end
context 'when application cannot be persisted' do context 'when application cannot be persisted' do
let(:application) { build(:applications_helm, :scheduled) } let(:application) { build(:cluster_applications_helm, :scheduled) }
it 'make the application errored' do it 'make the application errored' do
expect(application).to receive(:make_installing!).once.and_raise(ActiveRecord::RecordInvalid) expect(application).to receive(:make_installing!).once.and_raise(ActiveRecord::RecordInvalid)
expect_any_instance_of(Gitlab::Kubernetes::Helm).not_to receive(:install) expect(helm_client).not_to receive(:install)
service.execute service.execute
......
...@@ -32,7 +32,7 @@ describe Clusters::Applications::ScheduleInstallationService do ...@@ -32,7 +32,7 @@ describe Clusters::Applications::ScheduleInstallationService do
end end
context 'when installation is already in progress' do context 'when installation is already in progress' do
let(:application) { create(:applications_helm, :installing) } let(:application) { create(:cluster_applications_helm, :installing) }
let(:cluster) { application.cluster } let(:cluster) { application.cluster }
it_behaves_like 'a failing service' it_behaves_like 'a failing service'
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment