diff --git a/goatherd_test.go b/goatherd_test.go index 1692204acf33ecc7e0a31e482df13c41c42485f6..526517bc78078e0fb22738ebaa71cd6e9e4f504a 100644 --- a/goatherd_test.go +++ b/goatherd_test.go @@ -132,38 +132,55 @@ func check_offer_t(t *testing.T) { } +type client_t func(r *io.PipeReader, w *io.PipeWriter) -func mock_conn(name string, offer string) (delay *sync.Mutex, answer string) { - in_r, in_w := io.Pipe() - in_r_buf := bufio.NewReader(in_r) - defer in_r.Close() - out_r, out_w := io.Pipe() - out_r_buf, out_w_buf := bufio.NewReader(out_r), bufio.NewWriter(out_w) - defer out_r.Close() +func mock_conn(client client_t) (delay *sync.Mutex) { + server_r, client_w := io.Pipe() + server_r_buf := bufio.NewReader(server_r) + defer server_r.Close() + client_r, server_w := io.Pipe() + server_w_buf := bufio.NewWriter(server_w) + defer client_r.Close() - answer_c := make(chan string) + go client(client_r, client_w) - go func() { - in_w.Write(append([]byte(username), '\n')) - in_w.Write(append([]byte(offer), '\n')) - answer, _ := get_line(out_r_buf) - answer_c <- answer - }() - - delay = handle_conn(db, "handle_conn_t", in_r_buf, out_w_buf) - answer = <-answer_c + delay = handle_conn(db, "handle_conn_t", server_r_buf, server_w_buf) return } +func interact(name string, offer string, recv chan string) client_t { + return func(r *io.PipeReader, w *io.PipeWriter) { + w.Write(append([]byte(name), '\n')) + w.Write(append([]byte(offer), '\n')) + answer, _ := get_line(bufio.NewReader(r)) + recv <- answer + } +} + func handle_conn_t(t *testing.T) { // zero value Mutex is unlocked, can be compared to a given Mutex to // (unreliably?) check if it is locked unlocked := sync.Mutex{} + t.Run("dummy_user", func(t *testing.T) { + recv := make(chan string) + delay, answer := mock_conn(interact("dummy user", "dummy offer", recv)), <-recv + if delay != nil { + t.Fail() + } + if answer != "" { + t.Error("answer:", answer) + } + if faildelay.userlocks["dummy user"] != nil { + t.Error("userlock created for dummy user") + } + }) + t.Run("dummy_offer", func(t *testing.T) { - delay, answer := mock_conn(username, "dummy offer") + recv := make(chan string) + delay, answer := mock_conn(interact(username, "dummy offer", recv)), <-recv if delay == nil { t.Fail() } else if *delay == unlocked { @@ -174,16 +191,21 @@ func handle_conn_t(t *testing.T) { if answer != "FAIL" { t.Error("answer:", answer) } + if faildelay.userlocks[username] == nil { + t.Error("userlock not in map") + } }) - t.Run("ok", func(t *testing.T) { - tx, err := db.Begin() - t_err_fatal(t, err) - otp, err := get_otp(tx, username) - t_err_fatal(t, err) - tx.Commit() + tx, err := db.Begin() + t_err_fatal(t, err) + otp, err := get_otp(tx, username) + t_err_fatal(t, err) + tx.Commit() - delay, answer := mock_conn(username, otp.OTP()) + t.Run("ok", func(t *testing.T) { + recv := make(chan string) + delay := mock_conn(interact(username, otp.OTP(), recv)) + answer := <-recv if delay != nil { t.Fail() } @@ -194,6 +216,66 @@ func handle_conn_t(t *testing.T) { t.Error("answer:", answer) } }) + otp.Increment() + + t.Run("read_error", func(t *testing.T) { + t.Run("close_immediately", func(t *testing.T) { + delay := mock_conn(func(r *io.PipeReader, w *io.PipeWriter) { + w.Close() + }) + if delay != nil { + t.Fail() + } + if *faildelay.userlocks[username] != unlocked { + t.Error("userlock not unlocked") + } + }) + + t.Run("close_after_username", func(t *testing.T) { + delay := mock_conn(func(r *io.PipeReader, w *io.PipeWriter) { + w.Write(append([]byte(username), '\n')) + w.Close() + }) + if delay != nil { + t.Fail() + } + if *faildelay.userlocks[username] != unlocked { + t.Error("userlock not unlocked") + } + }) + }) + + t.Run("write_error", func(t *testing.T) { + t.Run("FAIL", func(t *testing.T) { + delay := mock_conn(func(r *io.PipeReader, w *io.PipeWriter) { + r.Close() + w.Write(append([]byte(username), '\n')) + w.Write(append([]byte("dummy offer"), '\n')) + }) + if delay == nil { + t.Fail() + } else if *delay == unlocked { + t.Error("delay mutex is unlocked") + } else { + delay.Unlock() + } + }) + + t.Run("OK", func(t *testing.T) { + delay := mock_conn(func(r *io.PipeReader, w *io.PipeWriter) { + r.Close() + w.Write(append([]byte(username), '\n')) + w.Write(append([]byte(otp.OTP()), '\n')) + }) + if delay != nil { + t.Fail() + } + if *faildelay.userlocks[username] != unlocked { + t.Error("userlock not unlocked") + } + }) + otp.Increment() + }) }