diff options
author | Bob Van Landuyt <bob@gitlab.com> | 2019-05-07 07:08:52 +0000 |
---|---|---|
committer | Bob Van Landuyt <bob@gitlab.com> | 2019-05-07 07:08:52 +0000 |
commit | 3371c1cb7102ec557065ea7e92b9f6fff9744bd1 (patch) | |
tree | 8421a6ac36b6318d96573c1325212a332d0aa847 /spec | |
parent | 5925b5bbdb0ffddf4ab8be84b84747a65c2aec3c (diff) | |
parent | f07d445b0c3296b3070221ccd70443fba15ba708 (diff) | |
download | gitlab-ce-3371c1cb7102ec557065ea7e92b9f6fff9744bd1.tar.gz |
Merge branch 'instance_level_clusters' into 'master'
Instance level k8s clusters
See merge request gitlab-org/gitlab-ce!27196
Diffstat (limited to 'spec')
-rw-r--r-- | spec/controllers/admin/clusters/applications_controller_spec.rb | 149 | ||||
-rw-r--r-- | spec/controllers/admin/clusters_controller_spec.rb | 540 | ||||
-rw-r--r-- | spec/controllers/concerns/enforces_admin_authentication_spec.rb | 40 | ||||
-rw-r--r-- | spec/finders/cluster_ancestors_finder_spec.rb | 29 | ||||
-rw-r--r-- | spec/models/clusters/applications/runner_spec.rb | 18 | ||||
-rw-r--r-- | spec/models/clusters/cluster_spec.rb | 9 | ||||
-rw-r--r-- | spec/policies/clusters/cluster_policy_spec.rb | 16 | ||||
-rw-r--r-- | spec/policies/clusters/instance_policy_spec.rb | 36 | ||||
-rw-r--r-- | spec/presenters/clusters/cluster_presenter_spec.rb | 12 | ||||
-rw-r--r-- | spec/presenters/group_clusterable_presenter_spec.rb | 6 | ||||
-rw-r--r-- | spec/presenters/project_clusterable_presenter_spec.rb | 6 | ||||
-rw-r--r-- | spec/services/clusters/build_service_spec.rb | 8 |
12 files changed, 846 insertions, 23 deletions
diff --git a/spec/controllers/admin/clusters/applications_controller_spec.rb b/spec/controllers/admin/clusters/applications_controller_spec.rb new file mode 100644 index 00000000000..76f261e7d3f --- /dev/null +++ b/spec/controllers/admin/clusters/applications_controller_spec.rb @@ -0,0 +1,149 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Admin::Clusters::ApplicationsController do + include AccessMatchersForController + + def current_application + Clusters::Cluster::APPLICATIONS[application] + end + + shared_examples 'a secure endpoint' do + it { expect { subject }.to be_allowed_for(:admin) } + it { expect { subject }.to be_denied_for(:user) } + it { expect { subject }.to be_denied_for(:external) } + + context 'when instance clusters are disabled' do + before do + stub_feature_flags(instance_clusters: false) + end + + it 'returns 404' do + is_expected.to have_http_status(:not_found) + end + end + end + + let(:cluster) { create(:cluster, :instance, :provided_by_gcp) } + + describe 'POST create' do + subject do + post :create, params: params + end + + let(:application) { 'helm' } + let(:params) { { application: application, id: cluster.id } } + + describe 'functionality' do + let(:admin) { create(:admin) } + + before do + sign_in(admin) + end + + it 'schedule an application installation' do + expect(ClusterInstallAppWorker).to receive(:perform_async).with(application, anything).once + + expect { subject }.to change { current_application.count } + expect(response).to have_http_status(:no_content) + expect(cluster.application_helm).to be_scheduled + end + + context 'when cluster do not exists' do + before do + cluster.destroy! + end + + it 'return 404' do + expect { subject }.not_to change { current_application.count } + expect(response).to have_http_status(:not_found) + end + end + + context 'when application is unknown' do + let(:application) { 'unkwnown-app' } + + it 'return 404' do + is_expected.to have_http_status(:not_found) + end + end + + context 'when application is already installing' do + before do + create(:clusters_applications_helm, :installing, cluster: cluster) + end + + it 'returns 400' do + is_expected.to have_http_status(:bad_request) + end + end + end + + describe 'security' do + before do + allow(ClusterInstallAppWorker).to receive(:perform_async) + end + + it_behaves_like 'a secure endpoint' + end + end + + describe 'PATCH update' do + subject do + patch :update, params: params + 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(:admin) { create(:admin) } + + before do + sign_in(admin) + end + + context "when cluster and app exists" do + it "schedules an application update" do + expect(ClusterPatchAppWorker).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(ClusterPatchAppWorker).to receive(:perform_async) + end + + it_behaves_like 'a secure endpoint' + end + end +end diff --git a/spec/controllers/admin/clusters_controller_spec.rb b/spec/controllers/admin/clusters_controller_spec.rb new file mode 100644 index 00000000000..7b77cb186a4 --- /dev/null +++ b/spec/controllers/admin/clusters_controller_spec.rb @@ -0,0 +1,540 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Admin::ClustersController do + include AccessMatchersForController + include GoogleApi::CloudPlatformHelpers + + let(:admin) { create(:admin) } + + before do + sign_in(admin) + end + + describe 'GET #index' do + def get_index(params = {}) + get :index, params: params + end + + context 'when feature flag is not enabled' do + before do + stub_feature_flags(instance_clusters: false) + end + + it 'responds with not found' do + get_index + + expect(response).to have_gitlab_http_status(404) + end + end + + context 'when feature flag is enabled' do + before do + stub_feature_flags(instance_clusters: true) + end + + describe 'functionality' do + context 'when instance has one or more clusters' do + let!(:enabled_cluster) do + create(:cluster, :provided_by_gcp, :instance) + end + + let!(:disabled_cluster) do + create(:cluster, :disabled, :provided_by_gcp, :production_environment, :instance) + end + + it 'lists available clusters' do + get_index + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template(:index) + expect(assigns(:clusters)).to match_array([enabled_cluster, disabled_cluster]) + end + + context 'when page is specified' do + let(:last_page) { Clusters::Cluster.instance_type.page.total_pages } + + before do + allow(Clusters::Cluster).to receive(:paginates_per).and_return(1) + create_list(:cluster, 2, :provided_by_gcp, :production_environment, :instance) + end + + it 'redirects to the page' do + get_index(page: last_page) + + expect(response).to have_gitlab_http_status(:ok) + expect(assigns(:clusters).current_page).to eq(last_page) + end + end + end + + context 'when instance does not have a cluster' do + it 'returns an empty state page' do + get_index + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template(:index, partial: :empty_state) + expect(assigns(:clusters)).to eq([]) + end + end + end + end + + describe 'security' do + let(:cluster) { create(:cluster, :provided_by_gcp, :instance) } + + it { expect { get_index }.to be_allowed_for(:admin) } + it { expect { get_index }.to be_denied_for(:user) } + it { expect { get_index }.to be_denied_for(:external) } + end + end + + describe 'GET #new' do + def get_new + get :new + end + + describe 'functionality for new cluster' do + context 'when omniauth has been configured' do + let(:key) { 'secret-key' } + let(:session_key_for_redirect_uri) do + GoogleApi::CloudPlatform::Client.session_key_for_redirect_uri(key) + end + + before do + allow(SecureRandom).to receive(:hex).and_return(key) + end + + it 'has authorize_url' do + get_new + + expect(assigns(:authorize_url)).to include(key) + expect(session[session_key_for_redirect_uri]).to eq(new_admin_cluster_path) + end + end + + context 'when omniauth has not configured' do + before do + stub_omniauth_setting(providers: []) + end + + it 'does not have authorize_url' do + get_new + + expect(assigns(:authorize_url)).to be_nil + end + end + + context 'when access token is valid' do + before do + stub_google_api_validate_token + end + + it 'has new object' do + get_new + + expect(assigns(:gcp_cluster)).to be_an_instance_of(Clusters::ClusterPresenter) + end + end + + context 'when access token is expired' do + before do + stub_google_api_expired_token + end + + it { expect(@valid_gcp_token).to be_falsey } + end + + context 'when access token is not stored in session' do + it { expect(@valid_gcp_token).to be_falsey } + end + end + + describe 'functionality for existing cluster' do + it 'has new object' do + get_new + + expect(assigns(:user_cluster)).to be_an_instance_of(Clusters::ClusterPresenter) + end + end + + describe 'security' do + it { expect { get_new }.to be_allowed_for(:admin) } + it { expect { get_new }.to be_denied_for(:user) } + it { expect { get_new }.to be_denied_for(:external) } + end + end + + describe 'POST #create_gcp' do + let(:legacy_abac_param) { 'true' } + let(:params) do + { + cluster: { + name: 'new-cluster', + provider_gcp_attributes: { + gcp_project_id: 'gcp-project-12345', + legacy_abac: legacy_abac_param + } + } + } + end + + def post_create_gcp + post :create_gcp, params: params + end + + describe 'functionality' do + context 'when access token is valid' do + before do + stub_google_api_validate_token + end + + it 'creates a new cluster' do + expect(ClusterProvisionWorker).to receive(:perform_async) + expect { post_create_gcp }.to change { Clusters::Cluster.count } + .and change { Clusters::Providers::Gcp.count } + + cluster = Clusters::Cluster.instance_type.first + + expect(response).to redirect_to(admin_cluster_path(cluster)) + expect(cluster).to be_gcp + expect(cluster).to be_kubernetes + expect(cluster.provider_gcp).to be_legacy_abac + end + + context 'when legacy_abac param is false' do + let(:legacy_abac_param) { 'false' } + + it 'creates a new cluster with legacy_abac_disabled' do + expect(ClusterProvisionWorker).to receive(:perform_async) + expect { post_create_gcp }.to change { Clusters::Cluster.count } + .and change { Clusters::Providers::Gcp.count } + expect(Clusters::Cluster.instance_type.first.provider_gcp).not_to be_legacy_abac + end + end + end + + context 'when access token is expired' do + before do + stub_google_api_expired_token + end + + it { expect(@valid_gcp_token).to be_falsey } + end + + context 'when access token is not stored in session' do + it { expect(@valid_gcp_token).to be_falsey } + end + end + + describe 'security' do + before do + allow_any_instance_of(described_class) + .to receive(:token_in_session).and_return('token') + allow_any_instance_of(described_class) + .to receive(:expires_at_in_session).and_return(1.hour.since.to_i.to_s) + allow_any_instance_of(GoogleApi::CloudPlatform::Client) + .to receive(:projects_zones_clusters_create) do + OpenStruct.new( + self_link: 'projects/gcp-project-12345/zones/us-central1-a/operations/ope-123', + status: 'RUNNING' + ) + end + + allow(WaitForClusterCreationWorker).to receive(:perform_in).and_return(nil) + end + + it { expect { post_create_gcp }.to be_allowed_for(:admin) } + it { expect { post_create_gcp }.to be_denied_for(:user) } + it { expect { post_create_gcp }.to be_denied_for(:external) } + end + end + + describe 'POST #create_user' do + let(:params) do + { + cluster: { + name: 'new-cluster', + platform_kubernetes_attributes: { + api_url: 'http://my-url', + token: 'test' + } + } + } + end + + def post_create_user + post :create_user, params: params + end + + describe 'functionality' do + context 'when creates a cluster' do + it 'creates a new cluster' do + expect(ClusterProvisionWorker).to receive(:perform_async) + + expect { post_create_user }.to change { Clusters::Cluster.count } + .and change { Clusters::Platforms::Kubernetes.count } + + cluster = Clusters::Cluster.instance_type.first + + expect(response).to redirect_to(admin_cluster_path(cluster)) + expect(cluster).to be_user + expect(cluster).to be_kubernetes + end + end + + context 'when creates a RBAC-enabled cluster' do + let(:params) do + { + cluster: { + name: 'new-cluster', + platform_kubernetes_attributes: { + api_url: 'http://my-url', + token: 'test', + authorization_type: 'rbac' + } + } + } + end + + it 'creates a new cluster' do + expect(ClusterProvisionWorker).to receive(:perform_async) + + expect { post_create_user }.to change { Clusters::Cluster.count } + .and change { Clusters::Platforms::Kubernetes.count } + + cluster = Clusters::Cluster.instance_type.first + + expect(response).to redirect_to(admin_cluster_path(cluster)) + expect(cluster).to be_user + expect(cluster).to be_kubernetes + expect(cluster).to be_platform_kubernetes_rbac + end + end + end + + describe 'security' do + it { expect { post_create_user }.to be_allowed_for(:admin) } + it { expect { post_create_user }.to be_denied_for(:user) } + it { expect { post_create_user }.to be_denied_for(:external) } + end + end + + describe 'GET #cluster_status' do + let(:cluster) { create(:cluster, :providing_by_gcp, :instance) } + + def get_cluster_status + get :cluster_status, + params: { + id: cluster + }, + format: :json + end + + describe 'functionality' do + it 'responds with matching schema' do + get_cluster_status + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('cluster_status') + end + + it 'invokes schedule_status_update on each application' do + expect_any_instance_of(Clusters::Applications::Ingress).to receive(:schedule_status_update) + + get_cluster_status + end + end + + describe 'security' do + it { expect { get_cluster_status }.to be_allowed_for(:admin) } + it { expect { get_cluster_status }.to be_denied_for(:user) } + it { expect { get_cluster_status }.to be_denied_for(:external) } + end + end + + describe 'GET #show' do + let(:cluster) { create(:cluster, :provided_by_gcp, :instance) } + + def get_show + get :show, + params: { + id: cluster + } + end + + describe 'functionality' do + it 'responds successfully' do + get_show + + expect(response).to have_gitlab_http_status(:ok) + expect(assigns(:cluster)).to eq(cluster) + end + end + + describe 'security' do + it { expect { get_show }.to be_allowed_for(:admin) } + it { expect { get_show }.to be_denied_for(:user) } + it { expect { get_show }.to be_denied_for(:external) } + end + end + + describe 'PUT #update' do + def put_update(format: :html) + put :update, params: params.merge( + id: cluster, + format: format + ) + end + + let(:cluster) { create(:cluster, :provided_by_user, :instance) } + let(:domain) { 'test-domain.com' } + + let(:params) do + { + cluster: { + enabled: false, + name: 'my-new-cluster-name', + base_domain: domain + } + } + end + + it 'updates and redirects back to show page' do + put_update + + cluster.reload + expect(response).to redirect_to(admin_cluster_path(cluster)) + expect(flash[:notice]).to eq('Kubernetes cluster was successfully updated.') + expect(cluster.enabled).to be_falsey + expect(cluster.name).to eq('my-new-cluster-name') + expect(cluster.domain).to eq('test-domain.com') + end + + context 'when domain is invalid' do + let(:domain) { 'http://not-a-valid-domain' } + + it 'does not update cluster attributes' do + put_update + + cluster.reload + expect(response).to render_template(:show) + expect(cluster.name).not_to eq('my-new-cluster-name') + expect(cluster.domain).not_to eq('test-domain.com') + end + end + + context 'when format is json' do + context 'when changing parameters' do + context 'when valid parameters are used' do + let(:params) do + { + cluster: { + enabled: false, + name: 'my-new-cluster-name', + domain: domain + } + } + end + + it 'updates and redirects back to show page' do + put_update(format: :json) + + cluster.reload + expect(response).to have_http_status(:no_content) + expect(cluster.enabled).to be_falsey + expect(cluster.name).to eq('my-new-cluster-name') + end + end + + context 'when invalid parameters are used' do + let(:params) do + { + cluster: { + enabled: false, + name: '' + } + } + end + + it 'rejects changes' do + put_update(format: :json) + + expect(response).to have_http_status(:bad_request) + end + end + end + end + + describe 'security' do + set(:cluster) { create(:cluster, :provided_by_gcp, :instance) } + + it { expect { put_update }.to be_allowed_for(:admin) } + it { expect { put_update }.to be_denied_for(:user) } + it { expect { put_update }.to be_denied_for(:external) } + end + end + + describe 'DELETE #destroy' do + let!(:cluster) { create(:cluster, :provided_by_gcp, :production_environment, :instance) } + + def delete_destroy + delete :destroy, + params: { + id: cluster + } + end + + describe 'functionality' do + context 'when cluster is provided by GCP' do + context 'when cluster is created' do + it 'destroys and redirects back to clusters list' do + expect { delete_destroy } + .to change { Clusters::Cluster.count }.by(-1) + .and change { Clusters::Platforms::Kubernetes.count }.by(-1) + .and change { Clusters::Providers::Gcp.count }.by(-1) + + expect(response).to redirect_to(admin_clusters_path) + expect(flash[:notice]).to eq('Kubernetes cluster integration was successfully removed.') + end + end + + context 'when cluster is being created' do + let!(:cluster) { create(:cluster, :providing_by_gcp, :production_environment, :instance) } + + it 'destroys and redirects back to clusters list' do + expect { delete_destroy } + .to change { Clusters::Cluster.count }.by(-1) + .and change { Clusters::Providers::Gcp.count }.by(-1) + + expect(response).to redirect_to(admin_clusters_path) + expect(flash[:notice]).to eq('Kubernetes cluster integration was successfully removed.') + end + end + end + + context 'when cluster is provided by user' do + let!(:cluster) { create(:cluster, :provided_by_user, :production_environment, :instance) } + + it 'destroys and redirects back to clusters list' do + expect { delete_destroy } + .to change { Clusters::Cluster.count }.by(-1) + .and change { Clusters::Platforms::Kubernetes.count }.by(-1) + .and change { Clusters::Providers::Gcp.count }.by(0) + + expect(response).to redirect_to(admin_clusters_path) + expect(flash[:notice]).to eq('Kubernetes cluster integration was successfully removed.') + end + end + end + + describe 'security' do + set(:cluster) { create(:cluster, :provided_by_gcp, :production_environment, :instance) } + + it { expect { delete_destroy }.to be_allowed_for(:admin) } + it { expect { delete_destroy }.to be_denied_for(:user) } + it { expect { delete_destroy }.to be_denied_for(:external) } + end + end +end diff --git a/spec/controllers/concerns/enforces_admin_authentication_spec.rb b/spec/controllers/concerns/enforces_admin_authentication_spec.rb new file mode 100644 index 00000000000..e6a6702fdea --- /dev/null +++ b/spec/controllers/concerns/enforces_admin_authentication_spec.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe EnforcesAdminAuthentication do + let(:user) { create(:user) } + + before do + sign_in(user) + end + + controller(ApplicationController) do + # `described_class` is not available in this context + include EnforcesAdminAuthentication # rubocop:disable RSpec/DescribedClass + + def index + head :ok + end + end + + describe 'authenticate_admin!' do + context 'as an admin' do + let(:user) { create(:admin) } + + it 'renders ok' do + get :index + + expect(response).to have_gitlab_http_status(200) + end + end + + context 'as a user' do + it 'renders a 404' do + get :index + + expect(response).to have_gitlab_http_status(404) + end + end + end +end diff --git a/spec/finders/cluster_ancestors_finder_spec.rb b/spec/finders/cluster_ancestors_finder_spec.rb index 332086c42e2..750042b6b54 100644 --- a/spec/finders/cluster_ancestors_finder_spec.rb +++ b/spec/finders/cluster_ancestors_finder_spec.rb @@ -8,11 +8,15 @@ describe ClusterAncestorsFinder, '#execute' do let(:user) { create(:user) } let!(:project_cluster) do - create(:cluster, :provided_by_user, cluster_type: :project_type, projects: [project]) + create(:cluster, :provided_by_user, :project, projects: [project]) end let!(:group_cluster) do - create(:cluster, :provided_by_user, cluster_type: :group_type, groups: [group]) + create(:cluster, :provided_by_user, :group, groups: [group]) + end + + let!(:instance_cluster) do + create(:cluster, :provided_by_user, :instance) end subject { described_class.new(clusterable, user).execute } @@ -25,7 +29,7 @@ describe ClusterAncestorsFinder, '#execute' do end it 'returns the project clusters followed by group clusters' do - is_expected.to eq([project_cluster, group_cluster]) + is_expected.to eq([project_cluster, group_cluster, instance_cluster]) end context 'nested groups', :nested_groups do @@ -33,11 +37,11 @@ describe ClusterAncestorsFinder, '#execute' do let(:parent_group) { create(:group) } let!(:parent_group_cluster) do - create(:cluster, :provided_by_user, cluster_type: :group_type, groups: [parent_group]) + create(:cluster, :provided_by_user, :group, groups: [parent_group]) end it 'returns the project clusters followed by group clusters ordered ascending the hierarchy' do - is_expected.to eq([project_cluster, group_cluster, parent_group_cluster]) + is_expected.to eq([project_cluster, group_cluster, parent_group_cluster, instance_cluster]) end end end @@ -58,7 +62,7 @@ describe ClusterAncestorsFinder, '#execute' do end it 'returns the list of group clusters' do - is_expected.to eq([group_cluster]) + is_expected.to eq([group_cluster, instance_cluster]) end context 'nested groups', :nested_groups do @@ -66,12 +70,21 @@ describe ClusterAncestorsFinder, '#execute' do let(:parent_group) { create(:group) } let!(:parent_group_cluster) do - create(:cluster, :provided_by_user, cluster_type: :group_type, groups: [parent_group]) + create(:cluster, :provided_by_user, :group, groups: [parent_group]) end it 'returns the list of group clusters ordered ascending the hierarchy' do - is_expected.to eq([group_cluster, parent_group_cluster]) + is_expected.to eq([group_cluster, parent_group_cluster, instance_cluster]) end end end + + context 'for an instance' do + let(:clusterable) { Clusters::Instance.new } + let(:user) { create(:admin) } + + it 'returns the list of instance clusters' do + is_expected.to eq([instance_cluster]) + end + end end diff --git a/spec/models/clusters/applications/runner_spec.rb b/spec/models/clusters/applications/runner_spec.rb index bdc0cb8ed86..4f0cd0efe9c 100644 --- a/spec/models/clusters/applications/runner_spec.rb +++ b/spec/models/clusters/applications/runner_spec.rb @@ -69,8 +69,8 @@ describe Clusters::Applications::Runner do expect(values).to include('privileged: true') expect(values).to include('image: ubuntu:16.04') expect(values).to include('resources') - expect(values).to match(/runnerToken: '?#{ci_runner.token}/) - expect(values).to match(/gitlabUrl: '?#{Gitlab::Routing.url_helpers.root_url}/) + expect(values).to match(/runnerToken: '?#{Regexp.escape(ci_runner.token)}/) + expect(values).to match(/gitlabUrl: '?#{Regexp.escape(Gitlab::Routing.url_helpers.root_url)}/) end context 'without a runner' do @@ -83,7 +83,7 @@ describe Clusters::Applications::Runner do end it 'uses the new runner token' do - expect(values).to match(/runnerToken: '?#{runner.token}/) + expect(values).to match(/runnerToken: '?#{Regexp.escape(runner.token)}/) end end @@ -114,6 +114,18 @@ describe Clusters::Applications::Runner do expect(runner.groups).to eq [group] end end + + context 'instance cluster' do + let(:cluster) { create(:cluster, :with_installed_helm, :instance) } + + include_examples 'runner creation' + + it 'creates an instance runner' do + subject + + expect(runner).to be_instance_type + end + end end context 'with duplicated values on vendor/runner/values.yaml' do diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb index e1506c06044..58203da5b22 100644 --- a/spec/models/clusters/cluster_spec.rb +++ b/spec/models/clusters/cluster_spec.rb @@ -325,6 +325,15 @@ describe Clusters::Cluster do end end + context 'when group and instance have configured kubernetes clusters' do + let(:project) { create(:project, group: group) } + let!(:instance_cluster) { create(:cluster, :provided_by_gcp, :instance) } + + it 'returns clusters in order, descending the hierachy' do + is_expected.to eq([group_cluster, instance_cluster]) + end + end + context 'when sub-group has configured kubernetes cluster', :nested_groups do let(:sub_group_cluster) { create(:cluster, :provided_by_gcp, :group) } let(:sub_group) { sub_group_cluster.group } diff --git a/spec/policies/clusters/cluster_policy_spec.rb b/spec/policies/clusters/cluster_policy_spec.rb index b2f0ca1bc30..cc3dde154dc 100644 --- a/spec/policies/clusters/cluster_policy_spec.rb +++ b/spec/policies/clusters/cluster_policy_spec.rb @@ -66,5 +66,21 @@ describe Clusters::ClusterPolicy, :models do it { expect(policy).to be_disallowed :admin_cluster } end end + + context 'instance cluster' do + let(:cluster) { create(:cluster, :instance) } + + context 'when user' do + it { expect(policy).to be_disallowed :update_cluster } + it { expect(policy).to be_disallowed :admin_cluster } + end + + context 'when admin' do + let(:user) { create(:admin) } + + it { expect(policy).to be_allowed :update_cluster } + it { expect(policy).to be_allowed :admin_cluster } + end + end end end diff --git a/spec/policies/clusters/instance_policy_spec.rb b/spec/policies/clusters/instance_policy_spec.rb new file mode 100644 index 00000000000..9d755c6d29d --- /dev/null +++ b/spec/policies/clusters/instance_policy_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Clusters::InstancePolicy do + let(:user) { create(:user) } + let(:policy) { described_class.new(user, Clusters::Instance.new) } + + describe 'rules' do + context 'when user' do + it { expect(policy).to be_disallowed :read_cluster } + it { expect(policy).to be_disallowed :update_cluster } + it { expect(policy).to be_disallowed :admin_cluster } + end + + context 'when admin' do + let(:user) { create(:admin) } + + context 'with instance_level_clusters enabled' do + it { expect(policy).to be_allowed :read_cluster } + it { expect(policy).to be_allowed :update_cluster } + it { expect(policy).to be_allowed :admin_cluster } + end + + context 'with instance_level_clusters disabled' do + before do + stub_feature_flags(instance_clusters: false) + end + + it { expect(policy).to be_disallowed :read_cluster } + it { expect(policy).to be_disallowed :update_cluster } + it { expect(policy).to be_disallowed :admin_cluster } + end + end + end +end diff --git a/spec/presenters/clusters/cluster_presenter_spec.rb b/spec/presenters/clusters/cluster_presenter_spec.rb index a9d786bc872..42701a5f8d1 100644 --- a/spec/presenters/clusters/cluster_presenter_spec.rb +++ b/spec/presenters/clusters/cluster_presenter_spec.rb @@ -210,6 +210,12 @@ describe Clusters::ClusterPresenter do it { is_expected.to eq('Group cluster') } end + + context 'instance_type cluster' do + let(:cluster) { create(:cluster, :provided_by_gcp, :instance) } + + it { is_expected.to eq('Instance cluster') } + end end describe '#show_path' do @@ -227,6 +233,12 @@ describe Clusters::ClusterPresenter do it { is_expected.to eq(group_cluster_path(group, cluster)) } end + + context 'instance_type cluster' do + let(:cluster) { create(:cluster, :provided_by_gcp, :instance) } + + it { is_expected.to eq(admin_cluster_path(cluster)) } + end end describe '#read_only_kubernetes_platform_fields?' do diff --git a/spec/presenters/group_clusterable_presenter_spec.rb b/spec/presenters/group_clusterable_presenter_spec.rb index cb623fa1fa4..fa77273f6aa 100644 --- a/spec/presenters/group_clusterable_presenter_spec.rb +++ b/spec/presenters/group_clusterable_presenter_spec.rb @@ -82,10 +82,4 @@ describe GroupClusterablePresenter do it { is_expected.to eq(group_cluster_path(group, cluster)) } end - - describe '#clusters_path' do - subject { presenter.clusters_path } - - it { is_expected.to eq(group_clusters_path(group)) } - end end diff --git a/spec/presenters/project_clusterable_presenter_spec.rb b/spec/presenters/project_clusterable_presenter_spec.rb index e5857f75aed..6786a84243f 100644 --- a/spec/presenters/project_clusterable_presenter_spec.rb +++ b/spec/presenters/project_clusterable_presenter_spec.rb @@ -82,10 +82,4 @@ describe ProjectClusterablePresenter do it { is_expected.to eq(project_cluster_path(project, cluster)) } end - - describe '#clusters_path' do - subject { presenter.clusters_path } - - it { is_expected.to eq(project_clusters_path(project)) } - end end diff --git a/spec/services/clusters/build_service_spec.rb b/spec/services/clusters/build_service_spec.rb index da0cb42b3a1..f3e852726f4 100644 --- a/spec/services/clusters/build_service_spec.rb +++ b/spec/services/clusters/build_service_spec.rb @@ -21,5 +21,13 @@ describe Clusters::BuildService do is_expected.to be_group_type end end + + describe 'when cluster subject is an instance' do + let(:cluster_subject) { Clusters::Instance.new } + + it 'sets the cluster_type to instance_type' do + is_expected.to be_instance_type + end + end end end |