5
0
mirror of git://git.proxmox.com/git/pve-common.git synced 2024-12-22 21:33:47 +03:00
pve-common/test/lock_file.pl
Wolfgang Bumiller 3feb2c7661 tests: remove acquire-lock newline termination
Not needed anymore.

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
2017-11-10 11:29:54 +01:00

162 lines
3.2 KiB
Perl
Executable File

#!/usr/bin/perl
use lib '../src';
use strict;
use warnings;
use Socket;
use POSIX (); # don't import assert()
use PVE::Tools 'lock_file_full';
my $name = "test.lockfile.$$-";
END {
system("rm $name*");
};
# Utilities:
sub forked($$) {
my ($code1, $code2) = @_;
pipe(my $except_r, my $except_w) or die "pipe: $!\n";
my $pid = fork();
die "fork failed: $!\n" if !defined($pid);
if ($pid == 0) {
close($except_r);
eval { $code1->() };
if ($@) {
print {$except_w} $@;
$except_w->flush();
POSIX::_exit(1);
}
POSIX::_exit(0);
}
close($except_w);
eval { $code2->() };
my $err = $@;
if ($err) {
kill(15, $pid);
} else {
my $err = do { local $/ = undef; <$except_r> };
}
die "interrupted\n" if waitpid($pid, 0) != $pid;
die $err if $err;
# Check exit code:
my $status = POSIX::WEXITSTATUS($?);
if ($? == -1) {
die "failed to execute\n";
} elsif (POSIX::WIFSIGNALED($?)) {
my $sig = POSIX::WTERMSIG($?);
die "got signal $sig\n";
} elsif ($status != 0) {
die "exit code $status\n";
}
}
# Book-keeping:
my %_ran;
sub new {
%_ran = ();
}
sub ran {
my ($what) = @_;
$_ran{$what} = 1;
}
sub assert {
my ($what) = @_;
die "code didn't run: $what\n" if !$_ran{$what};
}
sub assert_not {
my ($what) = @_;
die "code shouldn't have run: $what\n" if $_ran{$what};
}
# Regular lock:
new();
lock_file_full($name, 10, 0, sub { ran('single lock') });
assert('single lock');
# Lock multiple times in a row:
new();
lock_file_full($name, 10, 0, sub { ran('lock A') });
assert('lock A');
lock_file_full($name, 10, 0, sub { ran('lock B') });
assert('lock B');
# Nested lock:
new();
lock_file_full($name, 10, 0, sub {
ran('lock A');
lock_file_full($name, 10, 0, sub { ran('lock B') });
assert('lock B');
ran('lock C');
});
assert('lock A');
assert('lock B');
assert('lock C');
# Independent locks:
new();
lock_file_full($name, 10, 0, sub {
ran('lock A');
# locks file "${name}2"
lock_file_full($name.2, 10, 0, sub { ran('lock B') });
assert('lock B');
ran('lock C');
});
assert('lock A');
assert('lock B');
assert('lock C');
# Does it actually lock? (shared=0)
# Can we get two simultaneous shared locks? (shared=1)
sub forktest1($) {
my ($shared) = @_;
new();
# socket pair for synchronization
socketpair(my $fmain, my $fother, AF_UNIX, SOCK_STREAM, PF_UNSPEC)
or die "socketpair(): $!\n";
forked sub {
# other side
close($fmain);
my $line;
lock_file_full($name, 60, $shared, sub {
ran('other side');
# tell parent we've acquired the lock
print {$fother} "1\n";
$fother->flush();
# wait for parent to be done trying to lock
$line = <$fother>;
});
die $@ if $@;
die "parent failed\n" if !$line || $line ne "2\n";
assert('other side');
}, sub {
# main process
# Wait for our child to lock:
close($fother);
my $line = <$fmain>;
die "child failed to acquire a lock\n" if !$line || $line ne "1\n";
lock_file_full($name, 1, $shared, sub {
ran('local side');
});
if ($shared) {
assert('local side');
} else {
assert_not('local side');
}
print {$fmain} "2\n";
$fmain->flush();
};
close($fmain);
}
forktest1(0);
forktest1(1);