diff options
author | Sean McGivern <sean@mcgivern.me.uk> | 2016-11-21 17:08:36 +0000 |
---|---|---|
committer | Sean McGivern <sean@mcgivern.me.uk> | 2016-11-21 17:08:36 +0000 |
commit | 55ca2da7683a33872a25b2402435449435294c93 (patch) | |
tree | ae5daa45d0dd16dbad406e1054db05a9df26607f /spec | |
parent | d3236af1ae8cbe6cc1a0b813789f7ba040550f02 (diff) | |
parent | 289e433685867dbc569adc4e7d137253bb42c3c8 (diff) | |
download | gitlab-ce-55ca2da7683a33872a25b2402435449435294c93.tar.gz |
Merge branch 'smarter-cache-invalidation' into 'master'
Smarter cache invalidation
Fixes https://gitlab.com/gitlab-org/gitlab-ce/issues/23550
See merge request !7360
Diffstat (limited to 'spec')
-rw-r--r-- | spec/lib/gitlab/file_detector_spec.rb | 59 | ||||
-rw-r--r-- | spec/models/project_spec.rb | 2 | ||||
-rw-r--r-- | spec/models/repository_spec.rb | 477 | ||||
-rw-r--r-- | spec/requests/api/branches_spec.rb | 2 | ||||
-rw-r--r-- | spec/services/git_push_service_spec.rb | 104 | ||||
-rw-r--r-- | spec/services/git_tag_push_service_spec.rb | 8 | ||||
-rw-r--r-- | spec/workers/project_cache_worker_spec.rb | 86 |
7 files changed, 454 insertions, 284 deletions
diff --git a/spec/lib/gitlab/file_detector_spec.rb b/spec/lib/gitlab/file_detector_spec.rb new file mode 100644 index 00000000000..e5ba13bbaf8 --- /dev/null +++ b/spec/lib/gitlab/file_detector_spec.rb @@ -0,0 +1,59 @@ +require 'spec_helper' + +describe Gitlab::FileDetector do + describe '.types_in_paths' do + it 'returns the file types for the given paths' do + expect(described_class.types_in_paths(%w(README.md CHANGELOG VERSION VERSION))). + to eq(%i{readme changelog version}) + end + + it 'does not include unrecognized file paths' do + expect(described_class.types_in_paths(%w(README.md foo.txt))). + to eq(%i{readme}) + end + end + + describe '.type_of' do + it 'returns the type of a README file' do + expect(described_class.type_of('README.md')).to eq(:readme) + end + + it 'returns the type of a changelog file' do + %w(CHANGELOG HISTORY CHANGES NEWS).each do |file| + expect(described_class.type_of(file)).to eq(:changelog) + end + end + + it 'returns the type of a license file' do + %w(LICENSE LICENCE COPYING).each do |file| + expect(described_class.type_of(file)).to eq(:license) + end + end + + it 'returns the type of a version file' do + expect(described_class.type_of('VERSION')).to eq(:version) + end + + it 'returns the type of a .gitignore file' do + expect(described_class.type_of('.gitignore')).to eq(:gitignore) + end + + it 'returns the type of a Koding config file' do + expect(described_class.type_of('.koding.yml')).to eq(:koding) + end + + it 'returns the type of a GitLab CI config file' do + expect(described_class.type_of('.gitlab-ci.yml')).to eq(:gitlab_ci) + end + + it 'returns the type of an avatar' do + %w(logo.gif logo.png logo.jpg).each do |file| + expect(described_class.type_of(file)).to eq(:avatar) + end + end + + it 'returns nil for an unknown file' do + expect(described_class.type_of('foo.txt')).to be_nil + end + end +end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 25458e20618..e183fa88873 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1572,7 +1572,7 @@ describe Project, models: true do end it 'expires the avatar cache' do - expect(project.repository).to receive(:expire_avatar_cache).with(project.default_branch) + expect(project.repository).to receive(:expire_avatar_cache) project.change_head(project.default_branch) end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 72ac41f3472..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) @@ -811,8 +800,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 @@ -916,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 @@ -1003,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 @@ -1120,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) @@ -1162,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) @@ -1222,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 @@ -1240,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 - repository.after_push_commit('master', '123') + expect(repository).to receive(:expire_branch_cache). + with('master'). + and_call_original + + repository.after_push_commit('master') end end @@ -1302,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 @@ -1320,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 @@ -1412,170 +1361,316 @@ 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).to receive(:file_on_head). + with(:avatar). + once. + and_return(double(:tree, path: 'logo.png')) - expect(repository).not_to receive(:blob_at_branch) - expect(repository.avatar).to eq('logo.png') + 2.times { expect(repository.avatar).to eq('logo.png') } end end - describe '#expire_avatar_cache' do + describe '#expire_exists_cache' do let(:cache) { repository.send(:cache) } - before do - allow(repository).to receive(:cache).and_return(cache) + it 'expires the cache' do + expect(cache).to receive(:expire).with(:exists?) + + repository.expire_exists_cache end + end - context 'without a branch or revision' do - it 'flushes the cache' do - expect(cache).to receive(:expire).with(:avatar) + describe "#keep_around" do + it "does not fail if we attempt to reference bad commit" do + expect(repository.kept_around?('abc1234')).to be_falsey + end - repository.expire_avatar_cache - end + it "stores a reference to the specified commit sha so it isn't garbage collected" do + repository.keep_around(sample_commit.id) + + expect(repository.kept_around?(sample_commit.id)).to be_truthy + end + + it "attempting to call keep_around on truncated ref does not fail" do + repository.keep_around(sample_commit.id) + ref = repository.send(:keep_around_ref_name, sample_commit.id) + path = File.join(repository.path, ref) + # Corrupt the reference + File.truncate(path, 0) + + expect(repository.kept_around?(sample_commit.id)).to be_falsey + + repository.keep_around(sample_commit.id) + + expect(repository.kept_around?(sample_commit.id)).to be_falsey + + File.delete(path) + end + end + + describe '#update_ref!' do + it 'can create a ref' do + repository.update_ref!('refs/heads/foobar', 'refs/heads/master', Gitlab::Git::BLANK_SHA) + + expect(repository.find_branch('foobar')).not_to be_nil 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) + it 'raises CommitError when the ref update fails' do + expect do + repository.update_ref!('refs/heads/master', 'refs/heads/master', Gitlab::Git::BLANK_SHA) + 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 - repository.expire_avatar_cache('cats') + 2.times do + expect(repository.contribution_guide). + to be_an_instance_of(Gitlab::Git::Tree) end + end + end - it 'flushes the cache if the branch equals the default branch' do - expect(cache).to receive(:expire).with(:avatar) + 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 - repository.expire_avatar_cache(repository.root_ref) + 2.times do + expect(repository.gitignore).to be_an_instance_of(Gitlab::Git::Tree) end end + end - context 'with a branch and revision' do - let(:commit) { double(:commit) } + 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 - before do - allow(repository).to receive(:commit).and_return(commit) + 2.times do + expect(repository.koding_yml).to be_an_instance_of(Gitlab::Git::Tree) end + end + end - it 'does not flush the cache if the commit does not change any logos' do - diff = double(:diff, new_path: 'test.txt') + 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(commit).to receive(:raw_diffs).and_return([diff]) - expect(cache).not_to receive(:expire) + expect(repository.readme).to be_nil + end + end - repository.expire_avatar_cache(repository.root_ref, '123') + 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 - it 'flushes the cache if the commit changes any of the logos' do - diff = double(:diff, new_path: Repository::AVATAR_FILES[0]) + describe '#expire_statistics_caches' do + it 'expires the caches' do + expect(repository).to receive(:expire_method_caches). + with(%i(size commit_count)) + + repository.expire_statistics_caches + end + end - expect(commit).to receive(:raw_diffs).and_return([diff]) - expect(cache).to receive(:expire).with(:avatar) + 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_avatar_cache(repository.root_ref, '123') - end + repository.expire_method_caches(%i(readme gitignore)) end end - describe '#expire_exists_cache' do - let(:cache) { repository.send(:cache) } + 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(cache).to receive(:expire).with(:exists?) + expect(repository).to receive(:expire_method_caches).with(%i(avatar)) - repository.expire_exists_cache + repository.expire_avatar_cache end end - describe '#build_cache' do - let(:cache) { repository.send(:cache) } + 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) - it 'builds the caches if they do not already exist' do - cache_keys = repository.cache_keys + repository.cache_keys_for_branches_and_tags + expect(repository.file_on_head(:readme)).to be_nil + end + end - expect(cache).to receive(:exist?). - exactly(cache_keys.length). - times. - and_return(false) + 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 '#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 + + 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 - cache_keys.each do |key| - expect(repository).to receive(key) + describe '#tree' do + context 'using a non-existing repository' do + before do + allow(repository).to receive(:head_commit).and_return(nil) + end + + it 'returns nil' do + expect(repository.tree(:head)).to be_nil end - repository.build_cache + it 'returns nil when using a path' do + expect(repository.tree(:head, 'README.md')).to be_nil + end end - it 'does not build any caches that already exist' do - cache_keys = repository.cache_keys + repository.cache_keys_for_branches_and_tags + context 'using an existing repository' do + it 'returns a Tree' do + expect(repository.tree(:head)).to be_an_instance_of(Tree) + end + end + end - expect(cache).to receive(:exist?). - exactly(cache_keys.length). - times. - and_return(true) + describe '#size' do + context 'with a non-existing repository' do + it 'returns 0' do + expect(repository).to receive(:exists?).and_return(false) - cache_keys.each do |key| - expect(repository).not_to receive(key) + expect(repository.size).to eq(0.0) end + end - repository.build_cache + 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 "#keep_around" do - it "does not fail if we attempt to reference bad commit" do - expect(repository.kept_around?('abc1234')).to be_falsey + 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 - it "stores a reference to the specified commit sha so it isn't garbage collected" do - repository.keep_around(sample_commit.id) + 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 - expect(repository.kept_around?(sample_commit.id)).to be_truthy + 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 - it "attempting to call keep_around on truncated ref does not fail" do - repository.keep_around(sample_commit.id) - ref = repository.send(:keep_around_ref_name, sample_commit.id) - path = File.join(repository.path, ref) - # Corrupt the reference - File.truncate(path, 0) + context 'with an existing repository' do + it 'caches the output' do + object = double - expect(repository.kept_around?(sample_commit.id)).to be_falsey + expect(object).to receive(:number).once.and_return(10) - repository.keep_around(sample_commit.id) + 2.times do + val = repository.cache_method_output(:cats) { object.number } - expect(repository.kept_around?(sample_commit.id)).to be_falsey + expect(val).to eq(10) + end - File.delete(path) + expect(repository.send(:cache).exist?(:cats)).to eq(true) + expect(repository.instance_variable_get(:@cats)).to eq(10) + end end end - describe '#update_ref!' do - it 'can create a ref' do - repository.update_ref!('refs/heads/foobar', 'refs/heads/master', Gitlab::Git::BLANK_SHA) + 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.find_branch('foobar')).not_to be_nil - end + expect(repository).to receive(:readme) + expect(repository).to receive(:license_blob) + expect(repository).to receive(:license_key) - it 'raises CommitError when the ref update fails' do - expect do - repository.update_ref!('refs/heads/master', 'refs/heads/master', Gitlab::Git::BLANK_SHA) - end.to raise_error(Repository::CommitError) + repository.refresh_method_caches(%i(readme license)) end end end diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb index 8f605757186..fe6b875b997 100644 --- a/spec/requests/api/branches_spec.rb +++ b/spec/requests/api/branches_spec.rb @@ -14,7 +14,7 @@ describe API::API, api: true do describe "GET /projects/:id/repository/branches" do it "returns an array of project branches" do - project.repository.expire_cache + project.repository.expire_all_method_caches get api("/projects/#{project.id}/repository/branches", user) expect(response).to have_http_status(200) diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb index 62f9982e840..9d7702f5c96 100644 --- a/spec/services/git_push_service_spec.rb +++ b/spec/services/git_push_service_spec.rb @@ -27,27 +27,14 @@ describe GitPushService, services: true do it { is_expected.to be_truthy } - it 'flushes general cached data' do - expect(project.repository).to receive(:expire_cache). - with('master', newrev) + it 'calls the after_push_commit hook' do + expect(project.repository).to receive(:after_push_commit).with('master') subject end - it 'flushes the visible content cache' do - expect(project.repository).to receive(:expire_has_visible_content_cache) - - subject - end - - it 'flushes the branches cache' do - expect(project.repository).to receive(:expire_branches_cache) - - subject - end - - it 'flushes the branch count cache' do - expect(project.repository).to receive(:expire_branch_count_cache) + it 'calls the after_create_branch hook' do + expect(project.repository).to receive(:after_create_branch) subject end @@ -56,21 +43,8 @@ describe GitPushService, services: true do context 'existing branch' do it { is_expected.to be_truthy } - it 'flushes general cached data' do - expect(project.repository).to receive(:expire_cache). - with('master', newrev) - - subject - end - - it 'does not flush the branches cache' do - expect(project.repository).not_to receive(:expire_branches_cache) - - subject - end - - it 'does not flush the branch count cache' do - expect(project.repository).not_to receive(:expire_branch_count_cache) + it 'calls the after_push_commit hook' do + expect(project.repository).to receive(:after_push_commit).with('master') subject end @@ -81,27 +55,14 @@ describe GitPushService, services: true do it { is_expected.to be_truthy } - it 'flushes the visible content cache' do - expect(project.repository).to receive(:expire_has_visible_content_cache) - - subject - end - - it 'flushes the branches cache' do - expect(project.repository).to receive(:expire_branches_cache) - - subject - end - - it 'flushes the branch count cache' do - expect(project.repository).to receive(:expire_branch_count_cache) + it 'calls the after_push_commit hook' do + expect(project.repository).to receive(:after_push_commit).with('master') subject end - it 'flushes general cached data' do - expect(project.repository).to receive(:expire_cache). - with('master', newrev) + it 'calls the after_remove_branch hook' do + expect(project.repository).to receive(:after_remove_branch) subject end @@ -598,6 +559,51 @@ describe GitPushService, services: true do end end + describe '#update_caches' do + let(:service) do + described_class.new(project, + user, + oldrev: sample_commit.parent_id, + newrev: sample_commit.id, + ref: 'refs/heads/master') + end + + context 'on the default branch' do + before do + allow(service).to receive(:is_default_branch?).and_return(true) + end + + it 'flushes the caches of any special files that have been changed' do + commit = double(:commit) + diff = double(:diff, new_path: 'README.md') + + expect(commit).to receive(:raw_diffs).with(deltas_only: true). + and_return([diff]) + + service.push_commits = [commit] + + expect(ProjectCacheWorker).to receive(:perform_async). + with(project.id, %i(readme)) + + service.update_caches + end + end + + context 'on a non-default branch' do + before do + allow(service).to receive(:is_default_branch?).and_return(false) + end + + it 'does not flush any conditional caches' do + expect(ProjectCacheWorker).to receive(:perform_async). + with(project.id, []). + and_call_original + + service.update_caches + end + end + end + def execute_service(project, user, oldrev, newrev, ref) service = described_class.new(project, user, oldrev: oldrev, newrev: newrev, ref: ref ) service.execute diff --git a/spec/services/git_tag_push_service_spec.rb b/spec/services/git_tag_push_service_spec.rb index 0879e3ab4c8..bd074b9bd71 100644 --- a/spec/services/git_tag_push_service_spec.rb +++ b/spec/services/git_tag_push_service_spec.rb @@ -18,7 +18,7 @@ describe GitTagPushService, services: true do end it 'flushes general cached data' do - expect(project.repository).to receive(:expire_cache) + expect(project.repository).to receive(:before_push_tag) subject end @@ -28,12 +28,6 @@ describe GitTagPushService, services: true do subject end - - it 'flushes the tag count cache' do - expect(project.repository).to receive(:expire_tag_count_cache) - - subject - end end describe "Git Tag Push Data" do diff --git a/spec/workers/project_cache_worker_spec.rb b/spec/workers/project_cache_worker_spec.rb index bfa8c0ff2c6..855c28b584e 100644 --- a/spec/workers/project_cache_worker_spec.rb +++ b/spec/workers/project_cache_worker_spec.rb @@ -2,62 +2,78 @@ require 'spec_helper' describe ProjectCacheWorker do let(:project) { create(:project) } + let(:worker) { described_class.new } - subject { described_class.new } - - describe '.perform_async' do - it 'schedules the job when no lease exists' do - allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:exists?). - and_return(false) + describe '#perform' do + before do + allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain). + and_return(true) + end - expect_any_instance_of(described_class).to receive(:perform) + context 'with a non-existing project' do + it 'does nothing' do + expect(worker).not_to receive(:update_repository_size) - described_class.perform_async(project.id) + worker.perform(-1) + end end - it 'does not schedule the job when a lease exists' do - allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:exists?). - and_return(true) + context 'with an existing project without a repository' do + it 'does nothing' do + allow_any_instance_of(Repository).to receive(:exists?).and_return(false) - expect_any_instance_of(described_class).not_to receive(:perform) + expect(worker).not_to receive(:update_repository_size) - described_class.perform_async(project.id) + worker.perform(project.id) + end end - end - describe '#perform' do - context 'when an exclusive lease can be obtained' do - before do - allow(subject).to receive(:try_obtain_lease_for).with(project.id). - and_return(true) - end + context 'with an existing project' do + it 'updates the repository size' do + expect(worker).to receive(:update_repository_size).and_call_original - it 'updates project cache data' do - expect_any_instance_of(Repository).to receive(:size) - expect_any_instance_of(Repository).to receive(:commit_count) + worker.perform(project.id) + end - expect_any_instance_of(Project).to receive(:update_repository_size) - expect_any_instance_of(Project).to receive(:update_commit_count) + it 'updates the commit count' do + expect_any_instance_of(Project).to receive(:update_commit_count). + and_call_original - subject.perform(project.id) + worker.perform(project.id) end - it 'handles missing repository data' do - expect_any_instance_of(Repository).to receive(:exists?).and_return(false) - expect_any_instance_of(Repository).not_to receive(:size) + it 'refreshes the method caches' do + expect_any_instance_of(Repository).to receive(:refresh_method_caches). + with(%i(readme)). + and_call_original - subject.perform(project.id) + worker.perform(project.id, %i(readme)) end end + end - context 'when an exclusive lease can not be obtained' do - it 'does nothing' do - allow(subject).to receive(:try_obtain_lease_for).with(project.id). + describe '#update_repository_size' do + context 'when a lease could not be obtained' do + it 'does not update the repository size' do + allow(worker).to receive(:try_obtain_lease_for). + with(project.id, :update_repository_size). and_return(false) - expect(subject).not_to receive(:update_caches) + expect(project).not_to receive(:update_repository_size) + + worker.update_repository_size(project) + end + end + + context 'when a lease could be obtained' do + it 'updates the repository size' do + allow(worker).to receive(:try_obtain_lease_for). + with(project.id, :update_repository_size). + and_return(true) + + expect(project).to receive(:update_repository_size).and_call_original - subject.perform(project.id) + worker.update_repository_size(project) end end end |