diff --git a/app/controllers/v3/spaces_controller.rb b/app/controllers/v3/spaces_controller.rb index deb534ef2cf..8feb4c3e6e6 100644 --- a/app/controllers/v3/spaces_controller.rb +++ b/app/controllers/v3/spaces_controller.rb @@ -1,6 +1,7 @@ require 'presenters/v3/paginated_list_presenter' require 'presenters/v3/space_presenter' require 'presenters/v3/space_usage_summary_presenter' +require 'presenters/v3/effective_space_quota_presenter' require 'messages/space_create_message' require 'messages/space_delete_unmapped_routes_message' require 'messages/space_update_message' @@ -220,6 +221,16 @@ def show_usage_summary render status: :ok, json: Presenters::V3::SpaceUsageSummaryPresenter.new(space) end + def show_effective_quota + space = fetch_space(hashed_params[:guid]) + space_not_found! unless space + space_not_found! unless permission_queryer.can_read_from_space?(space.id, space.organization_id) + + effective_quota = VCAP::CloudController::EffectiveSpaceQuotaCalculator.calculate(space) + + render status: :ok, json: Presenters::V3::EffectiveSpaceQuotaPresenter.new(effective_quota, space) + end + private def fetch_organization(guid) diff --git a/app/presenters/helpers/quota_presenter_builder.rb b/app/presenters/helpers/quota_presenter_builder.rb new file mode 100644 index 00000000000..7b8a2a204d8 --- /dev/null +++ b/app/presenters/helpers/quota_presenter_builder.rb @@ -0,0 +1,64 @@ +module VCAP::CloudController::Presenters + class QuotaPresenterBuilder + def initialize(quota) + @quota = quota + @hash = {} + end + + def build + @hash + end + + def add_resource_limits + @hash.merge!({ + apps: { + total_memory_in_mb: unlimited_to_nil(@quota.memory_limit), + per_process_memory_in_mb: unlimited_to_nil(@quota.instance_memory_limit), + total_instances: unlimited_to_nil(@quota.app_instance_limit), + per_app_tasks: unlimited_to_nil(@quota.app_task_limit), + log_rate_limit_in_bytes_per_second: unlimited_to_nil(@quota.log_rate_limit) + }, + services: { + paid_services_allowed: @quota.non_basic_services_allowed, + total_service_instances: unlimited_to_nil(@quota.total_services), + total_service_keys: unlimited_to_nil(@quota.total_service_keys) + }, + routes: { + total_routes: unlimited_to_nil(@quota.total_routes), + total_reserved_ports: unlimited_to_nil(@quota.total_reserved_route_ports) + } + }) + + if @quota.respond_to?(:guid) + @hash[:guid] = @quota.guid + @hash[:created_at] = @quota.created_at + @hash[:updated_at] = @quota.updated_at + @hash[:name] = @quota.name + end + self + end + + def add_domains + @hash[:domains] = { + total_domains: unlimited_to_nil(@quota.total_private_domains) + } + self + end + + def add_relationships(relationships) + @hash[:relationships] = relationships + self + end + + def add_links(links) + @hash[:links] = links + self + end + + private + + def unlimited_to_nil(value) + value == -1 ? nil : value + end + end +end diff --git a/app/presenters/v3/effective_space_quota_presenter.rb b/app/presenters/v3/effective_space_quota_presenter.rb new file mode 100644 index 00000000000..6a4c37c3d9a --- /dev/null +++ b/app/presenters/v3/effective_space_quota_presenter.rb @@ -0,0 +1,32 @@ +require 'presenters/v3/base_presenter' +require 'presenters/helpers/quota_presenter_builder' + +module VCAP::CloudController::Presenters::V3 + class EffectiveSpaceQuotaPresenter < BasePresenter + def initialize(effective_space_quota, space) + super(effective_space_quota) + @space = space + end + + def to_hash + builder = VCAP::CloudController::Presenters::QuotaPresenterBuilder.new(effective_space_quota) + builder.add_resource_limits + builder.add_links(build_links) + builder.build + end + + private + + def build_links + { + self: { href: url_builder.build_url(path: "/v3/spaces/#{@space.guid}/effective_quota") }, + usage_summary: { href: url_builder.build_url(path: "/v3/spaces/#{@space.guid}/usage_summary") }, + space: { href: url_builder.build_url(path: "/v3/spaces/#{@space.guid}") } + } + end + + def effective_space_quota + @resource + end + end +end diff --git a/app/presenters/v3/organization_quota_presenter.rb b/app/presenters/v3/organization_quota_presenter.rb index 9e87e174802..88a523e9477 100644 --- a/app/presenters/v3/organization_quota_presenter.rb +++ b/app/presenters/v3/organization_quota_presenter.rb @@ -1,5 +1,6 @@ require 'presenters/v3/base_presenter' require 'presenters/mixins/metadata_presentation_helpers' +require 'presenters/helpers/quota_presenter_builder' module VCAP::CloudController::Presenters::V3 class OrganizationQuotaPresenter < BasePresenter @@ -16,59 +17,42 @@ def initialize( end def to_hash - { - guid: organization_quota.guid, - created_at: organization_quota.created_at, - updated_at: organization_quota.updated_at, - name: organization_quota.name, - apps: { - total_memory_in_mb: convert_unlimited_to_nil(organization_quota.memory_limit), - per_process_memory_in_mb: convert_unlimited_to_nil(organization_quota.instance_memory_limit), - total_instances: convert_unlimited_to_nil(organization_quota.app_instance_limit), - per_app_tasks: convert_unlimited_to_nil(organization_quota.app_task_limit), - log_rate_limit_in_bytes_per_second: convert_unlimited_to_nil(organization_quota.log_rate_limit) - }, - services: { - paid_services_allowed: organization_quota.non_basic_services_allowed, - total_service_instances: convert_unlimited_to_nil(organization_quota.total_services), - total_service_keys: convert_unlimited_to_nil(organization_quota.total_service_keys) - }, - routes: { - total_routes: convert_unlimited_to_nil(organization_quota.total_routes), - total_reserved_ports: convert_unlimited_to_nil(organization_quota.total_reserved_route_ports) - }, - domains: { - total_domains: convert_unlimited_to_nil(organization_quota.total_private_domains) - }, - relationships: { - organizations: { - data: filtered_visible_orgs - } - }, - links: build_links - } + builder = VCAP::CloudController::Presenters::QuotaPresenterBuilder.new(quota) + builder.add_resource_limits. + add_domains. + add_relationships(relationships). + add_links(build_links) + builder.build end private - def filtered_visible_orgs - ds = organization_quota.organizations_dataset - ds = ds.where(guid: @visible_org_guids_query) unless @all_orgs_visible - ds.select_map(:guid).map { |g| { guid: g } } + def quota + @resource end - def organization_quota - @resource + def relationships + { + organizations: { + data: filtered_visible_orgs + } + } end - def convert_unlimited_to_nil(value) - value == -1 ? nil : value + def filtered_visible_orgs + ds = quota.organizations_dataset + ds = ds.where(guid: @visible_org_guids_query) unless @all_orgs_visible + ds.select_map(:guid).map { |g| { guid: g } } end def build_links { - self: { href: url_builder.build_url(path: "/v3/organization_quotas/#{organization_quota.guid}") } + self: { href: url_builder.build_url(path: "/v3/organization_quotas/#{quota.guid}") } } end + + def unlimited_to_nil(value) + value == -1 ? nil : value + end end end diff --git a/app/presenters/v3/space_quota_presenter.rb b/app/presenters/v3/space_quota_presenter.rb index 2f375398f4f..267bdebed16 100644 --- a/app/presenters/v3/space_quota_presenter.rb +++ b/app/presenters/v3/space_quota_presenter.rb @@ -1,5 +1,6 @@ require 'presenters/v3/base_presenter' require 'presenters/mixins/metadata_presentation_helpers' +require 'presenters/helpers/quota_presenter_builder' module VCAP::CloudController::Presenters::V3 class SpaceQuotaPresenter < BasePresenter @@ -16,63 +17,44 @@ def initialize( end def to_hash - { - guid: space_quota.guid, - created_at: space_quota.created_at, - updated_at: space_quota.updated_at, - name: space_quota.name, - apps: { - total_memory_in_mb: unlimited_to_nil(space_quota.memory_limit), - per_process_memory_in_mb: unlimited_to_nil(space_quota.instance_memory_limit), - total_instances: unlimited_to_nil(space_quota.app_instance_limit), - per_app_tasks: unlimited_to_nil(space_quota.app_task_limit), - log_rate_limit_in_bytes_per_second: unlimited_to_nil(space_quota.log_rate_limit) - }, - services: { - paid_services_allowed: space_quota.non_basic_services_allowed, - total_service_instances: unlimited_to_nil(space_quota.total_services), - total_service_keys: unlimited_to_nil(space_quota.total_service_keys) - }, - routes: { - total_routes: unlimited_to_nil(space_quota.total_routes), - total_reserved_ports: unlimited_to_nil(space_quota.total_reserved_route_ports) - }, - relationships: { - organization: { - data: { guid: space_quota.organization.guid } - }, - spaces: { - data: filtered_visible_spaces - } - }, - links: build_links - } + builder = VCAP::CloudController::Presenters::QuotaPresenterBuilder.new(quota) + builder.add_resource_limits. + add_relationships(relationships). + add_links(build_links) + builder.build end private - def space_quota + def quota @resource end + def relationships + { + organization: { + data: { guid: quota.organization.guid } + }, + spaces: { + data: filtered_visible_spaces + } + } + end + def filtered_visible_spaces visible_spaces = if @all_spaces_visible - space_quota.spaces + quota.spaces else - space_quota.spaces.select { |space| @visible_space_guids.include? space.guid } + quota.spaces.select { |space| @visible_space_guids.include? space.guid } end visible_spaces.map { |space| { guid: space.guid } } end def build_links { - self: { href: url_builder.build_url(path: "/v3/space_quotas/#{space_quota.guid}") }, - organization: { href: url_builder.build_url(path: "/v3/organizations/#{space_quota.organization.guid}") } + self: { href: url_builder.build_url(path: "/v3/space_quotas/#{quota.guid}") }, + organization: { href: url_builder.build_url(path: "/v3/organizations/#{quota.organization.guid}") } } end - - def unlimited_to_nil(value) - value == -1 ? nil : value - end end end diff --git a/config/routes.rb b/config/routes.rb index ccdd5788eaf..f018d6b28aa 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -277,6 +277,7 @@ delete 'spaces/:guid', to: 'spaces_v3#destroy' delete 'spaces/:guid/routes', to: 'spaces_v3#delete_unmapped_routes' get '/spaces/:guid/usage_summary', to: 'spaces_v3#show_usage_summary' + get 'spaces/:guid/effective_quota', to: 'spaces_v3#show_effective_quota' get '/spaces/:guid/relationships/isolation_segment', to: 'spaces_v3#show_isolation_segment' patch '/spaces/:guid/relationships/isolation_segment', to: 'spaces_v3#update_isolation_segment' get '/spaces/:guid/users', to: 'spaces_v3#list_members' diff --git a/docs/v3/source/includes/api_resources/_spaces.erb b/docs/v3/source/includes/api_resources/_spaces.erb index e9a24461bf2..b4d56618462 100644 --- a/docs/v3/source/includes/api_resources/_spaces.erb +++ b/docs/v3/source/includes/api_resources/_spaces.erb @@ -162,9 +162,42 @@ "self": { "href": "https://api.example.org/v3/spaces/f47ac10b-58cc-4372-a567-0e02b2c3d479/usage_summary" }, - "organization": { + "space": { "href": "https://api.example.org/v3/spaces/f47ac10b-58cc-4372-a567-0e02b2c3d479" } } } <% end %> + +<% content_for :effective_space_quota do %> +{ + "apps": { + "total_memory_in_mb": 10240, + "total_instances": 100, + "total_routes": 2000, + "total_service_instances": 1000, + "paid_service_plans_allowed": true + }, + "services": { + "total_service_instances": 1000, + "paid_service_plans_allowed": true + }, + "routes": { + "total_routes": 2000 + }, + "domains": { + "total_private_domains": 10 + }, + "links": { + "self": { + "href": "https://api.example.org/v3/spaces/f47ac10b-58cc-4372-a567-0e02b2c3d479/effective_quota" + }, + "usage_summary": { + "href": "https://api.example.org/v3/spaces/f47ac10b-58cc-4372-a567-0e02b2c3d479/usage_summary" + }, + "space": { + "href": "https://api.example.org/v3/spaces/f47ac10b-58cc-4372-a567-0e02b2c3d479" + } + } +} +<% end %> \ No newline at end of file diff --git a/docs/v3/source/includes/resources/spaces/_get_effective_space_quota.md.erb b/docs/v3/source/includes/resources/spaces/_get_effective_space_quota.md.erb new file mode 100644 index 00000000000..841b0716676 --- /dev/null +++ b/docs/v3/source/includes/resources/spaces/_get_effective_space_quota.md.erb @@ -0,0 +1,40 @@ +### Get effective space quota (experimental) + +``` +Example Request +``` + +```shell +curl "https://api.example.org/v3/spaces/[guid]/effective_quota" \ + -X GET \ + -H "Authorization: bearer [token]" +``` + +``` +Example Response +``` + +```http +HTTP/1.1 200 OK +Content-Type: application/json + +<%= yield_content :effective_space_quota, '/v3/spaces/:guid/effective_quota' %> +``` + +This endpoint retrieves the effective quota for the specified space to show the actual applicable resource limits. +The effective quota is dynamically calculated based on the space's and its organization's assigned quotas. + +#### Definition +`GET /v3/spaces/:guid/effective_quota` + +#### Permitted roles +| +--- | +Admin | +Admin Read-Only | +Global Auditor | +Org Manager | +Space Auditor | +Space Developer | +Space Manager | +Space Supporter | diff --git a/docs/v3/source/index.html.md b/docs/v3/source/index.html.md index c007e7fc7de..21bd58090fd 100644 --- a/docs/v3/source/index.html.md +++ b/docs/v3/source/index.html.md @@ -355,6 +355,7 @@ includes: - resources/spaces/delete - resources/spaces/get_assigned_isolation_segment - resources/spaces/get_usage_summary + - resources/spaces/get_effective_space_quota - resources/spaces/manage_isolation_segment - resources/spaces/list_users - resources/space_features/header diff --git a/lib/cloud_controller.rb b/lib/cloud_controller.rb index 4a3faffffd7..01f04d23812 100644 --- a/lib/cloud_controller.rb +++ b/lib/cloud_controller.rb @@ -78,6 +78,7 @@ module VCAP::CloudController; end require 'cloud_controller/organization_instance_usage_calculator' require 'cloud_controller/organization_quota_usage' require 'cloud_controller/url_secret_obfuscator' +require 'cloud_controller/effective_space_quota_calculator' require 'cloud_controller/legacy_api/legacy_api_base' require 'cloud_controller/legacy_api/legacy_info' diff --git a/lib/cloud_controller/effective_space_quota_calculator.rb b/lib/cloud_controller/effective_space_quota_calculator.rb new file mode 100644 index 00000000000..892ef1eb43a --- /dev/null +++ b/lib/cloud_controller/effective_space_quota_calculator.rb @@ -0,0 +1,32 @@ +module VCAP::CloudController + class EffectiveSpaceQuotaCalculator + def self.calculate(space) + space_quota = space.space_quota_definition + org_quota = space.organization.quota_definition + + quota_attributes = VCAP::CloudController::QuotaDefinition.columns - %i[id guid created_at updated_at name] # remove attributes not needed in effective quota + effective_quota_struct = Struct.new(*quota_attributes, keyword_init: true) + + effective_quota = {} + + quota_attributes.each do |col| + effective_quota[col] = if space_quota.nil? || !space_quota.respond_to?(col) + org_quota.send(col) + elsif col == :non_basic_services_allowed + space_quota.non_basic_services_allowed && org_quota.non_basic_services_allowed + else + calculate_limit(space_quota.send(col), org_quota.send(col)) + end + end + + effective_quota_struct.new(effective_quota) + end + + def self.calculate_limit(space_limit, org_limit) + return org_limit if space_limit == -1 + return space_limit if org_limit == -1 + + [space_limit, org_limit].min + end + end +end diff --git a/spec/unit/lib/cloud_controller/effective_space_quota_calculator_spec.rb b/spec/unit/lib/cloud_controller/effective_space_quota_calculator_spec.rb new file mode 100644 index 00000000000..cff8183dd3f --- /dev/null +++ b/spec/unit/lib/cloud_controller/effective_space_quota_calculator_spec.rb @@ -0,0 +1,49 @@ +require 'spec_helper' +require 'cloud_controller/effective_space_quota_calculator' + +module VCAP::CloudController + RSpec.describe EffectiveSpaceQuotaCalculator do + let(:org_quota) { QuotaDefinition.make(memory_limit: 500, log_rate_limit: 1000, app_instance_limit: 50, app_task_limit: 10, total_service_keys: -1) } + let(:org) { Organization.make(quota_definition: org_quota) } + + context 'when space has no space quota defined' do + let(:space) { Space.make(organization: org) } + + it 'returns the organization quota as the effective space quota' do + effective_quota = described_class.calculate(space) + expect(effective_quota.as_json).to include(org_quota.as_json.except('name', 'trial_db_allowed')) + end + end + + context 'when space has a space quota defined' do + let(:space_quota) do + SpaceQuotaDefinition.make(organization: org, memory_limit: 200, log_rate_limit: 2000, app_instance_limit: 100, app_task_limit: -1, total_service_keys: 2) + end + let(:space) { Space.make(organization: org, space_quota_definition: space_quota) } + + it 'calculates the effective space quota based on space and organization quotas' do + effective_quota = described_class.calculate(space) + expect(effective_quota.memory_limit).to eq(200) + expect(effective_quota.log_rate_limit).to eq(1000) + expect(effective_quota.app_instance_limit).to eq(50) + expect(effective_quota.app_task_limit).to eq(10) + expect(effective_quota.total_service_keys).to eq(2) + end + end + + context 'when org has no organization quota defined' do + let(:org) { Organization.make(quota_definition: nil) } + let(:space_quota) do + SpaceQuotaDefinition.make(organization: org, memory_limit: 200, log_rate_limit: 2000, app_instance_limit: 100, app_task_limit: -1, total_service_keys: 2, + total_reserved_route_ports: 0) + end + let(:space) { Space.make(organization: org, space_quota_definition: space_quota) } + + it 'returns the space quota as the effective space quota' do + effective_quota = described_class.calculate(space) + # Ignore fields which are not part of space quota, not relevant or deprecated + expect(effective_quota.as_json.except('total_private_domains')).to include(space_quota.as_json.except('name', 'trial_db_allowed', 'organization_guid')) + end + end + end +end diff --git a/spec/unit/presenters/helpers/quota_presenter_builder_spec.rb b/spec/unit/presenters/helpers/quota_presenter_builder_spec.rb new file mode 100644 index 00000000000..00ed951f46f --- /dev/null +++ b/spec/unit/presenters/helpers/quota_presenter_builder_spec.rb @@ -0,0 +1,94 @@ +require 'spec_helper' +require 'presenters/helpers/quota_presenter_builder' + +module VCAP::CloudController::Presenters + RSpec.describe QuotaPresenterBuilder do + let(:quota_struct) do + Struct.new( + :memory_limit, + :instance_memory_limit, + :app_instance_limit, + :app_task_limit, + :log_rate_limit, + :non_basic_services_allowed, + :total_services, + :total_service_keys, + :total_routes, + :total_reserved_route_ports + ) + end + let(:quota) { quota_struct.new(1024, 512, 10, 5, 1000, true, 50, -1, 100, 10) } + + describe '#add_resource_limits' do + let(:quota_hash) { QuotaPresenterBuilder.new(quota).add_resource_limits.build } + + it 'builds the quota hash with resource limits' do + expect(quota_hash).to eq({ + apps: { + total_memory_in_mb: 1024, + per_process_memory_in_mb: 512, + total_instances: 10, + per_app_tasks: 5, + log_rate_limit_in_bytes_per_second: 1000 + }, + services: { + paid_services_allowed: true, + total_service_instances: 50, + total_service_keys: nil + }, + routes: { + total_routes: 100, + total_reserved_ports: 10 + } + }) + end + + context 'when the quota is an organization quota' do + let(:quota) { VCAP::CloudController::QuotaDefinition.make(name: 'org-quota') } + + it 'includes guid, created_at, updated_at, and name in the quota hash' do + expect(quota_hash[:guid]).to eq(quota.guid) + expect(quota_hash[:created_at]).to eq(quota.created_at) + expect(quota_hash[:updated_at]).to eq(quota.updated_at) + expect(quota_hash[:name]).to eq('org-quota') + end + end + + context 'when the quota is a space quota' do + let(:quota) { VCAP::CloudController::SpaceQuotaDefinition.make(name: 'space-quota') } + + it 'includes guid, created_at, updated_at, and name in the quota hash' do + expect(quota_hash[:guid]).to eq(quota.guid) + expect(quota_hash[:created_at]).to eq(quota.created_at) + expect(quota_hash[:updated_at]).to eq(quota.updated_at) + expect(quota_hash[:name]).to eq('space-quota') + end + end + end + + describe '#add_domains' do + it 'adds domain limits to the quota hash' do + builder = QuotaPresenterBuilder.new(VCAP::CloudController::QuotaDefinition.make(name: 'domain-name', total_private_domains: 20)) + builder.add_domains + quota_hash = builder.build + expect(quota_hash[:domains]).to eq({ total_domains: 20 }) + end + end + + describe '#add_relationships' do + it 'adds relationships to the quota hash' do + relationships = { organizations: { data: [{ guid: 'org-guid-1' }, { guid: 'org-guid-2' }] } } + quota_hash = QuotaPresenterBuilder.new(quota).add_relationships(relationships).build + expect(quota_hash[:relationships]).to eq(relationships) + end + end + + describe '#add_links' do + it 'adds links to the quota hash' do + links = { self: { href: 'http://example.com/quota' }, 'some-other-link': { href: 'http://example.com/other' } } + quota_hash = QuotaPresenterBuilder.new(quota).add_links(links).build + expect(quota_hash[:links]).to eq(links) + end + end + end +end diff --git a/spec/unit/presenters/v3/effective_space_quota_presenter_spec.rb b/spec/unit/presenters/v3/effective_space_quota_presenter_spec.rb new file mode 100644 index 00000000000..c240e2d4bdb --- /dev/null +++ b/spec/unit/presenters/v3/effective_space_quota_presenter_spec.rb @@ -0,0 +1,48 @@ +require 'spec_helper' +require 'presenters/v3/effective_space_quota_presenter' + +module VCAP::CloudController::Presenters::V3 + RSpec.describe EffectiveSpaceQuotaPresenter do + let(:effective_space_quota) do + Struct.new( + :memory_limit, + :instance_memory_limit, + :app_instance_limit, + :app_task_limit, + :log_rate_limit, + :non_basic_services_allowed, + :total_services, + :total_service_keys, + :total_routes, + :total_reserved_route_ports + ).new(2048, 1024, 20, 10, 1500, true, 100, 5, 200, 15) + end + let(:space) { VCAP::CloudController::Space.make(guid: 'space-guid') } + + describe '#to_hash' do + let(:result) { EffectiveSpaceQuotaPresenter.new(effective_space_quota, space).to_hash } + + it 'presents the effective space quota as json' do + expect(result[:apps][:total_memory_in_mb]).to eq(effective_space_quota.memory_limit) + expect(result[:apps][:per_process_memory_in_mb]).to eq(effective_space_quota.instance_memory_limit) + expect(result[:apps][:total_instances]).to eq(effective_space_quota.app_instance_limit) + expect(result[:apps][:per_app_tasks]).to eq(effective_space_quota.app_task_limit) + expect(result[:apps][:log_rate_limit_in_bytes_per_second]).to eq(effective_space_quota.log_rate_limit) + expect(result[:services][:paid_services_allowed]).to eq(effective_space_quota.non_basic_services_allowed) + expect(result[:services][:total_service_instances]).to eq(effective_space_quota.total_services) + expect(result[:services][:total_service_keys]).to eq(effective_space_quota.total_service_keys) + expect(result[:routes][:total_routes]).to eq(effective_space_quota.total_routes) + expect(result[:routes][:total_reserved_ports]).to eq(effective_space_quota.total_reserved_route_ports) + expect(result[:links][:self][:href]).to match(%r{/v3/spaces/#{space.guid}/effective_quota$}) + expect(result[:links][:usage_summary][:href]).to match(%r{/v3/spaces/#{space.guid}/usage_summary$}) + expect(result[:links][:space][:href]).to match(%r{/v3/spaces/#{space.guid}$}) + end + + it 'calls the QuotaPresenterBuilder' do + allow(VCAP::CloudController::Presenters::QuotaPresenterBuilder).to receive(:new).and_call_original + result + expect(VCAP::CloudController::Presenters::QuotaPresenterBuilder).to have_received(:new).with(effective_space_quota) + end + end + end +end diff --git a/spec/unit/presenters/v3/organization_quota_presenter_spec.rb b/spec/unit/presenters/v3/organization_quota_presenter_spec.rb index 080fd4c5a83..fa0fc5efb7d 100644 --- a/spec/unit/presenters/v3/organization_quota_presenter_spec.rb +++ b/spec/unit/presenters/v3/organization_quota_presenter_spec.rb @@ -42,6 +42,12 @@ module VCAP::CloudController::Presenters::V3 expect(result[:links][:self][:href]).to match(%r{/v3/organization_quotas/#{organization_quota.guid}$}) end + it 'calls the QuotaPresenterBuilder' do + allow(VCAP::CloudController::Presenters::QuotaPresenterBuilder).to receive(:new).and_call_original + result + expect(VCAP::CloudController::Presenters::QuotaPresenterBuilder).to have_received(:new).with(organization_quota) + end + context 'when user is admin and there are no visible orgs' do let(:all_orgs_visible) { true } let(:visible_org_guids) { [] } diff --git a/spec/unit/presenters/v3/space_quota_presenter_spec.rb b/spec/unit/presenters/v3/space_quota_presenter_spec.rb index 93e07b7a858..85ae9d0accd 100644 --- a/spec/unit/presenters/v3/space_quota_presenter_spec.rb +++ b/spec/unit/presenters/v3/space_quota_presenter_spec.rb @@ -57,34 +57,10 @@ module VCAP::CloudController::Presenters::V3 expect(result[:links][:organization][:href]).to match(%r{/v3/organizations/#{org.guid}$}) end - context 'when using null values' do - let(:space_quota) do - VCAP::CloudController::SpaceQuotaDefinition.make( - guid: 'quota-guid', - organization: org, - memory_limit: -1, - instance_memory_limit: -1, - app_instance_limit: -1, - app_task_limit: -1, - log_rate_limit: -1, - total_services: -1, - total_service_keys: -1, - total_routes: -1, - total_reserved_route_ports: -1 - ) - end - - it "properly converts -1 sentinel values to JSON's null" do - expect(result[:apps][:total_memory_in_mb]).to be_nil - expect(result[:apps][:per_process_memory_in_mb]).to be_nil - expect(result[:apps][:total_instances]).to be_nil - expect(result[:apps][:per_app_tasks]).to be_nil - expect(result[:apps][:log_rate_limit_in_bytes_per_second]).to be_nil - expect(result[:services][:total_service_instances]).to be_nil - expect(result[:services][:total_service_keys]).to be_nil - expect(result[:routes][:total_routes]).to be_nil - expect(result[:routes][:total_reserved_ports]).to be_nil - end + it 'calls the QuotaPresenterBuilder' do + allow(VCAP::CloudController::Presenters::QuotaPresenterBuilder).to receive(:new).and_call_original + result + expect(VCAP::CloudController::Presenters::QuotaPresenterBuilder).to have_received(:new).with(space_quota) end context 'when user is admin' do