From 1363ca12f1f07c634647cf55c4c16b7401098673 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 18 Mar 2020 12:09:13 +0000 Subject: Add latest changes from gitlab-org/gitlab@master --- .../repository/components/table/row_spec.js | 5 +- spec/helpers/blob_helper_spec.rb | 73 +++++------ .../gitlab/ci/pipeline/seed/build/cache_spec.rb | 10 -- spec/models/ci/group_variable_spec.rb | 2 +- spec/models/ci/variable_spec.rb | 2 +- spec/models/concerns/ci/has_variable_spec.rb | 65 ++++++++++ spec/models/concerns/ci/maskable_spec.rb | 76 ++++++++++++ spec/models/concerns/has_variable_spec.rb | 65 ---------- spec/models/concerns/maskable_spec.rb | 76 ------------ spec/models/jira_import_data_spec.rb | 134 +++++++++++++++++++++ spec/models/project_spec.rb | 57 +++++++++ spec/services/milestones/transfer_service_spec.rb | 10 ++ .../models/ci_variable_shared_examples.rb | 2 +- .../jira_import_workers_shared_examples.rb | 32 +++++ .../jira_import/stage/finish_import_worker_spec.rb | 63 ++++++++++ .../stage/import_attachments_worker_spec.rb | 40 ++++++ .../jira_import/stage/import_issues_worker_spec.rb | 40 ++++++ .../jira_import/stage/import_labels_worker_spec.rb | 40 ++++++ .../jira_import/stage/import_notes_worker_spec.rb | 40 ++++++ .../jira_import/stage/start_import_worker_spec.rb | 86 +++++++++++++ 20 files changed, 729 insertions(+), 189 deletions(-) create mode 100644 spec/models/concerns/ci/has_variable_spec.rb create mode 100644 spec/models/concerns/ci/maskable_spec.rb delete mode 100644 spec/models/concerns/has_variable_spec.rb delete mode 100644 spec/models/concerns/maskable_spec.rb create mode 100644 spec/models/jira_import_data_spec.rb create mode 100644 spec/support/shared_examples/workers/gitlab/jira_import/jira_import_workers_shared_examples.rb create mode 100644 spec/workers/gitlab/jira_import/stage/finish_import_worker_spec.rb create mode 100644 spec/workers/gitlab/jira_import/stage/import_attachments_worker_spec.rb create mode 100644 spec/workers/gitlab/jira_import/stage/import_issues_worker_spec.rb create mode 100644 spec/workers/gitlab/jira_import/stage/import_labels_worker_spec.rb create mode 100644 spec/workers/gitlab/jira_import/stage/import_notes_worker_spec.rb create mode 100644 spec/workers/gitlab/jira_import/stage/start_import_worker_spec.rb (limited to 'spec') diff --git a/spec/frontend/repository/components/table/row_spec.js b/spec/frontend/repository/components/table/row_spec.js index a51846023ac..22aacdc735c 100644 --- a/spec/frontend/repository/components/table/row_spec.js +++ b/spec/frontend/repository/components/table/row_spec.js @@ -4,7 +4,10 @@ import { visitUrl } from '~/lib/utils/url_utility'; import TableRow from '~/repository/components/table/row.vue'; import Icon from '~/vue_shared/components/icon.vue'; -jest.mock('~/lib/utils/url_utility'); +jest.mock('~/lib/utils/url_utility', () => ({ + ...jest.requireActual('~/lib/utils/url_utility'), + visitUrl: jest.fn(), +})); let vm; let $router; diff --git a/spec/helpers/blob_helper_spec.rb b/spec/helpers/blob_helper_spec.rb index dec7d6b2df3..2631c219222 100644 --- a/spec/helpers/blob_helper_spec.rb +++ b/spec/helpers/blob_helper_spec.rb @@ -204,7 +204,6 @@ describe BlobHelper do end describe '#show_suggest_pipeline_creation_celebration?' do - let(:blob) { fake_blob(path: Gitlab::FileDetector::PATTERNS[:gitlab_ci]) } let(:current_user) { create(:user) } before do @@ -212,52 +211,68 @@ describe BlobHelper do assign(:blob, blob) assign(:commit, double('Commit', sha: 'whatever')) helper.request.cookies["suggest_gitlab_ci_yml_commit_#{project.id}"] = 'true' - allow(blob).to receive(:auxiliary_viewer).and_return(double('viewer', valid?: true)) allow(helper).to receive(:current_user).and_return(current_user) end - context 'experiment enabled' do - before do - allow(helper).to receive(:experiment_enabled?).and_return(true) - end - - it 'is true' do - expect(helper.show_suggest_pipeline_creation_celebration?).to be_truthy - end + context 'when file is a pipeline config file' do + let(:data) { File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml')) } + let(:blob) { fake_blob(path: Gitlab::FileDetector::PATTERNS[:gitlab_ci], data: data) } - context 'file is invalid format' do + context 'experiment enabled' do before do - allow(blob).to receive(:auxiliary_viewer).and_return(double('viewer', valid?: false)) + allow(helper).to receive(:experiment_enabled?).and_return(true) end - it 'is false' do - expect(helper.show_suggest_pipeline_creation_celebration?).to be_falsey + it 'is true' do + expect(helper.show_suggest_pipeline_creation_celebration?).to be_truthy end - end - context 'path is not a ci file' do - before do - allow(blob).to receive(:path).and_return('something_bad') + context 'file is invalid format' do + let(:data) { 'foo' } + + it 'is false' do + expect(helper.show_suggest_pipeline_creation_celebration?).to be_falsey + end end - it 'is false' do - expect(helper.show_suggest_pipeline_creation_celebration?).to be_falsey + context 'does not use the default ci config' do + before do + project.ci_config_path = 'something_bad' + end + + it 'is false' do + expect(helper.show_suggest_pipeline_creation_celebration?).to be_falsey + end + end + + context 'does not have the needed cookie' do + before do + helper.request.cookies.delete "suggest_gitlab_ci_yml_commit_#{project.id}" + end + + it 'is false' do + expect(helper.show_suggest_pipeline_creation_celebration?).to be_falsey + end end end - context 'does not use the default ci config' do + context 'experiment disabled' do before do - project.ci_config_path = 'something_bad' + allow(helper).to receive(:experiment_enabled?).and_return(false) end it 'is false' do expect(helper.show_suggest_pipeline_creation_celebration?).to be_falsey end end + end - context 'does not have the needed cookie' do + context 'when file is not a pipeline config file' do + let(:blob) { fake_blob(path: 'LICENSE') } + + context 'experiment enabled' do before do - helper.request.cookies.delete "suggest_gitlab_ci_yml_commit_#{project.id}" + allow(helper).to receive(:experiment_enabled?).and_return(true) end it 'is false' do @@ -265,16 +280,6 @@ describe BlobHelper do end end end - - context 'experiment disabled' do - before do - allow(helper).to receive(:experiment_enabled?).and_return(false) - end - - it 'is false' do - expect(helper.show_suggest_pipeline_creation_celebration?).to be_falsey - end - end end end diff --git a/spec/lib/gitlab/ci/pipeline/seed/build/cache_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build/cache_spec.rb index 6a8b804597c..fe19244659f 100644 --- a/spec/lib/gitlab/ci/pipeline/seed/build/cache_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/seed/build/cache_spec.rb @@ -83,16 +83,6 @@ describe Gitlab::Ci::Pipeline::Seed::Build::Cache do it_behaves_like 'version and gemfile files' end - context 'with feature flag disabled' do - let(:files) { ['VERSION', 'Gemfile.zip'] } - - before do - stub_feature_flags(ci_file_based_cache: false) - end - - it_behaves_like 'default key' - end - context 'with files ending with /' do let(:files) { ['Gemfile.zip/'] } diff --git a/spec/models/ci/group_variable_spec.rb b/spec/models/ci/group_variable_spec.rb index 406a69f3bbc..610db9bf0e5 100644 --- a/spec/models/ci/group_variable_spec.rb +++ b/spec/models/ci/group_variable_spec.rb @@ -8,7 +8,7 @@ describe Ci::GroupVariable do it_behaves_like "CI variable" it { is_expected.to include_module(Presentable) } - it { is_expected.to include_module(Maskable) } + it { is_expected.to include_module(Ci::Maskable) } it { is_expected.to validate_uniqueness_of(:key).scoped_to(:group_id).with_message(/\(\w+\) has already been taken/) } describe '.unprotected' do diff --git a/spec/models/ci/variable_spec.rb b/spec/models/ci/variable_spec.rb index 3ff547456c6..810a0ddfd2e 100644 --- a/spec/models/ci/variable_spec.rb +++ b/spec/models/ci/variable_spec.rb @@ -9,7 +9,7 @@ describe Ci::Variable do describe 'validations' do it { is_expected.to include_module(Presentable) } - it { is_expected.to include_module(Maskable) } + it { is_expected.to include_module(Ci::Maskable) } it { is_expected.to include_module(HasEnvironmentScope) } it { is_expected.to validate_uniqueness_of(:key).scoped_to(:project_id, :environment_scope).with_message(/\(\w+\) has already been taken/) } end diff --git a/spec/models/concerns/ci/has_variable_spec.rb b/spec/models/concerns/ci/has_variable_spec.rb new file mode 100644 index 00000000000..c132fe47c3c --- /dev/null +++ b/spec/models/concerns/ci/has_variable_spec.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Ci::HasVariable do + subject { build(:ci_variable) } + + it { is_expected.to validate_presence_of(:key) } + it { is_expected.to validate_length_of(:key).is_at_most(255) } + it { is_expected.to allow_value('foo').for(:key) } + it { is_expected.not_to allow_value('foo bar').for(:key) } + it { is_expected.not_to allow_value('foo/bar').for(:key) } + + describe '#key=' do + context 'when the new key is nil' do + it 'strips leading and trailing whitespaces' do + subject.key = nil + + expect(subject.key).to eq('') + end + end + + context 'when the new key has leadind and trailing whitespaces' do + it 'strips leading and trailing whitespaces' do + subject.key = ' my key ' + + expect(subject.key).to eq('my key') + end + end + end + + describe '#value' do + before do + subject.value = 'secret' + end + + it 'stores the encrypted value' do + expect(subject.encrypted_value).not_to be_nil + end + + it 'stores an iv for value' do + expect(subject.encrypted_value_iv).not_to be_nil + end + + it 'stores a salt for value' do + expect(subject.encrypted_value_salt).not_to be_nil + end + + it 'fails to decrypt if iv is incorrect' do + # attr_encrypted expects the IV to be 16 bytes and base64-encoded + subject.encrypted_value_iv = [SecureRandom.hex(8)].pack('m') + subject.instance_variable_set(:@value, nil) + + expect { subject.value } + .to raise_error(OpenSSL::Cipher::CipherError, 'bad decrypt') + end + end + + describe '#to_runner_variable' do + it 'returns a hash for the runner' do + expect(subject.to_runner_variable) + .to include(key: subject.key, value: subject.value, public: false) + end + end +end diff --git a/spec/models/concerns/ci/maskable_spec.rb b/spec/models/concerns/ci/maskable_spec.rb new file mode 100644 index 00000000000..22ffb294819 --- /dev/null +++ b/spec/models/concerns/ci/maskable_spec.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Ci::Maskable do + let(:variable) { build(:ci_variable) } + + describe 'masked value validations' do + subject { variable } + + context 'when variable is masked' do + before do + subject.masked = true + end + + it { is_expected.not_to allow_value('hello').for(:value) } + it { is_expected.not_to allow_value('hello world').for(:value) } + it { is_expected.not_to allow_value('hello$VARIABLEworld').for(:value) } + it { is_expected.not_to allow_value('hello\rworld').for(:value) } + it { is_expected.to allow_value('helloworld').for(:value) } + end + + context 'when variable is not masked' do + before do + subject.masked = false + end + + it { is_expected.to allow_value('hello').for(:value) } + it { is_expected.to allow_value('hello world').for(:value) } + it { is_expected.to allow_value('hello$VARIABLEworld').for(:value) } + it { is_expected.to allow_value('hello\rworld').for(:value) } + it { is_expected.to allow_value('helloworld').for(:value) } + end + end + + describe 'REGEX' do + subject { Ci::Maskable::REGEX } + + it 'does not match strings shorter than 8 letters' do + expect(subject.match?('hello')).to eq(false) + end + + it 'does not match strings with spaces' do + expect(subject.match?('hello world')).to eq(false) + end + + it 'does not match strings with shell variables' do + expect(subject.match?('hello$VARIABLEworld')).to eq(false) + end + + it 'does not match strings with escape characters' do + expect(subject.match?('hello\rworld')).to eq(false) + end + + it 'does not match strings that span more than one line' do + string = <<~EOS + hello + world + EOS + + expect(subject.match?(string)).to eq(false) + end + + it 'matches valid strings' do + expect(subject.match?('helloworld')).to eq(true) + end + end + + describe '#to_runner_variable' do + subject { variable.to_runner_variable } + + it 'exposes the masked attribute' do + expect(subject).to include(:masked) + end + end +end diff --git a/spec/models/concerns/has_variable_spec.rb b/spec/models/concerns/has_variable_spec.rb deleted file mode 100644 index 2bb21d7934e..00000000000 --- a/spec/models/concerns/has_variable_spec.rb +++ /dev/null @@ -1,65 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe HasVariable do - subject { build(:ci_variable) } - - it { is_expected.to validate_presence_of(:key) } - it { is_expected.to validate_length_of(:key).is_at_most(255) } - it { is_expected.to allow_value('foo').for(:key) } - it { is_expected.not_to allow_value('foo bar').for(:key) } - it { is_expected.not_to allow_value('foo/bar').for(:key) } - - describe '#key=' do - context 'when the new key is nil' do - it 'strips leading and trailing whitespaces' do - subject.key = nil - - expect(subject.key).to eq('') - end - end - - context 'when the new key has leadind and trailing whitespaces' do - it 'strips leading and trailing whitespaces' do - subject.key = ' my key ' - - expect(subject.key).to eq('my key') - end - end - end - - describe '#value' do - before do - subject.value = 'secret' - end - - it 'stores the encrypted value' do - expect(subject.encrypted_value).not_to be_nil - end - - it 'stores an iv for value' do - expect(subject.encrypted_value_iv).not_to be_nil - end - - it 'stores a salt for value' do - expect(subject.encrypted_value_salt).not_to be_nil - end - - it 'fails to decrypt if iv is incorrect' do - # attr_encrypted expects the IV to be 16 bytes and base64-encoded - subject.encrypted_value_iv = [SecureRandom.hex(8)].pack('m') - subject.instance_variable_set(:@value, nil) - - expect { subject.value } - .to raise_error(OpenSSL::Cipher::CipherError, 'bad decrypt') - end - end - - describe '#to_runner_variable' do - it 'returns a hash for the runner' do - expect(subject.to_runner_variable) - .to include(key: subject.key, value: subject.value, public: false) - end - end -end diff --git a/spec/models/concerns/maskable_spec.rb b/spec/models/concerns/maskable_spec.rb deleted file mode 100644 index aeba7ad862f..00000000000 --- a/spec/models/concerns/maskable_spec.rb +++ /dev/null @@ -1,76 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe Maskable do - let(:variable) { build(:ci_variable) } - - describe 'masked value validations' do - subject { variable } - - context 'when variable is masked' do - before do - subject.masked = true - end - - it { is_expected.not_to allow_value('hello').for(:value) } - it { is_expected.not_to allow_value('hello world').for(:value) } - it { is_expected.not_to allow_value('hello$VARIABLEworld').for(:value) } - it { is_expected.not_to allow_value('hello\rworld').for(:value) } - it { is_expected.to allow_value('helloworld').for(:value) } - end - - context 'when variable is not masked' do - before do - subject.masked = false - end - - it { is_expected.to allow_value('hello').for(:value) } - it { is_expected.to allow_value('hello world').for(:value) } - it { is_expected.to allow_value('hello$VARIABLEworld').for(:value) } - it { is_expected.to allow_value('hello\rworld').for(:value) } - it { is_expected.to allow_value('helloworld').for(:value) } - end - end - - describe 'REGEX' do - subject { Maskable::REGEX } - - it 'does not match strings shorter than 8 letters' do - expect(subject.match?('hello')).to eq(false) - end - - it 'does not match strings with spaces' do - expect(subject.match?('hello world')).to eq(false) - end - - it 'does not match strings with shell variables' do - expect(subject.match?('hello$VARIABLEworld')).to eq(false) - end - - it 'does not match strings with escape characters' do - expect(subject.match?('hello\rworld')).to eq(false) - end - - it 'does not match strings that span more than one line' do - string = <<~EOS - hello - world - EOS - - expect(subject.match?(string)).to eq(false) - end - - it 'matches valid strings' do - expect(subject.match?('helloworld')).to eq(true) - end - end - - describe '#to_runner_variable' do - subject { variable.to_runner_variable } - - it 'exposes the masked attribute' do - expect(subject).to include(:masked) - end - end -end diff --git a/spec/models/jira_import_data_spec.rb b/spec/models/jira_import_data_spec.rb new file mode 100644 index 00000000000..ad7a704236b --- /dev/null +++ b/spec/models/jira_import_data_spec.rb @@ -0,0 +1,134 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe JiraImportData 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(:string_keys_project) do + { 'key': 'BB', 'scheduled_at': 1.hour.ago.strftime('%Y-%m-%d %H:%M:%S'), 'scheduled_by': { 'user_id': 2, 'name': 'tester2' } } + end + + let(:jira_project_details) do + JiraImportData::JiraProjectDetails.new('CC', 1.day.ago.strftime('%Y-%m-%d %H:%M:%S'), { user_id: 3, name: 'tester3' }) + end + + describe '#projects' do + it 'returns empty array if no data' do + expect(described_class.new.projects).to eq([]) + end + + it 'returns empty array if no projects' do + import_data = described_class.new(data: { 'some-key' => 10 }) + expect(import_data.projects).to eq([]) + end + + it 'returns JiraProjectDetails sorted by scheduled_at time' do + import_data = described_class.new(data: { jira: { projects: [symbol_keys_project, string_keys_project, jira_project_details] } }) + + expect(import_data.projects.size).to eq 3 + expect(import_data.projects.map(&:key)).to eq(%w(AA CC BB)) + expect(import_data.projects.map(&:scheduled_by).map {|e| e['name']}).to eq %w(tester1 tester3 tester2) + expect(import_data.projects.map(&:scheduled_by).map {|e| e['user_id']}).to eq [1, 3, 2] + end + end + + describe 'add projects' do + it 'adds project when data is nil' do + import_data = described_class.new + expect(import_data.data).to be nil + + import_data << string_keys_project + + expect(import_data.data).to eq({ 'jira' => { 'projects' => [string_keys_project] } }) + end + + it 'adds project when data has some random info' do + import_data = described_class.new(data: { 'one-key': 10 }) + expect(import_data.data).to eq({ 'one-key' => 10 }) + + import_data << string_keys_project + + expect(import_data.data).to eq({ 'one-key' => 10, 'jira' => { 'projects' => [string_keys_project] } }) + end + + it 'adds project when data already has some jira projects' do + import_data = described_class.new(data: { jira: { projects: [symbol_keys_project] } }) + expect(import_data.projects.map(&:to_h)).to eq [symbol_keys_project] + + import_data << string_keys_project + + expect(import_data.data['jira']['projects'].size).to eq 2 + expect(import_data.projects.map(&:key)).to eq(%w(AA BB)) + expect(import_data.projects.map(&:scheduled_by).map {|e| e['name']}).to eq %w(tester1 tester2) + expect(import_data.projects.map(&:scheduled_by).map {|e| e['user_id']}).to eq [1, 2] + end + end + + describe '#force_import!' do + it 'sets force import when data is nil' do + import_data = described_class.new + + import_data.force_import! + + expect(import_data.data['jira'][JiraImportData::FORCE_IMPORT_KEY]).to be true + expect(import_data.force_import?).to be false + end + + it 'sets force import when data is present but no jira key' do + import_data = described_class.new(data: { 'some-key': 'some-data' }) + + import_data.force_import! + + expect(import_data.data['jira'][JiraImportData::FORCE_IMPORT_KEY]).to be true + expect(import_data.data).to eq({ 'some-key' => 'some-data', 'jira' => { JiraImportData::FORCE_IMPORT_KEY => true } }) + expect(import_data.force_import?).to be false + end + + it 'sets force import when data and jira keys exist' do + import_data = described_class.new(data: { 'some-key': 'some-data', 'jira': {} }) + + import_data.force_import! + + expect(import_data.data['jira'][JiraImportData::FORCE_IMPORT_KEY]).to be true + expect(import_data.data).to eq({ 'some-key' => 'some-data', 'jira' => { JiraImportData::FORCE_IMPORT_KEY => true } }) + expect(import_data.force_import?).to be false + end + + it 'sets force import when data and jira project data exist' do + import_data = described_class.new(data: { jira: { projects: [symbol_keys_project], JiraImportData::FORCE_IMPORT_KEY => false }, 'some-key': 'some-data' }) + + import_data.force_import! + + expect(import_data.data['jira'][JiraImportData::FORCE_IMPORT_KEY]).to be true + expect(import_data.data).to eq({ 'some-key' => 'some-data', 'jira' => { 'projects' => [symbol_keys_project.deep_stringify_keys!], JiraImportData::FORCE_IMPORT_KEY => true } }) + expect(import_data.force_import?).to be true + end + end + + describe '#force_import?' do + it 'returns false when data blank' do + expect(described_class.new.force_import?).to be false + end + + it 'returns false if there is no project data present' do + import_data = described_class.new(data: { jira: { JiraImportData::FORCE_IMPORT_KEY => true }, 'one-key': 10 }) + + expect(import_data.force_import?).to be false + end + + it 'returns false when force import set to false' do + import_data = described_class.new(data: { jira: { projects: [symbol_keys_project], JiraImportData::FORCE_IMPORT_KEY => false }, 'one-key': 10 }) + + expect(import_data.force_import?).to be false + end + + it 'returns true when force import set to true' do + import_data = described_class.new(data: { jira: { projects: [symbol_keys_project], JiraImportData::FORCE_IMPORT_KEY => true } }) + + expect(import_data.force_import?).to be true + end + end +end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index ae97e5340e2..15b409b2dcf 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -2353,6 +2353,63 @@ describe Project do expect(project.add_import_job).to eq(import_jid) end end + + context 'jira import' do + it 'schedules a jira import job' do + project = create(:project, import_type: 'jira') + + expect(Gitlab::JiraImport::Stage::StartImportWorker).to receive(:perform_async).with(project.id).and_return(import_jid) + expect(project.add_import_job).to eq(import_jid) + end + end + end + + describe '#jira_import?' do + subject(:project) { build(:project, import_type: 'jira') } + + it { expect(project.jira_import?).to be true } + it { expect(project.import?).to be true } + end + + describe '#jira_force_import?' 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 + let(:jira_import_data) do + data = JiraImportData.new + data << imported_jira_project + data.force_import! + data + end + + subject(:project) { build(:project, import_type: 'jira', import_data: jira_import_data) } + + it { expect(project.jira_force_import?).to be true } + end + + describe '#remove_import_data' do + let(:import_data) { ProjectImportData.new(data: { 'test' => 'some data' }) } + + context 'when jira import' do + let!(:project) { create(:project, import_type: 'jira', import_data: import_data) } + + it 'does not remove import data' do + expect(project.mirror?).to be false + expect(project.jira_import?).to be true + expect { project.remove_import_data }.not_to change { ProjectImportData.count } + end + end + + context 'when not mirror neither jira import' do + let(:user) { create(:user) } + let!(:project) { create(:project, import_type: 'github', import_data: import_data) } + + it 'removes import data' do + expect(project.mirror?).to be false + expect(project.jira_import?).to be false + expect { project.remove_import_data }.to change { ProjectImportData.count }.by(-1) + end + end end describe '#gitlab_project_import?' do diff --git a/spec/services/milestones/transfer_service_spec.rb b/spec/services/milestones/transfer_service_spec.rb index 9b087b07cea..9f94d2d320b 100644 --- a/spec/services/milestones/transfer_service_spec.rb +++ b/spec/services/milestones/transfer_service_spec.rb @@ -40,6 +40,16 @@ describe Milestones::TransferService do expect(new_milestone.project_milestone?).to be_truthy end + context 'when milestone is from an ancestor group' do + let(:old_group_ancestor) { create(:group) } + let(:old_group) { create(:group, parent: old_group_ancestor) } + let(:group_milestone) { create(:milestone, group: old_group_ancestor)} + + it 'recreates the missing group milestones at project level' do + expect { service.execute }.to change(project.milestones, :count).by(1) + end + end + it 'deletes milestone issue counters cache for both milestones' do new_milestone = create(:milestone, project: project, title: group_milestone.title) diff --git a/spec/support/shared_examples/models/ci_variable_shared_examples.rb b/spec/support/shared_examples/models/ci_variable_shared_examples.rb index 6cc922b4101..e5463f26369 100644 --- a/spec/support/shared_examples/models/ci_variable_shared_examples.rb +++ b/spec/support/shared_examples/models/ci_variable_shared_examples.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true RSpec.shared_examples 'CI variable' do - it { is_expected.to include_module(HasVariable) } + it { is_expected.to include_module(Ci::HasVariable) } describe "variable type" do it 'defines variable types' do 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 new file mode 100644 index 00000000000..5448526f954 --- /dev/null +++ b/spec/support/shared_examples/workers/gitlab/jira_import/jira_import_workers_shared_examples.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +shared_examples 'include import workers modules' do + it { expect(described_class).to include_module(ApplicationWorker) } + it { expect(described_class).to include_module(Gitlab::JiraImport::QueueOptions) } + + if described_class == Gitlab::JiraImport::Stage::StartImportWorker + it { expect(described_class).to include_module(ProjectStartImport) } + it { expect(described_class).to include_module(ProjectImportOptions) } + else + it { expect(described_class).to include_module(Gitlab::JiraImport::ImportWorker) } + end +end + +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) + end +end + +shared_examples 'advance to next stage' do |next_stage| + let(:job_waiter) { Gitlab::JobWaiter.new(2, 'some-job-key') } + + 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) + + worker.perform(project.id) + 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 new file mode 100644 index 00000000000..fa0c7d83851 --- /dev/null +++ b/spec/workers/gitlab/jira_import/stage/finish_import_worker_spec.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::JiraImport::Stage::FinishImportWorker do + let(:project) { create(:project) } + let(:worker) { described_class.new } + + describe 'modules' do + it_behaves_like 'include import workers modules' + end + + describe '#perform' do + context 'when feature flag enabled' do + before do + stub_feature_flags(jira_issue_import: false) + end + + it_behaves_like 'exit import not started' + end + + context 'when feature flag enabled' do + before do + stub_feature_flags(jira_issue_import: true) + end + + context 'when import did not start' do + let!(:import_state) { create(:import_state, project: project) } + + it_behaves_like 'exit import not started' + end + + context 'when import started' 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 + let(:jira_import_data) do + data = JiraImportData.new + data << imported_jira_project + data.force_import! + data + end + let(:import_state) { create(:import_state, status: :started) } + let(:project) { create(:project, import_type: 'jira', import_data: jira_import_data, import_state: import_state) } + + it 'changes import state to finished' do + worker.perform(project.id) + + expect(project.reload.import_state.status).to eq "finished" + end + + it 'removes force-import flag' do + expect(project.reload.import_data.data['jira'][JiraImportData::FORCE_IMPORT_KEY]).to be true + + worker.perform(project.id) + + expect(project.reload.import_data.data['jira'][JiraImportData::FORCE_IMPORT_KEY]).to be nil + expect(project.reload.import_data.data['jira']).not_to be nil + end + end + end + end +end 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 new file mode 100644 index 00000000000..fa2f3501973 --- /dev/null +++ b/spec/workers/gitlab/jira_import/stage/import_attachments_worker_spec.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::JiraImport::Stage::ImportAttachmentsWorker do + let(:project) { create(:project) } + let(:worker) { described_class.new } + + describe 'modules' do + it_behaves_like 'include import workers modules' + end + + describe '#perform' do + context 'when feature flag enabled' do + before do + stub_feature_flags(jira_issue_import: false) + end + + it_behaves_like 'exit import not started' + end + + context 'when feature flag enabled' do + before do + stub_feature_flags(jira_issue_import: true) + end + + context 'when import did not start' do + let!(:import_state) { create(:import_state, project: project) } + + it_behaves_like 'exit import not started' + end + + context 'when import started' do + let!(:import_state) { create(:import_state, status: :started, project: project) } + + it_behaves_like 'advance to next stage', :notes + end + end + end +end 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 new file mode 100644 index 00000000000..b43519a3e5d --- /dev/null +++ b/spec/workers/gitlab/jira_import/stage/import_issues_worker_spec.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::JiraImport::Stage::ImportIssuesWorker do + let(:project) { create(:project) } + let(:worker) { described_class.new } + + describe 'modules' do + it_behaves_like 'include import workers modules' + end + + describe '#perform' do + context 'when feature flag enabled' do + before do + stub_feature_flags(jira_issue_import: false) + end + + it_behaves_like 'exit import not started' + end + + context 'when feature flag enabled' do + before do + stub_feature_flags(jira_issue_import: true) + end + + context 'when import did not start' do + let!(:import_state) { create(:import_state, project: project) } + + it_behaves_like 'exit import not started' + end + + context 'when import started' do + let!(:import_state) { create(:import_state, status: :started, project: project) } + + 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 new file mode 100644 index 00000000000..827efb85a17 --- /dev/null +++ b/spec/workers/gitlab/jira_import/stage/import_labels_worker_spec.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::JiraImport::Stage::ImportLabelsWorker do + let(:project) { create(:project) } + let(:worker) { described_class.new } + + describe 'modules' do + it_behaves_like 'include import workers modules' + end + + describe '#perform' do + context 'when feature flag enabled' do + before do + stub_feature_flags(jira_issue_import: false) + end + + it_behaves_like 'exit import not started' + end + + context 'when feature flag enabled' do + before do + stub_feature_flags(jira_issue_import: true) + end + + context 'when import did not start' do + let!(:import_state) { create(:import_state, project: project) } + + it_behaves_like 'exit import not started' + end + + context 'when import started' do + let!(:import_state) { create(:import_state, status: :started, project: project) } + + it_behaves_like 'advance to next stage', :issues + end + end + end +end 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 new file mode 100644 index 00000000000..bd6b36613cc --- /dev/null +++ b/spec/workers/gitlab/jira_import/stage/import_notes_worker_spec.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::JiraImport::Stage::ImportNotesWorker do + let(:project) { create(:project) } + let(:worker) { described_class.new } + + describe 'modules' do + it_behaves_like 'include import workers modules' + end + + describe '#perform' do + context 'when feature flag enabled' do + before do + stub_feature_flags(jira_issue_import: false) + end + + it_behaves_like 'exit import not started' + end + + context 'when feature flag enabled' do + before do + stub_feature_flags(jira_issue_import: true) + end + + context 'when import did not start' do + let!(:import_state) { create(:import_state, project: project) } + + it_behaves_like 'exit import not started' + end + + context 'when import started' do + let!(:import_state) { create(:import_state, status: :started, project: project) } + + it_behaves_like 'advance to next stage', :finish + end + end + end +end 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 new file mode 100644 index 00000000000..cc70277384d --- /dev/null +++ b/spec/workers/gitlab/jira_import/stage/start_import_worker_spec.rb @@ -0,0 +1,86 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::JiraImport::Stage::StartImportWorker do + let(:project) { create(:project) } + let(:worker) { described_class.new } + let(:jid) { '12345678' } + + describe 'modules' do + it_behaves_like 'include import workers modules' + end + + describe '#perform' do + context 'when feature flag not enabled' do + before do + stub_feature_flags(jira_issue_import: false) + end + + it 'exits because import not allowed' do + expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).not_to receive(:perform_async) + + worker.perform(project.id) + end + end + + context 'when feature flag not enabled' do + 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) } + + it 'exits because import not started' do + expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).not_to receive(:perform_async) + + worker.perform(project.id) + end + end + + context 'when import is scheduled' do + let!(:import_state) { create(:import_state, project: project, status: :scheduled, jid: jid) } + + it 'advances to importing labels' do + expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).to receive(:perform_async) + + worker.perform(project.id) + end + end + + context 'when import is started' do + let!(:import_state) { create(:import_state, project: project, status: :started, jid: jid) } + + context 'when this is the same worker that stated import' do + it 'advances to importing labels' do + allow(worker).to receive(:jid).and_return(jid) + expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).to receive(:perform_async) + + worker.perform(project.id) + end + end + + context 'when this is a different worker that stated import' do + it 'advances to importing labels' do + allow(worker).to receive(:jid).and_return('87654321') + expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).not_to receive(:perform_async) + + worker.perform(project.id) + end + end + end + + context 'when import is finished' do + let!(:import_state) { create(:import_state, project: project, status: :finished, jid: jid) } + + it 'advances to importing labels' do + allow(worker).to receive(:jid).and_return(jid) + expect(Gitlab::JiraImport::Stage::ImportLabelsWorker).not_to receive(:perform_async) + + worker.perform(project.id) + end + end + end + end +end -- cgit v1.2.3