summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Bennett <lbennett@gitlab.com>2018-11-29 01:06:10 +0000
committerLuke Bennett <lbennett@gitlab.com>2019-02-18 03:18:13 +0000
commit97e306a7334d64703c3cd4030c6ea3cd33ec5348 (patch)
tree5322245e3eaadb3b39169a90321ba3778d26173e
parent813df901e81257e3175015c94022151824682e83 (diff)
downloadgitlab-ce-ce-improve-admin-licence-page.tar.gz
Add GraphQL Metadata query typece-improve-admin-licence-page
Adds metadata resolver and permissions type. Adds id sort values to Sort type.
-rw-r--r--app/graphql/resolvers/metadata_resolver.rb11
-rw-r--r--app/graphql/types/metadata_type.rb15
-rw-r--r--app/graphql/types/mutation_type.rb3
-rw-r--r--app/graphql/types/permission_types/metadata.rb10
-rw-r--r--app/graphql/types/query_type.rb10
-rw-r--r--app/graphql/types/sort.rb2
-rw-r--r--spec/finders/licenses_finder_spec.rb19
-rw-r--r--spec/graphql/mutations/licenses/delete_spec.rb30
-rw-r--r--spec/graphql/resolvers/license_resolver_spec.rb23
-rw-r--r--spec/graphql/resolvers/licenses_resolver_spec.rb29
-rw-r--r--spec/graphql/resolvers/metadata_resolver_spec.rb16
-rw-r--r--spec/graphql/types/license_type_spec.rb31
-rw-r--r--spec/graphql/types/licensee_type_spec.rb9
-rw-r--r--spec/graphql/types/metadata_type.rb18
-rw-r--r--spec/graphql/types/metadata_type_spec.rb29
-rw-r--r--spec/graphql/types/permission_types/license_spec.rb9
-rw-r--r--spec/graphql/types/permission_types/metadata_spec.rb9
-rw-r--r--spec/graphql/types/query_type_spec.rb4
-rw-r--r--spec/requests/api/graphql/license_type_spec.rb40
-rw-r--r--spec/requests/api/graphql/metadata_type_spec.rb29
-rw-r--r--spec/requests/api/graphql/mutations/licenses/delete_spec.rb33
-rw-r--r--spec/services/licenses/destroy_service_spec.rb20
-rw-r--r--spec/support/helpers/graphql_helpers.rb5
-rw-r--r--spec/support/matchers/graphql_matchers.rb6
24 files changed, 406 insertions, 4 deletions
diff --git a/app/graphql/resolvers/metadata_resolver.rb b/app/graphql/resolvers/metadata_resolver.rb
new file mode 100644
index 00000000000..2b1d0d3952a
--- /dev/null
+++ b/app/graphql/resolvers/metadata_resolver.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Resolvers
+ class MetadataResolver < BaseResolver
+ type Types::MetadataType, null: false
+
+ def resolve
+ { version: Gitlab::VERSION, revision: Gitlab.revision }
+ end
+ end
+end
diff --git a/app/graphql/types/metadata_type.rb b/app/graphql/types/metadata_type.rb
new file mode 100644
index 00000000000..7d5164fb619
--- /dev/null
+++ b/app/graphql/types/metadata_type.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Types
+ class MetadataType < ::Types::BaseObject
+ graphql_name 'Metadata'
+
+ expose_permissions Types::PermissionTypes::Metadata
+
+ field :version, GraphQL::STRING_TYPE, null: false
+ field :revision, GraphQL::STRING_TYPE, null: false
+ end
+end
+
+require_dependency Rails.root.join('ee', 'app', 'graphql', 'types', 'ee', 'metadata_type')
+Types::MetadataType.prepend(EE::Types::MetadataType)
diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb
index 2b4ef299296..513049dff1c 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -9,3 +9,6 @@ module Types
mount_mutation Mutations::MergeRequests::SetWip
end
end
+
+require_dependency Rails.root.join('ee', 'app', 'graphql', 'types', 'ee', 'mutation_type')
+Types::MutationType.prepend(EE::Types::MutationType)
diff --git a/app/graphql/types/permission_types/metadata.rb b/app/graphql/types/permission_types/metadata.rb
new file mode 100644
index 00000000000..1316231786e
--- /dev/null
+++ b/app/graphql/types/permission_types/metadata.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+module Types
+ module PermissionTypes
+ class Metadata < BasePermissionType
+ graphql_name 'MetadataPermissions'
+ abilities :log_in
+ end
+ end
+end
diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb
index 7c41716b82a..22390fc695c 100644
--- a/app/graphql/types/query_type.rb
+++ b/app/graphql/types/query_type.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Types
- class QueryType < BaseObject
+ class QueryType < ::Types::BaseObject
graphql_name 'Query'
field :project, Types::ProjectType,
@@ -11,6 +11,14 @@ module Types
authorize :read_project
end
+ field :metadata, Types::MetadataType,
+ null: true,
+ resolver: Resolvers::MetadataResolver,
+ description: 'Metadata about GitLab' do |*args|
+
+ authorize :log_in
+ end
+
field :echo, GraphQL::STRING_TYPE, null: false, function: Functions::Echo.new
end
end
diff --git a/app/graphql/types/sort.rb b/app/graphql/types/sort.rb
index 1f756fdab69..da6dfd22e5d 100644
--- a/app/graphql/types/sort.rb
+++ b/app/graphql/types/sort.rb
@@ -6,5 +6,7 @@ module Types
value "updated_asc", "Updated at ascending order"
value "created_desc", "Created at descending order"
value "created_asc", "Created at ascending order"
+ value "id_asc", "ID ascending order"
+ value "id_desc", "ID descending order"
end
end
diff --git a/spec/finders/licenses_finder_spec.rb b/spec/finders/licenses_finder_spec.rb
new file mode 100644
index 00000000000..f32d165883e
--- /dev/null
+++ b/spec/finders/licenses_finder_spec.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe LicensesFinder do
+ let(:license) { License.last }
+
+ it 'returns a license by id' do
+ expect(described_class.new(id: license[:id]).execute.take).to eq(license)
+ end
+
+ it 'returns a sorted collection of licenses' do
+ expect(described_class.new(sort: 'id_desc').execute).to contain_exactly(*License.all.order_by('id_desc'))
+ end
+
+ it 'returns empty relation if the license doesnt exist' do
+ expect(described_class.new(id: license[:id] + 1).execute).to be_empty
+ end
+end
diff --git a/spec/graphql/mutations/licenses/delete_spec.rb b/spec/graphql/mutations/licenses/delete_spec.rb
new file mode 100644
index 00000000000..d8ff38eaa86
--- /dev/null
+++ b/spec/graphql/mutations/licenses/delete_spec.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Mutations::Licenses::Delete do
+ describe '#resolve' do
+ set(:license) { create(:license) }
+
+ it 'raises an error if the user cannot update the license' do
+ mutation = described_class.new(object: nil, context: { current_user: create(:user) })
+ expect { mutation.resolve(id: license[:id]) }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+
+ describe 'when the user can update the license' do
+ set(:user) { create(:admin) }
+ subject(:mutation) { described_class.new(object: nil, context: { current_user: user }) }
+
+ it 'returns the deleted license' do
+ response = mutation.resolve(id: license[:id])
+ expect(response[:license]).to eq(license)
+ expect(License.where(id: license[:id])).not_to exist
+ expect(response[:errors]).to be_empty
+ end
+
+ it 'returns an error when the license doesnt exist' do
+ expect { mutation.resolve(id: license[:id] + 1) }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+ end
+end
diff --git a/spec/graphql/resolvers/license_resolver_spec.rb b/spec/graphql/resolvers/license_resolver_spec.rb
new file mode 100644
index 00000000000..5e48c49604e
--- /dev/null
+++ b/spec/graphql/resolvers/license_resolver_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Resolvers::LicenseResolver do
+ include GraphqlHelpers
+
+ let(:license) { License.last }
+
+ describe '#resolve' do
+ it 'returns an existing license found by id' do
+ expect(resolve_license(license[:id])).to eq(license)
+ end
+
+ it 'returns nil if the license doesnt exist' do
+ expect(resolve_license(license[:id] + 1)).to be_nil
+ end
+ end
+
+ def resolve_license(id)
+ resolve(described_class, args: { id: id })
+ end
+end
diff --git a/spec/graphql/resolvers/licenses_resolver_spec.rb b/spec/graphql/resolvers/licenses_resolver_spec.rb
new file mode 100644
index 00000000000..f2465806086
--- /dev/null
+++ b/spec/graphql/resolvers/licenses_resolver_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Resolvers::LicensesResolver do
+ include GraphqlHelpers
+
+ let(:license) { License.last }
+
+ describe '#resolve' do
+ it 'returns a collection of licenses sorted by asc id by default' do
+ expect(resolve_licenses).to contain_exactly(*License.all.order_by('id_asc'))
+ end
+
+ it 'returns a collection of licenses sorted by a provided order_by string' do
+ expect(resolve_licenses('id_desc')).to contain_exactly(*License.all.order_by('id_asc'))
+ end
+
+ it 'returns an array if no licenses exist' do
+ License.delete_all
+
+ expect(resolve_licenses).to eq([])
+ end
+ end
+
+ def resolve_licenses(sort = nil)
+ resolve(described_class, args: { sort: sort })
+ end
+end
diff --git a/spec/graphql/resolvers/metadata_resolver_spec.rb b/spec/graphql/resolvers/metadata_resolver_spec.rb
new file mode 100644
index 00000000000..6fc7bfc355b
--- /dev/null
+++ b/spec/graphql/resolvers/metadata_resolver_spec.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Resolvers::MetadataResolver do
+ include GraphqlHelpers
+
+ describe '#resolve' do
+ it 'resolves the current version and revision' do
+ resolution = resolve(described_class)
+
+ expect(resolution[:version]).to eq(Gitlab::VERSION)
+ expect(resolution[:revision]).to eq(Gitlab.revision)
+ end
+ end
+end
diff --git a/spec/graphql/types/license_type_spec.rb b/spec/graphql/types/license_type_spec.rb
new file mode 100644
index 00000000000..2455131c394
--- /dev/null
+++ b/spec/graphql/types/license_type_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe GitlabSchema.types['License'] do
+ it 'has license permission type' do
+ expect(described_class).to expose_permissions_using(Types::PermissionTypes::License)
+ end
+
+ it 'has required fields' do
+ required_fields = [
+ :id,
+ :plan,
+ :expired,
+ :created_at,
+ :starts_at,
+ :expires_at,
+ :current_active_users_count,
+ :restricted_user_count,
+ :historical_max,
+ :overage,
+ :licensee
+ ]
+
+ is_expected.to have_graphql_field(*required_fields)
+ end
+
+ it 'has a non-null LicenseeType field' do
+ expect(described_class.fields["licensee"]).to have_graphql_type(Types::LicenseeType.to_non_null_type)
+ end
+end
diff --git a/spec/graphql/types/licensee_type_spec.rb b/spec/graphql/types/licensee_type_spec.rb
new file mode 100644
index 00000000000..2d43cf0e0b6
--- /dev/null
+++ b/spec/graphql/types/licensee_type_spec.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe GitlabSchema.types['Licensee'] do
+ it 'has required fields' do
+ is_expected.to have_graphql_field(:name, :email, :company)
+ end
+end
diff --git a/spec/graphql/types/metadata_type.rb b/spec/graphql/types/metadata_type.rb
new file mode 100644
index 00000000000..735a97bb229
--- /dev/null
+++ b/spec/graphql/types/metadata_type.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe GitlabSchema.types['Metadata'] do
+ it 'is called Metadata' do
+ expect(described_class.graphql_name).to eq('Metadata')
+ end
+
+ it 'has license permission type' do
+ expect(described_class).to expose_permissions_using(Types::PermissionTypes::Metadata)
+ end
+
+ it 'has required queries' do
+ is_expected.to have_graphql_field(:version)
+ is_expected.to have_graphql_field(:revision)
+ end
+end
diff --git a/spec/graphql/types/metadata_type_spec.rb b/spec/graphql/types/metadata_type_spec.rb
new file mode 100644
index 00000000000..4e1579e2698
--- /dev/null
+++ b/spec/graphql/types/metadata_type_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe GitlabSchema.types['Metadata'] do
+ context 'license' do
+ subject { described_class.fields['license'] }
+
+ it 'has required arguments, type and resolver' do
+ is_expected.to have_graphql_arguments(:id)
+ is_expected.to have_graphql_type(Types::LicenseType)
+ is_expected.to have_graphql_resolver(Resolvers::LicenseResolver)
+ end
+
+ it 'authorizes with read_license' do
+ is_expected.to require_graphql_authorizations(:read_license)
+ end
+ end
+
+ context 'licenses' do
+ subject { described_class.fields['licenses'] }
+
+ it 'has required arguments, type and resolver' do
+ is_expected.to have_graphql_arguments(:sort, :after, :before, :first, :last)
+ is_expected.to have_graphql_connection_type(Types::LicenseType)
+ is_expected.to have_graphql_resolver(Resolvers::LicensesResolver)
+ end
+ end
+end
diff --git a/spec/graphql/types/permission_types/license_spec.rb b/spec/graphql/types/permission_types/license_spec.rb
new file mode 100644
index 00000000000..9e0ee9e410e
--- /dev/null
+++ b/spec/graphql/types/permission_types/license_spec.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Types::PermissionTypes::License do
+ it 'has required fields' do
+ expect(described_class).to have_graphql_fields([:read_license, :update_license])
+ end
+end
diff --git a/spec/graphql/types/permission_types/metadata_spec.rb b/spec/graphql/types/permission_types/metadata_spec.rb
new file mode 100644
index 00000000000..b136873e37d
--- /dev/null
+++ b/spec/graphql/types/permission_types/metadata_spec.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Types::PermissionTypes::Metadata do
+ it 'has required fields' do
+ expect(described_class).to have_graphql_fields([:logIn])
+ end
+end
diff --git a/spec/graphql/types/query_type_spec.rb b/spec/graphql/types/query_type_spec.rb
index e1df6f9811d..fbe0ea10171 100644
--- a/spec/graphql/types/query_type_spec.rb
+++ b/spec/graphql/types/query_type_spec.rb
@@ -5,7 +5,9 @@ describe GitlabSchema.types['Query'] do
expect(described_class.graphql_name).to eq('Query')
end
- it { is_expected.to have_graphql_fields(:project, :echo) }
+ it 'has required queries' do
+ is_expected.to have_graphql_fields(:project, :echo, :metadata)
+ end
describe 'project field' do
subject { described_class.fields['project'] }
diff --git a/spec/requests/api/graphql/license_type_spec.rb b/spec/requests/api/graphql/license_type_spec.rb
new file mode 100644
index 00000000000..399499ee124
--- /dev/null
+++ b/spec/requests/api/graphql/license_type_spec.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'License' do
+ include GraphqlHelpers
+
+ set(:license) { create(:license, data: build(:gitlab_license, restrictions: { active_user_count: 10 }, licensee: { Email: 'test@gitlab.com', Name: 'Test User', Company: 'GitLab' }).export) }
+ set(:license_two) { create(:license, data: build(:gitlab_license, restrictions: { active_user_count: 10 }, licensee: { Email: 'test@gitlab.com', Name: 'Test User', Company: 'GitLab' }).export) }
+ set(:current_user) { create(:admin) }
+
+ let(:query) do
+ graphql_query_for('metadata', {}, query_graphql_field('license', { id: license[:id] }))
+ end
+
+ it_behaves_like 'a working graphql query' do
+ before do
+ post_graphql(query, current_user: current_user)
+ end
+ end
+
+ context 'licenses collection' do
+ let(:query) do
+ fields = <<~FIELDS
+ edges {
+ node {
+ #{all_graphql_fields_for('license'.classify)}
+ }
+ }
+ FIELDS
+ graphql_query_for('metadata', {}, query_graphql_field('licenses', { after: '', first: 2, sort: :id_desc }, fields))
+ end
+
+ it_behaves_like 'a working graphql query' do
+ before do
+ post_graphql(query, current_user: current_user)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/metadata_type_spec.rb b/spec/requests/api/graphql/metadata_type_spec.rb
new file mode 100644
index 00000000000..a340623918f
--- /dev/null
+++ b/spec/requests/api/graphql/metadata_type_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Metadata' do
+ include GraphqlHelpers
+
+ set(:current_user) { create(:user) }
+ let(:query) do
+ fields = <<~FIELDS
+ version
+ revision
+ FIELDS
+ graphql_query_for('metadata', {}, fields)
+ end
+
+ it_behaves_like 'a working graphql query' do
+ before do
+ post_graphql(query, current_user: current_user)
+ end
+ end
+
+ it 'returns version and revision' do
+ post_graphql(query, current_user: current_user)
+
+ expect(graphql_data['metadata']['version']).to eq(Gitlab::VERSION)
+ expect(graphql_data['metadata']['revision']).to eq(Gitlab.revision)
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/licenses/delete_spec.rb b/spec/requests/api/graphql/mutations/licenses/delete_spec.rb
new file mode 100644
index 00000000000..e3632a26ab8
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/licenses/delete_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Deleting an instance license' do
+ include GraphqlHelpers
+
+ set(:user) { create(:admin) }
+ set(:license) { create(:license) }
+ let(:mutation) do
+ variables = {
+ id: license[:id]
+ }
+ graphql_mutation(:license_delete, variables)
+ end
+
+ def mutation_response
+ graphql_mutation_response(:license_delete)
+ end
+
+ it 'returns an error if the user is not allowed to update the license' do
+ post_graphql_mutation(mutation, current_user: create(:user))
+
+ expect(graphql_errors).not_to be_empty
+ end
+
+ it 'deletes the license' do
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(License.where(id: license[:id])).not_to exist
+ end
+end
diff --git a/spec/services/licenses/destroy_service_spec.rb b/spec/services/licenses/destroy_service_spec.rb
new file mode 100644
index 00000000000..f4aad2c618b
--- /dev/null
+++ b/spec/services/licenses/destroy_service_spec.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+describe Licenses::DestroyService do
+ set(:license) { create(:license) }
+
+ def destroy(user)
+ described_class.new(license, user).execute
+ end
+
+ it 'destroys a license' do
+ destroy(create(:admin))
+
+ expect(License.where(id: license[:id])).not_to exist
+ end
+
+ it 'raises an error if the user cannot delete the license' do
+ expect { destroy(create(:user)) }.to raise_error Gitlab::Access::AccessDeniedError
+ end
+end
diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb
index e468ee4676d..40fb6aa66af 100644
--- a/spec/support/helpers/graphql_helpers.rb
+++ b/spec/support/helpers/graphql_helpers.rb
@@ -12,7 +12,7 @@ module GraphqlHelpers
# Run a loader's named resolver
def resolve(resolver_class, obj: nil, args: {}, ctx: {})
- resolver_class.new(object: obj, context: ctx).resolve(args)
+ resolver_class.new(object: obj, context: ctx).resolve(**args)
end
# Runs a block inside a BatchLoader::Executor wrapper
@@ -111,7 +111,8 @@ module GraphqlHelpers
def attributes_to_graphql(attributes)
attributes.map do |name, value|
- "#{GraphqlHelpers.fieldnamerize(name.to_s)}: \"#{value}\""
+ attribute = "#{GraphqlHelpers.fieldnamerize(name.to_s)}: "
+ attribute << (value.is_a?(Integer) || value.is_a?(Symbol) ? value.to_s : "\"#{value}\"")
end.join(", ")
end
diff --git a/spec/support/matchers/graphql_matchers.rb b/spec/support/matchers/graphql_matchers.rb
index 7be84838e00..ea106a43123 100644
--- a/spec/support/matchers/graphql_matchers.rb
+++ b/spec/support/matchers/graphql_matchers.rb
@@ -58,6 +58,12 @@ RSpec::Matchers.define :have_graphql_type do |expected|
end
end
+RSpec::Matchers.define :have_graphql_connection_type do |expected|
+ match do |field|
+ expect(field.type).to eq(expected.connection_type)
+ end
+end
+
RSpec::Matchers.define :have_graphql_resolver do |expected|
match do |field|
case expected