Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delete portfolio items #82

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions app/controllers/api/v0/admins_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ def add_to_order
render json: AddToOrder.new(params).process.to_hash
end

def destroy_portfolio_item
PortfolioItem.find(params.require(:portfolio_item_id)).destroy
head :no_content
end

private
def portfolio_item_params
params.permit(:service_offering_ref)
Expand Down
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def add_swagger_route(http_method, path, opts = {})
add_swagger_route 'GET', '/portfolios/{portfolio_id}', :controller_name => 'admins', :action_name => 'fetch_portfolio_with_id'
add_swagger_route 'PATCH', '/portfolios/{portfolio_id}', :controller_name => 'admins', :action_name => 'edit_portfolio'
add_swagger_route 'DELETE', '/portfolios/{portfolio_id}', :controller_name => 'admins', :action_name => 'destroy_portfolio'
add_swagger_route 'DELETE', '/portfolio_items/{portfolio_item_id}', :controller_name => 'admins', :action_name => 'destroy_portfolio_item'
add_swagger_route 'GET', '/orders/{order_id}/items/{order_item_id}', :controller_name => 'admins', :action_name => 'list_order_item'
add_swagger_route 'GET', '/orders/{order_id}/items', :controller_name => 'admins', :action_name => 'list_order_items'
add_swagger_route 'GET', '/orders', :controller_name => 'admins', :action_name => 'list_orders'
Expand Down
17 changes: 17 additions & 0 deletions public/doc/swagger-2.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,23 @@ paths:
description: Service Offering not found
'422':
$ref: '#/responses/InvalidEntity'
'/portfolio_items/{portfolio_item_id}':
delete:
tags:
- admins
summary: Delete an existing portfolio item
operationId: destroyPortfolioItem
description: |
Deletes the portfolio item id passed in as the param.
produces:
- application/json
parameters:
- $ref: '#/parameters/PortfolioItemID'
responses:
204:
description: Portfolio Item deleted
404:
description: Portfolio Item not Found
'/portfolio_items/{portfolio_item_id}/service_plans':
get:
tags:
Expand Down
32 changes: 32 additions & 0 deletions spec/requests/portfolio_items_request_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
describe "PortfolioItemRequests", :type => :request do
include ServiceSpecHelper

let(:service_offering_ref) { "998" }
let(:order) { create(:order) }
let(:portfolio_item) { create(:portfolio_item, :service_offering_ref => service_offering_ref) }
let(:svc_object) { instance_double("ServiceCatalog::ServicePlans") }
let(:plans) { [{}, {}] }
let(:topo_ex) { ServiceCatalog::TopologyError.new("kaboom") }

before do
allow(ServiceCatalog::ServicePlans).to receive(:new).with(portfolio_item.id.to_s).and_return(svc_object)
end

it "fetches plans" do
allow(svc_object).to receive(:process).and_return(svc_object)
allow(svc_object).to receive(:items).and_return(plans)

get "/api/v0.0/portfolio_items/#{portfolio_item.id}/service_plans"

expect(JSON.parse(response.body).count).to eq(2)
expect(response.content_type).to eq("application/json")
expect(response).to have_http_status(:ok)
end

it "raises error" do
allow(svc_object).to receive(:process).and_raise(topo_ex)

get "/api/v0.0/portfolio_items/#{portfolio_item.id}/service_plans"
expect(response).to have_http_status(:internal_server_error)
end
end
80 changes: 60 additions & 20 deletions spec/requests/portfolio_items_spec.rb
Original file line number Diff line number Diff line change
@@ -1,32 +1,72 @@
describe "PortfolioItemRequests", :type => :request do
describe 'PortfolioItems API' do
include RequestSpecHelper
include ServiceSpecHelper

let(:service_offering_ref) { "998" }
let(:order) { create(:order) }
let(:portfolio_item) { create(:portfolio_item, :service_offering_ref => service_offering_ref) }
let(:svc_object) { instance_double("ServiceCatalog::ServicePlans") }
let(:plans) { [{}, {}] }
let(:topo_ex) { ServiceCatalog::TopologyError.new("kaboom") }
let!(:portfolio_item) { create(:portfolio_item) }
let(:portfolio_item_id) { portfolio_item.id }
let(:tenant) { create(:tenant, :with_external_tenant) }

before do
allow(ServiceCatalog::ServicePlans).to receive(:new).with(portfolio_item.id.to_s).and_return(svc_object)
# Encoded Header: { 'identity' => { 'is_org_admin':false, 'org_id':111 } }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let(:user_encode_key_with_tenant) { { 'x-rh-auth-identity': 'eyJpZGVudGl0eSI6eyJpc19vcmdfYWRtaW4iOmZhbHNlLCJvcmdfaWQiOiIxMTEifX0=' } }
# Encoded Header: { 'identity' => { 'is_org_admin':true, 'org_id':111 } }
let(:admin_encode_key_with_tenant) { { 'x-rh-auth-identity': 'eyJpZGVudGl0eSI6eyJpc19vcmdfYWRtaW4iOnRydWUsIm9yZ19pZCI6MTExfX0=' } }

%w(admin user).each do |tag|
describe "GET #{tag} tagged /portfolio_items" do
before do
get "#{api}/portfolio_items", headers: send("#{tag}_encode_key_with_tenant")
end

context 'when portfolios exist' do
it 'returns status code 200' do
expect(response).to have_http_status(200)
end

it 'returns all portfolio requests' do
expect(json.size).to eq(1)
end
end
end
end

it "fetches plans" do
allow(svc_object).to receive(:process).and_return(svc_object)
allow(svc_object).to receive(:items).and_return(plans)
describe 'admin tagged /portfolio_items', :type => :routing do
let(:valid_attributes) { { name: 'rspec 1', description: 'rspec 1 description' } }
context 'with wrong header' do
it 'returns a 404' do
pending("Will work again when headers are checked")
expect(:post => "#{api}/portfolio_items").not_to be_routable
end
end
end

describe 'DELETE admin tagged /portfolio_items/:portfolio_item_id' do
let(:valid_attributes) { { :name => 'PatchPortfolio', :description => 'description for patched portfolio' } }

get "/api/v0.0/portfolio_items/#{portfolio_item.id}/service_plans"
context 'when :portfolio_item_id is valid' do
before do
delete "#{api}/portfolio_items/#{portfolio_item_id}", :headers => admin_headers, :params => valid_attributes
end

expect(JSON.parse(response.body).count).to eq(2)
expect(response.content_type).to eq("application/json")
expect(response).to have_http_status(:ok)
it 'deletes the record' do
expect(response).to have_http_status(204)
end
end
end

it "raises error" do
allow(svc_object).to receive(:process).and_raise(topo_ex)
describe 'POST admin tagged /portfolio_items' do
let(:valid_attributes) { { name: 'rh-mediawiki-apb', description: 'Mediawiki apb implementation', service_offering_ref: '21' } }
context 'when portfolio attributes are valid' do
before do
post "#{api}/portfolio_items", params: valid_attributes, headers: admin_encode_key_with_tenant
end

it 'returns status code 200' do
expect(response).to have_http_status(200)
end

get "/api/v0.0/portfolio_items/#{portfolio_item.id}/service_plans"
expect(response).to have_http_status(:internal_server_error)
it 'returns the new portfolio' do
expect(json['name']).to eq valid_attributes[:name]
end
end
end
end
18 changes: 1 addition & 17 deletions spec/services/service_catalog/service_offering_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,14 @@
[{:@name => name}, {:@description => description},
{:@service_offering_ref => service_offering_ref}]
end
let(:topology_service_offering) do
TopologicalInventoryApiClient::ServiceOffering.new('name' => name,
'id' => service_offering_ref,
'description' => description,
'source_ref' => '123',
'extra' => {},
'source_id' => '45')
end

let(:ti_class) { class_double("TopologicalInventory").as_stubbed_const(:transfer_nested_constants => true) }

before do
allow(ti_class).to receive(:call).and_yield(api_instance)
end

it "#{described_class}#find" do
expect(described_class).to receive(:new).and_return(service_offering)
expect(api_instance).to receive(:show_service_offering).with(service_offering_ref).and_return(topology_service_offering)
described_class.find(service_offering_ref)
end

it "#show" do
expect(api_instance).to receive(:show_service_offering).with(service_offering_ref).and_return(topology_service_offering)
service_offering.show(service_offering_ref)
expect(service_offering.show(service_offering_ref)).to be_a ServiceCatalog::ServiceOffering
end

it "#to_normalized_params" do
Expand Down
24 changes: 24 additions & 0 deletions spec/support/lib/topological_inventory.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
class TopologicalInventory
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No it isn't, it's a support file that allows us to call the TopologicalInventory class with out making a request to real Topological inventory. This file helped removing Mocking that was happening for any ServiceOffering instance. I'm going to pull this class out of the PR and move all these spec changes into their own PR to help clarify what I was doing here.

def self.api
Thread.current[:api_instance] ||= raw_api
end

def self.call
pass_thru_headers
yield api
rescue TopologicalInventoryApiClient::ApiError => err
Rails.logger.error("TopologicalInventoryApiClient::ApiError #{err.message} ")
raise ServiceCatalog::TopologyError, err.message
end

private_class_method def self.raw_api
TopologicalInventoryApiClient.configure do |config|
config.host = 'localhost'
config.scheme = 'http'
end
end

private_class_method def self.pass_thru_headers
{}
end
end
1 change: 1 addition & 0 deletions spec/support/service_catalog/service_offering.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"id":"21","name":"rh-mediawiki-apb","description":"Mediawiki apb implementation"},{"id":"153","name":"s2i-fuse71-karaf-camel-rest-sql","description":"Camel example using Rest DSL with SQL Database in Karaf container. This example demonstrates how to use SQL via JDBC along with Camel's REST DSL to expose a RESTful API. The OpenShift MySQL container image should already be installed and running on your OpenShift installation, one simple way to run a MySQL service is following the documentation of the OpenShift MySQL container image related to the mysql-ephemeral template.."}]
51 changes: 51 additions & 0 deletions spec/support/service_catalog/service_offering.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
module ServiceCatalog
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@syncrou
What is this file, is it a spec or a support file. We already have a spec file in
https://github.com/ManageIQ/service_portal-api/blob/master/spec/services/service_catalog/service_offering_spec.rb

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Support file

Same as my comment above.

Any spec calling create on PortfolioItem was causing me lots of pain. This allows those requests to work with real data see line 17 here: https://github.com/ManageIQ/service_portal-api/pull/82/files#diff-da5419dcb98a21e5282dcb098c832fea

class ServiceOffering
def initialize
@name = nil
@description = nil
@service_offering_ref = nil
end

def self.find(id)
new.show(id)
end

def show(id)
@service_offering_ref = id
obj = nil
TopologicalInventory.call do |api_instance|
obj = JSON.parse(File.read("#{Rails.root}/spec/support/service_catalog/service_offering.json"))
end
resp = obj.select { |x| x['id'] == id }
@normalized = resp.first
self
end

def to_normalized_params
hashy = instance_variables.each_with_object({}) do |var, hash|
next if var == :@normalized
hash[var.to_s.delete("@")] = instance_variable_get(var)
end
if @normalized
@normalized["service_offering_ref"] = @normalized["id"]
@normalized
else
hashy.compact
end
end

private

def apply_instance_vars(obj)
uniq_ivars(obj).each do |ivar|
value = obj.instance_variable_get(ivar)
instance_variable_set(ivar, value)
end
self
end

def uniq_ivars(object)
instance_variables & object.instance_variables
end
end
end