use strict; use warnings; use 5.14.2; use utf8; use Test::More tests => 30; use Test::NoWarnings; use Cwd; use File::Temp qw[tempdir]; use Zonemaster::Backend::Config; use Zonemaster::Backend::RPCAPI; use JSON::Validator::Joi "joi"; use JSON::PP; ### ### Setup ### my $tempdir = tempdir( CLEANUP => 1 ); my $cwd = cwd(); my $config = Zonemaster::Backend::Config->parse( <new( { dbtype => $config->DB_engine, config => $config, } ); ### ### JSONRPC request object construction helper ### sub jsonrpc { my ($method, $params, $force_undef) = @_; my $object = { jsonrpc => '2.0', id => 'testing', method => $method }; if (defined $params or $force_undef) { $object->{params} = $params; } return $object; } ### ### JSONRPC error response construction helpers ### sub jsonrpc_error { my ($message, $code, $data, $id) = @_; my $object = { jsonrpc => '2.0', id => $id, error => { message => $message, code => $code } }; $object->{error}{data} = $data if defined $data; return $object; } sub error_bad_jsonrpc { my ($data) = @_; jsonrpc_error('The JSON sent is not a valid request object.', '-32600', $data, undef); } sub error_missing_params { jsonrpc_error("Missing 'params' object", '-32602', undef, 'testing'); } sub error_bad_params { my ($messages) = @_; my @data; while (@$messages) { my $path = shift @$messages; my $message = shift @$messages; push @data, { path => $path, message => $message }; } jsonrpc_error('Invalid method parameter(s).', '-32602', \@data, 'testing'); } sub no_error { return ''; } ### ### Test wrapper functions ### sub test_validation { my ($input, $output, $message) = @_; my $res = $rpcapi->jsonrpc_validate($input); is_deeply($res, $output, $message) or diag(encode_json($res)); } ### ### The tests themselves ### test_validation undef, error_bad_jsonrpc('/: Expected object - got null.'), "Sending undef is an error"; test_validation JSON::PP::false, error_bad_jsonrpc('/: Expected object - got boolean.'), "Sending a boolean is an error"; test_validation -1, error_bad_jsonrpc('/: Expected object - got number.'), "Sending a number is an error"; test_validation "hello", error_bad_jsonrpc('/: Expected object - got string.'), "Sending a string is an error"; test_validation [qw(a b c)], error_bad_jsonrpc('/: Expected object - got array.'), "Sending an array is an error"; test_validation {}, error_bad_jsonrpc('/jsonrpc: Missing property. /method: Missing property.'), "Sending an empty object is an error"; test_validation { jsonrpc => '2.0' }, error_bad_jsonrpc('/method: Missing property.'), "Sending an incomplete object is an error"; test_validation { jsonrpc => '2.0', method => 'system_versions' }, error_bad_jsonrpc(''), "Sending an object with no ID is an error"; test_validation { jsonrpc => '2.0', method => 'system_versions', id => JSON::PP::false }, error_bad_jsonrpc('/id: Expected null/number/string - got boolean.'), "Sending an object whose ID is a boolean is an error"; test_validation { jsonrpc => '2.0', method => 'system_versions', id => [qw(a b c)] }, error_bad_jsonrpc('/id: Expected null/number/string - got array.'), "Sending an object whose ID is an array is an error"; test_validation { jsonrpc => '2.0', method => 'system_versions', id => { a => 1 } }, error_bad_jsonrpc('/id: Expected null/number/string - got object.'), "Sending an object whose ID is an object is an error"; test_validation jsonrpc("job_status"), error_missing_params(), "Calling job_status without parameters is an error"; test_validation jsonrpc("job_status", undef, 1), error_bad_params(["/" => "Expected object - got null."]), "Passing null as parameter to job_status is an error"; test_validation jsonrpc("job_status", JSON::PP::false), error_bad_params(["/" => "Expected object - got boolean."]), "Passing boolean as parameter to job_status is an error"; test_validation jsonrpc("job_status", 1), error_bad_params(["/" => "Expected object - got number."]), "Passing number as parameter to job_status is an error"; test_validation jsonrpc("job_status", "hello"), error_bad_params(["/" => "Expected object - got string."]), "Passing string as parameter to job_status is an error"; test_validation jsonrpc("job_status", [qw(a b c)]), error_bad_params(["/" => "Expected object - got array."]), "Passing array as parameter to job_status is an error"; test_validation jsonrpc("job_status", {}), error_bad_params(["/job_id" => "Missing property"]), "Passing empty object as parameter to job_status is an error"; test_validation jsonrpc("job_status", { job_id => 'this_will_definitely_never_ever_exist' }), error_bad_params(["/job_id" => 'String does not match (?^u:^[0-9a-f]{16}$).']), "Calling job_status with a bad job_id is an error"; test_validation jsonrpc("job_status", { job_id => '0123456789abcdef', data => "something" }), error_bad_params(["/" => "Properties not allowed: data."]), "Calling job_status with unknown parameters is an error"; test_validation jsonrpc("job_status", { job_id => '0123456789abcdef' }), no_error, "Calling job_status with a good job_id succeeds"; test_validation jsonrpc("system_versions"), no_error, "Calling system_versions with no parameters is OK"; test_validation jsonrpc("system_versions", undef, 1), error_bad_params(["/" => "Expected object - got null."]), "Passing null as parameter to system_versions is an error"; test_validation jsonrpc("system_versions", JSON::PP::false), error_bad_params(["/" => "Expected object - got boolean."]), "Passing number as parameter to system_versions is an error"; test_validation jsonrpc("system_versions", -1), error_bad_params(["/" => "Expected object - got number."]), "Passing number as parameter to system_versions is an error"; test_validation jsonrpc("system_versions", "hello"), error_bad_params(["/" => "Expected object - got string."]), "Passing string as parameter to system_versions is an error"; test_validation jsonrpc("system_versions", [qw(a b c)]), error_bad_params(["/" => "Expected object - got array."]), "Passing array as parameter to system_versions is an error"; test_validation jsonrpc("system_versions", { data => "something" }), error_bad_params(["/" => "Properties not allowed: data."]), "Calling system_versions with unrecognized parameter is an error"; test_validation jsonrpc("system_versions", {}), no_error, "Calling system_versions with empty object succeeds";