diff options
author | Yorick Peterse <yorickpeterse@gmail.com> | 2017-08-14 16:22:09 +0300 |
---|---|---|
committer | Yorick Peterse <yorickpeterse@gmail.com> | 2017-08-14 19:00:28 +0300 |
commit | aef9f1eb9405e9bab92b15f5c99bf06eaf28a5d6 (patch) | |
tree | 01ebae601e9df77c1b2887e0783b73b30f833b2b /spec | |
parent | 21a6898b10ed75f6260e72467b9e1f839d48456c (diff) |
Cache the number of forks of a project
The number of forks of a project doesn't change very frequently and
running a COUNT(*) every time this information is requested can be quite
expensive. We also end up running such a COUNT(*) query at least twice
on the homepage of a project.
By caching this data and refreshing it when necessary we can reduce
project homepage loading times by around 60 milliseconds (based on the
timings of https://gitlab.com/gitlab-org/gitlab-ce).
Diffstat (limited to 'spec')
-rw-r--r-- | spec/models/project_spec.rb | 10 | ||||
-rw-r--r-- | spec/requests/api/projects_spec.rb | 8 | ||||
-rw-r--r-- | spec/requests/api/v3/projects_spec.rb | 8 | ||||
-rw-r--r-- | spec/services/projects/fork_service_spec.rb | 8 | ||||
-rw-r--r-- | spec/services/projects/forks_count_service_spec.rb | 40 | ||||
-rw-r--r-- | spec/services/projects/unlink_fork_service_spec.rb | 10 |
6 files changed, 84 insertions, 0 deletions
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index d9ab44dc49f..eba71ba2f72 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -2310,4 +2310,14 @@ describe Project do end end end + + describe '#forks_count' do + it 'returns the number of forks' do + project = build(:project) + + allow(project.forks).to receive(:count).and_return(1) + + expect(project.forks_count).to eq(1) + end + end end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 6cb27d16fe5..a89a58ff713 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -1065,6 +1065,14 @@ describe API::Projects do expect(project_fork_target.forked?).to be_truthy end + it 'refreshes the forks count cachce' do + expect(project_fork_source.forks_count).to be_zero + + post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin) + + expect(project_fork_source.forks_count).to eq(1) + end + it 'fails if forked_from project which does not exist' do post api("/projects/#{project_fork_target.id}/fork/9999", admin) expect(response).to have_http_status(404) diff --git a/spec/requests/api/v3/projects_spec.rb b/spec/requests/api/v3/projects_spec.rb index fca5b5b5d82..a514166274a 100644 --- a/spec/requests/api/v3/projects_spec.rb +++ b/spec/requests/api/v3/projects_spec.rb @@ -1004,6 +1004,14 @@ describe API::V3::Projects do expect(project_fork_target.forked?).to be_truthy end + it 'refreshes the forks count cachce' do + expect(project_fork_source.forks_count).to be_zero + + post v3_api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin) + + expect(project_fork_source.forks_count).to eq(1) + end + it 'fails if forked_from project which does not exist' do post v3_api("/projects/#{project_fork_target.id}/fork/9999", admin) expect(response).to have_http_status(404) diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb index c90536ba346..21c4b30734c 100644 --- a/spec/services/projects/fork_service_spec.rb +++ b/spec/services/projects/fork_service_spec.rb @@ -50,6 +50,14 @@ describe Projects::ForkService do expect(@from_project.avatar.file).to be_exists end + + it 'flushes the forks count cache of the source project' do + expect(@from_project.forks_count).to be_zero + + fork_project(@from_project, @to_user) + + expect(@from_project.forks_count).to eq(1) + end end end diff --git a/spec/services/projects/forks_count_service_spec.rb b/spec/services/projects/forks_count_service_spec.rb new file mode 100644 index 00000000000..cf299c5d09b --- /dev/null +++ b/spec/services/projects/forks_count_service_spec.rb @@ -0,0 +1,40 @@ +require 'spec_helper' + +describe Projects::ForksCountService do + let(:project) { build(:project, id: 42) } + let(:service) { described_class.new(project) } + + describe '#count' do + it 'returns the number of forks' do + allow(service).to receive(:uncached_count).and_return(1) + + expect(service.count).to eq(1) + end + + it 'caches the forks count', :use_clean_rails_memory_store_caching do + expect(service).to receive(:uncached_count).once.and_return(1) + + 2.times { service.count } + end + end + + describe '#refresh_cache', :use_clean_rails_memory_store_caching do + it 'refreshes the cache' do + expect(service).to receive(:uncached_count).once.and_return(1) + + service.refresh_cache + + expect(service.count).to eq(1) + end + end + + describe '#delete_cache', :use_clean_rails_memory_store_caching do + it 'removes the cache' do + expect(service).to receive(:uncached_count).twice.and_return(1) + + service.count + service.delete_cache + service.count + end + end +end diff --git a/spec/services/projects/unlink_fork_service_spec.rb b/spec/services/projects/unlink_fork_service_spec.rb index 2ae8d5f7c54..4f1ab697460 100644 --- a/spec/services/projects/unlink_fork_service_spec.rb +++ b/spec/services/projects/unlink_fork_service_spec.rb @@ -29,4 +29,14 @@ describe Projects::UnlinkForkService do subject.execute end + + it 'refreshes the forks count cache of the source project' do + source = fork_project.forked_from_project + + expect(source.forks_count).to eq(1) + + subject.execute + + expect(source.forks_count).to be_zero + end end |