restic/vendor/github.com/ncw/swift/watchdog_reader_test.go

138 lines
3.8 KiB
Go

// This tests WatchdogReader
package swift
import (
"bytes"
"io"
"io/ioutil"
"testing"
"time"
)
// Uses testReader from timeout_reader_test.go
func testWatchdogReaderTimeout(t *testing.T, initialTimeout, watchdogTimeout time.Duration, expectedTimeout bool) {
test := newTestReader(3, 10*time.Millisecond)
timer, firedChan := setupTimer(initialTimeout)
wr := newWatchdogReader(test, watchdogTimeout, timer)
b, err := ioutil.ReadAll(wr)
if err != nil || string(b) != "AAA" {
t.Fatalf("Bad read %s %s", err, b)
}
checkTimer(t, firedChan, expectedTimeout)
}
func setupTimer(initialTimeout time.Duration) (timer *time.Timer, fired <-chan bool) {
timer = time.NewTimer(initialTimeout)
firedChan := make(chan bool)
started := make(chan bool)
go func() {
started <- true
select {
case <-timer.C:
firedChan <- true
}
}()
<-started
return timer, firedChan
}
func checkTimer(t *testing.T, firedChan <-chan bool, expectedTimeout bool) {
fired := false
select {
case fired = <-firedChan:
default:
}
if expectedTimeout {
if !fired {
t.Fatal("Timer should have fired")
}
} else {
if fired {
t.Fatal("Timer should not have fired")
}
}
}
func TestWatchdogReaderNoTimeout(t *testing.T) {
testWatchdogReaderTimeout(t, 100*time.Millisecond, 100*time.Millisecond, false)
}
func TestWatchdogReaderTimeout(t *testing.T) {
testWatchdogReaderTimeout(t, 5*time.Millisecond, 5*time.Millisecond, true)
}
func TestWatchdogReaderNoTimeoutShortInitial(t *testing.T) {
testWatchdogReaderTimeout(t, 5*time.Millisecond, 100*time.Millisecond, false)
}
func TestWatchdogReaderTimeoutLongInitial(t *testing.T) {
testWatchdogReaderTimeout(t, 100*time.Millisecond, 5*time.Millisecond, true)
}
//slowReader simulates reading from a slow network connection by introducing a delay
//in each Read() proportional to the amount of bytes read.
type slowReader struct {
reader io.Reader
delayPerByte time.Duration
}
func (r *slowReader) Read(p []byte) (n int, err error) {
n, err = r.reader.Read(p)
if n > 0 {
time.Sleep(time.Duration(n) * r.delayPerByte)
}
return
}
//This test verifies that the watchdogReader's timeout is not triggered by data
//that comes in very slowly. (It should only be triggered if no data arrives at
//all.)
func TestWatchdogReaderOnSlowNetwork(t *testing.T) {
byteString := make([]byte, 8*watchdogChunkSize)
reader := &slowReader{
reader: bytes.NewReader(byteString),
//reading everything at once would take 100 ms, which is longer than the
//watchdog timeout below
delayPerByte: 200 * time.Millisecond / time.Duration(len(byteString)),
}
timer, firedChan := setupTimer(10 * time.Millisecond)
wr := newWatchdogReader(reader, 190*time.Millisecond, timer)
//use io.ReadFull instead of ioutil.ReadAll here because ReadAll already does
//some chunking that would keep this testcase from failing
b := make([]byte, len(byteString))
n, err := io.ReadFull(wr, b)
if err != nil || n != len(b) || !bytes.Equal(b, byteString) {
t.Fatalf("Bad read %s %d", err, n)
}
checkTimer(t, firedChan, false)
}
//This test verifies that the watchdogReader's chunking logic does not mess up
//the byte strings that are read.
func TestWatchdogReaderValidity(t *testing.T) {
byteString := []byte("abcdefghij")
//make a reader with a non-standard chunk size (1 MiB would be much too huge
//to comfortably look at the bytestring that comes out of the reader)
wr := &watchdogReader{
reader: bytes.NewReader(byteString),
chunkSize: 3, //len(byteString) % chunkSize != 0 to be extra rude :)
//don't care about the timeout stuff here
timeout: 5 * time.Minute,
timer: time.NewTimer(5 * time.Minute),
}
b := make([]byte, len(byteString))
n, err := io.ReadFull(wr, b)
if err != nil || n != len(b) {
t.Fatalf("Read error: %s", err)
}
if !bytes.Equal(b, byteString) {
t.Fatalf("Bad read: %#v != %#v", string(b), string(byteString))
}
}