Subversion Repositories zfs_utils

Rev

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;