MT#20023 MT#20027 lnp unique number and lnp provider delete checks

+prohibit deletion of lnp providers if numbers are
 still linked to it
+number+provider must be unique
+fixed other panel lnp page validation checks
+db constraints to stand concurrent inserts/updates
+fixup all txn_do die() calls in panel to properly
 display the error
+bulk upload checks by db constraints
+lnp api testcase

Change-Id: I872b19f50d96e6c39c7fd5728b2a16555a397236
changes/38/6538/7
Rene Krenn 9 years ago
parent 6f99aa43d5
commit 2912808d77

@ -100,7 +100,7 @@ sub PATCH :Allow {
last unless $preference;
my $json = $self->get_valid_patch_data(
c => $c,
c => $c,
id => $id,
media_type => 'application/json-patch+json',
);
@ -115,7 +115,7 @@ sub PATCH :Allow {
my $form = $self->get_form($c);
$item = $self->update_item($c, $item, $old_resource, $resource, $form);
last unless $item;
$guard->commit;
if ('minimal' eq $preference) {
@ -156,7 +156,7 @@ sub PUT :Allow {
$item = $self->update_item($c, $item, $old_resource, $resource, $form);
last unless $item;
$guard->commit;
$guard->commit;
if ('minimal' eq $preference) {
$c->response->status(HTTP_NO_CONTENT);
@ -182,6 +182,12 @@ sub DELETE :Allow {
{
my $item = $self->item_by_id($c, $id);
last unless $self->resource_exists($c, lnpcarrier => $item);
my $number_count = $item->lnp_numbers->count;
if ($number_count > 0) {
$c->log->error("failed to delete lnp carrier, there are still $number_count lnp numbers linked to it.");
$self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Failed to delete lnp carrier.");
last;
}
$item->delete;
$guard->commit;

@ -128,7 +128,7 @@ sub GET :Allow {
$hal->resource({
total_count => $total_count,
});
my $response = HTTP::Response->new(HTTP_OK, undef,
my $response = HTTP::Response->new(HTTP_OK, undef,
HTTP::Headers->new($hal->http_headers(skip_links => 1)), $hal->as_json);
$c->response->headers($response->headers);
$c->response->body($response->content);
@ -164,7 +164,7 @@ sub POST :Allow {
my $schema = $c->model('DB');
my $resource;
my $data = $self->get_valid_raw_post_data(
c => $c,
c => $c,
media_type => [qw#application/json text/csv#],
);
last unless $data;
@ -233,27 +233,20 @@ sub POST :Allow {
my $carrier = $c->model('DB')->resultset('lnp_providers')->find($resource->{lnp_provider_id});
unless($carrier) {
$c->log->error("invalid carrier_id '$$resource{lnp_provider_id}'"); # TODO: user, message, trace, ...
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "LNP carrier_id does not exist");
$c->log->error("invalid carrier_id '$$resource{lnp_provider_id}'");
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "lnp carrier_id does not exist");
last;
}
my $item;
=pod
# for now numbers can be inserted duplicated, so don't check
$item = $c->model('DB')->resultset('lnp_numbers')->find({
lnp_provider_id => $resource->{lnp_provider_id},
number => $resource->{number},
});
if($item) {
$c->log->error("lnp number with number '$$resource{number}' already exists for carrier_id '$$resource{lnp_provider_id}'"); # TODO: user, message, trace, ...
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "LNP number with this number already exists for this LNP carrier");
if ($c->model('DB')->resultset('lnp_numbers')->search({
lnp_provider_id => $carrier->id,
number => $resource->{number}
},undef)->count > 0) {
$c->log->error("LNP number '$$resource{number}' already defined for carrier_id '$$resource{lnp_provider_id}'");
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "lnp number already exists for lnp carrier");
last;
}
=cut
my $item;
try {
$item = $c->model('DB')->resultset('lnp_numbers')->create($resource);
} catch($e) {

@ -312,10 +312,10 @@ sub terminate :Chained('base') :PathPart('terminate') :Args(0) {
try {
#todo: putting the profile fetch into a transaction wouldn't help since the count columns a prone to phantom reads...
unless($profile->get_column('contract_cnt') == 0) {
die('Cannnot terminate billing profile that is still used in profile mappings');
die(['Cannnot terminate billing profile that is still used in profile mappings', "showdetails"]);
}
unless($profile->get_column('package_cnt') == 0) {
die('Cannnot terminate billing profile that is still used in profile packages');
die(['Cannnot terminate billing profile that is still used in profile packages', "showdetails"]);
}
$profile->update({
status => 'terminated',

@ -1062,7 +1062,7 @@ sub topup_cash :Chained('base_restricted') :PathPart('balance/topupcash') :Args(
entities => $entities,
err_code => sub {
my ($err) = @_;
die($err);
die([$err, "showdetails"]);
},
);
@ -1154,7 +1154,7 @@ sub topup_voucher :Chained('base_restricted') :PathPart('balance/topupvoucher')
entities => $entities,
err_code => sub {
my ($err) = @_;
die($err);
die([$err, "showdetails"]);
},
);

@ -32,6 +32,9 @@ sub list :Chained('/') :PathPart('lnp') :CaptureArgs(0) {
{ name => "prefix", "search" => 1, "title" => $c->loc("Prefix") },
{ name => "authoritative", "search" => 0, "title" => $c->loc("Authoritative") },
{ name => "skip_rewrite", "search" => 0, "title" => $c->loc("Skip Rewrite") },
#better leave this out for performance reasons:
#{ name => "numbers_count", "search" => 0, "title" => $c->loc("#Numbers"),
# literal_sql=>"select count(n.id) from `billing`.`lnp_numbers` n where n.`lnp_provider_id` = `me`.`id`" },
]);
my $number_rs = $c->model('DB')->resultset('lnp_numbers');
@ -77,7 +80,7 @@ sub carrier_base :Chained('list') :PathPart('carrier') :CaptureArgs(1) {
NGCP::Panel::Utils::Message::error(
c => $c,
data => { id => $carrier_id },
desc => $c->loc('Invalid lnp carrier id detected!'),
desc => $c->loc('Invalid LNP carrier id detected!'),
);
$c->flash(carrier_messages => delete $c->flash->{messages});
$c->response->redirect($c->uri_for());
@ -193,10 +196,20 @@ sub carrier_delete :Chained('carrier_base') :PathPart('delete') :Args(0) {
my ($self, $c) = @_;
my $carrier = $c->stash->{carrier_result};
my $number_count = $carrier->lnp_numbers->count;
if ($number_count > 0) {
NGCP::Panel::Utils::Message::error(
c => $c,
desc => $c->loc("$number_count lnp numbers still linked to LNP carrier."),
);
$c->flash(carrier_messages => delete $c->flash->{messages});
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/lnp'));
return;
}
try {
my $schema = $c->model('DB');
$schema->txn_do(sub {
$carrier->lnp_numbers->delete;
$carrier->delete;
});
NGCP::Panel::Utils::Message::info(
@ -210,7 +223,7 @@ sub carrier_delete :Chained('carrier_base') :PathPart('delete') :Args(0) {
c => $c,
error => $e,
data => $c->stash->{carrier},
desc => $c->loc('Failed to terminate LNP carrier'),
desc => $c->loc('Failed to delete LNP carrier'),
);
$c->flash(carrier_messages => delete $c->flash->{messages});
};
@ -224,7 +237,7 @@ sub number_base :Chained('list') :PathPart('number') :CaptureArgs(1) {
NGCP::Panel::Utils::Message::error(
c => $c,
data => { id => $number_id },
desc => $c->loc('Invalid lnp number id detected!'),
desc => $c->loc('Invalid LNP number id detected!'),
);
$c->flash(number_messages => delete $c->flash->{messages});
$c->response->redirect($c->uri_for());
@ -271,11 +284,35 @@ sub number_edit :Chained('number_base') :PathPart('edit') {
back_uri => $c->req->uri,
);
if($posted && $form->validated) {
$form->values->{lnp_provider_id} = $form->values->{lnp_provider}{id};
delete $form->values->{lnp_provider};
my $carrier = $c->model('DB')->resultset('lnp_providers')->find($form->values->{lnp_provider_id});
unless($carrier) {
NGCP::Panel::Utils::Message::error(
c => $c,
data => { id => $form->values->{lnp_provider_id} },
desc => $c->loc('Invalid LNP provider id detected!'),
);
$c->flash(number_messages => delete $c->flash->{messages});
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/lnp'));
return;
}
if ($c->model('DB')->resultset('lnp_numbers')->search({
lnp_provider_id => $carrier->id,
number => $form->values->{number}
},undef)->count > 0) {
NGCP::Panel::Utils::Message::error(
c => $c,
data => { number => $form->values->{number} },
desc => $c->loc("LNP number '" . $form->values->{number} . "' already defined for LNP provider '" . $carrier->name . "'!"),
);
$c->flash(number_messages => delete $c->flash->{messages});
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/lnp'));
return;
}
try {
my $schema = $c->model('DB');
$schema->txn_do(sub {
$form->values->{lnp_provider_id} = $form->values->{lnp_provider}{id};
delete $form->values->{lnp_provider};
if(length $form->values->{start}) {
$form->values->{start} .= 'T00:00:00';
} else {
@ -287,15 +324,6 @@ sub number_edit :Chained('number_base') :PathPart('edit') {
$form->values->{end} = undef;
}
$form->values->{routing_number} = undef unless(length $form->values->{routing_number});
my $carrier = $c->model('DB')->resultset('lnp_providers')->find($form->values->{lnp_provider_id});
unless($carrier) {
NGCP::Panel::Utils::Message::error(
c => $c,
data => { id => $form->values->{lnp_provider_id} },
desc => $c->loc('Invalid lnp provider id detected!'),
);
$c->flash(number_messages => delete $c->flash->{messages});
}
$c->stash->{number_result}->update($form->values);
});
@ -339,18 +367,33 @@ sub number_create :Chained('list') :PathPart('number_create') :Args(0) {
back_uri => $c->req->uri,
);
if($posted && $form->validated) {
$form->values->{lnp_provider_id} = $form->values->{lnp_provider}{id};
delete $form->values->{lnp_provider};
my $carrier = $c->model('DB')->resultset('lnp_providers')->find($form->values->{lnp_provider_id});
unless($carrier) {
NGCP::Panel::Utils::Message::error(
c => $c,
data => { id => $form->values->{lnp_provider_id} },
desc => $c->loc('Invalid LNP provider id detected!'),
);
$c->flash(number_messages => delete $c->flash->{messages});
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/lnp'));
return;
}
if ($c->model('DB')->resultset('lnp_numbers')->search({
lnp_provider_id => $carrier->id,
number => $form->values->{number}
},undef)->count > 0) {
NGCP::Panel::Utils::Message::error(
c => $c,
data => { number => $form->values->{number} },
desc => $c->loc("LNP number '" . $form->values->{number} . "' already defined for LNP provider '" . $carrier->name . "'!"),
);
$c->flash(number_messages => delete $c->flash->{messages});
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/lnp'));
return;
}
try {
$form->values->{lnp_provider_id} = $form->values->{lnp_provider}{id};
delete $form->values->{lnp_provider};
my $carrier = $c->model('DB')->resultset('lnp_providers')->find($form->values->{lnp_provider_id});
unless($carrier) {
NGCP::Panel::Utils::Message::error(
c => $c,
data => { id => $form->values->{lnp_provider_id} },
desc => $c->loc('Invalid lnp provider id detected!'),
);
$c->flash(number_messages => delete $c->flash->{messages});
}
if(length $form->values->{start}) {
$form->values->{start} .= 'T00:00:00';
} else {
@ -495,4 +538,3 @@ sub numbers_download :Chained('list') :PathPart('download') :Args(0) {
__PACKAGE__->meta->make_immutable;
1;

@ -92,7 +92,7 @@ sub create :Chained('network_list') :PathPart('create') :Args(0) {
'reseller.create' => $c->uri_for('/reseller/create'),
},
back_uri => $c->req->uri,
);
);
if($posted && $form->validated) {
try {
my $reseller_id = ($c->user->is_superuser ? $form->values->{reseller}{id} : $c->user->reseller_id);
@ -108,7 +108,7 @@ sub create :Chained('network_list') :PathPart('create') :Args(0) {
delete $c->session->{created_objects}->{reseller};
$c->session->{created_objects}->{network} = { id => $bn->id };
});
NGCP::Panel::Utils::Message::info(
c => $c,
desc => $c->loc('Billing Network successfully created'),
@ -179,7 +179,7 @@ sub edit :Chained('base') :PathPart('edit') :Args(0) {
try {
$c->model('DB')->schema->txn_do( sub {
$c->stash->{'network_result'}->update({
name => $form->values->{name},
description => $form->values->{description},
@ -192,7 +192,7 @@ sub edit :Chained('base') :PathPart('edit') :Args(0) {
NGCP::Panel::Utils::Message::info(
c => $c,
desc => $c->loc('Billing network successfully updated'),
);
);
} catch ($e) {
NGCP::Panel::Utils::Message::error(
c => $c,
@ -219,10 +219,10 @@ sub terminate :Chained('base') :PathPart('terminate') :Args(0) {
try {
#todo: putting the network fetch into a transaction wouldn't help since the count columns a prone to phantom reads...
unless($network->get_column('contract_cnt') == 0) {
die('Cannnot terminate billing network that is still used in profile mappings');
die(['Cannnot terminate billing network that is still used in profile mappings', "showdetails"]);
}
unless($network->get_column('package_cnt') == 0) {
die('Cannnot terminate billing network that is still used in profile packages');
die(['Cannnot terminate billing network that is still used in profile packages', "showdetails"]);
}
$network->update({
status => 'terminated',

@ -93,7 +93,7 @@ sub create :Chained('package_list') :PathPart('create') :Args(0) {
'reseller.create' => $c->uri_for('/reseller/create'),
},
back_uri => $c->req->uri,
);
);
if($posted && $form->validated) {
try {
$form->values->{reseller_id} = ($c->user->is_superuser ? $form->values->{reseller}{id} : $c->user->reseller_id);
@ -106,16 +106,16 @@ sub create :Chained('package_list') :PathPart('create') :Args(0) {
my @mappings_to_create = ();
push(@mappings_to_create,@{delete $form->values->{initial_profiles}});
push(@mappings_to_create,@{delete $form->values->{underrun_profiles}});
push(@mappings_to_create,@{delete $form->values->{topup_profiles}});
push(@mappings_to_create,@{delete $form->values->{topup_profiles}});
$c->model('DB')->schema->txn_do( sub {
my $profile_package = $c->model('DB')->resultset('profile_packages')->create($form->values);
foreach my $mapping (@mappings_to_create) {
$profile_package->profiles->create($mapping);
$profile_package->profiles->create($mapping);
}
delete $c->session->{created_objects}->{reseller};
$c->session->{created_objects}->{package} = { id => $profile_package->id };
});
NGCP::Panel::Utils::Message::info(
c => $c,
desc => $c->loc('Profile package successfully created'),
@ -129,7 +129,7 @@ sub create :Chained('package_list') :PathPart('create') :Args(0) {
}
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/package'));
}
$c->stash(
close_target => $c->uri_for,
create_flag => 1,
@ -151,7 +151,7 @@ sub base :Chained('/package/package_list') :PathPart('') :CaptureArgs(1) {
$c->detach;
return;
}
my $res = $c->stash->{package_rs}->find($package_id);
unless(defined($res)) {
NGCP::Panel::Utils::Message::error(
@ -162,7 +162,7 @@ sub base :Chained('/package/package_list') :PathPart('') :CaptureArgs(1) {
$c->detach;
return;
}
$c->stash(package => {$res->get_inflated_columns},
initial_profiles => [ map { { $_->get_inflated_columns }; } $res->initial_profiles->all ],
underrun_profiles => [ map { { $_->get_inflated_columns }; } $res->underrun_profiles->all ],
@ -182,7 +182,7 @@ sub edit :Chained('base') :PathPart('edit') :Args(0) {
$params->{reseller}{id} = delete $params->{reseller_id};
foreach(qw/balance_interval timely_duration/){
$params->{$_} = { unit => delete $params->{$_.'_unit'}, value => delete $params->{$_.'_value'} };
}
}
$params = merge($params, $c->session->{created_objects});
$form->process(
posted => $posted,
@ -197,7 +197,7 @@ sub edit :Chained('base') :PathPart('edit') :Args(0) {
'reseller.create' => $c->uri_for('/reseller/create'),
},
back_uri => $c->req->uri,
);
);
if($posted && $form->validated) {
try {
foreach(qw/balance_interval timely_duration/){
@ -208,19 +208,19 @@ sub edit :Chained('base') :PathPart('edit') :Args(0) {
my @mappings_to_create = ();
push(@mappings_to_create,@{delete $form->values->{initial_profiles}});
push(@mappings_to_create,@{delete $form->values->{underrun_profiles}});
push(@mappings_to_create,@{delete $form->values->{topup_profiles}});
push(@mappings_to_create,@{delete $form->values->{topup_profiles}});
$c->model('DB')->schema->txn_do( sub {
my $profile_package = $c->stash->{'package_result'}->update($form->values);
$profile_package->profiles->delete;
$profile_package->profiles->delete;
foreach my $mapping (@mappings_to_create) {
$profile_package->profiles->create($mapping);
$profile_package->profiles->create($mapping);
}
});
NGCP::Panel::Utils::Message::info(
c => $c,
desc => $c->loc('Profile package successfully updated'),
);
);
} catch ($e) {
NGCP::Panel::Utils::Message::error(
c => $c,
@ -228,11 +228,11 @@ sub edit :Chained('base') :PathPart('edit') :Args(0) {
desc => $c->loc('Failed to update profile package'),
);
}
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/package'));
}
$c->stash(
close_target => $c->uri_for,
edit_flag => 1,
@ -247,12 +247,12 @@ sub delete :Chained('base') :PathPart('delete') :Args(0) {
try {
#todo: putting the package fetch into a transaction wouldn't help since the count columns a prone to phantom reads...
unless($package->get_column('contract_cnt') == 0) {
die('Cannnot delete profile package that is still assigned to contracts');
die(['Cannnot delete profile package that is still assigned to contracts', "showdetails"]);
}
unless($package->get_column('voucher_cnt') == 0) {
die('Cannnot delete profile package that is assigned to vouchers');
die(['Cannnot delete profile package that is assigned to vouchers', "showdetails"]);
}
$package->delete;
NGCP::Panel::Utils::Message::info(
c => $c,
@ -294,7 +294,7 @@ sub details_base :Chained('/') :PathPart('package') :CaptureArgs(1) {
my $dispatch_to = '_package_resultset_' . $c->user->roles;
my $package_rs = $self->$dispatch_to($c);
unless($package_id && is_int($package_id)) {
$package_id //= '';
NGCP::Panel::Utils::Message::error(
@ -306,7 +306,7 @@ sub details_base :Chained('/') :PathPart('package') :CaptureArgs(1) {
$c->detach;
return;
}
my $res = $package_rs->find($package_id);
unless(defined($res)) {
NGCP::Panel::Utils::Message::error(
@ -328,8 +328,8 @@ sub details_base :Chained('/') :PathPart('package') :CaptureArgs(1) {
]);
$c->stash->{voucher_dt_columns} = NGCP::Panel::Utils::Datatables::set_columns($c, [
NGCP::Panel::Utils::Voucher::get_datatable_cols($c,1)
]);
]);
$c->stash(package_result => $res);
}

@ -92,19 +92,14 @@ sub update_item {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "LNP carrier_id does not exist");
return;
}
=pod
# for now numbers can be inserted duplicated, so don't check
my $dup_item = $c->model('DB')->resultset('lnp_numbers')->find({
lnp_provider_id => $resource->{lnp_provider_id},
number => $resource->{number},
});
if($dup_item && $dup_item->id != $item->id) {
$c->log->error("lnp number with number '$$resource{number}' already exists for carrier_id '$$resource{lnp_provider_id}'"); # TODO: user, message, trace, ...
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "LNP number with this number already exists for this carrier");
if ($c->model('DB')->resultset('lnp_numbers')->search({
lnp_provider_id => $carrier->id,
number => $resource->{number}
},undef)->count > 0) {
$c->log->error("LNP number '$$resource{number}' already defined for carrier_id '$$resource{lnp_provider_id}'");
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "lnp number already exists for lnp carrier");
return;
}
=cut
$resource->{start} ||= undef;
if($resource->{start} && $resource->{start} =~ /^\d{4}-\d{2}-\d{2}$/) {

@ -0,0 +1,204 @@
use Sipwise::Base;
use Net::Domain qw(hostfqdn);
use LWP::UserAgent;
use JSON qw();
use Test::More;
use warnings;
my $is_local_env = 0;
my $uri = $ENV{CATALYST_SERVER} || ('https://'.hostfqdn.':4443');
my ($netloc) = ($uri =~ m!^https?://(.*)/?.*$!);
my ($ua, $req, $res);
$ua = LWP::UserAgent->new;
$ua->ssl_opts(
verify_hostname => 0,
SSL_verify_mode => 0,
);
my $user = $ENV{API_USER} // 'administrator';
my $pass = $ENV{API_PASS} // 'administrator';
$ua->credentials($netloc, "api_admin_http", $user, $pass);
#$ua->add_handler("request_send", sub {
# my ($request, $ua, $h) = @_;
# print $request->method . ' ' . $request->uri . "\n" . ($request->content ? $request->content . "\n" : '') unless $request->header('authorization');
# return undef;
#});
#$ua->add_handler("response_done", sub {
# my ($response, $ua, $h) = @_;
# print $response->decoded_content . "\n" if $response->code != 401;
# return undef;
#});
my $t = time;
my %carrier_map = ();
my %number_map = ();
{ #regular case
my $carrier1 = _create_lnp_provider();
my $number1 = _create_lnp_number($carrier1, number => '123');
my $number2 = _create_lnp_number($carrier1, number => '456');
_delete_lnp_number($number1);
_delete_lnp_number($number2);
_delete_lnp_provider($carrier1);
}
{ #delete provider with numbers left:
my $carrier1 = _create_lnp_provider();
my $number1 = _create_lnp_number($carrier1, number => '123');
_delete_lnp_provider($carrier1, 500);
}
{ #unique number - insert:
my $carrier1 = _create_lnp_provider();
my $number1 = _create_lnp_number($carrier1, number => '123');
my $number2 = _create_lnp_number($carrier1, number => '123', expected_code => 422);
#_delete_lnp_provider($carrier1, expected_code => 500);
}
{ #unique number - update:
my $carrier1 = _create_lnp_provider();
my $number1 = _create_lnp_number($carrier1, number => '123');
my $number2 = _create_lnp_number($carrier1, number => '1234');
_update_lnp_number($number2, number => '123', expected_code => 422);
}
#todo: multithread insert testcase
sub _create_lnp_number {
my $carrier = shift;
my (%further_opts) = @_;
my $expected_code = delete $further_opts{expected_code} // 201;
$req = HTTP::Request->new('POST', $uri.'/api/lnpnumbers/');
$req->header('Content-Type' => 'application/json');
$req->content(JSON::to_json({
carrier_id => $carrier->{id},
number => 'test'.$t,
%further_opts,
}));
$res = $ua->request($req);
if ($expected_code eq '201') {
is($res->code, 201, "create test lnp number");
$req = HTTP::Request->new('GET', $uri.'/'.$res->header('Location'));
$res = $ua->request($req);
is($res->code, 200, "fetch test lnp number");
my $number = JSON::from_json($res->decoded_content);
$number_map{$carrier->{id}} = $number;
return $number;
} else {
is($res->code, $expected_code, "create test lnp number returns $expected_code");
return undef;
}
}
sub _update_lnp_number {
my $number = shift;
my (%further_opts) = @_;
my $expected_code = delete $further_opts{expected_code} // 200;
my $url = $uri.'/api/lnpnumbers/'.$number->{id};
$req = HTTP::Request->new('PUT', $url);
$req->header('Content-Type' => 'application/json');
$req->header('Prefer' => 'return=representation');
$req->content(JSON::to_json({
%$number,
%further_opts,
}));
$res = $ua->request($req);
if ($expected_code eq '200') {
is($res->code, 200, "update test lnp number");
$number = JSON::from_json($res->decoded_content);
$number_map{$number->{id}} = $number;
return $number;
} else {
is($res->code, $expected_code, "update test lnp number returns $expected_code");
$req = HTTP::Request->new('GET', $url);
$res = $ua->request($req);
is($res->code, 200, "fetch test lnp number");
my $got_number = JSON::from_json($res->decoded_content);
is_deeply($got_number,$number,"lnp number unchanged");
return undef;
}
}
sub _delete_lnp_number {
my ($number,$expected_code) = @_;
$expected_code //= 204;
my $url = $uri.'/api/lnpnumbers/'.$number->{id};
$req = HTTP::Request->new('DELETE', $url);
$res = $ua->request($req);
if ($expected_code eq '204') {
is($res->code, 204, "delete test lnp number");
$req = HTTP::Request->new('GET', $url);
$res = $ua->request($req);
is($res->code, 404, "test lnp number is not found");
return delete $number_map{$number->{id}};
} else {
is($res->code, $expected_code, "create test lnp number returns $expected_code");
$req = HTTP::Request->new('GET', $url);
$res = $ua->request($req);
is($res->code, 200, "test lnp number is still found");
return undef;
}
}
sub _create_lnp_provider {
my (%further_opts) = @_;
my $expected_code = delete $further_opts{expected_code} // 201;
$req = HTTP::Request->new('POST', $uri.'/api/lnpcarriers/');
$req->header('Content-Type' => 'application/json');
$req->content(JSON::to_json({
#skip_rewrite => JSON::false,
name => "test_lnp_carrier_".(scalar keys %carrier_map).'_'.$t,
prefix => 'test'.$t,
%further_opts,
}));
$res = $ua->request($req);
if ($expected_code eq '201') {
is($res->code, 201, "create test lnp carrier");
$req = HTTP::Request->new('GET', $uri.'/'.$res->header('Location'));
$res = $ua->request($req);
is($res->code, 200, "fetch test lnp carrier");
my $carrier = JSON::from_json($res->decoded_content);
$carrier_map{$carrier->{id}} = $carrier;
return $carrier;
} else {
is($res->code, $expected_code, "create test lnp carrier returns $expected_code");
return undef;
}
}
sub _delete_lnp_provider {
my ($carrier,$expected_code) = @_;
$expected_code //= 204;
my $url = $uri.'/api/lnpcarriers/'.$carrier->{id};
$req = HTTP::Request->new('DELETE', $url);
$res = $ua->request($req);
if ($expected_code eq '204') {
is($res->code, 204, "delete test lnp carrier");
$req = HTTP::Request->new('GET', $url);
$res = $ua->request($req);
is($res->code, 404, "test lnp carrier is not found");
return delete $carrier_map{$carrier->{id}};
} else {
is($res->code, $expected_code, "create test lnp carrier returns $expected_code");
$req = HTTP::Request->new('GET', $url);
$res = $ua->request($req);
is($res->code, 200, "test lnp carrier is still found");
return undef;
}
}
done_testing;
Loading…
Cancel
Save