feat: add full Zonemaster stack with Docker and Spanish UI
- 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>
This commit is contained in:
73
zonemaster/utils/README.md
Normal file
73
zonemaster/utils/README.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# Document generation
|
||||
|
||||
## Background
|
||||
|
||||
The utility scripts described below are used to update or generate some documents
|
||||
in the public document tree.
|
||||
|
||||
* The scripts should be run at each Zonemaster release and the resulting update
|
||||
should be submitted to correct git branch of this git repository.
|
||||
|
||||
## Pre-requisite
|
||||
|
||||
The scripts should be run on a computer where the updated git branch of
|
||||
`zonemaster/zonemaster` has been cloned, and the equivalent version of
|
||||
`zonemaster/engine` has been **installed**. Usually the git branches will
|
||||
be the `develop` branches of each repository.
|
||||
|
||||
## Scripts
|
||||
|
||||
* [generateTestCaseList.pl]
|
||||
* This tool extracts all Test Case specifications and creates a Markdown table
|
||||
to be inserted in [Test Case README].
|
||||
* [updateTestPlanReadme.pl]
|
||||
* This tool extracts all Test Case specifications per Test Plan and creates
|
||||
Markdown tables. The tables are automatically added to the Test Plan
|
||||
README.md file which is located in the directory named after the Test Plan.
|
||||
* [generateTestMessages.pl]
|
||||
* This tools creates a map between the Zonemaster message tags from the
|
||||
[Zonemaster-Engine] implementation of the Test Cases and the Test Case
|
||||
specifications. This is used to create the complete [TestMessages.md] file.
|
||||
* [generateImplementedTestCases.pl]
|
||||
* This tool creates a list of implemented test cases from the
|
||||
[Zonemaster-Engine] implementation. This is used to create the complete
|
||||
[ImplementedTestCases.md] file.
|
||||
|
||||
## Steps to be run
|
||||
|
||||
1. You are assumed to start from the root of the zonemaster/zonemaster tree.
|
||||
Go to directory to execute the commands from.
|
||||
```sh
|
||||
cd docs/public/specifications/tests
|
||||
```
|
||||
2. All commands below must be run from the directory you are in now.
|
||||
3. Remove Test Case table from [README.md][Test Case README] in that directory
|
||||
and save the file.
|
||||
4. Run:
|
||||
```sh
|
||||
../../../../utils/generateTestCaseList.pl >> README.md
|
||||
```
|
||||
5. Run:
|
||||
```sh
|
||||
../../../../utils/updateTestPlanReadme.pl
|
||||
```
|
||||
6. Run:
|
||||
```sh
|
||||
../../../../utils/generateTestMessages.pl > TestMessages.md
|
||||
```
|
||||
7. Run:
|
||||
```sh
|
||||
../../../../utils/generateImplementedTestCases.pl > ImplementedTestCases.md
|
||||
```
|
||||
8. Verify any updated documents.
|
||||
9. Submit to git.
|
||||
|
||||
|
||||
[generateImplementedTestCases.pl]: generateImplementedTestCases.pl
|
||||
[generateTestCaseList.pl]: generateTestCaseList.pl
|
||||
[generateTestMessages.pl]: generateTestMessages.pl
|
||||
[ImplementedTestCases.md]: ../docs/public/specifications/tests/ImplementedTestCases.md
|
||||
[Test Case README]: ../docs/public/specifications/tests/README.md
|
||||
[TestMessages.md]: ../docs/public/specifications/tests/TestMessages.md
|
||||
[updateTestPlanReadme.pl]: generateTestMessages.pl
|
||||
[Zonemaster-Engine]: https://github.com/zonemaster/zonemaster-engine
|
||||
37
zonemaster/utils/generateImplementedTestCases.pl
Executable file
37
zonemaster/utils/generateImplementedTestCases.pl
Executable file
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
use 5.16.0;
|
||||
use warnings;
|
||||
use Zonemaster::Engine;
|
||||
use File::Basename;
|
||||
|
||||
# page header
|
||||
print '<!-- File generated by ', basename ($0), ", script in zonemaster/zonemaster util directory.\n";
|
||||
print "Use that script to generate a new file for each release of Zonemaster when \n";
|
||||
print "Zonemaster-Engine also has been updated.-->\n\n";
|
||||
print "# Implemented Test Cases\n\n";
|
||||
print "Index of Text Case specifications is also found in [README](README.md).\n";
|
||||
print "[Zonemaster-Engine] is the repository of the implementation of the Test Cases (the methods).\n";
|
||||
print "\n\n";
|
||||
|
||||
# table header
|
||||
print '|Test level (linked to Perl code at CPAN)|Method name in Perl code|',
|
||||
"Test Case Identifier (linked to specification)|\n";
|
||||
print '|:---------------------------------------|:-----------------------|',
|
||||
"----------------------------------------------|\n";
|
||||
|
||||
|
||||
# table content
|
||||
foreach my $module ( sort { fc $a cmp fc $b } Zonemaster::Engine::Test->modules ) {
|
||||
my $full = "Zonemaster::Engine::Test::$module";
|
||||
my $ref = $full->metadata;
|
||||
my $modulelink = "https://metacpan.org/pod/Zonemaster::Engine::Test::$module";
|
||||
for my $method (sort keys %$ref) {
|
||||
my $testcase = uc ($method);
|
||||
my $testcaselink = "${module}-TP/${method}.md";
|
||||
printf "| [%s](%s) | %s | [%s](%s) |\n", $module, $modulelink, $method, $testcase, $testcaselink;
|
||||
}
|
||||
}
|
||||
|
||||
print "\n[Zonemaster-Engine]: https://github.com/zonemaster/zonemaster-engine\n";
|
||||
|
||||
144
zonemaster/utils/generateTestCaseList.pl
Executable file
144
zonemaster/utils/generateTestCaseList.pl
Executable file
@@ -0,0 +1,144 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
# Copyright (c) 2014, IIS (The Internet Infrastructure Foundation)
|
||||
# Copyright (c) 2014, AFNIC
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# Redistributions in binary form must reproduce the above copyright notice, this
|
||||
# list of conditions and the following disclaimer in the documentation and/or
|
||||
# other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Pod::Usage;
|
||||
use Getopt::Long;
|
||||
use File::Basename;
|
||||
|
||||
# command line options
|
||||
my $dirloc = '.'; # directory for searching test cases
|
||||
my $help;
|
||||
my $DEBUG = 0;
|
||||
|
||||
# global variables
|
||||
my $tcCounter = 0;
|
||||
|
||||
sub main {
|
||||
GetOptions(
|
||||
'help|?' => \$help,
|
||||
'dir|d=s' => \$dirloc,
|
||||
'debug' => \$DEBUG,
|
||||
) or pod2usage(2);
|
||||
|
||||
if ($help) {
|
||||
pod2usage(1);
|
||||
exit;
|
||||
}
|
||||
opendir(my $dir, $dirloc) || die "cannot open directory $dirloc";
|
||||
print "<!-- Table generated by script ", basename ($0), " from Zonemaster/Zonemaster utils directory -->\n\n";
|
||||
|
||||
# Table header
|
||||
print '|Test Plan/Test Case |Test Case Description|', "\n";
|
||||
print '|:-------------------|:--------------------|', "\n";
|
||||
|
||||
my @files = readdir $dir;
|
||||
@files = sort {$a cmp $b} @files;
|
||||
foreach my $f (@files) {
|
||||
print "$dirloc/$f\n" if $DEBUG;
|
||||
next if $f =~ /^\./;
|
||||
if (-d "$dirloc/$f") {
|
||||
tcList("$dirloc/$f");
|
||||
}
|
||||
}
|
||||
print "No test cases found\nUse -d to specify directory\n" if !$tcCounter;
|
||||
}
|
||||
|
||||
sub tcList
|
||||
{
|
||||
my $tcDir = shift;
|
||||
my $tcLevel = basename($tcDir);
|
||||
|
||||
# For each level
|
||||
print '|**',$tcLevel,'**| |', "\n";
|
||||
|
||||
opendir(my $dir, $tcDir);
|
||||
my @files = readdir $dir;
|
||||
@files = sort {$a cmp $b} @files;
|
||||
foreach my $f (@files) {
|
||||
next if $f =~ /^\./;
|
||||
next if $f eq "README.md";
|
||||
unless ($f =~ /^[a-z]+[0-9]+\.md$/) {
|
||||
warn "Skip file with unknown file name pattern: $f\n";
|
||||
next;
|
||||
}
|
||||
tcName("$tcDir/$f", $tcLevel);
|
||||
}
|
||||
}
|
||||
|
||||
sub tcName
|
||||
{
|
||||
my $tcPath = shift;
|
||||
my $tcLevel = shift;
|
||||
my $basename = basename($tcPath);
|
||||
my $testcase = uc (basename($tcPath, ".md"));
|
||||
|
||||
open my $file, $tcPath or die "Cannot open file $tcPath: $!";
|
||||
my $header = <$file>;
|
||||
if (defined $header) {
|
||||
if ($header =~ /^#+ +([A-Z]+[0-9]+): +(.*)/) {
|
||||
|
||||
# For each test case
|
||||
print "|[$testcase]($tcLevel/$basename)|$2|\n";
|
||||
|
||||
warn "$tcPath: Test case ID does not match on first line\n" unless $1 eq $testcase;
|
||||
} else {
|
||||
warn "$tcPath: mismatch on first line\n";
|
||||
};
|
||||
} else {
|
||||
warn "$tcPath: empty file or empty first line\n";
|
||||
}
|
||||
$tcCounter++; # increase the global counter
|
||||
close $file;
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
=head1 NAME
|
||||
|
||||
testcase.pl
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This tools extracts all implemented test cases and prints the header of each.
|
||||
|
||||
=head1 USAGE
|
||||
|
||||
testcase.pl --dir .
|
||||
|
||||
Optional arguments:
|
||||
|
||||
--dir Directory path of the test case directory
|
||||
--help This help text
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Patrik Wallstrom <pawal@iis.se>
|
||||
|
||||
=cut
|
||||
36
zonemaster/utils/generateTestMessages.pl
Executable file
36
zonemaster/utils/generateTestMessages.pl
Executable file
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
use 5.16.0;
|
||||
use warnings;
|
||||
use Zonemaster::Engine;
|
||||
use File::Basename;
|
||||
|
||||
# page header
|
||||
print '<!-- File generated by ', basename ($0), ", script in zonemaster/zonemaster util directory.\n";
|
||||
print "Use that script to generate a new file for each release of Zonemaster when \n";
|
||||
print "Zonemaster-Engine also has been updated.-->\n\n";
|
||||
print "# Mapping test messages to Test Cases\n\n";
|
||||
print "Index of Text Cases are found in [README](README.md).\n\n";
|
||||
|
||||
# table header
|
||||
print "| Message tag from [Zonemaster-Engine] | Module | Method (implemented test case) |\n";
|
||||
print "|:-------------------------------------|:-------|:-------------------------------|\n";
|
||||
|
||||
# table content
|
||||
foreach my $module ( sort { fc $a cmp fc $b } Zonemaster::Engine::Test->modules ) {
|
||||
my $full = "Zonemaster::Engine::Test::$module";
|
||||
my $ref = $full->metadata;
|
||||
for my $key (sort keys %$ref) {
|
||||
my $list = $ref->{$key};
|
||||
for my $tag (sort { $a cmp $b } @$list) {
|
||||
my $testlevel = "${module}-TP";
|
||||
my $testlevellink = "$module-TP/README.md";
|
||||
my $testcasefile = "$key.md";
|
||||
my $testcaselink = "$testlevel/$testcasefile";
|
||||
printf "| %-40s | [%s](%s) | [%s](%s) |\n", $tag, $module, $testlevellink, $key, $testcaselink;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print "\n[Zonemaster-Engine]: https://github.com/zonemaster/zonemaster-engine\n";
|
||||
|
||||
181
zonemaster/utils/updateTestPlanReadme.pl
Executable file
181
zonemaster/utils/updateTestPlanReadme.pl
Executable file
@@ -0,0 +1,181 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Pod::Usage;
|
||||
use Getopt::Long;
|
||||
use File::Basename;
|
||||
|
||||
# command line options
|
||||
my $dirloc = '.'; # directory for searching test cases
|
||||
my $help;
|
||||
my $DEBUG = 0;
|
||||
|
||||
sub main {
|
||||
my $tcCounter = 0;
|
||||
|
||||
GetOptions(
|
||||
'help|?' => \$help,
|
||||
'dir|d=s' => \$dirloc,
|
||||
'debug' => \$DEBUG,
|
||||
) or pod2usage(2);
|
||||
|
||||
if ($help) {
|
||||
pod2usage(1);
|
||||
exit;
|
||||
}
|
||||
opendir(my $dir, $dirloc) || die "cannot open directory $dirloc";
|
||||
|
||||
my @directories;
|
||||
|
||||
for my $f (readdir $dir) {
|
||||
my $d = "$dirloc/$f";
|
||||
|
||||
if (! -d $d) {
|
||||
say STDERR qq{Skipping non-directory: $d} if $DEBUG;
|
||||
next;
|
||||
}
|
||||
|
||||
if ($f =~ /^\./) {
|
||||
say STDERR qq{Skipping hidden directory: $d} if $DEBUG;
|
||||
next;
|
||||
}
|
||||
|
||||
if ($f !~ /-TP$/) {
|
||||
say STDERR qq{Skipping directory not ending in "-TP": $d} if $DEBUG;
|
||||
next;
|
||||
}
|
||||
|
||||
push @directories, $d;
|
||||
}
|
||||
|
||||
close $dir;
|
||||
|
||||
@directories = sort { $a cmp $b } @directories;
|
||||
|
||||
foreach my $d (@directories) {
|
||||
say STDERR "Processing directory $d" if $DEBUG;
|
||||
$tcCounter += tcList($d);
|
||||
}
|
||||
|
||||
if ($tcCounter == 0) {
|
||||
say STDERR qq{No test cases found};
|
||||
say STDERR qq{Use -d to specify directory where all test plans (i.e. directories ending in "-TP") reside};
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
|
||||
sub tcList
|
||||
{
|
||||
my $tcDir = shift;
|
||||
|
||||
my $tcCount = 0;
|
||||
my $script_name = basename($0);
|
||||
|
||||
my $output = <<"HEADER";
|
||||
<!-- Content until EOF generated by script $script_name from Zonemaster/Zonemaster utils directory -->
|
||||
|
||||
## Test cases list
|
||||
|
||||
|Test Case |Test Case Description|
|
||||
|:---------|:--------------------|
|
||||
HEADER
|
||||
|
||||
opendir(my $dir, $tcDir);
|
||||
my @files = grep { ! /^\./ } readdir $dir;
|
||||
close $dir;
|
||||
|
||||
@files = sort {$a cmp $b} @files;
|
||||
|
||||
foreach my $f (@files) {
|
||||
next if $f eq "README.md";
|
||||
unless ($f =~ /^[a-z]+[0-9]+\.md$/) {
|
||||
warn "Skip file with unknown file name pattern: $f\n";
|
||||
next;
|
||||
}
|
||||
$output .= tcName("$tcDir/$f");
|
||||
$tcCount++;
|
||||
}
|
||||
|
||||
if ( ! grep( /^README\.md$/, @files ) ) {
|
||||
warn "No README.md file in folder $tcDir\n";
|
||||
}
|
||||
else {
|
||||
writeReadme( "$tcDir/README.md", $output );
|
||||
}
|
||||
|
||||
return $tcCount;
|
||||
}
|
||||
|
||||
sub writeReadme
|
||||
{
|
||||
my ( $tcPath, $tcTable ) = @_;
|
||||
|
||||
# slurp README content until pattern
|
||||
my $content = "";
|
||||
open( my $in, '<', $tcPath ) or die "Cannot open file $tcPath: $!";
|
||||
while( <$in> ) {
|
||||
last if /^## Test cases list$/;
|
||||
last if /^<!-- Content until EOF generated by script .* -->$/;
|
||||
$content .= $_;
|
||||
}
|
||||
close $in;
|
||||
|
||||
$content .= $tcTable;
|
||||
|
||||
open( my $file, '>', $tcPath ) or die "Cannot open file $tcPath: $!";
|
||||
print $file $content;
|
||||
close $file;
|
||||
}
|
||||
|
||||
sub tcName
|
||||
{
|
||||
my $tcPath = shift;
|
||||
my $basename = basename($tcPath);
|
||||
my $testcase = uc (basename($tcPath, ".md"));
|
||||
|
||||
my $output = "";
|
||||
|
||||
open my $file, $tcPath or die "Cannot open file $tcPath: $!";
|
||||
my $header = <$file>;
|
||||
if (defined $header) {
|
||||
if ($header =~ /^#+ +([A-Z]+[0-9]+): +(.*)/) {
|
||||
|
||||
# For each test case
|
||||
$output .= "|[$testcase]($basename)|$2|\n";
|
||||
|
||||
warn "$tcPath: Test case ID does not match on first line\n" unless $1 eq $testcase;
|
||||
} else {
|
||||
warn "$tcPath: mismatch on first line\n";
|
||||
};
|
||||
} else {
|
||||
warn "$tcPath: empty file or empty first line\n";
|
||||
}
|
||||
close $file;
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
=head1 NAME
|
||||
|
||||
updateTestPlanReadme
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This tools updates all TestPlans README files with the TestPlan's test cases.
|
||||
|
||||
=head1 USAGE
|
||||
|
||||
From the root of the project:
|
||||
|
||||
./utils/updateTestPlanReadme.pl -d docs/public/specifications/tests
|
||||
|
||||
Optional arguments:
|
||||
|
||||
--dir Directory path of the test case directory
|
||||
--help This help text
|
||||
|
||||
=cut
|
||||
Reference in New Issue
Block a user