Initial checkin of the netdomain test suite. It requires

dejagnu (which, in turn, requires tcl).
This commit is contained in:
Matt Barringer 2007-03-21 22:27:37 +00:00
parent f6244becd4
commit 371f984e09
21 changed files with 568 additions and 0 deletions

View file

@ -0,0 +1,23 @@
The multi-run testsuite works as follows:
In the base netdomain testsuite directory, there are two binaries:
test_multi.send and test_multi.receive.
The testcases are in test_multi/[testcase_name].testcase. These testcases contain
key/value pairs separated by a colon:
- send_ip: [ip address the sending program should bind to]
- send_port: [port number the sending program should bind to]
- send_profile: [the netdomain profile string for the sending program. It can be blank]
- receive_ip: [ip address the receive program should bind to]
- receive_port: [port number the receive program should bind to]
- receive_profile: [the netdomain profile string for the receive program. It can be blank]
- proto: [udp or tcp]
- message: [A message string that the sending program will send to the receiving program]
In test_multi/output there are the expected output files:
- [testcase_name].send.out
- [testcase_name].receive.out
When the test suite runs, it will execute the sending and receiving programs in parallel with
the appropriate testcase settings applied to them. Once the programs have finished executing,
the output is diff'd against the expected output to determine whether or not the test passes.

View file

@ -0,0 +1 @@
load_lib "netdomain_init.exp"

View file

@ -0,0 +1,2 @@
perror "No setup for current configuration."
exit 1

View file

@ -0,0 +1,161 @@
# Adapted from the limal testsuite
proc multi-run { send_program } {
set user_id [exec sh -c "/usr/bin/whoami"]
if {$user_id != "root"} {
puts "In order to actually load profiles, you need to run this test as root."
return 0
}
set errorOccurred 0
set path [split $send_program "/"]
set filename [lindex $path [expr [llength $path]-1]]
set cwd [pwd]
# extract basename and check extension
set fname [split $filename "."]
if {[llength $fname] < 2} {
fail "Bad filename syntax '$send_program'"
return -1
}
if {[lindex $fname [expr [llength $fname]-1]] != "send"} {
fail "Not .send extension '$send_program'"
return -1
}
# Set the name the multi run test
set base_name [lindex $fname 0]
puts "Running $base_name..."
set testcases [glob $base_name/*.testcase ]
foreach testcase $testcases {
set testPath [split $testcase "/"]
set testFilename [lindex $testPath [expr [llength $testPath]-1]]
set testFname [split $testFilename "."]
set testBase_name [lindex $testFname 0]
puts " ... $testBase_name"
# Generate the executable output directory
exec rm -rf $cwd/$base_name/.out
exec mkdir -p $cwd/$base_name/.out
set send_output_file $cwd/$base_name/.out/$testBase_name.sent
set receive_output_file $cwd/$base_name/.out/$testBase_name.received
# Set the testcase expected output files
set send_expected_out $cwd/$base_name/output/$testBase_name.send.out
set receive_expected_out $cwd/$base_name/output/$testBase_name.receive.out
# A little ways down I use sed to turn a generic profile into a testcase
# specific one. Since it uses sed, and we look for three variables in the
# generic testcase, we need a couple of staging files.
set profile $cwd/$base_name/$testBase_name.profile
set generic_profile $cwd/$base_name/$base_name.generic-profile
set pathname_profile $cwd/$base_name/.out/$testBase_name.profile.pathnames
set netdomain_profile $cwd/$base_name/.out/$testBase_name.profile.netdomain
set generated_profile $cwd/$base_name/.out/$testBase_name.profile
# The name of the server program
set receive_program "./$base_name.receive"
# This is used to check whether or not the receive daemon is still running
set receive_in_process ./$base_name/$testBase_name.rec.in.process
# Read in the test case
set testcaseFileId [open $testcase r]
set contents [read $testcaseFileId]
close $testcaseFileId
set line_list [split $contents "\n"]
foreach line $line_list {
set listlist [split $line ":"]
set listvalue [string trimleft [lindex $listlist 1]]
set testcase_array([lindex $listlist 0]) $listvalue
}
# Set up the sed commands to generate the profile
set sed_cmd "/bin/sed \"s|\\\$\\\$PWD|[pwd]|\" < $generic_profile > $pathname_profile"
set send_netdomain_sed_cmd "/bin/sed \"s|\\\$\\\$SENDNETDOMAIN|$testcase_array(send_profile)|\" < $pathname_profile > $netdomain_profile"
set receive_netdomain_sed_cmd "/bin/sed \"s|\\\$\\\$RECEIVENETDOMAIN|$testcase_array(receive_profile)|\" < $netdomain_profile > $generated_profile"
# Run sed
exec sh -c $sed_cmd
exec sh -c $send_netdomain_sed_cmd
exec sh -c $receive_netdomain_sed_cmd
# Load the profile
set apparmor_cmd "/sbin/apparmor_parser --replace < $generated_profile > /dev/null"
exec sh -c $apparmor_cmd
# fork off the server process
if {[fork] == 0} {
# Make a note of our running process
set fileId [open $receive_in_process w]
puts -nonewline $fileId "[pid]"
close $fileId
set rec_cmd "$receive_program $testcase_array(receive_ip) $testcase_array(receive_port) $testcase_array(proto) >$receive_output_file 2>$receive_output_file"
set rec_status [catch { exec sh -c $rec_cmd } rec_result]
file delete $receive_in_process
if { $rec_status != 0 } {
exit 1
}
exit 0
}
# Give the server a little time to get settled
sleep 2
set send_command "$send_program $testcase_array(send_ip) $testcase_array(send_port) $testcase_array(receive_ip) $testcase_array(receive_port) $testcase_array(proto) \"$testcase_array(message)\" >$send_output_file 2>$send_output_file"
set result ""
set oops [catch { set result [exec sh -c $send_command] } caught]
if {$oops != 0} {
fail "Test case failed for $testBase_name: $caught"
set errorOccurred 0
continue
}
if {$result != ""} {
warning "Run of $testBase_name results in '$result'"
set errorOccurred 0
continue
}
# Wait for the process that we forked earlier to be done
while { [file exists $receive_in_process ] != 0 } { }
# Now compare the expect output with the actual output from the two programs
if { [ file exists $send_output_file ] == 0 } {
perror "Missing file $send_output_file" 0
} else {
if { [ diff $send_output_file $send_expected_out ] != 1 } {
puts "Send program output doesn't match expected data:"
puts [ exec sh -c "diff -u $send_output_file $send_expected_out || true" ]
fail $testBase_name
set errorOccurred 0
continue
}
}
if { [ file exists $receive_output_file ] == 0 } {
perror "Missing file $receive_output_file" 0
} else {
if { [ diff $receive_output_file $receive_expected_out ] != 1 } {
puts "Receive program output doesn't match expected data:"
puts [ exec sh -c "diff -u $receive_output_file $receive_expected_out || true" ]
fail $testBase_name
set errorOccurred 0
continue
}
}
# If we got this far, then everything is fine
pass $testBase_name
}
if { $errorOccurred == 0 } {
return 0
} else {
return -1
}
}

View file

@ -0,0 +1,8 @@
if { [catch { set filenames [glob $srcdir/*.send] } ] } {
puts "No .send files found"
} else {
# foreach file, call multi-run (from testsuite/lib)
foreach file $filenames { multi-run $file }
}

View file

@ -0,0 +1 @@
MESSAGE: tcp_accept pass

View file

@ -0,0 +1 @@
Sending "tcp_accept pass"

View file

@ -0,0 +1 @@
MESSAGE: Test pass

View file

@ -0,0 +1 @@
Sending "Test pass"

View file

@ -0,0 +1 @@
MESSAGE: udp_recv pass

View file

@ -0,0 +1 @@
Sending "udp_recv pass"

View file

@ -0,0 +1 @@
MESSAGE: udp_send pass

View file

@ -0,0 +1 @@
Sending "udp_send pass"

View file

@ -0,0 +1,8 @@
send_ip: 127.0.0.1
send_port: 8989
send_profile:
receive_ip: 127.0.0.1
receive_port: 8990
receive_profile:
message: tcp_accept pass
proto: tcp

View file

@ -0,0 +1,8 @@
send_ip: 127.0.0.1
send_port: 9001
send_profile:
receive_ip: 127.0.0.1
receive_port: 9002
receive_profile:
message: Test pass
proto: tcp

View file

@ -0,0 +1,17 @@
# Generic profile for test_multi.send and test_multi.receive
#include <tunables/global>
$$PWD/test_multi.send {
#include <abstractions/base>
$$SENDNETDOMAIN
$$PWD/test_multi/*.send r,
$$PWD/test_multi.send mr,
}
$$PWD/test_multi.receive {
#include <abstractions/base>
$$RECEIVENETDOMAIN
$$PWD/test_multi/*.receive r,
$$PWD/test_multi.receive mr,
}

View file

@ -0,0 +1,8 @@
send_ip: 127.0.0.1
send_port: 9100
send_profile:
receive_ip: 127.0.0.1
receive_port: 9101
receive_profile:
message: udp_recv pass
proto: udp

View file

@ -0,0 +1,8 @@
send_ip: 127.0.0.1
send_port: 9200
send_profile:
receive_ip: 127.0.0.1
receive_port: 9201
receive_profile:
message: udp_send pass
proto: udp

View file

@ -0,0 +1,191 @@
/* Multiple iteration sending test. */
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
int receive_udp(char *bind_ip, char *bind_port);
int receive_tcp(char *bind_ip, char *bind_port);
int main(int argc, char *argv[])
{
int ret;
if (argc < 4)
{
printf("Usage: %s bind_ip bind_port proto\n", argv[0]);
exit(1);
}
if (strcmp(argv[3], "udp") == 0)
{
ret = receive_udp(argv[1], argv[2]);
}
else if (strcmp(argv[3], "tcp") == 0)
{
ret = receive_tcp(argv[1], argv[2]);
}
else
{
printf("Unknown protocol.\n");
}
if (ret == -1)
{
printf("Receive message failed.\n");
exit(1);
}
exit(0);
}
int receive_udp(char *bind_ip, char *bind_port)
{
int sock;
char *buf;
struct sockaddr_in remote, local;
int ret = -1;
int select_return;
fd_set read_set, err_set;
struct timeval timeout;
buf = (char *) malloc(255);
memset(buf, '\0', 255);
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("Socket error: ");
return(-1);
}
local.sin_family = AF_INET;
local.sin_port = htons(atoi(bind_port));
inet_aton(bind_ip, &local.sin_addr);
if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0)
{
perror("Bind error: ");
return(-1);
}
FD_ZERO(&read_set);
FD_SET(sock, &read_set);
FD_ZERO(&err_set);
FD_SET(sock, &err_set);
timeout.tv_sec = 10;
timeout.tv_usec = 0;
select_return = select(sock + 1, &read_set, NULL, &err_set, &timeout);
if (select_return < 0)
{
perror("Select error: ");
ret = -1;
}
if ((select_return > 0) && (FD_ISSET(sock, &read_set)) && (!FD_ISSET(sock, &err_set)))
{
if (recvfrom(sock, buf, 255, 0, (struct sockaddr *)0, (int *)0) >= 1)
{
printf("MESSAGE: %s\n", buf);
ret = 0;
}
else
{
printf("recvfrom failed\n");
ret = -1;
}
}
free(buf);
return(ret);
}
int receive_tcp(char *bind_ip, char *bind_port)
{
int sock, cli_sock;
char *buf;
struct sockaddr_in remote, local;
int ret = -1;
int select_return;
fd_set read_set, err_set;
struct timeval timeout;
buf = (char *) malloc(255);
memset(buf, '\0', 255);
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Socket error:");
return(-1);
}
local.sin_family = AF_INET;
local.sin_port = htons(atoi(bind_port));
inet_aton(bind_ip, &local.sin_addr);
if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0)
{
perror("Could not bind.");
return (-1);
}
if (listen(sock, 5) == -1)
{
perror("Could not listen: ");
return(-1);
}
FD_ZERO(&read_set);
FD_SET(sock, &read_set);
FD_ZERO(&err_set);
FD_SET(sock, &err_set);
timeout.tv_sec = 10;
timeout.tv_usec = 0;
select_return = select(sock + 1, &read_set, NULL, &err_set, &timeout);
if (select_return < 0)
{
perror("Select failed: ");
ret = -1;
}
if ((select_return > 0) && (FD_ISSET(sock, &read_set)) && (!FD_ISSET(sock, &err_set)))
{
if ((cli_sock = accept(sock, NULL, NULL)) < 0)
{
perror("Accept failed: ");
ret = -1;
}
else
{
if (recv(cli_sock, buf, 255, 0) >= 1)
{
printf("MESSAGE: %s\n", buf);
ret = 0;
}
else
{
perror("recv failure: ");
ret = -1;
}
}
}
else
{
perror("There were select failures: ");
ret = -1;
}
free(buf);
return(ret);
}

View file

@ -0,0 +1,125 @@
/* Multiple iteration sending test. */
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
int send_udp(char *bind_ip, char *bind_port, char *remote_ip, char *remote_port, char *message);
int send_tcp(char *bind_ip, char *bind_port, char *remote_ip, char *remote_port, char *message);
int main(int argc, char *argv[])
{
int send_ret;
if (argc < 7)
{
printf("Usage: %s bind_ip bind_port remote_ip remote_port proto message\n", argv[0]);
exit(1);
}
send_ret = -1;
if (strcmp(argv[5], "udp") == 0)
{
send_ret = send_udp(argv[1], argv[2], argv[3], argv[4], argv[6]);
}
else if (strcmp(argv[5], "tcp") == 0)
{
send_ret = send_tcp(argv[1], argv[2], argv[3], argv[4], argv[6]);
}
else
{
printf("Unknown protocol.\n");
}
if (send_ret == -1)
{
printf("Send message failed.\n");
exit(1);
}
exit(0);
}
int send_udp(char *bind_ip, char *bind_port, char *remote_ip, char *remote_port, char *message)
{
int sock;
struct sockaddr_in remote, local;
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("Could not open socket: ");
return(-1);
}
remote.sin_family = AF_INET;
remote.sin_port = htons(atoi(remote_port));
inet_aton(remote_ip, &remote.sin_addr);
local.sin_family = AF_INET;
local.sin_port = htons(atoi(bind_port));
inet_aton(bind_ip, &local.sin_addr);
if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0)
{
perror("Could not bind: ");
return(-1);
}
printf("Sending \"%s\"\n", message);
if (sendto(sock, message, strlen(message), 0, (struct sockaddr *) &remote, sizeof(remote)) <= 0)
{
perror("Send failed: ");
return(-1);
}
close(sock);
return(0);
}
int send_tcp(char *bind_ip, char *bind_port, char *remote_ip, char *remote_port, char *message)
{
int sock;
struct sockaddr_in remote, local;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Could not open socket: ");
return(-1);
}
remote.sin_family = AF_INET;
remote.sin_port = htons(atoi(remote_port));
inet_aton(remote_ip, &remote.sin_addr);
local.sin_family = AF_INET;
local.sin_port = htons(atoi(bind_port));
inet_aton(bind_ip, &local.sin_addr);
if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0)
{
perror("Could not bind: ");
return(-1);
}
if (connect(sock, (struct sockaddr *) &remote, sizeof(remote)) < 0)
{
perror("Could not connect: ");
return(-1);
}
printf("Sending \"%s\"\n", message);
if (send(sock, message, strlen(message), 0) <= 0)
{
perror("Send failed: ");
return(-1);
}
close(sock);
return(0);
}