Test for Pruner
This commit is contained in:
@@ -6,27 +6,26 @@ require_relative '../exceptions'
|
||||
|
||||
module Pruning
|
||||
module API
|
||||
# Handles general concers regarding API calls
|
||||
class App < Sinatra::Base
|
||||
before { content_type :json }
|
||||
after { serialise_response }
|
||||
set :show_exceptions, true
|
||||
|
||||
|
||||
error Pruning::Exceptions::UnexpectedError do
|
||||
error Pruning::Exceptions::UnexpectedError do
|
||||
status 500
|
||||
end
|
||||
|
||||
error Pruning::Exceptions::OriginCannotFindTheResource do
|
||||
status 404
|
||||
status 404
|
||||
end
|
||||
|
||||
|
||||
get '/' do
|
||||
"Try /tree/:name"
|
||||
'Try /tree/:name?indicator_ids[]=32&indicator_ids[]=31'
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def serialise_response
|
||||
return unless content_type == 'application/json'
|
||||
response.body = [JSON(response.body)]
|
||||
|
||||
@@ -7,17 +7,15 @@ require_relative '../exceptions'
|
||||
|
||||
module Pruning
|
||||
module API
|
||||
# Handles all tree related API requests
|
||||
class Tree < App
|
||||
get '/tree/:name' do
|
||||
tree_repo = Pruning::Repos::Tree.new(RestClient, ENV['TREE_SOURCE_API_HOSTNAME'])
|
||||
complete_tree = tree_repo.get(query.name)
|
||||
pruner = Pruning::Processing::Pruner.new(complete_tree)
|
||||
pruner.prune_tree(query.indicator_ids)
|
||||
tree_repo = Pruning::Repos::Tree.new(RestClient,
|
||||
ENV['TREE_SOURCE_API_HOSTNAME'])
|
||||
complete_tree = tree_repo.get(query.name)
|
||||
pruner = Pruning::Processing::Pruner.new(complete_tree)
|
||||
pruner.prune_tree(query.indicator_ids.to_a)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -4,10 +4,9 @@ module Pruning
|
||||
end
|
||||
|
||||
class OriginCannotFindTheResource < StandardError
|
||||
end
|
||||
end
|
||||
|
||||
class UnexpectedError < StandardError
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
module Pruning
|
||||
module HTTP
|
||||
# Whitelists the URL query parameters
|
||||
class Query < Struct.new(:name, :indicator_ids)
|
||||
def initialize(params = {})
|
||||
symbolised = params.map { |k, v| { k.to_sym => v } }.reduce({}, :merge)
|
||||
@@ -7,9 +8,9 @@ module Pruning
|
||||
value = symbolised.fetch(member, nil)
|
||||
next if value.nil?
|
||||
case member
|
||||
when :indicator_ids then value.map(&->(indicator_id) { indicator_id.to_i } ) # break on purpose if indicator_ids is not an array
|
||||
when :name then value.to_s.gsub(/[^A-Za-z]/,'')
|
||||
else value
|
||||
when :indicator_ids then value.map(&->(indicator_id) { indicator_id.to_i }) # break on purpose if indicator_ids is not an array
|
||||
when :name then value.to_s.gsub(/[^A-Za-z]/, '')
|
||||
else value
|
||||
end
|
||||
end
|
||||
super(*values)
|
||||
|
||||
@@ -1,27 +1,29 @@
|
||||
module Pruning
|
||||
module Processing
|
||||
# Contains methods that store the tree and prune everything
|
||||
# except the branches with requested indicator
|
||||
class Pruner
|
||||
|
||||
def initialize(tree)
|
||||
@tree = tree
|
||||
end
|
||||
|
||||
def prune_tree(indicator_ids)
|
||||
pruned_tree = @tree.dup
|
||||
pruned_tree = @tree
|
||||
prune_subtree(pruned_tree, indicator_ids)
|
||||
pruned_tree
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def prune_subtree(nodes, indicator_ids)
|
||||
nodes_to_examine = nodes.dup
|
||||
nodes_to_examine.each do |node|
|
||||
if indicator_node?(node)
|
||||
unwanted_indicator = !indicator_ids.include?(node['id'])
|
||||
nodes.delete(node) if unwanted_indicator
|
||||
else
|
||||
has_no_wanted_indicators_in_children = prune_subtree(children(node), indicator_ids)
|
||||
nodes.delete(node) if has_no_wanted_indicators_in_children
|
||||
if indicator_node?(node)
|
||||
indicator_not_wanted = !indicator_ids.include?(node['id'])
|
||||
nodes.delete(node) if indicator_not_wanted
|
||||
else
|
||||
no_wanted_children = prune_subtree(children(node), indicator_ids)
|
||||
nodes.delete(node) if no_wanted_children
|
||||
end
|
||||
end
|
||||
nodes.empty?
|
||||
@@ -29,11 +31,11 @@ module Pruning
|
||||
|
||||
def children(node)
|
||||
node.fetch('sub_themes', false) ||
|
||||
node.fetch('categories', false) ||
|
||||
node.fetch('indicators', false) ||
|
||||
[]
|
||||
node.fetch('categories', false) ||
|
||||
node.fetch('indicators', false) ||
|
||||
[]
|
||||
end
|
||||
|
||||
|
||||
def indicator_node?(node)
|
||||
children(node).empty?
|
||||
end
|
||||
|
||||
@@ -3,31 +3,36 @@ require 'retries'
|
||||
require 'json'
|
||||
require_relative '../exceptions'
|
||||
|
||||
|
||||
NUMBER_OF_RETRIES = 3
|
||||
|
||||
module Pruning
|
||||
module Repos
|
||||
# Handles communication with origin server
|
||||
# and all its problems
|
||||
class Tree
|
||||
def initialize(client=RestClient, base_url)
|
||||
def initialize(client, base_url)
|
||||
@client = client
|
||||
@base_url = base_url
|
||||
end
|
||||
|
||||
def get(name)
|
||||
with_retries(max_tries: 3, rescue: [Pruning::Exceptions::ServerErrorOnOrigin]) do
|
||||
with_retries(max_tries: NUMBER_OF_RETRIES, rescue: [Pruning::Exceptions::ServerErrorOnOrigin]) do
|
||||
begin
|
||||
resp = @client.get(url(name))
|
||||
rescue RestClient::ExceptionWithResponse => e
|
||||
if e.response.code != 404
|
||||
raise Pruning::Exceptions::ServerErrorOnOrigin
|
||||
else
|
||||
raise Pruning::Exceptions::OriginCannotFindTheResource
|
||||
end
|
||||
rescue RestClient::ExceptionWithResponse => e
|
||||
raise Pruning::Exceptions::ServerErrorOnOrigin if e.response.code != 404
|
||||
raise Pruning::Exceptions::OriginCannotFindTheResource
|
||||
end
|
||||
|
||||
return JSON(resp.body)
|
||||
end
|
||||
return JSON(resp.body)
|
||||
end
|
||||
raise Pruning::Exceptions::UnexpectedError
|
||||
raise Pruning::Exceptions::UnexpectedError
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
private
|
||||
|
||||
def url(name)
|
||||
"#{@base_url}/tree/#{name}"
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user