Skip to content
代码片段 群组 项目
提交 f8234d9a 编辑于 作者: João Cunha's avatar João Cunha 提交者: jerasmus
浏览文件

Creates Clusterss::ApplciationsController update endpoint

- Creates new route
- Creates new controller action
- Creates call stack:
  Clusterss::ApplciationsController calls -->
  Clusters::Applications::UpdateService calls -->
  Clusters::Applications::ScheduleUpdateService calls -->
  ClusterUpdateAppWorker calls -->
  Clusters::Applications::PatchService -->
  ClusterWaitForAppInstallationWorker

DRY req params

Adds gcp_cluster:cluster_update_app queue

Schedule_update_service is uneeded

Extract common logic to a parent class (UpdateService will need it)

Introduce new UpdateService

Fix rescue class namespace

Fix RuboCop offenses

Adds BaseService for create and update services

Remove request_handler code duplication

Fixes update command

Move update_command to ApplicationCore so all apps can use it

Adds tests for Knative update_command

Adds specs for PatchService

Raise error if update receives an unistalled app

Adds update_service spec

Fix RuboCop offense

Use subject in favor of go

Adds update endpoint specs for project namespace

Adds update endpoint specs for group namespace
上级 cf1b85dd
No related branches found
No related tags found
无相关合并请求
显示
569 个添加104 个删除
...@@ -3,26 +3,41 @@ ...@@ -3,26 +3,41 @@
class Clusters::ApplicationsController < Clusters::BaseController class Clusters::ApplicationsController < Clusters::BaseController
before_action :cluster before_action :cluster
before_action :authorize_create_cluster!, only: [:create] before_action :authorize_create_cluster!, only: [:create]
before_action :authorize_update_cluster!, only: [:update]
def create def create
Clusters::Applications::CreateService request_handler do
.new(@cluster, current_user, create_cluster_application_params) Clusters::Applications::CreateService
.execute(request) .new(@cluster, current_user, cluster_application_params)
.execute(request)
end
end
def update
request_handler do
Clusters::Applications::UpdateService
.new(@cluster, current_user, cluster_application_params)
.execute(request)
end
end
private
def request_handler
yield
head :no_content head :no_content
rescue Clusters::Applications::CreateService::InvalidApplicationError rescue Clusters::Applications::BaseService::InvalidApplicationError
render_404 render_404
rescue StandardError rescue StandardError
head :bad_request head :bad_request
end end
private
def cluster def cluster
@cluster ||= clusterable.clusters.find(params[:id]) || render_404 @cluster ||= clusterable.clusters.find(params[:id]) || render_404
end end
def create_cluster_application_params def cluster_application_params
params.permit(:application, :hostname, :email) params.permit(:application, :hostname, :email)
end end
end end
...@@ -30,6 +30,12 @@ def schedule_status_update ...@@ -30,6 +30,12 @@ def schedule_status_update
# Override if you need extra data synchronized # Override if you need extra data synchronized
# from K8s after installation # from K8s after installation
end end
def update_command
command = install_command
command.version = version
command
end
end end
end end
end end
......
...@@ -46,6 +46,10 @@ def install_command ...@@ -46,6 +46,10 @@ def install_command
@install_command ||= app.install_command @install_command ||= app.install_command
end end
def update_command
@update_command ||= app.update_command
end
def upgrade_command(new_values = "") def upgrade_command(new_values = "")
app.upgrade_command(new_values) app.upgrade_command(new_values)
end end
......
# frozen_string_literal: true
module Clusters
module Applications
class BaseService
InvalidApplicationError = Class.new(StandardError)
attr_reader :cluster, :current_user, :params
def initialize(cluster, user, params = {})
@cluster = cluster
@current_user = user
@params = params.dup
end
def execute(request)
instantiate_application.tap do |application|
if application.has_attribute?(:hostname)
application.hostname = params[:hostname]
end
if application.has_attribute?(:email)
application.email = params[:email]
end
if application.respond_to?(:oauth_application)
application.oauth_application = create_oauth_application(application, request)
end
worker = worker_class(application)
application.make_scheduled!
worker.perform_async(application.name, application.id)
end
end
protected
def worker_class(application)
raise NotImplementedError
end
def builders
raise NotImplementedError
end
def project_builders
raise NotImplementedError
end
def instantiate_application
builder.call(@cluster) || raise(InvalidApplicationError, "invalid application: #{application_name}")
end
def builder
builders[application_name] || raise(InvalidApplicationError, "invalid application: #{application_name}")
end
def application_name
params[:application]
end
def create_oauth_application(application, request)
oauth_application_params = {
name: params[:application],
redirect_uri: application.callback_url,
scopes: 'api read_user openid',
owner: current_user
}
::Applications::CreateService.new(current_user, oauth_application_params).execute(request)
end
end
end
end
...@@ -2,47 +2,11 @@ ...@@ -2,47 +2,11 @@
module Clusters module Clusters
module Applications module Applications
class CreateService class CreateService < Clusters::Applications::BaseService
InvalidApplicationError = Class.new(StandardError)
attr_reader :cluster, :current_user, :params
def initialize(cluster, user, params = {})
@cluster = cluster
@current_user = user
@params = params.dup
end
def execute(request)
create_application.tap do |application|
if application.has_attribute?(:hostname)
application.hostname = params[:hostname]
end
if application.has_attribute?(:email)
application.email = params[:email]
end
if application.respond_to?(:oauth_application)
application.oauth_application = create_oauth_application(application, request)
end
worker = application.updateable? ? ClusterUpgradeAppWorker : ClusterInstallAppWorker
application.make_scheduled!
worker.perform_async(application.name, application.id)
end
end
private private
def create_application def worker_class(application)
builder.call(@cluster) application.updateable? ? ClusterUpgradeAppWorker : ClusterInstallAppWorker
end
def builder
builders[application_name] || raise(InvalidApplicationError, "invalid application: #{application_name}")
end end
def builders def builders
...@@ -65,21 +29,6 @@ def project_builders ...@@ -65,21 +29,6 @@ def project_builders
"knative" => -> (cluster) { cluster.application_knative || cluster.build_application_knative } "knative" => -> (cluster) { cluster.application_knative || cluster.build_application_knative }
} }
end end
def application_name
params[:application]
end
def create_oauth_application(application, request)
oauth_application_params = {
name: params[:application],
redirect_uri: application.callback_url,
scopes: 'api read_user openid',
owner: current_user
}
::Applications::CreateService.new(current_user, oauth_application_params).execute(request)
end
end end
end end
end end
# frozen_string_literal: true
module Clusters
module Applications
class PatchService < BaseHelmService
def execute
return unless app.scheduled?
begin
app.make_updating!
helm_api.update(update_command)
ClusterWaitForAppInstallationWorker.perform_in(
ClusterWaitForAppInstallationWorker::INTERVAL, app.name, app.id)
rescue Kubeclient::HttpError => e
log_error(e)
app.make_update_errored!("Kubernetes error: #{e.error_code}")
rescue StandardError => e
log_error(e)
app.make_update_errored!("Can't start update process.")
end
end
end
end
end
# frozen_string_literal: true
module Clusters
module Applications
class UpdateService < Clusters::Applications::BaseService
private
def worker_class(application)
ClusterUpdateAppWorker
end
def builders
{
"helm" => -> (cluster) { cluster.application_helm },
"ingress" => -> (cluster) { cluster.application_ingress },
"cert_manager" => -> (cluster) { cluster.application_cert_manager }
}.tap do |hash|
hash.merge!(project_builders) if cluster.project_type?
end
end
# These applications will need extra configuration to enable them to work
# with groups of projects
def project_builders
{
"prometheus" => -> (cluster) { cluster.application_prometheus },
"runner" => -> (cluster) { cluster.application_runner },
"jupyter" => -> (cluster) { cluster.application_jupyter },
"knative" => -> (cluster) { cluster.application_knative }
}
end
end
end
end
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
- cronjob:prune_web_hook_logs - cronjob:prune_web_hook_logs
- gcp_cluster:cluster_install_app - gcp_cluster:cluster_install_app
- gcp_cluster:cluster_update_app
- gcp_cluster:cluster_upgrade_app - gcp_cluster:cluster_upgrade_app
- gcp_cluster:cluster_provision - gcp_cluster:cluster_provision
- gcp_cluster:cluster_wait_for_app_installation - gcp_cluster:cluster_wait_for_app_installation
......
# frozen_string_literal: true
class ClusterUpdateAppWorker
include ApplicationWorker
include ClusterQueue
include ClusterApplications
def perform(app_name, app_id)
find_application(app_name, app_id) do |app|
Clusters::Applications::PatchService.new(app).execute
end
end
end
...@@ -101,6 +101,7 @@ ...@@ -101,6 +101,7 @@
member do member do
scope :applications do scope :applications do
post '/:application', to: 'clusters/applications#create', as: :install_applications post '/:application', to: 'clusters/applications#create', as: :install_applications
patch '/:application', to: 'clusters/applications#update', as: :update_applications
end end
get :cluster_status, format: :json get :cluster_status, format: :json
......
...@@ -7,7 +7,8 @@ class InstallCommand ...@@ -7,7 +7,8 @@ class InstallCommand
include BaseCommand include BaseCommand
include ClientCommand include ClientCommand
attr_reader :name, :files, :chart, :version, :repository, :preinstall, :postinstall attr_reader :name, :files, :chart, :repository, :preinstall, :postinstall
attr_accessor :version
def initialize(name:, chart:, files:, rbac:, version: nil, repository: nil, preinstall: nil, postinstall: nil) def initialize(name:, chart:, files:, rbac:, version: nil, repository: nil, preinstall: nil, postinstall: nil)
@name = name @name = name
......
...@@ -9,9 +9,25 @@ def current_application ...@@ -9,9 +9,25 @@ def current_application
Clusters::Cluster::APPLICATIONS[application] Clusters::Cluster::APPLICATIONS[application]
end end
shared_examples 'a secure endpoint' do
it { expect { subject }.to be_allowed_for(:admin) }
it { expect { subject }.to be_allowed_for(:owner).of(group) }
it { expect { subject }.to be_allowed_for(:maintainer).of(group) }
it { expect { subject }.to be_denied_for(:developer).of(group) }
it { expect { subject }.to be_denied_for(:reporter).of(group) }
it { expect { subject }.to be_denied_for(:guest).of(group) }
it { expect { subject }.to be_denied_for(:user) }
it { expect { subject }.to be_denied_for(:external) }
end
let(:cluster) { create(:cluster, :group, :provided_by_gcp) }
let(:group) { cluster.group }
describe 'POST create' do describe 'POST create' do
let(:cluster) { create(:cluster, :group, :provided_by_gcp) } subject do
let(:group) { cluster.group } post :create, params: params.merge(group_id: group)
end
let(:application) { 'helm' } let(:application) { 'helm' }
let(:params) { { application: application, id: cluster.id } } let(:params) { { application: application, id: cluster.id } }
...@@ -26,7 +42,7 @@ def current_application ...@@ -26,7 +42,7 @@ def current_application
it 'schedule an application installation' do it 'schedule an application installation' do
expect(ClusterInstallAppWorker).to receive(:perform_async).with(application, anything).once expect(ClusterInstallAppWorker).to receive(:perform_async).with(application, anything).once
expect { go }.to change { current_application.count } expect { subject }.to change { current_application.count }
expect(response).to have_http_status(:no_content) expect(response).to have_http_status(:no_content)
expect(cluster.application_helm).to be_scheduled expect(cluster.application_helm).to be_scheduled
end end
...@@ -37,7 +53,7 @@ def current_application ...@@ -37,7 +53,7 @@ def current_application
end end
it 'return 404' do it 'return 404' do
expect { go }.not_to change { current_application.count } expect { subject }.not_to change { current_application.count }
expect(response).to have_http_status(:not_found) expect(response).to have_http_status(:not_found)
end end
end end
...@@ -46,9 +62,7 @@ def current_application ...@@ -46,9 +62,7 @@ def current_application
let(:application) { 'unkwnown-app' } let(:application) { 'unkwnown-app' }
it 'return 404' do it 'return 404' do
go is_expected.to have_http_status(:not_found)
expect(response).to have_http_status(:not_found)
end end
end end
...@@ -58,9 +72,7 @@ def current_application ...@@ -58,9 +72,7 @@ def current_application
end end
it 'returns 400' do it 'returns 400' do
go is_expected.to have_http_status(:bad_request)
expect(response).to have_http_status(:bad_request)
end end
end end
end end
...@@ -70,18 +82,66 @@ def current_application ...@@ -70,18 +82,66 @@ def current_application
allow(ClusterInstallAppWorker).to receive(:perform_async) allow(ClusterInstallAppWorker).to receive(:perform_async)
end end
it { expect { go }.to be_allowed_for(:admin) } it_behaves_like 'a secure endpoint'
it { expect { go }.to be_allowed_for(:owner).of(group) }
it { expect { go }.to be_allowed_for(:maintainer).of(group) }
it { expect { go }.to be_denied_for(:developer).of(group) }
it { expect { go }.to be_denied_for(:reporter).of(group) }
it { expect { go }.to be_denied_for(:guest).of(group) }
it { expect { go }.to be_denied_for(:user) }
it { expect { go }.to be_denied_for(:external) }
end end
end
def go describe 'PATCH update' do
post :create, params: params.merge(group_id: group) subject do
patch :update, params: params.merge(group_id: group)
end
let!(:application) { create(:clusters_applications_cert_managers, :installed, cluster: cluster) }
let(:application_name) { application.name }
let(:params) { { application: application_name, id: cluster.id, email: "new-email@example.com" } }
describe 'functionality' do
let(:user) { create(:user) }
before do
group.add_maintainer(user)
sign_in(user)
end
context "when cluster and app exists" do
it "schedules an application update" do
expect(ClusterUpdateAppWorker).to receive(:perform_async).with(application.name, anything).once
is_expected.to have_http_status(:no_content)
expect(cluster.application_cert_manager).to be_scheduled
end
end
context 'when cluster do not exists' do
before do
cluster.destroy!
end
it { is_expected.to have_http_status(:not_found) }
end
context 'when application is unknown' do
let(:application_name) { 'unkwnown-app' }
it { is_expected.to have_http_status(:not_found) }
end
context 'when application is already scheduled' do
before do
application.make_scheduled!
end
it { is_expected.to have_http_status(:bad_request) }
end
end
describe 'security' do
before do
allow(ClusterUpdateAppWorker).to receive(:perform_async)
end
it_behaves_like 'a secure endpoint'
end end
end end
end end
...@@ -9,7 +9,22 @@ def current_application ...@@ -9,7 +9,22 @@ def current_application
Clusters::Cluster::APPLICATIONS[application] Clusters::Cluster::APPLICATIONS[application]
end end
shared_examples 'a secure endpoint' do
it { expect { subject }.to be_allowed_for(:admin) }
it { expect { subject }.to be_allowed_for(:owner).of(project) }
it { expect { subject }.to be_allowed_for(:maintainer).of(project) }
it { expect { subject }.to be_denied_for(:developer).of(project) }
it { expect { subject }.to be_denied_for(:reporter).of(project) }
it { expect { subject }.to be_denied_for(:guest).of(project) }
it { expect { subject }.to be_denied_for(:user) }
it { expect { subject }.to be_denied_for(:external) }
end
describe 'POST create' do describe 'POST create' do
subject do
post :create, params: params.merge(namespace_id: project.namespace, project_id: project)
end
let(:cluster) { create(:cluster, :project, :provided_by_gcp) } let(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:project) { cluster.project } let(:project) { cluster.project }
let(:application) { 'helm' } let(:application) { 'helm' }
...@@ -26,7 +41,7 @@ def current_application ...@@ -26,7 +41,7 @@ def current_application
it 'schedule an application installation' do it 'schedule an application installation' do
expect(ClusterInstallAppWorker).to receive(:perform_async).with(application, anything).once expect(ClusterInstallAppWorker).to receive(:perform_async).with(application, anything).once
expect { go }.to change { current_application.count } expect { subject }.to change { current_application.count }
expect(response).to have_http_status(:no_content) expect(response).to have_http_status(:no_content)
expect(cluster.application_helm).to be_scheduled expect(cluster.application_helm).to be_scheduled
end end
...@@ -37,7 +52,7 @@ def current_application ...@@ -37,7 +52,7 @@ def current_application
end end
it 'return 404' do it 'return 404' do
expect { go }.not_to change { current_application.count } expect { subject }.not_to change { current_application.count }
expect(response).to have_http_status(:not_found) expect(response).to have_http_status(:not_found)
end end
end end
...@@ -46,9 +61,7 @@ def current_application ...@@ -46,9 +61,7 @@ def current_application
let(:application) { 'unkwnown-app' } let(:application) { 'unkwnown-app' }
it 'return 404' do it 'return 404' do
go is_expected.to have_http_status(:not_found)
expect(response).to have_http_status(:not_found)
end end
end end
...@@ -58,9 +71,7 @@ def current_application ...@@ -58,9 +71,7 @@ def current_application
end end
it 'returns 400' do it 'returns 400' do
go is_expected.to have_http_status(:bad_request)
expect(response).to have_http_status(:bad_request)
end end
end end
end end
...@@ -70,18 +81,68 @@ def current_application ...@@ -70,18 +81,68 @@ def current_application
allow(ClusterInstallAppWorker).to receive(:perform_async) allow(ClusterInstallAppWorker).to receive(:perform_async)
end end
it { expect { go }.to be_allowed_for(:admin) } it_behaves_like 'a secure endpoint'
it { expect { go }.to be_allowed_for(:owner).of(project) }
it { expect { go }.to be_allowed_for(:maintainer).of(project) }
it { expect { go }.to be_denied_for(:developer).of(project) }
it { expect { go }.to be_denied_for(:reporter).of(project) }
it { expect { go }.to be_denied_for(:guest).of(project) }
it { expect { go }.to be_denied_for(:user) }
it { expect { go }.to be_denied_for(:external) }
end end
end
def go describe 'PATCH update' do
post :create, params: params.merge(namespace_id: project.namespace, project_id: project) subject do
patch :update, params: params.merge(namespace_id: project.namespace, project_id: project)
end
let(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:project) { cluster.project }
let!(:application) { create(:clusters_applications_knative, :installed, cluster: cluster) }
let(:application_name) { application.name }
let(:params) { { application: application_name, id: cluster.id, hostname: "new.example.com" } }
describe 'functionality' do
let(:user) { create(:user) }
before do
project.add_maintainer(user)
sign_in(user)
end
context "when cluster and app exists" do
it "schedules an application update" do
expect(ClusterUpdateAppWorker).to receive(:perform_async).with(application.name, anything).once
is_expected.to have_http_status(:no_content)
expect(cluster.application_knative).to be_scheduled
end
end
context 'when cluster do not exists' do
before do
cluster.destroy!
end
it { is_expected.to have_http_status(:not_found) }
end
context 'when application is unknown' do
let(:application_name) { 'unkwnown-app' }
it { is_expected.to have_http_status(:not_found) }
end
context 'when application is already scheduled' do
before do
application.make_scheduled!
end
it { is_expected.to have_http_status(:bad_request) }
end
end
describe 'security' do
before do
allow(ClusterUpdateAppWorker).to receive(:perform_async)
end
it_behaves_like 'a secure endpoint'
end end
end end
end end
...@@ -66,9 +66,7 @@ ...@@ -66,9 +66,7 @@
end end
end end
describe '#install_command' do shared_examples 'a command' do
subject { knative.install_command }
it 'should be an instance of Helm::InstallCommand' do it 'should be an instance of Helm::InstallCommand' do
expect(subject).to be_an_instance_of(Gitlab::Kubernetes::Helm::InstallCommand) expect(subject).to be_an_instance_of(Gitlab::Kubernetes::Helm::InstallCommand)
end end
...@@ -76,7 +74,6 @@ ...@@ -76,7 +74,6 @@
it 'should be initialized with knative arguments' do it 'should be initialized with knative arguments' do
expect(subject.name).to eq('knative') expect(subject.name).to eq('knative')
expect(subject.chart).to eq('knative/knative') expect(subject.chart).to eq('knative/knative')
expect(subject.version).to eq('0.2.2')
expect(subject.files).to eq(knative.files) expect(subject.files).to eq(knative.files)
end end
...@@ -98,6 +95,27 @@ ...@@ -98,6 +95,27 @@
end end
end end
describe '#install_command' do
subject { knative.install_command }
it 'should be initialized with latest version' do
expect(subject.version).to eq('0.2.2')
end
it_behaves_like 'a command'
end
describe '#update_command' do
let!(:current_installed_version) { knative.version = '0.1.0' }
subject { knative.update_command }
it 'should be initialized with current version' do
expect(subject.version).to eq(current_installed_version)
end
it_behaves_like 'a command'
end
describe '#files' do describe '#files' do
let(:application) { knative } let(:application) { knative }
let(:values) { subject[:'values.yaml'] } let(:values) { subject[:'values.yaml'] }
......
# frozen_string_literal: true
require 'spec_helper'
describe Clusters::Applications::PatchService do
describe '#execute' do
let(:application) { create(:clusters_applications_knative, :scheduled) }
let!(:update_command) { application.update_command }
let(:service) { described_class.new(application) }
let(:helm_client) { instance_double(Gitlab::Kubernetes::Helm::Api) }
before do
allow(service).to receive(:update_command).and_return(update_command)
allow(service).to receive(:helm_api).and_return(helm_client)
end
context 'when there are no errors' do
before do
expect(helm_client).to receive(:update).with(update_command)
allow(ClusterWaitForAppInstallationWorker).to receive(:perform_in).and_return(nil)
end
it 'make the application updating' do
expect(application.cluster).not_to be_nil
service.execute
expect(application).to be_updating
end
it 'schedule async installation status check' do
expect(ClusterWaitForAppInstallationWorker).to receive(:perform_in).once
service.execute
end
end
context 'when kubernetes cluster communication fails' do
let(:error) { Kubeclient::HttpError.new(500, 'system failure', nil) }
before do
expect(helm_client).to receive(:update).with(update_command).and_raise(error)
end
it 'make the application errored' do
service.execute
expect(application).to be_update_errored
expect(application.status_reason).to match('Kubernetes error: 500')
end
it 'logs errors' do
expect(service.send(:logger)).to receive(:error).with(
{
exception: 'Kubeclient::HttpError',
message: 'system failure',
service: 'Clusters::Applications::PatchService',
app_id: application.id,
project_ids: application.cluster.project_ids,
group_ids: [],
error_code: 500
}
)
expect(Gitlab::Sentry).to receive(:track_acceptable_exception).with(
error,
extra: {
exception: 'Kubeclient::HttpError',
message: 'system failure',
service: 'Clusters::Applications::PatchService',
app_id: application.id,
project_ids: application.cluster.project_ids,
group_ids: [],
error_code: 500
}
)
service.execute
end
end
context 'a non kubernetes error happens' do
let(:application) { create(:clusters_applications_knative, :scheduled) }
let(:error) { StandardError.new('something bad happened') }
before do
expect(application).to receive(:make_updating!).once.and_raise(error)
end
it 'make the application errored' do
expect(helm_client).not_to receive(:update)
service.execute
expect(application).to be_update_errored
expect(application.status_reason).to eq("Can't start update process.")
end
it 'logs errors' do
expect(service.send(:logger)).to receive(:error).with(
{
exception: 'StandardError',
error_code: nil,
message: 'something bad happened',
service: 'Clusters::Applications::PatchService',
app_id: application.id,
project_ids: application.cluster.projects.pluck(:id),
group_ids: []
}
)
expect(Gitlab::Sentry).to receive(:track_acceptable_exception).with(
error,
extra: {
exception: 'StandardError',
error_code: nil,
message: 'something bad happened',
service: 'Clusters::Applications::PatchService',
app_id: application.id,
project_ids: application.cluster.projects.pluck(:id),
group_ids: []
}
)
service.execute
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Clusters::Applications::UpdateService do
include TestRequestHelpers
let(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:user) { create(:user) }
let(:params) { { application: 'knative', hostname: 'udpate.example.com' } }
let(:service) { described_class.new(cluster, user, params) }
subject { service.execute(test_request) }
describe '#execute' do
before do
allow(ClusterUpdateAppWorker).to receive(:perform_async)
end
context 'application is not installed' do
it 'raises Clusters::Applications::BaseService::InvalidApplicationError' do
expect(ClusterUpdateAppWorker).not_to receive(:perform_async)
expect { subject }
.to raise_exception { Clusters::Applications::BaseService::InvalidApplicationError }
.and not_change { Clusters::Applications::Knative.count }
.and not_change { Clusters::Applications::Knative.with_status(:scheduled).count }
end
end
context 'application is installed' do
context 'application is schedulable' do
let!(:application) do
create(:clusters_applications_knative, status: 3, cluster: cluster)
end
it 'updates the application data' do
expect do
subject
end.to change { application.reload.hostname }.to(params[:hostname])
end
it 'makes application scheduled!' do
subject
expect(application.reload).to be_scheduled
end
it 'schedules ClusterUpdateAppWorker' do
expect(ClusterUpdateAppWorker).to receive(:perform_async)
subject
end
end
context 'application is not schedulable' do
let!(:application) do
create(:clusters_applications_knative, status: 4, cluster: cluster)
end
it 'raises StateMachines::InvalidTransition' do
expect(ClusterUpdateAppWorker).not_to receive(:perform_async)
expect { subject }
.to raise_exception { StateMachines::InvalidTransition }
.and not_change { application.reload.hostname }
.and not_change { Clusters::Applications::Knative.with_status(:scheduled).count }
end
end
end
end
end
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册