Skip to content

support checking specified file content #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
307 changes: 307 additions & 0 deletions lib/Test/Nginx/Socket.pm
Original file line number Diff line number Diff line change
@@ -35,6 +35,9 @@ use Test::Nginx::Util qw(
$RepeatEach
timeout
error_log_data
file_data
file_like_data
parse_files
worker_connections
master_process_enabled
config_preamble
@@ -516,6 +519,7 @@ again:
}

check_error_log($block, $res, $dry_run, $req_idx, $need_array);
check_files($block, $res, $dry_run, $req_idx, $need_array);

$req_idx++;

@@ -717,6 +721,189 @@ sub check_error_log ($$$$$) {

}

sub check_files ($$$$$) {
my ($block, $res, $dry_run, $req_idx, $need_array) = @_;
my $name = $block->name;
my $lines;

if (defined $block->output_files) {
my $raw = $block->output_files;

open my $in, '<', \$raw;

my @files;
my ($fname, $body, $chop);
while (<$in>) {
if (/>>> (\S+)\s?(\S*)/) {
if ($fname) {
push @files, [$fname, $body, $chop];
}
$fname = $1;
if ($2 eq "chop") {
$chop = 1;
} else {
$chop = 0;
}
undef $body;
} else {
$body .= $_;
}
}
if ($fname) {
push @files, [$fname, $body, $chop];
}

for my $file (@files) {
my ($fname, $body, $chop) = @$file;

if (!defined $body) {
$body = '';
}
if (defined $file) {
my $lines = file_data($fname);
if ($chop == 1) {
chop $body;
}
if ($lines eq $body) {
SKIP: {
skip "$name - tests skipped due to the lack of directive $dry_run", 1 if $dry_run;
pass("$name - content \"$body\" matches file \"$fname\"");
}
undef $file;
}
}
}

for my $file (@files) {
if (defined $file) {
my ($fname, $body, $chop) = @$file;
SKIP: {
skip "$name - tests skipped due to the lack of directive $dry_run", 1 if $dry_run;
fail("$name - content \"$body\" not matches file \"$fname\"");
}
}
}

}

if (defined $block->output_files_like) {
my $pats = parse_files($block->output_files_like);

for my $pat (@$pats) {
if (defined $pat) {
my $lines = file_like_data(@$pat[0]);
for my $line (@$lines) {
my $val = @$pat[1];
if ($line =~ /$val/ || $line =~ /\Q$val\E/) {
SKIP: {
skip "$name - tests skipped due to the lack of directive $dry_run", 1 if $dry_run;
pass("$name - files_like: content \"@$pat[1]\" exists in file \"@$pat[0]\"");
}
undef $pat;
}
}
}
}
for my $pat (@$pats) {
if (defined $pat) {
SKIP: {
skip "$name - tests skipped due to the lack of directive $dry_run", 1 if $dry_run;
fail("$name - files_like: content \"@$pat[1]\" not exists in file \"@$pat[0]\"");
}
}
}
}

if (defined $block->output_files_unlike) {
my $pats = parse_files($block->output_files_unlike);

for my $pat (@$pats) {
if (defined $pat) {
my $lines = file_like_data(@$pat[0]);
for my $line (@$lines) {
my $val = @$pat[1];
if ($line =~ /$val/ || $line =~ /\Q$val\E/) {
SKIP: {
skip "$name - tests skipped due to the lack of directive $dry_run", 1 if $dry_run;
fail("$name - files_not_like: content \"@$pat[1]\" exists in file \"@$pat[0]\"");
}
undef $pat;
}
}
}
}
for my $pat (@$pats) {
if (defined $pat) {
SKIP: {
skip "$name - tests skipped due to the lack of directive $dry_run", 1 if $dry_run;
pass("$name - files_not_like: content \"@$pat[1]\" not exists in file \"@$pat[0]\"");
}
}
}
}

if ($block->files_exist) {
my $files = $block->files_exist;
if (!ref $files) {
chomp $files;
my @lines = split /\n+/, $files;
$files = \@lines;
} else {
my @clone = @$files;
$files = \@clone;
}

for my $file (@$files) {
if (-e $file) {
SKIP: {
skip "$name - tests skipped due to the lack of directive $dry_run", 1 if $dry_run;
pass("$name - files_exist: \"$file\" exists");
}
undef $file;
}
}
for my $file (@$files) {
if (defined $file) {
SKIP: {
skip "$name - tests skipped due to the lack of directive $dry_run", 1 if $dry_run;
fail("$name - files_exist: \"$file\" is not existing");
}
}
}
}

if ($block->files_not_exist) {
my $files = $block->files_not_exist;
if (!ref $files) {
chomp $files;
my @lines = split /\n+/, $files;
$files = \@lines;
} else {
my @clone = @$files;
$files = \@clone;
}

for my $file (@$files) {
if (-e $file) {
SKIP: {
skip "$name - tests skipped due to the lack of directive $dry_run", 1 if $dry_run;
fail("$name - files_not_exist: \"$file\" exists");
}
undef $file;
}
}
for my $file (@$files) {
if (defined $file) {
SKIP: {
skip "$name - tests skipped due to the lack of directive $dry_run", 1 if $dry_run;
pass("$name - files_not_exist: \"$file\" is not existing");
}
}
}
}

}

sub fmt_str ($) {
my $str = shift;
chomp $str;
@@ -1591,6 +1778,12 @@ test) is listening to:
As usual, if the test is made of multiple requests, then
raw_response_headers_like B<MUST> be an array.

=head2 timeout

Specifys the timeout value for test case running, default to 2(sec).

--- timeout: 50

=head2 error_code

The expected value of the HTTP response code. If not set, this is assumed
@@ -1665,6 +1858,120 @@ Just like the C<--- error_log> section, one can also specify multiple patterns:

Then if any line in F<error.log> contains the string C<"abc"> or match the Perl regex C<qr/blah/>, then the test will fail.

=head2 output_files

Checks if content of the file is equal to specified string. Usage most likes user_files, additional directive "chop" is added to remove unnecessary "\n" for some files.

For example,

=== TEST 0: write to file
--- config
location /write/to/file {
content_by_lua '
io.output("/tmp/file",rw);
io.write("hello");
io.flush();
io.output("/tmp/file1",rw);
io.write("hello\\nworld\\n");
io.flush();
io.close();
';
}
--- request
GET /write/to/file
--- error_code: 200
--- output_files
>>> /tmp/file chop
hello
>>> /tmp/file1
hello
world


Then content of the F</tmp/file> is "abcd", first case should be passed and second case failed.

=head2 output_files_like

Checks if specified pattern matches one line of the file. First section seperated by colon is file name and the second section is match pattern.

For example,

=== TEST 1: write to file
--- config
location /write/to/file {
content_by_lua '
io.output("/tmp/file",rw);
io.write("abcd");
io.flush();
io.close();
';
}
--- request
GET /write/to/file
--- error_code: 200
--- output_files_like
/tmp/file: abcde
/tmp/file: ^abc

Then content of the F</tmp/file> is "abcd", first case should be failed and second case passed.

=head2 output_files_unlike

Likes C<--- output_files_like> section, but does the opposite test, i.e.,
checks if specified pattern matches none line of the file. First section seperated by colon is file name and the second section is match pattern.

For example,

=== TEST 1: write to file
--- config
location /write/to/file {
content_by_lua '
io.output("/tmp/file",rw);
io.write("abcd");
io.flush();
io.close();
';
}
--- request
GET /write/to/file
--- error_code: 200
--- output_files_unlike
/tmp/file: abc
/tmp/file: ^bc

Then content of the F</tmp/file> is "abcd", first case should be failed and second case passed.

=head2 pre_remove_files

Remove files before start nginx. Both multi lines and eval are supported. For example:

--- pre_remove_files
/tmp/file
/tmp/file1

and:

--- pre_remove_files eval
["/tmp/file", "/tmp/file1"]

=head2 files_exist

Check if specified files exist.

--- files_exist
/tmp/file
/tmp/file1

And "eval" is also supported.

--- files_exist eval
["/tmp/file2", "/tmp/file3"]


=head2 files_not_exist

Likes C<--- files_exist> section, but does the opposite test.

=head2 raw_request

The exact request to send to nginx. This is useful when you want to test
66 changes: 66 additions & 0 deletions lib/Test/Nginx/Util.pm
Original file line number Diff line number Diff line change
@@ -147,6 +147,9 @@ sub master_process_enabled (@) {
our @EXPORT_OK = qw(
bail_out
error_log_data
file_data
file_like_data
parse_files
setup_server_root
write_config_file
get_canon_version
@@ -279,6 +282,68 @@ sub error_log_data () {
return \@lines;
}

sub file_data ($) {
my ($file) = @_;
open my $in, $file or
return undef;
my $lines = do { local $/; <$in>; };
close $in;
return $lines;
}

sub file_like_data ($) {
my ($file) = @_;
open my $in, $file or
return undef;
my @lines = <$in>;
close $in;
return \@lines;
}

sub parse_files ($) {
my $s = shift;
my @headers;
my @lines;
open my $in, '<', \$s;
while (<$in>) {
s/^\s+|\s+$//g;
my $neg = ($_ =~ s/^!\s*//);
if (!$neg) {
my ($key, $val) = split /\s*:\s*/, $_, 2;
@headers = ($key, $val);
push @lines, [ @headers ];
#warn "neg: $key $val";
}
}
close $in;
return \@lines;
}

sub pre_remove_files ($) {
my $block = shift;

my $name = $block->name;

if ($block->pre_remove_files) {
my $files = $block->pre_remove_files;
if (!ref $files) {
chomp $files;
my @lines = split /\n+/, $files;
$files = \@lines;
} else {
my @clone = @$files;
$files = \@clone;
}

for my $file (@$files) {
if (-e $file) {
unlink $file or die "unlink $file failed\n";
}
}

}
}

sub run_tests () {
$NginxVersion = get_nginx_version();

@@ -800,6 +865,7 @@ start_nginx:
#warn "*** Restarting the nginx server...\n";
setup_server_root();
write_user_files($block);
pre_remove_files($block);
write_config_file($config, $block->http_config, $block->main_config);
#warn "nginx binary: $NginxBinary";
if ( ! can_run($NginxBinary) ) {