use Sipwise::Base; use Net::Domain qw(hostfqdn); use JSON qw(); use Test::More; use DateTime::Format::ISO8601; use Data::Dumper; use DateTime; use DateTime::TimeZone; #use URI::Escape qw(); use warnings; BEGIN { unshift(@INC,'../../lib'); } use NGCP::Panel::Utils::DateTime qw(); my $is_local_env = 0; my $uri = $ENV{CATALYST_SERVER} || ('https://'.hostfqdn.':4443'); my ($ua, $req, $res); use Test::Collection; $ua = Test::Collection->new()->ua(); #$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 = (); #goto SKIP; { #regular case my $carrier1 = _create_lnp_provider(); my $number1 = _create_lnp_number($carrier1, number => '123'.$t); my $number2 = _create_lnp_number($carrier1, number => '456'.$t); _delete_lnp_number($number1); _delete_lnp_number($number2); _delete_lnp_provider($carrier1); } $t += 1; { #delete provider with numbers left: my $carrier1 = _create_lnp_provider(); my $number1 = _create_lnp_number($carrier1, number => '123'.$t); _delete_lnp_provider($carrier1, 500); } $t += 1; { my $carrier1 = _create_lnp_provider(); my $carrier2 = _create_lnp_provider(); my $number = '123'.$t; _set_time(NGCP::Panel::Utils::DateTime::from_string('2017-04-18 14:00:00')); my $now = NGCP::Panel::Utils::DateTime::current_local(); my $start1 = $now->clone->subtract(days=>1); my $start2 = $now->clone->subtract(days=>2); my $end = $now->clone->add(days=>1); my $number1 = _create_lnp_number($carrier1, number => $number, start => $start1->ymd, end => $end->ymd); my $number2 = _create_lnp_number($carrier2, number => $number, start => $start2->ymd, end => $end->ymd); _check_lnpnumber_history("total history of number $number: ",$number,[ { carrier_id => $carrier2->{id}, start => $start2->ymd, end => $end->ymd }, { carrier_id => $carrier1->{id}, start => $start1->ymd, end => $end->ymd }, ],undef); _check_lnpnumber_history("actual number $number before it was registered at all: ",$number,[ ],$now->clone->subtract(days=>3)); _check_lnpnumber_history("actual number $number after registration for first carrier: ",$number,[ { carrier_id => $carrier1->{id}, }, ],$now->clone->subtract(days=>1)->add(hours=>1)); _check_lnpnumber_history("actual number $number after registration for second carrier: ",$number,[ { carrier_id => $carrier2->{id}, }, ],$now->clone->subtract(days=>2)->add(hours=>1)); _check_lnpnumber_history("actual number $number now: ",$number,[ { carrier_id => $carrier1->{id}, }, ],""); _check_lnpnumber_history("actual number $number beyond/'terminated': ",$number,[ ],$end->clone->add(days => 1)); #23:59 vs 00:00 #_delete_lnp_number($number1); #_delete_lnp_number($number2); #_delete_lnp_provider($carrier1); #_delete_lnp_provider($carrier2); _set_time(); } $t += 1; #SKIP: { my $carrier1 = _create_lnp_provider(); my $carrier2 = _create_lnp_provider(); my $number = '123'.$t; _set_time(NGCP::Panel::Utils::DateTime::from_string('2017-04-18 14:00:00')); my $now = NGCP::Panel::Utils::DateTime::current_local(); my $start1 = $now->clone->subtract(days=>2); my $start2 = $now->clone->subtract(days=>1); my $end = $now->clone->add(days=>5); _terminate_lnp_numbers(undef,500); #empty number _terminate_lnp_numbers($number,404); #not found, all records my $number1 = _create_lnp_number($carrier1, number => $number, start => $start1->ymd, end => $end->ymd); my $number2 = _create_lnp_number($carrier2, number => $number, start => $start2->ymd, end => $end->ymd); _check_lnpnumber_history("number $number: ",$number,[ { carrier_id => $carrier1->{id} }, { carrier_id => $carrier2->{id} }, ],undef); _terminate_lnp_numbers($number,404,$now->clone->add(days=>6)); #not found, actual _terminate_lnp_numbers($number,undef,$start1->clone->add(hours=>1)); #delete actual _check_lnpnumber_history("number $number: ",$number,[ { carrier_id => $carrier1->{id}, end => $start1->ymd }, { carrier_id => $carrier2->{id}, end => $end->ymd }, ],undef); _terminate_lnp_numbers($number); #delete all sleep(2);; #$now = DateTime->now(); #$now->set_time_zone( DateTime::TimeZone->new(name => 'local') ); _check_lnpnumber_history("number $number: ",$number,[ ],""); _check_lnpnumber_history("number $number: ",$number,[ { carrier_id => $carrier1->{id}, end => $start1->ymd }, { carrier_id => $carrier2->{id}, end => $now->ymd }, ],undef); #_delete_lnp_number($number1); #_delete_lnp_number($number2); #_delete_lnp_provider($carrier1); #_delete_lnp_provider($carrier2); _set_time(); } $t += 1; { #unique number - insert: my $carrier1 = _create_lnp_provider(); my $number1 = _create_lnp_number($carrier1, number => '123'.$t); my $number2 = _create_lnp_number($carrier1, number => '123'.$t, expected_code => 201); # allowed again #my $number2 = _create_lnp_number($carrier1, number => '123'.$t, expected_code => 422); #_delete_lnp_provider($carrier1, expected_code => 500); } $t += 1; { #unique number - update: my $carrier1 = _create_lnp_provider(); my $number1 = _create_lnp_number($carrier1, number => '123'.$t); my $number2 = _create_lnp_number($carrier1, number => '1234'.$t); _update_lnp_number($number2, number => '123'.$t, expected_code => 200); # allowed again #_update_lnp_number($number2, number => '123'.$t, expected_code => 422); } 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->header('X-Fake-Clienttime' => _get_fake_clienttime_now()); $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; } } 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('X-Fake-Clienttime' => _get_fake_clienttime_now()); $req->header('Prefer' => 'return=representation'); $req->content(JSON::to_json({ %$number, ## no critic (ProhibitCommaSeparatedStatements) %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; } } sub _delete_lnp_number { my ($number,$expected_code) = @_; $expected_code //= 204; my $url = $uri.'/api/lnpnumbers/'.$number->{id}; $req = HTTP::Request->new('DELETE', $url); $req->header('X-Fake-Clienttime' => _get_fake_clienttime_now()); $res = $ua->request($req); if ($expected_code eq '204') { is($res->code, 204, "delete test lnp number"); $req = HTTP::Request->new('GET', $url); $req->header('X-Fake-Clienttime' => _get_fake_clienttime_now()); $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, "delete test lnp number returns $expected_code"); $req = HTTP::Request->new('GET', $url); $req->header('X-Fake-Clienttime' => _get_fake_clienttime_now()); $res = $ua->request($req); is($res->code, 200, "test lnp number is still found"); return; } } sub _terminate_lnp_numbers { my ($number,$expected_code,$actual) = @_; $expected_code //= 204; my %params = (); if (defined $actual) { my $actual_delete = $actual; eval { $actual_delete = DateTime::Format::ISO8601->parse_datetime($actual); }; $params{actual} = $actual_delete; } if (defined $number) { $params{number} = $number; } my $url = $uri.'/api/lnpnumbers/'._get_query_string(\%params); $req = HTTP::Request->new('DELETE', $url); $req->header('X-Fake-Clienttime' => _get_fake_clienttime_now()); $res = $ua->request($req); if ($expected_code eq '204') { is($res->code, 204, "delete test lnp numbers"); #_check_lnpnumber_history("test lnp numbers are not found: ",$number,[],$actual); } else { is($res->code, $expected_code, "delete test lnp numbers returns $expected_code"); } } 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; } } 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, "delete 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; } } sub _check_lnpnumber_history { my ($label,$number,$expected_lnpnumbers,$actual) = @_; if (defined $actual) { eval { $actual = DateTime::Format::ISO8601->parse_datetime($actual); }; $actual = '&actual=' . $actual; } else { $actual = ''; } if (defined $number) { $number = '&number=' . $number; } else { $number = ''; } my $total_count = (scalar @$expected_lnpnumbers); my $i = 0; my $ok = 1; my @lnpnumbers = (); my @requests = (); my $last_request; $last_request = _req_to_debug($req) if $req; my $nexturi = $uri.'/api/lnpnumbers/?page=1&rows=10&order_by_direction=asc&order_by=start'.$actual.$number; do { $req = HTTP::Request->new('GET',$nexturi); $req->header('X-Fake-Clienttime' => _get_fake_clienttime_now()); $res = $ua->request($req); is($res->code, 200, $label . "fetch lnpnumbers collection page"); push(@requests,_req_to_debug($req)); my $collection = JSON::from_json($res->decoded_content); my $selfuri = $uri . $collection->{_links}->{self}->{href}; my $colluri = URI->new($selfuri); $ok = ok($collection->{total_count} == $total_count, $label . "check 'total_count' of collection") && $ok; #my %q = $colluri->query_form; #ok(exists $q{page} && exists $q{rows}, $label . "check existence of 'page' and 'row' in 'self'"); #my $page = int($q{page}); #my $rows = int($q{rows}); #if($page == 1) { # ok(!exists $collection->{_links}->{prev}->{href}, $label . "check absence of 'prev' on first page"); #} else { # ok(exists $collection->{_links}->{prev}->{href}, $label . "check existence of 'prev'"); #} #if(($collection->{total_count} / $rows) <= $page) { # ok(!exists $collection->{_links}->{next}->{href}, $label . "check absence of 'next' on last page"); #} else { # ok(exists $collection->{_links}->{next}->{href}, $label . "check existence of 'next'"); #} if($collection->{_links}->{next}->{href}) { $nexturi = $uri . $collection->{_links}->{next}->{href}; } else { $nexturi = undef; } # TODO: I'd expect that to be an array ref in any case! #ok(ref $collection->{_links}->{'ngcp:lnpnumbers'} eq "ARRAY", $label . "check if 'ngcp:lnpnumbers' is array"); $collection->{_embedded}->{'ngcp:lnpnumbers'} = [ $collection->{_embedded}->{'ngcp:lnpnumbers'} ] if "HASH" eq ref $collection->{_embedded}->{'ngcp:lnpnumbers'}; my $page_items = {}; foreach my $lnpnumber (@{ $collection->{_embedded}->{'ngcp:lnpnumbers'} }) { #ok(exists $page_items->{$interval->{id}},$label . "check existence of linked item among embedded"); #my $fetched = delete $page_items->{$interval->{id}}; #delete $fetched->{content}; #is_deeply($interval,$fetched,$label . "compare fetched and embedded item deeply"); $ok = _compare_lnpnumber($lnpnumber,$expected_lnpnumbers->[$i],$label) && $ok; delete $lnpnumber->{'_links'}; push(@lnpnumbers,$lnpnumber); $i++ } } while($nexturi); ok($i == $total_count,$label . "check if all expected items are listed"); diag(Dumper({last_request => $last_request, collection_requests => \@requests, result => \@lnpnumbers})) if !$ok; } sub _compare_lnpnumber { my ($got,$expected,$label) = @_; my $ok = 1; if ($expected->{id}) { $ok = is($got->{id},$expected->{id},$label . "check lnpnumber " . $got->{id} . " id") && $ok; } if ($expected->{start}) { $ok = is($got->{start},$expected->{start},$label . "check lnpnumber " . $got->{id} . " start date") && $ok; } if ($expected->{end}) { $ok = is($got->{end},$expected->{end},$label . "check lnpnumber " . $got->{id} . " end date") && $ok; } if ($expected->{number}) { $ok = is($got->{number},$expected->{number},$label . "check lnpnumber " . $got->{id} . " number") && $ok; } if ($expected->{carrier_id}) { $ok = is($got->{carrier_id},$expected->{carrier_id},$label . "check lnpnumber " . $got->{id} . " lnp_provider_id") && $ok; } return $ok; } sub _req_to_debug { my $request = shift; return { request => $request->method . " " . $request->uri, headers => $request->headers }; } sub _get_query_string { my ($filters) = @_; my $query = ''; foreach my $param (keys %$filters) { if (length($query) == 0) { $query .= '?'; } else { $query .= '&'; } #$query .= URI::Escape::uri_escape($param) . '=' . URI::Escape::uri_escape($filters->{$param}); $query .= $param . '=' . $filters->{$param}; } return $query; }; sub _set_time { my ($o) = @_; my $dtf = DateTime::Format::Strptime->new( pattern => '%F %T', ); if (defined $o) { NGCP::Panel::Utils::DateTime::set_fake_time($o); my $now = NGCP::Panel::Utils::DateTime::current_local; diag("applying fake time offset '$o' - current time: " . $dtf->format_datetime($now)); } else { NGCP::Panel::Utils::DateTime::set_fake_time(); my $now = NGCP::Panel::Utils::DateTime::current_local; diag("resetting fake time - current time: " . $dtf->format_datetime($now)); } } sub _get_fake_clienttime_now { #return NGCP::Panel::Utils::DateTime::to_rfc1123_string(NGCP::Panel::Utils::DateTime::current_local); #with rfc1123 there could be a problem if jenkins runner and test host will not have the same (language) locale return NGCP::Panel::Utils::DateTime::to_string(NGCP::Panel::Utils::DateTime::current_local); } done_testing;