#! perl -I. -w use t::Test::abeltje; use Dancer qw/!pass !warning/; use Dancer::Test; use Dancer::RPCPlugin::DefaultRoute; use Dancer::Plugin::RPC::JSONRPC; my $ENDPOINT = '/system/code_wrapper'; my $UNKNOWN_ENDPOINT = '/system/code_wrapper/undefined_endpoint'; use MyTest::API; use MyTest::Client; my $client = MyTest::Client->new(ping_value => 'pong'); my $dispatch = { 'MyTest::API' => MyTest::API->new(test_client => $client), }; my $config = { config => 'config', code_wrapper => sub { my ($code, $package, $method_name, @arguments) = @_; my $result = eval { my $instance = $dispatch->{$package}; $instance->$code(@arguments); }; if (my $error = $@) { error("[code_wrapper] ($package\->$method_name) ", $error); if (blessed($error) and $error->does('MyTest::Exception')) { # The plugin will send a proper error-response for the protocol die $error->as_string; } die $error; }; return [ $result ]; }, }; set( plugins => { 'RPC::JSONRPC' => { $ENDPOINT => { 'MyTest::API' => { 'system_ping' => 'rpc_ping', 'system.exception' => 'rpc_fail', } } } } ); set( clients => { test_client => { endpoint => 'somewhere' } }); jsonrpc $ENDPOINT => $config; note("Without catchall unknown endpoint errors"); { my $prefix = "Without catchall"; my $response = _post($ENDPOINT); is($response->{status}, 200, "$prefix: Known endpoint returns 200 status"); is_deeply( $response->{content}{result}, [ { result => 'pong' } ], "$prefix: Known route returns result" ); $response = _post($UNKNOWN_ENDPOINT); route_doesnt_exist( [POST => $UNKNOWN_ENDPOINT], "$prefix: Unknown route $UNKNOWN_ENDPOINT" ); is($response->{status}, 404, "$prefix: unknown endpoint returns 404 status"); $response = _post( $ENDPOINT, { jsonrpc => "2.0", id => 4242, method => 'system_pong'} ); is($response->{status}, 200, "$prefix: Unknown method returns 200 status"); is( $response->{content}{error}{code}, -32601, "$prefix: Unknown method returns -32601 code" ); } setup_default_route(); note('With catchall unknown endpoint errors'); { my $prefix = "With catchall"; my $response = _post($ENDPOINT); is($response->{status}, 200, "$prefix: known endpoint returns 200 status"); is_deeply( $response->{content}{result}, [ { result => 'pong'} ], "$prefix: Known route returns result" ); route_exists([POST => $UNKNOWN_ENDPOINT], "$prefix: Known route: $UNKNOWN_ENDPOINT"); $response = _post($UNKNOWN_ENDPOINT); is($response->{status}, 200, "$prefix: Unknown route returns 200 status"); is_deeply( $response->{content}{error}, { code => -32601, message => "Method 'system_ping' not found", }, "$prefix: Unknown route returns -32601 error" ); route_exists([POST => $UNKNOWN_ENDPOINT], "$prefix: Known route $UNKNOWN_ENDPOINT"); $response = _post( $ENDPOINT, { jsonrpc => "2.0", id => 424242, method => 'system.pong' } ); is($response->{status}, 200, "$prefix: Unknown method returns 200 status"); is( $response->{content}{error}{code}, -32601, "$prefix: Unknown method returns -32601 code" ); like( $response->{content}{error}{message}, qr/Method '.*' not found/, sprintf("RPC::JSONRPC: %s - %s", $prefix, $response->{content}{error}{message}), ); } done_testing(); sub _post { my ($endpoint, $body) = @_; $body //= { jsonrpc => "2.0", id => "42", method => 'system_ping' }; my $request = to_json($body); my $response = dancer_response( POST => $endpoint, { content_type => 'application/json', body => $request, } ); if ($response->{headers}{'content-type'} eq 'application/json') { $response->{content} = from_json($response->{content}) } return $response; }