diff options
Diffstat (limited to 'spec/lib/gitlab/github_import')
20 files changed, 569 insertions, 73 deletions
diff --git a/spec/lib/gitlab/github_import/client_spec.rb b/spec/lib/gitlab/github_import/client_spec.rb index c4d05e92633..2bd3910ad87 100644 --- a/spec/lib/gitlab/github_import/client_spec.rb +++ b/spec/lib/gitlab/github_import/client_spec.rb @@ -208,7 +208,7 @@ RSpec.describe Gitlab::GithubImport::Client do expect(client).to receive(:requests_remaining?).and_return(true) - client.with_rate_limit { } + client.with_rate_limit {} end it 'ignores rate limiting when disabled' do diff --git a/spec/lib/gitlab/github_import/importer/events/base_importer_spec.rb b/spec/lib/gitlab/github_import/importer/events/base_importer_spec.rb new file mode 100644 index 00000000000..41fe5fbdbbd --- /dev/null +++ b/spec/lib/gitlab/github_import/importer/events/base_importer_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::GithubImport::Importer::Events::BaseImporter do + let(:project) { instance_double('Project') } + let(:client) { instance_double('Gitlab::GithubImport::Client') } + let(:issue_event) { instance_double('Gitlab::GithubImport::Representation::IssueEvent') } + let(:importer_class) { Class.new(described_class) } + let(:importer_instance) { importer_class.new(project, client) } + + describe '#execute' do + it { expect { importer_instance.execute(issue_event) }.to raise_error(NotImplementedError) } + end +end diff --git a/spec/lib/gitlab/github_import/importer/events/changed_assignee_spec.rb b/spec/lib/gitlab/github_import/importer/events/changed_assignee_spec.rb new file mode 100644 index 00000000000..2f6f727dc38 --- /dev/null +++ b/spec/lib/gitlab/github_import/importer/events/changed_assignee_spec.rb @@ -0,0 +1,95 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::GithubImport::Importer::Events::ChangedAssignee do + subject(:importer) { described_class.new(project, client) } + + let_it_be(:project) { create(:project, :repository) } + let_it_be(:assignee) { create(:user) } + let_it_be(:assigner) { create(:user) } + + let(:client) { instance_double('Gitlab::GithubImport::Client') } + let(:issue) { create(:issue, project: project) } + + let(:issue_event) do + Gitlab::GithubImport::Representation::IssueEvent.from_json_hash( + 'id' => 6501124486, + 'actor' => { 'id' => 4, 'login' => 'alice' }, + 'event' => event_type, + 'commit_id' => nil, + 'created_at' => '2022-04-26 18:30:53 UTC', + 'assigner' => { 'id' => assigner.id, 'login' => assigner.username }, + 'assignee' => { 'id' => assignee.id, 'login' => assignee.username }, + 'issue' => { 'number' => issue.iid } + ) + end + + let(:note_attrs) do + { + noteable_id: issue.id, + noteable_type: Issue.name, + project_id: project.id, + author_id: assigner.id, + system: true, + created_at: issue_event.created_at, + updated_at: issue_event.created_at + }.stringify_keys + end + + let(:expected_system_note_metadata_attrs) do + { + action: "assignee", + created_at: issue_event.created_at, + updated_at: issue_event.created_at + }.stringify_keys + end + + shared_examples 'new note' do + it 'creates expected note' do + expect { importer.execute(issue_event) }.to change { issue.notes.count } + .from(0).to(1) + + expect(issue.notes.last) + .to have_attributes(expected_note_attrs) + end + + it 'creates expected system note metadata' do + expect { importer.execute(issue_event) }.to change { SystemNoteMetadata.count } + .from(0).to(1) + + expect(SystemNoteMetadata.last) + .to have_attributes( + expected_system_note_metadata_attrs.merge( + note_id: Note.last.id + ) + ) + end + end + + describe '#execute' do + before do + allow_next_instance_of(Gitlab::GithubImport::IssuableFinder) do |finder| + allow(finder).to receive(:database_id).and_return(issue.id) + end + allow_next_instance_of(Gitlab::GithubImport::UserFinder) do |finder| + allow(finder).to receive(:find).with(assignee.id, assignee.username).and_return(assignee.id) + allow(finder).to receive(:find).with(assigner.id, assigner.username).and_return(assigner.id) + end + end + + context 'when importing an assigned event' do + let(:event_type) { 'assigned' } + let(:expected_note_attrs) { note_attrs.merge(note: "assigned to @#{assignee.username}") } + + it_behaves_like 'new note' + end + + context 'when importing an unassigned event' do + let(:event_type) { 'unassigned' } + let(:expected_note_attrs) { note_attrs.merge(note: "unassigned @#{assigner.username}") } + + it_behaves_like 'new note' + end + end +end diff --git a/spec/lib/gitlab/github_import/importer/events/changed_label_spec.rb b/spec/lib/gitlab/github_import/importer/events/changed_label_spec.rb index b773598853d..e21672aa430 100644 --- a/spec/lib/gitlab/github_import/importer/events/changed_label_spec.rb +++ b/spec/lib/gitlab/github_import/importer/events/changed_label_spec.rb @@ -3,23 +3,25 @@ require 'spec_helper' RSpec.describe Gitlab::GithubImport::Importer::Events::ChangedLabel do - subject(:importer) { described_class.new(project, user.id) } + subject(:importer) { described_class.new(project, client) } let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { create(:user) } + let(:client) { instance_double('Gitlab::GithubImport::Client') } let(:issue) { create(:issue, project: project) } let!(:label) { create(:label, project: project) } let(:issue_event) do Gitlab::GithubImport::Representation::IssueEvent.from_json_hash( 'id' => 6501124486, - 'actor' => { 'id' => 4, 'login' => 'alice' }, + 'actor' => { 'id' => user.id, 'login' => user.username }, 'event' => event_type, 'commit_id' => nil, 'label_title' => label.title, 'issue_db_id' => issue.id, - 'created_at' => '2022-04-26 18:30:53 UTC' + 'created_at' => '2022-04-26 18:30:53 UTC', + 'issue' => { 'number' => issue.iid } ) end @@ -43,6 +45,12 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::ChangedLabel do before do allow(Gitlab::Cache::Import::Caching).to receive(:read_integer).and_return(label.id) + allow_next_instance_of(Gitlab::GithubImport::IssuableFinder) do |finder| + allow(finder).to receive(:database_id).and_return(issue.id) + end + allow_next_instance_of(Gitlab::GithubImport::UserFinder) do |finder| + allow(finder).to receive(:find).with(user.id, user.username).and_return(user.id) + end end context 'when importing a labeled event' do diff --git a/spec/lib/gitlab/github_import/importer/events/changed_milestone_spec.rb b/spec/lib/gitlab/github_import/importer/events/changed_milestone_spec.rb new file mode 100644 index 00000000000..2687627fc23 --- /dev/null +++ b/spec/lib/gitlab/github_import/importer/events/changed_milestone_spec.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::GithubImport::Importer::Events::ChangedMilestone do + subject(:importer) { described_class.new(project, client) } + + let_it_be(:project) { create(:project, :repository) } + let_it_be(:user) { create(:user) } + + let(:client) { instance_double('Gitlab::GithubImport::Client') } + let(:issue) { create(:issue, project: project) } + let!(:milestone) { create(:milestone, project: project) } + + let(:issue_event) do + Gitlab::GithubImport::Representation::IssueEvent.from_json_hash( + 'id' => 6501124486, + 'actor' => { 'id' => user.id, 'login' => user.username }, + 'event' => event_type, + 'commit_id' => nil, + 'milestone_title' => milestone.title, + 'issue_db_id' => issue.id, + 'created_at' => '2022-04-26 18:30:53 UTC', + 'issue' => { 'number' => issue.iid } + ) + end + + let(:event_attrs) do + { + user_id: user.id, + issue_id: issue.id, + milestone_id: milestone.id, + state: 'opened', + created_at: issue_event.created_at + }.stringify_keys + end + + shared_examples 'new event' do + it 'creates a new milestone event' do + expect { importer.execute(issue_event) }.to change { issue.resource_milestone_events.count } + .from(0).to(1) + expect(issue.resource_milestone_events.last) + .to have_attributes(expected_event_attrs) + end + end + + describe '#execute' do + before do + allow(Gitlab::Cache::Import::Caching).to receive(:read_integer).and_return(milestone.id) + allow_next_instance_of(Gitlab::GithubImport::IssuableFinder) do |finder| + allow(finder).to receive(:database_id).and_return(issue.id) + end + allow_next_instance_of(Gitlab::GithubImport::UserFinder) do |finder| + allow(finder).to receive(:find).with(user.id, user.username).and_return(user.id) + end + end + + context 'when importing a milestoned event' do + let(:event_type) { 'milestoned' } + let(:expected_event_attrs) { event_attrs.merge(action: 'add') } + + it_behaves_like 'new event' + end + + context 'when importing demilestoned event' do + let(:event_type) { 'demilestoned' } + let(:expected_event_attrs) { event_attrs.merge(action: 'remove') } + + it_behaves_like 'new event' + end + end +end diff --git a/spec/lib/gitlab/github_import/importer/events/closed_spec.rb b/spec/lib/gitlab/github_import/importer/events/closed_spec.rb index 116917d3e06..9a49d80a8bb 100644 --- a/spec/lib/gitlab/github_import/importer/events/closed_spec.rb +++ b/spec/lib/gitlab/github_import/importer/events/closed_spec.rb @@ -3,11 +3,12 @@ require 'spec_helper' RSpec.describe Gitlab::GithubImport::Importer::Events::Closed do - subject(:importer) { described_class.new(project, user.id) } + subject(:importer) { described_class.new(project, client) } let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { create(:user) } + let(:client) { instance_double('Gitlab::GithubImport::Client') } let(:issue) { create(:issue, project: project) } let(:commit_id) { nil } @@ -16,11 +17,11 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::Closed do 'id' => 6501124486, 'node_id' => 'CE_lADOHK9fA85If7x0zwAAAAGDf0mG', 'url' => 'https://api.github.com/repos/elhowm/test-import/issues/events/6501124486', - 'actor' => { 'id' => 4, 'login' => 'alice' }, + 'actor' => { 'id' => user.id, 'login' => user.username }, 'event' => 'closed', 'created_at' => '2022-04-26 18:30:53 UTC', 'commit_id' => commit_id, - 'issue_db_id' => issue.id + 'issue' => { 'number' => issue.iid } ) end @@ -45,6 +46,15 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::Closed do }.stringify_keys end + before do + allow_next_instance_of(Gitlab::GithubImport::IssuableFinder) do |finder| + allow(finder).to receive(:database_id).and_return(issue.id) + end + allow_next_instance_of(Gitlab::GithubImport::UserFinder) do |finder| + allow(finder).to receive(:find).with(user.id, user.username).and_return(user.id) + end + end + it 'creates expected event and state event' do importer.execute(issue_event) diff --git a/spec/lib/gitlab/github_import/importer/events/cross_referenced_spec.rb b/spec/lib/gitlab/github_import/importer/events/cross_referenced_spec.rb index 118c482a7d9..68e001c7364 100644 --- a/spec/lib/gitlab/github_import/importer/events/cross_referenced_spec.rb +++ b/spec/lib/gitlab/github_import/importer/events/cross_referenced_spec.rb @@ -3,15 +3,16 @@ require 'spec_helper' RSpec.describe Gitlab::GithubImport::Importer::Events::CrossReferenced, :clean_gitlab_redis_cache do - subject(:importer) { described_class.new(project, user.id) } + subject(:importer) { described_class.new(project, client) } let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { create(:user) } - let(:sawyer_stub) { Struct.new(:iid, :issuable_type, keyword_init: true) } + let(:client) { instance_double('Gitlab::GithubImport::Client') } - let(:issue) { create(:issue, project: project) } - let(:referenced_in) { build_stubbed(:issue, project: project) } + let(:issue_iid) { 999 } + let(:issue) { create(:issue, project: project, iid: issue_iid) } + let(:referenced_in) { build_stubbed(:issue, project: project, iid: issue_iid + 1) } let(:commit_id) { nil } let(:issue_event) do @@ -19,7 +20,7 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::CrossReferenced, :clean_g 'id' => 6501124486, 'node_id' => 'CE_lADOHK9fA85If7x0zwAAAAGDf0mG', 'url' => 'https://api.github.com/repos/elhowm/test-import/issues/events/6501124486', - 'actor' => { 'id' => 4, 'login' => 'alice' }, + 'actor' => { 'id' => user.id, 'login' => user.username }, 'event' => 'cross-referenced', 'source' => { 'type' => 'issue', @@ -29,7 +30,7 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::CrossReferenced, :clean_g } }, 'created_at' => '2022-04-26 18:30:53 UTC', - 'issue_db_id' => issue.id + 'issue' => { 'number' => issue.iid } ) end @@ -38,7 +39,7 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::CrossReferenced, :clean_g { system: true, noteable_type: Issue.name, - noteable_id: issue_event.issue_db_id, + noteable_id: issue.id, project_id: project.id, author_id: user.id, note: expected_note_body, @@ -47,12 +48,16 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::CrossReferenced, :clean_g end context 'when referenced in other issue' do - let(:expected_note_body) { "mentioned in issue ##{issue.iid}" } + let(:expected_note_body) { "mentioned in issue ##{referenced_in.iid}" } before do - other_issue_resource = sawyer_stub.new(iid: referenced_in.iid, issuable_type: 'Issue') - Gitlab::GithubImport::IssuableFinder.new(project, other_issue_resource) - .cache_database_id(referenced_in.iid) + allow_next_instance_of(Gitlab::GithubImport::IssuableFinder) do |finder| + allow(finder).to receive(:database_id).and_return(referenced_in.iid) + allow(finder).to receive(:database_id).and_return(issue.id) + end + allow_next_instance_of(Gitlab::GithubImport::UserFinder) do |finder| + allow(finder).to receive(:find).with(user.id, user.username).and_return(user.id) + end end it 'creates expected note' do @@ -71,10 +76,13 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::CrossReferenced, :clean_g let(:expected_note_body) { "mentioned in merge request !#{referenced_in.iid}" } before do - other_issue_resource = - sawyer_stub.new(iid: referenced_in.iid, issuable_type: 'MergeRequest') - Gitlab::GithubImport::IssuableFinder.new(project, other_issue_resource) - .cache_database_id(referenced_in.iid) + allow_next_instance_of(Gitlab::GithubImport::IssuableFinder) do |finder| + allow(finder).to receive(:database_id).and_return(referenced_in.iid) + allow(finder).to receive(:database_id).and_return(issue.id) + end + allow_next_instance_of(Gitlab::GithubImport::UserFinder) do |finder| + allow(finder).to receive(:find).with(user.id, user.username).and_return(user.id) + end end it 'creates expected note' do @@ -87,7 +95,7 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::CrossReferenced, :clean_g end context 'when referenced in out of project issue/pull_request' do - it 'creates expected note' do + it 'does not create expected note' do importer.execute(issue_event) expect(issue.notes.count).to eq 0 diff --git a/spec/lib/gitlab/github_import/importer/events/renamed_spec.rb b/spec/lib/gitlab/github_import/importer/events/renamed_spec.rb index a8c3fbcb05d..316ea798965 100644 --- a/spec/lib/gitlab/github_import/importer/events/renamed_spec.rb +++ b/spec/lib/gitlab/github_import/importer/events/renamed_spec.rb @@ -3,23 +3,24 @@ require 'spec_helper' RSpec.describe Gitlab::GithubImport::Importer::Events::Renamed do - subject(:importer) { described_class.new(project, user.id) } + subject(:importer) { described_class.new(project, client) } let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { create(:user) } let(:issue) { create(:issue, project: project) } + let(:client) { instance_double('Gitlab::GithubImport::Client') } let(:issue_event) do Gitlab::GithubImport::Representation::IssueEvent.from_json_hash( 'id' => 6501124486, - 'actor' => { 'id' => 4, 'login' => 'alice' }, + 'actor' => { 'id' => user.id, 'login' => user.username }, 'event' => 'renamed', 'commit_id' => nil, 'created_at' => '2022-04-26 18:30:53 UTC', 'old_title' => 'old title', 'new_title' => 'new title', - 'issue_db_id' => issue.id + 'issue' => { 'number' => issue.iid } ) end @@ -45,6 +46,15 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::Renamed do end describe '#execute' do + before do + allow_next_instance_of(Gitlab::GithubImport::IssuableFinder) do |finder| + allow(finder).to receive(:database_id).and_return(issue.id) + end + allow_next_instance_of(Gitlab::GithubImport::UserFinder) do |finder| + allow(finder).to receive(:find).with(user.id, user.username).and_return(user.id) + end + end + it 'creates expected note' do expect { importer.execute(issue_event) }.to change { issue.notes.count } .from(0).to(1) diff --git a/spec/lib/gitlab/github_import/importer/events/reopened_spec.rb b/spec/lib/gitlab/github_import/importer/events/reopened_spec.rb index 81653b0ecdc..2461dbb9701 100644 --- a/spec/lib/gitlab/github_import/importer/events/reopened_spec.rb +++ b/spec/lib/gitlab/github_import/importer/events/reopened_spec.rb @@ -3,11 +3,12 @@ require 'spec_helper' RSpec.describe Gitlab::GithubImport::Importer::Events::Reopened, :aggregate_failures do - subject(:importer) { described_class.new(project, user.id) } + subject(:importer) { described_class.new(project, client) } let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { create(:user) } + let(:client) { instance_double('Gitlab::GithubImport::Client') } let(:issue) { create(:issue, project: project) } let(:issue_event) do @@ -15,10 +16,10 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::Reopened, :aggregate_fail 'id' => 6501124486, 'node_id' => 'CE_lADOHK9fA85If7x0zwAAAAGDf0mG', 'url' => 'https://api.github.com/repos/elhowm/test-import/issues/events/6501124486', - 'actor' => { 'id' => 4, 'login' => 'alice' }, + 'actor' => { 'id' => user.id, 'login' => user.username }, 'event' => 'reopened', 'created_at' => '2022-04-26 18:30:53 UTC', - 'issue_db_id' => issue.id + 'issue' => { 'number' => issue.iid } ) end @@ -42,6 +43,15 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::Reopened, :aggregate_fail }.stringify_keys end + before do + allow_next_instance_of(Gitlab::GithubImport::IssuableFinder) do |finder| + allow(finder).to receive(:database_id).and_return(issue.id) + end + allow_next_instance_of(Gitlab::GithubImport::UserFinder) do |finder| + allow(finder).to receive(:find).with(user.id, user.username).and_return(user.id) + end + end + it 'creates expected event and state event' do importer.execute(issue_event) diff --git a/spec/lib/gitlab/github_import/importer/issue_event_importer_spec.rb b/spec/lib/gitlab/github_import/importer/issue_event_importer_spec.rb index da32a3b3766..33d5fbf13a0 100644 --- a/spec/lib/gitlab/github_import/importer/issue_event_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/issue_event_importer_spec.rb @@ -33,7 +33,7 @@ RSpec.describe Gitlab::GithubImport::Importer::IssueEventImporter, :clean_gitlab specific_importer = double(importer_class.name) # rubocop:disable RSpec/VerifiedDoubles expect(importer_class) - .to receive(:new).with(project, user.id) + .to receive(:new).with(project, client) .and_return(specific_importer) expect(specific_importer).to receive(:execute).with(issue_event) @@ -43,12 +43,6 @@ RSpec.describe Gitlab::GithubImport::Importer::IssueEventImporter, :clean_gitlab describe '#execute' do before do - allow_next_instance_of(Gitlab::GithubImport::UserFinder) do |finder| - allow(finder).to receive(:author_id_for) - .with(issue_event, author_key: :actor) - .and_return(user.id, true) - end - issue_event.attributes[:issue_db_id] = issue.id end @@ -87,6 +81,20 @@ RSpec.describe Gitlab::GithubImport::Importer::IssueEventImporter, :clean_gitlab Gitlab::GithubImport::Importer::Events::Renamed end + context "when it's milestoned issue event" do + let(:event_name) { 'milestoned' } + + it_behaves_like 'triggers specific event importer', + Gitlab::GithubImport::Importer::Events::ChangedMilestone + end + + context "when it's demilestoned issue event" do + let(:event_name) { 'demilestoned' } + + it_behaves_like 'triggers specific event importer', + Gitlab::GithubImport::Importer::Events::ChangedMilestone + end + context "when it's cross-referenced issue event" do let(:event_name) { 'cross-referenced' } @@ -94,6 +102,20 @@ RSpec.describe Gitlab::GithubImport::Importer::IssueEventImporter, :clean_gitlab Gitlab::GithubImport::Importer::Events::CrossReferenced end + context "when it's assigned issue event" do + let(:event_name) { 'assigned' } + + it_behaves_like 'triggers specific event importer', + Gitlab::GithubImport::Importer::Events::ChangedAssignee + end + + context "when it's unassigned issue event" do + let(:event_name) { 'unassigned' } + + it_behaves_like 'triggers specific event importer', + Gitlab::GithubImport::Importer::Events::ChangedAssignee + end + context "when it's unknown issue event" do let(:event_name) { 'fake' } diff --git a/spec/lib/gitlab/github_import/importer/issue_events_importer_spec.rb b/spec/lib/gitlab/github_import/importer/issue_events_importer_spec.rb new file mode 100644 index 00000000000..8d4c1b01e50 --- /dev/null +++ b/spec/lib/gitlab/github_import/importer/issue_events_importer_spec.rb @@ -0,0 +1,122 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::GithubImport::Importer::IssueEventsImporter do + subject(:importer) { described_class.new(project, client, parallel: parallel) } + + let(:project) { instance_double(Project, id: 4, import_source: 'foo/bar') } + let(:client) { instance_double(Gitlab::GithubImport::Client) } + + let(:parallel) { true } + let(:issue_event) do + struct = Struct.new( + :id, :node_id, :url, :actor, :event, :commit_id, :commit_url, :label, :rename, :milestone, + :source, :assignee, :assigner, :issue, :created_at, :performed_via_github_app, + keyword_init: true + ) + struct.new(id: rand(10), event: 'closed', created_at: '2022-04-26 18:30:53 UTC') + end + + describe '#parallel?' do + context 'when running in parallel mode' do + it { expect(importer).to be_parallel } + end + + context 'when running in sequential mode' do + let(:parallel) { false } + + it { expect(importer).not_to be_parallel } + end + end + + describe '#execute' do + context 'when running in parallel mode' do + it 'imports events in parallel' do + expect(importer).to receive(:parallel_import) + + importer.execute + end + end + + context 'when running in sequential mode' do + let(:parallel) { false } + + it 'imports notes in sequence' do + expect(importer).to receive(:sequential_import) + + importer.execute + end + end + end + + describe '#sequential_import' do + let(:parallel) { false } + + it 'imports each event in sequence' do + event_importer = instance_double(Gitlab::GithubImport::Importer::IssueEventImporter) + + allow(importer).to receive(:each_object_to_import).and_yield(issue_event) + + expect(Gitlab::GithubImport::Importer::IssueEventImporter) + .to receive(:new) + .with( + an_instance_of(Gitlab::GithubImport::Representation::IssueEvent), + project, + client + ) + .and_return(event_importer) + + expect(event_importer).to receive(:execute) + + importer.sequential_import + end + end + + describe '#parallel_import' do + it 'imports each note in parallel' do + allow(importer).to receive(:each_object_to_import).and_yield(issue_event) + + expect(Gitlab::GithubImport::ImportIssueEventWorker).to receive(:bulk_perform_in).with( + 1.second, [ + [project.id, an_instance_of(Hash), an_instance_of(String)] + ], batch_size: 1000, batch_delay: 1.minute + ) + + waiter = importer.parallel_import + + expect(waiter).to be_an_instance_of(Gitlab::JobWaiter) + expect(waiter.jobs_remaining).to eq(1) + end + end + + describe '#importer_class' do + it { expect(importer.importer_class).to eq Gitlab::GithubImport::Importer::IssueEventImporter } + end + + describe '#representation_class' do + it { expect(importer.representation_class).to eq Gitlab::GithubImport::Representation::IssueEvent } + end + + describe '#sidekiq_worker_class' do + it { expect(importer.sidekiq_worker_class).to eq Gitlab::GithubImport::ImportIssueEventWorker } + end + + describe '#object_type' do + it { expect(importer.object_type).to eq :issue_event } + end + + describe '#collection_method' do + it { expect(importer.collection_method).to eq :repository_issue_events } + end + + describe '#id_for_already_imported_cache' do + it 'returns the ID of the given note' do + expect(importer.id_for_already_imported_cache(issue_event)).to eq(issue_event.id) + end + end + + describe '#collection_options' do + it { expect(importer.collection_options).to eq({}) } + end +end diff --git a/spec/lib/gitlab/github_import/importer/issue_importer_spec.rb b/spec/lib/gitlab/github_import/importer/issue_importer_spec.rb index 570d26cdf2d..1692aac49f2 100644 --- a/spec/lib/gitlab/github_import/importer/issue_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/issue_importer_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe Gitlab::GithubImport::Importer::IssueImporter, :clean_gitlab_redis_cache do + let_it_be(:work_item_type_id) { ::WorkItems::Type.default_issue_type.id } + let(:project) { create(:project) } let(:client) { double(:client) } let(:user) { create(:user) } @@ -25,7 +27,8 @@ RSpec.describe Gitlab::GithubImport::Importer::IssueImporter, :clean_gitlab_redi author: Gitlab::GithubImport::Representation::User.new(id: 4, login: 'alice'), created_at: created_at, updated_at: updated_at, - pull_request: false + pull_request: false, + work_item_type_id: work_item_type_id ) end @@ -116,6 +119,17 @@ RSpec.describe Gitlab::GithubImport::Importer::IssueImporter, :clean_gitlab_redi .and_return(milestone.id) end + it 'creates issues with a work item type id' do + allow(importer.user_finder) + .to receive(:author_id_for) + .with(issue) + .and_return([user.id, true]) + + issue_id = importer.create_issue + + expect(Issue.find(issue_id).work_item_type_id).to eq(work_item_type_id) + end + context 'when the issue author could be found' do it 'creates the issue with the found author as the issue author' do allow(importer.user_finder) @@ -136,7 +150,8 @@ RSpec.describe Gitlab::GithubImport::Importer::IssueImporter, :clean_gitlab_redi milestone_id: milestone.id, state_id: 1, created_at: created_at, - updated_at: updated_at + updated_at: updated_at, + work_item_type_id: work_item_type_id }, project.issues ) @@ -166,7 +181,8 @@ RSpec.describe Gitlab::GithubImport::Importer::IssueImporter, :clean_gitlab_redi milestone_id: milestone.id, state_id: 1, created_at: created_at, - updated_at: updated_at + updated_at: updated_at, + work_item_type_id: work_item_type_id }, project.issues ) diff --git a/spec/lib/gitlab/github_import/importer/lfs_objects_importer_spec.rb b/spec/lib/gitlab/github_import/importer/lfs_objects_importer_spec.rb index 6dfd4424342..251829b83a0 100644 --- a/spec/lib/gitlab/github_import/importer/lfs_objects_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/lfs_objects_importer_spec.rb @@ -10,7 +10,7 @@ RSpec.describe Gitlab::GithubImport::Importer::LfsObjectsImporter do let(:lfs_attributes) do { - oid: 'oid', + oid: 'a' * 64, size: 1, link: 'http://www.gitlab.com/lfs_objects/oid' } diff --git a/spec/lib/gitlab/github_import/importer/pull_requests_importer_spec.rb b/spec/lib/gitlab/github_import/importer/pull_requests_importer_spec.rb index c1b0f4df29a..c5846fa7a87 100644 --- a/spec/lib/gitlab/github_import/importer/pull_requests_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/pull_requests_importer_spec.rb @@ -149,7 +149,7 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestsImporter do expect(importer) .to receive(:update_repository) - importer.each_object_to_import { } + importer.each_object_to_import {} end end diff --git a/spec/lib/gitlab/github_import/importer/single_endpoint_issue_events_importer_spec.rb b/spec/lib/gitlab/github_import/importer/single_endpoint_issue_events_importer_spec.rb index 087faeffe02..bb1ee79ad93 100644 --- a/spec/lib/gitlab/github_import/importer/single_endpoint_issue_events_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/single_endpoint_issue_events_importer_spec.rb @@ -53,7 +53,7 @@ RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointIssueEventsImporter describe '#each_object_to_import', :clean_gitlab_redis_cache do let(:issue_event) do - struct = Struct.new(:id, :event, :created_at, :issue_db_id, keyword_init: true) + struct = Struct.new(:id, :event, :created_at, :issue, keyword_init: true) struct.new(id: rand(10), event: 'closed', created_at: '2022-04-26 18:30:53 UTC') end @@ -81,7 +81,7 @@ RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointIssueEventsImporter counter = 0 subject.each_object_to_import do |object| expect(object).to eq issue_event - expect(issue_event.issue_db_id).to eq issue.id + expect(issue_event.issue['number']).to eq issue.iid counter += 1 end expect(counter).to eq 1 diff --git a/spec/lib/gitlab/github_import/issuable_finder_spec.rb b/spec/lib/gitlab/github_import/issuable_finder_spec.rb index 3afd006109b..d550f15e8c5 100644 --- a/spec/lib/gitlab/github_import/issuable_finder_spec.rb +++ b/spec/lib/gitlab/github_import/issuable_finder_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' RSpec.describe Gitlab::GithubImport::IssuableFinder, :clean_gitlab_redis_cache do let(:project) { double(:project, id: 4, group: nil) } let(:issue) do - double(:issue, issuable_type: MergeRequest, iid: 1) + double(:issue, issuable_type: MergeRequest, issuable_id: 1) end let(:finder) { described_class.new(project, issue) } diff --git a/spec/lib/gitlab/github_import/parallel_scheduling_spec.rb b/spec/lib/gitlab/github_import/parallel_scheduling_spec.rb index 999f8ffb21e..738e7c88d7d 100644 --- a/spec/lib/gitlab/github_import/parallel_scheduling_spec.rb +++ b/spec/lib/gitlab/github_import/parallel_scheduling_spec.rb @@ -243,7 +243,7 @@ RSpec.describe Gitlab::GithubImport::ParallelScheduling do expect(repr_class) .to receive(:from_api_response) - .with(object) + .with(object, {}) .and_return(repr_instance) expect(importer) @@ -281,7 +281,7 @@ RSpec.describe Gitlab::GithubImport::ParallelScheduling do allow(repr_class) .to receive(:from_api_response) - .with(object) + .with(object, {}) .and_return({ title: 'Foo' }) end diff --git a/spec/lib/gitlab/github_import/representation/issue_event_spec.rb b/spec/lib/gitlab/github_import/representation/issue_event_spec.rb index 23da8276f64..d3a98035e73 100644 --- a/spec/lib/gitlab/github_import/representation/issue_event_spec.rb +++ b/spec/lib/gitlab/github_import/representation/issue_event_spec.rb @@ -25,8 +25,8 @@ RSpec.describe Gitlab::GithubImport::Representation::IssueEvent do expect(issue_event.source).to eq({ type: 'issue', id: 123456 }) end - it 'includes the issue_db_id' do - expect(issue_event.issue_db_id).to eq(100500) + it 'includes the issue data' do + expect(issue_event.issue).to eq({ number: 2, pull_request: pull_request }) end context 'when actor data present' do @@ -77,11 +77,66 @@ RSpec.describe Gitlab::GithubImport::Representation::IssueEvent do end end + context 'when milestone data is present' do + it 'includes the milestone_title' do + expect(issue_event.milestone_title).to eq('milestone title') + end + end + + context 'when milestone data is empty' do + let(:with_milestone) { false } + + it 'does not return such info' do + expect(issue_event.milestone_title).to eq nil + end + end + + context 'when assignee and assigner data is present' do + it 'includes assignee and assigner details' do + expect(issue_event.assignee) + .to be_an_instance_of(Gitlab::GithubImport::Representation::User) + expect(issue_event.assignee.id).to eq(5) + expect(issue_event.assignee.login).to eq('tom') + + expect(issue_event.assigner) + .to be_an_instance_of(Gitlab::GithubImport::Representation::User) + expect(issue_event.assigner.id).to eq(6) + expect(issue_event.assigner.login).to eq('jerry') + end + end + + context 'when assignee and assigner data is empty' do + let(:with_assignee) { false } + + it 'does not return such info' do + expect(issue_event.assignee).to eq nil + expect(issue_event.assigner).to eq nil + end + end + it 'includes the created timestamp' do expect(issue_event.created_at).to eq('2022-04-26 18:30:53 UTC') end end + describe '#issuable_id' do + it 'returns issuable_id' do + expect(issue_event.issuable_id).to eq(2) + end + end + + describe '#issuable_type' do + context 'when event related to issue' do + it { expect(issue_event.issuable_type).to eq('Issue') } + end + + context 'when event related to pull request' do + let(:pull_request) { { url: FFaker::Internet.http_url } } + + it { expect(issue_event.issuable_type).to eq('MergeRequest') } + end + end + describe '#github_identifiers' do it 'returns a hash with needed identifiers' do expect(issue_event.github_identifiers).to eq({ id: 6501124486 }) @@ -92,8 +147,8 @@ RSpec.describe Gitlab::GithubImport::Representation::IssueEvent do describe '.from_api_response' do let(:response) do event_resource = Struct.new( - :id, :node_id, :url, :actor, :event, :commit_id, :commit_url, :label, - :rename, :issue_db_id, :created_at, :performed_via_github_app, :source, + :id, :node_id, :url, :actor, :event, :commit_id, :commit_url, :label, :rename, :milestone, + :source, :assignee, :assigner, :issue, :created_at, :performed_via_github_app, keyword_init: true ) user_resource = Struct.new(:id, :login, keyword_init: true) @@ -106,10 +161,13 @@ RSpec.describe Gitlab::GithubImport::Representation::IssueEvent do commit_id: '570e7b2abdd848b95f2f578043fc23bd6f6fd24d', commit_url: 'https://api.github.com/repos/octocat/Hello-World/commits'\ '/570e7b2abdd848b95f2f578043fc23bd6f6fd24d', + label: with_label ? { name: 'label title' } : nil, rename: with_rename ? { from: 'old title', to: 'new title' } : nil, + milestone: with_milestone ? { title: 'milestone title' } : nil, source: { type: 'issue', id: 123456 }, - issue_db_id: 100500, - label: with_label ? { name: 'label title' } : nil, + assignee: with_assignee ? user_resource.new(id: 5, login: 'tom') : nil, + assigner: with_assignee ? user_resource.new(id: 6, login: 'jerry') : nil, + issue: { 'number' => 2, 'pull_request' => pull_request }, created_at: '2022-04-26 18:30:53 UTC', performed_via_github_app: nil ) @@ -118,6 +176,9 @@ RSpec.describe Gitlab::GithubImport::Representation::IssueEvent do let(:with_actor) { true } let(:with_label) { true } let(:with_rename) { true } + let(:with_milestone) { true } + let(:with_assignee) { true } + let(:pull_request) { nil } it_behaves_like 'an IssueEvent' do let(:issue_event) { described_class.from_api_response(response) } @@ -139,8 +200,11 @@ RSpec.describe Gitlab::GithubImport::Representation::IssueEvent do 'label_title' => (with_label ? 'label title' : nil), 'old_title' => with_rename ? 'old title' : nil, 'new_title' => with_rename ? 'new title' : nil, + 'milestone_title' => (with_milestone ? 'milestone title' : nil), 'source' => { 'type' => 'issue', 'id' => 123456 }, - "issue_db_id" => 100500, + 'assignee' => (with_assignee ? { 'id' => 5, 'login' => 'tom' } : nil), + 'assigner' => (with_assignee ? { 'id' => 6, 'login' => 'jerry' } : nil), + 'issue' => { 'number' => 2, 'pull_request' => pull_request }, 'created_at' => '2022-04-26 18:30:53 UTC', 'performed_via_github_app' => nil } @@ -149,6 +213,9 @@ RSpec.describe Gitlab::GithubImport::Representation::IssueEvent do let(:with_actor) { true } let(:with_label) { true } let(:with_rename) { true } + let(:with_milestone) { true } + let(:with_assignee) { true } + let(:pull_request) { nil } let(:issue_event) { described_class.from_json_hash(hash) } end diff --git a/spec/lib/gitlab/github_import/representation/issue_spec.rb b/spec/lib/gitlab/github_import/representation/issue_spec.rb index f3052efea70..5898518343a 100644 --- a/spec/lib/gitlab/github_import/representation/issue_spec.rb +++ b/spec/lib/gitlab/github_import/representation/issue_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe Gitlab::GithubImport::Representation::Issue do + let_it_be(:work_item_type_id) { ::WorkItems::Type.default_issue_type.id } + let(:created_at) { Time.new(2017, 1, 1, 12, 00) } let(:updated_at) { Time.new(2017, 1, 1, 12, 15) } @@ -60,6 +62,10 @@ RSpec.describe Gitlab::GithubImport::Representation::Issue do expect(issue.updated_at).to eq(updated_at) end + it 'includes the work_item_type_id' do + expect(issue.work_item_type_id).to eq(work_item_type_id) + end + it 'is not a pull request' do expect(issue.pull_request?).to eq(false) end @@ -84,8 +90,10 @@ RSpec.describe Gitlab::GithubImport::Representation::Issue do ) end + let(:additional_data) { { work_item_type_id: work_item_type_id } } + it_behaves_like 'an Issue' do - let(:issue) { described_class.from_api_response(response) } + let(:issue) { described_class.from_api_response(response, additional_data) } end it 'does not set the user if the response did not include a user' do @@ -93,7 +101,7 @@ RSpec.describe Gitlab::GithubImport::Representation::Issue do .to receive(:user) .and_return(nil) - issue = described_class.from_api_response(response) + issue = described_class.from_api_response(response, additional_data) expect(issue.author).to be_nil end @@ -113,7 +121,8 @@ RSpec.describe Gitlab::GithubImport::Representation::Issue do 'author' => { 'id' => 4, 'login' => 'alice' }, 'created_at' => created_at.to_s, 'updated_at' => updated_at.to_s, - 'pull_request' => false + 'pull_request' => false, + 'work_item_type_id' => work_item_type_id } end diff --git a/spec/lib/gitlab/github_import/user_finder_spec.rb b/spec/lib/gitlab/github_import/user_finder_spec.rb index 8eb6eedd72d..d85e298785c 100644 --- a/spec/lib/gitlab/github_import/user_finder_spec.rb +++ b/spec/lib/gitlab/github_import/user_finder_spec.rb @@ -15,32 +15,64 @@ RSpec.describe Gitlab::GithubImport::UserFinder, :clean_gitlab_redis_cache do let(:finder) { described_class.new(project, client) } describe '#author_id_for' do - it 'returns the user ID for the author of an object' do - user = double(:user, id: 4, login: 'kittens') - note = double(:note, author: user) + context 'with default author_key' do + it 'returns the user ID for the author of an object' do + user = double(:user, id: 4, login: 'kittens') + note = double(:note, author: user) - expect(finder).to receive(:user_id_for).with(user).and_return(42) + expect(finder).to receive(:user_id_for).with(user).and_return(42) - expect(finder.author_id_for(note)).to eq([42, true]) - end + expect(finder.author_id_for(note)).to eq([42, true]) + end - it 'returns the ID of the project creator if no user ID could be found' do - user = double(:user, id: 4, login: 'kittens') - note = double(:note, author: user) + it 'returns the ID of the project creator if no user ID could be found' do + user = double(:user, id: 4, login: 'kittens') + note = double(:note, author: user) - expect(finder).to receive(:user_id_for).with(user).and_return(nil) + expect(finder).to receive(:user_id_for).with(user).and_return(nil) - expect(finder.author_id_for(note)).to eq([project.creator_id, false]) - end + expect(finder.author_id_for(note)).to eq([project.creator_id, false]) + end + + it 'returns the ID of the ghost user when the object has no user' do + note = double(:note, author: nil) - it 'returns the ID of the ghost user when the object has no user' do - note = double(:note, author: nil) + expect(finder.author_id_for(note)).to eq([User.ghost.id, true]) + end - expect(finder.author_id_for(note)).to eq([User.ghost.id, true]) + it 'returns the ID of the ghost user when the given object is nil' do + expect(finder.author_id_for(nil)).to eq([User.ghost.id, true]) + end end - it 'returns the ID of the ghost user when the given object is nil' do - expect(finder.author_id_for(nil)).to eq([User.ghost.id, true]) + context 'with a non-default author_key' do + let(:user) { double(:user, id: 4, login: 'kittens') } + + shared_examples 'user ID finder' do |author_key| + it 'returns the user ID for an object' do + expect(finder).to receive(:user_id_for).with(user).and_return(42) + + expect(finder.author_id_for(issue_event, author_key: author_key)).to eq([42, true]) + end + end + + context 'when the author_key parameter is :actor' do + let(:issue_event) { double('Gitlab::GithubImport::Representation::IssueEvent', actor: user) } + + it_behaves_like 'user ID finder', :actor + end + + context 'when the author_key parameter is :assignee' do + let(:issue_event) { double('Gitlab::GithubImport::Representation::IssueEvent', assignee: user) } + + it_behaves_like 'user ID finder', :assignee + end + + context 'when the author_key parameter is :assigner' do + let(:issue_event) { double('Gitlab::GithubImport::Representation::IssueEvent', assigner: user) } + + it_behaves_like 'user ID finder', :assigner + end end end |