Rev 51 | Blame | Last modification | View Log | Download | RSS feed
#! /usr/bin/env perl
# Test script for ZFS_Utils module
# if run with no parameters, wil do smoke tests of functions (dry-run safe)
# if run with 2 or more parameters, will read snapshot files and process them
# Usage:
# perl test_zfs_utils.pl source_snapshots.txt target_snapshots.txt [dataset_name]
# - source_snapshots.txt: file containing list of source snapshots (one per line)
# - target_snapshots.txt: file containing list of target snapshots (one per line)
# - dataset_name: (optional) dataset name to process; if not provided, will
# attempt to auto-detect from snapshot names
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin";
use lib "$FindBin::Bin/.."; # ensure module path
use ZFS_Utils qw(runCmd loadConfig logMsg makeReplicateCommands $logFileName $displayLogsOnConsole);
# Test script for ZFS_Utils (dry-run safe)
$displayLogsOnConsole = 1;
$logFileName = '/tmp/zfs_utils_test.log';
unlink $logFileName if -f $logFileName;
# Check for command line arguments (source and target snapshot files, and optional dataset)
if (@ARGV >= 2) {
my ($source_file, $target_file, $dataset_filter) = @ARGV;
print "Reading snapshot files from command line:\n";
print " Source: $source_file\n";
print " Target: $target_file\n";
print " Dataset filter: " . ($dataset_filter || "(auto-detect)") . "\n";
# Read source snapshots (all snapshots on source dataset)
open my $src_fh, '<', $source_file or die "Cannot open source file '$source_file': $!";
my @source_snaps = <$src_fh>;
chomp @source_snaps;
close $src_fh;
# Read target snapshots (status - snapshots already on target)
open my $tgt_fh, '<', $target_file or die "Cannot open target file '$target_file': $!";
my @target_snaps = <$tgt_fh>;
chomp @target_snaps;
close $tgt_fh;
print "\nSource snapshots (" . scalar(@source_snaps) . " entries):\n";
if (@source_snaps) {
my $end = @source_snaps > 5 ? 4 : $#source_snaps;
print " $_\n" for @source_snaps[0..$end];
print " ...\n" if @source_snaps > 5;
}
print "\nTarget snapshots (" . scalar(@target_snaps) . " entries):\n";
if (@target_snaps) {
my $end = @target_snaps > 5 ? 4 : $#target_snaps;
print " $_\n" for @target_snaps[0..$end];
print " ...\n" if @target_snaps > 5;
}
# Determine dataset to process and extract parent directories
my $dataset;
my $source_parent = '';
my $target_parent = '';
if ($dataset_filter) {
# Use explicitly provided dataset
$dataset = $dataset_filter;
print "\nUsing provided dataset: $dataset\n";
} else {
# Extract dataset name from first source snapshot
if (@source_snaps && $source_snaps[0] =~ /^([^@]+)@/) {
my $full_path = $1;
# Extract just the dataset name (last component)
$dataset = $full_path;
$dataset =~ s/.*\///;
# Extract parent directory if present
if ($full_path =~ /^(.+)\/[^\/]+$/) {
$source_parent = $1;
}
}
unless ($dataset) {
die "Error: Could not extract dataset name from source snapshots\n";
}
print "\nAuto-detected dataset: $dataset\n";
}
# Extract target parent from first target snapshot if available
if (@target_snaps && $target_snaps[0] =~ /^([^@]+)@/) {
my $full_path = $1;
# Extract parent directory if present
if ($full_path =~ /^(.+)\/[^\/]+$/) {
$target_parent = $1;
}
}
print "Source parent: " . ($source_parent || "(none)") . "\n";
print "Target parent: " . ($target_parent || "(none)") . "\n";
# Process with makeReplicateCommands
my @newstatus;
my $cmds = makeReplicateCommands(\@source_snaps, \@target_snaps, $dataset, $source_parent, $target_parent, \@newstatus);
print "\nGenerated replicate commands:\n";
if (ref($cmds) eq 'HASH') {
for my $fs (sort keys %$cmds) {
print " $fs => $cmds->{$fs}\n";
}
} elsif (ref($cmds) eq 'ARRAY') {
print " (No commands generated - returned empty array)\n";
} else {
print " (Unexpected return type)\n";
}
print "\nNew status entries (" . scalar(@newstatus) . "):\n";
print " $_\n" for @newstatus;
print "\nSnapshot file processing complete.\n";
exit 0;
}
print "Running ZFS_Utils smoke tests (dry-run safe)\n";
# 1) runCmd in scalar context
my $echo_out = runCmd('printf', 'hello_from_runCmd');
print "runCmd scalar output: [$echo_out]\n";
# 2) runCmd in list context
my @ls = runCmd('printf', "line1\nline2\n");
print "runCmd list output: ". join('|', @ls) ."\n";
# 3) loadConfig using a temporary YAML file
my $tmp_yaml = '/tmp/test_zfs_utils.conf.yaml';
open my $yh, '>', $tmp_yaml or die "Cannot write $tmp_yaml: $!";
print $yh "transport:\n mount_point: /tmp/mount_point_test\n dryrun: 1\n";
print $yh "datasets:\n demo:\n source: pool\n target: backup\n";
close $yh;
my $loaded = loadConfig($tmp_yaml, { default_key => 'default_value' });
print "Loaded config keys: ". join(', ', sort keys %$loaded) ."\n";
print "transport.mount_point = " . ($loaded->{transport}{mount_point} // '(undef)') ."\n";
# 4) makeReplicateCommands - sample snapshot lines
my @snaplines = (
'tank/home@2025-12-01-1d extra',
'tank/home@2025-12-07-1d extra',
'tank/data@2025-11-01-7d',
);
my @status = ('tank/home@2025-11-30-1d');
my @newstatus;
my $cmds = makeReplicateCommands(\@snaplines, \@status, 'home', 'tank', 'tank', \@newstatus);
print "Generated replicate commands:\n";
for my $fs (sort keys %$cmds) {
print " $fs => $cmds->{$fs}\n";
}
print "New status entries: ". join(', ', @newstatus) ."\n";
# 5) logMsg test
logMsg("Test log entry from test_zfs_utils.pl");
print "Log file written to $logFileName (if enabled).\n";
print "Smoke tests complete.\n";
# Clean up temporary YAML
unlink $tmp_yaml;
1;