diff options
Diffstat (limited to 'spec/services/git/branch_hooks_service_spec.rb')
-rw-r--r-- | spec/services/git/branch_hooks_service_spec.rb | 339 |
1 files changed, 339 insertions, 0 deletions
diff --git a/spec/services/git/branch_hooks_service_spec.rb b/spec/services/git/branch_hooks_service_spec.rb new file mode 100644 index 00000000000..bb87267db7d --- /dev/null +++ b/spec/services/git/branch_hooks_service_spec.rb @@ -0,0 +1,339 @@ +require 'spec_helper' + +describe Git::BranchHooksService do + include RepoHelpers + + let(:project) { create(:project, :repository) } + let(:user) { project.creator } + + let(:branch) { project.default_branch } + let(:ref) { "refs/heads/#{branch}" } + let(:commit) { project.commit(sample_commit.id) } + let(:oldrev) { commit.parent_id } + let(:newrev) { commit.id } + + let(:service) do + described_class.new(project, user, oldrev: oldrev, newrev: newrev, ref: ref) + end + + describe "Git Push Data" do + subject(:push_data) { service.execute } + + it 'has expected push data attributes' do + is_expected.to match a_hash_including( + object_kind: 'push', + before: oldrev, + after: newrev, + ref: ref, + user_id: user.id, + user_name: user.name, + project_id: project.id + ) + end + + context "with repository data" do + subject { push_data[:repository] } + + it 'has expected attributes' do + is_expected.to match a_hash_including( + name: project.name, + url: project.url_to_repo, + description: project.description, + homepage: project.web_url + ) + end + end + + context "with commits" do + subject { push_data[:commits] } + + it { is_expected.to be_an(Array) } + + it 'has 1 element' do + expect(subject.size).to eq(1) + end + + context "the commit" do + subject { push_data[:commits].first } + + it { expect(subject[:timestamp].in_time_zone).to eq(commit.date.in_time_zone) } + + it 'includes expected commit data' do + is_expected.to match a_hash_including( + id: commit.id, + message: commit.safe_message, + url: [ + Gitlab.config.gitlab.url, + project.namespace.to_param, + project.to_param, + 'commit', + commit.id + ].join('/') + ) + end + + context "with a author" do + subject { push_data[:commits].first[:author] } + + it 'includes expected author data' do + is_expected.to match a_hash_including( + name: commit.author_name, + email: commit.author_email + ) + end + end + end + end + end + + describe 'Push Event' do + let(:event) { Event.find_by_action(Event::PUSHED) } + + before do + service.execute + end + + context "with an existing branch" do + it 'generates a push event with one commit' do + expect(event).to be_an_instance_of(PushEvent) + expect(event.project).to eq(project) + expect(event.action).to eq(Event::PUSHED) + expect(event.push_event_payload).to be_an_instance_of(PushEventPayload) + expect(event.push_event_payload.commit_from).to eq(oldrev) + expect(event.push_event_payload.commit_to).to eq(newrev) + expect(event.push_event_payload.ref).to eq('master') + expect(event.push_event_payload.commit_count).to eq(1) + end + end + + context "with a new branch" do + let(:oldrev) { Gitlab::Git::BLANK_SHA } + + it 'generates a push event with more than one commit' do + expect(event).to be_an_instance_of(PushEvent) + expect(event.project).to eq(project) + expect(event.action).to eq(Event::PUSHED) + expect(event.push_event_payload).to be_an_instance_of(PushEventPayload) + expect(event.push_event_payload.commit_from).to be_nil + expect(event.push_event_payload.commit_to).to eq(newrev) + expect(event.push_event_payload.ref).to eq('master') + expect(event.push_event_payload.commit_count).to be > 1 + end + end + + context 'removing a branch' do + let(:newrev) { Gitlab::Git::BLANK_SHA } + + it 'generates a push event with no commits' do + expect(event).to be_an_instance_of(PushEvent) + expect(event.project).to eq(project) + expect(event.action).to eq(Event::PUSHED) + expect(event.push_event_payload).to be_an_instance_of(PushEventPayload) + expect(event.push_event_payload.commit_from).to eq(oldrev) + expect(event.push_event_payload.commit_to).to be_nil + expect(event.push_event_payload.ref).to eq('master') + expect(event.push_event_payload.commit_count).to eq(0) + end + end + end + + describe 'Invalidating project cache' do + let(:commit_id) do + project.repository.update_file( + user, 'README.md', '', message: 'Update', branch_name: branch + ) + end + + let(:commit) { project.repository.commit(commit_id) } + let(:blank_sha) { Gitlab::Git::BLANK_SHA } + + def clears_cache(extended: []) + expect(ProjectCacheWorker) + .to receive(:perform_async) + .with(project.id, extended, %i[commit_count repository_size]) + + service.execute + end + + def clears_extended_cache + clears_cache(extended: %i[readme]) + end + + context 'on default branch' do + context 'create' do + # FIXME: When creating the default branch,the cache worker runs twice + before do + allow(ProjectCacheWorker).to receive(:perform_async) + end + + let(:oldrev) { blank_sha } + + it { clears_cache } + end + + context 'update' do + it { clears_extended_cache } + end + + context 'remove' do + let(:newrev) { blank_sha } + + # TODO: this case should pass, but we only take account of added files + it { clears_cache } + end + end + + context 'on ordinary branch' do + let(:branch) { 'fix' } + + context 'create' do + let(:oldrev) { blank_sha } + + it { clears_cache } + end + + context 'update' do + it { clears_cache } + end + + context 'remove' do + let(:newrev) { blank_sha } + + it { clears_cache } + end + end + end + + describe 'GPG signatures' do + context 'when the commit has a signature' do + context 'when the signature is already cached' do + before do + create(:gpg_signature, commit_sha: commit.id) + end + + it 'does not queue a CreateGpgSignatureWorker' do + expect(CreateGpgSignatureWorker).not_to receive(:perform_async) + + service.execute + end + end + + context 'when the signature is not yet cached' do + it 'queues a CreateGpgSignatureWorker' do + expect(CreateGpgSignatureWorker).to receive(:perform_async).with([commit.id], project.id) + + service.execute + end + + it 'can queue several commits to create the gpg signature' do + allow(Gitlab::Git::Commit) + .to receive(:shas_with_signatures) + .and_return([sample_commit.id, another_sample_commit.id]) + + expect(CreateGpgSignatureWorker) + .to receive(:perform_async) + .with([sample_commit.id, another_sample_commit.id], project.id) + + service.execute + end + end + end + + context 'when the commit does not have a signature' do + before do + allow(Gitlab::Git::Commit) + .to receive(:shas_with_signatures) + .with(project.repository, [sample_commit.id]) + .and_return([]) + end + + it 'does not queue a CreateGpgSignatureWorker' do + expect(CreateGpgSignatureWorker) + .not_to receive(:perform_async) + .with(sample_commit.id, project.id) + + service.execute + end + end + end + + describe 'Processing commit messages' do + # Create 4 commits, 2 of which have references. Limiting to 2 commits, we + # expect to see one commit message processor enqueued. + let(:commit_ids) do + Array.new(4) do |i| + message = "Issue #{'#' if i.even?}#{i}" + project.repository.update_file( + user, 'README.md', '', message: message, branch_name: branch + ) + end + end + + let(:oldrev) { commit_ids.first } + let(:newrev) { commit_ids.last } + + before do + stub_const("::Git::BaseHooksService::PROCESS_COMMIT_LIMIT", 2) + end + + context 'creating the default branch' do + let(:oldrev) { Gitlab::Git::BLANK_SHA } + + it 'does not process commit messages' do + expect(ProcessCommitWorker).not_to receive(:perform_async) + + service.execute + end + end + + context 'updating the default branch' do + it 'processes a limited number of commit messages' do + expect(ProcessCommitWorker).to receive(:perform_async).once + + service.execute + end + end + + context 'removing the default branch' do + let(:newrev) { Gitlab::Git::BLANK_SHA } + + it 'does not process commit messages' do + expect(ProcessCommitWorker).not_to receive(:perform_async) + + service.execute + end + end + + context 'creating a normal branch' do + let(:branch) { 'fix' } + let(:oldrev) { Gitlab::Git::BLANK_SHA } + + it 'processes a limited number of commit messages' do + expect(ProcessCommitWorker).to receive(:perform_async).once + + service.execute + end + end + + context 'updating a normal branch' do + let(:branch) { 'fix' } + + it 'processes a limited number of commit messages' do + expect(ProcessCommitWorker).to receive(:perform_async).once + + service.execute + end + end + + context 'removing a normal branch' do + let(:branch) { 'fix' } + let(:newrev) { Gitlab::Git::BLANK_SHA } + + it 'does not process commit messages' do + expect(ProcessCommitWorker).not_to receive(:perform_async) + + service.execute + end + end + end +end |