github.com/reds/docker@v1.11.2-rc1/pkg/broadcaster/unbuffered_test.go (about) 1 package broadcaster 2 3 import ( 4 "bytes" 5 "errors" 6 "strings" 7 8 "testing" 9 ) 10 11 type dummyWriter struct { 12 buffer bytes.Buffer 13 failOnWrite bool 14 } 15 16 func (dw *dummyWriter) Write(p []byte) (n int, err error) { 17 if dw.failOnWrite { 18 return 0, errors.New("Fake fail") 19 } 20 return dw.buffer.Write(p) 21 } 22 23 func (dw *dummyWriter) String() string { 24 return dw.buffer.String() 25 } 26 27 func (dw *dummyWriter) Close() error { 28 return nil 29 } 30 31 func TestUnbuffered(t *testing.T) { 32 writer := new(Unbuffered) 33 34 // Test 1: Both bufferA and bufferB should contain "foo" 35 bufferA := &dummyWriter{} 36 writer.Add(bufferA) 37 bufferB := &dummyWriter{} 38 writer.Add(bufferB) 39 writer.Write([]byte("foo")) 40 41 if bufferA.String() != "foo" { 42 t.Errorf("Buffer contains %v", bufferA.String()) 43 } 44 45 if bufferB.String() != "foo" { 46 t.Errorf("Buffer contains %v", bufferB.String()) 47 } 48 49 // Test2: bufferA and bufferB should contain "foobar", 50 // while bufferC should only contain "bar" 51 bufferC := &dummyWriter{} 52 writer.Add(bufferC) 53 writer.Write([]byte("bar")) 54 55 if bufferA.String() != "foobar" { 56 t.Errorf("Buffer contains %v", bufferA.String()) 57 } 58 59 if bufferB.String() != "foobar" { 60 t.Errorf("Buffer contains %v", bufferB.String()) 61 } 62 63 if bufferC.String() != "bar" { 64 t.Errorf("Buffer contains %v", bufferC.String()) 65 } 66 67 // Test3: Test eviction on failure 68 bufferA.failOnWrite = true 69 writer.Write([]byte("fail")) 70 if bufferA.String() != "foobar" { 71 t.Errorf("Buffer contains %v", bufferA.String()) 72 } 73 if bufferC.String() != "barfail" { 74 t.Errorf("Buffer contains %v", bufferC.String()) 75 } 76 // Even though we reset the flag, no more writes should go in there 77 bufferA.failOnWrite = false 78 writer.Write([]byte("test")) 79 if bufferA.String() != "foobar" { 80 t.Errorf("Buffer contains %v", bufferA.String()) 81 } 82 if bufferC.String() != "barfailtest" { 83 t.Errorf("Buffer contains %v", bufferC.String()) 84 } 85 86 // Test4: Test eviction on multiple simultaneous failures 87 bufferB.failOnWrite = true 88 bufferC.failOnWrite = true 89 bufferD := &dummyWriter{} 90 writer.Add(bufferD) 91 writer.Write([]byte("yo")) 92 writer.Write([]byte("ink")) 93 if strings.Contains(bufferB.String(), "yoink") { 94 t.Errorf("bufferB received write. contents: %q", bufferB) 95 } 96 if strings.Contains(bufferC.String(), "yoink") { 97 t.Errorf("bufferC received write. contents: %q", bufferC) 98 } 99 if g, w := bufferD.String(), "yoink"; g != w { 100 t.Errorf("bufferD = %q, want %q", g, w) 101 } 102 103 writer.Clean() 104 } 105 106 type devNullCloser int 107 108 func (d devNullCloser) Close() error { 109 return nil 110 } 111 112 func (d devNullCloser) Write(buf []byte) (int, error) { 113 return len(buf), nil 114 } 115 116 // This test checks for races. It is only useful when run with the race detector. 117 func TestRaceUnbuffered(t *testing.T) { 118 writer := new(Unbuffered) 119 c := make(chan bool) 120 go func() { 121 writer.Add(devNullCloser(0)) 122 c <- true 123 }() 124 writer.Write([]byte("hello")) 125 <-c 126 } 127 128 func BenchmarkUnbuffered(b *testing.B) { 129 writer := new(Unbuffered) 130 setUpWriter := func() { 131 for i := 0; i < 100; i++ { 132 writer.Add(devNullCloser(0)) 133 writer.Add(devNullCloser(0)) 134 writer.Add(devNullCloser(0)) 135 } 136 } 137 testLine := "Line that thinks that it is log line from docker" 138 var buf bytes.Buffer 139 for i := 0; i < 100; i++ { 140 buf.Write([]byte(testLine + "\n")) 141 } 142 // line without eol 143 buf.Write([]byte(testLine)) 144 testText := buf.Bytes() 145 b.SetBytes(int64(5 * len(testText))) 146 b.ResetTimer() 147 for i := 0; i < b.N; i++ { 148 b.StopTimer() 149 setUpWriter() 150 b.StartTimer() 151 152 for j := 0; j < 5; j++ { 153 if _, err := writer.Write(testText); err != nil { 154 b.Fatal(err) 155 } 156 } 157 158 b.StopTimer() 159 writer.Clean() 160 b.StartTimer() 161 } 162 }