spec/unit/presenters/v3/service_offering_presenter_spec.rb
require 'spec_helper'
require 'support/link_helpers'
require 'presenters/v3/service_offering_presenter'
RSpec.describe VCAP::CloudController::Presenters::V3::ServiceOfferingPresenter do
include LinkHelpers
let(:guid) { 'some-offering-guid' }
let(:name) { 'some-offering-name' }
let(:description) { 'some offering description' }
let(:documentation_url) { 'https://some.documentation.url/' }
let(:available) { false }
let(:bindable) { false }
let(:extra) { '{"foo": "bar", "baz": {"answer": 42}}' }
let(:id) { 'broker-id' }
let(:tags) { %w[foo bar] }
let(:requires) { %w[syslog_drain route_forwarding volume_mount] }
let(:updateable) { false }
let(:service_broker) { VCAP::CloudController::ServiceBroker.make }
let(:instances_retrievable) { false }
let(:bindings_retrievable) { false }
let(:allow_context_updates) { false }
let(:created_at) { Time.now.round(0) - 100 }
let(:service_offering) do
VCAP::CloudController::Service.make(
guid: guid,
label: name,
description: description,
active: available,
bindable: bindable,
extra: extra,
unique_id: id,
tags: tags,
requires: requires,
plan_updateable: updateable,
service_broker: service_broker,
instances_retrievable: instances_retrievable,
bindings_retrievable: bindings_retrievable,
allow_context_updates: allow_context_updates,
created_at: created_at
)
end
let!(:potato_label) do
VCAP::CloudController::ServiceOfferingLabelModel.make(
key_prefix: 'canberra.au',
key_name: 'potato',
value: 'mashed',
resource_guid: service_offering.guid
)
end
let!(:mountain_annotation) do
VCAP::CloudController::ServiceOfferingAnnotationModel.make(
key_name: 'altitude',
value: '14,412',
resource_guid: service_offering.guid
)
end
describe '#to_hash' do
let(:result) { described_class.new(service_offering).to_hash.deep_symbolize_keys }
it 'presents the service offering as JSON' do
expect(result).to match({
guid: guid,
name: name,
description: description,
available: available,
tags: tags,
requires: requires,
created_at: created_at,
updated_at: service_offering.updated_at,
shareable: false,
documentation_url: '',
broker_catalog: {
id: id,
metadata: {
foo: 'bar',
baz: {
answer: 42
}
},
features: {
plan_updateable: updateable,
bindable: bindable,
instances_retrievable: instances_retrievable,
bindings_retrievable: bindings_retrievable,
allow_context_updates: allow_context_updates
}
},
metadata: {
labels: {
'canberra.au/potato': 'mashed'
},
annotations: {
altitude: '14,412'
}
},
links: {
self: {
href: "#{link_prefix}/v3/service_offerings/#{guid}"
},
service_plans: {
href: "#{link_prefix}/v3/service_plans?service_offering_guids=#{guid}"
},
service_broker: {
href: "#{link_prefix}/v3/service_brokers/#{service_broker.guid}"
}
},
relationships: {
service_broker: {
data: {
guid: service_broker.guid
}
}
}
})
end
context 'when `available` is true' do
let(:available) { true }
it 'displays `true``' do
expect(result[:available]).to be(true)
end
end
context 'when `bindable` is true' do
let(:bindable) { true }
it 'displays `true``' do
expect(result.dig(:broker_catalog, :features, :bindable)).to be(true)
end
end
context 'when `updateable` is true' do
let(:updateable) { true }
it 'displays `true``' do
expect(result.dig(:broker_catalog, :features, :plan_updateable)).to be(true)
end
end
context 'when `instances_retrievable` is true' do
let(:instances_retrievable) { true }
it 'displays `true``' do
expect(result.dig(:broker_catalog, :features, :instances_retrievable)).to be(true)
end
end
context 'when `bindings_retrievable` is true' do
let(:bindings_retrievable) { true }
it 'displays `true``' do
expect(result.dig(:broker_catalog, :features, :bindings_retrievable)).to be(true)
end
end
context 'when `allow_context_updates` is true' do
let(:allow_context_updates) { true }
it 'displays `true``' do
expect(result.dig(:broker_catalog, :features, :allow_context_updates)).to be(true)
end
end
context 'extra' do
context 'when `shareable` is true' do
let(:extra) { '{"shareable": true}' }
it 'displays `true``' do
expect(result[:shareable]).to be true
end
end
context 'when `shareable` is non-boolean' do
let(:extra) { '{"shareable": "invalid value"}' }
it 'displays `false``' do
expect(result[:shareable]).to be false
end
end
context 'when `shareable` is explicitly false' do
let(:extra) { '{"shareable": false}' }
it 'displays `false``' do
expect(result[:shareable]).to be false
end
end
context 'when `documentation_url` is set' do
let(:extra) { '{"documentationUrl": "https://some.documentation.url/"}' }
it 'displays the value` as a top level field' do
expect(result[:documentation_url]).to eq 'https://some.documentation.url/'
end
end
end
context 'when `metadata` is not set' do
let(:extra) { nil }
it 'displays shareable as `false``' do
expect(result[:shareable]).to be false
end
end
# Note that the metadata is saved as a serialized JSON string, so it should always
# be possible to parse it.
context 'when the broker metadata cannot be parsed' do
let(:extra) { 'this will cause a JSON parse error' }
it 'defaults `shareable` to false' do
expect(result[:shareable]).to be false
end
it 'defaults `metadata` to empty' do
expect(result.dig(:broker_catalog, :metadata)).to be_empty
end
end
context 'when a decorator is provided' do
class FakeDecorator
def self.decorate(hash, resources)
hash[:included] = { resource: { guid: resources[0].guid } }
hash
end
end
let(:result) { described_class.new(service_offering, decorators: [FakeDecorator]).to_hash.deep_symbolize_keys }
let(:service_offering) { VCAP::CloudController::Service.make }
it 'uses the decorator' do
expect(result[:included]).to match({ resource: { guid: service_offering.guid } })
end
end
end
end