- Clone all 5 Zonemaster component repos (LDNS, Engine, CLI, Backend, GUI) - Dockerfile.backend: 8-stage multi-stage build LDNS→Engine→CLI→Backend - Dockerfile.gui: Astro static build served via nginx - docker-compose.yml: backend (internal) + frontend (port 5353) - nginx.conf: root redirects to /es/, /api/ proxied to backend - zonemaster-gui/config.ts: defaultLanguage set to 'es' (Spanish) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
243 lines
6.8 KiB
Perl
243 lines
6.8 KiB
Perl
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( <<EOF );
|
|
[DB]
|
|
engine = SQLite
|
|
|
|
[SQLITE]
|
|
database_file = $tempdir/zonemaster.sqlite
|
|
|
|
[PUBLIC PROFILES]
|
|
test = $cwd/t/test_profile.json
|
|
EOF
|
|
|
|
my $rpcapi = Zonemaster::Backend::RPCAPI->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";
|