diff options
author | Alessio Caiazza <acaiazza@gitlab.com> | 2019-08-23 01:08:28 +0300 |
---|---|---|
committer | Mayra Cabrera <mcabrera@gitlab.com> | 2019-08-23 01:08:28 +0300 |
commit | 606a1d2d31aff69ddabe7e3794f61f3e778da3e8 (patch) | |
tree | bfaee792fd551070a3581c77bc52164610f03b2a /spec | |
parent | c65ea080ba8637f0e83ea97b091e4ab3ebbce635 (diff) |
Expose namespace storage statistics with GraphQL
Root namespaces have storage statistics.
This commit allows namespace owners to get those stats via GraphQL
queries like the following one
{
namespace(fullPath: "a_namespace_path") {
rootStorageStatistics {
storageSize
repositorySize
lfsObjectsSize
buildArtifactsSize
packagesSize
wikiSize
}
}
}
Diffstat (limited to 'spec')
9 files changed, 185 insertions, 4 deletions
diff --git a/spec/graphql/types/namespace_type_spec.rb b/spec/graphql/types/namespace_type_spec.rb index e1153832cc9..f476dd7286f 100644 --- a/spec/graphql/types/namespace_type_spec.rb +++ b/spec/graphql/types/namespace_type_spec.rb @@ -8,7 +8,7 @@ describe GitlabSchema.types['Namespace'] do it 'has the expected fields' do expected_fields = %w[ id name path full_name full_path description description_html visibility - lfs_enabled request_access_enabled projects + lfs_enabled request_access_enabled projects root_storage_statistics ] is_expected.to have_graphql_fields(*expected_fields) diff --git a/spec/graphql/types/root_storage_statistics_type_spec.rb b/spec/graphql/types/root_storage_statistics_type_spec.rb new file mode 100644 index 00000000000..8c69c13aa73 --- /dev/null +++ b/spec/graphql/types/root_storage_statistics_type_spec.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe GitlabSchema.types['RootStorageStatistics'] do + it { expect(described_class.graphql_name).to eq('RootStorageStatistics') } + + it 'has all the required fields' do + is_expected.to have_graphql_fields(:storage_size, :repository_size, :lfs_objects_size, + :build_artifacts_size, :packages_size, :wiki_size) + end + + it { is_expected.to require_graphql_authorizations(:read_statistics) } +end diff --git a/spec/lib/gitlab/graphql/loaders/batch_root_storage_statistics_loader_spec.rb b/spec/lib/gitlab/graphql/loaders/batch_root_storage_statistics_loader_spec.rb new file mode 100644 index 00000000000..38931f7ab5e --- /dev/null +++ b/spec/lib/gitlab/graphql/loaders/batch_root_storage_statistics_loader_spec.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Graphql::Loaders::BatchRootStorageStatisticsLoader do + describe '#find' do + it 'only queries once for project statistics' do + stats = create_list(:namespace_root_storage_statistics, 2) + namespace1 = stats.first.namespace + namespace2 = stats.last.namespace + + expect do + described_class.new(namespace1.id).find + described_class.new(namespace2.id).find + end.not_to exceed_query_limit(1) + end + end +end diff --git a/spec/models/namespace/root_storage_statistics_spec.rb b/spec/models/namespace/root_storage_statistics_spec.rb index 5341278db7c..9e12831a704 100644 --- a/spec/models/namespace/root_storage_statistics_spec.rb +++ b/spec/models/namespace/root_storage_statistics_spec.rb @@ -8,6 +8,19 @@ RSpec.describe Namespace::RootStorageStatistics, type: :model do it { is_expected.to delegate_method(:all_projects).to(:namespace) } + context 'scopes' do + describe '.for_namespace_ids' do + it 'returns only requested namespaces' do + stats = create_list(:namespace_root_storage_statistics, 3) + namespace_ids = stats[0..1].map { |s| s.namespace_id } + + requested_stats = described_class.for_namespace_ids(namespace_ids).pluck(:namespace_id) + + expect(requested_stats).to eq(namespace_ids) + end + end + end + describe '#recalculate!' do let(:namespace) { create(:group) } let(:root_storage_statistics) { create(:namespace_root_storage_statistics, namespace: namespace) } diff --git a/spec/policies/namespace/root_storage_statistics_policy_spec.rb b/spec/policies/namespace/root_storage_statistics_policy_spec.rb new file mode 100644 index 00000000000..8d53050fffb --- /dev/null +++ b/spec/policies/namespace/root_storage_statistics_policy_spec.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Namespace::RootStorageStatisticsPolicy do + using RSpec::Parameterized::TableSyntax + + describe '#rules' do + let(:statistics) { create(:namespace_root_storage_statistics, namespace: namespace) } + let(:user) { create(:user) } + + subject { Ability.allowed?(user, :read_statistics, statistics) } + + shared_examples 'deny anonymous users' do + context 'when the users is anonymous' do + let(:user) { nil } + + it { is_expected.to be_falsey } + end + end + + context 'when the namespace is a personal namespace' do + let(:owner) { create(:user) } + let(:namespace) { owner.namespace } + + include_examples 'deny anonymous users' + + context 'when the user is not the owner' do + it { is_expected.to be_falsey } + end + + context 'when the user is the owner' do + let(:user) { owner } + + it { is_expected.to be_truthy } + end + end + + context 'when the namespace is a group' do + let(:user) { create(:user) } + let(:external) { create(:user, :external) } + + shared_examples 'allows only owners' do |group_type| + let(:group) { create(:group, visibility_level: Gitlab::VisibilityLevel.level_value(group_type.to_s)) } + let(:namespace) { group } + + include_examples 'deny anonymous users' + + where(:user_type, :outcome) do + [ + [:non_member, false], + [:guest, false], + [:reporter, false], + [:developer, false], + [:maintainer, false], + [:owner, true] + ] + end + + with_them do + before do + group.add_user(user, user_type) unless user_type == :non_member + end + + it { is_expected.to eq(outcome) } + + context 'when the user is external' do + let(:user) { external } + + it { is_expected.to eq(outcome) } + end + end + end + + include_examples 'allows only owners', :public + include_examples 'allows only owners', :private + include_examples 'allows only owners', :internal + end + end +end diff --git a/spec/policies/namespace_policy_spec.rb b/spec/policies/namespace_policy_spec.rb index 99fa8b1fe44..216aaae70ee 100644 --- a/spec/policies/namespace_policy_spec.rb +++ b/spec/policies/namespace_policy_spec.rb @@ -6,7 +6,7 @@ describe NamespacePolicy do let(:admin) { create(:admin) } let(:namespace) { create(:namespace, owner: owner) } - let(:owner_permissions) { [:create_projects, :admin_namespace, :read_namespace] } + let(:owner_permissions) { [:create_projects, :admin_namespace, :read_namespace, :read_statistics] } subject { described_class.new(current_user, namespace) } diff --git a/spec/requests/api/graphql/namespace/root_storage_statistics_spec.rb b/spec/requests/api/graphql/namespace/root_storage_statistics_spec.rb new file mode 100644 index 00000000000..ac76d991bd4 --- /dev/null +++ b/spec/requests/api/graphql/namespace/root_storage_statistics_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'rendering namespace statistics' do + include GraphqlHelpers + + let(:namespace) { user.namespace } + let!(:statistics) { create(:namespace_root_storage_statistics, namespace: namespace, packages_size: 5.megabytes) } + let(:user) { create(:user) } + + let(:query) do + graphql_query_for('namespace', + { 'fullPath' => namespace.full_path }, + "rootStorageStatistics { #{all_graphql_fields_for('RootStorageStatistics')} }") + end + + shared_examples 'a working namespace with storage statistics query' do + it_behaves_like 'a working graphql query' do + before do + post_graphql(query, current_user: user) + end + end + + it 'includes the packages size if the user can read the statistics' do + post_graphql(query, current_user: user) + + expect(graphql_data['namespace']['rootStorageStatistics']).not_to be_blank + expect(graphql_data['namespace']['rootStorageStatistics']['packagesSize']).to eq(5.megabytes) + end + end + + it_behaves_like 'a working namespace with storage statistics query' + + context 'when the namespace is a group' do + let(:group) { create(:group) } + let(:namespace) { group } + + before do + group.add_owner(user) + end + + it_behaves_like 'a working namespace with storage statistics query' + + context 'when the namespace is public' do + let(:group) { create(:group, :public)} + + it 'hides statistics for unauthenticated requests' do + post_graphql(query, current_user: nil) + + expect(graphql_data['namespace']).to be_blank + end + end + end +end diff --git a/spec/requests/api/graphql/project/project_statistics_spec.rb b/spec/requests/api/graphql/project/project_statistics_spec.rb index 14a3f37b779..ddee8537454 100644 --- a/spec/requests/api/graphql/project/project_statistics_spec.rb +++ b/spec/requests/api/graphql/project/project_statistics_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe 'rendering namespace statistics' do +describe 'rendering project statistics' do include GraphqlHelpers let(:project) { create(:project) } diff --git a/spec/support/shared_contexts/policies/group_policy_shared_context.rb b/spec/support/shared_contexts/policies/group_policy_shared_context.rb index fd24c443288..b89723b1e1a 100644 --- a/spec/support/shared_contexts/policies/group_policy_shared_context.rb +++ b/spec/support/shared_contexts/policies/group_policy_shared_context.rb @@ -31,7 +31,8 @@ RSpec.shared_context 'GroupPolicy context' do :admin_group_member, :change_visibility_level, :set_note_created_at, - :create_subgroup + :create_subgroup, + :read_statistics ].compact end |