From 84d1bd786125c1c14a3ba5f63e38a4cc736a9027 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Tue, 16 Jan 2024 10:42:19 +0000 Subject: Add latest changes from gitlab-org/gitlab@16-8-stable-ee --- .../setup_cloudsql_instance_service_spec.rb | 228 +++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 spec/services/cloud_seed/google_cloud/setup_cloudsql_instance_service_spec.rb (limited to 'spec/services/cloud_seed/google_cloud/setup_cloudsql_instance_service_spec.rb') diff --git a/spec/services/cloud_seed/google_cloud/setup_cloudsql_instance_service_spec.rb b/spec/services/cloud_seed/google_cloud/setup_cloudsql_instance_service_spec.rb new file mode 100644 index 00000000000..ce02672e3fa --- /dev/null +++ b/spec/services/cloud_seed/google_cloud/setup_cloudsql_instance_service_spec.rb @@ -0,0 +1,228 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe CloudSeed::GoogleCloud::SetupCloudsqlInstanceService, feature_category: :deployment_management do + let(:random_user) { create(:user) } + let(:project) { create(:project) } + let(:list_databases_empty) { Google::Apis::SqladminV1beta4::ListDatabasesResponse.new(items: []) } + let(:list_users_empty) { Google::Apis::SqladminV1beta4::ListUsersResponse.new(items: []) } + let(:list_databases) do + Google::Apis::SqladminV1beta4::ListDatabasesResponse.new( + items: [ + Google::Apis::SqladminV1beta4::Database.new(name: 'postgres'), + Google::Apis::SqladminV1beta4::Database.new(name: 'main_db') + ]) + end + + let(:list_users) do + Google::Apis::SqladminV1beta4::ListUsersResponse.new( + items: [ + Google::Apis::SqladminV1beta4::User.new(name: 'postgres'), + Google::Apis::SqladminV1beta4::User.new(name: 'main_user') + ]) + end + + context 'when unauthorized user triggers worker' do + subject do + params = { + gcp_project_id: :gcp_project_id, + instance_name: :instance_name, + database_version: :database_version, + environment_name: :environment_name, + is_protected: :is_protected + } + described_class.new(project, random_user, params).execute + end + + it 'raises unauthorized error' do + message = subject[:message] + status = subject[:status] + + expect(status).to eq(:error) + expect(message).to eq('Unauthorized user') + end + end + + context 'when authorized user triggers worker' do + subject do + user = project.creator + params = { + gcp_project_id: :gcp_project_id, + instance_name: :instance_name, + database_version: :database_version, + environment_name: :environment_name, + is_protected: :is_protected + } + described_class.new(project, user, params).execute + end + + context 'when instance is not RUNNABLE' do + let(:get_instance_response_pending) do + Google::Apis::SqladminV1beta4::DatabaseInstance.new(state: 'PENDING') + end + + it 'raises error' do + allow_next_instance_of(GoogleApi::CloudPlatform::Client) do |google_api_client| + expect(google_api_client).to receive(:get_cloudsql_instance).and_return(get_instance_response_pending) + end + + message = subject[:message] + status = subject[:status] + + expect(status).to eq(:error) + expect(message).to eq('CloudSQL instance not RUNNABLE: {"state":"PENDING"}') + end + end + + context 'when instance is RUNNABLE' do + let(:get_instance_response_runnable) do + Google::Apis::SqladminV1beta4::DatabaseInstance.new( + connection_name: 'mock-connection-name', + ip_addresses: [Struct.new(:ip_address).new('1.2.3.4')], + state: 'RUNNABLE' + ) + end + + let(:operation_fail) { Google::Apis::SqladminV1beta4::Operation.new(status: 'FAILED') } + + let(:operation_done) { Google::Apis::SqladminV1beta4::Operation.new(status: 'DONE') } + + context 'when database creation fails' do + it 'raises error' do + allow_next_instance_of(GoogleApi::CloudPlatform::Client) do |google_api_client| + expect(google_api_client).to receive(:get_cloudsql_instance).and_return(get_instance_response_runnable) + expect(google_api_client).to receive(:create_cloudsql_database).and_return(operation_fail) + expect(google_api_client).to receive(:list_cloudsql_databases).and_return(list_databases_empty) + expect(google_api_client).to receive(:list_cloudsql_users).and_return(list_users_empty) + end + + message = subject[:message] + status = subject[:status] + + expect(status).to eq(:error) + expect(message).to eq('Database creation failed: {"status":"FAILED"}') + end + end + + context 'when user creation fails' do + it 'raises error' do + allow_next_instance_of(GoogleApi::CloudPlatform::Client) do |google_api_client| + expect(google_api_client).to receive(:get_cloudsql_instance).and_return(get_instance_response_runnable) + expect(google_api_client).to receive(:create_cloudsql_database).and_return(operation_done) + expect(google_api_client).to receive(:create_cloudsql_user).and_return(operation_fail) + expect(google_api_client).to receive(:list_cloudsql_databases).and_return(list_databases_empty) + expect(google_api_client).to receive(:list_cloudsql_users).and_return(list_users_empty) + end + + message = subject[:message] + status = subject[:status] + + expect(status).to eq(:error) + expect(message).to eq('User creation failed: {"status":"FAILED"}') + end + end + + context 'when database and user already exist' do + it 'does not try to create a database or user' do + allow_next_instance_of(GoogleApi::CloudPlatform::Client) do |google_api_client| + expect(google_api_client).to receive(:get_cloudsql_instance).and_return(get_instance_response_runnable) + expect(google_api_client).not_to receive(:create_cloudsql_database) + expect(google_api_client).not_to receive(:create_cloudsql_user) + expect(google_api_client).to receive(:list_cloudsql_databases).and_return(list_databases) + expect(google_api_client).to receive(:list_cloudsql_users).and_return(list_users) + end + + status = subject[:status] + expect(status).to eq(:success) + end + end + + context 'when database already exists' do + it 'does not try to create a database' do + allow_next_instance_of(GoogleApi::CloudPlatform::Client) do |google_api_client| + expect(google_api_client).to receive(:get_cloudsql_instance).and_return(get_instance_response_runnable) + expect(google_api_client).not_to receive(:create_cloudsql_database) + expect(google_api_client).to receive(:create_cloudsql_user).and_return(operation_done) + expect(google_api_client).to receive(:list_cloudsql_databases).and_return(list_databases) + expect(google_api_client).to receive(:list_cloudsql_users).and_return(list_users_empty) + end + + status = subject[:status] + expect(status).to eq(:success) + end + end + + context 'when user already exists' do + it 'does not try to create a user' do + allow_next_instance_of(GoogleApi::CloudPlatform::Client) do |google_api_client| + expect(google_api_client).to receive(:get_cloudsql_instance).and_return(get_instance_response_runnable) + expect(google_api_client).to receive(:create_cloudsql_database).and_return(operation_done) + expect(google_api_client).not_to receive(:create_cloudsql_user) + expect(google_api_client).to receive(:list_cloudsql_databases).and_return(list_databases_empty) + expect(google_api_client).to receive(:list_cloudsql_users).and_return(list_users) + end + + status = subject[:status] + expect(status).to eq(:success) + end + end + + context 'when database and user creation succeeds' do + it 'stores project CI vars' do + allow_next_instance_of(GoogleApi::CloudPlatform::Client) do |google_api_client| + expect(google_api_client).to receive(:get_cloudsql_instance).and_return(get_instance_response_runnable) + expect(google_api_client).to receive(:create_cloudsql_database).and_return(operation_done) + expect(google_api_client).to receive(:create_cloudsql_user).and_return(operation_done) + expect(google_api_client).to receive(:list_cloudsql_databases).and_return(list_databases_empty) + expect(google_api_client).to receive(:list_cloudsql_users).and_return(list_users_empty) + end + + subject + + aggregate_failures 'test generated vars' do + variables = project.reload.variables + + expect(variables.count).to eq(8) + expect(variables.find_by(key: 'GCP_PROJECT_ID').value).to eq("gcp_project_id") + expect(variables.find_by(key: 'GCP_CLOUDSQL_INSTANCE_NAME').value).to eq("instance_name") + expect(variables.find_by(key: 'GCP_CLOUDSQL_CONNECTION_NAME').value).to eq("mock-connection-name") + expect(variables.find_by(key: 'GCP_CLOUDSQL_PRIMARY_IP_ADDRESS').value).to eq("1.2.3.4") + expect(variables.find_by(key: 'GCP_CLOUDSQL_VERSION').value).to eq("database_version") + expect(variables.find_by(key: 'GCP_CLOUDSQL_DATABASE_NAME').value).to eq("main_db") + expect(variables.find_by(key: 'GCP_CLOUDSQL_DATABASE_USER').value).to eq("main_user") + expect(variables.find_by(key: 'GCP_CLOUDSQL_DATABASE_PASS').value).to be_present + end + end + + context 'when the ci variable already exists' do + before do + create( + :ci_variable, + project: project, + key: 'GCP_PROJECT_ID', + value: 'previous_gcp_project_id', + environment_scope: :environment_name + ) + end + + it 'overwrites existing GCP_PROJECT_ID var' do + allow_next_instance_of(GoogleApi::CloudPlatform::Client) do |google_api_client| + expect(google_api_client).to receive(:get_cloudsql_instance).and_return(get_instance_response_runnable) + expect(google_api_client).to receive(:create_cloudsql_database).and_return(operation_done) + expect(google_api_client).to receive(:create_cloudsql_user).and_return(operation_done) + expect(google_api_client).to receive(:list_cloudsql_databases).and_return(list_databases_empty) + expect(google_api_client).to receive(:list_cloudsql_users).and_return(list_users_empty) + end + + subject + + variables = project.reload.variables + value = variables.find_by(key: 'GCP_PROJECT_ID', environment_scope: :environment_name).value + expect(value).to eq("gcp_project_id") + end + end + end + end + end +end -- cgit v1.2.3