From 846656c8a67fb5edf9bb48f8d59a9584a6870493 Mon Sep 17 00:00:00 2001 From: Irina Peshinskaya Date: Thu, 16 Aug 2018 15:28:26 +0200 Subject: [PATCH] TT#42860 Test subscribers profile and profile set management Change-Id: Ideada1fb1433d724dc6fd6e276f96313bdbaa47a --- t/api-rest/api-subscribers.t | 62 +++++++++++++-- t/lib/Test/ApplyPatch.pm | 85 +++++++++++++++++++++ t/lib/Test/Collection.pm | 142 ++++++++++++++++++++++++++++++++++- t/lib/Test/FakeData.pm | 7 ++ 4 files changed, 289 insertions(+), 7 deletions(-) create mode 100644 t/lib/Test/ApplyPatch.pm diff --git a/t/api-rest/api-subscribers.t b/t/api-rest/api-subscribers.t index a16e3a787f..6adc7d4065 100644 --- a/t/api-rest/api-subscribers.t +++ b/t/api-rest/api-subscribers.t @@ -23,8 +23,8 @@ $fake_data->set_data_from_script({ 'data' => { administrative => 0, customer_id => sub { return shift->get_id('customers',@_); }, - primary_number => { ac => 1, cc=> 1, sn => 1 }, - alias_numbers => [ { ac => 11, cc=> 11, sn => 11 } ], + primary_number => { ac => 12, cc=> 12, sn => 12 }, + alias_numbers => [ { ac => 112, cc=> 112, sn => 112 } ], username => 'api_test_username', password => 'api_test_password', webusername => 'api_test_webusername', @@ -47,6 +47,7 @@ $fake_data->set_data_from_script({ pbx_group_ids => [], pbx_groupmember_ids => [], profile_id => sub { return shift->get_id('subscriberprofiles',@_); }, + profile_set_id => sub { return shift->get_id('subscriberprofilesets',@_); }, status => 'active', pbx_hunt_policy => 'parallel', pbx_hunt_timeout => '15', @@ -332,7 +333,22 @@ if($remote_config->{config}->{features}->{cloudpbx}){ $test_machine->runas('admin'); } {#TT#34021 - diag("34021: check subscriberadmin PUT and PATCH. Possible only for pbx subscriberadmin. Access priveleges:".$remote_config->{config}->{acl}->{subscriberadmin}->{subscribers} .";\n"); + my ($res,$content,$req); + diag("34021: check subscriberadmin PUT and PATCH. Possible only for pbx subscriberadmin. Access priveleges:".Dumper($remote_config->{config}->{acl}).";\n"); + + $test_machine->runas('admin'); + + my $resellers = $test_machine->get_collection_hal('resellers','/api/resellers/'); + my $wrong_reseller; + foreach my $reseller (@{$resellers->{collection}}) { + if ($reseller->{content}->{id} ne $fake_data->data->{customers}->{reseller_id}) { + $wrong_reseller = $reseller; + last; + } + } + my $wrong_profile_sets = $fake_data->create( 'subscriberprofilesets', undef, { data => { 'subscriberprofilesets' => { reseller_id => $wrong_reseller->{content}->{id}}}} ); + my $wrong_profiles = $fake_data->create( 'subscriberprofiles', undef, { data => { 'subscriberprofiles' => { profile_set_id => $wrong_profile_sets->[0]->{content}->{id}, name => 'api_test_wrong_reseller_'.time() }}} ); + my $data = clone $test_machine->DATA_ITEM; $data->{administrative} = 1; my $pbxsubscriberadmin = $test_machine->check_create_correct(1, sub { @@ -347,6 +363,7 @@ if($remote_config->{config}->{features}->{cloudpbx}){ $_[0]->{is_pbx_pilot} = ($pilot || $_[1]->{i} > 1)? 0 : 1; delete $_[0]->{alias_numbers}; } )->[0]; + $test_machine->set_subscriber_credentials($pbxsubscriberadmin->{content}); $test_machine->runas('subscriber'); my $subscriber = $test_machine->check_create_correct(1, sub { @@ -360,11 +377,44 @@ if($remote_config->{config}->{features}->{cloudpbx}){ $_[0]->{is_pbx_pilot} = 0; delete $_[0]->{alias_numbers}; } )->[0]; - if ($remote_config->{config}->{privileges}->{subscriberadmin}->{subscribers} =~/write/) { + #if ($remote_config->{config}->{privileges}->{subscriberadmin}->{subscribers} =~/write/) { + if ($remote_config->{config}->{features}->{cloudpbx}) { $test_machine->check_get2put($subscriber,{},$put2get_check_params); - my($res,$content,$req) = $test_machine->request_patch( [ { op => 'replace', path => '/display_name', value => 'patched 34021' } ], $subscriber->{location} ); + + ($res,$content,$req) = $test_machine->request_patch( [ { op => 'replace', path => '/display_name', value => 'patched 34021' } ], $subscriber->{location} ); $test_machine->http_code_msg(200, "Check display_name patch for subscriberadmin", $res, $content); - }else{ + my $pilot_34021 = $test_machine->get_item_hal('subscribers','/api/subscribers/?customer_id='.$subscriber->{content}->{customer_id}.'&'.'is_pbx_pilot=1'); + #print Dumper [$wrong_reseller->{content},$wrong_profile_sets->[0]->{content},$wrong_profiles->[0]->{content}]; + #print Dumper [$subscriber->{content}]; + #subscriberadmin is not supposed to changed profile and profile_set. Subscriberadmin even don't contain these fields. + + ($res,$content,$req) = $test_machine->request_patch( [ { op => 'replace', path => '/profile_set_id', value => $wrong_profile_sets->[0]->{content}->{id} } ], $subscriber->{location} ); + $test_machine->http_code_msg(422, "Check profile_set_id patch for subscriberadmin", $res, $content); + ($res,$content,$req) = $test_machine->request_patch( [ { op => 'replace', path => '/profile_id', value => $wrong_profiles->[0]->{content}->{id} } ], $subscriber->{location} ); + $test_machine->http_code_msg(422, "Check profile_id patch for subscriberadmin", $res, $content); + + #($res,$content,$req) = $test_machine->request_patch( [ { op => 'replace', path => '/alias_numbers', value => [{'cc' => '111','ac' => '222','sn' => '444'.time(),}] } ], $subscriber->{location} ); + #$test_machine->http_code_msg(200, "Check patch alias_numbers not belonging to the pilot for subscriberadmin", $res, $content); + + $test_machine->runas('admin'); + + ($res,$content,$req) = $test_machine->request_patch( [ { op => 'replace', path => '/profile_set_id', value => $wrong_profile_sets->[0]->{content}->{id} } ], $subscriber->{location} ); + $test_machine->http_code_msg(422, "Check incorrect profile_set_id patch for administrator", $res, $content); + + ($res,$content,$req) = $test_machine->request_patch( [ { op => 'replace', path => '/profile_id', value => $wrong_profiles->[0]->{content}->{id} } ], $subscriber->{location} ); + $test_machine->http_code_msg(422, "Check incorrect profile_id patch for administrator", $res, $content); + + ($res,$content,$req) = $test_machine->request_patch( [ { op => 'replace', path => '/profile_set_id', value => $wrong_profile_sets->[0]->{content}->{id} } ], $subscriber->{location} ); + $test_machine->http_code_msg(422, "Check profile_set_id patch for administrator", $res, $content); + + ($res,$content,$req) = $test_machine->request_patch( [ { op => 'replace', path => '/profile_id', value => $wrong_profiles->[0]->{content}->{id} } ], $subscriber->{location} ); + $test_machine->http_code_msg(422, "Check profile_id patch for administrator", $res, $content); + + $test_machine->check_patch2get( [ { op => 'replace', path => '/profile_id', value => $test_machine->DATA_ITEM->{profile_id} } ], $subscriber->{location}, $put2get_check_params ); + + $test_machine->check_patch2get( [ { op => 'replace', path => '/profile_set_id', value => $test_machine->DATA_ITEM->{profile_set_id} } ], $subscriber->{location}, $put2get_check_params ); + + } else { my($res,$content,$req) = $test_machine->request_patch( [ { op => 'replace', path => '/display_name', value => 'patched 34021' } ], $subscriber->{location} ); $test_machine->http_code_msg(403, "Check display_name patch for subscriberadmin", $res, $content, "Read-only resource for authenticated role"); } diff --git a/t/lib/Test/ApplyPatch.pm b/t/lib/Test/ApplyPatch.pm new file mode 100644 index 0000000000..f7fac21ef4 --- /dev/null +++ b/t/lib/Test/ApplyPatch.pm @@ -0,0 +1,85 @@ +package Test::ApplyPatch; + +use strict; +use warnings; +use Exporter qw'import'; + +our @EXPORT = qw//; +our @EXPORT_OK = qw/&apply_patch/; +our %EXPORT_TAGS = ( + DEFAULT => [qw/&apply_patch/], + all => [qw/&apply_patch/] +); + +use JSON qw(); +use JSON::Pointer; +use JSON::Pointer::Exception qw(); +use TryCatch; +use Data::Dumper; + +sub apply_patch { + my ($entity, $patch, $optional_field_code_ref) = @_; + for my $op (@{ $patch }) { + my $coderef = JSON::Pointer->can($op->{op}); + die "invalid op '".$op->{op}."' despite schema validation" unless $coderef; + for ($op->{op}) { + if ('add' eq $_ or 'replace' eq $_) { + try { + $entity = $coderef->('JSON::Pointer', $entity, $op->{path}, $op->{value}); + } catch($pe) { + if (defined $optional_field_code_ref && ref $optional_field_code_ref eq 'CODE') { + if (blessed($pe) && $pe->isa('JSON::Pointer::Exception') && $pe->code == JSON::Pointer::Exception->ERROR_POINTER_REFERENCES_NON_EXISTENT_VALUE) { + &$optional_field_code_ref(substr($op->{path},1),$entity,$op); + $entity = $coderef->('JSON::Pointer', $entity, $op->{path}, $op->{value}); + } + } else { + die($pe); #->rethrow; + } + } + } elsif ('remove' eq $_) { + try { + $entity = $coderef->('JSON::Pointer', $entity, $op->{path}); + } catch($pe) { + if (defined $optional_field_code_ref && ref $optional_field_code_ref eq 'CODE') { + if (blessed $pe && $pe->isa('JSON::Pointer::Exception') && $pe->code == JSON::Pointer::Exception->ERROR_POINTER_REFERENCES_NON_EXISTENT_VALUE) { + &$optional_field_code_ref(substr($op->{path},1),$entity); + $entity = $coderef->('JSON::Pointer', $entity, $op->{path}); + } + } else { + die($pe); #->rethrow; + } + } + } elsif ('move' eq $_ or 'copy' eq $_) { + try { + $entity = $coderef->('JSON::Pointer', $entity, $op->{from}, $op->{path}); + } catch($pe) { + if (defined $optional_field_code_ref && ref $optional_field_code_ref eq 'CODE') { + if (blessed $pe && $pe->isa('JSON::Pointer::Exception') && $pe->code == JSON::Pointer::Exception->ERROR_POINTER_REFERENCES_NON_EXISTENT_VALUE) { + &$optional_field_code_ref(substr($op->{path},1),$entity); + $entity = $coderef->('JSON::Pointer', $entity, $op->{from}, $op->{path}); + } + } else { + die($pe); #->rethrow; + } + } + } elsif ('test' eq $_) { + try { + die "test failed - path: $op->{path} value: $op->{value}\n" + unless $coderef->('JSON::Pointer', $entity, $op->{path}, $op->{value}); + } catch($pe) { + if (defined $optional_field_code_ref && ref $optional_field_code_ref eq 'CODE') { + if (blessed $pe && $pe->isa('JSON::Pointer::Exception') && $pe->code == JSON::Pointer::Exception->ERROR_POINTER_REFERENCES_NON_EXISTENT_VALUE) { + &$optional_field_code_ref(substr($op->{path},1),$entity); + die "test failed - path: $op->{path} value: $op->{value}\n" + unless $coderef->('JSON::Pointer', $entity, $op->{path}, $op->{value}); + } + } else { + die($pe); #->rethrow; + } + } + } + } + } + return $entity; +} +1; \ No newline at end of file diff --git a/t/lib/Test/Collection.pm b/t/lib/Test/Collection.pm index 84d9b612e7..b1770ce981 100644 --- a/t/lib/Test/Collection.pm +++ b/t/lib/Test/Collection.pm @@ -17,6 +17,7 @@ use URI::Escape; use Clone qw/clone/; use File::Basename; use Test::HTTPRequestAsCurl; +use Test::ApplyPatch; use Data::Dumper; use File::Slurp qw/write_file/; use Storable; @@ -35,74 +36,88 @@ has 'ssl_cert' => ( lazy => 1, builder => 'init_ssl_cert', ); + has 'data_cache_file' => ( is => 'ro', isa => 'Str', lazy => 1, default => sub {'/tmp/ngcp-api-test-data-cache';}, ); + has 'cache_data' => ( is => 'ro', isa => 'Bool', lazy => 1, default => $ENV{API_CACHE_FAKE_DATA} // 0, ); + has 'local_test' => ( is => 'rw', isa => 'Str', default => sub {$ENV{LOCAL_TEST} // ''}, ); + has 'DEBUG' => ( is => 'rw', isa => 'Bool', default => 0, ); + has 'DEBUG_ONLY' => ( is => 'rw', isa => 'Bool', default => 0, ); + has 'QUIET_DELETION' => ( is => 'rw', isa => 'Bool', default => 1, ); + has 'ALLOW_EMPTY_COLLECTION' => ( is => 'rw', isa => 'Bool', default => 0, ); + has 'IS_EMPTY_COLLECTION' => ( is => 'rw', isa => 'Bool', default => 0, ); + has 'NO_ITEM_MODULE' => ( is => 'rw', isa => 'Bool', default => 0, ); + has 'catalyst_config' => ( is => 'rw', isa => 'HashRef', lazy => 1, builder => 'init_catalyst_config', ); + has 'panel_config' => ( is => 'rw', isa => 'HashRef', ); + has 'runas_role' => ( is => 'rw', isa => 'Str', default => 'default', ); + has 'ua' => ( is => 'rw', isa => 'LWP::UserAgent', lazy => 1, builder => 'init_ua', ); + has 'base_uri' => ( is => 'rw', isa => 'Str', @@ -113,31 +128,38 @@ has 'base_uri' => ( : $ENV{CATALYST_SERVER} || ('https://'.hostfqdn.':4443'); }, ); + has 'name' => ( is => 'rw', isa => 'Str', ); + has 'subscriber_user' => ( is => 'rw', isa => 'Str', ); + has 'subscriber_pass' => ( is => 'rw', isa => 'Str', ); + has 'reseller_admin_user' => ( is => 'rw', isa => 'Str', ); + has 'reseller_admin_pass' => ( is => 'rw', isa => 'Str', ); + has 'embedded_resources' => ( is => 'rw', isa => 'ArrayRef', default => sub { [] }, ); + has 'methods' => ( is => 'rw', isa => 'HashRef', @@ -152,6 +174,7 @@ has 'methods' => ( }, } }, ); + has 'content_type' => ( is => 'rw', isa => 'HashRef', @@ -166,10 +189,12 @@ has 'DATA_ITEM' => ( is => 'rw', isa => 'Ref', ); + has 'DATA_ITEM_STORE' => ( is => 'rw', isa => 'Ref', ); + after 'DATA_ITEM_STORE' => sub { my $self = shift; if(@_){ @@ -177,49 +202,59 @@ after 'DATA_ITEM_STORE' => sub { $self->form_data_item; } }; + has 'DATA_CREATED' => ( is => 'rw', isa => 'HashRef', builder => 'clear_data_created', ); + has 'KEEP_CREATED' =>( is => 'rw', isa => 'Bool', default => 1, ); + has 'DATA_LOADED' => ( is => 'rw', isa => 'HashRef', default => sub{{}}, ); + has 'URI_CUSTOM' =>( is => 'rw', isa => 'Str', ); + has 'QUERY_PARAMS' =>( is => 'rw', isa => 'Str', default => '', ); + has 'PAGE' =>( is => 'rw', isa => 'Str', default => '1', ); + has 'ROWS' =>( is => 'rw', isa => 'Str', default => '1', ); + has 'NO_COUNT' =>( is => 'rw', isa => 'Str', default => '', ); + has 'URI_CUSTOM_STORE' =>( is => 'rw', isa => 'Str', ); + before 'URI_CUSTOM' => sub { my $self = shift; if(@_){ @@ -230,11 +265,13 @@ before 'URI_CUSTOM' => sub { } } }; + has 'ENCODE_CONTENT' => ( is => 'rw', isa => 'Str', default => 'json', ); + sub set{ my $self = shift; my %params = @_; @@ -245,6 +282,7 @@ sub set{ } return $prev_state; } + sub get_cloned{ my $self = shift; my @params = @_; @@ -254,6 +292,7 @@ sub get_cloned{ } return $state; } + sub init_catalyst_config{ my $self = shift; my $config; @@ -278,10 +317,12 @@ sub init_catalyst_config{ $self->{panel_config} = $config->{file}; return $self->{catalyst_config}; } + sub init_ua { my $self = shift; return $self->_create_ua(1); } + sub _create_ua { my ($self,$init_cert) = @_; my $ua = LWP::UserAgent->new; @@ -348,6 +389,7 @@ sub init_ssl_cert { ) if $ua; return $tmpfilename; } + sub clear_cert { my $self = shift; lock $tmpfilename; @@ -358,6 +400,7 @@ sub clear_cert { delete $self->{ua}; return $self; } + sub ssl_auth_allowed { my $self = shift; my($role) = @_; @@ -434,38 +477,45 @@ sub clear_data_created{ }); return $self->DATA_CREATED; } + sub form_data_item{ my($self, $data_cb, $data_cb_data) = @_; $self->{DATA_ITEM} ||= clone($self->DATA_ITEM_STORE); (defined $data_cb) and $data_cb->($self->DATA_ITEM,$data_cb_data); return $self->DATA_ITEM; } + sub get_id_from_created{ my($self, $created_info) = @_; my $id = $self->get_id_from_location($created_info->{location}); return $id; } + sub get_id_from_location{ my($self, $location) = @_; my $id = $location // ''; $id=~s/.*?\D(\d+)$/$1/gis; return $id; } + sub get_hal_name{ my($self,$name) = @_; $name //= $self->name; return "ngcp:".$name; } + sub restore_uri_custom{ my($self) = @_; $self->URI_CUSTOM($self->URI_CUSTOM_STORE); $self->URI_CUSTOM_STORE(undef); } + sub get_uri_collection{ my($self,$name) = @_; $name //= $self->name; return $self->normalize_uri("/api/".$name.($name ? "/" : "").($self->QUERY_PARAMS ? "?".$self->QUERY_PARAMS : "")); } + sub get_uri_collection_paged{ my($self,$name) = @_; my $uri = $self->get_uri_collection($name); @@ -477,12 +527,14 @@ sub get_uri_get{ $name //= $self->name; return $self->normalize_uri("/api/".$name.($query_string ? '/?' : '/' ).$query_string); } + sub get_uri{ my($self,$add,$name) = @_; $add //= ''; $name //= $self->name; return $self->normalize_uri("/api/".$name.'/'.$add); } + sub get_uri_item{ my($self,$name,$item) = @_; my $resuri; @@ -530,6 +582,7 @@ sub get_item_hal{ } return $resitem; } + sub get_hal_from_collection{ my($self,$list_collection,$name,$number) = @_; $number //= 0; @@ -621,10 +674,12 @@ sub get_collection_hal{ } return $rescollection; } + sub get_created_first{ my($self) = @_; return $self->DATA_CREATED->{FIRST} ? $self->DATA_CREATED->{ALL}->{$self->DATA_CREATED->{FIRST}} : undef; } + sub get_uri_current{ my($self) = @_; $self->URI_CUSTOM and return $self->URI_CUSTOM; @@ -661,6 +716,7 @@ sub encode_content{ #print Dumper ["encode_content.2",$content_res,$content_type_res] ; return ($content_res,$content_type_res); } + sub request{ my($self,$req) = @_; @@ -696,6 +752,7 @@ sub request_process{ my $rescontent = $self->get_response_content($res); return ($res,$rescontent,$req); } + sub get_request_get{ my($self, $uri, $headers) = @_; $headers ||= {}; @@ -706,6 +763,7 @@ sub get_request_get{ } return $req ; } + sub get_request_put{ my($self,$content,$uri) = @_; $uri ||= $self->get_uri_current; @@ -751,6 +809,9 @@ sub request_put{ my($self,$content,$uri) = @_; $uri ||= $self->get_uri_current; my $req = $self->get_request_put( $content, $self->normalize_uri($uri) ); + diag("request_put: uri: ".$req->uri.";"); + diag("request_put: content: ".$req->content.";"); + diag("request_put: content_type: ".$req->header('Content-Type').";"); my $res = $self->request($req); if($res){ my $rescontent = $self->get_response_content($res); @@ -763,6 +824,9 @@ sub request_patch{ $uri ||= $self->get_uri_current; #patch is always a json $req ||= $self->get_request_patch( $self->normalize_uri($uri), $content); + diag("request_patch: uri: ".$req->uri.";"); + diag("request_patch: content: ".$req->content.";"); + diag("request_patch: content_type: ".$req->header('Content-Type').";"); my $res = $self->request($req); if($res){ my $rescontent = $self->get_response_content($res); @@ -863,6 +927,7 @@ sub get_response_content{ #print Dumper $content; return $content; } + sub normalize_uri{ my($self,$uri) = @_; $uri ||= $self->get_uri_current // ''; @@ -885,6 +950,7 @@ sub check_options_collection{ is($res->header('Accept-Post'), "application/hal+json; profile=http://purl.org/sipwise/ngcp-api/#rel-".$self->name, "$self->{name}: check Accept-Post header in options response"); $self->check_methods($res,'collection'); } + sub check_options_item{ my ($self,$uri) = @_; # OPTIONS tests @@ -895,6 +961,7 @@ sub check_options_item{ $self->check_methods($res,'item'); } } + sub check_methods{ my($self, $res, $area) = @_; my $opts = $self->get_response_content($res); @@ -1032,6 +1099,7 @@ sub check_put_content_type_empty{ my($res,$content) = $self->request_process($req); $self->http_code_msg(415, "check put missing content type", $res, $content); } + sub check_put_content_type_wrong{ my($self) = @_; # check if it fails with unsupported content type @@ -1088,6 +1156,7 @@ sub check_patch_prefer_wrong{ my ($res,$content) = $self->request_process($req); $self->http_code_msg(415, "check patch invalid prefer", $res, $content); } + sub check_patch_content_type_empty{ my($self) = @_; my $req = $self->get_request_patch; @@ -1156,6 +1225,7 @@ sub check_patch_opreplace_paramsextra{ $self->http_code_msg(400, "check patch extra fields for op", $res, $content); like($content->{message}, qr/Invalid PATCH key /, "$self->{name}: check patch extra fields for op response"); } + sub check_patch_path_wrong{ my($self) = @_; my ($res,$content,$req) = $self->request_patch( @@ -1177,6 +1247,7 @@ sub check_patch_bundle{ $self->check_patch_opreplace_paramsextra; $self->check_patch_path_wrong; } + sub check_bundle{ my($self) = @_; $self->check_options_collection(); @@ -1212,6 +1283,7 @@ sub check_item_get{ $self->http_code_msg(200, $msg.($msg?": ":"")."fetch uri: $uri", $res); return wantarray ? ($res, $content, $req) : $res; } + sub process_data{ my($self, $data_cb, $data_in, $data_cb_data) = @_; my $data = $data_in || clone($self->DATA_ITEM); @@ -1220,6 +1292,7 @@ sub process_data{ } return $data; } + sub check_item_post{ my($self, $data_cb, $data_in, $data_cb_data) = @_; my $data = $self->process_data($data_cb, $data_in, $data_cb_data); @@ -1290,6 +1363,7 @@ sub clear_test_data_all{ $self->clear_data_created(); return \@uris; } + sub clear_test_data_dependent{ my($self,$uri,$strict) = @_; my $name = $self->name // ''; @@ -1393,6 +1467,67 @@ sub check_put2get{ return ($put_out,$get_out); } +sub check_patch2get{ + my($self, $patch_in, $get_in, $params) = @_; + + my($patch_out, $get_out, $get_uri, $patch_uri); + + $params //= {}; + $get_in //= {}; + $patch_in //= {}; + $patch_uri //= $patch_in->{location} if ref $patch_in eq 'HASH'; + $get_uri //= $patch_uri; + $get_uri = $get_in if !ref $get_in; + $get_uri //= $get_in->{location} if ref $get_in eq 'HASH'; + $patch_uri //= $get_uri; + $get_out->{uri} = $get_uri; + + my $get_ignore_fields; + $get_ignore_fields = $get_in->{ignore_fields} if ref $get_in eq 'HASH'; + $get_ignore_fields //= []; + my $patch_ignore_fields; + $patch_ignore_fields = $patch_in->{ignore_fields} if ref $patch_in eq 'HASH'; + $patch_ignore_fields //= []; + $params->{ignore_fields} //= []; + my $ignore_fields = [@{$params->{ignore_fields}}, @{$get_ignore_fields}, @{$patch_ignore_fields}]; + delete $get_in->{ignore_fields} if ref $get_in eq 'HASH'; + delete $patch_in->{ignore_fields} if ref $patch_in eq 'HASH'; + + $patch_out->{content_in} = ref $patch_in eq 'HASH' && $patch_in->{content} + ? $patch_in->{content} + : ref $patch_in eq 'ARRAY' + ? $patch_in + : [] + ; + (undef, $patch_out->{content_before}) = $self->check_item_get( $patch_uri ); + $patch_out->{content_patched} = Test::ApplyPatch::apply_patch(clone($patch_out->{content_before}),$patch_out->{content_in}); + @{$patch_out}{qw/response content request/} = $self->request_patch( $patch_out->{content_in}, $patch_uri ); + $self->http_code_msg(200, "check_patch2get: check patch successful",$patch_out->{response}, $patch_out->{content}); + + #print Dumper $patch_out; + + @{$get_out}{qw/response content request/} = $self->check_item_get($get_out->{uri}); + delete $patch_out->{content_patched}->{_links}; + delete $patch_out->{content_patched}->{_links}; + delete $get_out->{content}->{_links}; + delete $get_out->{content}->{_embedded}; + my $item_id = delete $get_out->{content}->{id}; + my $item_id_in = delete$patch_out->{content_patched}->{id}; + foreach my $field (@{$ignore_fields}){ + delete $get_out->{content}->{$field}; + delete $patch_out->{content_patched}->{$field}; + } + if('CODE' eq ref $params->{compare_cb}){ + $params->{compare_cb}->($patch_out,$get_out); + } + if(!$params->{skip_compare}){ + is_deeply($get_out->{content}, $patch_out->{content_patched}, "$self->{name}: check_patch2get: check PATCHed item against GETed item"); + } + $get_out->{content}->{id} = $item_id; + $patch_out->{content_patched}->{id} = $item_id_in; + return ($patch_out,$get_out); +} + sub check_post2get{ my($self, $post_in, $get_in, $params) = @_; $get_in //= {}; @@ -1435,6 +1570,7 @@ sub check_post2get{ return ($post_out, $get_out); } + sub put_and_get{ my($self, $put_in, $get_in,$params) = @_; my($put_out,$put_get_out,$get_out); @@ -1473,11 +1609,13 @@ sub hash2params{ my($self,$hash) = @_; return join '&', map {$_.'='.uri_escape($hash->{$_})} keys %{ $hash }; } + sub resource_fill_file{ my($self,$filename,$data) = @_; $data //= 'aaa'; write_file($filename,$data); } + sub resource_clear_file{ my $cmd = "echo -n '' > $_[1]"; print "cmd=$cmd;\n"; @@ -1505,17 +1643,18 @@ sub get_embedded_forcearray{ return 'ARRAY' eq ref $embedded ? $embedded : [ $embedded ]; } - sub uri2location{ my($self,$uri) = @_; $uri=~s/^.*?(\/api\/.*$)/$1/; return $uri; } + sub http_code_msg{ my($self,$code,$message,$res,$content, $check_message) = @_; my $message_res; my $name = $self->{name} // ''; $message //= ''; + #print Dumper [caller]; if ( ($res->code < 300) || ( $code >= 300 ) ) { my $res_message = $res->message // ''; my $content_message = 'HASH' eq ref $content ? $content->{message} // '' : '' ; @@ -1561,6 +1700,7 @@ sub clear_cache{ `$cmd`; } } + sub is_int { my $val = shift; if($val =~ /^[+-]?[0-9]+$/) { diff --git a/t/lib/Test/FakeData.pm b/t/lib/Test/FakeData.pm index a0fa5dccc5..4b9cbb9b69 100644 --- a/t/lib/Test/FakeData.pm +++ b/t/lib/Test/FakeData.pm @@ -732,6 +732,7 @@ sub create_get_id{ sub create{ my($self, $collection_name, $parents_in, $params) = @_; $parents_in //= {}; + $params //= {}; if($parents_in->{$collection_name}){ if($self->data->{$collection_name}->{default}){ $self->data->{$collection_name}->{process_cycled} = {'parents'=>$parents_in}; @@ -743,6 +744,12 @@ sub create{ $self->process($collection_name, $parents_in); #create itself my $data = clone($self->data->{$collection_name}->{data}); + if ( ref $params eq 'HASH' && ref $params->{data} eq 'HASH' && ref $params->{data}->{$collection_name} eq 'HASH' ) { + $data = { %{$data}, %{$params->{data}->{$collection_name}} }; + } + if ( ref $params eq 'HASH' && ref $params->{data_cb} eq 'HASH' && ref $params->{data_cb}->{$collection_name} eq 'CODE') { + $data = $params->{data_cb}->{$collection_name}->($self, $collection_name, $data, $params); + } #$self->test_machine->ssl_cert; my $test_machine = clone $self->test_machine; $test_machine->set(