view release on metacpan or search on metacpan
0.175 2014-09-25 09:29 CEST
- Resource.pm: encode response body in UTF-8 before sending it out on the line
0.176 2014-10-14 17:31 CEST
- Dispatch/: add some comments
- Resource.pm: add debug message; add allow_nonref; find bug #57
0.177 2014-10-15 10:33 CEST
- start revamping path dispatch code in light of bug #57 (PUT request to
non-existent resource returns HTTP code 200 and null entity body)
- realize that it makes no sense to return 404 on a PUT request, since the
whole idea of PUT is to create a new resource
- the principal change is in Resource.pm->allowed_methods:
- the definition of each resource (in config/dispatch) should contain list of allowed methods
- when path is recognized, return the allowed methods from the resource definition
- when the path is not recognized _AND_ the method is PUT, return 405 Method Not Allowed
0.178 2014-10-15 16:41 CEST
- the design change in 0.177 caused a lot of breakage: put the pieces back together (WIP)
0.179 2014-10-15 22:54 CEST
'employee/current/priv' resource
- Model/Shared.pm: add some log messages in course of debugging a problem with
App::Dochazka::CLI
0.193 2014-10-21 08:35 CEST
- t/: fix accumulated brokenness in data model tests
- t/315-dispatch-employee-get.t: clean up comments and add a test case
0.194 2014-10-21 09:21 CEST
- Resource.pm: if method is GET and result is "No records found", return
404 instead of 200 + status object
- t/: adapt tests to this change
0.195 2014-10-21 10:51 CEST
- Model/Employee.pm->noof_employees_by_priv: if $priv is not a valid
privlevel, return 'OK' status + status code DISPATCH_NO_RECORDS_FOUND
to trigger a 404 Not Found response; also, put 'count' property in the
payload where it belongs
- t/315-dispatch-employee-get.t: adapt existing test case
0.196 2014-10-21 11:38 CEST
- config/dispatch_Top_Config.pm: make "echo" work with POST only; put
resources in alphabetical order
- t/: remove 'echo' tests from top-level PUT and DELETE units
0.197 2014-10-21 11:47 CEST
- work on development-checklist
- Util.pm: get rid of jury-rigged 'deep_copy' routine (use Storable::dclone
instead!)
0.251 2014-11-06 09:42 CET
- Dispatch/Schedule.pm->_intervals_delete was reporting success even when
nothing was actually deleted - fixed
- Model/Schedule.pm->schedule_all was crashing when no records found (because
$counter was not initialized) - fixed
- t/104-employee.t: deprecate expurgate in favor of TO_JSON
- t/dispatch/intervals.t: when no schedule records are in the database,
'schedule/all/...' will return 404 - fixed
- t/dispatch/schedule.t: add basic tests for 'schedule/all' and
'schedule/all/disabled'
0.252 2014-11-06 16:43 CET
- Build.PL: require App::Dochazka 0.181 for new boilerplate code
- schedule_Config.pm: rename '/schedule/intervals/:sid' to
'/schedule/sid/:sid'
- dbinit_Config.pm: add a trigger to make immutable/unupdatable the 'schedule'
field of the 'shedules' table
- add a 'SQL_SCHEDULE_UPDATE' statement to support updates on the
dispatch target
- t/dispatch/interval.pm: add some missing boilerplate tests
0.290 2014-11-19 11:23 CET
- interval_Config.pm: 'interval/nick/:nick/:tsrange' resource was broken due to
missing EOH - fixed
- t/dispatch/interval.t: $base for 'interval/nick/:nick/:tsrange' resource was
set to wrong value - fixed
0.291 2014-11-19 15:19 CET
- HTTP_Message_en.conf, Resources.pm: add 404 status trigger
- interval_Config.pm: call the hypothetical error code DISPATCH_TOO_MANY_RECORDS_FOUND
- top_Config.pm: fix factual error in documentation
- dispatch_Message_en.conf: add DISPATCH_TOO_MANY_RECORDS_FOUND definition
- Dispatch/Shared.pm->history: trigger 404 when no records found
- Model/Employee.pm: return DISPATCH_NO_RECORDS_FOUND with status level 'NOTICE'
- t/dispatch/history.t: explore more possibilities for entering an invalid EID;
adapt to current state (status-triggered 404 errors)
- t/dispatch/interval.t: add basic tests for 'interval/self/:tsrange'
0.292 2014-11-19 16:40 CET
- dispatch/interval_Config.pm: enable _fetch_* dispatch targets
- sql/interval_Config.pm: add SQL_INTERVAL_SELECT_BY_EID_AND_TSRANGE
- Dispatch/Interval.pm: implement _fetch_* dispatch targets
- Model/Interval.pm: implement a fetch_by_eid_and_tsrange function
- Model/Shared.pm: load_multiple had no provision for binding parameters -
fixed
- t/dispatch/interval.t: add some basic tests for
0.315 2014-11-28 16:23 CET
- got Path::Router validations to work!!!
- config/dispatch/activity_Config.pm: added validations clauses
- config/dispatch/employee_Config.pm: added validations clauses
- config/dispatch_Message_en.conf: delete DISPATCH_AID_DOES_NOT_EXIST and
DISPATCH_CODE_DOES_NOT_EXIST
- dbinit_Config.pm: change 'kosher_code' constraint on 'activities' table to
match the validations clause
- Dispatch/Activity.pm: noticed that we were still returning custom codes (e.g.
DISPATCH_AID_DOES_NOT_EXIST) instead of a simple 404 (405 on PUT) -- fixed
- t/dispatch/activity.t: fix tests broken by the above changes
0.316 2014-11-28 16:48 CET
- dispatch/employee_Config.pm: add validations clause to the
'employee/count/:priv' resource definition
- Dispatch/Employee.pm: handle upper/mixed case priv strings gracefully
- Model/Employee.pm: noof_employees_by_priv was written long ago - update it to
use best practices
- t/dispatch/employee.t: add 'employee/count/:priv' test cases
- Test.pm: include location header in return status (a-la Web::MREST)
- t/dispatch/top.t: migrate unit
0.383 2015-02-11 16:43 CET
- migrate Employee resources (WIP)
0.384 2015-02-12 07:31 CET
- support 'employee/search/nick/:key'
0.385 2015-02-12 09:22 CET
- Dispatch.pm: make 404 explanation in 'handler_get_employee_search_nick' more
descriptive
- move ACL.pm up one level in the directory structure, since the Dispatch/
directory will soon be gone
0.386 2015-02-12 09:44 CET
- Dispatch.pm: in 'GET employee/search/nick/:key', add '%' characters to :key
implicitly if none are provided (and note this in resource documentation)
- Model/Shared.pm: in load_multiple, mention search keys in the result
0.387 2015-02-12 10:13 CET
- Dispatch.pm: make 404 explanation more descriptive
- t/dispatch/employee.t: get unit running cleanly
0.388 2015-02-12 11:22 CET
- move Dispatch/Shared.pm up one directory level
- convert insert_employee and update_employee into ordinary functions and move
them to Shared.pm - to be manageable, Dispatch.pm should contain resource
handlers only
0.389 2015-02-12 14:40 CET
- Dispatch.pm, Shared.pm: migrating shared (non-handler) routines to Shared.pm
- Docs/Resource.pm: re-generate POD by latest docgen.plx
0.402 2015-02-17 18:30 CET
- t/model/schedule.t: fix brokenness previously hidden by a stale module file
in /usr/lib/perl5/site_perl
0.403 2015-02-18 11:59 CET
- use normalize_filespec to avoid $ENV{'HOME'}, which does not work on Windows
systems
0.404 2015-02-18 17:59 CET
- dispatch_Messages_en.conf, Auth.pm: define and use DISPATCH_ACL_CHECK_FAILED message
- Dispatch.pm: remove extraneous 'my'
0.405 2015-02-20 15:24 CET
- ACL.pm: add 'acl_check_is_me' - generalized check for handlers that have
acl_profile "passerby" but may only used to operate on one's own records
- ResourceDefs.pm, Dispatch.pm: use 'acl_check_is_me' in several handlers
0.406 2015-02-20 20:55 CET
- config/sql: add SQL_EMPLOYEE_SELECT_BY_SEC_ID
- ResourceDefs.pm: change ACL of 'GET schedule/all' so inactives and actives
can do it, too
- t/dispatch/schedule.t: add appropriate test cases
0.420 2015-04-04 21:18 CEST
- SQL: implement 'not_before_1892' function to enforce sane timestamp policy
(no dates before 1892 in the database)
- t/: adapt tests; add test cases
0.421 2015-04-05 13:34 CEST
- REST/Shared.pm: in 'shared_get_privsched', return 404 if no priv/schedule
assigned (instead of returning 200 OK with a null priv/schedule)
- t/dispatch/schedule.t: adapt tests
0.422 2015-04-05 20:45 CEST
- dbinit_Config.pm: make schedule_at_timestamp return SID instead of the
schedule JSON itself
- Model/Shared.pm: schedule_by_eid returns SID
- REST/Shared.pm: shared_get_privsched looks up the SID and returns the
entire schedule
- t/dispatch/schedule.t: adapt tests affected by the above change
- LDAP.pm: fix populate_employee() so it returns not_ok if nick is not in LDAP
- Dispatch.pm: implement handler_get_employee_ldap and handler_put_employee_ldap
- Auth.pm: fix DOCHAZKA_LDAP_AUTOCREATE_AS code path
0.472 2015-07-24 17:06 CEST
- doc: config/REST_Config.pm: tell users to not add a nick property to
DOCHAZKA_LDAP_POPULATE_MATRIX
- t/: test POST employee/nick without required nick property
- Dispatch.pm: return 400 if POST employee/nick without nick property
(fixes github issue #2)
- Dispatch.pm: handler_put_employee_ldap() return 404 if nick not found in LDAP
0.473 2015-07-25 03:45 CEST
- REST_SiteConfig.pm: add config file for overriding Web::MREST core params
since those are set first
- REST.pm: add a version() package method
- GET version now reports App::Dochazka::REST version instead of Web::MREST
version (Github issue #3)
- t/sql/disabled_to_zero.t: fix issue where test was not cleaning up after itself
- Dispatch.pm: write a debug message if LDAP is enabled
- MANIFEST: refrain from packaging release script
config/dispatch_Message_en.conf view on Meta::CPAN
DISPATCH_DATE_LIST_OR_TSRANGE
Request entity must contain either date_list or tsrange property (not both, not neither)
DOCHAZKA_MALFORMED_400
Status trigger for HTTP code 400 ("Malformed")
DOCHAZKA_FORBIDDEN_403
Status trigger for HTTP code 403 ("Forbidden")
DOCHAZKA_NOT_FOUND_404
Status trigger for HTTP code 404 ("Not Found")
DOCHAZKA_SESSION_TERMINATED
REST session terminated
DISPATCH_SCHEDULED_INTERVALS_CREATED
%s intervals created according to schedule
DISPATCH_SCHEDULED_NO_INTERVALS_CREATED
No intervals created
lib/App/Dochazka/REST/Dispatch.pm view on Meta::CPAN
# the resource to be documented should be in the request body - if not, return 400
my $docu_resource = $self->context->{'request_entity'};
if ( $docu_resource ) {
$log->debug( "handler_docu: request body is ->$docu_resource<-" );
} else {
$self->mrest_declare_status( 'code' => 400, 'explanation' => 'Missing request entity' );
return $fail;
}
# the resource should be defined - if not, return 404
my $def = $resources->{$docu_resource};
$log->debug( "handler_docu: resource definition is " . Dumper( $def ) );
if ( ref( $def ) ne 'HASH' ) {
$self->mrest_declare_status( 'code' => 404,
'explanation' => "Could not find resource definition for $docu_resource"
);
return $fail;
}
# all green - assemble the requested documentation
my $method = $self->context->{'method'};
my $resource_name = $self->context->{'resource_name'};
my $pl = {
'resource' => $docu_resource,
lib/App/Dochazka/REST/Dispatch.pm view on Meta::CPAN
my ( $self, $emp ) = @_;
$log->debug( "Entering " . __PACKAGE__ . "::_ldap_sync_pass1" );
my $status = $emp->ldap_sync();
$log->debug( "ldap_sync status: " . Dumper( $status ) );
if ( $status->not_ok ) {
if ( $status->code eq 'DOCHAZKA_LDAP_SYSTEM_USER_NOSYNC' ) {
# system user - 403
$status->{'http_code'} = 403;
} else {
$status->{'http_code'} = 404;
}
$self->mrest_declare_status( $status );
return 0;
}
$self->context->{'stashed_employee_object'} = $emp;
return 1;
}
=head3 handler_get_employee_ldap
lib/App/Dochazka/REST/Dispatch.pm view on Meta::CPAN
# second pass
my $key = $self->context->{'mapping'}->{'key'};
$key = "%$key%" unless $key =~ m/%/;
my $status = $CELL->status_ok;
$status = load_multiple(
conn => $self->context->{'dbix_conn'},
class => 'App::Dochazka::REST::Model::Employee',
sql => $site->SQL_EMPLOYEE_SELECT_MULTIPLE_BY_NICK,
keys => [ $key ],
);
# check for 404
if ( $status->level eq 'NOTICE' and $status->code eq 'DISPATCH_NO_RECORDS_FOUND' ) {
$self->mrest_declare_status( code => 404,
explanation => "DISPATCH_SEARCH_EMPTY",
args => [ 'employee', "nick LIKE $key" ],
);
return $fail;
}
return $status if $status->not_ok;
# found some employee objects
foreach my $emp ( @{ $status->payload } ) {
$emp = $emp->TO_JSON;
lib/App/Dochazka/REST/Dispatch.pm view on Meta::CPAN
$emp->eid,
$ts
);
} else {
die "BGUDFUUFF! Improper prop ->$prop<- seen!";
}
# - process return value
if ( $status->level eq 'NOTICE' and $status->code eq 'DISPATCH_NO_RECORDS_FOUND' ) {
my $tsmsg = ( $ts ) ? $ts : 'now';
$self->mrest_declare_status(
code => 404,
explanation => "No $prop history for $key $value as of $tsmsg",
);
return $fail;
} elsif ( $status->not_ok ) {
$self->mrest_declare_status(
code => 500,
explanation => $status->text,
);
return $fail;
}
lib/App/Dochazka/REST/Dispatch.pm view on Meta::CPAN
my $emp = $self->context->{'stashed_employee_obj'};
my $status = App::Dochazka::REST::Model::Shared::get_history(
$prop,
$context->{'dbix_conn'},
eid => $emp->eid,
nick => $emp->nick,
tsrange => $tsrange,
);
# - process return value
if ( $status->level eq 'NOTICE' and $status->code eq 'DISPATCH_NO_RECORDS_FOUND' ) {
$self->mrest_declare_status( code => 404, explanation => "No history for $key $value $tsrange" );
return $fail;
} elsif ( $status->not_ok ) {
$self->mrest_declare_status( code => 500, explanation => $status->text );
return $fail;
}
return $status;
}
=head3 handler_history_post
lib/App/Dochazka/REST/Dispatch.pm view on Meta::CPAN
$key = 'eid';
$value = $entity->{eid};
} elsif ( $entity->{nick} ) {
$key = 'nick';
$value = $entity->{nick};
} elsif ( $entity->{sec_id} ) {
$key = 'sec_id';
$value = $entity->{sec_id};
} else {
$self->mrest_declare_status(
code => 404,
explanation => "DISPATCH_EMPLOYEE_CANNOT_BE_DETERMINED"
);
return;
}
map { delete $entity->{$_} } ( 'eid', 'nick', 'sec_id' );
my $emp = shared_first_pass_lookup( $self, $key, $value );
return unless $emp->isa( 'App::Dochazka::REST::Model::Employee' );
return $emp;
}
lib/App/Dochazka/REST/Guide.pm view on Meta::CPAN
full range of functionality may be available only to administrators. See These
operations are special cases. Their ACL profile is either 'inactive' or
'active', but a non-administrator employee may still get a 403 Forbidden error
on the operation if they are trying to do something, such as update an interval
belonging to a different employee, that is reserved for administrators.
=item * B<Test for resource existence>
The next test a request undergoes on its quest to become a response is the
test of resource existence. If the request is asking for a non-existent resource,
e.g. L<http://dochazka.site/employee/curent>, it cannot be fulfilled and a "404
Not Found" response will be sent.
For GET requests, this is ordinarily the last cog in the state machine: if the
test passes, a "200 OK" response is typically sent, along with a response body.
(There are exceptions to this rule, however - see L<the AUTHORIZATION
chapter|"AUTHORIZATION">.) Requests using other methods (POST, PUT, DELETE) are
subject to further processing as described below.
=back
lib/App/Dochazka/REST/Guide.pm view on Meta::CPAN
C<PUT> and C<POST> requests may take a request body. If a request body is
expected or accepted, it must be a valid JSON string. (JSON is a simple way of
"stringifying" a data structure.)
=head2 HTTP response
The HTTP response returned by the REST server consists of:
=over
=item * Status code (e.g. 200, 400, 404, etc.)
=item * Headers
=item * Content body (or "response entity")
=back
=head3 Status
The HTTP standard stipulates a number of status codes. The server listens for
lib/App/Dochazka/REST/Guide.pm view on Meta::CPAN
=item C<200> (OK)
The request was accepted and processed. Refer to the response body for the
result.
=item C<204> ()
This code is returned on C<DELETE> requests when either the record was
successfully deleted or the resource did not exist in the first place.
=item C<404> (Not Found)
The resource specification given in the URI could not be associated with a
known resource.
=item C<405> (Method Not Allowed)
The resource was recognized but it is not defined for this method.
=item C<401> (Not authorized)
lib/App/Dochazka/REST/Model/Employee.pm view on Meta::CPAN
$priv = lc $priv;
if ( $priv eq 'total' ) {
my $count = noof( $conn, 'employees' );
return $CELL->status_ok(
'DISPATCH_COUNT_EMPLOYEES',
args => [ $count, $priv ],
payload => { count => $count } );
}
return $CELL->status_err( 'DOCHAZKA_NOT_FOUND_404' ) unless
$priv =~ m/^(passerby)|(inactive)|(active)|(admin)$/i;
my $sql = $site->SQL_EMPLOYEE_COUNT_BY_PRIV_LEVEL;
my ( $count ) = @{ select_single( conn => $conn, sql => $sql, keys => [ $priv ] )->payload };
$log->debug( "select_single returned: $count" );
$count += 0;
$CELL->status_ok( 'DISPATCH_COUNT_EMPLOYEES', args => [ $count, $priv ],
payload => { 'priv' => $priv, 'count' => $count } );
}
lib/App/Dochazka/REST/Shared.pm view on Meta::CPAN
$thing = 'schedule';
$status = App::Dochazka::REST::Model::Schedule->load_by_sid( $conn, $value );
} elsif ( $key eq 'scode' ) {
$thing = 'schedule';
$status = App::Dochazka::REST::Model::Schedule->load_by_scode( $conn, $value );
} else {
die "shared_first_pass_lookup could not do anything with key $key!";
}
if ( $status->level eq 'NOTICE' and $status->code eq 'DISPATCH_NO_RECORDS_FOUND' ) {
$d_obj->mrest_declare_status( code => 404,
explanation => 'DISPATCH_SEARCH_EMPTY',
args => [ $thing, "$key equals $value" ],
);
return;
}
if ( $status->not_ok ) {
$d_obj->mrest_declare_status( code => 500, explanation => $status->code,
args => $status->args
);
return;
lib/App/Dochazka/REST/Shared.pm view on Meta::CPAN
#
if (
! acl_check_is_my_report( $d_obj, ( lc $key ) => $value ) and
! acl_check_is_me( $d_obj, ( lc $key ) => $value )
)
{
$d_obj->mrest_declare_status( code => 403, explanation => "DISPATCH_KEEP_TO_YOURSELF" );
return 0;
}
#
# 404 check
#
my $emp = shared_first_pass_lookup( $d_obj, $key, $value );
return 0 unless $emp;
$d_obj->context->{'stashed_employee_object'} = $emp;
return 1;
}
=head2 shared_get_employee
lib/App/Dochazka/REST/Shared.pm view on Meta::CPAN
# first pass
if ( $pass == 1 ) {
#
# 403 (ACL) check - passerby can only look up him- or herself
#
if ( ! acl_check_is_me( $d_obj, ( lc $key ) => $value ) ) {
$d_obj->mrest_declare_status( code => 403, explanation => "DISPATCH_KEEP_TO_YOURSELF" );
return 0;
}
#
# 404 check
#
my $emp = shared_first_pass_lookup( $d_obj, $key => $value );
return 0 unless $emp;
$d_obj->context->{'stashed_employee_object'} = $emp;
return 1;
}
# second pass
# - initialization
lib/App/Dochazka/REST/Shared.pm view on Meta::CPAN
if ( $return_value and $t eq 'schedule' ) {
# $return_value is SID of the schedule, but we want the schedule itself
my $status = App::Dochazka::REST::Model::Schedule->load_by_sid( $conn, $return_value );
$return_value = $status->payload;
}
my @privsched = ( $t, $return_value );
if ( $ts ) {
if ( ! $return_value ) {
$d_obj->mrest_declare_status(
code => 404,
explanation => "Employee $nick (EID $eid) has no $t assigned as of $ts"
);
return $CELL->status_not_ok;
}
my $code;
if ( 'PRIV' eq uc( $t ) ) {
$code = 'DISPATCH_EMPLOYEE_PRIV_AS_AT';
} elsif ( 'SCHEDULE' eq uc( $t ) ) {
$code = 'DISPATCH_EMPLOYEE_SCHEDULE_AS_AT';
} else {
lib/App/Dochazka/REST/Shared.pm view on Meta::CPAN
payload => {
eid => $eid += 0, # "numify"
nick => $emp->nick,
timestamp => $ts,
@privsched,
},
);
} else {
if ( ! $return_value ) {
$d_obj->mrest_declare_status(
code => 404,
explanation => "Employee $nick (EID $eid) has no $t assigned"
);
return $CELL->status_not_ok;
}
my $code;
if ( 'PRIV' eq uc( $t ) ) {
$code = 'DISPATCH_EMPLOYEE_PRIV';
} elsif ( 'SCHEDULE' eq uc( $t ) ) {
$code = 'DISPATCH_EMPLOYEE_SCHEDULE';
} else {
t/dispatch/activity.t view on Meta::CPAN
ok( defined $status->payload );
is( $status->payload->{'remark'}, 'puppy', "POST $base 6" );
is( $status->payload->{'long_desc'}, 'wop wop ng', "POST $base 7" );
note( 'non-existent AID and also out of range' );
$activity_obj = '{ "aid" : 3434342342342, "long_desc" : 3434341, "remark" : 34334342 }';
dbi_err( $test, 500, 'root', 'POST', $base, $activity_obj, qr/out of range for type integer/ );
note( 'non-existent AID' );
$activity_obj = '{ "aid" : 342342342, "long_desc" : 3434341, "remark" : 34334342 }';
req( $test, 404, 'root', 'POST', $base, $activity_obj );
note( 'throw a couple curve balls' );
my $weirded_object = '{ "copious_turds" : 555, "long_desc" : "wang wang wazoo", "disabled" : "f" }';
req( $test, 400, 'root', 'POST', $base, $weirded_object );
my $no_closing_bracket = '{ "copious_turds" : 555, "long_desc" : "wang wang wazoo", "disabled" : "f"';
req( $test, 400, 'root', 'POST', $base, $no_closing_bracket );
$weirded_object = '{ "aid" : "!!!!!", "long_desc" : "down it goes" }';
dbi_err( $test, 500, 'root', 'POST', $base, $weirded_object, qr/invalid input syntax for type integer/ );
t/dispatch/activity.t view on Meta::CPAN
code => 'WORK',
long_desc => 'Work',
remark => 'dbinit',
disabled => 0,
}, "GET $base/:aid 4" );
note( "fail invalid (non-integer) AID" );
req( $test, 400, 'active', 'GET', "$base/jj" );
note( "fail non-existent AID" );
req( $test, 404, 'active', 'GET', "$base/444" );
note( "succeed disabled AID" );
$status = req( $test, 200, 'active', 'GET', "$base/$aid_of_foobar" );
is( $status->level, 'OK', "GET $base/:aid 13" );
is( $status->code, 'DISPATCH_ACTIVITY_FOUND', "GET $base/:aid 14" );
is_deeply( $status->payload, {
aid => $aid_of_foobar,
code => 'FOOBAR',
long_desc => undef,
remark => undef,
t/dispatch/activity.t view on Meta::CPAN
note( 'active fail 403' );
req( $test, 403, 'active', 'DELETE', "$base/1" );
note( 'root success' );
note( "DELETE $base/$aid_of_foobar" );
$status = req( $test, 200, 'root', 'DELETE', "$base/$aid_of_foobar" );
is( $status->level, 'OK', "DELETE $base/:aid 3" );
is( $status->code, 'DOCHAZKA_CUD_OK', "DELETE $base/:aid 4" );
note( 'really gone' );
req( $test, 404, 'active', 'GET', "$base/$aid_of_foobar" );
note( 'root fail invalid AID' );
req( $test, 400, 'root', 'DELETE', "$base/asd" );
note( '=============================' );
note( '"activity/all" resource' );
note( '=============================' );
$base = 'activity/all';
docu_check($test, $base);
t/dispatch/activity.t view on Meta::CPAN
is( $status->code, 'DISPATCH_ACTIVITY_FOUND', "GET $base/:code 6" );
is_deeply( $status->payload, {
aid => $aid_of_foobar,
code => 'FOOBAR',
long_desc => undef,
remark => 'bazblat',
disabled => 0,
}, "GET $base/:code 7" );
note( 'non-existent code' );
req( $test, 404, 'root', 'GET', "$base/jj" );
note( 'invalid code' );
foreach my $invalid_code (
'!!!! !134@@',
'whiner*44',
'@=1337',
'/ninety/nine/luftbalons//',
) {
foreach my $user ( qw( root demo ) ) {
req( $test, 400, $user, 'GET', "$base/$invalid_code" );
t/dispatch/activity.t view on Meta::CPAN
note( "POST on $base/:code" );
req( $test, 405, 'demo', 'POST', "$base/WORK" );
req( $test, 405, 'active', 'POST', "$base/WORK" );
req( $test, 405, 'root', 'POST', "$base/WORK" );
note( "DELETE on $base/:code" );
note( 'demo fail 403 once' );
req( $test, 403, 'demo', 'DELETE', "$base/FOOBAR1" );
note( 'root fail 404' );
req( $test, 404, 'root', 'DELETE', "$base/FOOBAR1" );
note( 'demo fail 403 a second time' );
req( $test, 403, 'demo', 'DELETE', "$base/FOOBAR" );
note( "root success: DELETE $base/FOOBAR" );
$status = req( $test, 200, 'root', 'DELETE', "$base/FOOBAR" );
is( $status->level, 'OK', "DELETE $base/FOOBAR 3" );
is( $status->code, 'DOCHAZKA_CUD_OK', "DELETE $base/FOOBAR 4" );
note( "really gone" );
req( $test, 404, 'root', 'GET', "$base/FOOBAR" );
note( "root: fail invalid code" );
req( $test, 400, 'root', 'DELETE', "$base/!!!" );
note( "delete FOOBARPUS, too" );
$status = req( $test, 200, 'root', 'DELETE', "$base/foobarpus" );
is( $status->level, 'OK', "DELETE $base/foobarpus 2" );
is( $status->code, 'DOCHAZKA_CUD_OK', "DELETE $base/foobarpus 3" );
note( "teardown" );
t/dispatch/component.t view on Meta::CPAN
ok( -o File::Spec->catfile( $comp_root, $status->payload->{path} ) );
is( $full_path_of_foowop, File::Spec->catfile( $comp_root, $status->payload->{path} ) );
is( "wop wop ng", read_file( $full_path_of_foowop ) );
note( 'non-existent cid and also out of range' );
$component_obj = '{ "cid" : 3434342342342, "source" : 3434341, "acl" : "passerby" }';
dbi_err( $test, 500, 'root', 'POST', $base, $component_obj, qr/out of range for type integer/ );
note( 'non-existent cid' );
$component_obj = '{ "cid" : 342342342, "source" : 3434341, "acl" : "passerby" }';
req( $test, 404, 'root', 'POST', $base, $component_obj );
note( 'throw a couple curve balls' );
my $weirded_object = '{ "copious_turds" : 555, "source" : "wang wang wazoo", "acl" : "passerby" }';
req( $test, 400, 'root', 'POST', $base, $weirded_object );
my $no_closing_bracket = '{ "copious_turds" : 555, "source" : "wang wang wazoo", "acl" : "passerby"';
req( $test, 400, 'root', 'POST', $base, $no_closing_bracket );
$weirded_object = '{ "cid" : "!!!!!", "source" : "down it goes" }';
dbi_err( $test, 500, 'root', 'POST', $base, $weirded_object, qr/invalid input syntax for type integer/ );
t/dispatch/component.t view on Meta::CPAN
path => 'FOOBAR',
source => 'wombat',
acl => 'passerby',
validations => undef,
}, "GET $base/:cid 4" );
note( "fail invalid (non-integer) cid" );
req( $test, 400, 'root', 'GET', "$base/jj" );
note( "fail non-existent cid" );
req( $test, 404, 'root', 'GET', "$base/444" );
note( "PUT on $base/:cid" );
$component_obj = '{ "path" : "FOOBAR", "source" : "The bar of foo", "acl" : "inactive" }';
# - test with demo fail 403
req( $test, 403, 'demo', 'PUT', "$base/$cid_of_foobar", $component_obj );
note( 'test with root (successful update)' );
$status = req( $test, 200, 'root', 'PUT', "$base/$cid_of_foobar", $component_obj );
is( $status->level, 'OK', "PUT $base/:cid 3" );
is( $status->code, 'DOCHAZKA_CUD_OK', "PUT $base/:cid 4" );
t/dispatch/component.t view on Meta::CPAN
req( $test, 403, 'demo', 'DELETE', "$base/$cid_of_foobar" );
note( 'root success' );
note( "DELETE $base/$cid_of_foobar" );
ok( -e $full_path_of_foobar );
$status = req( $test, 200, 'root', 'DELETE', "$base/$cid_of_foobar" );
is( $status->level, 'OK', "DELETE $base/:cid 3" );
is( $status->code, 'DOCHAZKA_CUD_OK', "DELETE $base/:cid 4" );
note( 'really gone' );
req( $test, 404, 'root', 'GET', "$base/$cid_of_foobar" );
ok( ! -e $full_path_of_foobar );
note( 'root fail invalid cid' );
req( $test, 400, 'root', 'DELETE', "$base/asd" );
note( "=============================" );
note( "'component/path' resource" );
note( "=============================" );
$base = 'component/path';
t/dispatch/employee.t view on Meta::CPAN
is( $mrsfu->nick, $mrsfuprime->nick, 'POST employee/eid 10' );
is( $mrsfu->fullname, $mrsfuprime->fullname, 'POST employee/eid 10' );
is( $mrsfu->email, $mrsfuprime->email, 'POST employee/eid 10' );
is( $mrsfu->remark, $mrsfuprime->remark, 'POST employee/eid 10' );
note( "attempt as demo and root to update Mr./Mrs. Fu to a non-existent EID" );
#diag("--- POST employee/eid (non-existent EID)");
req( $test, 403, 'demo', 'POST', $base, '{ "eid" : 5442' );
req( $test, 400, 'root', 'POST', $base, '{ "eid" : 5442' );
req( $test, 403, 'demo', 'POST', $base, '{ "eid" : 5442 }' );
req( $test, 404, 'root', 'POST', $base, '{ "eid" : 5442 }' );
req( $test, 404, 'root', 'POST', $base, '{ "eid": 534, "nick": "mrfu", "fullname":"Lizard Scale" }' );
note( 'missing EID' );
req( $test, 400, 'root', 'POST', $base, '{ "long-john": "silber" }' );
note( 'incorrigibly attempt to update totally bogus and invalid EIDs' );
req( $test, 400, 'root', 'POST', $base, '{ "eid" : }' );
req( $test, 400, 'root', 'POST', $base, '{ "eid" : jj }' );
$status = req( $test, 500, 'root', 'POST', $base, '{ "eid" : "jj" }' );
like( $status->text, qr/invalid input syntax for type integer/ );
t/dispatch/employee.t view on Meta::CPAN
ok( exists $status->payload->{'fullname'} );
is( $status->payload->{'fullname'}, $params->[3] );
}
note( "GET $base/2 as demo" );
req( $test, 200, 'demo', 'GET', "$base/2" );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_EMPLOYEE_FOUND' );
note( "GET $base/53432 as root" );
req( $test, 404, 'root', 'GET', "$base/53432" );
note( "GET $base/53432 as demo" );
req( $test, 403, 'demo', 'GET', "$base/53432" );
note( 'invalid EIDs caught by Path::Router validations clause' );
foreach my $eid ( @invalid_eids ) {
foreach my $user ( qw( root demo ) ) {
req( $test, 400, $user, 'GET', "$base/$eid" );
}
}
t/dispatch/employee.t view on Meta::CPAN
is( $mrfu->nick, 'mrfu' );
my $mrfuprime = App::Dochazka::REST::Model::Employee->spawn( eid => $eid_of_brchen,
nick => 'mrfu', fullname => 'Lizard Scale', email => 'mrfu@dragon.cn',
salt => 'tasty', sync => 0 );
is_deeply( $mrfu, $mrfuprime );
$eid_of_mrfu = $mrfu->eid;
is( $eid_of_mrfu, $eid_of_brchen );
note( 'provide non-existent EID' );
req( $test, 403, 'demo', 'PUT', "$base/5633", '{' );
req( $test, 404, 'root', 'PUT', "$base/5633", '{' );
req( $test, 403, 'demo', 'PUT', "$base/5633",
'{ "nick": "mrfu", "fullname":"Lizard Scale" }' );
req( $test, 404, 'root', 'PUT', "$base/5633",
'{ "eid": 534, "nick": "mrfu", "fullname":"Lizard Scale" }' );
note( 'with valid JSON that is not what we are expecting' );
req( $test, 400, 'root', 'PUT', "$base/2", 0 );
note( 'another kind of bogus JSON' );
$status = req( $test, 200, 'root', 'PUT', "$base/2", '{ "legal" : "json" }' );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_UPDATE_NO_CHANGE_OK' );
t/dispatch/employee.t view on Meta::CPAN
note( 'employee/eid/:eid - delete cannonfodder' );
req( $test, 403, 'demo', 'DELETE', "$base/$eid_of_cf" );
req( $test, 403, 'active', 'DELETE', "$base/$eid_of_cf" );
req( $test, 401, 'unknown', 'DELETE', "$base/$eid_of_cf" ); # 401 because 'unknown' doesn't exist
$status = req( $test, 200, 'root', 'DELETE', "$base/$eid_of_cf" );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
note( 'attempt to get cannonfodder - not there anymore' );
req( $test, 403, 'demo', 'GET', "$base/$eid_of_cf" );
req( $test, 404, 'root', 'GET', "$base/$eid_of_cf" );
note( 'create another "cannon fodder" employee' );
$cf = create_bare_employee( { nick => 'cannonfodder' } );
ok( $cf->eid > $eid_of_cf ); # EID will have incremented
$eid_of_cf = $cf->eid;
note( 'delete the sucker' );
req( $test, 403, 'demo', 'DELETE', '/employee/nick/cannonfodder' );
$status = req( $test, 200, 'root', 'DELETE', '/employee/nick/cannonfodder' );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
note( 'attempt to get cannonfodder - not there anymore' );
req( $test, 403, 'demo', 'GET', "$base/$eid_of_cf" );
req( $test, 404, 'root', 'GET', "$base/$eid_of_cf" );
note( 'attempt to delete "root the immutable" (won\'t work)' );
dbi_err( $test, 500, 'root', 'DELETE', "$base/1", undef, qr/immutable/i );
note( 'invalid EIDs caught by Path::Router validations clause' );
foreach my $eid ( @invalid_eids ) {
foreach my $user ( qw( root demo ) ) {
req( $test, 400, $user, 'GET', "$base/$eid" );
}
}
note( '=============================' );
note( '"employee/eid/:eid/minimal" resource' );
note( '=============================' );
$base = 'employee/eid';
docu_check($test, "$base/:eid/minimal");
note( 'root attempt to get non-existent EID (minimal)' );
req( $test, 404, 'root', 'GET', "$base/53432/minimal" );
note( 'demo attempt to get non-existent EID (minimal)' );
req( $test, 403, 'demo', 'GET', "$base/53432/minimal" );
note( 'demo attempt to get existent EID (minimal)' );
note( 'DOCHAZKA_EMPLOYEE_MINIMAL_FIELDS is ' . Dumper( $site->DOCHAZKA_EMPLOYEE_MINIMAL_FIELDS ) );
req( $test, 403, 'demo', 'GET', "$base/" . $site->DOCHAZKA_EID_OF_ROOT . "/minimal" );
note( 'root get active (minimal)' );
$status = req( $test, 200, 'root', 'GET', "$base/$ts_eid_active/minimal" );
t/dispatch/employee.t view on Meta::CPAN
is( $status->payload->{'nick'}, 'demo' );
ok( exists $status->payload->{'fullname'} );
is( $status->payload->{'fullname'}, 'Demo Employee' );
note( "GET $base/demo" );
req( $test, 200, 'demo', 'GET', "$base/demo" );
is( $status->level, "OK" );
is( $status->code, 'DISPATCH_EMPLOYEE_FOUND' );
note( "GET $base/nick/{various bogus nicks}" );
req( $test, 404, 'root', 'GET', "$base/53432" );
req( $test, 403, 'demo', 'GET', "$base/53432" );
req( $test, 404, 'root', 'GET', "$base/heathledger" );
# this one triggers "wide character in print" warnings
#req( $test, 404, 'root', 'GET', "$base/" . uri_escape_utf8('/employee/nick//////áÄÄoÄÅ¡ÄqwšášÄšýš..-...-...-..-.00') );
note( 'single-character nicks' );
$status = req( $test, 404, 'root', 'GET', "$base/4" );
note( "PUT employee/nick/:nick" );
note( 'demo cannot PUT no matter what' );
req( $test, 403, 'demo', 'PUT', "$base/mrsfu", '{' );
note( 'root can PUT, but JSON entity is invalid' );
req( $test, 400, 'root', 'PUT', "$base/mrsfu", '{' );
t/dispatch/employee.t view on Meta::CPAN
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_EMPLOYEE_FOUND' );
note( 'DELETE "employee/nick/:nick" with nick cannonfodder' );
req( $test, 403, 'demo', 'DELETE', $base . "/" . $cf->nick );
$status = req( $test, 200, 'root', 'DELETE', $base . "/" . $cf->nick );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
note( 'attempt to get cannonfodder - not there anymore' );
req( $test, 404, 'root', 'GET', "$base/cannonfodder" );
note( 'attempt to get in a different way' );
$status = App::Dochazka::REST::Model::Employee->load_by_nick( $dbix_conn, 'cannonfodder' );
is( $status->level, 'NOTICE' );
is( $status->code, 'DISPATCH_NO_RECORDS_FOUND' );
note( 'create another "cannon fodder" employee' );
$cf = create_bare_employee( { nick => 'cannonfodder' } );
ok( $cf->eid > $eid_of_cf ); # EID will have incremented
$eid_of_cf = $cf->eid;
note( 'get cannonfodder - again, no problem' );
$status = req( $test, 200, 'root', 'GET', "$base/cannonfodder" );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_EMPLOYEE_FOUND' );
note( 'delete with a typo (non-existent nick)' );
req( $test, 403, 'demo', 'DELETE', "$base/cannonfoddertypo" );
req( $test, 404, 'root', 'DELETE', "$base/cannonfoddertypo" );
note( 'attempt to get cannonfodder - still there' );
$status = req( $test, 200, 'root', 'GET', "$base/cannonfodder" );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_EMPLOYEE_FOUND' );
note( 'tear down testing employee' );
delete_bare_employee( $eid_of_cf );
note( 'attempt to delete \'root the immutable\' (won\'t work)' );
dbi_err( $test, 500, 'root', 'DELETE', "$base/root", undef, qr/immutable/i );
note( '=============================' );
note( '"employee/nick/:nick/minimal" resource' );
note( '=============================' );
$base = 'employee/nick';
docu_check($test, "$base/:nick/minimal");
note( 'root attempt to get non-existent nick (minimal)' );
req( $test, 404, 'root', 'GET', "$base/53432/minimal" );
note( 'demo attempt to get non-existent nick (minimal)' );
req( $test, 403, 'demo', 'GET', "$base/53432/minimal" );
note( 'demo attempt to get existent nick (minimal)' );
req( $test, 403, 'demo', 'GET', "$base/root/minimal" );
note( 'root get active (minimal)' );
$status = req( $test, 200, 'root', 'GET', "$base/active/minimal" );
is( $status->level, 'OK' );
t/dispatch/employee.t view on Meta::CPAN
is_deeply( $status->payload, $mustr );
note( '=============================' );
note( '"employee/sec_id/:sec_id/minimal" resource' );
note( '=============================' );
$base = 'employee/sec_id';
docu_check($test, "$base/:sec_id/minimal");
note( 'root attempt to get non-existent sec_id (minimal)' );
req( $test, 404, 'root', 'GET', "$base/53432/minimal" );
note( 'demo attempt to get non-existent sec_id (minimal)' );
req( $test, 403, 'demo', 'GET', "$base/53432/minimal" );
note( 'set root\'s sec_id to be foobar' );
my $eid_of_root = $site->DOCHAZKA_EID_OF_ROOT;
$status = req( $test, 200, 'root', 'POST', 'employee/eid', <<"EOS" );
{ "eid" : $eid_of_root, "sec_id" : "foobar" }
EOS
is( $status->level, 'OK' );
t/dispatch/history.t view on Meta::CPAN
ok( exists $status->payload->{'history'} );
is( scalar @{ $status->payload->{'history'} }, 1 );
is( $status->payload->{'history'}->[0]->{'eid'}, $site->DOCHAZKA_EID_OF_ROOT );
ok( exists $status->payload->{'history'}->[0]->{'effective'} );
note( 'get history of non-existent EID' );
note( 'fail 403 as demo' );
req( $test, 403, 'demo', 'GET', "$base/4534" );
note( '"succeed" (404) as root' );
req( $test, 404, 'root', 'GET', "$base/4534" );
note( 'GET history of various invalid EIDs' );
foreach my $inv_eid ( 'asas', '!*!*', 'A long list of useless words followed by lots of spaces \\,', '3.1415926', '; drop database dochazka-test;' ) {
foreach my $user ( qw( demo root ) ) {
req( $test, 400, 'demo', 'GET', "$base/$inv_eid" );
}
}
foreach my $inv_eid ( '0', '-1' ) {
# - as demo
req( $test, 403, 'demo', 'GET', "$base/$inv_eid" );
# - as root
req( $test, 404, 'root', 'GET', "$base/$inv_eid" );
}
foreach my $inv_eid ( '3443/plus/several/bogus/levels/of/subresources' ) {
# - as demo (entire resource is invalid, so ACL check is not reached)
req( $test, 400, 'demo', 'GET', "$base/$inv_eid" );
# - as root
req( $test, 400, 'root', 'GET', "$base/$inv_eid" );
}
note( 'PUT' );
t/dispatch/history.t view on Meta::CPAN
is( scalar @{ $status->payload->{'history'} }, 1 );
is( $status->payload->{'history'}->[0]->{'eid'}, $site->DOCHAZKA_EID_OF_ROOT );
ok( exists $status->payload->{'history'}->[0]->{'effective'} );
my $uri = $base . '/' . $site->DOCHAZKA_EID_OF_ROOT .
'/[1999-12-31 23:59, 2000-01-01 00:01)';
note( 'fail 403 as demo' );
req( $test, 403, 'demo', 'GET', $uri );
note( '"succeed" (404) as root' );
req( $test, 404, 'root', 'GET', $uri );
note( 'non-existent EID');
my $tsr = '[1999-12-31 23:59, 2000-01-01 00:01)';
req( $test, 403, 'demo', 'GET', "$base/4534/$tsr" );
req( $test, 404, 'root', 'GET', "$base/4534/$tsr" );
note( 'invalid EID (caught by Path::Router validations)' );
foreach my $user ( qw( demo root ) ) {
req( $test, 400, $user, 'GET', "$base/asas/$tsr" );
}
note( 'PUT, POST, DELETE' );
foreach my $user ( qw( demo root ) ) {
foreach my $method ( qw( PUT POST DELETE ) ) {
req( $test, 405, $user, $method, "$base/23/[,)" );
t/dispatch/history.t view on Meta::CPAN
BAIL_OUT(0);
}
ok( exists $status->payload->{'effective'} );
my $uri = $base . '/' . $site->DOCHAZKA_EID_OF_ROOT .
'/"1891-12-31 23:59:59"';
note( 'fail 403 as demo' );
req( $test, 403, 'demo', 'GET', $uri );
note( '"succeed" (404) as root' );
req( $test, 404, 'root', 'GET', $uri );
note( 'non-existent EID');
my $ts = '\'2015-01-06 14:55\'';
req( $test, 403, 'demo', 'GET', "$base/4534/$ts" );
req( $test, 404, 'root', 'GET', "$base/4534/$ts" );
note( 'invalid EID (caught by Path::Router validations)' );
foreach my $user ( qw( demo root ) ) {
req( $test, 400, $user, 'GET', "$base/asas/$ts" );
}
note( 'PUT, POST, DELETE' );
foreach my $user ( qw( demo root ) ) {
foreach my $method ( qw( PUT POST DELETE ) ) {
req( $test, 405, $user, $method, "$base/23/1966-09-28 00:00" );
t/dispatch/history.t view on Meta::CPAN
}
ok( exists $status->payload->{'effective'} );
my $uri = $base . '/' . $site->DOCHAZKA_EID_OF_ROOT . '/now';
note( 'fail 403 as demo' );
req( $test, 403, 'demo', 'GET', $uri );
$uri = $base . '/' . $site->DOCHAZKA_EID_OF_DEMO . '/now';
note( '"succeed" (404) as root' );
req( $test, 404, 'root', 'GET', $uri );
note( 'non-existent EID');
my $ts = '\'2015-01-06 14:55\'';
req( $test, 403, 'demo', 'GET', "$base/4534/now" );
req( $test, 404, 'root', 'GET', "$base/4534/now" );
note( 'invalid EID (caught by Path::Router validations)' );
foreach my $user ( qw( demo root ) ) {
req( $test, 400, $user, 'GET', "$base/asas/now" );
}
note( 'PUT, POST, DELETE' );
foreach my $user ( qw( demo root ) ) {
foreach my $method ( qw( PUT POST DELETE ) ) {
req( $test, 405, $user, $method, "$base/23/now" );
t/dispatch/history.t view on Meta::CPAN
ok( defined $status->payload );
ok( exists $status->payload->{'nick'} );
is( $status->payload->{'nick'}, 'root' );
ok( exists $status->payload->{'history'} );
is( scalar @{ $status->payload->{'history'} }, 1 );
is( $status->payload->{'history'}->[0]->{'eid'}, 1 );
ok( exists $status->payload->{'history'}->[0]->{'effective'} );
note( 'non-existent employee' );
req( $test, 403, 'demo', 'GET', "$base/rotoroot" );
req( $test, 404, 'root', 'GET', "$base/rotoroot" );
note( 'PUT' );
req( $test, 405, 'demo', 'PUT', "$base/asdf" );
req( $test, 405, 'root', 'PUT', "$base/asdf" );
note( "POST" );
$j = ( $base =~ m/^priv/ )
? '{ "effective":"1969-04-27 9:45", "priv":"inactive" }'
: '{ "effective":"1969-04-27 9:45", "sid":' . $ts_sid . ' }';
req( $test, 403, 'demo', 'POST', "$base/demo", $j );
t/dispatch/history.t view on Meta::CPAN
ok( exists $status->payload->{'nick'} );
is( $status->payload->{'nick'}, 'root' );
ok( exists $status->payload->{'history'} );
is( scalar @{ $status->payload->{'history'} }, 1 );
is( $status->payload->{'history'}->[0]->{'eid'}, 1 );
ok( exists $status->payload->{'history'}->[0]->{'effective'} );
note( 'non-existent employee' );
my $tsr = '[1891-12-30, 1892-01-02)';
req( $test, 403, 'demo', 'GET', "$base/humphreybogart/$tsr" );
req( $test, 404, 'root', 'GET', "$base/humphreybogart/$tsr" );
note( 'root employee, with tsrange but no records found' );
req( $test, 403, 'demo', 'GET', "$base/root/[1999-12-31 23:59, 2000-01-01 00:01)" );
req( $test, 404, 'root', 'GET', "$base/root/[1999-12-31 23:59, 2000-01-01 00:01)" );
note( 'PUT, POST, DELETE' );
foreach my $user ( qw( demo root ) ) {
foreach my $method ( qw( PUT POST DELETE ) ) {
req( $test, 405, $user, $method, "$base/root/[1999-12-31 23:59, 2000-01-01 00:01)" );
}
}
}
t/dispatch/history.t view on Meta::CPAN
is( $status->payload->{'remark'}, 'I am foo!' );
note( 'DELETE' );
note( 'delete the privhistory record we created earlier' );
$status = req( $test, 200, 'root', 'DELETE', "$base/$tphid" );
is( $status->level, "OK" );
is( $status->code, 'DOCHAZKA_CUD_OK' );
note( 'not there anymore' );
req( $test, 404, 'root', 'GET', "$base/$tphid" );
note( 'and demo is a passerby again' );
$status = req( $test, 200, 'demo', 'GET', "priv/self" );
is( $status->level, 'OK' );
is( $status->payload->{'priv'}, "passerby" );
}
note( 'tear down' );
$status = delete_all_attendance_data();
BAIL_OUT(0) unless $status->ok;
t/dispatch/interval_lock.t view on Meta::CPAN
note( 'non-existent ID and also out of range' );
$int_obj = <<"EOH";
{ "$idmap{$il}" : 3434342342342, "remark" : 34334342 }
EOH
dbi_err( $test, 500, 'root', 'POST', $base, $int_obj, qr/out of range for type integer/ );
note( 'non-existent ID' );
$int_obj = <<"EOH";
{ "$idmap{$il}" : 342342342, "remark" : 34334342 }
EOH
req( $test, 404, 'root', 'POST', $base, $int_obj );
note( 'throw a couple curve balls: weirded object' );
my $weirded_object = '{ "copious_turds" : 555, "long_desc" : "wang wang wazoo", "disabled" : "f" }';
req( $test, 400, 'root', 'POST', $base, $weirded_object );
note( 'throw a couple curve balls: no closing bracket' );
my $no_closing_bracket = '{ "copious_turds" : 555, "long_desc" : "wang wang wazoo", "disabled" : "f"';
req( $test, 400, 'root', 'POST', $base, $no_closing_bracket );
note( 'throw a couple curve balls: weirded object 2' );
t/dispatch/interval_lock.t view on Meta::CPAN
ok( $status->payload->{'aid'} );
ok( exists $status->payload->{'long_desc'} );
ok( $status->payload->{'remark'} );
ok( ! defined $status->payload->{'long_desc'} );
}
note( 'fail invalid ID' );
req( $test, 400, 'active', 'GET', "$base/jj" );
note( 'fail non-existent IID' );
req( $test, 404, 'active', 'GET', "$base/444" );
note( 'PUT' );
my $int_obj = '{ "remark" : "Change is good" }';
note( 'test with demo fail 405' );
req( $test, 403, 'demo', 'PUT', "$base/$test_id", $int_obj );
note( 'test with root no request body' );
$status = req( $test, 200, 'root', 'PUT', "$base/$test_id" );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_UPDATE_NO_CHANGE_OK' );
note( 'test with root fail invalid JSON' );
t/dispatch/interval_lock.t view on Meta::CPAN
#req( $test, 403, 'active', 'DELETE', "$base/$test_id" );
#
# - test with root success
#diag( "DELETE $base/$test_id" );
note( 'delete something testy' );
$status = req( $test, 200, 'root', 'DELETE', "$base/$test_id" );
is( $status->level, 'OK', "DELETE $base/:iid 3" );
is( $status->code, 'DOCHAZKA_CUD_OK', "DELETE $base/:iid 4" );
note( 'really gone' );
req( $test, 404, 'active', 'GET', "$base/$test_id" );
note( 'test with root fail invalid IID' );
req( $test, 400, 'root', 'DELETE', "$base/asd" );
}
note( 're-create the testing intervals' );
$test_iid = test_interval_new( $test );
$test_lid = create_testing_lock( $test );
t/dispatch/interval_lock.t view on Meta::CPAN
note( '- this one will be OK' );
$status = req( $test, 201, 'active', 'POST', 'interval/new', <<"EOH" );
{ "aid" : $aid_of_work, "eid" : $eid_active, "intvl" : "[2014-07-31 20:00, 2014-08-01 00:00)" }
EOH
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
my $tiid = $status->payload->{'iid'};
$status = req( $test, 200, 'active', 'DELETE', "interval/iid/$tiid" );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
req( $test, 404, 'active', 'GET', "interval/iid/$tiid" );
note( '- illegal interval' );
dbi_err( $test, 500, 'active', 'POST', 'interval/new',
'{ "aid" : ' . $aid_of_work . ', "eid" : ' . $eid_active .
', "intvl" : "[2014-07-31 20:00, 2014-08-01 00:00]" }', $illegal );
note( '- upper bound not evenly divisible by 5 minutes' );
dbi_err( $test, 500, 'active', 'POST', 'interval/new',
'{ "aid" : '. $aid_of_work . ', "eid" : ' . $eid_active .
', "intvl" : "[2014-07-31 20:00, 2014-08-01 00:01)" }',
t/dispatch/interval_lock.t view on Meta::CPAN
$status = req( $test, 201, 'active', 'POST', 'interval/new', <<"EOH" );
{ "aid" : $aid_of_work, "eid" : $eid_active, "intvl" : "[2014-09-01 00:00, 2014-09-01 04:00)" }
EOH
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
$tiid = $status->payload->{'iid'};
$status = req( $test, 200, 'active', 'DELETE', "interval/iid/$tiid" );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
req( $test, 404, 'active', 'GET', "interval/iid/$tiid" );
note( '- conclusion: I see no way to create an unexpected conflict (famous last words)' );
note( 'CLEANUP: delete the lock' );
$status = req( $test, 200, 'root', 'DELETE', "lock/lid/$tlid" );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
req( $test, 404, 'root', 'GET', "lock/lid/$tlid" );
note( "have an active user try to create a lock on someone else's attendance" );
req( $test, 403, 'active', 'POST', $base, <<"EOH" );
{ "eid" : $eid_inactive, "intvl" : "[1957-02-01 00:00, 1957-03-01 00:00)" }
EOH
note( 'DELETE -> 405' );
req( $test, 405, 'demo', 'DELETE', $base );
req( $test, 405, 'root', 'DELETE', $base );
t/dispatch/schedule.t view on Meta::CPAN
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
ok( exists $status->{payload} );
ok( $status->payload->{shid} );
my $ts_shid = $status->payload->{shid};
note( 'GET' );
note( 'root has no schedule' );
req( $test, 403, 'demo', 'GET', "$base/1" );
req( $test, 404, 'root', 'GET', "$base/1" );
note( 'as root, with timestamp before 1892' );
req( $test, 404, 'root', 'GET', "$base/1/1891-12-31 23:59" );
note( 'as root, with timestamp 1892-01-01 01:01' );
req( $test, 404, 'root', 'GET', "$base/1/1892-01-01 00:01" );
note( 'get inactive\'s schedule in many different ways' );
foreach my $spec (
[ 'root', "$base/$ts_eid_inactive" ],
[ 'root', "/schedule/nick/inactive" ],
[ 'inactive', "/schedule/self" ],
[ 'root', "$base/$ts_eid_inactive/2015-06-01 00:00" ],
[ 'root', "/schedule/nick/inactive/2015-06-01 00:00" ],
[ 'inactive', "/schedule/self/2015-06-01 00:00" ],
) {
t/dispatch/schedule.t view on Meta::CPAN
note( 'payload is a schedule object' );
my $sch = App::Dochazka::REST::Model::Schedule->spawn( %{ $status->payload->{schedule} } );
is( $sch->scode, 'KOBOLD' );
}
note( 'attempt to GET inactive\'s schedule at a time when it didn\'t have one assigned' );
foreach my $spec ( [ 'root', "$base/$ts_eid_inactive/1955-06-01 00:00" ],
[ 'root', "/schedule/nick/inactive/1955-06-01 00:00" ],
[ 'inactive', "/schedule/self/1955-06-01 00:00" ] ) {
note( 'GET ' . $spec->[1] . ' as ' . $spec->[0] );
req( $test, 404, $spec->[0], 'GET', $spec->[1] );
}
note( "GET $base/5343 (non-existent EID)" );
req( $test, 404, 'root', 'GET', "$base/5343" );
note( "GET $base/-33 (negative EID)" );
req( $test, 404, 'root', 'GET', "$base/-33" );
note( "GET $base/34343.33322.22.21 (non-integer EID)" );
req( $test, 400, 'root', 'GET', "$base/34343.33322.22.21" );
note( "GET $base/a thousand clarinets (non-integer EID)" );
req( $test, 400, 'root', 'GET', "$base/a thousand clarinets" );
note( "GET $base/sad;f3.** * @#/ 12341 12 jjj (non-integer EID combined with invalid timestamp)" );
req( $test, 400, 'root', 'GET', "$base/sad;f3.** * @#/ 12341 12 jjj" );
note( "GET $base/2/ 12341 12 jjj (valid EID, stupid timestamp)" );
dbi_err( $test, 500, 'root', 'GET', "$base/2/ 12341 12 jjj", undef,
qr/invalid input syntax for type timestamp with time zone/ );
note( "GET $base/999/ 12341 12 jjj (valid EID, stupid timestamp)" );
req( $test, 404, 'root', 'GET', "$base/999/ 12341 12 jjj" );
note( "GET $base/999/2999-01-33 00:-1 (valid EID, valid timestamp)" );
req( $test, 404, 'root', 'GET', "$base/999/2999-01-33 00:-1" );
note( "GET $base/1/2999-01-33 00:-1 (valid EID, valid timestamp)" );
dbi_err( $test, 500, 'root', 'GET', "$base/1/2999-01-33 00:-1", undef,
qr#date/time field value out of range# );
note( "GET $base/1/wanger (wanger)" );
dbi_err( $test, 500, 'root', 'GET', "$base/1/wanger", undef,
qr/invalid input syntax for type timestamp/ );
t/dispatch/schedule.t view on Meta::CPAN
note( '===========================================' );
$base = "schedule/nick";
docu_check($test, "$base/:nick/?:ts");
note( 'GET' );
note( "GET $base/root as demo" );
req( $test, 403, 'demo', 'GET', "$base/root" );
note( "GET $base/root as root" );
req( $test, 404, 'root', 'GET', "$base/root" );
note( "GET $base/root as root, with timestamp before 1892-01-01" );
req( $test, 404, 'root', 'GET', "$base/root/1891-12-31 23:59" );
note( "GET $base/root as root, with timestamp 1892-01-01 00:00" );
req( $test, 404, 'root', 'GET', "$base/root/1892-01-01 00:01" );
note( 'non-existent nick' );
req( $test, 404, 'root', 'GET', "$base/wanger" );
note( 'negative nick (does not pass validations)' );
req( $test, 400, 'root', 'GET', "$base/-33" );
note( 'stupid nick (fails on validations)' );
req( $test, 400, 'root', 'GET', "$base/34343.33322.22.21" );
note( 'stupid nick (fails on validations)' );
req( $test, 400, 'root', 'GET', "$base/a thousand clarinets" );
note( 'stupid nick (fails on validations)' );
req( $test, 400, 'root', 'GET', "$base/sad;f3.** * @#/ 12341 12 jjj" );
note( 'stupid ts' );
dbi_err( $test, 500, 'root', 'GET', "$base/demo/ 12341 12 jjj", undef,
qr/invalid input syntax for type timestamp/ );
note( 'valid nick, stupid timestamp' );
req( $test, 404, 'root', 'GET', "$base/wanger/ 12341 12 jjj" );
note( 'valid nick, valid timestamp' );
req( $test, 404, 'root', 'GET', "$base/wanger/2999-01-33 00:-1" );
note( 'valid nick, valid timestamp' );
dbi_err( $test, 500, 'root', 'GET', "$base/root/2999-01-33 00:-1", undef,
qr#date/time field value out of range# );
note( 'wanger' );
#req( $test, 404, 'root', 'GET', "$base/root/wanger" );
dbi_err( $test, 500, 'root', 'GET', "$base/root/wanger", undef,
qr/invalid input syntax for type timestamp/ );
note( 'PUT, POST, DELETE -> 405' );
foreach my $user ( qw( demo root ) ) {
foreach my $method ( qw( PUT POST DELETE ) ) {
foreach my $baz ( "$base/root", "$base/root/1892-01-01" ) {
req( $test, 405, $user, $method, $baz );
}
}
t/dispatch/schedule.t view on Meta::CPAN
note( '=============================' );
note( '"schedule/self/?:ts" resource' );
note( '=============================' );
$base = "schedule/self";
docu_check($test, "$base/?:ts");
note( 'GET' );
note( "GET $base as demo, but demo has no schedule history" );
req( $test, 404, 'demo', 'GET', $base );
note( "GET $base as root, but root has no schedule history, either" );
req( $test, 404, 'root', 'GET', $base );
note( "GET $base as root, with timestamp before 1892 A.D." );
req( $test, 404, 'root', 'GET', "$base/1891-12-31 23:59" );
note( "GET $base as root, with timestamp 1892-01-01 00:00" );
req( $test, 404, 'root', 'GET', "$base/1892-01-01 00:01" );
note( "wanger" );
dbi_err( $test, 500, 'root', 'GET', "$base/wanger", undef,
qr/invalid input syntax for type timestamp/ );
note( "stupid ts" );
dbi_err( $test, 500, 'root', 'GET', "$base/ 12341 12 jjj", undef,
qr/invalid input syntax for type timestamp/ );
note( "valid nick, valid timestamp" );
t/dispatch/top.t view on Meta::CPAN
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_ONLINE_DOCUMENTATION' );
ok( exists $status->payload->{'resource'} );
is( $status->payload->{'resource'}, '/' );
ok( exists $status->payload->{'documentation'} );
ok( length( $status->payload->{'documentation'} ) > 10 );
isnt( $status->payload->{'documentation'}, $docustr, "We are not getting the same string over and over again" );
isnt( $docustr_len, length( $status->payload->{'documentation'} ), "We are not getting the same string over and over again" );
note( '- be nice but not careful (non-existent resource)' );
$status = req( $test, 404, 'demo', 'POST', $base, '"echop"' );
is( $status->text, 'Could not find resource definition for echop');
note( '- be pathological (invalid JSON)' );
req( $test, 400, 'demo', 'POST', $base, 'bare, unquoted string will never pass for JSON' );
req( $test, 400, 'demo', 'POST', $base, '[ 1, 2' );
note( 'DELETE docu -> 405' );
req( $test, 405, 'demo', 'DELETE', $base );
req( $test, 405, 'root', 'DELETE', $base );
t/dispatch/top.t view on Meta::CPAN
req( $test, 400, $user, 'GET', "$base//////1/1/234/20" );
req( $test, 400, $user, 'GET', "$base/{}" );
req( $test, 400, $user, 'GET', "$base/-1" );
req( $test, 400, $user, 'GET', "$base/0" );
req( $test, 400, $user, 'GET', "$base/" . '\b\b\o\o\g\\' );
req( $test, 400, $user, 'GET', "$base/" . '\b\b\o\o\\' );
req( $test, 400, $user, 'GET', "$base/**0" );
req( $test, 400, $user, 'GET', "$base/}lieutenant" );
req( $test, 400, $user, 'GET', "$base/<HEAD><tail><body> " );
}
my $mapping = { "demo" => 403, "root" => 404 };
foreach my $user ( qw( demo root ) ) {
# these are bogus in that the parameter does not exist
req( $test, $mapping->{$user}, $user, 'GET', "$base/DOCHEEEHAWHAZKA_appname" );
req( $test, $mapping->{$user}, $user, 'GET', "$base/abc123" );
req( $test, $mapping->{$user}, $user, 'GET', "$base/null" );
}
}
note( 'metaparam-specific tests' );
note( '- try to use metaparam to access a site parameter' );
req( $test, 404, 'root', 'GET', "param/meta/DOCHAZKA_APPNAME" );
note( '- as root, existent parameter' );
$status = req( $test, 200, 'root', 'GET', 'param/meta/META_DOCHAZKA_UNIT_TESTING/' );
is( $status->level, 'OK' );
is( $status->code, 'MREST_PARAMETER_VALUE' );
is_deeply( $status->payload, { 'META_DOCHAZKA_UNIT_TESTING' => 1 } );
note( "- as root, existent parameter without trailing '/'" );
$status = req( $test, 200, 'root', 'GET', 'param/meta/META_DOCHAZKA_UNIT_TESTING' );
is( $status->level, 'OK' );
note( "1. populate $noex employee object from LDAP: fail" );
$emp = $noex_obj->clone();
$status = $emp->ldap_sync();
ok( $status->not_ok );
note( '####################################################' );
note( 'DISPATCH TESTS' );
note( '####################################################' );
note( "GET employee/nick/$noex/ldap returns 404" );
req( $test, 404, 'root', 'GET', "employee/nick/$noex/ldap" );
note( "PUT employee/nick/$noex/ldap returns 404" );
req( $test, 404, 'root', 'PUT', "employee/nick/$noex/ldap" );
note( "GET employee/nick/$ex/ldap returns 200" );
$status = req( $test, 200, 'root', 'GET', "employee/nick/$ex/ldap" );
is( $status->level, 'OK' );
ok( $status->payload, "There is a payload" );
map {
my $value = $status->payload->{$_};
ok( $value, "$_ property has value $value" );
} @props;