commit 4de36bbc08e89ba97df98b0f18baa84243e65236
parent 2d37110b2625acc95e90121184b4390f3aa8d281
Author: kyle <kyle@getaddrinfo.net>
Date: Sun, 22 Nov 2015 21:46:52 -0700
tests: polish test infrastructure some more
- delete 'sleep 0.1' hack for waiting for the server to be ready
- instead, reconnect every 50ms if we keep getting ECONNREFUSED
- this is more robust than waiting an arbitrary amount of time for startup
- only make new listen socket when we're ready for connections
- doing this too early coupled with tests that only send data results in
the test being killed before hitting the main processing loop
- this was the source of major confusion, although it makes sense now that
only tests that were sending were breaking
- replace tests/bsd_msg shell test with perl one
- pick up connection retry for free
- switch send_msg/recv_msg api to take/receive message strings for types
- you can do send_msg($sock, 'new_device', $content)
- recv_msg analogously gives back a string message type
- convert tests to use this new api
Diffstat:
17 files changed, 105 insertions(+), 84 deletions(-)
diff --git a/run_tests.sh b/run_tests.sh
@@ -24,10 +24,9 @@ for t in `ls tests/*/Makefile`; do
perl sl -p $PORT -t > $test_dir/server.log &
server_pid=$!
- sleep 0.1
# run test, complain if failed
- if ! make -s -C $test_dir "test"; then
+ if ! make -s -C $test_dir test; then
fail $test_dir "test failed"
kill $server_pid
wait
diff --git a/sl b/sl
@@ -1,5 +1,4 @@
#!/usr/bin/perl -w
-
use warnings;
use strict;
@@ -25,17 +24,6 @@ my %args;
# -p is port, -t is use temporary in memory db
getopts("p:t", \%args);
-my $sock = new IO::Socket::INET (
- LocalHost => '0.0.0.0',
- LocalPort => $args{p} || '5437',
- Proto => 'tcp',
- Listen => 1,
- Reuse => 1,
-);
-
-die "Could not create socket: $!\n" unless $sock;
-my $local_addr_port = inet_ntoa($sock->sockaddr) . ":" .$sock->sockport();
-
my $db_file = "db";
if ($args{t}) {
$db_file = ":memory:";
@@ -77,6 +65,7 @@ my $ph_num_exists_sth = $parent_dbh->prepare($sql);
$sql = qq{select * from devices where device_id = ?};
my $device_id_exists_sth = $parent_dbh->prepare($sql);
+
# friends_map table queries
$sql = qq{insert into friends_map (device_id, friend) values (?, ?)};
my $friends_map_sth = $parent_dbh->prepare($sql);
@@ -126,13 +115,35 @@ my $get_list_items_sth = $parent_dbh->prepare($sql);
$sql = qq{insert into list_data (list_id, name, quantity, status, owner, last_updated) values (?, ?, ?, ?, ?, ?)};
my $new_list_item_sth = $parent_dbh->prepare($sql);
-# make sure children get reaped :)
-$SIG{CHLD} = 'IGNORE';
+my $done = 0;
-while (my ($new_sock, $bin_addr) = $sock->accept()) {
+my $sock = new IO::Socket::INET (
+ LocalHost => '0.0.0.0',
+ LocalPort => $args{p} || '5437',
+ Proto => 'tcp',
+ Listen => 100,
+ Reuse => 1,
+);
+die "Could not create socket: $!\n" unless $sock;
+my $local_addr_port = inet_ntoa($sock->sockaddr) . ":" .$sock->sockport();
+
+$SIG{CHLD} = 'IGNORE';
+$SIG{INT} = \&sig_handler;
+$SIG{TERM} = \&sig_handler;
+sub sig_handler {
+ wait;
+ $parent_dbh->disconnect();
+ $parent_dbh = undef;
+ $sock->shutdown(SHUT_RDWR);
+ close($sock);
+ $done = 1;
+}
+
+while (!$done) {
+ my ($new_sock, $bin_addr) = $sock->accept();
if (!$new_sock) {
- print "warn: accepted empty socket";
+ # print "warn: accepted empty socket";
next;
}
@@ -142,9 +153,12 @@ while (my ($new_sock, $bin_addr) = $sock->accept()) {
if ($pid) {
# parent goes back to listening for more connections
close $new_sock;
+ # print "parent: forked child $pid\n";
next;
}
+ $SIG{INT} = 'IGNORE';
+ $SIG{TERM} = 'IGNORE';
# after here we know we're in the child
# supposed to do this for db connections across forks
@@ -218,6 +232,7 @@ while (my ($new_sock, $bin_addr) = $sock->accept()) {
}
print "$addr: disconnected!\n";
+ $new_sock->shutdown(SHUT_RDWR);
close($new_sock);
$child_dbh->disconnect();
$child_dbh = undef;
@@ -225,9 +240,6 @@ while (my ($new_sock, $bin_addr) = $sock->accept()) {
exit 0;
}
-$parent_dbh->disconnect();
-close($sock);
-
sub get_phone_number
{
my ($dbh, $device_id) = @_;
diff --git a/tests/add_friend/test.pl b/tests/add_friend/test.pl
@@ -8,13 +8,10 @@ use test;
# - adds a new friend
my $sock = new_socket();
-send_msg($sock, 0, "4038675309");
+send_msg($sock, 'new_device', "4038675309");
my ($type, $device_id, $length) = recv_msg($sock);
-fail "got response type $type, expected 0" if ($type != 0);
-fail "expected response length of 43, got $length" if ($length != 43);
-
-send_msg($sock, 2, "$device_id\0" . "4033217654");
+send_msg($sock, 'add_friend', "$device_id\0" . "4033217654");
# my ($type2, $list_data, $length2) = recv_msg($sock);
# fail "got response type $type, expected 1" if ($type2 != 2);
diff --git a/tests/bad_deviceid/test.pl b/tests/bad_deviceid/test.pl
@@ -11,5 +11,7 @@ my $sock = new_socket();
for my $msg (sort @msg_str) {
# new device doesn't take device id as a first parameter
next if ($msg eq "new_device");
- send_msg($sock, $msg_num{$msg}, "notvaliddeviceid");
+ send_msg($sock, $msg, "notvaliddeviceid");
}
+$sock->shutdown(SHUT_RDWR);
+close $sock;
diff --git a/tests/bad_msg/Makefile b/tests/bad_msg/Makefile
@@ -1,4 +1 @@
-test:
- sh test.sh
-
include ../test.mk
diff --git a/tests/bad_msg/test.pl b/tests/bad_msg/test.pl
@@ -0,0 +1,9 @@
+#!/usr/bin/perl -I../
+use strict;
+use warnings;
+use test;
+
+my $sock = new_socket();
+# send_msg is too sophisticated for this test
+print $sock pack("nn", 47837, 0);
+close $sock;
diff --git a/tests/bad_msg/test.sh b/tests/bad_msg/test.sh
@@ -1,5 +0,0 @@
-#!/bin/sh
-
-. ../test.sh
-
-echo -n "baddbedd" | xxd -r -p | nc 127.0.0.1 ${PORT}
diff --git a/tests/double_register/test.pl b/tests/double_register/test.pl
@@ -4,7 +4,7 @@ use warnings;
use test;
my $sock = new_socket();
-send_msg($sock, $msg_num{new_device}, "4038675309");
+send_msg($sock, 'new_device', "4038675309");
my ($type, $response, $length) = recv_msg($sock);
# verify response length is 32 random bytes encoded with base64
@@ -12,4 +12,4 @@ if ($length != 43) {
fail "expected response length of 43, got $length";
}
-send_msg($sock, $msg_num{new_device}, "4038675309");
+send_msg($sock, 'new_device', "4038675309");
diff --git a/tests/list_request_basic/test.pl b/tests/list_request_basic/test.pl
@@ -11,23 +11,23 @@ use test;
my $phone_num = "4038675309";
my $sock = new_socket();
-send_msg($sock, $msg_num{new_device}, $phone_num);
+send_msg($sock, 'new_device', $phone_num);
my (undef, $device_id, undef) = recv_msg($sock);
my %list_id_map;
for my $name ("new list 1", "new list 2", "new list 3") {
- send_msg($sock, $msg_num{new_list}, "$device_id\0$name");
+ send_msg($sock, 'new_list', "$device_id\0$name");
my (undef, $data, undef) = recv_msg($sock);
my ($id, $name, $member) = split("\0", $data);
# save this for verification later
$list_id_map{$name} = $id;
}
-send_msg($sock, $msg_num{list_request}, $device_id);
+send_msg($sock, 'list_request', $device_id);
my ($type, $list_data, $length) = recv_msg($sock);
-if ($type != $msg_num{list_request}) {
- fail "got response type $type, expected $msg_num{list_request}"
+if ($type ne 'list_request') {
+ fail "got response type '$type', expected 'list_request'";
}
my ($direct, $indirect) = split("\0\0", $list_data);
diff --git a/tests/new_device/test.pl b/tests/new_device/test.pl
@@ -4,7 +4,7 @@ use warnings;
use test;
my $sock = new_socket();
-send_msg($sock, $msg_num{new_device}, "4038675309");
+send_msg($sock, 'new_device', "4038675309");
my ($type, $response, $length) = recv_msg($sock);
close $sock;
diff --git a/tests/new_device_bad_phnum/test.pl b/tests/new_device_bad_phnum/test.pl
@@ -5,5 +5,5 @@ use test;
# send a new device message with a bad phone number
my $sock = new_socket();
-send_msg($sock, $msg_num{new_device}, "403867530&");
-close($sock);
+send_msg($sock, 'new_device', "403867530&");
+#close($sock);
diff --git a/tests/new_list/test.pl b/tests/new_list/test.pl
@@ -10,19 +10,19 @@ use test;
# - verifies received information is congruent with what was sent
my $sock = new_socket();
-my $send_t = $msg_num{new_device};
+my $send_t = 'new_device';
send_msg($sock, $send_t, "4038675309");
my ($recv_t, $device_id, $length) = recv_msg($sock);
-fail "got response type $recv_t, expected $send_t" if ($recv_t != $send_t);
+fail "got response type '$recv_t', expected '$send_t'" if ($recv_t ne $send_t);
fail "expected response length of 43, got $length" if ($length != 43);
my $list_name = "this is a new list";
-$send_t = $msg_num{new_list};
+$send_t = 'new_list';
send_msg($sock, $send_t, "$device_id\0$list_name");
my ($recv_t2, $list_data, $length2) = recv_msg($sock);
-fail "got response type $recv_t2, expected $send_t" if ($recv_t2 != $send_t);
+fail "got response type '$recv_t2', expected '$send_t'" if ($recv_t2 ne $send_t);
my ($id, $name, @members) = split("\0", $list_data);
my $id_length = length($id);
diff --git a/tests/new_list_missing_name/test.pl b/tests/new_list_missing_name/test.pl
@@ -1,8 +1,6 @@
#!/usr/bin/perl -I../
-
use strict;
use warnings;
-
use test;
# this test:
@@ -10,10 +8,10 @@ use test;
# - tries to create a new list without a name
my $sock = new_socket();
-send_msg($sock, 0, "4038675309");
+send_msg($sock, 'new_device', "4038675309");
my ($type, $device_id, $length) = recv_msg($sock);
-fail "got response type $type, expected 0" if ($type != 0);
+fail "got response type '$type', expected 'new_device'" if ($type ne 'new_device');
fail "expected response length of 43, got $length" if ($length != 43);
-send_msg($sock, 1, "$device_id\0");
+send_msg($sock, 'new_list', "$device_id\0");
diff --git a/tests/payload_size_zero/test.pl b/tests/payload_size_zero/test.pl
@@ -1,10 +1,8 @@
#!/usr/bin/perl -I../
-
use strict;
use warnings;
-
use test;
my $sock = new_socket();
-send_msg($sock, 0, "");
+send_msg($sock, 'new_device', "");
close $sock;
diff --git a/tests/payload_too_large/test.pl b/tests/payload_too_large/test.pl
@@ -1,8 +1,6 @@
#!/usr/bin/perl -I../
-
use strict;
use warnings;
-
use test;
my $sock = new_socket();
@@ -11,5 +9,5 @@ my $sock = new_socket();
my $out;
$out .= "asdf" for (1..1000);
-send_msg($sock, 0, $out);
+send_msg($sock, 'new_device', $out);
close $sock;
diff --git a/tests/test.pm b/tests/test.pm
@@ -2,16 +2,18 @@ package test;
use strict;
use warnings;
+use Errno;
use Exporter qw(import);
-use IO::Socket;
+use IO::Socket qw(SHUT_RDWR);
+use Time::HiRes qw(usleep);
require "msgs.pl";
-our (%msg_num, @msg_str, @msg_func, $protocol_ver);
+our (%msg_num, @msg_str);
-our @EXPORT = qw(new_socket fail send_msg recv_msg %msg_num @msg_str);
+our @EXPORT = qw(new_socket fail send_msg recv_msg %msg_num @msg_str SHUT_RDWR);
sub fail {
- print shift . "\n";
+ print "$0: " . shift . "\n";
exit 1;
}
@@ -22,23 +24,39 @@ sub new_socket
exit 1;
}
- my $sock = new IO::Socket::INET(
- LocalHost => '127.0.0.1',
- PeerHost => '127.0.0.1',
- PeerPort => $ENV{PORT},
- Proto => 'tcp'
- );
+ my $sock = undef;
+ my $i = 0;
+ while (! $sock) {
+ $sock = new IO::Socket::INET(
+ LocalHost => '127.0.0.1',
+ PeerHost => '127.0.0.1',
+ PeerPort => $ENV{PORT},
+ Proto => 'tcp',
+ );
+
+ if ($!{ECONNREFUSED}) {
+ # print "$i: connection refused, retrying\n";
+ $i++;
+ usleep(50 * 1000);
+ }
+ else {
+ die "error: new socket: $!\n" unless $sock;
+ }
+ }
- die "error: new socket: $!\n" unless $sock;
return $sock;
}
sub send_msg
{
- my ($sock, $type, $contents) = @_;
+ my ($sock, $type_str, $contents) = @_;
+
+ if (! exists $msg_num{$type_str}) {
+ fail "$0: send_msg: invalid msg type '$type_str'";
+ }
# send away
- print $sock pack("nn", $type, length($contents));
+ print $sock pack("nn", $msg_num{$type_str}, length($contents));
print $sock $contents;
}
@@ -59,7 +77,9 @@ sub recv_msg
fail "error unpacking metadata";
}
- # XXX: do msg type upper bounds checking here
+ if ($type < 0 || $type >= @msg_str) {
+ fail "$0: recv_msg: invalid msg num '$type'";
+ }
fail "bad message size not 0 <= $size < 1024" if ($size < 0 || $size > 1023);
my $data;
@@ -68,7 +88,7 @@ sub recv_msg
}
# caller should validate this is the expected type
- return ($type, $data, $size);
+ return ($msg_str[$type], $data, $size);
}
1;
diff --git a/tests/two_lists_same_name/test.pl b/tests/two_lists_same_name/test.pl
@@ -1,28 +1,24 @@
#!/usr/bin/perl -I../
-
use strict;
use warnings;
-
use test;
# this test:
# - gets a new device id
# - creates a new list
-# - receives new list response
-# - verifies received information is congruent with what was sent
my $sock = new_socket();
-send_msg($sock, 0, "4038675309");
+send_msg($sock, 'new_device', "4038675309");
my ($type, $device_id, $length) = recv_msg($sock);
-fail "got response type $type, expected 0" if ($type != 0);
+fail "got response type '$type', expected 'new_device" if ($type ne 'new_device');
fail "expected response length of 43, got $length" if ($length != 43);
my $list_name = "this is a new list";
-send_msg($sock, 1, "$device_id\0$list_name");
+send_msg($sock, 'new_list', "$device_id\0$list_name");
my ($type2, $list_data, $length2) = recv_msg($sock);
-fail "got response type $type, expected 1" if ($type2 != 1);
+fail "got response type '$type', expected 'new_list'" if ($type2 ne 'new_list');
my ($id, $name, @members) = split("\0", $list_data);
my $id_length = length($id);
@@ -32,5 +28,5 @@ fail "recv'd name '$name' not equal to '$list_name'" if ($name ne $list_name);
fail "list does not have exactly 1 member" if (@members != 1);
# add the same list again
-send_msg($sock, 1, "$device_id\0$list_name");
+send_msg($sock, 'new_list', "$device_id\0$list_name");
($type2, $list_data, $length2) = recv_msg($sock);