debian-mirror-gitlab/spec/lib/gitlab/background_migration/migrate_merge_request_diff_commit_users_spec.rb
2021-12-11 22:18:48 +05:30

413 lines
13 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::BackgroundMigration::MigrateMergeRequestDiffCommitUsers, schema: 20211012134316 do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:users) { table(:users) }
let(:merge_requests) { table(:merge_requests) }
let(:diffs) { table(:merge_request_diffs) }
let(:commits) do
table(:merge_request_diff_commits).tap do |t|
t.extend(SuppressCompositePrimaryKeyWarning)
end
end
let(:commit_users) { described_class::MergeRequestDiffCommitUser }
let(:namespace) { namespaces.create!(name: 'foo', path: 'foo') }
let(:project) { projects.create!(namespace_id: namespace.id) }
let(:merge_request) do
merge_requests.create!(
source_branch: 'x',
target_branch: 'master',
target_project_id: project.id
)
end
let(:diff) { diffs.create!(merge_request_id: merge_request.id) }
let(:migration) { described_class.new }
describe 'MergeRequestDiffCommit' do
describe '.each_row_to_migrate' do
it 'yields the rows to migrate for a given range' do
commit1 = commits.create!(
merge_request_diff_id: diff.id,
relative_order: 0,
sha: Gitlab::Database::ShaAttribute.serialize('123abc'),
author_name: 'bob',
author_email: 'bob@example.com',
committer_name: 'bob',
committer_email: 'bob@example.com'
)
commit2 = commits.create!(
merge_request_diff_id: diff.id,
relative_order: 1,
sha: Gitlab::Database::ShaAttribute.serialize('123abc'),
author_name: 'Alice',
author_email: 'alice@example.com',
committer_name: 'Alice',
committer_email: 'alice@example.com'
)
# We stub this constant to make sure we run at least two pagination
# queries for getting the data. This way we can test if the pagination
# is actually working properly.
stub_const(
'Gitlab::BackgroundMigration::MigrateMergeRequestDiffCommitUsers::COMMIT_ROWS_PER_QUERY',
1
)
rows = []
described_class::MergeRequestDiffCommit.each_row_to_migrate(diff.id, diff.id + 1) do |row|
rows << row
end
expect(rows.length).to eq(2)
expect(rows[0].author_name).to eq(commit1.author_name)
expect(rows[1].author_name).to eq(commit2.author_name)
end
end
end
describe 'MergeRequestDiffCommitUser' do
describe '.union' do
it 'produces a union of the given queries' do
alice = commit_users.create!(name: 'Alice', email: 'alice@example.com')
bob = commit_users.create!(name: 'Bob', email: 'bob@example.com')
users = commit_users.union([
commit_users.where(name: 'Alice').to_sql,
commit_users.where(name: 'Bob').to_sql
])
expect(users).to include(alice)
expect(users).to include(bob)
end
end
end
describe '#perform' do
it 'skips jobs that have already been completed' do
Gitlab::Database::BackgroundMigrationJob.create!(
class_name: 'MigrateMergeRequestDiffCommitUsers',
arguments: [1, 10],
status: :succeeded
)
expect(migration).not_to receive(:get_data_to_update)
migration.perform(1, 10)
end
it 'migrates the data in the range' do
commits.create!(
merge_request_diff_id: diff.id,
relative_order: 0,
sha: Gitlab::Database::ShaAttribute.serialize('123abc'),
author_name: 'bob',
author_email: 'bob@example.com',
committer_name: 'bob',
committer_email: 'bob@example.com'
)
migration.perform(diff.id, diff.id + 1)
bob = commit_users.find_by(name: 'bob')
commit = commits.first
expect(commit.commit_author_id).to eq(bob.id)
expect(commit.committer_id).to eq(bob.id)
end
it 'treats empty names and Emails the same as NULL values' do
commits.create!(
merge_request_diff_id: diff.id,
relative_order: 0,
sha: Gitlab::Database::ShaAttribute.serialize('123abc'),
author_name: 'bob',
author_email: 'bob@example.com',
committer_name: '',
committer_email: ''
)
migration.perform(diff.id, diff.id + 1)
bob = commit_users.find_by(name: 'bob')
commit = commits.first
expect(commit.commit_author_id).to eq(bob.id)
expect(commit.committer_id).to be_nil
end
it 'does not update rows without a committer and author' do
commits.create!(
merge_request_diff_id: diff.id,
relative_order: 0,
sha: Gitlab::Database::ShaAttribute.serialize('123abc')
)
migration.perform(diff.id, diff.id + 1)
commit = commits.first
expect(commit_users.count).to eq(0)
expect(commit.commit_author_id).to be_nil
expect(commit.committer_id).to be_nil
end
it 'marks the background job as done' do
Gitlab::Database::BackgroundMigrationJob.create!(
class_name: 'MigrateMergeRequestDiffCommitUsers',
arguments: [diff.id, diff.id + 1]
)
migration.perform(diff.id, diff.id + 1)
job = Gitlab::Database::BackgroundMigrationJob.first
expect(job.status).to eq('succeeded')
end
end
describe '#get_data_to_update' do
it 'returns the users and commit rows to update' do
commits.create!(
merge_request_diff_id: diff.id,
relative_order: 0,
sha: Gitlab::Database::ShaAttribute.serialize('123abc'),
author_name: 'bob' + ('a' * 510),
author_email: 'bob@example.com',
committer_name: 'bob' + ('a' * 510),
committer_email: 'bob@example.com'
)
commits.create!(
merge_request_diff_id: diff.id,
relative_order: 1,
sha: Gitlab::Database::ShaAttribute.serialize('456abc'),
author_name: 'alice',
author_email: 'alice@example.com',
committer_name: 'alice',
committer_email: 'alice@example.com'
)
users, to_update = migration.get_data_to_update(diff.id, diff.id + 1)
bob_name = 'bob' + ('a' * 509)
expect(users).to include(%w[alice alice@example.com])
expect(users).to include([bob_name, 'bob@example.com'])
expect(to_update[[diff.id, 0]])
.to eq([[bob_name, 'bob@example.com'], [bob_name, 'bob@example.com']])
expect(to_update[[diff.id, 1]])
.to eq([%w[alice alice@example.com], %w[alice alice@example.com]])
end
it 'does not include a user if both the name and Email are missing' do
commits.create!(
merge_request_diff_id: diff.id,
relative_order: 0,
sha: Gitlab::Database::ShaAttribute.serialize('123abc'),
author_name: nil,
author_email: nil,
committer_name: 'bob',
committer_email: 'bob@example.com'
)
users, _ = migration.get_data_to_update(diff.id, diff.id + 1)
expect(users).to eq([%w[bob bob@example.com]].to_set)
end
end
describe '#get_user_rows_in_batches' do
it 'retrieves all existing users' do
alice = commit_users.create!(name: 'alice', email: 'alice@example.com')
bob = commit_users.create!(name: 'bob', email: 'bob@example.com')
users = [[alice.name, alice.email], [bob.name, bob.email]]
mapping = {}
migration.get_user_rows_in_batches(users, mapping)
expect(mapping[%w[alice alice@example.com]]).to eq(alice)
expect(mapping[%w[bob bob@example.com]]).to eq(bob)
end
end
describe '#create_missing_users' do
it 'creates merge request diff commit users that are missing' do
alice = commit_users.create!(name: 'alice', email: 'alice@example.com')
users = [%w[alice alice@example.com], %w[bob bob@example.com]]
mapping = { %w[alice alice@example.com] => alice }
migration.create_missing_users(users, mapping)
expect(mapping[%w[alice alice@example.com]]).to eq(alice)
expect(mapping[%w[bob bob@example.com]].name).to eq('bob')
expect(mapping[%w[bob bob@example.com]].email).to eq('bob@example.com')
end
end
describe '#update_commit_rows' do
it 'updates the merge request diff commit rows' do
to_update = { [42, 0] => [%w[alice alice@example.com], []] }
user_mapping = { %w[alice alice@example.com] => double(:user, id: 1) }
expect(migration)
.to receive(:bulk_update_commit_rows)
.with({ [42, 0] => [1, nil] })
migration.update_commit_rows(to_update, user_mapping)
end
end
describe '#bulk_update_commit_rows' do
context 'when there are no authors and committers' do
it 'does not update any rows' do
migration.bulk_update_commit_rows({ [1, 0] => [] })
expect(described_class::MergeRequestDiffCommit.connection)
.not_to receive(:execute)
end
end
context 'when there are only authors' do
it 'only updates the author IDs' do
author = commit_users.create!(name: 'Alice', email: 'alice@example.com')
commit = commits.create!(
merge_request_diff_id: diff.id,
relative_order: 0,
sha: Gitlab::Database::ShaAttribute.serialize('123abc')
)
mapping = {
[commit.merge_request_diff_id, commit.relative_order] =>
[author.id, nil]
}
migration.bulk_update_commit_rows(mapping)
commit = commits.first
expect(commit.commit_author_id).to eq(author.id)
expect(commit.committer_id).to be_nil
end
end
context 'when there are only committers' do
it 'only updates the committer IDs' do
committer =
commit_users.create!(name: 'Alice', email: 'alice@example.com')
commit = commits.create!(
merge_request_diff_id: diff.id,
relative_order: 0,
sha: Gitlab::Database::ShaAttribute.serialize('123abc')
)
mapping = {
[commit.merge_request_diff_id, commit.relative_order] =>
[nil, committer.id]
}
migration.bulk_update_commit_rows(mapping)
commit = commits.first
expect(commit.committer_id).to eq(committer.id)
expect(commit.commit_author_id).to be_nil
end
end
context 'when there are both authors and committers' do
it 'updates both the author and committer IDs' do
author = commit_users.create!(name: 'Bob', email: 'bob@example.com')
committer =
commit_users.create!(name: 'Alice', email: 'alice@example.com')
commit = commits.create!(
merge_request_diff_id: diff.id,
relative_order: 0,
sha: Gitlab::Database::ShaAttribute.serialize('123abc')
)
mapping = {
[commit.merge_request_diff_id, commit.relative_order] =>
[author.id, committer.id]
}
migration.bulk_update_commit_rows(mapping)
commit = commits.first
expect(commit.commit_author_id).to eq(author.id)
expect(commit.committer_id).to eq(committer.id)
end
end
context 'when there are multiple commit rows to update' do
it 'updates all the rows' do
author = commit_users.create!(name: 'Bob', email: 'bob@example.com')
committer =
commit_users.create!(name: 'Alice', email: 'alice@example.com')
commit1 = commits.create!(
merge_request_diff_id: diff.id,
relative_order: 0,
sha: Gitlab::Database::ShaAttribute.serialize('123abc')
)
commit2 = commits.create!(
merge_request_diff_id: diff.id,
relative_order: 1,
sha: Gitlab::Database::ShaAttribute.serialize('456abc')
)
mapping = {
[commit1.merge_request_diff_id, commit1.relative_order] =>
[author.id, committer.id],
[commit2.merge_request_diff_id, commit2.relative_order] =>
[author.id, nil]
}
migration.bulk_update_commit_rows(mapping)
commit1 = commits.find_by(relative_order: 0)
commit2 = commits.find_by(relative_order: 1)
expect(commit1.commit_author_id).to eq(author.id)
expect(commit1.committer_id).to eq(committer.id)
expect(commit2.commit_author_id).to eq(author.id)
expect(commit2.committer_id).to be_nil
end
end
end
describe '#primary_key' do
it 'returns the primary key for the commits table' do
key = migration.primary_key
expect(key.to_sql).to eq('("merge_request_diff_commits"."merge_request_diff_id", "merge_request_diff_commits"."relative_order")')
end
end
describe '#prepare' do
it 'trims a value to at most 512 characters' do
expect(migration.prepare('€' * 1_000)).to eq('€' * 512)
end
it 'returns nil if the value is an empty string' do
expect(migration.prepare('')).to be_nil
end
end
end