Skip to content

Commit e111947

Browse files
authored
Merge pull request #283 from jajik/perl-tests
Add an initial support of Apache::Test framework
2 parents e12d802 + 1c9eeee commit e111947

File tree

16 files changed

+1091
-5
lines changed

16 files changed

+1091
-5
lines changed

.github/workflows/ci.yml

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ jobs:
164164
--with-port=8000
165165
sudo make
166166
sudo make install
167-
- name: Build mod_proxy_cluster
167+
- name: Build mod_proxy_cluster and add it to httpd
168168
run: |
169169
ls
170170
cd mod_proxy_cluster/native
@@ -174,8 +174,15 @@ jobs:
174174
./configure CFLAGS="-Wall -Werror" --with-apxs=/usr/local/apache2/bin/apxs; \
175175
make clean; \
176176
make || exit 1; \
177+
sudo cp *.so /usr/local/apache2/modules; \
177178
cd ..; \
178179
done;
180+
- name: Preserve built Apache for perl-test job
181+
uses: actions/[email protected]
182+
with:
183+
name: apache-trunk
184+
path: /usr/local/apache2
185+
retention-days: 0
179186

180187
cmake-windows-latest:
181188
runs-on: windows-latest
@@ -259,6 +266,49 @@ jobs:
259266
test/logs/*
260267
retention-days: 7
261268

269+
perl-tests:
270+
runs-on: ubuntu-latest
271+
needs: make-with-httpd-trunk
272+
steps:
273+
- name: Checkout
274+
uses: actions/checkout@v4
275+
- name: Setup dependencies
276+
run: |
277+
sudo apt update
278+
sudo apt remove apache2*
279+
sudo apt install -y gcc make perl cpanminus libcrypt-ssleay-perl
280+
- name: Get Apache built in the previous job
281+
uses: actions/download-artifact@v4
282+
with:
283+
name: apache-trunk
284+
path: apache2
285+
- name: Put httpd on the right path
286+
run: |
287+
mkdir test-perl/t/modules/
288+
cp apache2/modules/{mod_proxy_cluster.so,mod_manager.so,mod_advertise.so,mod_lbmethod_cluster.so} test-perl/t/modules/
289+
sudo mv apache2/ /usr/local/apache2/
290+
sudo chmod -R 755 /usr/local/apache2/
291+
- name: Install perl modules
292+
run: |
293+
sudo cpanm --force Apache::Test Apache::TestMM HTTP::Request LWP::UserAgent
294+
- name: Run testsuite
295+
run: |
296+
cd test-perl
297+
perl Makefile.PL -httpd /usr/local/apache2/bin/httpd
298+
make
299+
t/TEST -httpd /usr/local/apache2/bin/httpd 2>&1 | tee test-perl.log
300+
mv test-perl.log t/logs/test-perl.log
301+
grep "Result: PASS" -q t/logs/test-perl.log
302+
exit $?
303+
- name: Preserve test logs
304+
uses: actions/upload-artifact@v4
305+
if: always()
306+
with:
307+
name: Perl tests logs
308+
path: |
309+
test-perl/t/logs/*
310+
retention-days: 7
311+
262312
doxygen:
263313
runs-on: ubuntu-latest
264314
steps:

.gitignore

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@
88
*.ipr
99
*.iml
1010

11+
# vim
12+
*.swp
13+
1114
# Visual Studio Code IDE
1215
.vscode/
1316

1417
# Native built files
15-
native/*/*.slo
16-
native/*/*.so
17-
native/*/*.lo
18-
native/*/*.o
1918
native/*/.libs/
2019
native/*/Makefile
2120
native/*/autom4te.cache/
@@ -37,6 +36,12 @@ test/httpd/mod_proxy_cluster
3736
# Log files
3837
**/*.log
3938

39+
# build files
40+
*.slo
41+
*.so
42+
*.lo
43+
*.o
44+
4045
# test files
4146
**/nohup.out
4247
test/MODCLUSTER-640/mod_proxy_cluster_new.conf
@@ -46,6 +51,15 @@ test/new.xml
4651
test/server.xml
4752
test/includes/dependency-reduced-pom.xml
4853

54+
# perl test files
55+
test-perl/MYMETA*
56+
test-perl/Makefile
57+
test-perl/blib/**
58+
test-perl/pm_to_blib
59+
test-perl/t/conf/*.conf
60+
test-perl/t/conf/apache_test_config.pm
61+
test-perl/t/logs/**
62+
4963
# patch files
5064
**/*.patch
5165

test-perl/Makefile.PL

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use v5.32;
2+
use ExtUtils::MakeMaker;
3+
use Apache::TestMM qw(test clean);
4+
use Apache::TestMM qw(test clean);
5+
use Apache::TestReport ();
6+
use Apache::TestSmoke ();
7+
use Apache::TestRun ();
8+
9+
use File::Find qw(finddepth);
10+
11+
my @scripts = ();
12+
13+
finddepth(sub {
14+
return unless /^(?!.#)(.*?\.pl)\.PL$/;
15+
push @scripts, "$File::Find::dir/$1";
16+
}, '.');
17+
18+
Apache::TestMM::filter_args();
19+
20+
for my $script (@scripts) {
21+
Apache::TestMM::generate_script($script);
22+
}
23+
24+
25+
WriteMakefile(
26+
NAME => 'mpc-test',
27+
VERSION => '0.0.1'
28+
);
29+

test-perl/README.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Testsuite based on httpd-tests
2+
3+
This testsuite is based on perl testing framework for Apache.
4+
5+
To run these tests, you will need `httpd`, `perl` and `cpan`. You will be required to compile
6+
this project as well, for more information see the `native/` directory at root of this
7+
repository.
8+
9+
## Dependencies
10+
11+
On Fedora, install `perl-Test` and `perl-ExtUtils-MakeMaker`. Then install required packages
12+
from `cpan`:
13+
14+
```
15+
cpan install Bundle::ApacheTest Apache::TestMM HTTP::Request
16+
```
17+
18+
Then compile the four modules provided by this repository and place the built modules into `t/modules/`
19+
directory.
20+
21+
## Running tests
22+
23+
To run tests just execute following:
24+
25+
```
26+
perl Makefile.PL
27+
make
28+
t/TEST
29+
```
30+
31+
In case you have a custom installation of httpd, you'll be probably required to provide its path. E.g.,
32+
in case of httpd installed under `/opt/apache2/`, execute following:
33+
34+
```
35+
perl Makefile.PL -apxs /opt/apache2/bin/apxs
36+
make
37+
t/TEST -apxs /opt/apache2/bin/apxs
38+
```
39+
40+
For more information about the testing framework see the official
41+
[documentation](https://perl.apache.org/docs/general/testing/testing.html).
42+

test-perl/lib/ModProxyCluster.pm

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
package ModProxyCluster;
2+
3+
use v5.32;
4+
5+
require Exporter;
6+
use HTTP::Request;
7+
use HTTP::Request::Common;
8+
use LWP::UserAgent;
9+
10+
our @ISA = qw(Exporter);
11+
12+
our @EXPORT = qw(
13+
CMD
14+
parse_params
15+
parse_response
16+
);
17+
18+
our $VERSION = '0.0.1';
19+
20+
sub CMD_internal {
21+
my ($cmd, $url, $params) = @_;
22+
my $header = [];
23+
24+
my $ua = LWP::UserAgent->new();
25+
my $request = HTTP::Request->new($cmd, $url, $header, $params);
26+
27+
return $ua->request($request);
28+
}
29+
30+
sub concat_params {
31+
my (%params) = @_;
32+
my $p = "";
33+
my $d = "";
34+
35+
foreach my $k (sort(keys %params)) {
36+
if ($params{$k}) {
37+
$p .= $d . $k . '=' . $params{$k};
38+
$d = "&";
39+
}
40+
}
41+
42+
return $p;
43+
}
44+
45+
sub parse_two_layers {
46+
my ($d1, $d2, $string) = @_;
47+
48+
my %params;
49+
for my $pair (split $d1, $string) {
50+
my ($key, $val) = split $d2, $pair;
51+
# Needed because of the leading whitespace before Type field in DUMP/node...
52+
# TODO: Remove this after we fix the issue...
53+
(my $fixkey = $key) =~ s/\s+//g;
54+
$params{$fixkey} = $val;
55+
}
56+
57+
return %params;
58+
59+
}
60+
61+
sub parse_params {
62+
return parse_two_layers '&', '=', @_;
63+
}
64+
65+
sub parse_INFO {
66+
my $input = shift;
67+
my @lines = split '\n', $input;
68+
my (@nodes, @hosts, @contexts);
69+
70+
my $line = "";
71+
my $i = 0;
72+
for (; $i < @lines; $i++) {
73+
$line = $lines[$i];
74+
if ($line !~ m/Node:/) {
75+
last;
76+
}
77+
my %node = parse_two_layers ',', ': ', $line;
78+
push @nodes, \%node;
79+
}
80+
81+
for (; $i < @lines; $i++) {
82+
$line = $lines[$i];
83+
if ($line !~ m/Vhost:/) {
84+
last;
85+
}
86+
my %host = parse_two_layers ',', ': ', $line;
87+
push @hosts, \%host;
88+
}
89+
90+
for (; $i < @lines; $i++) {
91+
$line = $lines[$i];
92+
if ($line !~ m/Context:/) {
93+
last;
94+
}
95+
my %context = parse_two_layers ',', ': ', $line;
96+
push @contexts, \%context;
97+
}
98+
99+
# Check that everything was parsed
100+
return () if $i != @lines;
101+
return (Nodes => \@nodes, Hosts => \@hosts, Contexts => \@contexts );
102+
}
103+
104+
sub parse_DUMP {
105+
my $input = shift;
106+
my @lines = split '\n', $input;
107+
my (@balancers, @nodes, @hosts, @contexts);
108+
109+
my $line = "";
110+
my $i = 0;
111+
for (; $i < @lines; $i++) {
112+
$line = $lines[$i];
113+
if ($line !~ m/^balancer:/) {
114+
last
115+
}
116+
(my $b = $line) =~ s/: /=/g;
117+
$b =~ s/\[([^\]]*)\]\/\[([^\]]*)\]/Cookie=$1 Path=$2/;
118+
my %balancer = parse_two_layers ' ', '=', $b;
119+
push @balancers, \%balancer;
120+
}
121+
122+
for (; $i < @lines; $i++) {
123+
$line = $lines[$i];
124+
if ($line !~ m/^node:/) {
125+
last;
126+
}
127+
(my $n = $line) =~ s/LBGroup: \[([^\]]*)\]/LBGroup: $1/;
128+
my %node = parse_two_layers ',', ': ', $n;
129+
push @nodes, \%node;
130+
}
131+
132+
for (; $i < @lines; $i++) {
133+
$line = $lines[$i];
134+
if ($line !~ m/^host:/) {
135+
last;
136+
}
137+
(my $h = $line) =~ s/: /=/g;
138+
$h =~ s/\[([^\]]*)\]/alias=$1/;
139+
my %host = parse_two_layers ' ', '=', $h;
140+
push @hosts, \%host;
141+
}
142+
143+
144+
for (; $i < @lines; $i++) {
145+
$line = $lines[$i];
146+
if ($line !~ m/^context:/) {
147+
last;
148+
}
149+
(my $c = $line) =~ s/: /=/g;
150+
$c =~ s/\[([^\]]*)\]/path=$1/;
151+
my %context = parse_two_layers ' ', '=', $c;
152+
push @contexts, \%context;
153+
}
154+
155+
# Check that the whole input was consumed!
156+
return () if $i != @lines;
157+
return ( Balancers => \@balancers, Nodes => \@nodes, Hosts => \@hosts, Contexts => \@contexts );
158+
}
159+
160+
sub CMD {
161+
my ($cmd, $url, %params) = @_;
162+
my @mpc_commands = qw(CONFIG ENABLE-APP DISABLE-APP STOP-APP REMOVE-APP STOP-APP-RSP
163+
STATUS STATUS-RSP INFO INFO-RSP DUMP DUMP-RSP PING PING-RSP);
164+
165+
if (grep /^$cmd$/, @mpc_commands) {
166+
return CMD_internal $cmd, $url, concat_params %params;
167+
}
168+
169+
return HTTP::Response->new();
170+
}
171+
172+
sub parse_response {
173+
my ($cmd, $resp) = @_;
174+
175+
if ($cmd eq 'CONFIG') {
176+
return parse_params $resp;
177+
} elsif ($cmd eq 'DUMP') {
178+
return parse_DUMP $resp;
179+
} elsif ($cmd eq 'INFO') {
180+
return parse_INFO $resp;
181+
} elsif ($cmd eq 'STATUS') {
182+
return parse_params $resp;
183+
} elsif ($cmd eq 'PING') {
184+
return parse_params $resp;
185+
} elsif ($cmd eq 'STOP-APP') {
186+
return parse_params $resp;
187+
}
188+
189+
return {};
190+
}
191+
192+
193+
1;
194+

0 commit comments

Comments
 (0)