diff --git a/app/controllers/v3/service_instances_controller.rb b/app/controllers/v3/service_instances_controller.rb index a3dd03dc0e9..5a44bd809e8 100644 --- a/app/controllers/v3/service_instances_controller.rb +++ b/app/controllers/v3/service_instances_controller.rb @@ -6,7 +6,7 @@ require 'presenters/v3/paginated_list_presenter' require 'actions/service_instance_share' require 'actions/service_instance_unshare' -require 'fetchers/service_instance_list_fetcher' +require 'fetchers/managed_service_instance_list_fetcher' class ServiceInstancesV3Controller < ApplicationController def index @@ -14,9 +14,9 @@ def index invalid_param!(message.errors.full_messages) unless message.valid? dataset = if can_read_globally? - ServiceInstanceListFetcher.new.fetch_all(message: message) + ManagedServiceInstanceListFetcher.new.fetch_all(message: message) else - ServiceInstanceListFetcher.new.fetch(message: message, space_guids: readable_space_guids) + ManagedServiceInstanceListFetcher.new.fetch(message: message, readable_space_guids: readable_space_guids) end render status: :ok, json: Presenters::V3::PaginatedListPresenter.new( diff --git a/app/fetchers/managed_service_instance_list_fetcher.rb b/app/fetchers/managed_service_instance_list_fetcher.rb new file mode 100644 index 00000000000..adab35171fd --- /dev/null +++ b/app/fetchers/managed_service_instance_list_fetcher.rb @@ -0,0 +1,35 @@ +module VCAP::CloudController + class ManagedServiceInstanceListFetcher + def fetch(message:, readable_space_guids:) + source_space_instance_dataset = ManagedServiceInstance.select_all(ServiceInstance.table_name). + join(Space.table_name, id: :space_id, guid: readable_space_guids) + + shared_instance_dataset = ManagedServiceInstance.select_all(ServiceInstance.table_name). + join(:service_instance_shares, service_instance_guid: :guid, target_space_guid: readable_space_guids) + + dataset = source_space_instance_dataset.union(shared_instance_dataset, alias: :service_instances) + + filter(dataset, message) + end + + def fetch_all(message:) + dataset = ManagedServiceInstance.dataset + filter(dataset, message) + end + + private + + def filter(dataset, message) + if message.requested?(:names) + dataset = dataset.where(service_instances__name: message.names) + end + + if message.requested?(:space_guids) + dataset = dataset.select_all(ServiceInstance.table_name). + join_table(:inner, Space.table_name, { id: Sequel.qualify(:service_instances, :space_id), guid: message.space_guids }) + end + + dataset + end + end +end diff --git a/app/fetchers/service_instance_list_fetcher.rb b/app/fetchers/service_instance_list_fetcher.rb deleted file mode 100644 index 01212a3f3b1..00000000000 --- a/app/fetchers/service_instance_list_fetcher.rb +++ /dev/null @@ -1,30 +0,0 @@ -module VCAP::CloudController - class ServiceInstanceListFetcher - def fetch(message:, space_guids:) - source_space_instance_dataset = ServiceInstance.select_all(ServiceInstance.table_name). - join(Space.table_name, id: :space_id, guid: space_guids) - - shared_instance_dataset = ServiceInstance.select_all(ServiceInstance.table_name). - join(:service_instance_shares, service_instance_guid: :guid, target_space_guid: space_guids) - - dataset = source_space_instance_dataset.union(shared_instance_dataset, alias: :service_instances) - - filter(dataset, message) - end - - def fetch_all(message:) - dataset = ServiceInstance.dataset - filter(dataset, message) - end - - private - - def filter(dataset, message) - if message.requested?(:names) - dataset = dataset.where(service_instances__name: message.names) - end - - dataset - end - end -end diff --git a/app/messages/service_instances/service_instances_list_message.rb b/app/messages/service_instances/service_instances_list_message.rb index f368e921fe4..1f1a4478670 100644 --- a/app/messages/service_instances/service_instances_list_message.rb +++ b/app/messages/service_instances/service_instances_list_message.rb @@ -2,12 +2,13 @@ module VCAP::CloudController class ServiceInstancesListMessage < ListMessage - ALLOWED_KEYS = [:page, :per_page, :order_by, :names].freeze + ALLOWED_KEYS = [:page, :per_page, :order_by, :names, :space_guids].freeze attr_accessor(*ALLOWED_KEYS) validates_with NoAdditionalParamsValidator validates :names, array: true, allow_nil: true + validates :space_guids, array: true, allow_nil: true def initialize(params={}) super(params.symbolize_keys) @@ -16,6 +17,7 @@ def initialize(params={}) def self.from_params(params) opts = params.dup to_array! opts, 'names' + to_array! opts, 'space_guids' new(opts.symbolize_keys) end diff --git a/app/presenters/v3/service_instance_presenter.rb b/app/presenters/v3/service_instance_presenter.rb index 537d1969e8a..b218ab488b0 100644 --- a/app/presenters/v3/service_instance_presenter.rb +++ b/app/presenters/v3/service_instance_presenter.rb @@ -9,12 +9,28 @@ def to_hash guid: service_instance.guid, created_at: service_instance.created_at, updated_at: service_instance.updated_at, - name: service_instance.name + name: service_instance.name, + relationships: { + space: { + data: { + guid: service_instance.space.guid + } + } + }, + links: { + space: { + href: url_builder.build_url(path: "/v3/spaces/#{service_instance.space.guid}") + } + } } end private + def url_builder + VCAP::CloudController::Presenters::ApiUrlBuilder.new + end + def service_instance @resource end diff --git a/docs/v3/source/includes/api_resources/_service_instances.erb b/docs/v3/source/includes/api_resources/_service_instances.erb index a9a15f49183..81c52eae9b9 100644 --- a/docs/v3/source/includes/api_resources/_service_instances.erb +++ b/docs/v3/source/includes/api_resources/_service_instances.erb @@ -35,10 +35,22 @@ }, "resources": [ { - "guid": "d4c91047-7b29-4fda-b7f9-04033e5c9c9f", - "created_at": "2017-02-02T00:14:30Z", - "updated_at": "2017-02-02T00:14:30Z", - "name": "my_service_instance" + "guid": "85ccdcad-d725-4109-bca4-fd6ba062b5c8", + "created_at": "2017-11-17T13:54:21Z", + "updated_at": "2017-11-17T13:54:21Z", + "name": "my_service_instance", + "relationships": { + "space": { + "data": { + "guid": "ae0031f9-dd49-461c-a945-df40e77c39cb" + } + } + }, + "links": { + "space": { + "href": "https://api.example.org/v3/spaces/ae0031f9-dd49-461c-a945-df40e77c39cb" + } + } } ] } diff --git a/docs/v3/source/includes/experimental_resources/service_instances/_list.md.erb b/docs/v3/source/includes/experimental_resources/service_instances/_list.md.erb index 90822bb3bb5..47be9f9a5cb 100644 --- a/docs/v3/source/includes/experimental_resources/service_instances/_list.md.erb +++ b/docs/v3/source/includes/experimental_resources/service_instances/_list.md.erb @@ -32,5 +32,6 @@ This includes access granted by service instance sharing. Name | Type | Description ---- | ---- | ------------ **names** | _list of strings_ | Comma-delimited list of service instance names to filter by. +**space_guids** | _list of strings_ | Comma-delimited list of space guids to filter by. **page** | _integer_ | Page to display. Valid values are integers >= 1. **per_page** | _integer_ | Number of results per page.
Valid values are 1 through 5000. diff --git a/docs/v3/source/includes/experimental_resources/service_instances/_object.md.erb b/docs/v3/source/includes/experimental_resources/service_instances/_object.md.erb new file mode 100644 index 00000000000..fdb3ed1c886 --- /dev/null +++ b/docs/v3/source/includes/experimental_resources/service_instances/_object.md.erb @@ -0,0 +1,10 @@ +### The service_instance object + +Name | Type | Description +---- | ---- | ----------- +**name** | _string_ | Name of the service instance. +**guid** | _uuid_ | Unique identifier for the service instance. +**created_at** | _datetime_ | The time with zone when the object was created. +**updated_at** | _datetime_ | The time with zone when the object was last updated. +**space** | [_to-one relationship_](#to-one-relationships) | The space the service instance is contained in. +**links** | [_links object_](#links) | Links to related resources. diff --git a/docs/v3/source/index.md b/docs/v3/source/index.md index 9028e760027..1c48ded85a1 100644 --- a/docs/v3/source/index.md +++ b/docs/v3/source/index.md @@ -137,6 +137,7 @@ includes: - experimental_resources/service_bindings/delete - experimental_resources/service_bindings/list - experimental_resources/service_instances/header + - experimental_resources/service_instances/object - experimental_resources/service_instances/list - experimental_resources/service_instances/share_to_space - experimental_resources/service_instances/unshare_from_space diff --git a/spec/request/service_instances_spec.rb b/spec/request/service_instances_spec.rb index 5d98657fb46..4b34c57a4e7 100644 --- a/spec/request/service_instances_spec.rb +++ b/spec/request/service_instances_spec.rb @@ -7,14 +7,16 @@ let(:user_header) { headers_for(user) } let(:admin_header) { admin_headers_for(user, email: user_email, user_name: user_name) } let(:space) { VCAP::CloudController::Space.make } + let(:another_space) { VCAP::CloudController::Space.make } let(:target_space) { VCAP::CloudController::Space.make } let!(:service_instance1) { VCAP::CloudController::ManagedServiceInstance.make(space: space, name: 'rabbitmq') } let!(:service_instance2) { VCAP::CloudController::ManagedServiceInstance.make(space: space, name: 'redis') } - let!(:service_instance3) { VCAP::CloudController::ManagedServiceInstance.make(space: space, name: 'mysql') } + let!(:service_instance3) { VCAP::CloudController::ManagedServiceInstance.make(space: another_space, name: 'mysql') } describe 'GET /v3/service_instances' do it 'returns a paginated list of service instances the user has access to' do set_current_user_as_role(role: 'space_developer', org: space.organization, space: space, user: user) + set_current_user_as_role(role: 'space_developer', org: another_space.organization, space: another_space, user: user) get '/v3/service_instances?per_page=2&order_by=name', nil, user_header expect(last_response.status).to eq(200) @@ -41,12 +43,36 @@ 'name' => service_instance3.name, 'created_at' => iso8601, 'updated_at' => iso8601, + 'relationships' => { + 'space' => { + 'data' => { + 'guid' => service_instance3.space.guid + } + } + }, + 'links' => { + 'space' => { + 'href' => "#{link_prefix}/v3/spaces/#{service_instance3.space.guid}" + } + } }, { 'guid' => service_instance1.guid, 'name' => service_instance1.name, 'created_at' => iso8601, 'updated_at' => iso8601, + 'relationships' => { + 'space' => { + 'data' => { + 'guid' => service_instance1.space.guid + } + } + }, + 'links' => { + 'space' => { + 'href' => "#{link_prefix}/v3/spaces/#{service_instance1.space.guid}" + } + } } ] } @@ -79,6 +105,80 @@ 'name' => service_instance2.name, 'created_at' => iso8601, 'updated_at' => iso8601, + 'relationships' => { + 'space' => { + 'data' => { + 'guid' => service_instance2.space.guid + } + } + }, + 'links' => { + 'space' => { + 'href' => "#{link_prefix}/v3/spaces/#{service_instance2.space.guid}" + } + } + } + ] + } + ) + end + + it 'returns a paginated list of service instances filtered by space guid' do + set_current_user_as_role(role: 'space_developer', org: space.organization, space: space, user: user) + get "/v3/service_instances?per_page=2&space_guids=#{space.guid}", nil, user_header + expect(last_response.status).to eq(200) + + parsed_response = MultiJson.load(last_response.body) + expect(parsed_response).to be_a_response_like( + { + 'pagination' => { + 'total_results' => 2, + 'total_pages' => 1, + 'first' => { + 'href' => "#{link_prefix}/v3/service_instances?page=1&per_page=2&space_guids=#{space.guid}" + }, + 'last' => { + 'href' => "#{link_prefix}/v3/service_instances?page=1&per_page=2&space_guids=#{space.guid}" + }, + 'next' => nil, + 'previous' => nil + }, + 'resources' => [ + { + 'guid' => service_instance1.guid, + 'name' => service_instance1.name, + 'created_at' => iso8601, + 'updated_at' => iso8601, + 'relationships' => { + 'space' => { + 'data' => { + 'guid' => service_instance1.space.guid + } + } + }, + 'links' => { + 'space' => { + 'href' => "#{link_prefix}/v3/spaces/#{service_instance1.space.guid}" + } + } + }, + { + 'guid' => service_instance2.guid, + 'name' => service_instance2.name, + 'created_at' => iso8601, + 'updated_at' => iso8601, + 'relationships' => { + 'space' => { + 'data' => { + 'guid' => service_instance2.space.guid + } + } + }, + 'links' => { + 'space' => { + 'href' => "#{link_prefix}/v3/spaces/#{service_instance2.space.guid}" + } + } } ] } @@ -116,6 +216,18 @@ 'name' => service_instance1.name, 'created_at' => iso8601, 'updated_at' => iso8601, + 'relationships' => { + 'space' => { + 'data' => { + 'guid' => service_instance1.space.guid + } + } + }, + 'links' => { + 'space' => { + 'href' => "#{link_prefix}/v3/spaces/#{service_instance1.space.guid}" + } + } } ] } diff --git a/spec/unit/controllers/v3/service_instance_controller_spec.rb b/spec/unit/controllers/v3/service_instances_controller_spec.rb similarity index 90% rename from spec/unit/controllers/v3/service_instance_controller_spec.rb rename to spec/unit/controllers/v3/service_instances_controller_spec.rb index cb08319882d..106c79c8b06 100644 --- a/spec/unit/controllers/v3/service_instance_controller_spec.rb +++ b/spec/unit/controllers/v3/service_instances_controller_spec.rb @@ -2,20 +2,21 @@ RSpec.describe ServiceInstancesV3Controller, type: :controller do let(:user) { set_current_user(VCAP::CloudController::User.make) } - let(:space) { VCAP::CloudController::Space.make } - let!(:service_instance) { VCAP::CloudController::ManagedServiceInstance.make(space: space) } + let(:space) { VCAP::CloudController::Space.make(guid: 'space-1-guid') } + let!(:service_instance) { VCAP::CloudController::ManagedServiceInstance.make(space: space, name: 'service-instance-1') } describe '#index' do context 'when there are multiple service instances' do - let!(:service_instance2) { VCAP::CloudController::ManagedServiceInstance.make } - let!(:service_instance3) { VCAP::CloudController::ManagedServiceInstance.make } + let!(:service_instance2) { VCAP::CloudController::ManagedServiceInstance.make(name: 'service-instance-2', space: VCAP::CloudController::Space.make(guid: 'space-2-guid')) } + let!(:service_instance3) { VCAP::CloudController::ManagedServiceInstance.make(name: 'service-instance-3', space: VCAP::CloudController::Space.make(guid: 'space-3-guid')) } + let!(:user_provided_service_instance) { VCAP::CloudController::UserProvidedServiceInstance.make } context 'as an admin' do before do set_current_user_as_admin end - it 'returns all service instances' do + it 'returns all managed service instances' do get :index expect(response.status).to eq(200), response.body expect(parsed_body['resources'].length).to eq 3 @@ -23,6 +24,28 @@ response_names = parsed_body['resources'].map { |resource| resource['name'] } expect(response_names).to include(service_instance.name, service_instance2.name, service_instance3.name) end + + context 'when service instances are filtered by name' do + it 'returns only the matching service instances' do + get :index, names: 'service-instance-1,service-instance-2' + expect(response.status).to eq(200), response.body + expect(parsed_body['resources'].length).to eq 2 + + response_names = parsed_body['resources'].map { |resource| resource['name'] } + expect(response_names).to include(service_instance.name, service_instance2.name) + end + end + + context 'when service instances are filtered by space guid' do + it 'returns only the matching service instances' do + get :index, space_guids: 'space-2-guid, space-3-guid' + expect(response.status).to eq(200), response.body + expect(parsed_body['resources'].length).to eq 2 + + response_names = parsed_body['resources'].map { |resource| resource['name'] } + expect(response_names).to include(service_instance2.name, service_instance3.name) + end + end end context 'as a user who only has limited access' do @@ -30,7 +53,7 @@ set_current_user_as_role(role: 'space_developer', org: space.organization, space: space, user: user) end - it 'returns a subset of service instances' do + it 'returns a subset of managed service instances' do get :index expect(response.status).to eq(200), response.body expect(parsed_body['resources'].length).to eq 1 @@ -185,6 +208,16 @@ end end + context 'when the service instance is user provided' do + let(:service_instance) { VCAP::CloudController::UserProvidedServiceInstance.make } + + it 'returns a 400' do + post :share_service_instance, service_instance_guid: service_instance.guid, body: req_body + expect(response.status).to eq 400 + expect(response.body).to include('User-provided services cannot be shared') + end + end + context 'when the target space does not exist' do before do req_body[:data] = [{ guid: 'nonexistant-space-guid' }] diff --git a/spec/unit/messages/service_instances_list_message_spec.rb b/spec/unit/messages/service_instances_list_message_spec.rb index 1d935b1d602..b5fac8eeccf 100644 --- a/spec/unit/messages/service_instances_list_message_spec.rb +++ b/spec/unit/messages/service_instances_list_message_spec.rb @@ -9,7 +9,8 @@ module VCAP::CloudController 'page' => 1, 'per_page' => 5, 'order_by' => 'name', - 'names' => 'rabbitmq, redis,mysql' + 'names' => 'rabbitmq, redis,mysql', + 'space_guids' => 'space-1, space-2, space-3', } end @@ -21,6 +22,7 @@ module VCAP::CloudController expect(message.per_page).to eq(5) expect(message.order_by).to eq('name') expect(message.names).to match_array(['mysql', 'rabbitmq', 'redis']) + expect(message.space_guids).to match_array(['space-1', 'space-2', 'space-3']) end it 'converts requested keys to symbols' do @@ -30,6 +32,7 @@ module VCAP::CloudController expect(message.requested?(:per_page)).to be_truthy expect(message.requested?(:order_by)).to be_truthy expect(message.requested?(:names)).to be_truthy + expect(message.requested?(:space_guids)).to be_truthy end end @@ -39,7 +42,8 @@ module VCAP::CloudController page: 1, per_page: 5, order_by: 'created_at', - names: ['rabbitmq', 'redis'] + names: ['rabbitmq', 'redis'], + space_guids: ['space-1', 'space-2'], }) expect(message).to be_valid end @@ -56,5 +60,23 @@ module VCAP::CloudController expect(message.errors[:base]).to include("Unknown query parameter(s): 'foobar'") end end + + describe 'validations' do + context 'names' do + it 'validates names is an array' do + message = ServiceInstancesListMessage.new names: 'tricked you, not an array' + expect(message).to be_invalid + expect(message.errors[:names]).to include('must be an array') + end + end + + context 'space guids' do + it 'validates app_guids is an array' do + message = ServiceInstancesListMessage.new space_guids: 'tricked you, not an array' + expect(message).to be_invalid + expect(message.errors[:space_guids]).to include('must be an array') + end + end + end end end diff --git a/spec/unit/presenters/v3/service_instance_presenter_spec.rb b/spec/unit/presenters/v3/service_instance_presenter_spec.rb index 58c595f90a4..292faa22691 100644 --- a/spec/unit/presenters/v3/service_instance_presenter_spec.rb +++ b/spec/unit/presenters/v3/service_instance_presenter_spec.rb @@ -14,6 +14,11 @@ module VCAP::CloudController::Presenters::V3 expect(result[:created_at]).to eq(service_instance.created_at) expect(result[:updated_at]).to eq(service_instance.updated_at) expect(result[:name]).to eq('denise-db') + expect(result[:relationships][:space][:data][:guid]).to equal(service_instance.space.guid) + end + + it 'has a links hash with a space url' do + expect(result[:links][:space][:href]).to eq "#{link_prefix}/v3/spaces/#{service_instance.space.guid}" end end end diff --git a/spec/unit/queries/managed_service_instance_list_fetcher_spec.rb b/spec/unit/queries/managed_service_instance_list_fetcher_spec.rb new file mode 100644 index 00000000000..b08104293f3 --- /dev/null +++ b/spec/unit/queries/managed_service_instance_list_fetcher_spec.rb @@ -0,0 +1,164 @@ +require 'spec_helper' +require 'fetchers/managed_service_instance_list_fetcher' +require 'messages/service_instances/service_instances_list_message' + +module VCAP::CloudController + RSpec.describe ManagedServiceInstanceListFetcher do + let(:filters) { {} } + let(:message) { ServiceInstancesListMessage.new(filters) } + let(:fetcher) { ManagedServiceInstanceListFetcher.new } + + describe '#fetch_all' do + let!(:service_instance_1) { ManagedServiceInstance.make(name: 'rabbitmq', space: Space.make(guid: 'space-1')) } + let!(:service_instance_2) { ManagedServiceInstance.make(name: 'redis', space: Space.make(guid: 'space-2')) } + let!(:service_instance_3) { ManagedServiceInstance.make(name: 'mysql', space: Space.make(guid: 'space-3')) } + let!(:user_provided_service_instance) { UserProvidedServiceInstance.make(name: 'my-thing') } + + it 'returns a Sequel::Dataset' do + results = fetcher.fetch_all(message: message) + expect(results).to be_a(Sequel::Dataset) + end + + it 'includes all the managed service instances' do + results = fetcher.fetch_all(message: message).all + expect(results.length).to eq 3 + expect(results).to include(service_instance_1, service_instance_2, service_instance_3) + end + + context 'filter' do + context 'by service instance name' do + let(:filters) { { names: ['rabbitmq', 'redis'] } } + + it 'only returns matching managed service instances' do + results = fetcher.fetch_all(message: message).all + expect(results).to match_array([service_instance_1, service_instance_2]) + expect(results).not_to include(service_instance_3) + end + end + + context 'by space guid' do + let(:filters) { { space_guids: ['space-2', 'space-3'] } } + + it 'only returns matching service instances' do + results = fetcher.fetch_all(message: message).all + expect(results).to match_array([service_instance_2, service_instance_3]) + expect(results).not_to include(service_instance_1) + end + end + + context 'by all query params' do + let!(:service_instance_4) { ManagedServiceInstance.make(name: 'couchdb', space: service_instance_3.space) } + let(:filters) { + { + space_guids: ['space-3'], + names: ['couchdb'], + } + } + + it 'only returns matching service instances' do + results = fetcher.fetch_all(message: message).all + expect(results).to match_array([service_instance_4]) + end + end + end + end + + describe '#fetch' do + let!(:service_instance_1) { ManagedServiceInstance.make(name: 'rabbitmq', space: space_1) } + let!(:service_instance_2) { ManagedServiceInstance.make(name: 'redis', space: space_1) } + let!(:service_instance_3) { ManagedServiceInstance.make(name: 'mysql', space: space_2) } + let!(:user_provided_service_instance) { UserProvidedServiceInstance.make(name: 'my-thing', space: space_1) } + + let(:space_1) { Space.make(guid: 'space-1') } + let(:space_2) { Space.make(guid: 'space-2') } + + it 'returns all of the managed service instances in the specified space' do + results = fetcher.fetch(message: message, readable_space_guids: [space_1.guid]).all + + expect(results).to match_array([service_instance_1, service_instance_2]) + end + + context 'filter' do + context 'by service instance name' do + let(:filters) { { names: ['rabbitmq'] } } + + it 'only returns matching service instances' do + results = fetcher.fetch(message: message, readable_space_guids: [space_1.guid]).all + expect(results).to match_array([service_instance_1]) + end + end + + context 'by space guid' do + let(:filters) { { space_guids: ['space-1'] } } + + it 'only returns matching service instances' do + results = fetcher.fetch_all(message: message).all + expect(results).to match_array([service_instance_1, service_instance_2]) + expect(results).not_to include(service_instance_3) + end + end + + context 'by all query params' do + let(:filters) { + { + space_guids: ['space-1'], + names: ['rabbitmq'], + } + } + + it 'only returns matching managed service instances' do + results = fetcher.fetch(message: message, readable_space_guids: [space_1.guid]).all + expect(results).to match_array([service_instance_1]) + end + end + + context 'by non-existent service instance name' do + let(:filters) { { names: ['made-up-name'] } } + + it 'returns no matching service instances' do + results = fetcher.fetch(message: message, readable_space_guids: [space_1.guid]).all + expect(results).to be_empty + end + end + + context 'by non-existent space guid' do + let(:filters) { { space_guids: ['made-up-name'] } } + + it 'returns no matching service instances' do + results = fetcher.fetch(message: message, readable_space_guids: [space_1.guid]).all + expect(results).to be_empty + end + end + end + + context 'when managed service instances are shared' do + let(:shared_to_space) { Space.make } + + before do + service_instance_2.add_shared_space(shared_to_space) + service_instance_1.add_shared_space(shared_to_space) + end + + it 'returns all of the service instances shared into the specified space' do + results = fetcher.fetch(message: message, readable_space_guids: [shared_to_space.guid]).all + expect(results).to match_array([service_instance_1, service_instance_2]) + end + end + + context 'when a space contains both shared and non-shared service instances' do + let(:shared_to_space) { Space.make } + let!(:service_instance_4) { ManagedServiceInstance.make(space: shared_to_space) } + + before do + service_instance_2.add_shared_space(shared_to_space) + service_instance_1.add_shared_space(shared_to_space) + end + + it 'returns all of the service instances shared into the specified space' do + results = fetcher.fetch(message: message, readable_space_guids: [shared_to_space.guid]).all + expect(results).to match_array([service_instance_1, service_instance_2, service_instance_4]) + end + end + end + end +end diff --git a/spec/unit/queries/service_instance_list_fetcher_spec.rb b/spec/unit/queries/service_instance_list_fetcher_spec.rb deleted file mode 100644 index fa07743ce8d..00000000000 --- a/spec/unit/queries/service_instance_list_fetcher_spec.rb +++ /dev/null @@ -1,103 +0,0 @@ -require 'spec_helper' -require 'fetchers/service_instance_list_fetcher' -require 'messages/service_instances/service_instances_list_message' - -module VCAP::CloudController - RSpec.describe ServiceInstanceListFetcher do - let(:filters) { {} } - let(:message) { ServiceInstancesListMessage.new(filters) } - let(:fetcher) { ServiceInstanceListFetcher.new } - - describe '#fetch_all' do - let!(:service_instance_1) { ManagedServiceInstance.make(name: 'rabbitmq') } - let!(:service_instance_2) { ManagedServiceInstance.make(name: 'redis') } - - it 'returns a Sequel::Dataset' do - results = fetcher.fetch_all(message: message) - expect(results).to be_a(Sequel::Dataset) - end - - it 'includes all the V3 Service Instances' do - results = fetcher.fetch_all(message: message).all - expect(results.length).to eq 2 - expect(results).to include(service_instance_1, service_instance_2) - end - - context 'filter' do - context 'by service instance name' do - let(:filters) { { names: ['rabbitmq'] } } - - it 'only returns matching service instances' do - results = fetcher.fetch_all(message: message).all - expect(results).to match_array([service_instance_1]) - expect(results).not_to include(service_instance_2) - end - end - end - end - - describe '#fetch' do - let!(:service_instance_1) { ManagedServiceInstance.make(name: 'rabbitmq', space: space_1) } - let!(:service_instance_2) { ManagedServiceInstance.make(name: 'redis', space: space_1) } - let!(:service_instance_3) { ManagedServiceInstance.make(name: 'mysql', space: space_2) } - - let(:space_1) { Space.make } - let(:space_2) { Space.make } - - it 'returns all of the service instances in the specified space' do - results = fetcher.fetch(message: message, space_guids: [space_1.guid]).all - - expect(results).to match_array([service_instance_1, service_instance_2]) - end - - context 'filter' do - context 'by service instance name' do - let(:filters) { { names: ['rabbitmq'] } } - - it 'only returns matching service instances' do - results = fetcher.fetch(message: message, space_guids: [space_1.guid]).all - expect(results).to match_array([service_instance_1]) - end - end - - context 'by non-existent service instance name' do - let(:filters) { { names: ['made-up-name'] } } - - it 'returns no matching service instances' do - results = fetcher.fetch(message: message, space_guids: [space_1.guid]).all - expect(results).to be_empty - end - end - end - - context 'when service instances are shared' do - let(:shared_to_space) { Space.make } - - before do - service_instance_2.add_shared_space(shared_to_space) - service_instance_1.add_shared_space(shared_to_space) - end - - it 'returns all of the service instances shared into the specified space' do - results = fetcher.fetch(message: message, space_guids: [shared_to_space.guid]).all - expect(results).to match_array([service_instance_1, service_instance_2]) - end - end - - context 'when a space contains both shared and non-shared service instances' do - let(:shared_to_space) { Space.make } - let!(:service_instance_4) { ManagedServiceInstance.make(space: shared_to_space) } - - before do - service_instance_2.add_shared_space(shared_to_space) - service_instance_1.add_shared_space(shared_to_space) - end - - it 'returns all of the service instances shared into the specified space' do - results = fetcher.fetch(message: message, space_guids: [shared_to_space.guid]).all - expect(results).to match_array([service_instance_1, service_instance_2, service_instance_4]) - end - end - end - end -end