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  }