-
Notifications
You must be signed in to change notification settings - Fork 141
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
Generic Object Definition CRUD #15
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
module Api | ||
class GenericObjectDefinitionsController < BaseController | ||
def show | ||
object = fetch_generic_object_definition(@req.c_id) | ||
render_resource(:generic_object_definitions, object) | ||
end | ||
|
||
def create_resource(_type, _id, data) | ||
klass = collection_class(:generic_object_definitions) | ||
klass.create!(data.deep_symbolize_keys) | ||
rescue => err | ||
raise BadRequestError, "Failed to create new generic object definition - #{err}" | ||
end | ||
|
||
def edit_resource(_type, id, data) | ||
id ||= data['name'] | ||
go_def = fetch_generic_object_definition(id) | ||
updated_data = data['resource'].try(:deep_symbolize_keys) || data.deep_symbolize_keys | ||
go_def.update_attributes!(updated_data) if data.present? | ||
go_def | ||
rescue => err | ||
raise BadRequestError, "Failed to update generic object definition - #{err}" | ||
end | ||
|
||
def delete_resource(_type, id, data = {}) | ||
id ||= data['name'] | ||
go_def = fetch_generic_object_definition(id) | ||
go_def.destroy! | ||
rescue => err | ||
raise BadRequestError, "Failed to delete generic object definition - #{err}" | ||
end | ||
|
||
private | ||
|
||
def fetch_generic_object_definition(id) | ||
klass = collection_class(:generic_object_definitions) | ||
klass.find_by(:name => id) || klass.find(id) | ||
end | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's add Rbac.filtered_object before returning it. |
||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,312 @@ | ||
# rubocop:disable Style/WordArray | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Disabling as I prefer that the sample requests not use word arrays to better align with how the request will look. |
||
RSpec.describe 'GenericObjectDefinitions API' do | ||
let(:object_def) { FactoryGirl.create(:generic_object_definition, :name => 'foo') } | ||
|
||
describe 'GET /api/generic_object_definitions' do | ||
it 'does not list object definitions without an appropriate role' do | ||
api_basic_authorize | ||
|
||
run_get(generic_object_definitions_url) | ||
|
||
expect(response).to have_http_status(:forbidden) | ||
end | ||
|
||
it 'lists all generic object definitions with an appropriate role' do | ||
api_basic_authorize collection_action_identifier(:generic_object_definitions, :read, :get) | ||
object_def_href = generic_object_definitions_url(object_def.compressed_id) | ||
|
||
run_get(generic_object_definitions_url) | ||
|
||
expected = { | ||
'count' => 1, | ||
'subcount' => 1, | ||
'name' => 'generic_object_definitions', | ||
'resources' => [ | ||
hash_including('href' => a_string_matching(object_def_href)) | ||
] | ||
} | ||
expect(response).to have_http_status(:ok) | ||
expect(response.parsed_body).to include(expected) | ||
end | ||
end | ||
|
||
describe 'GET /api/generic_object_definitions/:id' do | ||
it 'does not let you query object definitions without an appropriate role' do | ||
api_basic_authorize | ||
|
||
run_get(generic_object_definitions_url(object_def.compressed_id)) | ||
|
||
expect(response).to have_http_status(:forbidden) | ||
end | ||
|
||
it 'can query an object definition by its id' do | ||
api_basic_authorize action_identifier(:generic_object_definitions, :read, :resource_actions, :get) | ||
|
||
run_get(generic_object_definitions_url(object_def.id)) | ||
|
||
expected = { | ||
'id' => object_def.compressed_id, | ||
'name' => object_def.name | ||
} | ||
expect(response).to have_http_status(:ok) | ||
expect(response.parsed_body).to include(expected) | ||
end | ||
|
||
it 'can query an object definition by its name' do | ||
api_basic_authorize action_identifier(:generic_object_definitions, :read, :resource_actions, :get) | ||
|
||
run_get(generic_object_definitions_url(object_def.name)) | ||
|
||
expected = { | ||
'id' => object_def.compressed_id, | ||
'name' => object_def.name | ||
} | ||
expect(response).to have_http_status(:ok) | ||
expect(response.parsed_body).to include(expected) | ||
end | ||
|
||
it 'raises a record not found error if no object definition is found' do | ||
api_basic_authorize action_identifier(:generic_object_definitions, :read, :resource_actions, :get) | ||
|
||
run_get(generic_object_definitions_url('bar')) | ||
|
||
expect(response).to have_http_status(:not_found) | ||
end | ||
end | ||
|
||
describe 'POST /api/generic_object_definitions' do | ||
it 'can create a new generic_object_definition' do | ||
api_basic_authorize collection_action_identifier(:generic_object_definitions, :create) | ||
|
||
object_definition = { | ||
'name' => 'LoadBalancer', | ||
'description' => 'LoadBalancer description', | ||
'properties' => { | ||
'attributes' => { | ||
'address' => 'string', | ||
'last_restart' => 'datetime' | ||
}, | ||
'associations' => { | ||
'vms' => 'Vm', | ||
'services' => 'Service' | ||
}, | ||
'methods' => [ | ||
'add_vm', | ||
'remove_vm' | ||
] | ||
} | ||
} | ||
run_post(generic_object_definitions_url, object_definition) | ||
|
||
expect(response).to have_http_status(:ok) | ||
expect(response.parsed_body['results'].first).to include(object_definition) | ||
end | ||
|
||
it 'cannot create an invalid generic_object_definition' do | ||
api_basic_authorize collection_action_identifier(:generic_object_definitions, :create) | ||
|
||
request = { | ||
'name' => 'foo', | ||
'description' => 'LoadBalancer description', | ||
'properties' => { | ||
'attributes' => { | ||
'last_restart' => 'date' | ||
} | ||
} | ||
} | ||
run_post(generic_object_definitions_url, request) | ||
|
||
expected = { | ||
'error' => a_hash_including( | ||
'kind' => 'bad_request', | ||
'message' => a_string_including('Failed to create new generic object definition - Validation failed') | ||
) | ||
} | ||
expect(response).to have_http_status(:bad_request) | ||
expect(response.parsed_body).to include(expected) | ||
end | ||
|
||
it 'can edit generic_object_definitions by id, name, or href' do | ||
object_def2 = FactoryGirl.create(:generic_object_definition, :name => 'foo 2') | ||
object_def3 = FactoryGirl.create(:generic_object_definition, :name => 'foo 3') | ||
api_basic_authorize collection_action_identifier(:generic_object_definitions, :edit) | ||
|
||
request = { | ||
'action' => 'edit', | ||
'resources' => [ | ||
{ 'name' => object_def.name, 'resource' => { 'name' => 'updated 1' } }, | ||
{ 'id' => object_def2.compressed_id, 'resource' => { 'name' => 'updated 2' }}, | ||
{ 'href' => generic_object_definitions_url(object_def3.compressed_id), 'resource' => { 'name' => 'updated 3' }} | ||
] | ||
} | ||
run_post(generic_object_definitions_url, request) | ||
|
||
expected = { | ||
'results' => a_collection_including( | ||
a_hash_including('id' => object_def.compressed_id, 'name' => 'updated 1'), | ||
a_hash_including('id' => object_def2.compressed_id, 'name' => 'updated 2'), | ||
a_hash_including('id' => object_def3.compressed_id, 'name' => 'updated 3') | ||
) | ||
} | ||
expect(response).to have_http_status(:ok) | ||
expect(response.parsed_body).to include(expected) | ||
end | ||
end | ||
|
||
describe 'POST /api/generic_object_definitions/:id' do | ||
it 'can update an object definition by name' do | ||
api_basic_authorize action_identifier(:generic_object_definitions, :edit) | ||
|
||
request = { | ||
'action' => 'edit', | ||
'name' => 'LoadBalancer Updated', | ||
'description' => 'LoadBalancer description Updated', | ||
'properties' => { | ||
'attributes' => { | ||
'last_updated' => 'string', | ||
}, | ||
'associations' => { | ||
'vms' => 'Vm', | ||
'services' => 'Service' | ||
}, | ||
'methods' => [ | ||
'add_vm', | ||
'remove_vm', | ||
'new_method' | ||
] | ||
} | ||
} | ||
run_post(generic_object_definitions_url(object_def.name), request) | ||
|
||
expect(response).to have_http_status(:ok) | ||
expect(response.parsed_body).to include(request.except('action')) | ||
end | ||
|
||
it 'can update an object definition by id' do | ||
api_basic_authorize action_identifier(:generic_object_definitions, :edit) | ||
|
||
request = { | ||
'action' => 'edit', | ||
'name' => 'LoadBalancer Updated', | ||
'description' => 'LoadBalancer description Updated', | ||
'properties' => { | ||
'attributes' => { | ||
'last_updated' => 'string', | ||
}, | ||
'associations' => { | ||
'vms' => 'Vm', | ||
'services' => 'Service' | ||
}, | ||
'methods' => [ | ||
'add_vm', | ||
'remove_vm', | ||
'new_method' | ||
] | ||
} | ||
} | ||
run_post(generic_object_definitions_url(object_def.compressed_id), request) | ||
|
||
expect(response).to have_http_status(:ok) | ||
expect(response.parsed_body).to include(request.except('action')) | ||
end | ||
|
||
it 'cannot update an object with bad data' do | ||
api_basic_authorize action_identifier(:generic_object_definitions, :edit) | ||
|
||
request = { | ||
'action' => 'edit', | ||
'properties' => { | ||
'attributes' => { | ||
'last_updated' => 'date', | ||
} | ||
} | ||
} | ||
run_post(generic_object_definitions_url(object_def.compressed_id), request) | ||
|
||
expected = { | ||
'error' => a_hash_including( | ||
'kind' => 'bad_request', | ||
'message' => a_string_including('Failed to update generic object definition - Validation failed') | ||
) | ||
} | ||
expect(response).to have_http_status(:bad_request) | ||
expect(response.parsed_body).to include(expected) | ||
end | ||
|
||
it 'can delete an object definition by name' do | ||
api_basic_authorize action_identifier(:generic_object_definitions, :delete) | ||
|
||
run_post(generic_object_definitions_url(object_def.name), :action => 'delete') | ||
|
||
expect(response).to have_http_status(:ok) | ||
end | ||
|
||
it 'can delete an object definition by id' do | ||
api_basic_authorize action_identifier(:generic_object_definitions, :delete) | ||
|
||
run_post(generic_object_definitions_url(object_def.compressed_id), :action => 'delete') | ||
|
||
expect(response).to have_http_status(:ok) | ||
end | ||
|
||
it 'will not delete a generic_object_definition if it is in use' do | ||
api_basic_authorize action_identifier(:generic_object_definitions, :delete, :resource_actions, :delete) | ||
object_def.create_object(:name => 'foo object') | ||
|
||
run_post(generic_object_definitions_url(object_def.name), :action => 'delete') | ||
|
||
expected = { | ||
'error' => a_hash_including( | ||
'kind' => 'bad_request', | ||
'message' => a_string_including('Failed to delete generic object definition') | ||
) | ||
} | ||
expect(response).to have_http_status(:bad_request) | ||
expect(response.parsed_body).to include(expected) | ||
end | ||
|
||
it 'can delete generic_object_definition in bulk by name, id, or href' do | ||
object_def2 = FactoryGirl.create(:generic_object_definition, :name => 'foo 2') | ||
object_def3 = FactoryGirl.create(:generic_object_definition, :name => 'foo 3') | ||
api_basic_authorize collection_action_identifier(:generic_object_definitions, :delete) | ||
|
||
request = { | ||
'action' => 'delete', | ||
'resources' => [ | ||
{ 'name' => object_def.name }, | ||
{ 'id' => object_def2.compressed_id}, | ||
{ 'href' => generic_object_definitions_url(object_def3.compressed_id)} | ||
] | ||
} | ||
run_post(generic_object_definitions_url, request) | ||
|
||
expected = { | ||
'results' => a_collection_including( | ||
a_hash_including('id' => object_def.compressed_id), | ||
a_hash_including('id' => object_def2.compressed_id), | ||
a_hash_including('id' => object_def3.compressed_id) | ||
) | ||
} | ||
expect(response).to have_http_status(:ok) | ||
expect(response.parsed_body).to include(expected) | ||
end | ||
end | ||
|
||
describe 'DELETE /api/generic_object_definitions/:id' do | ||
it 'can delete a generic_object_definition by id' do | ||
api_basic_authorize action_identifier(:generic_object_definitions, :delete, :resource_actions, :delete) | ||
|
||
run_delete(generic_object_definitions_url(object_def.compressed_id)) | ||
|
||
expect(response).to have_http_status(:no_content) | ||
end | ||
|
||
it 'can delete a generic_object_definition by name' do | ||
api_basic_authorize action_identifier(:generic_object_definitions, :delete, :resource_actions, :delete) | ||
|
||
run_delete(generic_object_definitions_url(object_def.name)) | ||
|
||
expect(response).to have_http_status(:no_content) | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's leverage ApplicationRecord.compressed_id?(id) and leverage resource_search for id based.