From 11979e04adb683b97807e0f79e37fb27ee9e6ac4 Mon Sep 17 00:00:00 2001 From: Irina Peshinskaya Date: Thu, 26 Mar 2015 20:29:03 +0200 Subject: [PATCH] MT#11147 Create fake data for the devicemodels and pbxdevices tests Change-Id: I782bd536fe6dc18d35857519f463329fba0c9da2 --- .../Panel/Controller/API/BillingProfiles.pm | 11 + lib/NGCP/Panel/Controller/API/Contracts.pm | 11 + .../Controller/API/SubscriberProfileSets.pm | 11 + .../Controller/API/SubscriberProfiles.pm | 11 + .../NGCP/Panel/Utils => t}/Test/Collection.pm | 143 +++-- t/Test/DeepHashUtils.pm | 330 +++++++++++ t/Test/FakeData.pm | 546 ++++++++++++++++++ t/api-devicemodels.t | 143 ----- t/api-pbxdevicemodels.t | 104 ++++ t/api-pbxdevices.t | 41 +- 10 files changed, 1134 insertions(+), 217 deletions(-) rename {lib/NGCP/Panel/Utils => t}/Test/Collection.pm (83%) create mode 100644 t/Test/DeepHashUtils.pm create mode 100644 t/Test/FakeData.pm delete mode 100644 t/api-devicemodels.t create mode 100644 t/api-pbxdevicemodels.t diff --git a/lib/NGCP/Panel/Controller/API/BillingProfiles.pm b/lib/NGCP/Panel/Controller/API/BillingProfiles.pm index c6bc729278..40d68e8e87 100644 --- a/lib/NGCP/Panel/Controller/API/BillingProfiles.pm +++ b/lib/NGCP/Panel/Controller/API/BillingProfiles.pm @@ -37,6 +37,17 @@ class_has 'query_params' => ( second => sub {}, }, }, + { + param => 'handle', + description => 'Filter for billing profiles with a specific handle', + query => { + first => sub { + my $q = shift; + { handle => { like => $q } }; + }, + second => sub {}, + }, + }, ]}, ); diff --git a/lib/NGCP/Panel/Controller/API/Contracts.pm b/lib/NGCP/Panel/Controller/API/Contracts.pm index 5d58c133fb..e35b20d9bf 100644 --- a/lib/NGCP/Panel/Controller/API/Contracts.pm +++ b/lib/NGCP/Panel/Controller/API/Contracts.pm @@ -49,6 +49,17 @@ class_has 'query_params' => ( second => sub {}, }, }, + { + param => 'external_id', + description => 'Filter for contracts with a specific external id', + query => { + first => sub { + my $q = shift; + { 'me.external_id' => { like => $q } }; + }, + second => sub {}, + }, + }, ]}, ); diff --git a/lib/NGCP/Panel/Controller/API/SubscriberProfileSets.pm b/lib/NGCP/Panel/Controller/API/SubscriberProfileSets.pm index 1d6c8c1f5e..d55422199e 100644 --- a/lib/NGCP/Panel/Controller/API/SubscriberProfileSets.pm +++ b/lib/NGCP/Panel/Controller/API/SubscriberProfileSets.pm @@ -38,6 +38,17 @@ class_has 'query_params' => ( second => sub {}, }, }, + { + param => 'name', + description => 'Filter for profile sets with a specific name', + query => { + first => sub { + my $q = shift; + { 'me.name' => { like => $q } }; + }, + second => sub {}, + }, + }, ]}, ); diff --git a/lib/NGCP/Panel/Controller/API/SubscriberProfiles.pm b/lib/NGCP/Panel/Controller/API/SubscriberProfiles.pm index 5974a6f7bf..b5b388ea99 100644 --- a/lib/NGCP/Panel/Controller/API/SubscriberProfiles.pm +++ b/lib/NGCP/Panel/Controller/API/SubscriberProfiles.pm @@ -38,6 +38,17 @@ class_has 'query_params' => ( second => sub {}, }, }, + { + param => 'name', + description => 'Filter for profile with a specific name', + query => { + first => sub { + my $q = shift; + { 'me.name' => { like => $q } }; + }, + second => sub {}, + }, + }, ]}, ); diff --git a/lib/NGCP/Panel/Utils/Test/Collection.pm b/t/Test/Collection.pm similarity index 83% rename from lib/NGCP/Panel/Utils/Test/Collection.pm rename to t/Test/Collection.pm index 3dc3a2b260..289391efe8 100644 --- a/lib/NGCP/Panel/Utils/Test/Collection.pm +++ b/t/Test/Collection.pm @@ -1,4 +1,6 @@ -package NGCP::Panel::Utils::Test::Collection; +package Test::Collection; +#later package should be split into 2: apiclient and testcollection +#testcollection will keep object of the apiclient use strict; use Test::More; @@ -8,6 +10,7 @@ use LWP::UserAgent; use HTTP::Request::Common; use Net::Domain qw(hostfqdn); use URI; +use URI::Escape; use Clone qw/clone/; use Data::Dumper; @@ -22,7 +25,7 @@ has 'base_uri' => ( is => 'ro', isa => 'Str', default => $ENV{CATALYST_SERVER} || ('https://'.hostfqdn.':4443'), -); +); has 'name' => ( is => 'rw', isa => 'Str', @@ -37,11 +40,11 @@ has 'methods' => ( isa => 'HashRef', default => sub { { 'collection' =>{ - 'all' => {map {$_ => 1} qw/GET HEAD OPTIONS POST/}, + 'all' => {map {$_ => 1} qw/GET HEAD OPTIONS POST/}, 'allowed' => {map {$_ => 1} qw/GET HEAD OPTIONS POST/}, #some default }, 'item' =>{ - 'all' => {map {$_ => 1} qw/GET HEAD OPTIONS PUT PATCH POST DELETE/}, + 'all' => {map {$_ => 1} qw/GET HEAD OPTIONS PUT PATCH POST DELETE/}, 'allowed' => {map {$_ => 1} qw/GET HEAD OPTIONS PUT PATCH DELETE/}, #some default }, } }, @@ -76,10 +79,19 @@ has 'DATA_CREATED' => ( isa => 'HashRef', builder => 'clear_data_created', ); +has 'KEEP_CREATED' =>( + is => 'rw', + isa => 'Bool', +); has 'URI_CUSTOM' =>( is => 'rw', isa => 'Str', ); +has 'QUERY_PARAMS' =>( + is => 'rw', + isa => 'Str', + default => '', +); has 'URI_CUSTOM_STORE' =>( is => 'rw', isa => 'Str', @@ -99,9 +111,28 @@ has 'ENCODE_CONTENT' => ( isa => 'Str', default => 'json', ); +sub set{ + my $self = shift; + my %params = @_; + my $prev_state = {}; + while (my ($variable, $value) = each %params){ + $prev_state->{$variable} = $self->$variable; + $self->$variable($value); + } + return $prev_state; +} +sub get_cloned{ + my $self = shift; + my @params = @_; + my $state = {}; + foreach my $variable (@params){ + $state->{$variable} = clone( $self->$variable ); + } + return $state; +} sub _init_ua { my $self = shift; - my $valid_ssl_client_cert = $ENV{API_SSL_CLIENT_CERT} || + 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; @@ -118,7 +149,7 @@ sub _init_ua { # SSL_verify_mode => 0x00, #); return $ua; -}; +} sub clear_data_created{ my($self) = @_; $self->DATA_CREATED({ @@ -133,6 +164,12 @@ sub form_data_item{ (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 = $created_info->{location} || ''; + $id=~s/.*?\D(\d+)$/$1/gis; + return $id; +} sub get_hal_name{ my($self) = @_; return "ngcp:".$self->name; @@ -143,8 +180,13 @@ sub restore_uri_custom{ $self->URI_CUSTOM_STORE(undef); } sub get_uri_collection{ - my($self) = @_; - return $self->base_uri."/api/".$self->name.($self->name ? "/" : ""); + my($self,$name) = @_; + $name //= $self->name; + return $self->base_uri."/api/".$name.($name ? "/" : "").($self->QUERY_PARAMS ? "?".$self->QUERY_PARAMS : ""); +} +sub get_uri_get{ + my($self,$query_string) = @_; + return $self->base_uri."/api/".$self->name.'/?'.$query_string; } sub get_uri_firstitem{ my($self) = @_; @@ -174,17 +216,18 @@ sub encode_content{ 'application/json-patch+json' => 1, 'json' => 1, ); - #print "content=$content;\n\n"; + #print "1. content=$content;\n\n"; if($content){ if( $json_types{$type} && (('HASH' eq ref $content) ||('ARRAY' eq ref $content)) ){ return JSON::to_json($content); } } + #print "2. content=$content;\n\n"; return $content; } sub request{ my($self,$req) = @_; - #print $req->as_string; + #print $req->as_string; $self->ua->request($req); } @@ -193,8 +236,8 @@ sub get_request_put{ $uri ||= $self->get_uri_current; #This is for multipart/form-data cases $content = $self->encode_content($content, $self->content_type->{PUT}); - my $req = POST $uri, - Content_Type => $self->content_type->{POST}, + my $req = POST $uri, + Content_Type => $self->content_type->{POST}, $content ? ( Content => $content ) : (); $req->method('PUT'); $req->header('Prefer' => 'return=representation'); @@ -214,21 +257,21 @@ sub request_put{ my $req = $self->get_request_put( $content, $uri ); my $res = $self->request($req); #print Dumper $res; - - my $err = $res->decoded_content ? JSON::from_json($res->decoded_content) : ''; - return wantarray ? ($res,$err,$req) : $res; + + my $rescontent = $res->decoded_content ? JSON::from_json($res->decoded_content) : ''; + return wantarray ? ($res,$rescontent,$req) : $res; } sub request_patch{ - my($self,$content,$uri, $req) = @_; + my($self,$content, $uri, $req) = @_; $uri ||= $self->get_uri_current; $req ||= $self->get_request_patch($uri); #patch is always a json $content = $self->encode_content($content, $self->content_type->{PATCH}); $content and $req->content($content); my $res = $self->request($req); - my $err = $res->decoded_content ? JSON::from_json($res->decoded_content) : ''; - #print Dumper [$res,$err,$req]; - return ($res,$err,$req); + my $rescontent = $res->decoded_content ? JSON::from_json($res->decoded_content) : ''; + #print Dumper [$res,$rescontent,$req]; + return wantarray ? ($res,$rescontent,$req) : $res; } sub request_post{ @@ -241,16 +284,14 @@ sub request_post{ }; $content = $self->encode_content($content, $self->content_type->{POST} ); #form-data is set automatically, despite on $self->content_type->{POST} - my $req = POST $self->get_uri_collection, - Content_Type => $self->content_type->{POST}, + my $req = POST $self->get_uri_collection, + Content_Type => $self->content_type->{POST}, Content => $content; my $res = $self->request($req); - my $err = $res->decoded_content ? JSON::from_json($res->decoded_content) : ''; - return ($res,$err,$req); + my $rescontent = $res->decoded_content ? JSON::from_json($res->decoded_content) : ''; + return wantarray ? ($res,$rescontent,$req) : $res; }; - - sub request_options{ my ($self,$uri) = @_; # OPTIONS tests @@ -260,6 +301,7 @@ sub request_options{ my $content = $res->decoded_content ? JSON::from_json($res->decoded_content) : ''; return($req,$res,$content); } + sub request_delete{ my ($self,$uri) = @_; # DELETE tests @@ -269,10 +311,15 @@ sub request_delete{ my $content = $res->decoded_content ? JSON::from_json($res->decoded_content) : ''; return($req,$res,$content); } + +############## end of test machine +############## start of test collection + sub check_options_collection{ - my ($self) = @_; + my ($self, $uri) = @_; # OPTIONS tests - my $req = HTTP::Request->new('OPTIONS', $self->get_uri_collection ); + $uri //= $self->get_uri_collection; + my $req = HTTP::Request->new('OPTIONS', $uri ); my $res = $self->request($req); is($res->header('Accept-Post'), "application/hal+json; profile=http://purl.org/sipwise/ngcp-api/#rel-".$self->name, "check Accept-Post header in options response"); $self->check_methods($res,'collection'); @@ -297,34 +344,39 @@ sub check_methods{ ok(grep(/^$opt$/, @{ $opts->{methods} }), "check for existence of '$opt' in body"); }else{ ok(!grep(/^$opt$/, @hopts), "check for absence of '$opt' in Allow header"); - ok(!grep(/^$opt$/, @{ $opts->{methods} }), "check for absence of '$opt' in body"); + ok(!grep(/^$opt$/, @{ $opts->{methods} }), "check for absence of '$opt' in body"); } } } sub check_create_correct{ - my($self, $number, $uniquizer_cb, $keep_data) = @_; - if(!$keep_data){ + my($self, $number, $uniquizer_cb, $keep_created) = @_; + if(!$keep_created && !$self->KEEP_CREATED){ $self->clear_data_created; } $self->DATA_CREATED->{ALL} //= {}; for(my $i = 1; $i <= $number; ++$i) { - my ($res, $err) = $self->request_post( $uniquizer_cb , undef, { i => $i} ); - is($res->code, 201, "create test item $i"); + my ($res, $content, $req) = $self->request_post( $uniquizer_cb , undef, { i => $i} ); + is($res->code, 201, "create test item '".$self->name."' $i"); my $location = $res->header('Location'); if($location){ - $self->DATA_CREATED->{ALL}->{$location} = $i; + $self->DATA_CREATED->{ALL}->{$location} = { num => $i, content => $content, res => $res, req => $req, location => $location}; $self->DATA_CREATED->{FIRST} = $location unless $self->DATA_CREATED->{FIRST}; } } } -sub check_delete_use_created{ +sub clear_test_data_all{ my($self,$uri) = @_; - my @uris = $uri ? ($uri) : keys $self->DATA_CREATED->{ALL}; + my @uris = $uri ? (('ARRAY' eq ref $uri) ? @$uri : ($uri)) : keys $self->DATA_CREATED->{ALL}; foreach my $del_uri(@uris){ my($req,$res,$content) = $self->request_delete($self->base_uri.$del_uri); is($res->code, 204, "check delete item $del_uri"); } } +sub clear_test_data_dependent{ + my($self,$uri) = @_; + my($req,$res,$content) = $self->request_delete($self->base_uri.$uri); + return ('204' eq $res->code); +} sub check_list_collection{ my($self, $check_embedded_cb) = @_; my $nexturi = $self->get_uri_collection."?page=1&rows=5"; @@ -363,7 +415,7 @@ sub check_list_collection{ } my $hal_name = $self->get_hal_name; - ok(((ref $list_collection->{_links}->{$hal_name} eq "ARRAY" ) || + ok(((ref $list_collection->{_links}->{$hal_name} eq "ARRAY" ) || (ref $list_collection->{_links}->{$hal_name} eq "HASH" ) ), "check if 'ngcp:".$self->name."' is array/hash-ref"); my $check_embedded = sub { @@ -410,8 +462,8 @@ sub check_item_get{ my $req = HTTP::Request->new('GET', $uri); my $res = $self->request($req); is($res->code, 200, "fetch one item"); - my $err = $res->decoded_content ? JSON::from_json($res->decoded_content) : ''; - return wantarray ? ($res, $err, $req) : $res; + my $content = $res->decoded_content ? JSON::from_json($res->decoded_content) : ''; + return wantarray ? ($res, $content, $req) : $res; } sub check_put_content_type_empty{ @@ -476,11 +528,11 @@ sub check_put_bundle{ } sub check_patch_correct{ my($self,$content) = @_; - my ($res,$mod_model,$req) = $self->request_patch( $content ); + my ($res,$rescontent,$req) = $self->request_patch( $content ); is($res->code, 200, "check patched item"); - is($mod_model->{_links}->{self}->{href}, $self->DATA_CREATED->{FIRST}, "check patched self link"); - is($mod_model->{_links}->{collection}->{href}, '/api/'.$self->name.'/', "check patched collection link"); - return ($res,$mod_model,$req); + is($rescontent->{_links}->{self}->{href}, $self->DATA_CREATED->{FIRST}, "check patched self link"); + is($rescontent->{_links}->{collection}->{href}, '/api/'.$self->name.'/', "check patched collection link"); + return ($res,$rescontent,$req); } sub check_patch_prefer_wrong{ @@ -574,7 +626,7 @@ sub check_patch_bundle{ } sub check_bundle{ my($self) = @_; - $self->check_options_collection; + $self->check_options_collection(); # iterate over collection to check next/prev links and status my $listed = $self->check_list_collection(); $self->check_created_listed($listed); @@ -583,4 +635,9 @@ sub check_bundle{ $self->check_put_bundle; $self->check_patch_bundle; } +#utils +sub hash2params{ + my($self,$hash) = @_; + return join '&', map {$_.'='.uri_escape($hash->{$_})} keys %{ $hash }; +} 1; \ No newline at end of file diff --git a/t/Test/DeepHashUtils.pm b/t/Test/DeepHashUtils.pm new file mode 100644 index 0000000000..62a7d2bb40 --- /dev/null +++ b/t/Test/DeepHashUtils.pm @@ -0,0 +1,330 @@ +package Test::DeepHashUtils; + +use 5.006; +use strict; +use warnings; +use Data::Dumper; + +require Exporter; + +our @ISA = qw(Exporter); +our %EXPORT_TAGS = ( 'all' => [ qw( reach slurp nest deepvalue ) ] ); +our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); +our @EXPORT = (); +our $VERSION = '0.03'; + + +my $C; + +# Recursive version of C; +sub reach { + my $ref = shift; + if (ref $ref eq 'HASH') { + + if (defined $C->{$ref}{v}) { + if (ref $C->{$ref}{v} eq 'HASH' || ref $C->{$ref}{v} eq 'ARRAY') { + if (my @rec = reach($C->{$ref}{v})) { + if (defined $C->{$ref}{k}) { + return ($C->{$ref}{k},@rec); + } + if (defined $C->{$ref}{i}) { + return ($C->{$ref}{i},@rec); + } + return @rec; + } + } + undef $C->{$ref}{v}; + } + + + if (my ($k,$v) = each %$ref) { + $C->{$ref}{v} = $v; + $C->{$ref}{k} = $k; + return ($k,reach($v)); + } + return (); + + } elsif (ref $ref eq 'ARRAY') { + + if (defined $C->{$ref}{v}) { + if (ref $C->{$ref}{v} eq 'HASH' || + ref $C->{$ref}{v} eq 'ARRAY') { + + if (my @rec = reach($C->{$ref}{v})) { + if (defined $C->{$ref}{i}) { + return $C->{$ref}{i},@rec; + } + if (defined $C->{$ref}{k}) { + return $C->{$ref}{k},@rec; + } + return @rec; + } + } + undef $C->{$ref}{v}; + } + + if(!(defined $C->{$ref}{i})){ + $C->{$ref}{i} = 0; + }else{ + $C->{$ref}{i}++; + } + if (my $v = $ref->[$C->{$ref}{i}]) { + $C->{$ref}{v} = $v; + return ($C->{$ref}{i}, reach($v)); + } + + return (); + } + return $ref; +} + + +# run C over entire hash and return the final list of values at once +sub slurp { + my $ref = shift; + my @h; + while (my @a = reach($ref)) { + push @h,\@a; + } + return @h; +} + + +# Define nested hash keys from the given list of values +sub nest { + my $hr = shift; + my $ref = $hr; + while ( @_ ) { + my $key = shift @_; + if (@_ > 1) { + $ref = ('HASH' eq ref $ref ? $ref->{$key} : ('ARRAY' eq ref $ref ? $ref->[$key]:undef) ) ; + $ref ||= {}; + } else { + my $value = shift; + if('HASH' eq ref $ref){ + $ref->{$key} = $value; + }elsif('ARRAY' eq ref $ref){ + $ref->[$key] = $value; + } + } + } + return $hr; +} + + + +# Return value at the end of the given nested hash keys and/or array indexes +sub deepvalue { + my $hr = shift; + while (@_) { + my $key = shift; + if (ref $hr eq 'HASH') { + return unless ($hr = $hr->{$key}); + } elsif (ref $hr eq 'ARRAY') { + return unless ($hr = $hr->[$key]); + } else { + return; + } + } + return $hr; +} + + +1; +__END__ + + +=head1 NAME + +Test::DeepHashUtils - functions for iterating over and working with nested hashes + +=head1 SYNOPSIS + + use Deep::Hash::Utils qw(reach slurp nest deepvalue); + + my %hash = ( + A => { + B => { + W => 1, + X => 2, + }, + C => { + Y => 3, + Z => 4, + }, + } + ); + + while (my @list = reach(\%hash)) { + print "@list"; + } + + for my $a (sort {$a->[2] cmp $b->[2]} slurp(\%hash)) { + print "@$a"; + } + + + + my %new_hash = (); + + nest(\%new_hash,1,2,3,4,5); + + my $value = deepvalue(\%new_hash,1,2,3,4); + + + +=head1 DESCRIPTION + +This module provides functions for accessing and modifying values in deeply nested data structures + + +=head3 C + +reach HASHREF + +Iterate over each nested data structure contained in the given hash. Returns an array of each nested key/value set. + +Just as C lets you iterate over the keys and values in a single hash, C provides an iterator over any recursively nested data structures. + +This helps avoid the need to use layers of nested loops in order to iterate over all entities in nested hashes and arrays. + +The reference passed to C can contain any combination of nested hashes and arrays. Hash keys and values will be ordered in the same manner as when using C, C, or C. + + use Deep::Hash::Utils qw(reach slurp nest); + $\ = "\n"; + + my %hash = ( + A => { + B => { + W => 1, + X => 2, + }, + C => { + Y => 3, + Z => 4, + }, + } + ); + + while (my @list = reach(\%hash)) { + print "@list"; + } + + __END__ + + Outputs: + + A C Z 4 + A C Y 3 + A B W 1 + A B X 2 + + + +=head3 C + +slurp HASHREF + +Returns a list of arrays generated by C at once. +Use this if you want the same result of C with the ability to sort each layer of keys. + + for my $a (sort {$a->[2] cmp $b->[2]} slurp(\%hash)) { + print "@$a"; + } + + __END__ + + Output: + + A B W 1 + A B X 2 + A C Y 3 + A C Z 4 + + + +=head3 C + +nest HASHREF, LIST + +define nested hash keys with a given list + + use Data::Dumper; + + my %new_hash = (); + nest(\%new_hash,1,2,3,4,5); + + print Dumper \%new_hash; + + __END__ + + Output: + + $VAR1 = { + '1' => { + '2' => { + '3' => { + '4' => 5 + } + } + } + }; + + +=head3 C + +deepvalue HASHREF, LIST + +retrieve deeply nested values with a list of keys: + + my %new_hash = ( + '1' => { + '2' => { + '3' => { + '4' => 5 + } + } + } + ); + + print Dumper deepvalue(\%new_hash,1,2,3,4); + + print Dumper deepvalue(\%new_hash,1,2); + + __END__ + + Output: + + $VAR1 = 5; + + $VAR1 = { + '3' => { + '4' => 5 + } + }; + + +=head2 EXPORT + +None by default. + +=head1 REPOSITORY + +L + +=head1 AUTHOR + +Chris Becker, Eclbecker@gmail.com + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2009 by Chris Becker + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself, either Perl version 5.8.5 or, +at your option, any later version of Perl 5 you may have available. + + + + +=cut diff --git a/t/Test/FakeData.pm b/t/Test/FakeData.pm new file mode 100644 index 0000000000..09b352663e --- /dev/null +++ b/t/Test/FakeData.pm @@ -0,0 +1,546 @@ +package Test::FakeData; + +use strict; + +use Sipwise::Base; +use Test::Collection; +use JSON; +use Test::More; +use File::Basename; +use Data::Dumper; +use Test::DeepHashUtils qw(reach nest deepvalue); +use Clone qw/clone/; + +has 'test_machine' =>( + is => 'rw', + isa => 'Test::Collection', + default => sub { Test::Collection->new () }, +); +has 'created' => ( + is => 'rw', + isa => 'HashRef', + default => sub { {} }, +); +has 'loaded' => ( + is => 'rw', + isa => 'HashRef', + default => sub { {} }, +); +has 'data_default' => ( + is => 'rw', + isa => 'HashRef', + builder => 'build_data_default', +); +has 'data' => ( + is => 'rw', + isa => 'HashRef', + builder => 'build_data', +); +has 'FLAVOUR' => ( + is => 'rw', + isa => 'Str', +); +#TODO: optimization - pre load and predelete should be done only for required collections and dependencies +has 'work_collections' => ( + is => 'rw', + isa => 'ArrayRef', + default => sub { [] }, +); +sub build_data_default{ + return { + 'products' => [ + { + id => 1, + reseller_id => undef, + class => 'pstnpeering', + handle => 'PSTN_PEERING', + name => 'PSTN Peering', + on_sale => 1, + price => undef, + weight => undef, + billing_profile_id => undef, + },{ + id => 2, + reseller_id => undef, + class => 'sippeering', + handle => 'SIP_PEERING', + name => 'PSTN Peering', + on_sale => 1, + price => undef, + weight => undef, + billing_profile_id => undef, + },{ + id => 3, + reseller_id => undef, + class => 'reseller', + handle => 'VOIP_RESELLER', + name => 'VoIP Reseller', + on_sale => 1, + price => undef, + weight => undef, + billing_profile_id => undef, + }, + ], + 'contracts' => { + id => 1, + customer_id => undef, + reseller_id => undef, + contact_id => undef, + order_id => undef, + status => 'active', + modify_timestamp => '0', + create_timestamp => '0', + activate_timestamp => '0', + terminate_timestamp => undef, + }, + 'resellers' => { + id => 1, + contract_id => 1, + name => 'default', + status => 'active', + }, + 'billing_mappings' => { + id => 1, + start_date => undef, + end_date => undef, + billing_profile_id => undef, + contract_id => 1, + product_id => 3, + }, + 'billing_profiles' => { + id => 1, + reseller_id => 1, + handle => 'default', + name => 'Default Billing Profile', + prepaid => 1, + interval_charge => 0, + interval_free_time => 0, + interval_free_cash => 0, + interval_unit => 'month', + interval_count => 1, + currency => undef, + vat_rate => 0, + vat_included => 0, + }, + 'billing_zones' => { + id => 1, + billing_profile_id => 1, + zone => 'Free Default Zone', + detail => 'All Destinations', + }, + 'billing_fees' => { + id => 1, + billing_profile_id => 1, + billing_zone_id => 1, + destination => '.*', + type => 'call', + onpeak_init_rate => 0, + onpeak_init_interval => 600, + onpeak_follow_rate => 0, + onpeak_follow_interval => 600, + offpeak_init_rate => 0, + offpeak_init_interval => 600, + offpeak_follow_rate => 0, + offpeak_follow_interval => 600, + }, + 'domains' => { + domain => 'voip.sipwise.local', + local => 1, + } + }; +} + +sub build_data{ + my ($self) = @_; + my $data = { + 'systemcontacts' => { + 'data' => { + email => 'api_test_reseller@reseller.invalid', + firstname => 'api_test first', + lastname => 'api_test last', + }, + 'query' => ['email'], + 'delete_potentially_dependent' => 1, + }, + 'customercontacts' => { + 'data' => { + firstname => 'api_test cust_contact_first', + lastname => 'api_test cust_contact_last', + email => 'api_test_cust_contact@custcontact.invalid', + reseller_id => sub { return shift->create('resellers',@_); }, + }, + 'query' => ['email'], + 'delete_potentially_dependent' => 1, + }, + 'contracts' => { + 'data' => { + contact_id => sub { return shift->create('systemcontacts',@_); }, + status => 'active', + external_id => 'api_test', + #type => sub { return value_request('contracts','type',['reseller']); }, + type => 'reseller', + billing_profile_id => sub { return shift->create('billingprofiles',@_); }, + }, + 'default' => 'contracts', + 'query' => ['external_id'], + 'no_delete_available' => 1, + }, + 'resellers' => { + 'data' => { + contract_id => sub { return shift->create('contracts', @_ ); }, + name => 'api_test test reseller', + status => 'active', + }, + 'default' => 'resellers', + 'query' => ['name'], + 'no_delete_available' => 1, + }, + 'customers' => { + 'data' => { + status => 'active', + contact_id => sub { return shift->create('customercontacts',@_); }, + billing_profile_id => sub { return shift->create('billingprofiles',@_); }, + max_subscribers => undef, + external_id => 'api_test customer', + type => 'pbxaccount',#sipaccount + }, + 'query' => ['external_id'], + 'no_delete_available' => 1, + }, + 'billingprofiles' => { + 'data' => { + name => 'api_test test profile', + handle => 'api_test_testprofile', + reseller_id => sub { return shift->create('resellers',@_); }, + }, + 'default' => 'billing_profiles', + 'query' => ['handle'], + 'no_delete_available' => 1, + }, + 'subscribers' => { + 'data' => { + administrative => 0, + customer_id => sub { return shift->create('customers',@_); }, + primary_number => { ac => 111, cc=> 111, sn => 111 }, + alias_numbers => [ { ac => 11, cc=> 11, sn => 11 } ], + username => 'api_test_username', + password => 'api_test_password', + webusername => 'api_test_webusername', + webpassword => undef, + domain_id => sub { return shift->create('domains',@_); },, + #domain_id => + email => undef, + external_id => undef, + is_pbx_group => 1, + is_pbx_pilot => 1, + pbx_extension => '111', + pbx_group_ids => [], + pbx_groupmember_ids => [], + profile_id => sub { return shift->create('subscriberprofiles',@_); }, + status => 'active', + pbx_hunt_policy => 'parallel', + pbx_hunt_timeout => '15', + }, + 'query' => ['username'], + }, + 'domains' => { + 'data' => { + domain => 'api_test_domain.api_test_domain', + reseller_id => sub { return shift->create('resellers',@_); }, + }, + 'query' => ['domain'], + }, + 'subscriberprofilesets' => { + 'data' => { + name => 'api_test_subscriberprofileset', + reseller_id => sub { return shift->create('resellers',@_); }, + description => 'api_test_subscriberprofileset', + }, + 'query' => ['name'], + }, + 'subscriberprofiles' => { + 'data' => { + name => 'api_test subscriberprofile', + profile_set_id => sub { return shift->create('subscriberprofilesets',@_); }, + description => 'api_test subscriberprofile', + }, + 'query' => ['name'], + }, + 'pbxdevicemodels' => { + 'data' => { + json => { + model => "api_test ATA111", + #reseller_id=1 is very default, as is seen from the base initial script + #reseller_id => "1", + reseller_id => sub { return shift->create('resellers',@_); }, + vendor =>"Cisco", + #3.7relative tests + type => "phone", + connectable_models => [], + extensions_num => "2", + bootstrap_method => "http", + bootstrap_uri => "", + bootstrap_config_http_sync_method => "GET", + bootstrap_config_http_sync_params => "[% server.uri %]/\$MA", + bootstrap_config_http_sync_uri => "http=>//[% client.ip %]/admin/resync", + bootstrap_config_redirect_panasonic_password => "", + bootstrap_config_redirect_panasonic_user => "", + bootstrap_config_redirect_polycom_password => "", + bootstrap_config_redirect_polycom_profile => "", + bootstrap_config_redirect_polycom_user => "", + bootstrap_config_redirect_yealink_password => "", + bootstrap_config_redirect_yealink_user => "", + #TODO:implement checking against this number in the controller and api + #/3.7relative tests + "linerange"=>[ + { + "keys" => [ + {y => "390", labelpos => "left", x => "510"}, + {y => "350", labelpos => "left", x => "510"} + ], + can_private => "1", + can_shared => "0", + can_blf => "0", + name => "Phone Ports api_test", + #TODO: test duplicate creation #"id"=>1311, + }, + { + "keys"=>[ + {y => "390", labelpos => "left", x => "510"}, + {y => "350", labelpos => "left", x => "510"} + ], + can_private => "1", + can_shared => "0", + #TODO: If I'm right - now we don't check field values against this, because test for pbxdevice xreation is OK + can_blf => "0", + name => "Extra Ports api_test", + #TODO: test duplicate creation #"id"=>1311, + } + ] + }, + #TODO: can check big files + #front_image => [ dirname($0).'/resources/api_devicemodels_front_image.jpg' ], + front_image => [ dirname($0).'/resources/empty.txt' ], + }, + 'query' => [ ['model','json','model'] ], + 'create_special'=> sub { + my ($self,$name) = @_; + my $prev_params = $self->test_machine->get_cloned('content_type'); + @{$self->test_machine->content_type}{qw/POST PUT/} = (('multipart/form-data') x 2); + $self->test_machine->check_create_correct(1); + $self->test_machine->set(%$prev_params); + }, + 'no_delete_available' => 1, + }, + 'pbxdeviceconfigs' => { + 'data' => { + device_id => sub { return shift->create('pbxdevicemodels',@_); }, + version => 'api_test 1.1', + content_type => 'text/plain', + }, + 'query' => ['version'], + 'create_special'=> sub { + my ($self,$name) = @_; + my $prev_params = $self->test_machine->get_cloned('content_type','QUERY_PARAMS'); + $self->test_machine->content_type->{POST} = $self->data->{$name}->{data}->{content_type}; + $self->test_machine->QUERY_PARAMS($self->test_machine->hash2params($self->data->{$name}->{data})); + $self->test_machine->check_create_correct(1, sub {return 'test_api_empty_config';} ); + $self->test_machine->set(%$prev_params); + }, + 'no_delete_available' => 1, + }, + 'pbxdeviceprofiles' => { + 'data' => { + config_id => sub { return shift->create('pbxdeviceconfigs',@_); }, + name => 'api_test profile 1.1', + }, + 'query' => ['name'], + 'no_delete_available' => 1, + }, + 'pbxdevices' => { + 'data' => { + profile_id => sub { return shift->create('pbxdeviceprofiles',@_); }, + customer_id => sub { return shift->create('customers',@_); }, + identifier => 'aaaabbbbcccc', + station_name => 'api_test_vun', + lines=>[{ + linerange => 'Phone Ports api_test', + type => 'private', + key_num => '0', + subscriber_id => sub { return shift->create('subscribers',@_); }, + extension_unit => '1', + extension_num => '1',#to handle some the same extensions devices + },{ + linerange => 'Extra Ports api_test', + type => 'blf', + key_num => '1', + subscriber_id => sub { return shift->create('subscribers',@_); }, + extension_unit => '2', + }], + }, + 'query' => ['station_name'], + }, + }; + foreach my $collection_name( keys %$data ){ + if($self->FLAVOUR && exists $data->{$collection_name}->{flavour} && exists $data->{$collection_name}->{flavour}->{$self->FLAVOUR}){ + $data = {%$data, %{$data->{$collection_name}->{flavour}->{$self->FLAVOUR}}}, + } + } + $self->clear_db($data,[qw/contracts systemcontacts customercontacts/]); + #incorrect place, leave it for the next timeframe to work on it + $self->load_db($data); + return $data; +} +sub load_db{ + my($self,$data) = @_; + $data //= $self->data; + foreach my $collection_name( keys %$data ){ + #print "collection_name=$collection_name;\n"; + if((!exists $self->loaded->{$collection_name}) && $data->{$collection_name}->{query}){ + my(undef,$content) = $self->search_item($collection_name,$data); + if($content->{total_count}){ + my $values = $content->{_embedded}->{$self->test_machine->get_hal_name}; + $values = ('HASH' eq ref $values) ? [$values] : $values; + $self->loaded->{$collection_name} = [ map { + { + location => $_->{_links}->{self}->{href}, + content => $_, + } + } @$values ]; + } + } + } + return; +} +sub clear_db{ + my($self,$data,$order_array) = @_; + $order_array //= []; + my $order_hash = {}; + @$order_hash{(keys %$data)} = (0) x (keys %$data); + @$order_hash{@$order_array} = (1..$#$order_array+1); + my @undeletable_items = (); + foreach my $collection_name (sort {$order_hash->{$a} <=> $order_hash->{$b}} keys %$data ){ + if((!$data->{$collection_name}->{query})){ + next; + } + my(undef,$content) = $self->search_item($collection_name,$data); + if($content->{total_count}){ + my $values = $content->{_links}->{$self->test_machine->get_hal_name}; + $values = + ('HASH' eq ref $values) ? [$values] : $values; + my @locations = map {$_->{href}} @$values; + if($data->{$collection_name}->{no_delete_available}){ + push @undeletable_items, @locations; + }else{ + if($data->{$collection_name}->{delete_potentially_dependent}){ + foreach( @locations ){ + if(!$self->test_machine->clear_test_data_dependent($_)){ + push @undeletable_items, $_; + } + } + }else{ + $self->test_machine->clear_test_data_all([ @locations ]); + } + } + } + } + if(@undeletable_items){ + print "We have test items, which can't delete through API:\n"; + print Dumper [ @undeletable_items ]; + } + return; +} +sub search_item{ + my($self,$collection_name,$data) = @_; + $data //= $self->data; + my $item = $data->{$collection_name}; + if(!$item->{query}){ + return; + } + $self->test_machine->name($collection_name); + my $query_string = join('&', map { + my @deep_keys = ('ARRAY' eq ref $_) ? @$_:($_); + my $field_name = ( @deep_keys > 1 ) ? shift @deep_keys : $deep_keys[0]; + $field_name.'='.deepvalue($item->{data},@deep_keys); + } @{$item->{query}} + ); + my($res, $content, $req) = $self->test_machine->check_item_get($self->test_machine->get_uri_get($query_string)); + return ($res, $content, $req); +} +sub create{ + my($self, $name, $parents_in, $field_path, $params) = @_; + $parents_in //= {}; + if($self->loaded->{$name} || $self->created->{$name}){ + return $self->get_id($name); + } + if($parents_in->{$name}){ + if($self->data->{$name}->{default}){ + $self->data->{$name}->{process_cycled} = {'parents'=>$parents_in,'field_path'=>$field_path}; + return $self->data_default->{$self->data->{$name}->{default}}->{id}; + }else{ + die('Data absence', Dumper([$name,$parents_in])); + } + } + $self->process($name, $parents_in); + #create itself + my $data = clone($self->data->{$name}->{data}); + $self->test_machine->set( + name => $name, + DATA_ITEM => $data, + ); + if(exists $self->data->{$name}->{create_special} && 'CODE' eq ref $self->data->{$name}->{create_special}){ + $self->data->{$name}->{create_special}->($self,$name); + }else{ + $self->test_machine->check_create_correct(1); + } + $self->created->{$name} = [values %{$self->test_machine->DATA_CREATED->{ALL}}]; + + if($self->data->{$name}->{process_cycled}){ + my %parents_cycled_ordered = reverse %{$self->data->{$name}->{process_cycled}->{parents}}; + my $last_parent = -1 + ( scalar values (%parents_cycled_ordered) ); + my $uri = $self->test_machine->get_uri_collection($parents_cycled_ordered{$last_parent}).$self->get_id($parents_cycled_ordered{$last_parent}); + $self->test_machine->request_patch([ { + op => 'replace', + path => join('/',('',@{$self->data->{$name}->{process_cycled}->{field_path}})), + value => $self->get_id($name) } ], + $uri + ); + delete $self->data->{$name}->{process_cycled}; + } + return $self->get_id($name); +} + +sub process{ + my($self, $name, $parents_in) = @_; + $parents_in //= {}; + my $parents = {%{$parents_in}}; + $parents->{$name} //= scalar values %$parents_in; + while (my @keys_and_value = reach($self->data->{$name}->{data})){ + my $field_value = pop @keys_and_value; + if('CODE' eq ref $field_value ){ + my $value = $field_value->($self,$parents,[@keys_and_value]); + nest( $self->data->{$name}->{data}, @keys_and_value, $value ); + } + } + return $self->data->{$name}->{data}; +} +sub get_id{ + my($self, $name) = @_; + my $id = $self->test_machine->get_id_from_created($self->created->{$name}->[0]) + || $self->test_machine->get_id_from_created($self->loaded->{$name}->[0]); + return $id +} +sub DEMOLISH{ + my($self) = @_; + ( 'ARRAY' eq ref$self->created ) and ( $self->test_machine->clear_test_data_all([ map {$_->{location}} @$self->created ]) ); +} +1; +__END__ + +Further improvements: +Really it would be much more correct to use collection clases with ALL their own test machine initialization for data creation. just will call proper collection class. It will allow to keep data near releveant tests, and don't duplicate test_machine params in the FakeData. + +Optimizations: +1.make wrapper for data creation/deletion for all tests. +2.Load/Clear only relevant tests data + diff --git a/t/api-devicemodels.t b/t/api-devicemodels.t deleted file mode 100644 index 4dc726e37c..0000000000 --- a/t/api-devicemodels.t +++ /dev/null @@ -1,143 +0,0 @@ -#use Sipwise::Base; -use strict; - -#use Moose; -use Sipwise::Base; -extends 'NGCP::Panel::Utils::Test::Collection'; -use Net::Domain qw(hostfqdn); -use LWP::UserAgent; -use HTTP::Request::Common; -use JSON; -use Test::More; -use Data::Dumper; -use File::Basename; - -#init test_machine -my $test_machine = NGCP::Panel::Utils::Test::Collection->new( - name => 'pbxdevicemodels', - embedded => [qw/pbxdevicefirmwares/] -); -@{$test_machine->content_type}{qw/POST PUT/} = (('multipart/form-data') x 2); -$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)}; -#for item creation test purposes /post request data/ -$test_machine->DATA_ITEM_STORE({ - json => { - "model"=>"ATA111", - #should be some fake reseller - create reseller/customer/subscriber tests? - #"reseller_id"=>"1", - "vendor"=>"Cisco", - #3.7relative tests - "bootstrap_method"=>"http", - "bootstrap_uri"=>"", - "bootstrap_config_http_sync_method"=>"GET", - "bootstrap_config_http_sync_params"=>"[% server.uri %]/\$MA", - "bootstrap_config_http_sync_uri"=>"http=>//[% client.ip %]/admin/resync", - "bootstrap_config_redirect_panasonic_password"=>"", - "bootstrap_config_redirect_panasonic_user"=>"", - "bootstrap_config_redirect_polycom_password"=>"", - "bootstrap_config_redirect_polycom_profile"=>"", - "bootstrap_config_redirect_polycom_user"=>"", - "bootstrap_config_redirect_yealink_password"=>"", - "bootstrap_config_redirect_yealink_user"=>"", - "type"=>"phone", - #"connectable_models"=>[702,703,704], - "extensions_num"=>"2", - #/3.7relative tests - "linerange"=>[ - { - "keys"=>[ - {"y"=>"390","labelpos"=>"left","x"=>"510"}, - {"y"=>"350","labelpos"=>"left","x"=>"510"} - ], - "can_private"=>"1", - "can_shared"=>"0", - "can_blf"=>"0", - "name"=>"Phone Ports", -#test duplicate creation #"id"=>1311, - } - ] - }, - #can check big files - #'front_image' => [ dirname($0).'/resources/api_devicemodels_front_image.jpg' ], - 'front_image' => [ dirname($0).'/resources/empty.txt' ], -}); - - - -##$test_machine->form_data_item( sub {$_[0]->{json}->{type} = "extension";} ); -##$test_machine->check_create_correct( 1, sub{ $_[0]->{json}->{model} .= "Extension 2".$_[1]->{i}; } ); -#$test_machine->check_get2put( sub { -# $_[0]->{connectable_models} = [670], -# $_[0] = { -# json => JSON::to_json($_[0]), -# 'front_image' => $test_machine->DATA_ITEM_STORE->{front_image} -# }; }, -# $test_machine->get_uri_collection.'449' -#); -# -##test check_patch_prefer_wrong is broken -##$test_machine->name('billingprofiles'); -##$test_machine->check_patch_prefer_wrong; - - -foreach my $type(qw/phone extension/){ - #last;#skip classic tests - $test_machine->form_data_item( sub {$_[0]->{json}->{type} = $type;} ); - # create 6 new billing models from DATA_ITEM - #$test_machine->check_create_correct( 6, sub{ $_[0]->{json}->{model} .= $type."TEST_".$_[1]->{i}; } ); - #$test_machine->check_get2put( sub { $_[0] = { json => JSON::to_json($_[0]), 'front_image' => $test_machine->DATA_ITEM_STORE->{front_image} }; } ); - - - $test_machine->check_bundle(); - - # try to create model without reseller_id - { - my ($res, $err) = $test_machine->request_post(sub{delete $_[0]->{json}->{reseller_id};}); - is($res->code, 422, "create model without reseller_id"); - is($err->{code}, "422", "check error code in body"); - ok($err->{message} =~ /field='reseller_id'/, "check error message in body"); - } - # try to create model with empty reseller_id - { - my ($res, $err) = $test_machine->request_post(sub{$_[0]->{json}->{reseller_id} = undef;}); - is($res->code, 422, "create model with empty reseller_id"); - is($err->{code}, "422", "check error code in body"); - ok($err->{message} =~ /field='reseller_id'/, "check error message in body"); - } - # try to create model with invalid reseller_id - { - my ($res, $err) = $test_machine->request_post(sub{$_[0]->{json}->{reseller_id} = 99999;}); - is($res->code, 422, "create model with invalid reseller_id"); - is($err->{code}, "422", "check error code in body"); - ok($err->{message} =~ /Invalid reseller_id/, "check error message in body"); - } - - { - my (undef, $item_first_get) = $test_machine->check_item_get; - ok(exists $item_first_get->{reseller_id} && $item_first_get->{reseller_id}->is_int, "check existence of reseller_id"); - foreach(qw/vendor model/){ - ok(exists $item_first_get->{$_}, "check existence of $_"); - } - # check if we have the proper links - # TODO: fees, reseller links - #ok(exists $new_contract->{_links}->{'ngcp:resellers'}, "check put presence of ngcp:resellers relation"); - } - { - my $t = time; - my($res,$mod_model) = $test_machine->check_patch_correct( [ { op => 'replace', path => '/model', value => 'patched model '.$t } ] ); - is($mod_model->{model}, "patched model $t", "check patched replace op"); - } - { - my($res) = $test_machine->request_patch( [ { op => 'replace', path => '/reseller_id', value => undef } ] ); - is($res->code, 422, "check patched undef reseller"); - } - { - my($res) = $test_machine->request_patch( [ { op => 'replace', path => '/reseller_id', value => 99999 } ] ); - is($res->code, 422, "check patched invalid reseller"); - } -} -`echo 'delete from autoprov_devices where model like "%TEST\\_%" or model like "patched model%";'|mysql provisioning`; -done_testing; - -# vim: set tabstop=4 expandtab: diff --git a/t/api-pbxdevicemodels.t b/t/api-pbxdevicemodels.t new file mode 100644 index 0000000000..74e24d719b --- /dev/null +++ b/t/api-pbxdevicemodels.t @@ -0,0 +1,104 @@ +#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 $fake_data = Test::FakeData->new; +my $test_machine = Test::Collection->new( + name => 'pbxdevicemodels', + embedded => [qw/pbxdevicefirmwares/] +); +@{$test_machine->content_type}{qw/POST PUT/} = (('multipart/form-data') x 2); +$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)}; +$test_machine->KEEP_CREATED( 1 ); +$test_machine->DATA_ITEM_STORE($fake_data->process('pbxdevicemodels')); + + +my $connactable_devices={}; + +foreach my $type(qw/extension phone/){ + #last;#skip classic tests + $test_machine->form_data_item( sub {$_[0]->{json}->{type} = $type;} ); + # create 3 & 3 new billing models from DATA_ITEM + $test_machine->check_create_correct( 3, sub{ $_[0]->{json}->{model} .= $type."TEST_".$_[1]->{i}; } ); + #print Dumper $test_machine->DATA_CREATED->{ALL}; + $connactable_devices->{$type}->{data} = [ values %{$test_machine->DATA_CREATED->{ALL}}]; + $connactable_devices->{$type}->{ids} = [ map {$test_machine->get_id_from_created($_)} @{$connactable_devices->{$type}->{data}}]; +} +sub get_connectable_type{ + my $type = shift; + return ('extension' eq $type) ? 'phone' : 'extension'; +} +foreach my $type(qw/extension phone/){ + #last;#skip classic tests + $test_machine->form_data_item( sub {$_[0]->{json}->{type} = $type;} ); + # create 3 next new models from DATA_ITEM + $test_machine->check_create_correct( 3, sub{ + $_[0]->{json}->{model} .= $type."TEST_".($_[1]->{i} + 3); + $_[0]->{json}->{connactable_devices} = $connactable_devices->{ get_connectable_type( $type) }->{ids}; + } ); + $test_machine->check_get2put( sub { $_[0] = { json => JSON::to_json($_[0]), 'front_image' => $test_machine->DATA_ITEM_STORE->{front_image} }; } ); + + $test_machine->check_bundle(); + + # try to create model without reseller_id + { + my ($res, $err) = $test_machine->request_post(sub{delete $_[0]->{json}->{reseller_id};}); + is($res->code, 422, "create model without reseller_id"); + is($err->{code}, "422", "check error code in body"); + ok($err->{message} =~ /field='reseller_id'/, "check error message in body"); + } + # try to create model with empty reseller_id + { + my ($res, $err) = $test_machine->request_post(sub{$_[0]->{json}->{reseller_id} = undef;}); + is($res->code, 422, "create model with empty reseller_id"); + is($err->{code}, "422", "check error code in body"); + ok($err->{message} =~ /field='reseller_id'/, "check error message in body"); + } + # try to create model with invalid reseller_id + { + my ($res, $err) = $test_machine->request_post(sub{$_[0]->{json}->{reseller_id} = 99999;}); + is($res->code, 422, "create model with invalid reseller_id"); + is($err->{code}, "422", "check error code in body"); + ok($err->{message} =~ /Invalid reseller_id/, "check error message in body"); + } + + { + my (undef, $item_first_get) = $test_machine->check_item_get; + ok(exists $item_first_get->{reseller_id} && $item_first_get->{reseller_id}->is_int, "check existence of the reseller_id"); + foreach(qw/vendor model/){ + ok(exists $item_first_get->{$_}, "check existence of $_"); + } + # check if we have the proper links + } + { + my $t = time; + my($res,$mod_model) = $test_machine->check_patch_correct( [ { op => 'replace', path => '/model', value => 'patched model '.$t } ] ); + is($mod_model->{model}, "patched model $t", "check patched replace op"); + } + { + my($res) = $test_machine->request_patch( [ { op => 'replace', path => '/reseller_id', value => undef } ] ); + is($res->code, 422, "check patched undef reseller"); + } + { + my($res) = $test_machine->request_patch( [ { op => 'replace', path => '/reseller_id', value => 99999 } ] ); + is($res->code, 422, "check patched invalid reseller"); + } +} +#pbxdevicemodels doesn't have DELETE method +#`echo 'delete from autoprov_devices where model like "%api_test %" or model like "patched model%";'|mysql provisioning`; +done_testing; + +# vim: set tabstop=4 expandtab: diff --git a/t/api-pbxdevices.t b/t/api-pbxdevices.t index 324fa8494f..7171f1685b 100644 --- a/t/api-pbxdevices.t +++ b/t/api-pbxdevices.t @@ -1,9 +1,9 @@ #use Sipwise::Base; use strict; - #use Moose; use Sipwise::Base; -extends 'NGCP::Panel::Utils::Test::Collection'; +use Test::Collection; +use Test::FakeData; use Net::Domain qw(hostfqdn); use LWP::UserAgent; use HTTP::Request::Common; @@ -14,44 +14,23 @@ use File::Basename; use bignum qw/hex/; #init test_machine -my $test_machine = NGCP::Panel::Utils::Test::Collection->new( - name => 'pbxdevices', +my $test_machine = Test::Collection->new( + name => 'pbxdevices', embedded => [qw/pbxdeviceprofiles customers/] ); $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)}; +my $fake_data = Test::FakeData->new; #for item creation test purposes /post request data/ -$test_machine->DATA_ITEM_STORE({ - #'profile_id' => '151', - #somehow should obtain/create test customer with the test subscriber - discuss with alex - #'customer_id' => '968', - 'identifier' => 'aaaabbbbcccc', - 'station_name' => 'abc', - 'lines'=>[{ - 'linerange' => 'Phone Ports', - 'type' => 'private', - 'key_num' => '0', - #somehow should obtain/create test customer with the test subscriber - discuss with alex -#'subscriber_id' => '1198', - 'extension_unit' => '1', - #'extension_num' => '1',#to handle some the same extensions devices - },{ - 'linerange' => 'Phone Ports', - 'type' => 'private', - 'key_num' => '1', - #somehow should obtain/create test customer with the test subscriber - discuss with alex - #'subscriber_id' => '1198', - 'extension_unit' => '2', - }], -}); +$test_machine->DATA_ITEM_STORE($fake_data->process('pbxdevices')); $test_machine->form_data_item( ); -# create 3 new billing models from DATA_ITEM -#$test_machine->check_create_correct( 3, sub{ $_[0]->{identifier} = sprintf('%x', (hex('0x'.$_[0]->{identifier}) + $_[1]->{i}) ); } ); -#$test_machine->check_get2put( ); +# create 3 new field pbx devices from DATA_ITEM +$test_machine->check_create_correct( 3, sub{ $_[0]->{identifier} = sprintf('%x', (hex('0x'.$_[0]->{identifier}) + $_[1]->{i}) ); } ); +$test_machine->check_get2put( ); $test_machine->check_bundle(); -$test_machine->check_delete_use_created(); +$test_machine->clear_test_data_all(); done_testing;