summaryrefslogtreecommitdiff
path: root/spec/gitlab_custom_hook_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/gitlab_custom_hook_spec.rb')
-rw-r--r--spec/gitlab_custom_hook_spec.rb254
1 files changed, 239 insertions, 15 deletions
diff --git a/spec/gitlab_custom_hook_spec.rb b/spec/gitlab_custom_hook_spec.rb
index f93c8b4..b5be8ec 100644
--- a/spec/gitlab_custom_hook_spec.rb
+++ b/spec/gitlab_custom_hook_spec.rb
@@ -1,33 +1,257 @@
# coding: utf-8
require 'spec_helper'
-require 'pry'
require 'gitlab_custom_hook'
describe GitlabCustomHook do
- let(:gitlab_custom_hook) { GitlabCustomHook.new('key_1') }
- let(:hook_path) { File.join(ROOT_PATH, 'spec/support/gl_id_test_hook') }
+ let(:tmp_repo_path) { File.join(ROOT_PATH, 'tmp', 'repo.git') }
+ let(:tmp_root_path) { File.join(ROOT_PATH, 'tmp') }
+ let(:hook_ok) { File.join(ROOT_PATH, 'spec', 'support', 'hook_ok') }
+ let(:hook_fail) { File.join(ROOT_PATH, 'spec', 'support', 'hook_fail') }
+ let(:hook_gl_id) { File.join(ROOT_PATH, 'spec', 'support', 'gl_id_test_hook') }
- context 'pre_receive hook' do
- it 'passes GL_ID variable to hook' do
- allow(gitlab_custom_hook).to receive(:hook_file).and_return(hook_path)
+ let(:vars) { {"GL_ID" => "key_1"} }
+ let(:old_value) { "old-value" }
+ let(:new_value) { "new-value" }
+ let(:ref_name) { "name/of/ref" }
+ let(:changes) { "#{old_value} #{new_value} #{ref_name}\n" }
- expect(gitlab_custom_hook.pre_receive('changes', 'repo_path')).to be_true
+ let(:gitlab_custom_hook) { GitlabCustomHook.new(tmp_repo_path, 'key_1') }
+
+ def hook_path(path)
+ File.join(tmp_repo_path, path.split('/'))
+ end
+
+ def create_hook(path, which)
+ FileUtils.ln_sf(which, hook_path(path))
+ end
+
+ # global hooks multiplexed
+ def create_global_hooks_d(which, hook_name = 'hook')
+ create_hook('hooks/pre-receive.d/' + hook_name, which)
+ create_hook('hooks/update.d/' + hook_name, which)
+ create_hook('hooks/post-receive.d/' + hook_name, which)
+ end
+
+ # repo hooks
+ def create_repo_hooks(which)
+ create_hook('custom_hooks/pre-receive', which)
+ create_hook('custom_hooks/update', which)
+ create_hook('custom_hooks/post-receive', which)
+ end
+
+ # repo hooks multiplexed
+ def create_repo_hooks_d(which, hook_name = 'hook')
+ create_hook('custom_hooks/pre-receive.d/' + hook_name, which)
+ create_hook('custom_hooks/update.d/' + hook_name, which)
+ create_hook('custom_hooks/post-receive.d/' + hook_name, which)
+ end
+
+ def cleanup_hook_setup
+ FileUtils.rm_rf(File.join(tmp_repo_path))
+ FileUtils.rm_rf(File.join(tmp_root_path, 'hooks'))
+ end
+
+ def expect_call_receive_hook(path)
+ expect(gitlab_custom_hook)
+ .to receive(:call_receive_hook)
+ .with(hook_path(path), changes)
+ .and_call_original
+ end
+
+ def expect_call_update_hook(path)
+ expect(gitlab_custom_hook)
+ .to receive(:system)
+ .with(vars, hook_path(path), ref_name, old_value, new_value)
+ .and_call_original
+ end
+
+ # setup paths
+ # <repository>.git/hooks/ - symlink to gitlab-shell/hooks global dir
+ # <repository>.git/hooks/<hook_name> - executed by git itself, this is gitlab-shell/hooks/<hook_name>
+ # <repository>.git/hooks/<hook_name>.d/* - global hooks: all executable files (minus editor backup files)
+ # <repository>.git/custom_hooks/<hook_name> - per project hook (this is already existing behavior)
+ # <repository>.git/custom_hooks/<hook_name>.d/* - per project hooks
+ #
+ # custom hooks are invoked in such way that first failure prevents other scripts being ran
+ # as global scripts are ran first, failing global skips repo hooks
+
+ before do
+ cleanup_hook_setup
+
+ FileUtils.mkdir_p(File.join(tmp_repo_path, 'custom_hooks'))
+ FileUtils.mkdir_p(File.join(tmp_repo_path, 'custom_hooks', 'update.d'))
+ FileUtils.mkdir_p(File.join(tmp_repo_path, 'custom_hooks', 'pre-receive.d'))
+ FileUtils.mkdir_p(File.join(tmp_repo_path, 'custom_hooks', 'post-receive.d'))
+
+ FileUtils.mkdir_p(File.join(tmp_root_path, 'hooks'))
+ FileUtils.mkdir_p(File.join(tmp_root_path, 'hooks', 'update.d'))
+ FileUtils.mkdir_p(File.join(tmp_root_path, 'hooks', 'pre-receive.d'))
+ FileUtils.mkdir_p(File.join(tmp_root_path, 'hooks', 'post-receive.d'))
+
+ FileUtils.symlink(File.join(tmp_root_path, 'hooks'), File.join(tmp_repo_path, 'hooks'))
+ end
+
+ after do
+ cleanup_hook_setup
+ end
+
+ context 'with gl_id_test_hook as repo hook' do
+ before do
+ create_repo_hooks(hook_gl_id)
+ end
+
+ context 'pre_receive hook' do
+ it 'passes GL_ID variable to hook' do
+ expect(gitlab_custom_hook.pre_receive(changes)).to eq(true)
+ end
+ end
+
+ context 'post_receive hook' do
+ it 'passes GL_ID variable to hook' do
+ expect(gitlab_custom_hook.post_receive(changes)).to eq(true)
+ end
+ end
+
+ context 'update hook' do
+ it 'passes GL_ID variable to hook' do
+ expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to eq(true)
+ end
end
end
- context 'post_receive hook' do
- it 'passes GL_ID variable to hook' do
- allow(gitlab_custom_hook).to receive(:hook_file).and_return(hook_path)
+ context 'with gl_id_test_hook as global hook' do
+ before do
+ create_global_hooks_d(hook_gl_id)
+ end
+
+ context 'pre_receive hook' do
+ it 'passes GL_ID variable to hook' do
+ expect(gitlab_custom_hook.pre_receive(changes)).to eq(true)
+ end
+ end
- expect(gitlab_custom_hook.post_receive('changes', 'repo_path')).to be_true
+ context 'post_receive hook' do
+ it 'passes GL_ID variable to hook' do
+ expect(gitlab_custom_hook.post_receive(changes)).to eq(true)
+ end
+ end
+
+ context 'update hook' do
+ it 'passes GL_ID variable to hook' do
+ expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to eq(true)
+ end
+ end
+ end
+
+ context "having no hooks" do
+ it "returns true" do
+ expect(gitlab_custom_hook.pre_receive(changes)).to eq(true)
+ expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to eq(true)
+ expect(gitlab_custom_hook.post_receive(changes)).to eq(true)
+ end
+ end
+
+ context "having only successful repo hooks" do
+ before do
+ create_repo_hooks(hook_ok)
+ end
+
+ it "returns true" do
+ expect(gitlab_custom_hook.pre_receive(changes)).to eq(true)
+ expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to eq(true)
+ expect(gitlab_custom_hook.post_receive(changes)).to eq(true)
+ end
+ end
+
+ context "having both successful repo and global hooks" do
+ before do
+ create_repo_hooks(hook_ok)
+ create_global_hooks_d(hook_ok)
+ end
+
+ it "returns true" do
+ expect(gitlab_custom_hook.pre_receive(changes)).to eq(true)
+ expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to eq(true)
+ expect(gitlab_custom_hook.post_receive(changes)).to eq(true)
+ end
+ end
+
+ context "having failing repo and successful global hooks" do
+ before do
+ create_repo_hooks_d(hook_fail)
+ create_global_hooks_d(hook_ok)
+ end
+
+ it "returns false" do
+ expect(gitlab_custom_hook.pre_receive(changes)).to eq(false)
+ expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to eq(false)
+ expect(gitlab_custom_hook.post_receive(changes)).to eq(false)
+ end
+
+ it "only executes the global hook" do
+ expect_call_receive_hook("custom_hooks/pre-receive.d/hook")
+ expect_call_update_hook("custom_hooks/update.d/hook")
+ expect_call_receive_hook("custom_hooks/post-receive.d/hook")
+
+ gitlab_custom_hook.pre_receive(changes)
+ gitlab_custom_hook.update(ref_name, old_value, new_value)
+ gitlab_custom_hook.post_receive(changes)
end
end
- context 'update hook' do
- it 'passes GL_ID variable to hook' do
- allow(gitlab_custom_hook).to receive(:hook_file).and_return(hook_path)
+ context "having successful repo but failing global hooks" do
+ before do
+ create_repo_hooks_d(hook_ok)
+ create_global_hooks_d(hook_fail)
+ end
+
+ it "returns false" do
+ expect(gitlab_custom_hook.pre_receive(changes)).to eq(false)
+ expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to eq(false)
+ expect(gitlab_custom_hook.post_receive(changes)).to eq(false)
+ end
+
+ it "executes the relevant hooks" do
+ expect_call_receive_hook("hooks/pre-receive.d/hook")
+ expect_call_receive_hook("custom_hooks/pre-receive.d/hook")
+ expect_call_update_hook("hooks/update.d/hook")
+ expect_call_update_hook("custom_hooks/update.d/hook")
+ expect_call_receive_hook("hooks/post-receive.d/hook")
+ expect_call_receive_hook("custom_hooks/post-receive.d/hook")
+
+ gitlab_custom_hook.pre_receive(changes)
+ gitlab_custom_hook.update(ref_name, old_value, new_value)
+ gitlab_custom_hook.post_receive(changes)
+ end
+ end
+
+ context "executing hooks in expected order" do
+ before do
+ create_repo_hooks_d(hook_ok, '01-test')
+ create_repo_hooks_d(hook_ok, '02-test')
+ create_global_hooks_d(hook_ok, '03-test')
+ create_global_hooks_d(hook_ok, '04-test')
+ end
+
+ it "executes hooks in order" do
+ expect_call_receive_hook("custom_hooks/pre-receive.d/01-test").ordered
+ expect_call_receive_hook("custom_hooks/pre-receive.d/02-test").ordered
+ expect_call_receive_hook("hooks/pre-receive.d/03-test").ordered
+ expect_call_receive_hook("hooks/pre-receive.d/04-test").ordered
+
+ expect_call_update_hook("custom_hooks/update.d/01-test").ordered
+ expect_call_update_hook("custom_hooks/update.d/02-test").ordered
+ expect_call_update_hook("hooks/update.d/03-test").ordered
+ expect_call_update_hook("hooks/update.d/04-test").ordered
+
+ expect_call_receive_hook("custom_hooks/post-receive.d/01-test").ordered
+ expect_call_receive_hook("custom_hooks/post-receive.d/02-test").ordered
+ expect_call_receive_hook("hooks/post-receive.d/03-test").ordered
+ expect_call_receive_hook("hooks/post-receive.d/04-test").ordered
- expect(gitlab_custom_hook.update('master', '', '', 'repo_path')).to be_true
+ gitlab_custom_hook.pre_receive(changes)
+ gitlab_custom_hook.update(ref_name, old_value, new_value)
+ gitlab_custom_hook.post_receive(changes)
end
end
end