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

Refactor commands and add testing #72

Merged
merged 28 commits into from
Nov 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f4a1682
refactor copy_service command
eguzki Nov 6, 2018
37c3953
refactor update_service command
eguzki Nov 19, 2018
d786e3d
minor: source/target and other vars naming refactor
eguzki Nov 20, 2018
f407432
spec/unit/copy_service_spec: tests
eguzki Nov 20, 2018
4b8188b
spec/unit/update_service_spec: unittests
eguzki Nov 21, 2018
a53f945
tasks/copy_app_plans_task: refator var names
eguzki Nov 21, 2018
03fc5c5
spec/unit/copy_app_plans_task_spec: unittest
eguzki Nov 21, 2018
9d2483c
tasks/copy_limits_task, tasks/helper_task: refactor var name
eguzki Nov 21, 2018
a1cef44
copy_app_plans_task_spec: match stdout
eguzki Nov 21, 2018
8284e38
tasks/copy_limits_task_spec: unittests
eguzki Nov 21, 2018
d2458af
tasks test folder
eguzki Nov 21, 2018
f511f8b
copy_mapping_rules_task: refactor var names
eguzki Nov 21, 2018
b0a0e70
copy_mapping_rules_task_spec: unittests
eguzki Nov 21, 2018
3ed3fbf
tasks/copy_methods_task: refactor
eguzki Nov 21, 2018
6d3869c
copy_methods_task_spec: unittests
eguzki Nov 21, 2018
925ff68
refactor some variable names
eguzki Nov 21, 2018
53a5f48
copy_metrics_task: refactor variable names
eguzki Nov 21, 2018
8c9199a
copy_metrics_task_spec: unittests
eguzki Nov 21, 2018
a5a5fae
copy_service_proxy_task_spec: unittests
eguzki Nov 21, 2018
bc516f9
destroy_mapping_rules_task_spec: unittests
eguzki Nov 21, 2018
5314203
simplify copy_service_spec unittest
eguzki Nov 22, 2018
886b407
helper: enhance compare_hashes method
eguzki Nov 22, 2018
43177e5
unit/helper_spec.rb: helper unittests
eguzki Nov 22, 2018
2acbd50
entities/service_spec: unittests
eguzki Nov 22, 2018
b89bab9
remotes requires verify_ssl as input argument
eguzki Nov 22, 2018
df44db2
remotes_spec: unittests
eguzki Nov 22, 2018
8cadf9d
update_service_settings_task_spec: unittests
eguzki Nov 22, 2018
cce16f4
service_spec: fix plan limit object
eguzki Nov 23, 2018
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: 4 additions & 1 deletion lib/3scale_toolbox.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
require '3scale_toolbox/version'
require '3scale_toolbox/helper'
require '3scale_toolbox/error'
require '3scale_toolbox/configuration'
require '3scale_toolbox/remotes'
require '3scale_toolbox/entities'
require '3scale_toolbox/tasks'
require '3scale_toolbox/base_command'
require '3scale_toolbox/commands'
require '3scale_toolbox/cli'
require '3scale_toolbox/remotes'

module ThreeScaleToolbox

Expand Down
8 changes: 0 additions & 8 deletions lib/3scale_toolbox/commands.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,5 @@ module Commands
ThreeScaleToolbox::Commands::UpdateCommand,
ThreeScaleToolbox::Commands::RemoteCommand::RemoteCommand
].freeze

def self.service_valid_params
%w[
name backend_version deployment_option description
system_name end_user_registration_required
support_email tech_support_email admin_support_email
]
end
end
end
193 changes: 26 additions & 167 deletions lib/3scale_toolbox/commands/copy_command/copy_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ module Commands
module CopyCommand
class CopyServiceSubcommand < Cri::CommandRunner
include ThreeScaleToolbox::Command
include ThreeScaleToolbox::Remotes

def self.command
Cri::Command.define do
name 'service'
Expand All @@ -27,178 +29,35 @@ def run
destination = fetch_required_option(:destination)
system_name = fetch_required_option(:target_system_name)

copy_service(arguments[:service_id], source, destination, system_name)
end

def compare_hashes(first, second, keys)
keys.map{ |key| first.fetch(key) } == keys.map{ |key| second.fetch(key) }
end

def provider_key_from_url(url)
url[/\w*@/][0..-2]
end

def endpoint_from_url(url)
url.sub /\w*@/, ''
source_service = Entities::Service.new(id: arguments[:service_id],
remote: remote(source, verify_ssl))
target_service = create_new_service(source_service.show_service, destination, system_name)
context = create_context(source_service, target_service)
tasks = [
Tasks::CopyServiceProxyTask.new(context),
Tasks::CopyMethodsTask.new(context),
Tasks::CopyMetricsTask.new(context),
Tasks::CopyApplicationPlansTask.new(context),
Tasks::CopyLimitsTask.new(context),
Tasks::DestroyMappingRulesTask.new(context),
Tasks::CopyMappingRulesTask.new(context)
]
tasks.each(&:call)
end

private

# Returns new hash object with not nil valid params
def filter_params(valid_params, source)
valid_params.each_with_object({}) do |key, target|
target[key] = source[key] unless source[key].nil?
end
def create_context(source, target)
{
source: source,
target: target
}
end

def copy_service_params(original, system_name)
service_params = filter_params(Commands.service_valid_params, original)
service_params.tap do |hash|
hash['system_name'] = system_name if system_name
end
end

def copy_service(service_id, source, destination, system_name)
require '3scale/api'

source_client = ThreeScale::API.new(
endpoint: endpoint_from_url(source),
provider_key: provider_key_from_url(source),
verify_ssl: verify_ssl
)
client = ThreeScale::API.new(
endpoint: endpoint_from_url(destination),
provider_key: provider_key_from_url(destination),
verify_ssl: verify_ssl
)

service = source_client.show_service(service_id)
copy = client.create_service(copy_service_params(service, system_name))

raise "Service has not been saved. Errors: #{copy['errors']}" unless copy['errors'].nil?

service_copy_id = copy.fetch('id')

puts "new service id #{service_copy_id}"

proxy = source_client.show_proxy(service_id)
client.update_proxy(service_copy_id, proxy)
puts "updated proxy of #{service_copy_id} to match the original"

metrics = source_client.list_metrics(service_id)
metrics_copies = client.list_metrics(service_copy_id)

hits = metrics.find{ |metric| metric['system_name'] == 'hits' } or raise 'missing hits metric'
hits_copy = metrics_copies.find{ |metric| metric['system_name'] == 'hits' } or raise 'missing hits metric'

methods = source_client.list_methods(service_id, hits['id'])
methods_copies = client.list_methods(service_copy_id, hits_copy['id'])

puts "original service hits metric #{hits['id']} has #{methods.size} methods"
puts "copied service hits metric #{hits_copy['id']} has #{methods_copies.size} methods"

missing_methods = methods.reject { |method| methods_copies.find{|copy| compare_hashes(method, copy, ['system_name']) } }

puts "creating #{missing_methods.size} missing methods on copied service"

missing_methods.each do |method|
copy = { friendly_name: method['friendly_name'], system_name: method['system_name'] }
client.create_method(service_copy_id, hits_copy['id'], copy)
end

metrics_copies = client.list_metrics(service_copy_id)

puts "original service has #{metrics.size} metrics"
puts "copied service has #{metrics_copies.size} metrics"

missing_metrics = metrics.reject { |metric| metrics_copies.find{|copy| compare_hashes(metric, copy, ['system_name']) } }

missing_metrics.map do |metric|
metric.delete('links')
client.create_metric(service_copy_id, metric)
end

puts "created #{missing_metrics.size} metrics on the copied service"

plans = source_client.list_service_application_plans(service_id)
plan_copies = client.list_service_application_plans(service_copy_id)

puts "original service has #{plans.size} application plans "
puts "copied service has #{plan_copies.size} application plans"

missing_application_plans = plans.reject { |plan| plan_copies.find{|copy| plan.fetch('system_name') == copy.fetch('system_name') } }

puts "copied service missing #{missing_application_plans.size} application plans"

missing_application_plans.each do |plan|
plan.delete('links')
plan.delete('default') # TODO: handle default plan

if plan.delete('custom') # TODO: what to do with custom plans?
puts "skipping custom plan #{plan}"
else
client.create_application_plan(service_copy_id, plan)
end
end

application_plan_mapping = client.list_service_application_plans(service_copy_id).map do |plan_copy|
plan = plans.find{|plan| plan.fetch('system_name') == plan_copy.fetch('system_name') }

[plan['id'], plan_copy['id']]
end

metrics_mapping = client.list_metrics(service_copy_id).map do |copy|
metric = metrics.find{|metric| metric.fetch('system_name') == copy.fetch('system_name') }
metric ||= {}

[metric['id'], copy['id']]
end.to_h

puts "destroying all mapping rules of the copy which have been created by default"
client.list_mapping_rules(service_copy_id).each do |mapping_rule|
client.delete_mapping_rule(service_copy_id, mapping_rule['id'])
end

mapping_rules = source_client.list_mapping_rules(service_id)
mapping_rules_copy = client.list_mapping_rules(service_copy_id)

puts "the original service has #{mapping_rules.size} mapping rules"
puts "the copy has #{mapping_rules_copy.size} mapping rules"

unique_mapping_rules_copy = mapping_rules_copy.dup

missing_mapping_rules = mapping_rules.reject do |mapping_rule|
matching_metric = unique_mapping_rules_copy.find do |copy|
compare_hashes(mapping_rule, copy, %w(pattern http_method delta)) &&
metrics_mapping.fetch(mapping_rule.fetch('metric_id')) == copy.fetch('metric_id')
end

unique_mapping_rules_copy.delete(matching_metric)
end

puts "missing #{missing_mapping_rules.size} mapping rules"

missing_mapping_rules.each do |mapping_rule|
mapping_rule.delete('links')
mapping_rule['metric_id'] = metrics_mapping.fetch(mapping_rule.delete('metric_id'))
client.create_mapping_rule(service_copy_id, mapping_rule)
end
puts "created #{missing_mapping_rules.size} mapping rules"

puts "extra #{unique_mapping_rules_copy.size} mapping rules"
puts unique_mapping_rules_copy.each{|rule| rule.delete('links') }

application_plan_mapping.each do |original_id, copy_id|
limits = source_client.list_application_plan_limits(original_id)
limits_copy = client.list_application_plan_limits(copy_id)

missing_limits = limits.reject { |limit| limits_copy.find{|limit_copy| limit.fetch('period') == limit_copy.fetch('period') } }

missing_limits.each do |limit|
limit.delete('links')
client.create_application_plan_limit(copy_id, metrics_mapping.fetch(limit.fetch('metric_id')), limit)
end
puts "copied application plan #{copy_id} is missing #{missing_limits.size} from the original plan #{original_id}"
end
def create_new_service(service, destination, system_name)
Entities::Service.create(remote: remote(destination, verify_ssl),
service: service,
system_name: system_name)
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/3scale_toolbox/commands/remote_command/remote_add.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def validate_remote_name(name)
def add_remote(remote_name, remote_url)
validate_remote_name remote_name
remote = parse_remote_uri remote_url
validate_remote remote
validate_remote verify_ssl, remote
update_remotes do |remotes|
remotes.tap { |r| r[remote_name] = remote }
end
Expand Down
Loading