Adopt tests from vouchers. Suggest to use in vouchers.
Change-Id: Ia157c2c6028a2d2d323fdc1d1d766e6e1f182e56
(cherry picked from commit dd5c984e61)
			
			
				changes/80/1880/16
			
			
		
							parent
							
								
									c7db27fb34
								
							
						
					
					
						commit
						039fd497b5
					
				| @ -1,454 +1,166 @@ | ||||
| #use Sipwise::Base; | ||||
| use strict; | ||||
| 
 | ||||
| #use Moose; | ||||
| use Sipwise::Base; | ||||
| use Test::Collection; | ||||
| use Test::FakeData; | ||||
| use Net::Domain qw(hostfqdn); | ||||
| use LWP::UserAgent; | ||||
| use JSON qw(); | ||||
| use HTTP::Request::Common; | ||||
| use JSON; | ||||
| use Test::More; | ||||
| 
 | ||||
| my $uri = $ENV{CATALYST_SERVER} || ('https://'.hostfqdn.':4443'); | ||||
| 
 | ||||
| my $valid_ssl_client_cert = $ENV{API_SSL_CLIENT_CERT} ||  | ||||
|     "/etc/ngcp-panel/api_ssl/NGCP-API-client-certificate.pem"; | ||||
| my $valid_ssl_client_key = $ENV{API_SSL_CLIENT_KEY} || | ||||
|     $valid_ssl_client_cert; | ||||
| my $ssl_ca_cert = $ENV{API_SSL_CA_CERT} || "/etc/ngcp-panel/api_ssl/api_ca.crt"; | ||||
| 
 | ||||
| my ($ua, $req, $res); | ||||
| $ua = LWP::UserAgent->new; | ||||
| 
 | ||||
| $ua->ssl_opts( | ||||
|     SSL_cert_file => $valid_ssl_client_cert, | ||||
|     SSL_key_file  => $valid_ssl_client_key, | ||||
|     SSL_ca_file   => $ssl_ca_cert, | ||||
| use Data::Dumper; | ||||
| 
 | ||||
| 
 | ||||
| #init test_machine | ||||
| my $fake_data = Test::FakeData->new; | ||||
| $fake_data->set_data_from_script({ | ||||
|     'billingfees' => { | ||||
|         data => { | ||||
|             billing_profile_id      => sub { return shift->get_id('billingprofiles', @_); }, | ||||
|             billing_zone_id         => sub { return shift->get_id('billingzones', @_); }, | ||||
|             destination             => "^1234", | ||||
|             direction               => "out", | ||||
|             onpeak_init_rate        => 1, | ||||
|             onpeak_init_interval    => 60, | ||||
|             onpeak_follow_rate      => 1, | ||||
|             onpeak_follow_interval  => 30, | ||||
|             offpeak_init_rate       => 0.5, | ||||
|             offpeak_init_interval   => 60, | ||||
|             offpeak_follow_rate     => 0.5, | ||||
|             offpeak_follow_interval => 30, | ||||
|         }, | ||||
|         'query' => ['billing_zone_id'], | ||||
|     }, | ||||
| }); | ||||
| my $test_machine = Test::Collection->new( | ||||
|     name => 'billingfees', | ||||
|     embedded => [qw/billingzones billingprofiles/] | ||||
| ); | ||||
| 
 | ||||
| # OPTIONS tests | ||||
| $test_machine->DATA_ITEM_STORE($fake_data->process('billingfees')); | ||||
| $test_machine->methods->{collection}->{allowed} = {map {$_ => 1} qw(GET HEAD OPTIONS POST)}; | ||||
| $test_machine->methods->{item}->{allowed}       = {map {$_ => 1} qw(GET HEAD OPTIONS PUT PATCH DELETE)}; | ||||
| $test_machine->form_data_item( ); | ||||
| # create 3 new field billing fees from DATA_ITEM | ||||
| $test_machine->check_create_correct( 3, sub{ $_[0]->{destination} .= $_[1]->{i} ; } ); | ||||
| $test_machine->check_get2put(  ); | ||||
| $test_machine->check_bundle(); | ||||
| 
 | ||||
| # specific tests | ||||
| 
 | ||||
| # try to create fee without billing_profile_id | ||||
| { | ||||
|     $req = HTTP::Request->new('OPTIONS', $uri.'/api/billingfees/'); | ||||
|     $res = $ua->request($req); | ||||
|     is($res->code, 200, "check options request"); | ||||
|     is($res->header('Accept-Post'), "application/hal+json; profile=http://purl.org/sipwise/ngcp-api/#rel-billingfees", "check Accept-Post header in options response"); | ||||
|     my $opts = JSON::from_json($res->decoded_content); | ||||
|     my @hopts = split /\s*,\s*/, $res->header('Allow'); | ||||
|     ok(exists $opts->{methods} && ref $opts->{methods} eq "ARRAY", "check for valid 'methods' in body"); | ||||
|     foreach my $opt(qw( GET HEAD OPTIONS POST )) { | ||||
|         ok(grep(/^$opt$/, @hopts), "check for existence of '$opt' in Allow header"); | ||||
|         ok(grep(/^$opt$/, @{ $opts->{methods} }), "check for existence of '$opt' in body"); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| my $reseller_id = 1; | ||||
| 
 | ||||
| # first, we need a billing profile | ||||
| $req = HTTP::Request->new('POST', $uri.'/api/billingprofiles/'); | ||||
| $req->header('Content-Type' => 'application/json'); | ||||
| $req->header('Prefer' => 'return=representation'); | ||||
| my $t = time; | ||||
| $req->content(JSON::to_json({ | ||||
|     reseller_id => $reseller_id, | ||||
|     handle => "testapihandle$t", | ||||
|     name => "test api name $t", | ||||
| })); | ||||
| $res = $ua->request($req); | ||||
| is($res->code, 201, "create test billing profile"); | ||||
| my $billing_profile_id = $res->header('Location'); | ||||
| # TODO: get it from body! | ||||
| $billing_profile_id =~ s/^.+\/(\d+)$/$1/; | ||||
| 
 | ||||
| # then, we need a billing zone | ||||
| $req = HTTP::Request->new('POST', $uri.'/api/billingzones/'); | ||||
| $req->header('Content-Type' => 'application/json'); | ||||
| $req->header('Prefer' => 'return=representation'); | ||||
| $req->content(JSON::to_json({ | ||||
|     billing_profile_id => $billing_profile_id, | ||||
|     zone => "testzone", | ||||
|     detail => "test zone from api", | ||||
| })); | ||||
| $res = $ua->request($req); | ||||
| is($res->code, 201, "create test billing zone"); | ||||
| my $billing_zone_id = $res->header('Location'); | ||||
| # TODO: get it from body! | ||||
| $billing_zone_id =~ s/^.+\/(\d+)$/$1/; | ||||
| 
 | ||||
| # collection test | ||||
| my $firstfee = undef; | ||||
| my @allfees = (); | ||||
| { | ||||
|     # create 6 new billing profiles | ||||
|     my %fees = (); | ||||
|     for(my $i = 1; $i <= 6; ++$i) { | ||||
|         $req = HTTP::Request->new('POST', $uri.'/api/billingfees/'); | ||||
|         $req->header('Content-Type' => 'application/json'); | ||||
|         $req->content(JSON::to_json({ | ||||
|             billing_profile_id => $billing_profile_id, | ||||
|             billing_zone_id => $billing_zone_id, | ||||
|             destination => "^1234$i", | ||||
|             direction => "out", | ||||
|             onpeak_init_rate => 1, | ||||
|             onpeak_init_interval => 60, | ||||
|             onpeak_follow_rate => 1, | ||||
|             onpeak_follow_interval => 30, | ||||
|             offpeak_init_rate => 0.5, | ||||
|             offpeak_init_interval => 60, | ||||
|             offpeak_follow_rate => 0.5, | ||||
|             offpeak_follow_interval => 30, | ||||
|         })); | ||||
|         $res = $ua->request($req); | ||||
|         is($res->code, 201, "create test billing fee $i"); | ||||
|         $fees{$res->header('Location')} = 1; | ||||
|         push @allfees, $res->header('Location'); | ||||
|         $firstfee = $res->header('Location') unless $firstfee; | ||||
|     } | ||||
| 
 | ||||
|     # try to create fee without billing_profile_id | ||||
|     $req = HTTP::Request->new('POST', $uri.'/api/billingfees/'); | ||||
|     $req->header('Content-Type' => 'application/json'); | ||||
|     $req->content(JSON::to_json({ | ||||
|         #billing_profile_id => $billing_profile_id, | ||||
|         billing_zone_id => $billing_zone_id, | ||||
|         destination => "^1234", | ||||
|         direction => "out", | ||||
|         onpeak_init_rate => 1, | ||||
|         onpeak_init_interval => 60, | ||||
|         onpeak_follow_rate => 1, | ||||
|         onpeak_follow_interval => 30, | ||||
|         offpeak_init_rate => 0.5, | ||||
|         offpeak_init_interval => 60, | ||||
|         offpeak_follow_rate => 0.5, | ||||
|         offpeak_follow_interval => 30, | ||||
|     })); | ||||
|     $res = $ua->request($req); | ||||
|     is($res->code, 422, "create profile without billing_profile_id"); | ||||
|     my $err = JSON::from_json($res->decoded_content); | ||||
|     my ($res, $err) = $test_machine->request_post(sub{delete $_[0]->{billing_profile_id};}); | ||||
|     is($res->code, 422, "create billing zone without billing_profile_id"); | ||||
|     is($err->{code}, "422", "check error code in body"); | ||||
|     ok($err->{message} =~ /Missing parameter 'billing_profile_id'/, "check error message in body"); | ||||
| 
 | ||||
|     # try to create fee with invalid billing_profile_id | ||||
|     $req = HTTP::Request->new('POST', $uri.'/api/billingfees/'); | ||||
|     $req->header('Content-Type' => 'application/json'); | ||||
|     $req->content(JSON::to_json({ | ||||
|         billing_profile_id => 99999, | ||||
|         billing_zone_id => $billing_zone_id, | ||||
|         destination => "^1234", | ||||
|         direction => "out", | ||||
|         onpeak_init_rate => 1, | ||||
|         onpeak_init_interval => 60, | ||||
|         onpeak_follow_rate => 1, | ||||
|         onpeak_follow_interval => 30, | ||||
|         offpeak_init_rate => 0.5, | ||||
|         offpeak_init_interval => 60, | ||||
|         offpeak_follow_rate => 0.5, | ||||
|         offpeak_follow_interval => 30, | ||||
|     })); | ||||
|     $res = $ua->request($req); | ||||
|     is($res->code, 422, "create profile with invalid billing_profile_id"); | ||||
|     $err = JSON::from_json($res->decoded_content); | ||||
| } | ||||
| # try to create fee with invalid billing_profile_id | ||||
| { | ||||
|     my ($res, $err) = $test_machine->request_post(sub{$_[0]->{billing_profile_id} = 99999;}); | ||||
|     is($res->code, 422, "create billing zone with invalid billing_profile_id"); | ||||
|     is($err->{code}, "422", "check error code in body"); | ||||
|     ok($err->{message} =~ /Invalid 'billing_profile_id'/, "check error message in body"); | ||||
| 
 | ||||
|     # try to create fee with missing billing_zone_id | ||||
|     $req = HTTP::Request->new('POST', $uri.'/api/billingfees/'); | ||||
|     $req->header('Content-Type' => 'application/json'); | ||||
|     $req->content(JSON::to_json({ | ||||
|         billing_profile_id => $billing_profile_id, | ||||
|         #billing_zone_id => $billing_zone_id, | ||||
|         destination => "^1234", | ||||
|         direction => "out", | ||||
|         onpeak_init_rate => 1, | ||||
|         onpeak_init_interval => 60, | ||||
|         onpeak_follow_rate => 1, | ||||
|         onpeak_follow_interval => 30, | ||||
|         offpeak_init_rate => 0.5, | ||||
|         offpeak_init_interval => 60, | ||||
|         offpeak_follow_rate => 0.5, | ||||
|         offpeak_follow_interval => 30, | ||||
|     })); | ||||
|     $res = $ua->request($req); | ||||
|     is($res->code, 422, "create profile without billing_zone_id"); | ||||
|     $err = JSON::from_json($res->decoded_content); | ||||
| } | ||||
| # try to create fee without billing_zone_id | ||||
| { | ||||
|     my ($res, $err) = $test_machine->request_post(sub{delete $_[0]->{billing_zone_id};}); | ||||
|     is($res->code, 422, "create billing zone without billing_zone_id"); | ||||
|     is($err->{code}, "422", "check error code in body"); | ||||
|     ok($err->{message} =~ /Invalid 'billing_zone_id'/, "check error message in body"); | ||||
| 
 | ||||
|     # try to create fee with invalid billing_zone_id | ||||
|     $req = HTTP::Request->new('POST', $uri.'/api/billingfees/'); | ||||
|     $req->header('Content-Type' => 'application/json'); | ||||
|     $req->content(JSON::to_json({ | ||||
|         billing_profile_id => $billing_profile_id, | ||||
|         billing_zone_id => 99999, | ||||
|         destination => "^1234", | ||||
|         direction => "out", | ||||
|         onpeak_init_rate => 1, | ||||
|         onpeak_init_interval => 60, | ||||
|         onpeak_follow_rate => 1, | ||||
|         onpeak_follow_interval => 30, | ||||
|         offpeak_init_rate => 0.5, | ||||
|         offpeak_init_interval => 60, | ||||
|         offpeak_follow_rate => 0.5, | ||||
|         offpeak_follow_interval => 30, | ||||
|     })); | ||||
|     $res = $ua->request($req); | ||||
|     is($res->code, 422, "create profile without billing_profile_id"); | ||||
|     $err = JSON::from_json($res->decoded_content); | ||||
| } | ||||
| # try to create fee with invalid billing_zone_id | ||||
| { | ||||
|     my ($res, $err) = $test_machine->request_post(sub{$_[0]->{billing_zone_id} = 99999;}); | ||||
|     is($res->code, 422, "create billing zone with invalid billing_zone_id"); | ||||
|     is($err->{code}, "422", "check error code in body"); | ||||
|     ok($err->{message} =~ /Invalid 'billing_zone_id'/, "check error message in body"); | ||||
| 
 | ||||
|     # TODO: check for wrong values in rates, prepaid etc | ||||
| 
 | ||||
|     # iterate over fees collection to check next/prev links and status | ||||
|     my $nexturi = $uri.'/api/billingfees/?page=1&rows=5'; | ||||
|     do { | ||||
|         $res = $ua->get($nexturi); | ||||
|         is($res->code, 200, "fetch fees page"); | ||||
|         my $collection = JSON::from_json($res->decoded_content); | ||||
|         my $selfuri = $uri . $collection->{_links}->{self}->{href}; | ||||
|         is($selfuri, $nexturi, "check _links.self.href of collection"); | ||||
|         my $colluri = URI->new($selfuri); | ||||
| 
 | ||||
|         ok($collection->{total_count} > 0, "check 'total_count' of collection"); | ||||
| 
 | ||||
|         my %q = $colluri->query_form; | ||||
|         ok(exists $q{page} && exists $q{rows}, "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}, "check absence of 'prev' on first page"); | ||||
|         } else { | ||||
|             ok(exists $collection->{_links}->{prev}->{href}, "check existence of 'prev'"); | ||||
|         } | ||||
|         if(($collection->{total_count} / $rows) <= $page) { | ||||
|             ok(!exists $collection->{_links}->{next}->{href}, "check absence of 'next' on last page"); | ||||
|         } else { | ||||
|             ok(exists $collection->{_links}->{next}->{href}, "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:billingfees'} eq "ARRAY" || | ||||
|             ref $collection->{_links}->{'ngcp:billingfees'} eq "HASH"), "check if 'ngcp:billingfees' is array/hash-ref"); | ||||
| 
 | ||||
|         # remove any entry we find in the collection for later check | ||||
|         if(ref $collection->{_links}->{'ngcp:billingfees'} eq "HASH") { | ||||
|             ok(exists $collection->{_embedded}->{'ngcp:billingfees'}->{_links}->{'ngcp:billingprofiles'}, "check presence of ngcp:billingprofiles relation"); | ||||
|             ok(exists $collection->{_embedded}->{'ngcp:billingfees'}->{_links}->{'ngcp:billingzones'}, "check presence of ngcp:billingzones relation"); | ||||
|             delete $fees{$collection->{_links}->{'ngcp:billingfees'}->{href}}; | ||||
|         } else { | ||||
|             foreach my $c(@{ $collection->{_links}->{'ngcp:billingfees'} }) { | ||||
|                 delete $fees{$c->{href}}; | ||||
|             } | ||||
|             foreach my $c(@{ $collection->{_embedded}->{'ngcp:billingfees'} }) { | ||||
|                 ok(exists $c->{_links}->{'ngcp:billingprofiles'}, "check presence of ngcp:billingprofiles relation"); | ||||
|                 ok(exists $c->{_links}->{'ngcp:billingzones'}, "check presence of ngcp:billingzones relation"); | ||||
| 
 | ||||
|                 delete $fees{$c->{_links}->{self}->{href}}; | ||||
|             } | ||||
|         } | ||||
|               | ||||
|     } while($nexturi); | ||||
| 
 | ||||
|     is(scalar(keys %fees), 0, "check if all test billing fees have been found"); | ||||
| 
 | ||||
|     # try to create fee with implicit zone which already exists | ||||
|     $req = HTTP::Request->new('POST', $uri.'/api/billingfees/'); | ||||
|     $req->header('Content-Type' => 'application/json'); | ||||
|     $req->content(JSON::to_json({ | ||||
|         billing_profile_id => $billing_profile_id, | ||||
|         billing_zone_zone => 'testzone', | ||||
|         billing_zone_detail => 'test zone from api', | ||||
|         destination => "^1234", | ||||
|         direction => "out", | ||||
|         onpeak_init_rate => 1, | ||||
|         onpeak_init_interval => 60, | ||||
|         onpeak_follow_rate => 1, | ||||
|         onpeak_follow_interval => 30, | ||||
|         offpeak_init_rate => 0.5, | ||||
|         offpeak_init_interval => 60, | ||||
|         offpeak_follow_rate => 0.5, | ||||
|         offpeak_follow_interval => 30, | ||||
|     })); | ||||
|     $res = $ua->request($req); | ||||
| } | ||||
| # try to create fee with implicit zone which already exists | ||||
| { | ||||
|     my $t = time; | ||||
|     my ($res, $err) = $test_machine->request_post(sub{ | ||||
|         delete $_[0]->{billing_zone_id}; | ||||
|         $_[0]->{billing_zone_zone} = 'apitestzone'; | ||||
|         $_[0]->{billing_zone_detail} = 'api_test zone'; | ||||
|         $_[0]->{destination} = "^".$t; | ||||
|     }); | ||||
|     is($res->code, 201, "create profile fee with existing implicit zone"); | ||||
|     $req = HTTP::Request->new('GET', $uri.$res->header('Location')); | ||||
|     $res = $ua->request($req); | ||||
|     my($z_fee,$req); | ||||
|     ($res, $z_fee, $req) = $test_machine->request_get($test_machine->base_uri.$res->header('Location')); | ||||
|     is($res->code, 200, "fetch profile fee with existing implicit zone"); | ||||
|     my $z_fee = JSON::from_json($res->decoded_content); | ||||
|     ok(exists $z_fee->{billing_zone_id} && $z_fee->{billing_zone_id} == $billing_zone_id, "check if implicit zone returns the correct zone id"); | ||||
|      | ||||
|     $req = HTTP::Request->new('DELETE', $uri.$z_fee->{_links}->{'self'}->{href}); | ||||
|     $res = $ua->request($req); | ||||
|     is($res->code, 204, "delete fee of existing implicit zone"); | ||||
| 
 | ||||
|     # try to create fee with implicit zone which doesn't exist yet | ||||
|     ok(exists $z_fee->{billing_zone_id} && $z_fee->{billing_zone_id} == $test_machine->DATA_ITEM->{billing_zone_id}, "check if implicit zone returns the correct zone id"); | ||||
| } | ||||
| # try to create fee with implicit zone which doesn't exist yet | ||||
| { | ||||
|     my $t = time; | ||||
|     $req = HTTP::Request->new('POST', $uri.'/api/billingfees/'); | ||||
|     $req->header('Content-Type' => 'application/json'); | ||||
|     $req->content(JSON::to_json({ | ||||
|         billing_profile_id => $billing_profile_id, | ||||
|         billing_zone_zone => 'testzone new'.$t, | ||||
|         billing_zone_detail => 'test zone from api new'.$t, | ||||
|         destination => "^1234", | ||||
|         direction => "out", | ||||
|         onpeak_init_rate => 1, | ||||
|         onpeak_init_interval => 60, | ||||
|         onpeak_follow_rate => 1, | ||||
|         onpeak_follow_interval => 30, | ||||
|         offpeak_init_rate => 0.5, | ||||
|         offpeak_init_interval => 60, | ||||
|         offpeak_follow_rate => 0.5, | ||||
|         offpeak_follow_interval => 30, | ||||
|     })); | ||||
|     $res = $ua->request($req); | ||||
|     my ($res, $err) = $test_machine->request_post(sub{ | ||||
|         delete $_[0]->{billing_zone_id}; | ||||
|         $_[0]->{billing_zone_zone} = 'apitestzone'.$t; | ||||
|         $_[0]->{billing_zone_detail} = 'api_test zone'.$t; | ||||
|         $_[0]->{destination} = "^".$t; | ||||
|     }); | ||||
|     is($res->code, 201, "create profile fee with new implicit zone"); | ||||
|     $req = HTTP::Request->new('GET', $uri.$res->header('Location')); | ||||
|     $res = $ua->request($req); | ||||
|     my($z_fee, $req, $content); | ||||
|     ($res, $z_fee, $req) = $test_machine->request_get($test_machine->base_uri.$res->header('Location')); | ||||
|     is($res->code, 200, "fetch profile fee with new implicit zone"); | ||||
|     $z_fee = JSON::from_json($res->decoded_content); | ||||
|     ok(exists $z_fee->{billing_zone_id} && $z_fee->{billing_zone_id} > $billing_zone_id, "check if implicit zone returns a new zone id"); | ||||
|     ok(exists $z_fee->{billing_zone_id} && $z_fee->{billing_zone_id} > $test_machine->DATA_ITEM->{billing_zone_id}, "check if implicit zone returns a new zone id"); | ||||
| 
 | ||||
|     $req = HTTP::Request->new('DELETE', $uri.$z_fee->{_links}->{'ngcp:billingzones'}->{href}); | ||||
|     $res = $ua->request($req); | ||||
|     ($req,$res,$content) = $test_machine->request_delete($test_machine->base_uri.$z_fee->{_links}->{'ngcp:billingzones'}->{href}); | ||||
|     is($res->code, 204, "delete new implicit zone"); | ||||
| 
 | ||||
|     $req = HTTP::Request->new('GET', $uri.$z_fee->{_links}->{'self'}->{href}); | ||||
|     $res = $ua->request($req); | ||||
|     is($res->code, 404, "check if fee is deleted when zone is deleted"); | ||||
|     ($res) = $test_machine->request_get($test_machine->base_uri.$z_fee->{_links}->{'self'}->{href}); | ||||
|     is($res->code, 404, "check if fee is deleted when zone is deleted");     | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| # test fee item | ||||
| { | ||||
|     $req = HTTP::Request->new('OPTIONS', $uri.'/'.$firstfee); | ||||
|     $res = $ua->request($req); | ||||
|     is($res->code, 200, "check options on item"); | ||||
|     my @hopts = split /\s*,\s*/, $res->header('Allow'); | ||||
|     my $opts = JSON::from_json($res->decoded_content); | ||||
|     ok(exists $opts->{methods} && ref $opts->{methods} eq "ARRAY", "check for valid 'methods' in body"); | ||||
|     foreach my $opt(qw( GET HEAD OPTIONS PUT PATCH DELETE )) { | ||||
|         ok(grep(/^$opt$/, @hopts), "check for existence of '$opt' in Allow header"); | ||||
|         ok(grep(/^$opt$/, @{ $opts->{methods} }), "check for existence of '$opt' in body"); | ||||
|     } | ||||
|     foreach my $opt(qw( POST )) { | ||||
|         ok(!grep(/^$opt$/, @hopts), "check for absence of '$opt' in Allow header"); | ||||
|         ok(!grep(/^$opt$/, @{ $opts->{methods} }), "check for absence of '$opt' in body"); | ||||
|     } | ||||
| 
 | ||||
|     $req = HTTP::Request->new('GET', $uri.'/'.$firstfee); | ||||
|     $res = $ua->request($req); | ||||
|     is($res->code, 200, "fetch one fee item"); | ||||
|     my $fee = JSON::from_json($res->decoded_content); | ||||
|     ok(exists $fee->{billing_profile_id} && $fee->{billing_profile_id} == $billing_profile_id, "check existence of billing_profile_id"); | ||||
|     ok(exists $fee->{billing_zone_id} && $fee->{billing_zone_id} == $billing_zone_id, "check existence of billing_zone_id"); | ||||
|     ok(exists $fee->{direction} && $fee->{direction} =~ /^(in|out)$/ , "check existence of direction"); | ||||
|     ok(exists $fee->{source} && length($fee->{source}) > 0, "check existence of source"); | ||||
|     ok(exists $fee->{destination} && length($fee->{destination}) > 0, "check existence of destination"); | ||||
|      | ||||
|     # PUT same result again | ||||
|     my $old_fee = { %$fee }; | ||||
|     delete $fee->{_links}; | ||||
|     delete $fee->{_embedded}; | ||||
|     $req = HTTP::Request->new('PUT', $uri.'/'.$firstfee); | ||||
| 
 | ||||
|     # check if it fails without content type | ||||
|     $req->remove_header('Content-Type'); | ||||
|     $req->header('Prefer' => "return=minimal"); | ||||
|     $res = $ua->request($req); | ||||
|     is($res->code, 415, "check put missing content type"); | ||||
| 
 | ||||
|     # check if it fails with unsupported content type | ||||
|     $req->header('Content-Type' => 'application/xxx'); | ||||
|     $res = $ua->request($req); | ||||
|     is($res->code, 415, "check put invalid content type"); | ||||
| 
 | ||||
|     $req->remove_header('Content-Type'); | ||||
|     $req->header('Content-Type' => 'application/json'); | ||||
| 
 | ||||
|     # check if it fails with invalid Prefer | ||||
|     $req->header('Prefer' => "return=invalid"); | ||||
|     $res = $ua->request($req); | ||||
|     is($res->code, 400, "check put invalid prefer"); | ||||
| 
 | ||||
|     $req->remove_header('Prefer'); | ||||
|     $req->header('Prefer' => "return=representation"); | ||||
| 
 | ||||
|     # check if it fails with missing body | ||||
|     $res = $ua->request($req); | ||||
|     is($res->code, 400, "check put no body"); | ||||
| 
 | ||||
|     # check if put is ok | ||||
|     $req->content(JSON::to_json($fee)); | ||||
|     $res = $ua->request($req); | ||||
|     is($res->code, 200, "check put successful"); | ||||
| 
 | ||||
|     my $new_fee = JSON::from_json($res->decoded_content); | ||||
|     is_deeply($old_fee, $new_fee, "check put if unmodified put returns the same"); | ||||
| 
 | ||||
|     # check if we have the proper links | ||||
|     ok(exists $new_fee->{_links}->{'ngcp:billingprofiles'}, "check put presence of ngcp:billingprofiles relation"); | ||||
|     ok(exists $new_fee->{_links}->{'ngcp:billingzones'}, "check put presence of ngcp:billingzones relation"); | ||||
| 
 | ||||
|     $req = HTTP::Request->new('PATCH', $uri.'/'.$firstfee); | ||||
|     $req->header('Prefer' => 'return=representation'); | ||||
|     $req->header('Content-Type' => 'application/json-patch+json'); | ||||
|     $req->content(JSON::to_json( | ||||
|         [ { op => 'replace', path => '/direction', value => 'in' } ] | ||||
|     )); | ||||
|     $res = $ua->request($req); | ||||
|     is($res->code, 200, "check patched fee item"); | ||||
|     my $mod_fee = JSON::from_json($res->decoded_content); | ||||
|     my (undef, $item_first_get) = $test_machine->check_item_get; | ||||
|     ok(exists $item_first_get->{billing_profile_id} && $item_first_get->{billing_profile_id} == $test_machine->DATA_ITEM->{billing_profile_id}, "check existence of billing_profile_id"); | ||||
|     ok(exists $item_first_get->{billing_zone_id}    && $item_first_get->{billing_zone_id} == $test_machine->DATA_ITEM->{billing_zone_id}, "check existence of billing_zone_id"); | ||||
|     ok(exists $item_first_get->{direction}          && $item_first_get->{direction} =~ /^(in|out)$/ , "check existence of direction"); | ||||
|     ok(exists $item_first_get->{source}             && length($item_first_get->{source}) > 0, "check existence of source"); | ||||
|     ok(exists $item_first_get->{destination}        && length($item_first_get->{destination}) > 0, "check existence of destination"); | ||||
| } | ||||
| { | ||||
|     my($res,$item_put,$req) = $test_machine->check_get2put(); | ||||
|     $test_machine->check_embedded($item_put); | ||||
| } | ||||
| { | ||||
|     my $t = time; | ||||
|     my($res,$mod_fee) = $test_machine->check_patch_correct( [ { op => 'replace', path => '/direction', value => 'in' } ] ); | ||||
|     is($mod_fee->{direction}, "in", "check patched replace op"); | ||||
|     is($mod_fee->{_links}->{self}->{href}, $firstfee, "check patched self link"); | ||||
|     is($mod_fee->{_links}->{collection}->{href}, '/api/billingfees/', "check patched collection link"); | ||||
|      | ||||
|     $req->content(JSON::to_json( | ||||
|         [ { op => 'replace', path => '/billing_profile_id', value => undef } ] | ||||
|     )); | ||||
|     $res = $ua->request($req); | ||||
| } | ||||
| { | ||||
|     my($res) = $test_machine->request_patch( [ { op => 'replace', path => '/billing_profile_id', value => undef } ] ); | ||||
|     is($res->code, 422, "check patched undef billing_profile_id"); | ||||
| 
 | ||||
|     $req->content(JSON::to_json( | ||||
|         [ { op => 'replace', path => '/billing_profile_id', value => 99999 } ] | ||||
|     )); | ||||
|     $res = $ua->request($req); | ||||
| } | ||||
| { | ||||
|     my($res) = $test_machine->request_patch( [ { op => 'replace', path => '/billing_profile_id', value => 99999 } ] ); | ||||
|     is($res->code, 422, "check patched invalid billing_profile_id"); | ||||
| 
 | ||||
|     $req->content(JSON::to_json( | ||||
|         [ { op => 'replace', path => '/billing_zone_id', value => undef } ] | ||||
|     )); | ||||
|     $res = $ua->request($req); | ||||
| } | ||||
| { | ||||
|     my($res) = $test_machine->request_patch( [ { op => 'replace', path => '/billing_zone_id', value => undef } ] ); | ||||
|     is($res->code, 422, "check patched undef billing_zone_id"); | ||||
| 
 | ||||
|     $req->content(JSON::to_json( | ||||
|         [ { op => 'replace', path => '/billing_zone_id', value => 99999 } ] | ||||
|     )); | ||||
|     $res = $ua->request($req); | ||||
| } | ||||
| { | ||||
|     my($res) = $test_machine->request_patch( [ { op => 'replace', path => '/billing_zone_id', value => 99999 } ] ); | ||||
|     is($res->code, 422, "check patched invalid billing_zone_id"); | ||||
| } | ||||
| 
 | ||||
| { | ||||
|     my $ff; | ||||
|     foreach my $f(@allfees) { | ||||
|         $req = HTTP::Request->new('DELETE', $uri.'/'.$f); | ||||
|         $res = $ua->request($req); | ||||
|         is($res->code, 204, "check delete of fee"); | ||||
|         $ff = $f unless $ff; | ||||
|     } | ||||
|     $req = HTTP::Request->new('GET', $uri.'/'.$ff); | ||||
|     $res = $ua->request($req); | ||||
|     is($res->code, 404, "check if deleted fee is really gone"); | ||||
| $test_machine->clear_test_data_all(); | ||||
| 
 | ||||
|     $req = HTTP::Request->new('DELETE', $uri.'/api/billingzones/'.$billing_zone_id); | ||||
|     $res = $ua->request($req); | ||||
| { | ||||
|     my $uri = $test_machine->base_uri.'/api/billingzones/'.$test_machine->DATA_ITEM->{billing_zone_id}; | ||||
|     my($req,$res,$content) = $test_machine->request_delete($uri); | ||||
|     is($res->code, 204, "check delete of zone"); | ||||
| 
 | ||||
|     $req = HTTP::Request->new('GET', $uri.'/api/billingzones/'.$billing_zone_id); | ||||
|     $res = $ua->request($req); | ||||
|     ($res, $content, $req) = $test_machine->request_get($uri); | ||||
|     is($res->code, 404, "check if deleted zone is really gone"); | ||||
| } | ||||
| 
 | ||||
| done_testing; | ||||
| #call destructors | ||||
| $fake_data = undef; | ||||
| $test_machine = undef; | ||||
| 
 | ||||
| done_testing; | ||||
| # vim: set tabstop=4 expandtab: | ||||
|  | ||||
| @ -0,0 +1,46 @@ | ||||
| #use Sipwise::Base; | ||||
| use strict; | ||||
| 
 | ||||
| #use Moose; | ||||
| use Sipwise::Base; | ||||
| use Test::Collection; | ||||
| use Test::FakeData; | ||||
| use Net::Domain qw(hostfqdn); | ||||
| use LWP::UserAgent; | ||||
| use HTTP::Request::Common; | ||||
| use JSON; | ||||
| use Test::More; | ||||
| use Data::Dumper; | ||||
| 
 | ||||
| 
 | ||||
| #init test_machine | ||||
| my $test_machine = Test::Collection->new( | ||||
|     name => 'billingzones', | ||||
| ); | ||||
| my $fake_data = Test::FakeData->new; | ||||
| 
 | ||||
| $test_machine->methods->{collection}->{allowed} = {map {$_ => 1} qw(GET HEAD OPTIONS POST)}; | ||||
| $test_machine->methods->{item}->{allowed}       = {map {$_ => 1} qw(GET HEAD OPTIONS PUT PATCH DELETE)}; | ||||
| 
 | ||||
| $fake_data->set_data_from_script({ | ||||
|     'billingzones' => { | ||||
|         data => { | ||||
|             billing_profile_id => sub { return shift->get_id('billingprofiles', @_); }, | ||||
|             zone               => "apitestzone", | ||||
|             detail             => "api_test zone", | ||||
|         }, | ||||
|         'query' => ['zone'], | ||||
|     }, | ||||
| }); | ||||
| 
 | ||||
| $test_machine->DATA_ITEM_STORE($fake_data->process('billingzones')); | ||||
| $test_machine->form_data_item( ); | ||||
| 
 | ||||
| # create 3 new billing zones from DATA_ITEM | ||||
| $test_machine->check_create_correct( 3, sub{ $_[0]->{zone} .= $_[1]->{i} ; } ); | ||||
| $test_machine->check_get2put(  ); | ||||
| $test_machine->check_bundle(); | ||||
| $test_machine->clear_test_data_all(); | ||||
| done_testing; | ||||
| 
 | ||||
| # vim: set tabstop=4 expandtab: | ||||
| @ -1,199 +1,73 @@ | ||||
| #use Sipwise::Base; | ||||
| use strict; | ||||
| 
 | ||||
| #use Moose; | ||||
| use Sipwise::Base; | ||||
| use Net::Domain qw(hostfqdn); | ||||
| use LWP::UserAgent; | ||||
| use JSON qw(); | ||||
| use Test::Collection; | ||||
| use Test::FakeData; | ||||
| use Test::More; | ||||
| use Storable qw(); | ||||
| use Data::Printer; | ||||
| 
 | ||||
| use JSON::PP; | ||||
| use LWP::Debug; | ||||
| 
 | ||||
| BEGIN { | ||||
|     unshift(@INC,'../lib'); | ||||
| } | ||||
| 
 | ||||
| my $json = JSON::PP->new(); | ||||
| $json->allow_blessed(1); | ||||
| $json->convert_blessed(1); | ||||
| 
 | ||||
| my $is_local_env = $ENV{LOCAL_TEST} // 0; | ||||
| my $mysql_sqlstrict = 1; #https://bugtracker.sipwise.com/view.php?id=12565 | ||||
| 
 | ||||
| use Config::General; | ||||
| my $catalyst_config; | ||||
| if ($is_local_env) { | ||||
|     my $panel_config; | ||||
|     for my $path(qw#../ngcp_panel.conf ngcp_panel.conf#) { | ||||
|         if(-f $path) { | ||||
|             $panel_config = $path; | ||||
|             last; | ||||
|         } | ||||
|     } | ||||
|     $panel_config //= '../ngcp_panel.conf'; | ||||
|     $catalyst_config = Config::General->new($panel_config);    | ||||
| } else { | ||||
|     #taken 1:1 from /lib/NGCP/Panel.pm | ||||
|     my $panel_config; | ||||
|     for my $path(qw#/etc/ngcp-panel/ngcp_panel.conf etc/ngcp_panel.conf ngcp_panel.conf#) { | ||||
|         if(-f $path) { | ||||
|             $panel_config = $path; | ||||
|             last; | ||||
|         } | ||||
|     } | ||||
|     $panel_config //= 'ngcp_panel.conf'; | ||||
|     $catalyst_config = Config::General->new($panel_config);    | ||||
| } | ||||
| my %config = $catalyst_config->getall(); | ||||
| 
 | ||||
| my $uri = $ENV{CATALYST_SERVER} || ('https://'.hostfqdn.':4443'); | ||||
| 
 | ||||
| my $valid_ssl_client_cert = $ENV{API_SSL_CLIENT_CERT} ||  | ||||
|     "/etc/ngcp-panel/api_ssl/NGCP-API-client-certificate.pem"; | ||||
| my $valid_ssl_client_key = $ENV{API_SSL_CLIENT_KEY} || | ||||
|     $valid_ssl_client_cert; | ||||
| my $ssl_ca_cert = $ENV{API_SSL_CA_CERT} || "/etc/ngcp-panel/api_ssl/api_ca.crt"; | ||||
| 
 | ||||
| my ($ua, $req, $res); | ||||
| $ua = LWP::UserAgent->new; | ||||
| 
 | ||||
| if ($is_local_env) { | ||||
|     $ua->ssl_opts( | ||||
|         verify_hostname => 0, | ||||
|     ); | ||||
|     my $realm = $uri; $realm =~ s/^https?:\/\///; | ||||
|     $ua->credentials($realm, "api_admin_http", 'administrator', 'administrator'); | ||||
|     #$ua->timeout(500); #useless, need to change the nginx timeout | ||||
| } else { | ||||
|     $ua->ssl_opts( | ||||
|         SSL_cert_file => $valid_ssl_client_cert, | ||||
|         SSL_key_file  => $valid_ssl_client_key, | ||||
|         SSL_ca_file   => $ssl_ca_cert, | ||||
|     );     | ||||
| } | ||||
| 
 | ||||
| my $t = time; | ||||
| my $default_reseller_id = 1; | ||||
| 
 | ||||
| test_voucher(); | ||||
| done_testing(); | ||||
| 
 | ||||
| 
 | ||||
| sub test_voucher { | ||||
|     my $code = 'testcode'.$t; | ||||
|     my $voucher = { | ||||
|         amount => 100, | ||||
|         code => $code, | ||||
|         customer_id => undef, | ||||
|         reseller_id => $default_reseller_id, | ||||
|         valid_until => '2037-01-01 12:00:00', | ||||
|     }; | ||||
|     $req = HTTP::Request->new('POST', $uri.'/api/vouchers/'); | ||||
|     $req->header('Content-Type' => 'application/json'); | ||||
|     $req->content(JSON::to_json($voucher)); | ||||
|     $res = $ua->request($req); | ||||
|     is($res->code, 201, _get_request_test_message("POST test voucher")); | ||||
|     my $voucher_uri = $uri.'/'.$res->header('Location'); | ||||
|     $req = HTTP::Request->new('GET', $voucher_uri); | ||||
|     $res = $ua->request($req); | ||||
|     is($res->code, 200, _get_request_test_message("fetch POSTed test voucher")); | ||||
|     my $post_voucher = JSON::from_json($res->decoded_content); | ||||
|     delete $post_voucher->{_links}; | ||||
|     my $voucher_id = delete $post_voucher->{id}; | ||||
|     is_deeply($voucher, $post_voucher, "check POSTed voucher against fetched"); | ||||
|     $post_voucher->{id} = $voucher_id; | ||||
| 
 | ||||
|     $req = HTTP::Request->new('PUT', $voucher_uri); | ||||
|     $req->header('Content-Type' => 'application/json'); | ||||
|     $req->header('Prefer' => 'return=representation'); | ||||
|     $req->content(JSON::to_json($post_voucher)); | ||||
|     $res = $ua->request($req); | ||||
|     is($res->code, 200, _get_request_test_message("PUT test voucher")); | ||||
|     $req = HTTP::Request->new('GET', $voucher_uri); | ||||
|     $res = $ua->request($req); | ||||
|     is($res->code, 200, _get_request_test_message("fetch PUT test voucher")); | ||||
|     my $put_voucher = JSON::from_json($res->decoded_content); | ||||
|     delete $put_voucher->{_links}; | ||||
|     $voucher_id = delete $put_voucher->{id}; | ||||
|     is_deeply($voucher, $put_voucher, "check PUTed voucher against POSTed voucher"); | ||||
| 
 | ||||
|     $req = HTTP::Request->new('PATCH', $voucher_uri); | ||||
|     $req->header('Content-Type' => 'application/json-patch+json'); | ||||
|     $req->header('Prefer' => 'return=representation'); | ||||
|     $req->content(JSON::to_json([{op=>"replace", path=>"/code", value=>$put_voucher->{code}}])); | ||||
|     $res = $ua->request($req); | ||||
|     is($res->code, 200, _get_request_test_message("PATCH test voucher")); | ||||
|     $req = HTTP::Request->new('GET', $voucher_uri); | ||||
|     $res = $ua->request($req); | ||||
|     is($res->code, 200, _get_request_test_message("fetch PATCH test voucher")); | ||||
|     my $patch_voucher = JSON::from_json($res->decoded_content); | ||||
|     delete $patch_voucher->{_links}; | ||||
|     $voucher_id = delete $patch_voucher->{id}; | ||||
|     is_deeply($voucher, $patch_voucher, "check PATCHed voucher against POSTed voucher"); | ||||
| 
 | ||||
| 
 | ||||
|     $req = HTTP::Request->new('POST', $uri.'/api/vouchers/'); | ||||
|     $req->header('Content-Type' => 'application/json'); | ||||
|     $req->content(JSON::to_json($put_voucher)); | ||||
|     $res = $ua->request($req); | ||||
|     is($res->code, 422, _get_request_test_message("POST same voucher code again")); | ||||
| 
 | ||||
|     $put_voucher->{id} = $voucher_id; | ||||
| 
 | ||||
| use Data::Dumper; | ||||
| 
 | ||||
| 
 | ||||
| #init test_machine | ||||
| my $test_machine = Test::Collection->new( | ||||
|     name => 'vouchers', | ||||
| ); | ||||
| my $fake_data = Test::FakeData->new; | ||||
| 
 | ||||
| $test_machine->methods->{collection}->{allowed} = {map {$_ => 1} qw(GET HEAD OPTIONS POST)}; | ||||
| $test_machine->methods->{item}->{allowed}       = {map {$_ => 1} qw(GET HEAD OPTIONS PUT PATCH DELETE)}; | ||||
| 
 | ||||
| $fake_data->set_data_from_script({ | ||||
|     'vouchers' => { | ||||
|         data => { | ||||
|             amount => 100, | ||||
|             code => 'apitestcode', | ||||
|             customer_id => undef, | ||||
|             reseller_id => sub { return shift->get_id('resellers', @_); },, | ||||
|             valid_until => '2037-01-01 12:00:00', | ||||
|         }, | ||||
|         'query' => ['code'], | ||||
|     }, | ||||
| }); | ||||
| 
 | ||||
| $test_machine->DATA_ITEM_STORE($fake_data->process('vouchers')); | ||||
| $test_machine->form_data_item( ); | ||||
| 
 | ||||
| # create 3 new vouchers from DATA_ITEM | ||||
| $test_machine->check_create_correct( 3, sub{ $_[0]->{code} .= $_[1]->{i} ; } ); | ||||
| $test_machine->check_get2put(); | ||||
| $test_machine->check_bundle(); | ||||
| 
 | ||||
| my $voucher = $test_machine->{DATA_ITEM}; | ||||
| print Dumper $voucher; | ||||
| my $voucher_uri; | ||||
| 
 | ||||
| { | ||||
|     #todo: move request processing results to separate package inside collection, to don't return these chains | ||||
|     my($res_post,$result_item_post,$req_post,$content_post_in,$location_post,$content_get) = $test_machine->check_post2get(); | ||||
|     my($res_put,$result_item_put,$req_put,$item_put_data,$get_res,$result_item_get,$get_req) = $test_machine->check_put2get(undef, undef, $location_post); | ||||
| 
 | ||||
|     $voucher_uri = $location_post; | ||||
|     $voucher = $result_item_get; | ||||
|      | ||||
| #    $req = HTTP::Request->new('PATCH', $billingzone_uri); | ||||
| #    $req->header('Content-Type' => 'application/json-patch+json'); | ||||
| #    $req->header('Prefer' => 'return=representation'); | ||||
| #    $req->content(JSON::to_json( | ||||
| #        [ { op => 'replace', path => '/zone', value => 'AT' } ] | ||||
| #    )); | ||||
| #    $res = $ua->request($req); | ||||
| #    is($res->code, 200, _get_request_test_message("PATCH test billingzone")); | ||||
| #    $req = HTTP::Request->new('GET', $billingzone_uri); | ||||
| #    $res = $ua->request($req); | ||||
| #    is($res->code, 200, _get_request_test_message("fetch PATCHed test billingzone")); | ||||
| #    $billingzone = JSON::from_json($res->decoded_content); | ||||
| 
 | ||||
| 
 | ||||
|     # mysql has an issue with datetime overruns,check for max date | ||||
|     $req = HTTP::Request->new('PATCH', $voucher_uri); | ||||
|     $req->header('Content-Type' => 'application/json-patch+json'); | ||||
|     $req->header('Prefer' => 'return=representation'); | ||||
|     $req->content(JSON::to_json( | ||||
|         [ { op => 'replace', path => '/valid_until', value => '2099-01-01 00:00:00' } ] | ||||
|     )); | ||||
|     $res = $ua->request($req); | ||||
|     is($res->code, 422, _get_request_test_message("PATCH too far valid_until in voucher")); | ||||
| 
 | ||||
|     $req = HTTP::Request->new('DELETE', $voucher_uri); | ||||
|     $res = $ua->request($req); | ||||
|     is($res->code, 204, _get_request_test_message("delete POSTed test voucher")); | ||||
|     $req = HTTP::Request->new('GET', $voucher_uri); | ||||
|     $res = $ua->request($req); | ||||
|     is($res->code, 404, _get_request_test_message("fetch DELETEd test voucher")); | ||||
|     my($res,$result_item,$req) = $test_machine->request_post(undef,$voucher); | ||||
|     $test_machine->http_code_msg(422, "POST same voucher code again", $res, $result_item); | ||||
| } | ||||
| 
 | ||||
| sub _to_json { | ||||
|     return $json->encode(shift); | ||||
| { | ||||
|     my($res,$content) = $test_machine->request_patch(  [ { op => 'replace', path => '/valid_until', value => '2099-01-01 00:00:00' } ] ); | ||||
|     $test_machine->http_code_msg(422, "check patched invalid billing_zone_id",$res,,$content); | ||||
| } | ||||
| 
 | ||||
| sub _from_json { | ||||
|     return $json->decode(shift); | ||||
| } | ||||
| $test_machine->clear_test_data_all(); | ||||
| 
 | ||||
| sub _get_request_test_message { | ||||
|     my ($message) = @_; | ||||
|     my $code = $res->code; | ||||
|     if ($code == 200 || $code == 201 || $code == 204) { | ||||
|         return $message; | ||||
|     } else { | ||||
|         my $error_content = _from_json($res->content); | ||||
|         if (defined $error_content && defined $error_content->{message}) { | ||||
|             return $message . ' (' . $res->message . ': ' . $error_content->{message} . ')'; | ||||
|         } else { | ||||
|             return $message . ' (' . $res->message . ')'; | ||||
|         } | ||||
|     } | ||||
| { | ||||
|     my $uri = $test_machine->get_uri($voucher->{id}); | ||||
|     my($req,$res,$content) = $test_machine->request_delete($uri); | ||||
|     $test_machine->http_code_msg(204, "check delete of voucher", $res, $content); | ||||
|     ($res, $content, $req) = $test_machine->request_get($uri); | ||||
|     is($res->code, 404, "check if deleted voucher is really gone"); | ||||
| } | ||||
| done_testing; | ||||
| 
 | ||||
| # vim: set tabstop=4 expandtab: | ||||
|  | ||||
					Loading…
					
					
				
		Reference in new issue