shlist

share and manage lists between multiple people
Log | Files | Refs

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:
Mrun_tests.sh | 3+--
Msl | 50+++++++++++++++++++++++++++++++-------------------
Mtests/add_friend/test.pl | 7++-----
Mtests/bad_deviceid/test.pl | 4+++-
Mtests/bad_msg/Makefile | 3---
Atests/bad_msg/test.pl | 9+++++++++
Dtests/bad_msg/test.sh | 5-----
Mtests/double_register/test.pl | 4++--
Mtests/list_request_basic/test.pl | 10+++++-----
Mtests/new_device/test.pl | 2+-
Mtests/new_device_bad_phnum/test.pl | 4++--
Mtests/new_list/test.pl | 8++++----
Mtests/new_list_missing_name/test.pl | 8+++-----
Mtests/payload_size_zero/test.pl | 4+---
Mtests/payload_too_large/test.pl | 4+---
Mtests/test.pm | 50+++++++++++++++++++++++++++++++++++---------------
Mtests/two_lists_same_name/test.pl | 14+++++---------
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);