github.com/emate/nomad@v0.8.2-wo-binpacking/client/lib/streamframer/framer_test.go (about) 1 package framer 2 3 import ( 4 "bytes" 5 "reflect" 6 "strconv" 7 "testing" 8 "time" 9 10 "github.com/hashicorp/nomad/testutil" 11 ) 12 13 // This test checks, that even if the frame size has not been hit, a flush will 14 // periodically occur. 15 func TestStreamFramer_Flush(t *testing.T) { 16 // Create the stream framer 17 frames := make(chan *StreamFrame, 10) 18 hRate, bWindow := 100*time.Millisecond, 100*time.Millisecond 19 sf := NewStreamFramer(frames, hRate, bWindow, 100) 20 sf.Run() 21 22 f := "foo" 23 fe := "bar" 24 d := []byte{0xa} 25 o := int64(10) 26 27 // Start the reader 28 resultCh := make(chan struct{}) 29 go func() { 30 for { 31 frame := <-frames 32 33 if frame.IsHeartbeat() { 34 continue 35 } 36 37 if reflect.DeepEqual(frame.Data, d) && frame.Offset == o && frame.File == f && frame.FileEvent == fe { 38 resultCh <- struct{}{} 39 return 40 } 41 42 } 43 }() 44 45 // Write only 1 byte so we do not hit the frame size 46 if err := sf.Send(f, fe, d, o); err != nil { 47 t.Fatalf("Send() failed %v", err) 48 } 49 50 select { 51 case <-resultCh: 52 case <-time.After(10 * time.Duration(testutil.TestMultiplier()) * bWindow): 53 t.Fatalf("failed to flush") 54 } 55 56 // Shutdown 57 sf.Destroy() 58 59 select { 60 case <-sf.ExitCh(): 61 case <-time.After(10 * time.Duration(testutil.TestMultiplier()) * hRate): 62 t.Fatalf("exit channel should close") 63 } 64 65 if _, ok := <-frames; ok { 66 t.Fatal("out channel should be closed") 67 } 68 } 69 70 // This test checks that frames will be batched till the frame size is hit (in 71 // the case that is before the flush). 72 func TestStreamFramer_Batch(t *testing.T) { 73 // Ensure the batch window doesn't get hit 74 hRate, bWindow := 100*time.Millisecond, 500*time.Millisecond 75 76 // Create the stream framer 77 frames := make(chan *StreamFrame, 10) 78 sf := NewStreamFramer(frames, hRate, bWindow, 3) 79 sf.Run() 80 81 f := "foo" 82 fe := "bar" 83 d := []byte{0xa, 0xb, 0xc} 84 o := int64(10) 85 86 // Start the reader 87 resultCh := make(chan struct{}) 88 go func() { 89 for { 90 frame := <-frames 91 if frame.IsHeartbeat() { 92 continue 93 } 94 95 if reflect.DeepEqual(frame.Data, d) && frame.Offset == o && frame.File == f && frame.FileEvent == fe { 96 resultCh <- struct{}{} 97 return 98 } 99 } 100 }() 101 102 // Write only 1 byte so we do not hit the frame size 103 if err := sf.Send(f, fe, d[:1], o); err != nil { 104 t.Fatalf("Send() failed %v", err) 105 } 106 107 // Ensure we didn't get any data 108 select { 109 case <-resultCh: 110 t.Fatalf("Got data before frame size reached") 111 case <-time.After(bWindow / 2): 112 } 113 114 // Write the rest so we hit the frame size 115 if err := sf.Send(f, fe, d[1:], o); err != nil { 116 t.Fatalf("Send() failed %v", err) 117 } 118 119 // Ensure we get data 120 select { 121 case <-resultCh: 122 case <-time.After(10 * time.Duration(testutil.TestMultiplier()) * bWindow): 123 t.Fatalf("Did not receive data after batch size reached") 124 } 125 126 // Shutdown 127 sf.Destroy() 128 129 select { 130 case <-sf.ExitCh(): 131 case <-time.After(10 * time.Duration(testutil.TestMultiplier()) * hRate): 132 t.Fatalf("exit channel should close") 133 } 134 135 if _, ok := <-frames; ok { 136 t.Fatal("out channel should be closed") 137 } 138 } 139 140 func TestStreamFramer_Heartbeat(t *testing.T) { 141 // Create the stream framer 142 frames := make(chan *StreamFrame, 10) 143 hRate, bWindow := 100*time.Millisecond, 100*time.Millisecond 144 sf := NewStreamFramer(frames, hRate, bWindow, 100) 145 sf.Run() 146 147 // Start the reader 148 resultCh := make(chan struct{}) 149 go func() { 150 for { 151 frame := <-frames 152 if frame.IsHeartbeat() { 153 resultCh <- struct{}{} 154 return 155 } 156 } 157 }() 158 159 select { 160 case <-resultCh: 161 case <-time.After(10 * time.Duration(testutil.TestMultiplier()) * hRate): 162 t.Fatalf("failed to heartbeat") 163 } 164 165 // Shutdown 166 sf.Destroy() 167 168 select { 169 case <-sf.ExitCh(): 170 case <-time.After(10 * time.Duration(testutil.TestMultiplier()) * hRate): 171 t.Fatalf("exit channel should close") 172 } 173 174 if _, ok := <-frames; ok { 175 t.Fatal("out channel should be closed") 176 } 177 } 178 179 // This test checks that frames are received in order 180 func TestStreamFramer_Order(t *testing.T) { 181 // Ensure the batch window doesn't get hit 182 hRate, bWindow := 100*time.Millisecond, 10*time.Millisecond 183 // Create the stream framer 184 frames := make(chan *StreamFrame, 10) 185 sf := NewStreamFramer(frames, hRate, bWindow, 10) 186 sf.Run() 187 188 files := []string{"1", "2", "3", "4", "5"} 189 input := bytes.NewBuffer(make([]byte, 0, 100000)) 190 for i := 0; i <= 1000; i++ { 191 str := strconv.Itoa(i) + "," 192 input.WriteString(str) 193 } 194 195 expected := bytes.NewBuffer(make([]byte, 0, 100000)) 196 for range files { 197 expected.Write(input.Bytes()) 198 } 199 receivedBuf := bytes.NewBuffer(make([]byte, 0, 100000)) 200 201 // Start the reader 202 resultCh := make(chan struct{}) 203 go func() { 204 for { 205 frame := <-frames 206 if frame.IsHeartbeat() { 207 continue 208 } 209 210 receivedBuf.Write(frame.Data) 211 212 if reflect.DeepEqual(expected, receivedBuf) { 213 resultCh <- struct{}{} 214 return 215 } 216 } 217 }() 218 219 // Send the data 220 b := input.Bytes() 221 shards := 10 222 each := len(b) / shards 223 for _, f := range files { 224 for i := 0; i < shards; i++ { 225 l, r := each*i, each*(i+1) 226 if i == shards-1 { 227 r = len(b) 228 } 229 230 if err := sf.Send(f, "", b[l:r], 0); err != nil { 231 t.Fatalf("Send() failed %v", err) 232 } 233 } 234 } 235 236 // Ensure we get data 237 select { 238 case <-resultCh: 239 case <-time.After(10 * time.Duration(testutil.TestMultiplier()) * bWindow): 240 if reflect.DeepEqual(expected, receivedBuf) { 241 got := receivedBuf.String() 242 want := expected.String() 243 t.Fatalf("Got %v; want %v", got, want) 244 } 245 } 246 247 // Shutdown 248 sf.Destroy() 249 250 select { 251 case <-sf.ExitCh(): 252 case <-time.After(10 * time.Duration(testutil.TestMultiplier()) * hRate): 253 t.Fatalf("exit channel should close") 254 } 255 256 if _, ok := <-frames; ok { 257 t.Fatal("out channel should be closed") 258 } 259 }