diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-26 12:07:48 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-26 12:07:48 +0000 |
commit | ef31adeb0fb9a02b2c6a4529ec4e38d7082a4b2b (patch) | |
tree | f0ee2b8bdffd7f91ad0b31388562c90825179585 /spec | |
parent | 7e019504f5ac6decde690565857238e7e59aa034 (diff) | |
download | gitlab-ce-ef31adeb0fb9a02b2c6a4529ec4e38d7082a4b2b.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
22 files changed, 793 insertions, 52 deletions
diff --git a/spec/controllers/admin/sessions_controller_spec.rb b/spec/controllers/admin/sessions_controller_spec.rb index fabd79133ec..351148dbc65 100644 --- a/spec/controllers/admin/sessions_controller_spec.rb +++ b/spec/controllers/admin/sessions_controller_spec.rb @@ -176,6 +176,48 @@ describe Admin::SessionsController, :do_not_mock_admin_mode do expect(controller.current_user_mode.admin_mode?).to be(true) end end + + context 'on a read-only instance' do + before do + allow(Gitlab::Database).to receive(:read_only?).and_return(true) + end + + it 'does not attempt to write to the database with valid otp' do + expect_any_instance_of(User).not_to receive(:save) + expect_any_instance_of(User).not_to receive(:save!) + + controller.store_location_for(:redirect, admin_root_path) + controller.current_user_mode.request_admin_mode! + + authenticate_2fa(otp_attempt: user.current_otp) + + expect(response).to redirect_to admin_root_path + end + + it 'does not attempt to write to the database with invalid otp' do + expect_any_instance_of(User).not_to receive(:save) + expect_any_instance_of(User).not_to receive(:save!) + + controller.current_user_mode.request_admin_mode! + + authenticate_2fa(otp_attempt: 'invalid') + + expect(response).to render_template('admin/sessions/two_factor') + expect(controller.current_user_mode.admin_mode?).to be(false) + end + + it 'does not attempt to write to the database with backup code' do + expect_any_instance_of(User).not_to receive(:save) + expect_any_instance_of(User).not_to receive(:save!) + + controller.current_user_mode.request_admin_mode! + + authenticate_2fa(otp_attempt: user.otp_backup_codes.first) + + expect(response).to render_template('admin/sessions/two_factor') + expect(controller.current_user_mode.admin_mode?).to be(false) + end + end end context 'when using two-factor authentication via U2F' do diff --git a/spec/graphql/resolvers/projects/jira_imports_resolver_spec.rb b/spec/graphql/resolvers/projects/jira_imports_resolver_spec.rb new file mode 100644 index 00000000000..54d51292919 --- /dev/null +++ b/spec/graphql/resolvers/projects/jira_imports_resolver_spec.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Resolvers::Projects::JiraImportsResolver do + include GraphqlHelpers + + describe '#resolve' do + let_it_be(:user) { create(:user) } + let_it_be(:jira_import_data) do + data = JiraImportData.new + data << JiraImportData::JiraProjectDetails.new('AA', 2.days.ago.strftime('%Y-%m-%d %H:%M:%S'), { user_id: user.id, name: user.name }) + data << JiraImportData::JiraProjectDetails.new('BB', 5.days.ago.strftime('%Y-%m-%d %H:%M:%S'), { user_id: user.id, name: user.name }) + data + end + + context 'when project does not have Jira import data' do + let_it_be(:project) { create(:project, :private, import_data: nil) } + + context 'when user cannot read Jira import data' do + context 'when anonymous user' do + it_behaves_like 'no jira import data present' + end + + context 'when user developer' do + before do + project.add_developer(user) + end + + it_behaves_like 'no jira import data present' + end + end + + context 'when user can read Jira import data' do + before do + project.add_maintainer(user) + end + + it_behaves_like 'no jira import data present' + end + end + + context 'when project has Jira import data' do + let_it_be(:project) { create(:project, :private, import_data: jira_import_data) } + + context 'when user cannot read Jira import data' do + context 'when anonymous user' do + it_behaves_like 'no jira import access' + end + + context 'when user developer' do + before do + project.add_developer(user) + end + + it_behaves_like 'no jira import access' + end + end + + context 'when user can access Jira import data' do + before do + project.add_maintainer(user) + end + + it 'returns Jira imports sorted ascending by scheduledAt time' do + imports = resolve_imports + + expect(imports.size).to eq 2 + expect(imports.map(&:key)).to eq %w(BB AA) + end + end + end + end + + def resolve_imports(args = {}, context = { current_user: user }) + resolve(described_class, obj: project, args: args, ctx: context) + end +end diff --git a/spec/graphql/types/jira_import_type_spec.rb b/spec/graphql/types/jira_import_type_spec.rb new file mode 100644 index 00000000000..8448a120682 --- /dev/null +++ b/spec/graphql/types/jira_import_type_spec.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe GitlabSchema.types['JiraImport'] do + it { expect(described_class.graphql_name).to eq('JiraImport') } + + it 'has the expected fields' do + expect(described_class).to have_graphql_fields(:jira_project_key, :scheduled_at, :scheduled_by) + end +end diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb index 475ae9ff5f6..0c8be50ed90 100644 --- a/spec/graphql/types/project_type_spec.rb +++ b/spec/graphql/types/project_type_spec.rb @@ -24,7 +24,7 @@ describe GitlabSchema.types['Project'] do namespace group statistics repository merge_requests merge_request issues issue pipelines removeSourceBranchAfterMerge sentryDetailedError snippets grafanaIntegration autocloseReferencedIssues suggestion_commit_message environments - boards + boards jira_import_status jira_imports ] expect(described_class).to include_graphql_fields(*expected_fields) diff --git a/spec/lib/gitlab/jira_import/base_importer_spec.rb b/spec/lib/gitlab/jira_import/base_importer_spec.rb new file mode 100644 index 00000000000..8bc43feb356 --- /dev/null +++ b/spec/lib/gitlab/jira_import/base_importer_spec.rb @@ -0,0 +1,89 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::JiraImport::BaseImporter do + let(:project) { create(:project) } + + describe 'with any inheriting class' do + context 'when feature flag disabled' do + before do + stub_feature_flags(jira_issue_import: false) + end + + it 'raises exception' do + expect { described_class.new(project) }.to raise_error(Projects::ImportService::Error, 'Jira import feature is disabled.') + end + end + + context 'when feature flag enabled' do + before do + stub_feature_flags(jira_issue_import: true) + end + + context 'when Jira service was not setup' do + it 'raises exception' do + expect { described_class.new(project) }.to raise_error(Projects::ImportService::Error, 'Jira integration not configured.') + end + end + + context 'when Jira service exists' do + let!(:jira_service) { create(:jira_service, project: project) } + + context 'when Jira import data is not present' do + it 'raises exception' do + expect { described_class.new(project) }.to raise_error(Projects::ImportService::Error, 'Unable to find Jira project to import data from.') + end + end + + context 'when import data exists' do + let(:jira_import_data) do + data = JiraImportData.new + data << JiraImportData::JiraProjectDetails.new('xx', Time.now.strftime('%Y-%m-%d %H:%M:%S'), { user_id: 1, name: 'root' }) + data + end + let(:project) { create(:project, import_data: jira_import_data) } + let(:subject) { described_class.new(project) } + + context 'when #imported_items_cache_key is not implemented' do + it { expect { subject.send(:imported_items_cache_key) }.to raise_error(NotImplementedError) } + end + + context 'when #imported_items_cache_key is implemented' do + before do + allow(subject).to receive(:imported_items_cache_key).and_return('dumb-importer-key') + end + + describe '#imported_items_cache_key' do + it { expect(subject.send(:imported_items_cache_key)).to eq('dumb-importer-key') } + end + + describe '#mark_as_imported', :clean_gitlab_redis_cache do + it 'stores id in redis cache' do + expect(Gitlab::Cache::Import::Caching).to receive(:set_add).once.and_call_original + + subject.send(:mark_as_imported, 'some-id') + + expect(Gitlab::Cache::Import::Caching.set_includes?(subject.send(:imported_items_cache_key), 'some-id')).to be true + end + end + + describe '#already_imported?', :clean_gitlab_redis_cache do + it 'returns false if value is not in cache' do + expect(Gitlab::Cache::Import::Caching).to receive(:set_includes?).once.and_call_original + + expect(subject.send(:already_imported?, 'some-id')).to be false + end + + it 'returns true if value already stored in cache' do + Gitlab::Cache::Import::Caching.set_add(subject.send(:imported_items_cache_key), 'some-id') + + expect(subject.send(:already_imported?, 'some-id')).to be true + end + end + end + end + end + end + end +end diff --git a/spec/lib/gitlab/jira_import/issues_importer_spec.rb b/spec/lib/gitlab/jira_import/issues_importer_spec.rb new file mode 100644 index 00000000000..88e8b195dbe --- /dev/null +++ b/spec/lib/gitlab/jira_import/issues_importer_spec.rb @@ -0,0 +1,110 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::JiraImport::IssuesImporter do + let(:user) { create(:user) } + let(:jira_import_data) do + data = JiraImportData.new + data << JiraImportData::JiraProjectDetails.new('XX', Time.now.strftime('%Y-%m-%d %H:%M:%S'), { user_id: user.id, name: user.name }) + data + end + let(:project) { create(:project, import_data: jira_import_data) } + let!(:jira_service) { create(:jira_service, project: project) } + + subject { described_class.new(project) } + + before do + stub_feature_flags(jira_issue_import: true) + end + + describe '#imported_items_cache_key' do + it_behaves_like 'raise exception if not implemented' + it { expect(subject.imported_items_cache_key).to eq("jira-importer/already-imported/#{project.id}/issues") } + end + + describe '#execute', :clean_gitlab_redis_cache do + context 'when no returned issues' do + it 'does not schedule any import jobs' do + expect(subject).to receive(:fetch_issues).with(0).and_return([]) + expect(subject).not_to receive(:already_imported?) + expect(subject).not_to receive(:mark_as_imported) + expect(Gitlab::JiraImport::ImportIssueWorker).not_to receive(:perform_async) + + job_waiter = subject.execute + + expect(job_waiter.jobs_remaining).to eq(0) + expect(Gitlab::JiraImport.get_issues_next_start_at(project.id)).to eq(-1) + end + end + + context 'with results returned' do + JiraIssue = Struct.new(:id) + let_it_be(:jira_issue1) { JiraIssue.new(1) } + let_it_be(:jira_issue2) { JiraIssue.new(2) } + + context 'when single page of results is returned' do + before do + stub_const("#{described_class.name}::BATCH_SIZE", 3) + end + + it 'schedules 2 import jobs' do + expect(subject).to receive(:fetch_issues).and_return([jira_issue1, jira_issue2]) + expect(Gitlab::JiraImport::ImportIssueWorker).to receive(:perform_async).twice + expect(Gitlab::Cache::Import::Caching).to receive(:set_add).twice.and_call_original + expect(Gitlab::Cache::Import::Caching).to receive(:set_includes?).twice.and_call_original + allow_next_instance_of(Gitlab::JiraImport::IssueSerializer) do |instance| + allow(instance).to receive(:execute).and_return({ key: 'data' }) + end + + job_waiter = subject.execute + + expect(job_waiter.jobs_remaining).to eq(2) + expect(Gitlab::JiraImport.get_issues_next_start_at(project.id)).to eq(2) + end + end + + context 'when there is more than one page of results' do + before do + stub_const("#{described_class.name}::BATCH_SIZE", 2) + end + + it 'schedules 3 import jobs' do + expect(subject).to receive(:fetch_issues).with(0).and_return([jira_issue1, jira_issue2]) + expect(Gitlab::JiraImport::ImportIssueWorker).to receive(:perform_async).twice.times + expect(Gitlab::Cache::Import::Caching).to receive(:set_add).twice.times.and_call_original + expect(Gitlab::Cache::Import::Caching).to receive(:set_includes?).twice.times.and_call_original + allow_next_instance_of(Gitlab::JiraImport::IssueSerializer) do |instance| + allow(instance).to receive(:execute).and_return({ key: 'data' }) + end + + job_waiter = subject.execute + + expect(job_waiter.jobs_remaining).to eq(2) + expect(Gitlab::JiraImport.get_issues_next_start_at(project.id)).to eq(2) + end + end + + context 'when duplicate results are returned' do + before do + stub_const("#{described_class.name}::BATCH_SIZE", 2) + end + + it 'schedules 2 import jobs' do + expect(subject).to receive(:fetch_issues).with(0).and_return([jira_issue1, jira_issue1]) + expect(Gitlab::JiraImport::ImportIssueWorker).to receive(:perform_async).once + expect(Gitlab::Cache::Import::Caching).to receive(:set_add).once.and_call_original + expect(Gitlab::Cache::Import::Caching).to receive(:set_includes?).twice.times.and_call_original + allow_next_instance_of(Gitlab::JiraImport::IssueSerializer) do |instance| + allow(instance).to receive(:execute).and_return({ key: 'data' }) + end + + job_waiter = subject.execute + + expect(job_waiter.jobs_remaining).to eq(1) + expect(Gitlab::JiraImport.get_issues_next_start_at(project.id)).to eq(2) + end + end + end + end +end diff --git a/spec/lib/gitlab/jira_import_spec.rb b/spec/lib/gitlab/jira_import_spec.rb new file mode 100644 index 00000000000..c5c3d6ef4b9 --- /dev/null +++ b/spec/lib/gitlab/jira_import_spec.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::JiraImport do + let(:project_id) { 321 } + + describe '.jira_issue_cache_key' do + it 'returns cache key for Jira issue imported to given project' do + expect(described_class.jira_issue_cache_key(project_id, 'DEMO-123')).to eq("jira-import/items-mapper/#{project_id}/issues/DEMO-123") + end + end + + describe '.already_imported_cache_key' do + it 'returns cache key for already imported items' do + expect(described_class.already_imported_cache_key(:issues, project_id)).to eq("jira-importer/already-imported/#{project_id}/issues") + end + end + + describe '.jira_issues_next_page_cache_key' do + it 'returns cache key for next issues' do + expect(described_class.jira_issues_next_page_cache_key(project_id)).to eq("jira-import/paginator/#{project_id}/issues") + end + end + + describe '.get_issues_next_start_at', :clean_gitlab_redis_cache do + it 'returns zero when not defined' do + expect(Gitlab::Cache::Import::Caching.read("jira-import/paginator/#{project_id}/issues")).to be nil + expect(described_class.get_issues_next_start_at(project_id)).to eq(0) + end + + it 'returns negative value for next issues to be imported starting point' do + Gitlab::Cache::Import::Caching.write("jira-import/paginator/#{project_id}/issues", -10) + + expect(Gitlab::Cache::Import::Caching.read("jira-import/paginator/#{project_id}/issues")).to eq('-10') + expect(described_class.get_issues_next_start_at(project_id)).to eq(-10) + end + + it 'returns cached value for next issues to be imported starting point' do + Gitlab::Cache::Import::Caching.write("jira-import/paginator/#{project_id}/issues", 10) + + expect(Gitlab::Cache::Import::Caching.read("jira-import/paginator/#{project_id}/issues")).to eq('10') + expect(described_class.get_issues_next_start_at(project_id)).to eq(10) + end + end + + describe '.store_issues_next_started_at', :clean_gitlab_redis_cache do + it 'stores nil value' do + described_class.store_issues_next_started_at(project_id, nil) + + expect(Gitlab::Cache::Import::Caching.read("jira-import/paginator/#{project_id}/issues")).to eq '' + expect(Gitlab::Cache::Import::Caching.read("jira-import/paginator/#{project_id}/issues").to_i).to eq(0) + end + + it 'stores positive value' do + described_class.store_issues_next_started_at(project_id, 10) + + expect(Gitlab::Cache::Import::Caching.read("jira-import/paginator/#{project_id}/issues").to_i).to eq(10) + end + + it 'stores negative value' do + described_class.store_issues_next_started_at(project_id, -10) + + expect(Gitlab::Cache::Import::Caching.read("jira-import/paginator/#{project_id}/issues").to_i).to eq(-10) + end + end +end diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index c3f2e3aebdd..425194ba0e3 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -3061,20 +3061,6 @@ describe Ci::Pipeline, :mailer do expect(pipeline.source_bridge).to eq bridge end end - - describe '#update_bridge_status!' do - it 'can update bridge status if it is running' do - pipeline.update_bridge_status! - - expect(bridge.reload).to be_success - end - - it 'can not update bridge status if is not active' do - bridge.success! - - expect { pipeline.update_bridge_status! }.not_to change { bridge.status } - end - end end context 'when an upstream status is a build' do @@ -3101,16 +3087,6 @@ describe Ci::Pipeline, :mailer do expect(pipeline.source_bridge).to be_nil end end - - describe '#update_bridge_status!' do - it 'tracks an ArgumentError and does not update upstream job status' do - expect(Gitlab::ErrorTracking) - .to receive(:track_exception) - .with(instance_of(ArgumentError), pipeline_id: pipeline.id) - - pipeline.update_bridge_status! - end - end end end end diff --git a/spec/models/project_services/bamboo_service_spec.rb b/spec/models/project_services/bamboo_service_spec.rb index 1b946278790..c1efa3a4348 100644 --- a/spec/models/project_services/bamboo_service_spec.rb +++ b/spec/models/project_services/bamboo_service_spec.rb @@ -8,9 +8,11 @@ describe BambooService, :use_clean_rails_memory_store_caching do let(:bamboo_url) { 'http://gitlab.com/bamboo' } + let_it_be(:project) { create(:project) } + subject(:service) do described_class.create( - project: create(:project), + project: project, properties: { bamboo_url: bamboo_url, username: 'mic', @@ -224,6 +226,19 @@ describe BambooService, :use_clean_rails_memory_store_caching do is_expected.to eq(:error) end + + Gitlab::HTTP::HTTP_ERRORS.each do |http_error| + it "sets commit status to :error with a #{http_error.name} error" do + WebMock.stub_request(:get, 'http://gitlab.com/bamboo/rest/api/latest/result/byChangeset/123?os_authType=basic') + .to_raise(http_error) + + expect(Gitlab::ErrorTracking) + .to receive(:log_exception) + .with(instance_of(http_error), project_id: project.id) + + is_expected.to eq(:error) + end + end end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 51fcee29485..694c6935c1d 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -2282,6 +2282,44 @@ describe Project do end end + describe '#jira_import_status' do + let(:project) { create(:project, :import_started, import_type: 'jira') } + + context 'when import_data is nil' do + it 'returns none' do + expect(project.import_data).to be nil + expect(project.jira_import_status).to eq('none') + end + end + + context 'when import_data is set' do + let(:jira_import_data) { JiraImportData.new } + let(:project) { create(:project, :import_started, import_data: jira_import_data, import_type: 'jira') } + + it 'returns none' do + expect(project.import_data.becomes(JiraImportData).force_import?).to be false + expect(project.jira_import_status).to eq('none') + end + + context 'when jira_force_import is true' do + let(:imported_jira_project) do + JiraImportData::JiraProjectDetails.new('xx', Time.now.strftime('%Y-%m-%d %H:%M:%S'), { user_id: 1, name: 'root' }) + end + + before do + jira_import_data = project.import_data.becomes(JiraImportData) + jira_import_data << imported_jira_project + jira_import_data.force_import! + end + + it 'returns started' do + expect(project.import_data.becomes(JiraImportData).force_import?).to be true + expect(project.jira_import_status).to eq('started') + end + end + end + end + describe '#human_import_status_name' do context 'with import_state' do it 'returns the right human import status' do diff --git a/spec/requests/api/graphql/project/jira_import_spec.rb b/spec/requests/api/graphql/project/jira_import_spec.rb new file mode 100644 index 00000000000..beebc63a3c6 --- /dev/null +++ b/spec/requests/api/graphql/project/jira_import_spec.rb @@ -0,0 +1,183 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'query jira import data' do + include GraphqlHelpers + + let_it_be(:current_user) { create(:user) } + let_it_be(:jira_import_data) do + data = JiraImportData.new + data << JiraImportData::JiraProjectDetails.new( + 'AA', 2.days.ago.strftime('%Y-%m-%d %H:%M:%S'), + { user_id: current_user.id, name: current_user.name } + ) + data << JiraImportData::JiraProjectDetails.new( + 'BB', 5.days.ago.strftime('%Y-%m-%d %H:%M:%S'), + { user_id: current_user.id, name: current_user.name } + ) + data + end + let_it_be(:project) { create(:project, :private, :import_started, import_data: jira_import_data, import_type: 'jira') } + let(:query) do + %( + query { + project(fullPath: "#{project.full_path}") { + jiraImportStatus + jiraImports { + nodes { + jiraProjectKey + scheduledAt + scheduledBy { + username + } + } + } + } + } + ) + end + let(:jira_imports) { graphql_data.dig('project', 'jiraImports', 'nodes')} + let(:jira_import_status) { graphql_data.dig('project', 'jiraImportStatus')} + + context 'when user cannot read Jira import data' do + before do + post_graphql(query, current_user: current_user) + end + + context 'when anonymous user' do + let(:current_user) { nil } + + it { expect(jira_imports).to be nil } + end + + context 'when user developer' do + before do + project.add_developer(current_user) + end + + it { expect(jira_imports).to be nil } + end + end + + context 'when user can access Jira import data' do + before do + project.add_maintainer(current_user) + post_graphql(query, current_user: current_user) + end + + it_behaves_like 'a working graphql query' + + context 'list of jira imports sorted ascending by scheduledAt time' do + it 'retuns list of jira imports' do + jira_proket_keys = jira_imports.map {|ji| ji['jiraProjectKey']} + usernames = jira_imports.map {|ji| ji.dig('scheduledBy', 'username')} + + expect(jira_imports.size).to eq 2 + expect(jira_proket_keys).to eq %w(BB AA) + expect(usernames).to eq [current_user.username, current_user.username] + end + end + + describe 'jira imports pagination' do + context 'first jira import' do + let(:query) do + %( + query { + project(fullPath:"#{project.full_path}") { + jiraImports(first: 1) { + nodes { + jiraProjectKey + scheduledBy { + username + } + } + } + } + } + ) + end + + it 'returns latest jira import data' do + first_jira_import = jira_imports.first + + expect(first_jira_import['jiraProjectKey']).to eq 'BB' + expect(first_jira_import.dig('scheduledBy', 'username')).to eq current_user.username + end + end + + context 'lastest jira import' do + let(:query) do + %( + query { + project(fullPath:"#{project.full_path}") { + jiraImports(last: 1) { + nodes { + jiraProjectKey + scheduledBy { + username + } + } + } + } + } + ) + end + + it 'returns latest jira import data' do + latest_jira_import = jira_imports.first + + expect(latest_jira_import['jiraProjectKey']).to eq 'AA' + expect(latest_jira_import.dig('scheduledBy', 'username')).to eq current_user.username + end + end + end + end + + context 'jira import status' do + context 'when user cannot access project' do + it 'does not return import status' do + post_graphql(query, current_user: current_user) + + expect(graphql_data['project']).to be nil + end + end + + context 'when user can access project' do + before do + project.add_guest(current_user) + end + + context 'when import never ran' do + let(:project) { create(:project) } + + it 'returns import status' do + post_graphql(query, current_user: current_user) + + expect(jira_import_status).to eq('none') + end + end + + context 'when import finished' do + it 'returns import status' do + post_graphql(query, current_user: current_user) + + expect(jira_import_status).to eq('finished') + end + end + + context 'when import running, i.e. force-import: true' do + before do + project.import_data.becomes(JiraImportData).force_import! + project.save! + end + + it 'returns import status' do + post_graphql(query, current_user: current_user) + + expect(jira_import_status).to eq('started') + end + end + end + end +end diff --git a/spec/support/shared_examples/graphql/jira_import/jira_import_resolved_shared_examples.rb b/spec/support/shared_examples/graphql/jira_import/jira_import_resolved_shared_examples.rb new file mode 100644 index 00000000000..b1d178521bb --- /dev/null +++ b/spec/support/shared_examples/graphql/jira_import/jira_import_resolved_shared_examples.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +shared_examples 'no jira import data present' do + it 'returns none' do + expect(resolve_imports).to eq JiraImportData.none + end +end + +shared_examples 'no jira import access' do + it 'raises error' do + expect do + resolve_imports + end.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end +end diff --git a/spec/support/shared_examples/lib/gitlab/jira_import/base_importer_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/jira_import/base_importer_shared_examples.rb new file mode 100644 index 00000000000..85dcc053447 --- /dev/null +++ b/spec/support/shared_examples/lib/gitlab/jira_import/base_importer_shared_examples.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +shared_examples 'raise exception if not implemented' do + it { expect { described_class.new(project).imported_items_cache_key }.not_to raise_error } +end diff --git a/spec/support/shared_examples/workers/gitlab/jira_import/jira_import_workers_shared_examples.rb b/spec/support/shared_examples/workers/gitlab/jira_import/jira_import_workers_shared_examples.rb index 5448526f954..71ec1ea6a74 100644 --- a/spec/support/shared_examples/workers/gitlab/jira_import/jira_import_workers_shared_examples.rb +++ b/spec/support/shared_examples/workers/gitlab/jira_import/jira_import_workers_shared_examples.rb @@ -16,7 +16,7 @@ shared_examples 'exit import not started' do it 'does nothing, and exits' do expect(Gitlab::JiraImport::AdvanceStageWorker).not_to receive(:perform_async) - worker.perform(project.id) + described_class.new.perform(project.id) end end @@ -25,8 +25,8 @@ shared_examples 'advance to next stage' do |next_stage| it "advances to #{next_stage} stage" do expect(Gitlab::JobWaiter).to receive(:new).and_return(job_waiter) - expect(Gitlab::JiraImport::AdvanceStageWorker).to receive(:perform_async).with(project.id, { job_waiter.key => job_waiter.jobs_remaining }, next_stage.to_sym) + expect(Gitlab::JiraImport::AdvanceStageWorker).to receive(:perform_async).with(project.id, { job_waiter.key => job_waiter.jobs_remaining }, next_stage.to_sym).and_return([]) - worker.perform(project.id) + described_class.new.perform(project.id) end end diff --git a/spec/workers/gitlab/jira_import/import_issue_worker_spec.rb b/spec/workers/gitlab/jira_import/import_issue_worker_spec.rb new file mode 100644 index 00000000000..c09492efcae --- /dev/null +++ b/spec/workers/gitlab/jira_import/import_issue_worker_spec.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::JiraImport::ImportIssueWorker do + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project) } + + describe 'modules' do + it { expect(described_class).to include_module(ApplicationWorker) } + it { expect(described_class).to include_module(Gitlab::NotifyUponDeath) } + it { expect(described_class).to include_module(Gitlab::JiraImport::QueueOptions) } + it { expect(described_class).to include_module(Gitlab::Import::DatabaseHelpers) } + end + + subject { described_class.new } + + describe '#perform', :clean_gitlab_redis_cache do + let(:issue_attrs) { build(:issue, project_id: project.id).as_json.compact } + + context 'when any exception raised while inserting to DB' do + before do + allow(subject).to receive(:insert_and_return_id).and_raise(StandardError) + expect(Gitlab::JobWaiter).to receive(:notify) + + subject.perform(project.id, 123, issue_attrs, 'some-key') + end + + it 'record a failed to import issue' do + expect(Gitlab::Cache::Import::Caching.read(Gitlab::JiraImport.failed_issues_counter_cache_key(project.id)).to_i).to eq(1) + end + end + + context 'when record is successfully inserted' do + before do + subject.perform(project.id, 123, issue_attrs, 'some-key') + end + + it 'does not record import failure' do + expect(Gitlab::Cache::Import::Caching.read(Gitlab::JiraImport.failed_issues_counter_cache_key(project.id)).to_i).to eq(0) + end + end + end +end diff --git a/spec/workers/gitlab/jira_import/stage/finish_import_worker_spec.rb b/spec/workers/gitlab/jira_import/stage/finish_import_worker_spec.rb index fa0c7d83851..00505226212 100644 --- a/spec/workers/gitlab/jira_import/stage/finish_import_worker_spec.rb +++ b/spec/workers/gitlab/jira_import/stage/finish_import_worker_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' describe Gitlab::JiraImport::Stage::FinishImportWorker do - let(:project) { create(:project) } - let(:worker) { described_class.new } + let_it_be(:project) { create(:project) } + let_it_be(:worker) { described_class.new } describe 'modules' do it_behaves_like 'include import workers modules' @@ -46,7 +46,7 @@ describe Gitlab::JiraImport::Stage::FinishImportWorker do it 'changes import state to finished' do worker.perform(project.id) - expect(project.reload.import_state.status).to eq "finished" + expect(project.reload.import_state.status).to eq("finished") end it 'removes force-import flag' do diff --git a/spec/workers/gitlab/jira_import/stage/import_attachments_worker_spec.rb b/spec/workers/gitlab/jira_import/stage/import_attachments_worker_spec.rb index fa2f3501973..513925507a1 100644 --- a/spec/workers/gitlab/jira_import/stage/import_attachments_worker_spec.rb +++ b/spec/workers/gitlab/jira_import/stage/import_attachments_worker_spec.rb @@ -3,8 +3,7 @@ require 'spec_helper' describe Gitlab::JiraImport::Stage::ImportAttachmentsWorker do - let(:project) { create(:project) } - let(:worker) { described_class.new } + let_it_be(:project) { create(:project) } describe 'modules' do it_behaves_like 'include import workers modules' diff --git a/spec/workers/gitlab/jira_import/stage/import_issues_worker_spec.rb b/spec/workers/gitlab/jira_import/stage/import_issues_worker_spec.rb index b43519a3e5d..dca748a6ebc 100644 --- a/spec/workers/gitlab/jira_import/stage/import_issues_worker_spec.rb +++ b/spec/workers/gitlab/jira_import/stage/import_issues_worker_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' describe Gitlab::JiraImport::Stage::ImportIssuesWorker do - let(:project) { create(:project) } - let(:worker) { described_class.new } + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project) } describe 'modules' do it_behaves_like 'include import workers modules' @@ -30,10 +30,49 @@ describe Gitlab::JiraImport::Stage::ImportIssuesWorker do it_behaves_like 'exit import not started' end - context 'when import started' do + context 'when import started', :clean_gitlab_redis_cache do + let(:jira_import_data) do + data = JiraImportData.new + data << JiraImportData::JiraProjectDetails.new('XX', Time.now.strftime('%Y-%m-%d %H:%M:%S'), { user_id: user.id, name: user.name }) + data + end + let(:project) { create(:project, import_data: jira_import_data) } + let!(:jira_service) { create(:jira_service, project: project) } let!(:import_state) { create(:import_state, status: :started, project: project) } - it_behaves_like 'advance to next stage', :attachments + before do + allow_next_instance_of(Gitlab::JiraImport::IssuesImporter) do |instance| + allow(instance).to receive(:fetch_issues).and_return([]) + end + end + + context 'when start_at is nil' do + it_behaves_like 'advance to next stage', :attachments + end + + context 'when start_at is zero' do + before do + allow(Gitlab::Cache::Import::Caching).to receive(:read).and_return(0) + end + + it_behaves_like 'advance to next stage', :issues + end + + context 'when start_at is greater than zero' do + before do + allow(Gitlab::Cache::Import::Caching).to receive(:read).and_return(25) + end + + it_behaves_like 'advance to next stage', :issues + end + + context 'when start_at is below zero' do + before do + allow(Gitlab::Cache::Import::Caching).to receive(:read).and_return(-1) + end + + it_behaves_like 'advance to next stage', :attachments + end end end end diff --git a/spec/workers/gitlab/jira_import/stage/import_labels_worker_spec.rb b/spec/workers/gitlab/jira_import/stage/import_labels_worker_spec.rb index 827efb85a17..2b156e0f489 100644 --- a/spec/workers/gitlab/jira_import/stage/import_labels_worker_spec.rb +++ b/spec/workers/gitlab/jira_import/stage/import_labels_worker_spec.rb @@ -3,8 +3,7 @@ require 'spec_helper' describe Gitlab::JiraImport::Stage::ImportLabelsWorker do - let(:project) { create(:project) } - let(:worker) { described_class.new } + let_it_be(:project) { create(:project) } describe 'modules' do it_behaves_like 'include import workers modules' diff --git a/spec/workers/gitlab/jira_import/stage/import_notes_worker_spec.rb b/spec/workers/gitlab/jira_import/stage/import_notes_worker_spec.rb index bd6b36613cc..7d1c29614e4 100644 --- a/spec/workers/gitlab/jira_import/stage/import_notes_worker_spec.rb +++ b/spec/workers/gitlab/jira_import/stage/import_notes_worker_spec.rb @@ -3,8 +3,7 @@ require 'spec_helper' describe Gitlab::JiraImport::Stage::ImportNotesWorker do - let(:project) { create(:project) } - let(:worker) { described_class.new } + let_it_be(:project) { create(:project) } describe 'modules' do it_behaves_like 'include import workers modules' diff --git a/spec/workers/gitlab/jira_import/stage/start_import_worker_spec.rb b/spec/workers/gitlab/jira_import/stage/start_import_worker_spec.rb index cc70277384d..d5e10a950bb 100644 --- a/spec/workers/gitlab/jira_import/stage/start_import_worker_spec.rb +++ b/spec/workers/gitlab/jira_import/stage/start_import_worker_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Gitlab::JiraImport::Stage::StartImportWorker do - let(:project) { create(:project) } + let(:project) { create(:project, import_type: 'jira') } let(:worker) { described_class.new } let(:jid) { '12345678' } @@ -24,13 +24,19 @@ describe Gitlab::JiraImport::Stage::StartImportWorker do end end - context 'when feature flag not enabled' do + context 'when feature flag enabled' do + let(:symbol_keys_project) do + { key: 'AA', scheduled_at: 2.days.ago.strftime('%Y-%m-%d %H:%M:%S'), scheduled_by: { 'user_id' => 1, 'name' => 'tester1' } } + end + let(:import_data) { JiraImportData.new( data: { 'jira' => { JiraImportData::FORCE_IMPORT_KEY => true, projects: [symbol_keys_project] } }) } + before do stub_feature_flags(jira_issue_import: true) end - context 'when import is not scheudled' do - let!(:import_state) { create(:import_state, project: project, status: :none, jid: jid) } + context 'when import is not scheduled' do + let(:project) { create(:project, import_type: 'jira') } + let(:import_state) { create(:import_state, project: project, status: :none, jid: jid) } it 'exits because import not started' do expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).not_to receive(:perform_async) @@ -40,17 +46,32 @@ describe Gitlab::JiraImport::Stage::StartImportWorker do end context 'when import is scheduled' do - let!(:import_state) { create(:import_state, project: project, status: :scheduled, jid: jid) } + let(:import_state) { create(:import_state, status: :scheduled, jid: jid) } + let(:project) { create(:project, import_type: 'jira', import_state: import_state) } - it 'advances to importing labels' do - expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).to receive(:perform_async) + context 'when this is a mirror sync in a jira imported project' do + it 'exits early' do + expect(Gitlab::Import::SetAsyncJid).not_to receive(:set_jid) + expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).not_to receive(:perform_async) - worker.perform(project.id) + worker.perform(project.id) + end + end + + context 'when scheduled import is a hard triggered jira import and not a mirror' do + let!(:project) { create(:project, import_type: 'jira', import_data: import_data, import_state: import_state) } + + it 'advances to importing labels' do + expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).to receive(:perform_async) + + worker.perform(project.id) + end end end context 'when import is started' do - let!(:import_state) { create(:import_state, project: project, status: :started, jid: jid) } + let!(:import_state) { create(:import_state, status: :started, jid: jid) } + let!(:project) { create(:project, import_type: 'jira', import_data: import_data, import_state: import_state) } context 'when this is the same worker that stated import' do it 'advances to importing labels' do @@ -72,7 +93,8 @@ describe Gitlab::JiraImport::Stage::StartImportWorker do end context 'when import is finished' do - let!(:import_state) { create(:import_state, project: project, status: :finished, jid: jid) } + let!(:import_state) { create(:import_state, status: :finished, jid: jid) } + let!(:project) { create(:project, import_type: 'jira', import_data: import_data, import_state: import_state) } it 'advances to importing labels' do allow(worker).to receive(:jid).and_return(jid) diff --git a/spec/workers/reactive_caching_worker_spec.rb b/spec/workers/reactive_caching_worker_spec.rb index 6c74c4ea072..c39a97b4eee 100644 --- a/spec/workers/reactive_caching_worker_spec.rb +++ b/spec/workers/reactive_caching_worker_spec.rb @@ -28,4 +28,14 @@ describe ReactiveCachingWorker do end end end + + describe 'worker context' do + it 'sets the related class on the job' do + described_class.perform_async('Environment', 1, 'other', 'argument') + + scheduled_job = described_class.jobs.first + + expect(scheduled_job).to include('meta.related_class' => 'Environment') + end + end end |