From 3b6ccfc4c8629148075efe6ffd749341fab2222a Mon Sep 17 00:00:00 2001 From: Brian Butz Date: Wed, 29 Jul 2020 17:40:41 +0100 Subject: [PATCH] v3(services): Return list of service credential bindings (#1761) * v3(services): Return list of service credential bindings [#173171550](https://www.pivotaltracker.com/story/show/173171550) --- .rspec | 1 + .../service_credential_bindings_controller.rb | 56 +++++++++----- .../service_credential_binding_fetcher.rb | 15 ++-- ...service_credential_binding_list_fetcher.rb | 14 ++++ .../service_credential_binding_view.rb | 38 ++++------ app/presenters/helpers/censorship.rb | 16 ++-- app/presenters/v3/base_presenter.rb | 40 +++++----- .../service_credential_binding_presenter.rb | 18 +++++ config/routes.rb | 4 +- .../_service_credential_bindings.erb | 42 +++++++++++ .../service_credential_bindings/_get.md.erb | 50 +++++++++++++ .../service_credential_bindings/_header.md | 3 + .../service_credential_bindings/_list.md.erb | 39 ++++++++++ docs/v3/source/index.md | 4 + .../service_credential_bindings_spec.rb | 75 ++++++++++++++++++- ...service_credential_binding_fetcher_spec.rb | 67 +++++++---------- ...ce_credential_binding_list_fetcher_spec.rb | 46 ++++++++++++ ...rvice_credential_binding_presenter_spec.rb | 17 +++++ 18 files changed, 429 insertions(+), 116 deletions(-) create mode 100644 app/fetchers/service_credential_binding_list_fetcher.rb create mode 100644 app/presenters/v3/service_credential_binding_presenter.rb create mode 100644 docs/v3/source/includes/api_resources/_service_credential_bindings.erb create mode 100644 docs/v3/source/includes/experimental_resources/service_credential_bindings/_get.md.erb create mode 100644 docs/v3/source/includes/experimental_resources/service_credential_bindings/_header.md create mode 100644 docs/v3/source/includes/experimental_resources/service_credential_bindings/_list.md.erb create mode 100644 spec/unit/fetchers/service_credential_binding_list_fetcher_spec.rb create mode 100644 spec/unit/presenters/v3/service_credential_binding_presenter_spec.rb diff --git a/.rspec b/.rspec index fdd4d9d89ce..246083596e9 100644 --- a/.rspec +++ b/.rspec @@ -1,2 +1,3 @@ --color --order rand +-I app \ No newline at end of file diff --git a/app/controllers/v3/service_credential_bindings_controller.rb b/app/controllers/v3/service_credential_bindings_controller.rb index 4472342009c..d927a1ad530 100644 --- a/app/controllers/v3/service_credential_bindings_controller.rb +++ b/app/controllers/v3/service_credential_bindings_controller.rb @@ -1,49 +1,65 @@ require 'fetchers/service_credential_binding_fetcher' +require 'fetchers/service_credential_binding_list_fetcher' +require 'presenters/v3/service_credential_binding_presenter' class ServiceCredentialBindingsController < ApplicationController - before_action :ensure_service_credential_binding_exists! - before_action :ensure_user_has_access! + def index + results = list_fetcher.fetch(space_guids: space_guids) + + presenter = Presenters::V3::PaginatedListPresenter.new( + presenter: Presenters::V3::ServiceCredentialBindingPresenter, + paginated_result: SequelPaginator.new.get_page(results, pagination_options), + path: '/v3' + service_credential_bindings_path + ) + + render status: :ok, json: presenter + end def show + ensure_service_credential_binding_is_accessible! render status: :ok, json: serialized end private - def serialized - { - guid: service_credential_binding.guid, - type: service_credential_binding.type - } + def service_credential_binding + @service_credential_binding ||= fetcher.fetch(hashed_params[:guid], space_guids: space_guids) end - def ensure_service_credential_binding_exists! - not_found! unless service_credential_binding_exists? + def space_guids + if permission_queryer.can_read_globally? + :all + else + permission_queryer.readable_space_guids + end end - def ensure_user_has_access! - not_found! unless allowed_to_access_space? + def pagination_options + query_params_with_order_by = query_params.reverse_merge(order_by: :created_at) + ListMessage.from_params(query_params_with_order_by, []).pagination_options end - def not_found! - resource_not_found!(:service_credential_binding) + def serialized + Presenters::V3::ServiceCredentialBindingPresenter.new(service_credential_binding).to_hash end - def service_credential_binding - @service_credential_binding ||= fetcher.fetch(hashed_params[:guid]) + def ensure_service_credential_binding_is_accessible! + not_found! unless service_credential_binding_exists? end - def fetcher - @fetcher ||= VCAP::CloudController::ServiceCredentialBindingFetcher.new + def not_found! + resource_not_found!(:service_credential_binding) end def service_credential_binding_exists? !!service_credential_binding end - def allowed_to_access_space? - space = service_credential_binding.space + def list_fetcher + @list_fetcher ||= VCAP::CloudController::ServiceCredentialBindingListFetcher.new + end - permission_queryer.can_read_from_space?(space.guid, space.organization_guid) + def fetcher + @fetcher ||= VCAP::CloudController::ServiceCredentialBindingFetcher.new end end diff --git a/app/fetchers/service_credential_binding_fetcher.rb b/app/fetchers/service_credential_binding_fetcher.rb index bebfa94e98f..c874f45fb1c 100644 --- a/app/fetchers/service_credential_binding_fetcher.rb +++ b/app/fetchers/service_credential_binding_fetcher.rb @@ -1,17 +1,22 @@ module VCAP module CloudController class ServiceCredentialBindingFetcher - ServiceInstanceCredential = Struct.new(:guid, :type, :space).freeze + ServiceInstanceCredential = Struct.new(:guid, :type).freeze - def fetch(guid) - ServiceCredentialBinding::View.first(guid: guid).try do |db_binding| + def fetch(guid, space_guids:) + list_fetcher.fetch(space_guids: space_guids).first(guid: guid).try do |db_binding| ServiceInstanceCredential.new( db_binding.guid, - db_binding.type, - db_binding.space + db_binding.type ) end end + + private + + def list_fetcher + ServiceCredentialBindingListFetcher.new + end end end end diff --git a/app/fetchers/service_credential_binding_list_fetcher.rb b/app/fetchers/service_credential_binding_list_fetcher.rb new file mode 100644 index 00000000000..4eae3d3daa8 --- /dev/null +++ b/app/fetchers/service_credential_binding_list_fetcher.rb @@ -0,0 +1,14 @@ +module VCAP + module CloudController + class ServiceCredentialBindingListFetcher + def fetch(space_guids:) + case space_guids + when :all + ServiceCredentialBinding::View.dataset + else + ServiceCredentialBinding::View.where { Sequel[:space_guid] =~ space_guids } + end + end + end + end +end diff --git a/app/models/services/service_credential_binding_view.rb b/app/models/services/service_credential_binding_view.rb index f73d54c571f..08b7da114c5 100644 --- a/app/models/services/service_credential_binding_view.rb +++ b/app/models/services/service_credential_binding_view.rb @@ -6,18 +6,26 @@ module Types SERVICE_BINDING = 'app'.freeze end - SERVICE_KEY_VIEW = VCAP::CloudController::ServiceKey.select( - :guid, + SERVICE_KEY_VIEW = Sequel::Model(:service_keys).select( + Sequel.as(:service_keys__guid, :guid), Sequel.as(Types::SERVICE_KEY, :type), - :service_instance_id, - Sequel.as(nil, :app_guid) + Sequel.as(:spaces__guid, :space_guid), + Sequel.as(:service_keys__created_at, :created_at) + ).join( + :service_instances, id: Sequel[:service_keys][:service_instance_id] + ).join( + :spaces, id: Sequel[:service_instances][:space_id] ).freeze - SERVICE_BINDING_VIEW = VCAP::CloudController::ServiceBinding.select( - :guid, + SERVICE_BINDING_VIEW = Sequel::Model(:service_bindings).select( + Sequel.as(:service_bindings__guid, :guid), Sequel.as(Types::SERVICE_BINDING, :type), - Sequel.as(nil, :service_instance_id), - :app_guid + Sequel.as(:spaces__guid, :space_guid), + Sequel.as(:service_bindings__created_at, :created_at) + ).join( + :apps, guid: Sequel[:service_bindings][:app_guid] + ).join( + :spaces, guid: Sequel[:apps][:space_guid] ).freeze VIEW = [ @@ -28,20 +36,6 @@ module Types end.from_self.freeze class View < Sequel::Model(VIEW) - many_to_one :service_instance, class: 'VCAP::CloudController::ServiceInstance' - many_to_one :app, class: 'VCAP::CloudController::AppModel', key: :app_guid, primary_key: :guid, without_guid_generation: true - - def space - relation = - case type - when Types::SERVICE_BINDING - app - else - service_instance - end - - relation.space - end end end end diff --git a/app/presenters/helpers/censorship.rb b/app/presenters/helpers/censorship.rb index f64606ed74c..43b919fe836 100644 --- a/app/presenters/helpers/censorship.rb +++ b/app/presenters/helpers/censorship.rb @@ -1,10 +1,12 @@ -module VCAP::CloudController - module Presenters - module Censorship - PRIVATE_DATA_HIDDEN = '[PRIVATE DATA HIDDEN]'.freeze - PRIVATE_DATA_HIDDEN_LIST = '[PRIVATE DATA HIDDEN IN LISTS]'.freeze - REDACTED = '[REDACTED]'.freeze - REDACTED_CREDENTIAL = '***'.freeze +module VCAP + module CloudController + module Presenters + module Censorship + PRIVATE_DATA_HIDDEN = '[PRIVATE DATA HIDDEN]'.freeze + PRIVATE_DATA_HIDDEN_LIST = '[PRIVATE DATA HIDDEN IN LISTS]'.freeze + REDACTED = '[REDACTED]'.freeze + REDACTED_CREDENTIAL = '***'.freeze + end end end end diff --git a/app/presenters/v3/base_presenter.rb b/app/presenters/v3/base_presenter.rb index 90dce577444..15c9a567f24 100644 --- a/app/presenters/v3/base_presenter.rb +++ b/app/presenters/v3/base_presenter.rb @@ -1,28 +1,30 @@ require 'presenters/helpers/censorship' -module VCAP::CloudController - module Presenters - module V3 - class BasePresenter - def initialize(resource, show_secrets: true, censored_message: Censorship::PRIVATE_DATA_HIDDEN, decorators: []) - @resource = resource - @show_secrets = show_secrets - @censored_message = censored_message - @decorators = decorators - end +module VCAP + module CloudController + module Presenters + module V3 + class BasePresenter + def initialize(resource, show_secrets: true, censored_message: Censorship::PRIVATE_DATA_HIDDEN, decorators: []) + @resource = resource + @show_secrets = show_secrets + @censored_message = censored_message + @decorators = decorators + end - private + private - def redact(unredacted_value) - @show_secrets ? unredacted_value : @censored_message - end + def redact(unredacted_value) + @show_secrets ? unredacted_value : @censored_message + end - def redact_hash(unredacted_value) - @show_secrets ? unredacted_value : { 'redacted_message' => @censored_message } - end + def redact_hash(unredacted_value) + @show_secrets ? unredacted_value : { 'redacted_message' => @censored_message } + end - def url_builder - @url_builder ||= VCAP::CloudController::Presenters::ApiUrlBuilder + def url_builder + @url_builder ||= VCAP::CloudController::Presenters::ApiUrlBuilder + end end end end diff --git a/app/presenters/v3/service_credential_binding_presenter.rb b/app/presenters/v3/service_credential_binding_presenter.rb new file mode 100644 index 00000000000..2f4331117c4 --- /dev/null +++ b/app/presenters/v3/service_credential_binding_presenter.rb @@ -0,0 +1,18 @@ +require_relative 'base_presenter' + +module VCAP + module CloudController + module Presenters + module V3 + class ServiceCredentialBindingPresenter < BasePresenter + def to_hash + { + guid: @resource.guid, + type: @resource.type + } + end + end + end + end + end +end diff --git a/config/routes.rb b/config/routes.rb index 02f9d2d8d0f..a17a0a5c9a9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -185,7 +185,9 @@ delete '/service_bindings/:guid', to: 'service_bindings#destroy' # service_credential_bindings - get '/service_credential_bindings/:guid', to: 'service_credential_bindings#show' + resources :service_credential_bindings, + param: :guid, + only: [:show, :index] # service_brokers get '/service_brokers', to: 'service_brokers#index' diff --git a/docs/v3/source/includes/api_resources/_service_credential_bindings.erb b/docs/v3/source/includes/api_resources/_service_credential_bindings.erb new file mode 100644 index 00000000000..b8ae8fa1936 --- /dev/null +++ b/docs/v3/source/includes/api_resources/_service_credential_bindings.erb @@ -0,0 +1,42 @@ +<% content_for :single_service_credential_binding_app do %> +{ + "guid": "ddd7fb26-c42d-4acf-a035-60fdd094a167", + "type": "app" +} +<% end %> + +<% content_for :single_service_credential_binding_key do %> +{ + "guid": "ddd7fb26-c42d-4acf-a035-60fdd094a167", + "type": "key" +} +<% end %> + +<% content_for :paginated_list_of_service_credential_bindings do |base_url| %> + { + "pagination": { + "total_results": 3, + "total_pages": 2, + "first": { + "href": "https://api.example.org<%= base_url %>?page=1&per_page=2" + }, + "last": { + "href": "https://api.example.org<%= base_url %>?page=2&per_page=2" + }, + "next": { + "href": "https://api.example.org<%= base_url %>?page=2&per_page=2" + }, + "previous": null + }, + "resources": [ + { + "guid": "dde5ad2a-d8f4-44dc-a56f-0452d744f1c3", + "type": "app" + }, + { + "guid": "7aa37bad-6ccb-4ef9-ba48-9ce3a91b2b62", + "type": "key" + } + ] +} +<% end %> diff --git a/docs/v3/source/includes/experimental_resources/service_credential_bindings/_get.md.erb b/docs/v3/source/includes/experimental_resources/service_credential_bindings/_get.md.erb new file mode 100644 index 00000000000..54522660c4a --- /dev/null +++ b/docs/v3/source/includes/experimental_resources/service_credential_bindings/_get.md.erb @@ -0,0 +1,50 @@ +### Get a service credential binding + +``` +Example Request +``` + +```shell +curl "https://api.example.org/v3/service_credential_bindings/[guid]" \ + -X GET \ + -H "Authorization: bearer [token]" +``` + +``` +Example App Credential Binding Response +``` + +```http +HTTP/1.1 200 OK +Content-Type: application/json + +<%= yield_content :single_service_credential_binding_app %> +``` + +``` +Example Key Credential Binding Response +``` + +```http +HTTP/1.1 200 OK +Content-Type: application/json + +<%= yield_content :single_service_credential_binding_key %> +``` + + +This endpoint retrieves the service credential binding by GUID. + +#### Definition +`GET /v3/service_service_credential_bindings/:guid` + +#### Permitted roles + | +--- | --- +Admin | +Admin Read-Only | +Global Auditor | +Org Manager | +Space Auditor | +Space Developer | +Space Manager | diff --git a/docs/v3/source/includes/experimental_resources/service_credential_bindings/_header.md b/docs/v3/source/includes/experimental_resources/service_credential_bindings/_header.md new file mode 100644 index 00000000000..f34c491afa0 --- /dev/null +++ b/docs/v3/source/includes/experimental_resources/service_credential_bindings/_header.md @@ -0,0 +1,3 @@ +## Service Credential Binding (experimental) + +An instantiation of a service credential binding. diff --git a/docs/v3/source/includes/experimental_resources/service_credential_bindings/_list.md.erb b/docs/v3/source/includes/experimental_resources/service_credential_bindings/_list.md.erb new file mode 100644 index 00000000000..da42ed64418 --- /dev/null +++ b/docs/v3/source/includes/experimental_resources/service_credential_bindings/_list.md.erb @@ -0,0 +1,39 @@ +<%- @service_credential_binding_list_path = '/v3/service_credential_bindings' %> +### List service credential bindings + +``` +Example Request +``` + +```shell +curl "https://api.example.org<%= @service_credential_binding_list_path %> \ + -X GET \ + -H "Authorization: bearer [token]" +``` + +``` +Example Response +``` + +```http +HTTP/1.1 200 OK +Content-Type: application/json + +<%= yield_content :paginated_list_of_service_credential_bindings, @service_credential_binding_list_path %> +``` + +This endpoint retrieves the service credential bindings the user has access to. + +#### Definition +`GET <%= @service_credential_binding_list_path %>` + +#### Permitted roles + | +--- | --- +Admin | +Admin Read-Only | +Global Auditor | +Org Manager | +Space Auditor | +Space Developer | +Space Manager | diff --git a/docs/v3/source/index.md b/docs/v3/source/index.md index 82f897c56e6..2fae399f4f8 100644 --- a/docs/v3/source/index.md +++ b/docs/v3/source/index.md @@ -31,6 +31,7 @@ includes: - api_resources/service_offerings - api_resources/service_plans - api_resources/service_plan_visibility + - api_resources/service_credential_bindings - api_resources/service_instances - api_resources/service_usage_events - api_resources/sidecars @@ -354,6 +355,9 @@ includes: - experimental_resources/service_bindings/get - experimental_resources/service_bindings/list - experimental_resources/service_bindings/delete + - experimental_resources/service_credential_bindings/header + - experimental_resources/service_credential_bindings/get + - experimental_resources/service_credential_bindings/list - experimental_resources/service_instances/header - experimental_resources/service_instances/create - experimental_resources/service_instances/get diff --git a/spec/request/service_credential_bindings_spec.rb b/spec/request/service_credential_bindings_spec.rb index 298a0b9d757..d9a0d13027e 100644 --- a/spec/request/service_credential_bindings_spec.rb +++ b/spec/request/service_credential_bindings_spec.rb @@ -7,7 +7,59 @@ let(:space) { VCAP::CloudController::Space.make(organization: org) } let(:other_space) { VCAP::CloudController::Space.make } - context 'GET /v3/service_credential_bindings/:missing_key' do + describe 'GET /v3/service_credential_bindings' do + let(:instance) { VCAP::CloudController::ManagedServiceInstance.make(space: space) } + let(:other_instance) { VCAP::CloudController::ManagedServiceInstance.make(space: other_space) } + let!(:key_binding) { VCAP::CloudController::ServiceKey.make(service_instance: instance) } + let!(:other_key_binding) { VCAP::CloudController::ServiceKey.make(service_instance: other_instance) } + let!(:app_binding) { VCAP::CloudController::ServiceBinding.make(service_instance: instance) } + let!(:other_app_binding) { VCAP::CloudController::ServiceBinding.make(service_instance: other_instance) } + + describe 'permissions' do + let(:api_call) { ->(user_headers) { get '/v3/service_credential_bindings', nil, user_headers } } + + let(:all_bindings) do + { + code: 200, + response_objects: [ + expected_json(key_binding), + expected_json(other_key_binding), + expected_json(app_binding), + expected_json(other_app_binding), + ] + } + end + + let(:space_bindings) do + { + code: 200, + response_objects: [ + expected_json(key_binding), + expected_json(app_binding) + ] + } + end + + let(:expected_codes_and_responses) do + Hash.new( + code: 200, + response_objects: [] + ).tap do |h| + h['admin'] = all_bindings + h['admin_read_only'] = all_bindings + h['global_auditor'] = all_bindings + h['space_developer'] = space_bindings + h['space_manager'] = space_bindings + h['space_auditor'] = space_bindings + h['org_manager'] = space_bindings + end + end + + it_behaves_like 'permissions for list endpoint', ALL_PERMISSIONS + end + end + + describe 'GET /v3/service_credential_bindings/:missing_key' do let(:api_call) { ->(user_headers) { get '/v3/service_credential_bindings/no-binding', nil, user_headers } } let(:expected_codes_and_responses) do @@ -113,4 +165,25 @@ end end end + + def expected_json(binding) + { + guid: binding.guid + }.merge(extra(binding)) + end + + def extra(binding) + case binding + when VCAP::CloudController::ServiceKey + { + type: 'key' + } + when VCAP::CloudController::ServiceBinding + { + type: 'app' + } + else + raise 'not a binding' + end + end end diff --git a/spec/unit/fetchers/service_credential_binding_fetcher_spec.rb b/spec/unit/fetchers/service_credential_binding_fetcher_spec.rb index b179cbeadf8..e1f68a1fdc4 100644 --- a/spec/unit/fetchers/service_credential_binding_fetcher_spec.rb +++ b/spec/unit/fetchers/service_credential_binding_fetcher_spec.rb @@ -10,7 +10,7 @@ module CloudController let!(:existing_credential_binding) { ServiceBinding.make } it 'should return nothing' do - credential_binding = fetcher.fetch('does-not-exist') + credential_binding = fetcher.fetch('does-not-exist', space_guids: :all) expect(credential_binding).to be_nil end end @@ -21,17 +21,22 @@ module CloudController let(:service_instance) { ManagedServiceInstance.make(space: space) } let!(:service_key) { ServiceKey.make(service_instance: service_instance) } - it 'can be found' do - credential_binding = fetcher.fetch(service_key.guid) + describe 'when in the space' do + it 'can be found' do + credential_binding = fetcher.fetch(service_key.guid, space_guids: [space.guid]) - expect(credential_binding).not_to be_nil - expect(credential_binding.type).to eql(type) + expect(credential_binding).not_to be_nil + expect(credential_binding.type).to eql(type) + end end - it 'can access the space' do - credential_binding = fetcher.fetch(service_key.guid) + describe 'when not in the space' do + let!(:other_space) { Space.make } + it 'can not be found' do + credential_binding = fetcher.fetch(service_key.guid, space_guids: [other_space.guid]) - expect(credential_binding.space).to eql(space) + expect(credential_binding).to be_nil + end end end @@ -44,16 +49,19 @@ module CloudController let!(:app_binding) { ServiceBinding.make(service_instance: service_instance) } it 'can be found' do - credential_binding = fetcher.fetch(app_binding.guid) + credential_binding = fetcher.fetch(app_binding.guid, space_guids: [space.guid]) expect(credential_binding).not_to be_nil expect(credential_binding.type).to eql(type) end - it 'can access the space' do - credential_binding = fetcher.fetch(app_binding.guid) + describe 'when not in the space' do + let!(:other_space) { Space.make } + it 'can not be found' do + credential_binding = fetcher.fetch(app_binding.guid, space_guids: [other_space.guid]) - expect(credential_binding.space).to eql(space) + expect(credential_binding).to be_nil + end end end @@ -63,43 +71,20 @@ module CloudController let!(:app_binding) { ServiceBinding.make(service_instance: service_instance) } it 'can be found' do - credential_binding = fetcher.fetch(app_binding.guid) + credential_binding = fetcher.fetch(app_binding.guid, space_guids: [space.guid]) expect(credential_binding).not_to be_nil expect(credential_binding.type).to eql(type) end - it 'can access the space' do - credential_binding = fetcher.fetch(app_binding.guid) + describe 'when not in the space' do + let!(:other_space) { Space.make } + it 'can not be found' do + credential_binding = fetcher.fetch(app_binding.guid, space_guids: [other_space.guid]) - expect(credential_binding.space).to eql(space) - end - end - - describe 'shared services' do - let(:space) { Space.make } - let(:other_space) { Space.make } - let(:service_instance) do - ManagedServiceInstance.make(space: other_space).tap do |si| - si.shared_spaces << space + expect(credential_binding).to be_nil end end - - let(:app) { AppModel.make(space: space) } - let!(:app_binding) { ServiceBinding.make(service_instance: service_instance, app: app) } - - it 'can be found' do - credential_binding = fetcher.fetch(app_binding.guid) - - expect(credential_binding).not_to be_nil - expect(credential_binding.type).to eql(type) - end - - it "can access the app's space" do - credential_binding = fetcher.fetch(app_binding.guid) - - expect(credential_binding.space).to eql(space) - end end end end diff --git a/spec/unit/fetchers/service_credential_binding_list_fetcher_spec.rb b/spec/unit/fetchers/service_credential_binding_list_fetcher_spec.rb new file mode 100644 index 00000000000..7747e95e873 --- /dev/null +++ b/spec/unit/fetchers/service_credential_binding_list_fetcher_spec.rb @@ -0,0 +1,46 @@ +require 'spec_helper' +require 'fetchers/service_credential_binding_list_fetcher' + +module VCAP + module CloudController + RSpec.describe ServiceCredentialBindingListFetcher do + let(:fetcher) { ServiceCredentialBindingListFetcher.new } + + describe 'no bindings' do + it 'returns an empty result' do + expect(fetcher.fetch(space_guids: :all).all).to eql([]) + end + end + + describe 'app and key bindings' do + let(:space) { VCAP::CloudController::Space.make } + let(:instance) { VCAP::CloudController::ManagedServiceInstance.make(space: space) } + let!(:key_binding) { VCAP::CloudController::ServiceKey.make(service_instance: instance) } + let!(:app_binding) { VCAP::CloudController::ServiceBinding.make(service_instance: instance) } + + context 'when getting everything' do + it 'returns both key and app bindings' do + bindings = fetcher.fetch(space_guids: :all).all + binding_guids = bindings.map(&:guid) + + expect(binding_guids).to contain_exactly(key_binding.guid, app_binding.guid) + end + end + + context 'when limiting to a space' do + let(:other_space) { VCAP::CloudController::Space.make } + let(:other_instance) { VCAP::CloudController::ManagedServiceInstance.make(space: other_space) } + let!(:key_other_binding) { VCAP::CloudController::ServiceKey.make(service_instance: other_instance) } + let!(:app_other_binding) { VCAP::CloudController::ServiceBinding.make(service_instance: other_instance) } + + it 'returns only the bindings within that space' do + bindings = fetcher.fetch(space_guids: [space.guid]).all + binding_guids = bindings.map(&:guid) + + expect(binding_guids).to contain_exactly(key_binding.guid, app_binding.guid) + end + end + end + end + end +end diff --git a/spec/unit/presenters/v3/service_credential_binding_presenter_spec.rb b/spec/unit/presenters/v3/service_credential_binding_presenter_spec.rb new file mode 100644 index 00000000000..ea44eed41b8 --- /dev/null +++ b/spec/unit/presenters/v3/service_credential_binding_presenter_spec.rb @@ -0,0 +1,17 @@ +require 'presenters/v3/service_credential_binding_presenter' + +module VCAP + module CloudController + RSpec.describe Presenters::V3::ServiceCredentialBindingPresenter do + CredentialBinding = Struct.new(:guid, :type) + + it 'should include the id and the guid' do + credential_binding = CredentialBinding.new('some-guid', 'some-type') + + presenter = described_class.new(credential_binding) + + expect(presenter.to_hash).to eql({ guid: 'some-guid', type: 'some-type' }) + end + end + end +end