From d76416f5e8697341c1c32b0bf19101501300349d Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 7 Nov 2016 13:33:33 +0100 Subject: Evade some exceptions when using invalid references --- spec/models/repository_spec.rb | 49 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'spec/models/repository_spec.rb') diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 04b7d19d414..f35de604c7a 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -113,6 +113,26 @@ describe Repository, models: true do end end + describe '#ref_exists?' do + context 'when ref exists' do + it 'returns true' do + expect(repository.ref_exists?('refs/heads/master')).to be true + end + end + + context 'when ref does not exist' do + it 'returns false' do + expect(repository.ref_exists?('refs/heads/non-existent')).to be false + end + end + + context 'when ref format is incorrect' do + it 'returns false' do + expect(repository.ref_exists?('refs/heads/invalid:master')).to be false + end + end + end + describe '#last_commit_for_path' do subject { repository.last_commit_for_path(sample_commit.id, '.gitignore').id } @@ -197,6 +217,35 @@ describe Repository, models: true do end end + describe '#commit' do + context 'when ref exists' do + it 'returns commit object' do + expect(repository.commit('master')) + .to be_an_instance_of Commit + end + end + + context 'when ref does not exist' do + it 'returns nil' do + expect(repository.commit('non-existent-ref')).to be_nil + end + end + + context 'when ref is not valid' do + context 'when preceding tree element exists' do + it 'returns nil' do + expect(repository.commit('master:ref')).to be_nil + end + end + + context 'when preceding tree element does not exist' do + it 'returns nil' do + expect(repository.commit('non-existent:ref')).to be_nil + end + end + end + end + describe "#commit_dir" do it "commits a change that creates a new directory" do expect do -- cgit v1.2.1 From 869696bca3d8ff72e2dbaa96744eb7a7d560f0cf Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Tue, 8 Nov 2016 14:21:19 +0200 Subject: Faster search --- spec/models/repository_spec.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'spec/models/repository_spec.rb') diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 04b7d19d414..12989d4db53 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -362,6 +362,19 @@ describe Repository, models: true do expect(results.first).not_to start_with('fatal:') end + it 'properly handles when query is not present' do + results = repository.search_files('', 'master') + + expect(results).to match_array([]) + end + + it 'properly handles query when repo is empty' do + repository = create(:empty_project).repository + results = repository.search_files('test', 'master') + + expect(results).to match_array([]) + end + describe 'result' do subject { results.first } -- cgit v1.2.1 From a5632e802b72db01c0fb0b8bec77c0fc28b41427 Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Thu, 10 Nov 2016 19:27:09 +0200 Subject: Search for a filename in a project --- spec/models/repository_spec.rb | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) (limited to 'spec/models/repository_spec.rb') diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index fe26b4ac18c..3bd5741f2b7 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -393,33 +393,33 @@ describe Repository, models: true do end end - describe "search_files" do - let(:results) { repository.search_files('feature', 'master') } + describe "search_files_by_content" do + let(:results) { repository.search_files_by_content('feature', 'master') } subject { results } it { is_expected.to be_an Array } it 'regex-escapes the query string' do - results = repository.search_files("test\\", 'master') + results = repository.search_files_by_content("test\\", 'master') expect(results.first).not_to start_with('fatal:') end it 'properly handles an unmatched parenthesis' do - results = repository.search_files("test(", 'master') + results = repository.search_files_by_content("test(", 'master') expect(results.first).not_to start_with('fatal:') end it 'properly handles when query is not present' do - results = repository.search_files('', 'master') + results = repository.search_files_by_content('', 'master') expect(results).to match_array([]) end it 'properly handles query when repo is empty' do repository = create(:empty_project).repository - results = repository.search_files('test', 'master') + results = repository.search_files_by_content('test', 'master') expect(results).to match_array([]) end @@ -432,6 +432,28 @@ describe Repository, models: true do end end + describe "search_files_by_name" do + let(:results) { repository.search_files_by_name('files', 'master') } + + it 'returns result' do + expect(results.first).to eq('files/html/500.html') + end + + it 'properly handles when query is not present' do + results = repository.search_files_by_name('', 'master') + + expect(results).to match_array([]) + end + + it 'properly handles query when repo is empty' do + repository = create(:empty_project).repository + + results = repository.search_files_by_name('test', 'master') + + expect(results).to match_array([]) + end + end + describe '#create_ref' do it 'redirects the call to fetch_ref' do ref, ref_path = '1', '2' -- cgit v1.2.1 From 1c994dbc05c147714479288126742f3fee158fd8 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Tue, 15 Nov 2016 15:02:44 +0000 Subject: Fix POST /internal/allowed to cope with gitlab-shell v4.0.0 project paths gitlab-shell v3.6.6 would give project paths like so: * namespace/project gitlab-shell v4.0.0 can give project paths like so: * /namespace1/namespace2/project * /namespace/project * /path/to/repository/storage/namespace1/namespace2/project * /path/to/repository/storage/namespace/project --- spec/models/repository_spec.rb | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'spec/models/repository_spec.rb') diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index fe26b4ac18c..c93ec08b822 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -1534,14 +1534,4 @@ describe Repository, models: true do end.to raise_error(Repository::CommitError) end end - - describe '#remove_storage_from_path' do - let(:storage_path) { project.repository_storage_path } - let(:project_path) { project.path_with_namespace } - let(:full_path) { File.join(storage_path, project_path) } - - it { expect(Repository.remove_storage_from_path(full_path)).to eq(project_path) } - it { expect(Repository.remove_storage_from_path(project_path)).to eq(project_path) } - it { expect(Repository.remove_storage_from_path(storage_path)).to eq('') } - end end -- cgit v1.2.1 From ae51774bc45d2e15ccc61b01a30d1b588f179f85 Mon Sep 17 00:00:00 2001 From: Adam Niedzielski Date: Fri, 18 Nov 2016 15:20:48 +0100 Subject: Pass correct tag target to post-receive hook when creating tag via UI We need to handle annotated tags that are created via GitLab UI. Annotated tags have their own SHA. We have to pass this SHA to post-receive hook to mirror what happens when someone creates an annotated tag in their local repository and pushes it via command line. In order to obtain tag SHA we first have to create it. This is a bit confusing because we create the tag before executing pre-hooks, but there is no way to create a tag outside the repository. If pre-hooks fail we have to clean up after ourselves. --- spec/models/repository_spec.rb | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'spec/models/repository_spec.rb') diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 2470d504c68..72ac41f3472 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -1354,6 +1354,28 @@ describe Repository, models: true do repository.add_tag(user, '8.5', 'master', 'foo') end + it 'does not create a tag when a pre-hook fails' do + allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([false, '']) + + expect do + repository.add_tag(user, '8.5', 'master', 'foo') + end.to raise_error(GitHooksService::PreReceiveError) + + repository.expire_tags_cache + expect(repository.find_tag('8.5')).to be_nil + end + + it 'passes tag SHA to hooks' do + spy = GitHooksService.new + allow(GitHooksService).to receive(:new).and_return(spy) + allow(spy).to receive(:execute).and_call_original + + tag = repository.add_tag(user, '8.5', 'master', 'foo') + + expect(spy).to have_received(:execute). + with(anything, anything, anything, tag.target, anything) + end + it 'returns a Gitlab::Git::Tag object' do tag = repository.add_tag(user, '8.5', 'master', 'foo') -- cgit v1.2.1 From df5548e19e8c988b709e66a7e35ddc097344913e Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 8 Nov 2016 16:42:28 +0100 Subject: Unify detecting of special repository files This moves the logic of detecting special repository files (e.g. a README or a Koding configuration file) to a single class: Gitlab::FileDetector. Moving this logic into a single place allows this to be re-used more easily. This commit also changes Repository#gitlab_ci_yaml so that its cached similar to other data (e.g. the Koding configuration file). --- spec/models/repository_spec.rb | 94 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) (limited to 'spec/models/repository_spec.rb') diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 72ac41f3472..5e8a7bb08a1 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -1578,4 +1578,98 @@ describe Repository, models: true do end.to raise_error(Repository::CommitError) end end + + describe '#contribution_guide', caching: true do + it 'returns and caches the output' do + expect(repository).to receive(:file_on_head). + with(:contributing). + and_return(Gitlab::Git::Tree.new(path: 'CONTRIBUTING.md')). + once + + 2.times do + expect(repository.contribution_guide). + to be_an_instance_of(Gitlab::Git::Tree) + end + end + end + + describe '#changelog', caching: true do + it 'returns and caches the output' do + expect(repository).to receive(:file_on_head). + with(:changelog). + and_return(Gitlab::Git::Tree.new(path: 'CHANGELOG')). + once + + 2.times do + expect(repository.changelog).to be_an_instance_of(Gitlab::Git::Tree) + end + end + end + + describe '#license_blob', caching: true do + it 'returns and caches the output' do + expect(repository).to receive(:file_on_head). + with(:license). + and_return(Gitlab::Git::Tree.new(path: 'LICENSE')). + once + + 2.times do + expect(repository.license_blob).to be_an_instance_of(Gitlab::Git::Tree) + end + end + end + + describe '#license_key', caching: true do + it 'returns and caches the output' do + license = double(key: 'mit') + + expect(Licensee).to receive(:license). + with(repository.path). + and_return(license). + once + + 2.times do + expect(repository.license_key).to eq('mit') + end + end + end + + describe '#gitignore', caching: true do + it 'returns and caches the output' do + expect(repository).to receive(:file_on_head). + with(:gitignore). + and_return(Gitlab::Git::Tree.new(path: '.gitignore')). + once + + 2.times do + expect(repository.gitignore).to be_an_instance_of(Gitlab::Git::Tree) + end + end + end + + describe '#koding_yml', caching: true do + it 'returns and caches the output' do + expect(repository).to receive(:file_on_head). + with(:koding). + and_return(Gitlab::Git::Tree.new(path: '.koding.yml')). + once + + 2.times do + expect(repository.koding_yml).to be_an_instance_of(Gitlab::Git::Tree) + end + end + end + + describe '#gitlab_ci_yml', caching: true do + it 'returns and caches the output' do + expect(repository).to receive(:file_on_head). + with(:gitlab_ci). + and_return(Gitlab::Git::Tree.new(path: '.gitlab-ci.yml')). + once + + 2.times do + expect(repository.gitlab_ci_yml).to be_an_instance_of(Gitlab::Git::Tree) + end + end + end end -- cgit v1.2.1 From 6f393877e555c9e87017747cd70d3577bb70a03e Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 8 Nov 2016 18:42:13 +0100 Subject: Use File.exist? to check if a repository exists Initializing Rugged objects is way too expensive just to check if a repository exists. Even though we cache this data once in a while we have to refresh this. On GitLab.com we have seen Repository#exists? taking up to _1 minute_ to complete in the absolute worst case, though usually it sits around a second or so. Using File.exist? to instead check if $GIT_DIR/refs exists is a much faster way of checking if a repository was initialized properly. --- spec/models/repository_spec.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'spec/models/repository_spec.rb') diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 5e8a7bb08a1..635130cf797 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -811,8 +811,7 @@ describe Repository, models: true do end it 'returns false when a repository does not exist' do - expect(repository.raw_repository).to receive(:rugged). - and_raise(Gitlab::Git::Repository::NoRepository) + allow(repository).to receive(:refs_directory_exists?).and_return(false) expect(repository.exists?).to eq(false) end -- cgit v1.2.1 From ffb9b3ef18dee6f7e561ff53253da42a25854c6c Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Fri, 18 Nov 2016 14:04:18 +0100 Subject: Refactor cache refreshing/expiring This refactors repository caching so it's possible to selectively refresh certain caches, instead of just expiring and refreshing everything. To allow this the various methods that were cached (e.g. "tag_count" and "readme") use a similar pattern that makes expiring and refreshing their data much easier. In this new setup caches are refreshed as follows: 1. After a commit (but before running ProjectCacheWorker) we expire some basic caches such as the commit count and repository size. 2. ProjectCacheWorker will recalculate the commit count, repository size, then refresh a specific set of caches based on the list of files changed in a push payload. This requires a bunch of changes to the various methods that may be cached. For one, data should not be cached if a branch used or the entire repository does not exist. To prevent all these methods from handling this manually this is taken care of in Repository#cache_method_output. Some methods still manually check for the existence of a repository but this result is also cached. With selective flushing implemented ProjectCacheWorker no longer uses an exclusive lease for all of its work. Instead this worker only uses a lease to limit the number of times the repository size is updated as this is a fairly expensive operation. --- spec/models/repository_spec.rb | 484 +++++++++++++++++++++-------------------- 1 file changed, 243 insertions(+), 241 deletions(-) (limited to 'spec/models/repository_spec.rb') diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 635130cf797..04afb8ebc98 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -464,11 +464,7 @@ describe Repository, models: true do end end - describe "#changelog" do - before do - repository.send(:cache).expire(:changelog) - end - + describe "#changelog", caching: true do it 'accepts changelog' do expect(repository.tree).to receive(:blobs).and_return([TestBlob.new('changelog')]) @@ -500,17 +496,16 @@ describe Repository, models: true do end end - describe "#license_blob" do + describe "#license_blob", caching: true do before do - repository.send(:cache).expire(:license_blob) repository.remove_file(user, 'LICENSE', 'Remove LICENSE', 'master') end it 'handles when HEAD points to non-existent ref' do repository.commit_file(user, 'LICENSE', 'Copyright!', 'Add LICENSE', 'master', false) - rugged = double('rugged') - expect(rugged).to receive(:head_unborn?).and_return(true) - expect(repository).to receive(:rugged).and_return(rugged) + + allow(repository).to receive(:file_on_head). + and_raise(Rugged::ReferenceError) expect(repository.license_blob).to be_nil end @@ -537,22 +532,18 @@ describe Repository, models: true do end end - describe '#license_key' do + describe '#license_key', caching: true do before do - repository.send(:cache).expire(:license_key) repository.remove_file(user, 'LICENSE', 'Remove LICENSE', 'master') end - it 'handles when HEAD points to non-existent ref' do - repository.commit_file(user, 'LICENSE', 'Copyright!', 'Add LICENSE', 'master', false) - rugged = double('rugged') - expect(rugged).to receive(:head_unborn?).and_return(true) - expect(repository).to receive(:rugged).and_return(rugged) - + it 'returns nil when no license is detected' do expect(repository.license_key).to be_nil end - it 'returns nil when no license is detected' do + it 'returns nil when the repository does not exist' do + expect(repository).to receive(:exists?).and_return(false) + expect(repository.license_key).to be_nil end @@ -569,7 +560,7 @@ describe Repository, models: true do end end - describe "#gitlab_ci_yml" do + describe "#gitlab_ci_yml", caching: true do it 'returns valid file' do files = [TestBlob.new('file'), TestBlob.new('.gitlab-ci.yml'), TestBlob.new('copying')] expect(repository.tree).to receive(:blobs).and_return(files) @@ -583,7 +574,7 @@ describe Repository, models: true do end it 'returns nil for empty repository' do - expect(repository).to receive(:empty?).and_return(true) + allow(repository).to receive(:file_on_head).and_raise(Rugged::ReferenceError) expect(repository.gitlab_ci_yml).to be_nil end end @@ -778,7 +769,6 @@ describe Repository, models: true do expect(repository).not_to receive(:expire_emptiness_caches) expect(repository).to receive(:expire_branches_cache) expect(repository).to receive(:expire_has_visible_content_cache) - expect(repository).to receive(:expire_branch_count_cache) repository.update_branch_with_hooks(user, 'new-feature') { new_rev } end @@ -797,7 +787,6 @@ describe Repository, models: true do expect(empty_repository).to receive(:expire_emptiness_caches) expect(empty_repository).to receive(:expire_branches_cache) expect(empty_repository).to receive(:expire_has_visible_content_cache) - expect(empty_repository).to receive(:expire_branch_count_cache) empty_repository.commit_file(user, 'CHANGELOG', 'Changelog!', 'Updates file content', 'master', false) @@ -915,34 +904,6 @@ describe Repository, models: true do end end - describe '#expire_cache' do - it 'expires all caches' do - expect(repository).to receive(:expire_branch_cache) - - repository.expire_cache - end - - it 'expires the caches for a specific branch' do - expect(repository).to receive(:expire_branch_cache).with('master') - - repository.expire_cache('master') - end - - it 'expires the emptiness caches for an empty repository' do - expect(repository).to receive(:empty?).and_return(true) - expect(repository).to receive(:expire_emptiness_caches) - - repository.expire_cache - end - - it 'does not expire the emptiness caches for a non-empty repository' do - expect(repository).to receive(:empty?).and_return(false) - expect(repository).not_to receive(:expire_emptiness_caches) - - repository.expire_cache - end - end - describe '#expire_root_ref_cache' do it 'expires the root reference cache' do repository.root_ref @@ -1002,12 +963,23 @@ describe Repository, models: true do describe '#expire_emptiness_caches' do let(:cache) { repository.send(:cache) } - it 'expires the caches' do + it 'expires the caches for an empty repository' do + allow(repository).to receive(:empty?).and_return(true) + expect(cache).to receive(:expire).with(:empty?) expect(repository).to receive(:expire_has_visible_content_cache) repository.expire_emptiness_caches end + + it 'does not expire the cache for a non-empty repository' do + allow(repository).to receive(:empty?).and_return(false) + + expect(cache).not_to receive(:expire).with(:empty?) + expect(repository).not_to receive(:expire_has_visible_content_cache) + + repository.expire_emptiness_caches + end end describe :skip_merged_commit do @@ -1119,24 +1091,12 @@ describe Repository, models: true do repository.before_delete end - it 'flushes the tag count cache' do - expect(repository).to receive(:expire_tag_count_cache) - - repository.before_delete - end - it 'flushes the branches cache' do expect(repository).to receive(:expire_branches_cache) repository.before_delete end - it 'flushes the branch count cache' do - expect(repository).to receive(:expire_branch_count_cache) - - repository.before_delete - end - it 'flushes the root ref cache' do expect(repository).to receive(:expire_root_ref_cache) @@ -1161,36 +1121,18 @@ describe Repository, models: true do allow(repository).to receive(:exists?).and_return(true) end - it 'flushes the caches that depend on repository data' do - expect(repository).to receive(:expire_cache) - - repository.before_delete - end - it 'flushes the tags cache' do expect(repository).to receive(:expire_tags_cache) repository.before_delete end - it 'flushes the tag count cache' do - expect(repository).to receive(:expire_tag_count_cache) - - repository.before_delete - end - it 'flushes the branches cache' do expect(repository).to receive(:expire_branches_cache) repository.before_delete end - it 'flushes the branch count cache' do - expect(repository).to receive(:expire_branch_count_cache) - - repository.before_delete - end - it 'flushes the root ref cache' do expect(repository).to receive(:expire_root_ref_cache) @@ -1221,8 +1163,9 @@ describe Repository, models: true do describe '#before_push_tag' do it 'flushes the cache' do - expect(repository).to receive(:expire_cache) - expect(repository).to receive(:expire_tag_count_cache) + expect(repository).to receive(:expire_statistics_caches) + expect(repository).to receive(:expire_emptiness_caches) + expect(repository).to receive(:expire_tags_cache) repository.before_push_tag end @@ -1239,17 +1182,23 @@ describe Repository, models: true do describe '#after_import' do it 'flushes and builds the cache' do expect(repository).to receive(:expire_content_cache) - expect(repository).to receive(:build_cache) + expect(repository).to receive(:expire_tags_cache) + expect(repository).to receive(:expire_branches_cache) repository.after_import end end describe '#after_push_commit' do - it 'flushes the cache' do - expect(repository).to receive(:expire_cache).with('master', '123') + it 'expires statistics caches' do + expect(repository).to receive(:expire_statistics_caches). + and_call_original + + expect(repository).to receive(:expire_branch_cache). + with('master'). + and_call_original - repository.after_push_commit('master', '123') + repository.after_push_commit('master') end end @@ -1301,7 +1250,8 @@ describe Repository, models: true do describe '#before_remove_tag' do it 'flushes the tag cache' do - expect(repository).to receive(:expire_tag_count_cache) + expect(repository).to receive(:expire_tags_cache).and_call_original + expect(repository).to receive(:expire_statistics_caches).and_call_original repository.before_remove_tag end @@ -1319,23 +1269,23 @@ describe Repository, models: true do end end - describe '#expire_branch_count_cache' do - let(:cache) { repository.send(:cache) } - + describe '#expire_branches_cache' do it 'expires the cache' do - expect(cache).to receive(:expire).with(:branch_count) + expect(repository).to receive(:expire_method_caches). + with(%i(branch_names branch_count)). + and_call_original - repository.expire_branch_count_cache + repository.expire_branches_cache end end - describe '#expire_tag_count_cache' do - let(:cache) { repository.send(:cache) } - + describe '#expire_tags_cache' do it 'expires the cache' do - expect(cache).to receive(:expire).with(:tag_count) + expect(repository).to receive(:expire_method_caches). + with(%i(tag_names tag_count)). + and_call_original - repository.expire_tag_count_cache + repository.expire_tags_cache end end @@ -1411,84 +1361,27 @@ describe Repository, models: true do describe '#avatar' do it 'returns nil if repo does not exist' do - expect(repository).to receive(:exists?).and_return(false) + expect(repository).to receive(:file_on_head). + and_raise(Rugged::ReferenceError) expect(repository.avatar).to eq(nil) end it 'returns the first avatar file found in the repository' do - expect(repository).to receive(:blob_at_branch). - with('master', 'logo.png'). - and_return(true) + expect(repository).to receive(:file_on_head). + with(:avatar). + and_return(double(:tree, path: 'logo.png')) expect(repository.avatar).to eq('logo.png') end it 'caches the output' do - allow(repository).to receive(:blob_at_branch). - with('master', 'logo.png'). - and_return(true) - - expect(repository.avatar).to eq('logo.png') - - expect(repository).not_to receive(:blob_at_branch) - expect(repository.avatar).to eq('logo.png') - end - end - - describe '#expire_avatar_cache' do - let(:cache) { repository.send(:cache) } - - before do - allow(repository).to receive(:cache).and_return(cache) - end - - context 'without a branch or revision' do - it 'flushes the cache' do - expect(cache).to receive(:expire).with(:avatar) - - repository.expire_avatar_cache - end - end - - context 'with a branch' do - it 'does not flush the cache if the branch is not the default branch' do - expect(cache).not_to receive(:expire) - - repository.expire_avatar_cache('cats') - end - - it 'flushes the cache if the branch equals the default branch' do - expect(cache).to receive(:expire).with(:avatar) - - repository.expire_avatar_cache(repository.root_ref) - end - end - - context 'with a branch and revision' do - let(:commit) { double(:commit) } - - before do - allow(repository).to receive(:commit).and_return(commit) - end - - it 'does not flush the cache if the commit does not change any logos' do - diff = double(:diff, new_path: 'test.txt') - - expect(commit).to receive(:raw_diffs).and_return([diff]) - expect(cache).not_to receive(:expire) - - repository.expire_avatar_cache(repository.root_ref, '123') - end - - it 'flushes the cache if the commit changes any of the logos' do - diff = double(:diff, new_path: Repository::AVATAR_FILES[0]) - - expect(commit).to receive(:raw_diffs).and_return([diff]) - expect(cache).to receive(:expire).with(:avatar) + expect(repository).to receive(:file_on_head). + with(:avatar). + once. + and_return(double(:tree, path: 'logo.png')) - repository.expire_avatar_cache(repository.root_ref, '123') - end + 2.times { expect(repository.avatar).to eq('logo.png') } end end @@ -1502,40 +1395,6 @@ describe Repository, models: true do end end - describe '#build_cache' do - let(:cache) { repository.send(:cache) } - - it 'builds the caches if they do not already exist' do - cache_keys = repository.cache_keys + repository.cache_keys_for_branches_and_tags - - expect(cache).to receive(:exist?). - exactly(cache_keys.length). - times. - and_return(false) - - cache_keys.each do |key| - expect(repository).to receive(key) - end - - repository.build_cache - end - - it 'does not build any caches that already exist' do - cache_keys = repository.cache_keys + repository.cache_keys_for_branches_and_tags - - expect(cache).to receive(:exist?). - exactly(cache_keys.length). - times. - and_return(true) - - cache_keys.each do |key| - expect(repository).not_to receive(key) - end - - repository.build_cache - end - end - describe "#keep_around" do it "does not fail if we attempt to reference bad commit" do expect(repository.kept_around?('abc1234')).to be_falsey @@ -1592,83 +1451,226 @@ describe Repository, models: true do end end - describe '#changelog', caching: true do + describe '#gitignore', caching: true do it 'returns and caches the output' do expect(repository).to receive(:file_on_head). - with(:changelog). - and_return(Gitlab::Git::Tree.new(path: 'CHANGELOG')). + with(:gitignore). + and_return(Gitlab::Git::Tree.new(path: '.gitignore')). once 2.times do - expect(repository.changelog).to be_an_instance_of(Gitlab::Git::Tree) + expect(repository.gitignore).to be_an_instance_of(Gitlab::Git::Tree) end end end - describe '#license_blob', caching: true do + describe '#koding_yml', caching: true do it 'returns and caches the output' do expect(repository).to receive(:file_on_head). - with(:license). - and_return(Gitlab::Git::Tree.new(path: 'LICENSE')). + with(:koding). + and_return(Gitlab::Git::Tree.new(path: '.koding.yml')). once 2.times do - expect(repository.license_blob).to be_an_instance_of(Gitlab::Git::Tree) + expect(repository.koding_yml).to be_an_instance_of(Gitlab::Git::Tree) end end end - describe '#license_key', caching: true do - it 'returns and caches the output' do - license = double(key: 'mit') + describe '#readme', caching: true do + context 'with a non-existing repository' do + it 'returns nil' do + expect(repository).to receive(:tree).with(:head).and_return(nil) - expect(Licensee).to receive(:license). - with(repository.path). - and_return(license). - once + expect(repository.readme).to be_nil + end + end - 2.times do - expect(repository.license_key).to eq('mit') + context 'with an existing repository' do + it 'returns the README' do + expect(repository.readme).to be_an_instance_of(Gitlab::Git::Blob) end end end - describe '#gitignore', caching: true do - it 'returns and caches the output' do - expect(repository).to receive(:file_on_head). - with(:gitignore). - and_return(Gitlab::Git::Tree.new(path: '.gitignore')). - once + describe '#expire_statistics_caches' do + it 'expires the caches' do + expect(repository).to receive(:expire_method_caches). + with(%i(size commit_count)) - 2.times do - expect(repository.gitignore).to be_an_instance_of(Gitlab::Git::Tree) + repository.expire_statistics_caches + end + end + + describe '#expire_method_caches' do + it 'expires the caches of the given methods' do + expect_any_instance_of(RepositoryCache).to receive(:expire).with(:readme) + expect_any_instance_of(RepositoryCache).to receive(:expire).with(:gitignore) + + repository.expire_method_caches(%i(readme gitignore)) + end + end + + describe '#expire_all_method_caches' do + it 'expires the caches of all methods' do + expect(repository).to receive(:expire_method_caches). + with(Repository::CACHED_METHODS) + + repository.expire_all_method_caches + end + end + + describe '#expire_avatar_cache' do + it 'expires the cache' do + expect(repository).to receive(:expire_method_caches).with(%i(avatar)) + + repository.expire_avatar_cache + end + end + + describe '#file_on_head' do + context 'with a non-existing repository' do + it 'returns nil' do + expect(repository).to receive(:tree).with(:head).and_return(nil) + + expect(repository.file_on_head(:readme)).to be_nil + end + end + + context 'with a repository that has no blobs' do + it 'returns nil' do + expect_any_instance_of(Tree).to receive(:blobs).and_return([]) + + expect(repository.file_on_head(:readme)).to be_nil + end + end + + context 'with an existing repository' do + it 'returns a Gitlab::Git::Tree' do + expect(repository.file_on_head(:readme)). + to be_an_instance_of(Gitlab::Git::Tree) end end end - describe '#koding_yml', caching: true do - it 'returns and caches the output' do - expect(repository).to receive(:file_on_head). - with(:koding). - and_return(Gitlab::Git::Tree.new(path: '.koding.yml')). - once + describe '#head_tree' do + context 'with an existing repository' do + it 'returns a Tree' do + expect(repository.head_tree).to be_an_instance_of(Tree) + end + end - 2.times do - expect(repository.koding_yml).to be_an_instance_of(Gitlab::Git::Tree) + context 'with a non-existing repository' do + it 'returns nil' do + expect(repository).to receive(:head_commit).and_return(nil) + + expect(repository.head_tree).to be_nil end end end - describe '#gitlab_ci_yml', caching: true do - it 'returns and caches the output' do - expect(repository).to receive(:file_on_head). - with(:gitlab_ci). - and_return(Gitlab::Git::Tree.new(path: '.gitlab-ci.yml')). - once + describe '#tree' do + context 'using a non-existing repository' do + before do + allow(repository).to receive(:head_commit).and_return(nil) + end - 2.times do - expect(repository.gitlab_ci_yml).to be_an_instance_of(Gitlab::Git::Tree) + it 'returns nil' do + expect(repository.tree(:head)).to be_nil + end + + it 'returns nil when using a path' do + expect(repository.tree(:head, 'README.md')).to be_nil + end + end + + context 'using an existing repository' do + it 'returns a Tree' do + expect(repository.tree(:head)).to be_an_instance_of(Tree) + end + end + end + + describe '#size' do + context 'with a non-existing repository' do + it 'returns 0' do + expect(repository).to receive(:exists?).and_return(false) + + expect(repository.size).to eq(0.0) + end + end + + context 'with an existing repository' do + it 'returns the repository size as a Float' do + expect(repository.size).to be_an_instance_of(Float) + end + end + end + + describe '#commit_count' do + context 'with a non-existing repository' do + it 'returns 0' do + expect(repository).to receive(:root_ref).and_return(nil) + + expect(repository.commit_count).to eq(0) + end + end + + context 'with an existing repository' do + it 'returns the commit count' do + expect(repository.commit_count).to be_an_instance_of(Fixnum) + end + end + end + + describe '#cache_method_output', caching: true do + context 'with a non-existing repository' do + let(:value) do + repository.cache_method_output(:cats, fallback: 10) do + raise Rugged::ReferenceError + end + end + + it 'returns a fallback value' do + expect(value).to eq(10) + end + + it 'does not cache the data' do + value + + expect(repository.instance_variable_defined?(:@cats)).to eq(false) + expect(repository.send(:cache).exist?(:cats)).to eq(false) end end + + context 'with an existing repository' do + it 'caches the output' do + object = double + + expect(object).to receive(:number).once.and_return(10) + + 2.times do + val = repository.cache_method_output(:cats) { object.number } + + expect(val).to eq(10) + end + + expect(repository.send(:cache).exist?(:cats)).to eq(true) + expect(repository.instance_variable_get(:@cats)).to eq(10) + end + end + end + + describe '#refresh_method_caches' do + it 'refreshes the caches of the given types' do + expect(repository).to receive(:expire_method_caches). + with(%i(readme license_blob license_key)) + + expect(repository).to receive(:readme) + expect(repository).to receive(:license_blob) + expect(repository).to receive(:license_key) + + repository.refresh_method_caches(%i(readme license)) + end end end -- cgit v1.2.1 From 9e6cdc64741583ed0db74485892c1970ff960eab Mon Sep 17 00:00:00 2001 From: Adam Niedzielski Date: Mon, 28 Nov 2016 13:00:42 +0100 Subject: Revert "Pass correct tag target to post-receive hook when creating tag via UI" This reverts commit ae51774bc45d2e15ccc61b01a30d1b588f179f85. --- spec/models/repository_spec.rb | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'spec/models/repository_spec.rb') diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 04afb8ebc98..214bf478d19 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -1303,28 +1303,6 @@ describe Repository, models: true do repository.add_tag(user, '8.5', 'master', 'foo') end - it 'does not create a tag when a pre-hook fails' do - allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([false, '']) - - expect do - repository.add_tag(user, '8.5', 'master', 'foo') - end.to raise_error(GitHooksService::PreReceiveError) - - repository.expire_tags_cache - expect(repository.find_tag('8.5')).to be_nil - end - - it 'passes tag SHA to hooks' do - spy = GitHooksService.new - allow(GitHooksService).to receive(:new).and_return(spy) - allow(spy).to receive(:execute).and_call_original - - tag = repository.add_tag(user, '8.5', 'master', 'foo') - - expect(spy).to have_received(:execute). - with(anything, anything, anything, tag.target, anything) - end - it 'returns a Gitlab::Git::Tag object' do tag = repository.add_tag(user, '8.5', 'master', 'foo') -- cgit v1.2.1 From cf58271e11f6704523be5211ecfb2d02ae1091fe Mon Sep 17 00:00:00 2001 From: Adam Niedzielski Date: Mon, 28 Nov 2016 15:04:51 +0100 Subject: Pass tag SHA to post-receive hook when tag is created via UI We only know the tag SHA after we create the tag. This means that we pass a different value to the hooks that happen before creating the tag, and a different value to the hooks that happen after creating the tag. This is not an ideal situation, but it is a trade-off we decided to make. For discussion of the alternatives please refer to https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7700#note_18982873 "pre-receive" and "update" hooks always get the SHA of the commit that the tag points to. "post-receive" gets the tag SHA if it is an annotated tag or the commit SHA if it is an lightweight tag. Currently we always create annotated tags if UI is used. --- spec/models/repository_spec.rb | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'spec/models/repository_spec.rb') diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 214bf478d19..b797d19161d 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -1308,6 +1308,32 @@ describe Repository, models: true do expect(tag).to be_a(Gitlab::Git::Tag) end + + it 'passes commit SHA to pre-receive and update hooks,\ + and tag SHA to post-receive hook' do + pre_receive_hook = Gitlab::Git::Hook.new('pre-receive', repository.path_to_repo) + update_hook = Gitlab::Git::Hook.new('update', repository.path_to_repo) + post_receive_hook = Gitlab::Git::Hook.new('post-receive', repository.path_to_repo) + + allow(Gitlab::Git::Hook).to receive(:new). + and_return(pre_receive_hook, update_hook, post_receive_hook) + + allow(pre_receive_hook).to receive(:trigger).and_call_original + allow(update_hook).to receive(:trigger).and_call_original + allow(post_receive_hook).to receive(:trigger).and_call_original + + tag = repository.add_tag(user, '8.5', 'master', 'foo') + + commit_sha = repository.commit('master').id + tag_sha = tag.target + + expect(pre_receive_hook).to have_received(:trigger). + with(anything, anything, commit_sha, anything) + expect(update_hook).to have_received(:trigger). + with(anything, anything, commit_sha, anything) + expect(post_receive_hook).to have_received(:trigger). + with(anything, anything, tag_sha, anything) + end end context 'with an invalid target' do -- cgit v1.2.1 From 5eb12bd75fff65bb2ea8677cc317877e45d3d6f8 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 6 Dec 2016 13:22:45 +0100 Subject: Remove caching of Repository#has_visible_content? This method already uses the cached method Repository#branch_count so there's no point in also caching has_visible_content?. Fixes gitlab-org/gitlab-ce#25278 --- spec/models/repository_spec.rb | 31 ++----------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) (limited to 'spec/models/repository_spec.rb') diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index b797d19161d..d9b0e63eeb6 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -768,7 +768,6 @@ describe Repository, models: true do expect(repository).not_to receive(:expire_root_ref_cache) expect(repository).not_to receive(:expire_emptiness_caches) expect(repository).to receive(:expire_branches_cache) - expect(repository).to receive(:expire_has_visible_content_cache) repository.update_branch_with_hooks(user, 'new-feature') { new_rev } end @@ -786,7 +785,6 @@ describe Repository, models: true do expect(empty_repository).to receive(:expire_root_ref_cache) expect(empty_repository).to receive(:expire_emptiness_caches) expect(empty_repository).to receive(:expire_branches_cache) - expect(empty_repository).to receive(:expire_has_visible_content_cache) empty_repository.commit_file(user, 'CHANGELOG', 'Changelog!', 'Updates file content', 'master', false) @@ -829,15 +827,6 @@ describe Repository, models: true do expect(subject).to eq(true) end - - it 'caches the output' do - expect(repository).to receive(:branch_count). - once. - and_return(3) - - repository.has_visible_content? - repository.has_visible_content? - end end end @@ -918,20 +907,6 @@ describe Repository, models: true do end end - describe '#expire_has_visible_content_cache' do - it 'expires the visible content cache' do - repository.has_visible_content? - - expect(repository).to receive(:branch_count). - once. - and_return(0) - - repository.expire_has_visible_content_cache - - expect(repository.has_visible_content?).to eq(false) - end - end - describe '#expire_branch_cache' do # This method is private but we need it for testing purposes. Sadly there's # no other proper way of testing caching operations. @@ -967,7 +942,6 @@ describe Repository, models: true do allow(repository).to receive(:empty?).and_return(true) expect(cache).to receive(:expire).with(:empty?) - expect(repository).to receive(:expire_has_visible_content_cache) repository.expire_emptiness_caches end @@ -976,7 +950,6 @@ describe Repository, models: true do allow(repository).to receive(:empty?).and_return(false) expect(cache).not_to receive(:expire).with(:empty?) - expect(repository).not_to receive(:expire_has_visible_content_cache) repository.expire_emptiness_caches end @@ -1204,7 +1177,7 @@ describe Repository, models: true do describe '#after_create_branch' do it 'flushes the visible content cache' do - expect(repository).to receive(:expire_has_visible_content_cache) + expect(repository).to receive(:expire_branches_cache) repository.after_create_branch end @@ -1212,7 +1185,7 @@ describe Repository, models: true do describe '#after_remove_branch' do it 'flushes the visible content cache' do - expect(repository).to receive(:expire_has_visible_content_cache) + expect(repository).to receive(:expire_branches_cache) repository.after_remove_branch end -- cgit v1.2.1 From dec384cf23787e156eac8d633f70fb40479a5283 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Wed, 7 Dec 2016 11:31:01 +0100 Subject: Update outdated visible content spec descriptions --- spec/models/repository_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec/models/repository_spec.rb') diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index d9b0e63eeb6..b5a42edd192 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -1176,7 +1176,7 @@ describe Repository, models: true do end describe '#after_create_branch' do - it 'flushes the visible content cache' do + it 'expires the branch caches' do expect(repository).to receive(:expire_branches_cache) repository.after_create_branch @@ -1184,7 +1184,7 @@ describe Repository, models: true do end describe '#after_remove_branch' do - it 'flushes the visible content cache' do + it 'expires the branch caches' do expect(repository).to receive(:expire_branches_cache) repository.after_remove_branch -- cgit v1.2.1