From 7e3a1d1cd249c9ef919bb066deee10384d9e70f9 Mon Sep 17 00:00:00 2001 From: Irina Peshinskaya Date: Mon, 12 Nov 2018 01:27:50 +0100 Subject: [PATCH] TT#46187 Use value in "remove" PATCH op as filter Change-Id: Ic04917b1e90750e4517d45082cdab7f7f2bcf534 --- lib/NGCP/Panel/Role/API.pm | 49 +++++++++++++++++++++++++++++++++++- t/api-rest/api-preferences.t | 44 ++++++++++++++++++++++++++++++-- 2 files changed, 90 insertions(+), 3 deletions(-) diff --git a/lib/NGCP/Panel/Role/API.pm b/lib/NGCP/Panel/Role/API.pm index b5e3f8300a..65ae565e85 100644 --- a/lib/NGCP/Panel/Role/API.pm +++ b/lib/NGCP/Panel/Role/API.pm @@ -576,7 +576,7 @@ sub require_valid_patch { my $valid_ops = { 'replace' => { 'path' => 1, 'value' => 1 }, 'copy' => { 'from' => 1, 'path' => 1 }, - 'remove' => { 'path' => 1 }, + 'remove' => { 'path' => 1, 'value' => 0, 'index' => 0 },# 0 means optional 'add' => { 'path' => 1, 'value' => 1, mode => { required => 0, allowed_values => [qw/append/], @@ -811,6 +811,53 @@ sub process_patch_description { } else { push @$patch_diff, map {{"op" => "add", "path" => $op->{path}.'/-', "value" => $_}} ref $op->{value} eq 'ARRAY' ? @{$op->{value}} : ($op->{value}); } + } elsif ($op->{op} eq 'remove' && $op->{value}) { + splice @$patch, $op_iterator, 1; + my $remove_index = $op->{index};#no default value, undefined means "remove all" + my $found_count = 0; + my $removal_done = 0; + my $values_to_remove; + if (ref $op->{value} eq 'ARRAY') { + undef $remove_index;#??? - this is according to AC, but during meeting it sounded different + $values_to_remove = $op->{value}; + } else { + $values_to_remove = [$op->{value}]; + } + my $value_current = JSON::Pointer->get($entity, $op->{path}); + foreach my $value_to_remove (@$values_to_remove) { + #we are not able to request full array removal with exact value + if (ref $value_current eq 'ARRAY') { + for (my $i=0; $i < @$value_current; $i++) { + # 0 if different, 1 if equal + if (compare($value_current->[$i], $value_to_remove)) { + if ( defined $remove_index ) { + if ($found_count == $remove_index) { + #if we want to use patch info to try to make clear changes, we shouldn't use replace + #from the other pov, if we requested 10000 removals, we will have 10000 new op entries + push @$patch_diff, {"op" => "remove", "path" => $op->{path}.'/'.$i }; + $removal_done = 1; + last; + } else { + $found_count++; + } + } else { + push @$patch_diff, {"op" => "remove", "path" => $op->{path}.'/'.$i }; + } + } + } + if ($removal_done) { + last; + } + } else { #current value is not an array + if (compare($value_current, $value_to_remove)) { + push @$patch_diff, {"op" => "remove", "path" => $op->{path} }; + } + } + } + #we went through all the filter values and still didn't find enough elements to satisfy requested index + if ($remove_index && $found_count < $remove_index ) { + die("delete index $remove_index out of bounds"); + } } } push @$patch, @$patch_diff; diff --git a/t/api-rest/api-preferences.t b/t/api-rest/api-preferences.t index 3c3da8d5f8..337c9d71e0 100644 --- a/t/api-rest/api-preferences.t +++ b/t/api-rest/api-preferences.t @@ -45,6 +45,8 @@ my @apis = qw/subscriber domain peeringserver customer profile pbxdevice pbxfiel foreach my $api (@apis){ my $preferences_old; my $preferences_put; + my $preferences_patch; + my $res; my $index = $api.'_id'; my ($preferences) = {'uri' => '/api/'.$api.'preferences/'.$test_machine->DATA_ITEM->{$index}}; (undef, $preferences_old) = $test_machine->check_item_get($preferences->{uri}); @@ -86,7 +88,11 @@ foreach my $api (@apis){ } if($value && 'no_process' ne $value){ if($preference->{max_occur} > 0 ){ - $preferences->{content}->{$preference_name} = 1 < $preference->{max_occur} ? [$value] : $value ; + if ($preference->{max_occur} eq '1') { + $preferences->{content}->{$preference_name} = $value; + } else { + $preferences->{content}->{$preference_name} = [$value]; + } } }else{ #print "Undefined value for preference: $api:$preference_name;\n"; @@ -96,7 +102,41 @@ foreach my $api (@apis){ #(undef, $preferences_put->{content}) = $test_machine->request_put($preferences->{content},$preferences->{uri}); #we don't check read_only flag when update preferences? (undef, $preferences_put->{content}) = $test_machine->check_put2get({data_in=>$preferences->{content},uri=>$preferences->{uri}},undef, { skip_compare => 1 }); - (undef, $preferences_put->{content}) = $test_machine->request_put($preferences_old,$preferences->{uri}); + (undef, $preferences_patch->{content}) = $test_machine->check_patch2get({location => $preferences->{uri}} ); + + if ($api eq 'subscriber') { + diag("test extended patch"); + my $preferences_new; + my $addmulti_value = ['111','222','222','333']; + my $preferences_patch_op = [ + {'op' => 'add', 'path' => '/allowed_clis', value => $addmulti_value, mode => 'append' }, + ]; + ($res, $preferences_put->{content}) = $test_machine->request_patch($preferences_patch_op,$preferences->{uri}); + $test_machine->http_code_msg(200, "check extended patch result: add multi to absent", $res, $preferences_put->{content}); + (undef, $preferences_new->{content}) = $test_machine->check_item_get($preferences->{uri}); + is_deeply([@{$preferences_new->{content}->{allowed_clis}}[-4..-1]], $addmulti_value, "check patched allowed_clis: add multi to absent"); + + $addmulti_value = ['222','222','222','555','666']; + $preferences_patch_op = [ + {'op' => 'add', 'path' => '/allowed_clis', value => $addmulti_value, mode => 'append' }, + ]; + ($res, $preferences_put->{content}) = $test_machine->request_patch($preferences_patch_op,$preferences->{uri}); + $test_machine->http_code_msg(200, "check extended patch result: add multi to existing", $res, $preferences_put->{content}); + (undef, $preferences_new->{content}) = $test_machine->check_item_get($preferences->{uri}); + is_deeply([@{$preferences_new->{content}->{allowed_clis}}[-5..-1]], $addmulti_value, "check patched allowed_clis: add multi to existing"); + + $preferences_patch_op = [ + {'op' => 'remove', 'path' => '/allowed_clis', value => '222', 'index' => 2 }, + ]; + ($res, $preferences_put->{content}) = $test_machine->request_patch($preferences_patch_op,$preferences->{uri}); + $test_machine->http_code_msg(200, "check extended patch result: remove by value", $res, $preferences_put->{content}); + (undef, $preferences_new->{content}) = $test_machine->check_item_get($preferences->{uri}); + is_deeply([@{$preferences_new->{content}->{allowed_clis}}[-8..-1]], ['111','222','222','333','222','222','555','666'], "check patched allowed_clis: remove by value."); + } + + + ($res, $preferences_put->{content}) = $test_machine->request_put($preferences_old,$preferences->{uri}); + $test_machine->http_code_msg(200, "check return old values", $res, $preferences_put->{content}); } $test_machine->clear_test_data_all();