blob: c510584aa355f5256b1ea1a690fc29637dcced4b [file] [log] [blame]
package broadcaster // import "github.com/docker/docker/pkg/broadcaster"
import (
"bytes"
"errors"
"strings"
"testing"
)
type dummyWriter struct {
buffer bytes.Buffer
failOnWrite bool
}
func (dw *dummyWriter) Write(p []byte) (n int, err error) {
if dw.failOnWrite {
return 0, errors.New("Fake fail")
}
return dw.buffer.Write(p)
}
func (dw *dummyWriter) String() string {
return dw.buffer.String()
}
func (dw *dummyWriter) Close() error {
return nil
}
func TestUnbuffered(t *testing.T) {
writer := new(Unbuffered)
// Test 1: Both bufferA and bufferB should contain "foo"
bufferA := &dummyWriter{}
writer.Add(bufferA)
bufferB := &dummyWriter{}
writer.Add(bufferB)
writer.Write([]byte("foo"))
if bufferA.String() != "foo" {
t.Errorf("Buffer contains %v", bufferA.String())
}
if bufferB.String() != "foo" {
t.Errorf("Buffer contains %v", bufferB.String())
}
// Test2: bufferA and bufferB should contain "foobar",
// while bufferC should only contain "bar"
bufferC := &dummyWriter{}
writer.Add(bufferC)
writer.Write([]byte("bar"))
if bufferA.String() != "foobar" {
t.Errorf("Buffer contains %v", bufferA.String())
}
if bufferB.String() != "foobar" {
t.Errorf("Buffer contains %v", bufferB.String())
}
if bufferC.String() != "bar" {
t.Errorf("Buffer contains %v", bufferC.String())
}
// Test3: Test eviction on failure
bufferA.failOnWrite = true
writer.Write([]byte("fail"))
if bufferA.String() != "foobar" {
t.Errorf("Buffer contains %v", bufferA.String())
}
if bufferC.String() != "barfail" {
t.Errorf("Buffer contains %v", bufferC.String())
}
// Even though we reset the flag, no more writes should go in there
bufferA.failOnWrite = false
writer.Write([]byte("test"))
if bufferA.String() != "foobar" {
t.Errorf("Buffer contains %v", bufferA.String())
}
if bufferC.String() != "barfailtest" {
t.Errorf("Buffer contains %v", bufferC.String())
}
// Test4: Test eviction on multiple simultaneous failures
bufferB.failOnWrite = true
bufferC.failOnWrite = true
bufferD := &dummyWriter{}
writer.Add(bufferD)
writer.Write([]byte("yo"))
writer.Write([]byte("ink"))
if strings.Contains(bufferB.String(), "yoink") {
t.Errorf("bufferB received write. contents: %q", bufferB)
}
if strings.Contains(bufferC.String(), "yoink") {
t.Errorf("bufferC received write. contents: %q", bufferC)
}
if g, w := bufferD.String(), "yoink"; g != w {
t.Errorf("bufferD = %q, want %q", g, w)
}
writer.Clean()
}
type devNullCloser int
func (d devNullCloser) Close() error {
return nil
}
func (d devNullCloser) Write(buf []byte) (int, error) {
return len(buf), nil
}
// This test checks for races. It is only useful when run with the race detector.
func TestRaceUnbuffered(t *testing.T) {
writer := new(Unbuffered)
c := make(chan bool)
go func() {
writer.Add(devNullCloser(0))
c <- true
}()
writer.Write([]byte("hello"))
<-c
}
func BenchmarkUnbuffered(b *testing.B) {
writer := new(Unbuffered)
setUpWriter := func() {
for i := 0; i < 100; i++ {
writer.Add(devNullCloser(0))
writer.Add(devNullCloser(0))
writer.Add(devNullCloser(0))
}
}
testLine := "Line that thinks that it is log line from docker"
var buf bytes.Buffer
for i := 0; i < 100; i++ {
buf.Write([]byte(testLine + "\n"))
}
// line without eol
buf.Write([]byte(testLine))
testText := buf.Bytes()
b.SetBytes(int64(5 * len(testText)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
b.StopTimer()
setUpWriter()
b.StartTimer()
for j := 0; j < 5; j++ {
if _, err := writer.Write(testText); err != nil {
b.Fatal(err)
}
}
b.StopTimer()
writer.Clean()
b.StartTimer()
}
}