summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorSean McGivern <sean@mcgivern.me.uk>2016-11-21 17:08:36 +0000
committerSean McGivern <sean@mcgivern.me.uk>2016-11-21 17:08:36 +0000
commit55ca2da7683a33872a25b2402435449435294c93 (patch)
treeae5daa45d0dd16dbad406e1054db05a9df26607f /spec
parentd3236af1ae8cbe6cc1a0b813789f7ba040550f02 (diff)
parent289e433685867dbc569adc4e7d137253bb42c3c8 (diff)
downloadgitlab-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.rb59
-rw-r--r--spec/models/project_spec.rb2
-rw-r--r--spec/models/repository_spec.rb477
-rw-r--r--spec/requests/api/branches_spec.rb2
-rw-r--r--spec/services/git_push_service_spec.rb104
-rw-r--r--spec/services/git_tag_push_service_spec.rb8
-rw-r--r--spec/workers/project_cache_worker_spec.rb86
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