summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-03-26 12:07:48 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-03-26 12:07:48 +0000
commitef31adeb0fb9a02b2c6a4529ec4e38d7082a4b2b (patch)
treef0ee2b8bdffd7f91ad0b31388562c90825179585 /spec
parent7e019504f5ac6decde690565857238e7e59aa034 (diff)
downloadgitlab-ce-ef31adeb0fb9a02b2c6a4529ec4e38d7082a4b2b.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/admin/sessions_controller_spec.rb42
-rw-r--r--spec/graphql/resolvers/projects/jira_imports_resolver_spec.rb78
-rw-r--r--spec/graphql/types/jira_import_type_spec.rb11
-rw-r--r--spec/graphql/types/project_type_spec.rb2
-rw-r--r--spec/lib/gitlab/jira_import/base_importer_spec.rb89
-rw-r--r--spec/lib/gitlab/jira_import/issues_importer_spec.rb110
-rw-r--r--spec/lib/gitlab/jira_import_spec.rb67
-rw-r--r--spec/models/ci/pipeline_spec.rb24
-rw-r--r--spec/models/project_services/bamboo_service_spec.rb17
-rw-r--r--spec/models/project_spec.rb38
-rw-r--r--spec/requests/api/graphql/project/jira_import_spec.rb183
-rw-r--r--spec/support/shared_examples/graphql/jira_import/jira_import_resolved_shared_examples.rb15
-rw-r--r--spec/support/shared_examples/lib/gitlab/jira_import/base_importer_shared_examples.rb5
-rw-r--r--spec/support/shared_examples/workers/gitlab/jira_import/jira_import_workers_shared_examples.rb6
-rw-r--r--spec/workers/gitlab/jira_import/import_issue_worker_spec.rb44
-rw-r--r--spec/workers/gitlab/jira_import/stage/finish_import_worker_spec.rb6
-rw-r--r--spec/workers/gitlab/jira_import/stage/import_attachments_worker_spec.rb3
-rw-r--r--spec/workers/gitlab/jira_import/stage/import_issues_worker_spec.rb47
-rw-r--r--spec/workers/gitlab/jira_import/stage/import_labels_worker_spec.rb3
-rw-r--r--spec/workers/gitlab/jira_import/stage/import_notes_worker_spec.rb3
-rw-r--r--spec/workers/gitlab/jira_import/stage/start_import_worker_spec.rb42
-rw-r--r--spec/workers/reactive_caching_worker_spec.rb10
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