You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ngcp-panel/t/api-rest2/Contracts.yaml

1016 lines
29 KiB

---
#check options
-
name: check OPTIONS for contracts
type: item
method: OPTIONS
path: /api/contracts/
conditions:
is:
code: 200
header:
Accept-Post: application/hal+json; profile=http://purl.org/sipwise/ngcp-api/#rel-contracts
ok:
options:
- GET
- HEAD
- OPTIONS
- POST
#create a BillingProfile
-
name: create a BillingProfile
type: item
thread: 1
method: POST
path: /api/billingprofiles/
header:
Content-Type: application/json
Prefer: return=representation
content:
name: test profile ${unique_id}
handle: test_profile_handle${unique_id}
reseller_id: 1
conditions:
is:
code: 201
retain:
billing_profile_id: header.location
#create a Customer Contact
-
name: create a Customer Contact
type: item
method: POST
path: /api/customercontacts/
header:
Content-Type: application/json
content:
firstname: cust_contact_first
lastname: cust_contact_last
email: cust_contact@custcontact.invalid
reseller_id: 1
conditions:
is:
code: 201
retain:
customer_contact_path: header.location
customer_contact_id: header.location
#check CustomerContact
-
name: check CustomerContact
type: item
method: GET
path: '/${customer_contact_path}'
conditions:
is:
code: 200
#create a System Contact
-
name: create a System Contact
type: item
method: POST
path: /api/systemcontacts/
header:
Content-Type: application/json
content:
firstname: sys_contact_first
lastname: sys_contact_last
email: sys_contact@syscontact.invalid
conditions:
is:
code: 201
retain:
system_contact_path: header.location
system_contact_id: header.location
#get System Contact
-
name: get System Contact
type: item
method: GET
path: '/${system_contact_path}'
retain:
system_contact: body
#create batch
-
name: create batch
type: batch
method: POST
path: '/api/contracts/'
iterations: 6
header:
Content-Type: application/json
content:
status: active
contact_id: ${system_contact_id}
type: reseller
billing_profile_id: ${billing_profile_id}
retain:
contract_path: header.location
conditions:
is:
code: 201
#create invalid Contract with wrong type
-
name: create invalid Contract with wrong type
type: item
method: POST
path: '/api/contracts/'
header:
Content-Type: application/json
content:
status: active
contact_id: ${system_contact_id}
billing_profile_id: ${billing_profile_id}
type: invalid
conditions:
is:
code: 422
body.code: 422
like:
body.message: Validation failed.*type
#create invalid Contract with wrong billing profile
-
name: create invalid Contract with wrong billing profile
type: item
method: POST
path: '/api/contracts/'
header:
Content-Type: application/json
content:
status: active
contact_id: ${system_contact_id}
billing_profile_id: 999999
type: reseller
conditions:
is:
code: 422
body.code: 422
like:
body.message: Invalid 'billing_profile_id'
#create invalid Contract with customercontact
-
name: create invalid Contract with customercontact
type: item
method: POST
path: '/api/contracts/'
header:
Content-Type: application/json
content:
status: active
type: reseller
billing_profile_id: ${billing_profile_id}
contact_id: ${customer_contact_id}
conditions:
is:
code: 422
body.code: 422
like:
body.message: The contact_id is not a valid ngcp:systemcontacts item
#create invalid Contract without contact
-
name: create invalid Contract without contact
type: item
method: POST
path: '/api/contracts/'
header:
Content-Type: application/json
content:
status: active
type: reseller
billing_profile_id: ${billing_profile_id}
conditions:
is:
code: 422
#create invalid Contract with invalid status
-
name: create invalid Contract with invalid status
type: item
method: POST
path: '/api/contracts/'
header:
Content-Type: application/json
content:
status: invalid
type: reseller
billing_profile_id: ${billing_profile_id}
contact_id: ${system_contact_id}
conditions:
is:
code: 422
body.code: 422
like:
body.message: field='status'
#verify pagination
-
name: verify pagination
skip: 1
type: pagination
method: GET
path: '/api/contracts/?page=1&rows=5'
retain:
collection: body
conditions:
is:
code: 200
#check options on contract
-
name: check OPTIONS on contract
type: item
method: OPTIONS
path: '/${contract_path}'
conditions:
is:
code: 200
ok:
options:
- GET
- HEAD
- OPTIONS
- PUT
- PATCH
#get contract
-
name: GET contract
type: item
method: GET
path: '/${contract_path}'
retain:
contract: body
perl_code: !!perl/code |
{
my ($retained) = @_;
map { delete $_->{effective_start_time}; $_; } @{$retained->{contract}->{all_billing_profiles}};
}
conditions:
is:
code: 200
ok:
'${contract}.status': defined
'${contract}.type': defined
'${contract}.all_billing_profiles': defined
like:
'${contract}.billing_profile_id': '[0-9]+'
'${contract}.contact_id': '[0-9]+'
'${contract}.id': '[0-9]+'
is_deeply:
'${contract}.all_billing_profiles':
-
profile_id: ${billing_profile_id}
start: null
stop: null
#put contract with missing content-type
-
name: PUT contract with missing content-type
type: item
method: PUT
path: '/${contract_path}'
header:
Prefer: return=minimal
conditions:
is:
code: 415
#put contract with unsupported content type
-
name: PUT contract with unsupported Content-Type
type: item
method: PUT
path: '/${contract_path}'
header:
Content-Type: application/xxx
conditions:
is:
code: 415
#put contract with missing body
-
name: PUT contract with missing body
type: item
method: PUT
path: '/${contract_path}'
header:
Content-Type: application/json
Prefer: return=representation
conditions:
is:
code: 400
#put contract
-
name: PUT contract
type: item
method: PUT
path: '/${contract_path}'
header:
Content-Type: application/json
Prefer: return=representation
content: '${contract}'
retain:
new_contract: body
perl_code: !!perl/code |
{
my ($retained) = @_;
map { delete $_->{effective_start_time}; $_; } @{$retained->{new_contract}->{all_billing_profiles}};
}
conditions:
is:
code: 200
is_deeply:
'${contract}': ${new_contract}
ok:
'${new_contract}._links.ngcp:systemcontacts': defined
'${new_contract}._links.ngcp:billingprofiles': defined
#modify contract status
-
name: modify contract status
type: item
method: PATCH
path: '/${contract_path}'
header:
Content-Type: application/json-patch+json
Prefer: return=representation
content:
-
op: replace
path: /status
value: pending
retain:
modified_contract: body
conditions:
is:
code: 200
'${modified_contract}.status': pending
'${modified_contract}._links.self.href': ${contract_path}
'${modified_contract}._links.collection.href': /api/contracts/
#check patch with status undef
-
name: check patch with status undef
type: item
method: PATCH
path: '/${contract_path}'
header:
Content-Type: application/json-patch+json
Prefer: return=representation
content:
-
op: replace
path: /status
value: null
conditions:
is:
code: 422
#check patch with invalid status
-
name: check patch with invalid status
type: item
method: PATCH
path: '/${contract_path}'
header:
Content-Type: application/json-patch+json
Prefer: return=representation
content:
-
op: replace
path: /status
value: invalid
conditions:
is:
code: 422
#check patch with invalid contact_id
-
name: check patch with invalid contact_id
type: item
method: PATCH
path: '/${contract_path}'
header:
Content-Type: application/json-patch+json
Prefer: return=representation
content:
-
op: replace
path: /contact_id
value: 99999
conditions:
is:
code: 422
#check patch with customer contact_id
-
name: check patch with customer contact_id
type: item
method: PATCH
path: '/${contract_path}'
header:
Content-Type: application/json-patch+json
Prefer: return=representation
content:
-
op: replace
path: /contact_id
value: ${customer_contact_id}
conditions:
is:
code: 422
#check patch with undef billing_profile_id
-
name: check patch with undef billing_profile_id
type: item
method: PATCH
path: '/${contract_path}'
header:
Content-Type: application/json-patch+json
Prefer: return=representation
content:
-
op: replace
path: /billing_profile_id
value: null
conditions:
is:
code: 422
#check patch with invalid billing_profile_id
-
name: check patch with invalid billing_profile_id
type: item
method: PATCH
path: '/${contract_path}'
header:
Content-Type: application/json-patch+json
Prefer: return=representation
content:
-
op: replace
path: /billing_profile_id
value: 99999
conditions:
is:
code: 422
#multi-bill-prof: create another test billing profile
-
name: 'multi-bill-prof: create another test billing profile'
type: item
method: POST
path: '/api/billingprofiles/'
header:
Content-Type: application/json
Prefer: return=representation
content:
name: SECOND test profile ${unique_id}
handle: second_testprofile${unique_id}
reseller_id: 1
retain:
second_billing_profile_id: header.location
conditions:
is:
code: 201
perl_code: !!perl/code |
{
my ( $retained ) = @_;
my $dtf = DateTime::Format::Strptime->new(
pattern => '%F %T',
); #DateTime::Format::Strptime->new( pattern => '%Y-%m-%d %H:%M:%S' );
my $now = DateTime->now(
time_zone => DateTime::TimeZone->new(name => 'local')
);
my $t1 = $now->clone->add(days => 1);
my $t2 = $now->clone->add(days => 2);
my $t3 = $now->clone->add(days => 3);
my $billing_profile_id = $retained->{billing_profile_id};
$retained->{malformed_profilemappings1} = [ { profile_id => $billing_profile_id,
start => $dtf->format_datetime($now),
stop => $dtf->format_datetime($now),} ];
$retained->{malformed_profilemappings2} = [ { profile_id => $billing_profile_id,
start => $dtf->format_datetime($t1),
stop => $dtf->format_datetime($t1),} ];
$retained->{malformed_profilemappings3} = [ { profile_id => $billing_profile_id,
start => undef,
stop => $dtf->format_datetime($now),},];
$retained->{malformed_profilemappings4} = [ { profile_id => $billing_profile_id,
start => $dtf->format_datetime($t1),
stop => $dtf->format_datetime($t2),}, ];
$retained->{correct_profile_mappings1} = [ { profile_id => $retained->{second_billing_profile_id},
start => undef,
stop => undef, },
{ profile_id => $billing_profile_id,
start => $dtf->format_datetime($t1),
stop => $dtf->format_datetime($t2), },
{ profile_id => $billing_profile_id,
start => $dtf->format_datetime($t2),
stop => $dtf->format_datetime($t3), }
];
$retained->{correct_profile_mappings2} = [ { profile_id => $billing_profile_id,
start => $dtf->format_datetime($t1),
stop => $dtf->format_datetime($t2), },
{ profile_id => $billing_profile_id,
start => $dtf->format_datetime($t2),
stop => $dtf->format_datetime($t3), },
{ profile_id => $retained->{second_billing_profile_id},
start => $dtf->format_datetime($t3),
stop => undef, }
];
}
#multi-bill-prof POST: check 'start' timestamp is not in future
-
name: 'multi-bill-prof POST: check "start" timestamp is not in future'
type: item
method: POST
path: '/api/contracts/'
header:
Content-Type: application/json
content:
status: active
contact_id: ${system_contact_id}
type: reseller
max_subscriber: null
external_id: null
billing_profile_definition: profiles
billing_profiles: ${malformed_profilemappings1}
conditions:
is:
code: 422
#multi-bill-prof POST: check 'start' timestamp has to be before 'stop' timestamp
-
name: 'multi-bill-prof POST: check "start" timestamp has to be before "stop" timestamp'
type: item
method: POST
path: '/api/contracts/'
header:
Content-Type: application/json
content:
status: active
contact_id: ${system_contact_id}
type: reseller
max_subscriber: null
external_id: null
billing_profile_definition: profiles
billing_profiles: ${malformed_profilemappings2}
conditions:
is:
code: 422
#multi-bill-prof POST: check Interval with 'stop' timestamp but no 'start' timestamp specified
-
name: 'multi-bill-prof POST: check "Interval with "stop" timestamp but no "start" timestamp specified"'
type: item
method: POST
path: '/api/contracts/'
header:
Content-Type: application/json
content:
status: active
contact_id: ${system_contact_id}
type: reseller
max_subscriber: null
external_id: null
billing_profile_definition: profiles
billing_profiles: ${malformed_profilemappings3}
conditions:
is:
code: 422
#multi-bill-prof POST: check An initial interval without 'start' and 'stop' timestamps is required
-
name: 'multi-bill-prof POST: check An initial interval without "start" and "stop" timestamps is required'
type: item
method: POST
path: '/api/contracts/'
header:
Content-Type: application/json
content:
status: active
contact_id: ${system_contact_id}
type: reseller
max_subscriber: null
external_id: null
billing_profile_definition: profiles
billing_profiles: ${malformed_profilemappings4}
conditions:
is:
code: 422
#multi-bill-prof: create test contract
-
name: 'multi-bill-prof: create test contract'
type: item
method: POST
path: '/api/contracts/'
header:
Content-Type: application/json
content:
status: active
contact_id: ${system_contact_id}
type: reseller
max_subscriber: null
external_id: null
billing_profile_definition: profiles
billing_profiles: ${correct_profile_mappings1}
retain:
contract_path: header.location
conditions:
is:
code: 201
#get contract
-
name: GET contract
type: item
method: GET
path: '/${contract_path}'
retain:
contract: body
perl_code: !!perl/code |
{
my ($retained) = @_;
map { delete $_->{effective_start_time}; $_; } @{$retained->{contract}->{all_billing_profiles}};
$retained->{malformed_profilemappings4} = [ { profile_id => $retained->{billing_profile_id},
start => undef,
stop => undef,}, ];
}
conditions:
is:
code: 200
'${contract}.billing_profile_id': ${second_billing_profile_id}
ok:
'${contract}.profile_package_id': undefined
'${contract}.billing_profile_id': defined
'${contract}.billing_profiles': defined
'${contract}.all_billing_profiles': defined
is_deeply:
'${contract}.all_billing_profiles': ${correct_profile_mappings1}
#multi-bill-prof PATCH: check 'start' timestamp is not in future
-
name: 'multi-bill-prof PATCH: check "start" timestamp is not in future'
type: item
method: PATCH
path: '/${contract_path}'
header:
Content-Type: application/json-patch+json
Prefer: return=representation
content:
-
op: replace
path: /billing_profiles
value: ${malformed_profilemappings1}
conditions:
is:
code: 422
#multi-bill-prof PATCH: check 'start' timestamp has to be before 'stop' timestamp
-
name: 'multi-bill-prof PATCH: check "start" timestamp has to be before "stop" timestamp'
type: item
method: PATCH
path: '/${contract_path}'
header:
Content-Type: application/json-patch+json
Prefer: return=representation
content:
-
op: replace
path: /billing_profiles
value: ${malformed_profilemappings2}
conditions:
is:
code: 422
#multi-bill-prof PATCH: check Interval with 'stop' timestamp but no 'start' timestamp specified
-
name: 'multi-bill-prof PATCH: check Interval with "stop" timestamp but no "start" timestamp specified'
type: item
method: PATCH
path: '/${contract_path}'
header:
Content-Type: application/json-patch+json
Prefer: return=representation
content:
-
op: replace
path: /billing_profiles
value: ${malformed_profilemappings3}
conditions:
is:
code: 422
#multi-bill-prof PATCH: check Adding intervals without 'start' and 'stop' timestamps is not allowed.
-
name: 'multi-bill-prof PATCH: check Adding intervals without "start" and "stop" timestamps is not allowed.'
type: item
method: PATCH
path: '/${contract_path}'
header:
Content-Type: application/json-patch+json
Prefer: return=representation
content:
-
op: replace
path: /billing_profiles
value: ${malformed_profilemappings4}
conditions:
is:
code: 422
#multi-bill-prof PATCH: test if patching profile_package_id fails
-
name: 'multi-bill-prof PATCH: test if patching profile_package_id fails'
type: item
method: PATCH
path: '/${contract_path}'
header:
Content-Type: application/json-patch+json
Prefer: return=representation
content:
-
op: replace
path: /profile_package_id
value: null
conditions:
is:
code: 422
#multi-bill-prof PATCH: test contract with new billing profile
-
name: 'multi-bill-prof PATCH: test contract with new billing profile'
type: item
method: PATCH
path: '/${contract_path}'
header:
Content-Type: application/json-patch+json
Prefer: return=representation
retain:
patched_contract: body
content:
-
op: replace
path: /billing_profile_id
value: ${billing_profile_id}
perl_code: !!perl/code |
{
my ($retained) = @_;
$retained->{posted_profiles_number} = scalar @{$retained->{correct_profile_mappings1}} + 1;
$retained->{actual_profiles_number} = scalar @{$retained->{patched_contract}->{all_billing_profiles}};
my $now = DateTime->now(
time_zone => DateTime::TimeZone->new(name => 'local')
);
foreach my $m ( @{$retained->{patched_contract}->{billing_profiles}} ) {
if (!defined $m->{start}) {
push(@{$retained->{expected_mappings}},$m);
next;
}
my $s = $m->{start};
$s =~ s/^(\d{4}\-\d{2}\-\d{2})\s+(\d.+)$/$1T$2/;
my $start = DateTime::Format::ISO8601->parse_datetime($s);
$start->set_time_zone( DateTime::TimeZone->new(name => 'local') );
push(@{$retained->{expected_mappings}},$m) if ($start <= $now);
}
push ( @{$retained->{expected_mappings}}, @{$retained->{correct_profile_mappings2}} );
}
conditions:
is:
code: 200
'${patched_contract}.billing_profile_id': ${billing_profile_id}
'${posted_profiles_number}': '${actual_profiles_number}'
ok:
'${patched_contract}.profile_package_id': undefined
'${patched_contract}.billing_profile_id': defined
'${patched_contract}.billing_profiles': defined
'${patched_contract}.all_billing_profiles': defined
#multi-bill-prof: patch test contract
-
name: 'multi-bill-prof: patch test contract'
type: item
method: PATCH
path: '/${contract_path}'
header:
Content-Type: application/json-patch+json
Prefer: return=representation
retain:
patched_contract: body
content:
-
op: replace
path: /billing_profiles
value: ${correct_profile_mappings2}
conditions:
is:
code: 200
#get contract
-
name: GET contract
type: item
method: GET
path: '/${contract_path}'
retain:
got_contract: body
conditions:
is:
code: 200
'${patched_contract}.billing_profile_id': ${billing_profile_id}
ok:
'${patched_contract}.billing_profile_id': defined
'${patched_contract}.billing_profiles': defined
is_deeply:
'${got_contract}': '${patched_contract}'
#multi-bill-prof: put test contract
-
name: 'multi-bill-prof: put test contract'
type: item
method: PUT
path: '/${contract_path}'
header:
Content-Type: application/json
Prefer: return=representation
retain:
updated_contract: body
content:
status: active
contact_id: ${system_contact_id}
type: reseller
max_subscriber: null
external_id: null
billing_profile_definition: profiles
billing_profiles: ${correct_profile_mappings2}
conditions:
is:
code: 200
#get contract
-
name: GET contract
type: item
method: GET
path: '/${contract_path}'
retain:
got_contract: body
conditions:
is:
code: 200
'${updated_contract}.billing_profile_id': ${billing_profile_id}
ok:
'${updated_contract}.billing_profile_id': defined
'${updated_contract}.billing_profiles': defined
is_deeply:
'${got_contract}': '${updated_contract}'
#try to delete contact before terminating contracts
-
name: try to delete contact before terminating contracts
type: item
method: DELETE
path: '/api/systemcontacts/${system_contact_id}'
perl_code: !!perl/code |
{
my ($retained) = @_;
map { delete $_->{effective_start_time}; $_; } @{$retained->{patched_contract}->{billing_profiles}};
map { delete $_->{effective_start_time}; $_; } @{$retained->{updated_contract}->{billing_profiles}};
}
conditions:
is:
code: 423
is_deeply:
#perform tests against stripped mapping here, because deleting start_time would have affected previous is_deeply verification
'${patched_contract}.billing_profiles': '${expected_mappings}'
'${updated_contract}.billing_profiles': '${expected_mappings}'
#multi-bill-prof: terminate contract
-
name: 'multi-bill-prof: terminate contract'
type: item
method: PATCH
path: '/${contract_path}'
header:
Content-Type: application/json-patch+json
Prefer: return=representation
content:
-
op: replace
path: /status
value: terminated
conditions:
is:
code: 200
#try to get already terminated contract
-
name: try to get already terminated contract
type: item
method: GET
path: '/${contract_path}'
conditions:
is:
code: 404
#terminate billingprofile
-
name: 'terminate billingprofile'
type: item
method: PATCH
path: '/api/billingprofiles/${billing_profile_id}'
header:
Content-Type: application/json-patch+json
Prefer: return=representation
content:
-
op: replace
path: /status
value: terminated
conditions:
is:
code: 200
#get contract 1
-
name: 'get contract 1'
type: item
method: GET
path: '/api/contracts/1'
retain:
contract1: body
conditions:
is:
code: 200
'${contract1}.id': 1
'${contract1}.type': reseller
#check contract 1 can't be terminated
-
name: 'check contract 1 can not be terminated'
type: item
method: PATCH
path: '/api/contracts/1'
header:
Content-Type: application/json-patch+json
Prefer: return=representation
content:
-
op: replace
path: /status
value: terminated
conditions:
is:
code: 403
#get contract 1 again to verify billing.schedule_contract_billing_profile_network proc contains no implicit commits
-
name: 'get contract 1 again to verify billing.schedule_contract_billing_profile_network proc contains no implicit commits'
type: item
method: GET
path: '/api/contracts/1'
retain:
contract1: body
conditions:
is:
code: 200
'${contract1}.id': 1
'${contract1}.type': reseller
#check contract 1 can't be terminated again to verify billing.schedule_contract_billing_profile_network proc contains no implicit commits
-
name: 'check contract 1 can not be terminated again to verify billing.schedule_contract_billing_profile_network proc contains no implicit commits'
type: item
method: PATCH
path: '/api/contracts/1'
header:
Content-Type: application/json-patch+json
Prefer: return=representation
content:
-
op: replace
path: /status
value: terminated
conditions:
is:
code: 403