github.com/m3db/m3@v1.5.0/src/aggregator/client/queue_test.go (about)

     1  // Copyright (c) 2018 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package client
    22  
    23  import (
    24  	"testing"
    25  
    26  	"github.com/stretchr/testify/assert"
    27  	"github.com/stretchr/testify/require"
    28  	"gopkg.in/yaml.v2"
    29  
    30  	"github.com/m3db/m3/src/metrics/encoding/protobuf"
    31  )
    32  
    33  func TestInstanceQueueEnqueueClosed(t *testing.T) {
    34  	opts := testOptions()
    35  	queue := newInstanceQueue(testPlacementInstance, opts).(*queue)
    36  	queue.writeFn = func([]byte) error { return nil }
    37  	queue.closed.Store(true)
    38  
    39  	require.Equal(t, errInstanceQueueClosed, queue.Enqueue(testNewBuffer(nil)))
    40  }
    41  
    42  func TestInstanceQueueEnqueueQueueFullDropCurrent(t *testing.T) {
    43  	opts := testOptions().
    44  		SetInstanceQueueSize(2).
    45  		SetQueueDropType(DropCurrent)
    46  	queue := newInstanceQueue(testPlacementInstance, opts).(*queue)
    47  
    48  	var result []byte
    49  	queue.writeFn = func(payload []byte) error {
    50  		result = payload
    51  		return nil
    52  	}
    53  	require.NoError(t, queue.Enqueue(testNewBuffer([]byte{42, 43, 44})))
    54  	require.NoError(t, queue.Enqueue(testNewBuffer([]byte{45, 46, 47})))
    55  	require.Equal(t, errWriterQueueFull, queue.Enqueue(testNewBuffer([]byte{42})))
    56  	queue.Flush()
    57  	require.EqualValues(t, []byte{42, 43, 44, 45, 46, 47}, result)
    58  }
    59  
    60  func TestInstanceQueueEnqueueQueueFullDropOldest(t *testing.T) {
    61  	opts := testOptions().
    62  		SetInstanceQueueSize(4)
    63  	queue := newInstanceQueue(testPlacementInstance, opts).(*queue)
    64  
    65  	var result []byte
    66  	queue.writeFn = func(payload []byte) error {
    67  		result = payload
    68  		return nil
    69  	}
    70  
    71  	require.NoError(t, queue.Enqueue(testNewBuffer([]byte{42})))
    72  	require.NoError(t, queue.Enqueue(testNewBuffer([]byte{42, 43, 44})))
    73  	require.NoError(t, queue.Enqueue(testNewBuffer([]byte{45, 46, 47})))
    74  	require.NoError(t, queue.Enqueue(testNewBuffer([]byte{1, 2, 3})))
    75  	require.NoError(t, queue.Enqueue(testNewBuffer([]byte{1})))
    76  
    77  	queue.Flush()
    78  	require.EqualValues(t, []byte{
    79  		42, 43, 44, 45, 46, 47, 1, 2, 3, 1,
    80  	}, result)
    81  
    82  	require.NoError(t, queue.Enqueue(testNewBuffer([]byte{})))
    83  	require.NoError(t, queue.Enqueue(testNewBuffer([]byte{1, 2, 3})))
    84  	require.NoError(t, queue.Enqueue(testNewBuffer([]byte{42})))
    85  	require.NoError(t, queue.Enqueue(testNewBuffer([]byte{})))
    86  	require.NoError(t, queue.Enqueue(testNewBuffer([]byte{42, 43, 44})))
    87  	require.NoError(t, queue.Enqueue(testNewBuffer([]byte{45, 46, 47})))
    88  	require.NoError(t, queue.Enqueue(testNewBuffer([]byte{1})))
    89  
    90  	queue.Flush()
    91  
    92  	require.EqualValues(t, []byte{
    93  		42, 42, 43, 44, 45, 46, 47, 1,
    94  	}, result)
    95  }
    96  
    97  func TestInstanceQueueEnqueueLargeBuffers(t *testing.T) {
    98  	var (
    99  		opts = testOptions().
   100  			SetInstanceQueueSize(4)
   101  		queue        = newInstanceQueue(testPlacementInstance, opts).(*queue)
   102  		largeBuf     = [_queueMaxWriteBufSize * 2]byte{}
   103  		bytesWritten int
   104  		timesWritten int
   105  	)
   106  
   107  	queue.writeFn = func(payload []byte) error {
   108  		bytesWritten += len(payload)
   109  		timesWritten++
   110  		return nil
   111  	}
   112  
   113  	require.NoError(t, queue.Enqueue(testNewBuffer([]byte{42})))
   114  	require.NoError(t, queue.Enqueue(testNewBuffer([]byte{42})))
   115  	require.NoError(t, queue.Enqueue(testNewBuffer([]byte{42})))
   116  	require.NoError(t, queue.Enqueue(testNewBuffer(largeBuf[:])))
   117  	queue.Flush()
   118  	require.Equal(t, len(largeBuf)+3, bytesWritten)
   119  	require.Equal(t, 2, timesWritten)
   120  
   121  	timesWritten, bytesWritten = 0, 0
   122  	require.NoError(t, queue.Enqueue(testNewBuffer(largeBuf[:])))
   123  	queue.Flush()
   124  	require.Equal(t, len(largeBuf), bytesWritten)
   125  	require.Equal(t, 1, timesWritten)
   126  }
   127  
   128  func TestInstanceQueueEnqueueSuccessDrainSuccess(t *testing.T) {
   129  	opts := testOptions().SetMaxBatchSize(1)
   130  	queue := newInstanceQueue(testPlacementInstance, opts).(*queue)
   131  	var (
   132  		res []byte
   133  	)
   134  
   135  	ready := make(chan struct{}, 1)
   136  	queue.writeFn = func(data []byte) error {
   137  		defer func() {
   138  			ready <- struct{}{}
   139  		}()
   140  		res = data
   141  		return nil
   142  	}
   143  
   144  	data := []byte("foobar")
   145  	require.NoError(t, queue.Enqueue(testNewBuffer(data)))
   146  
   147  	queue.Flush()
   148  	<-ready
   149  
   150  	require.Equal(t, data, res)
   151  }
   152  
   153  func TestInstanceQueueEnqueueSuccessDrainError(t *testing.T) {
   154  	opts := testOptions()
   155  	queue := newInstanceQueue(testPlacementInstance, opts).(*queue)
   156  	drained := make(chan struct{}, 1)
   157  	queue.writeFn = func(data []byte) error {
   158  		defer func() {
   159  			drained <- struct{}{}
   160  		}()
   161  		return errTestWrite
   162  	}
   163  
   164  	require.NoError(t, queue.Enqueue(testNewBuffer([]byte{42})))
   165  	queue.Flush()
   166  	// Wait for the queue to be drained.
   167  	<-drained
   168  }
   169  
   170  func TestInstanceQueueEnqueueSuccessWriteError(t *testing.T) {
   171  	opts := testOptions()
   172  	queue := newInstanceQueue(testPlacementInstance, opts).(*queue)
   173  	done := make(chan struct{}, 1)
   174  	queue.writeFn = func(data []byte) error {
   175  		err := queue.conn.Write(data)
   176  		done <- struct{}{}
   177  		return err
   178  	}
   179  
   180  	require.NoError(t, queue.Enqueue(testNewBuffer([]byte{0x1, 0x2})))
   181  	queue.Flush()
   182  	// Wait for the queue to be drained.
   183  	<-done
   184  }
   185  
   186  func TestInstanceQueueCloseAlreadyClosed(t *testing.T) {
   187  	opts := testOptions()
   188  	queue := newInstanceQueue(testPlacementInstance, opts).(*queue)
   189  	queue.closed.Store(true)
   190  
   191  	require.Equal(t, errInstanceQueueClosed, queue.Close())
   192  }
   193  
   194  func TestInstanceQueueCloseSuccess(t *testing.T) {
   195  	opts := testOptions()
   196  	queue := newInstanceQueue(testPlacementInstance, opts).(*queue)
   197  	require.NoError(t, queue.Close())
   198  	require.True(t, queue.closed.Load())
   199  	require.Error(t, queue.Enqueue(testNewBuffer([]byte("foo"))))
   200  }
   201  
   202  func TestInstanceQueueSizeIsPowerOfTwo(t *testing.T) {
   203  	for _, tt := range []struct {
   204  		size     int
   205  		expected int
   206  	}{
   207  		{1, 1},
   208  		{2, 2},
   209  		{3, 4},
   210  		{4, 4},
   211  		{42, 64},
   212  		{123, 128},
   213  	} {
   214  		opts := testOptions().SetInstanceQueueSize(tt.size)
   215  		q := newInstanceQueue(testPlacementInstance, opts).(*queue)
   216  		require.Equal(t, tt.expected, cap(q.buf.b))
   217  	}
   218  }
   219  
   220  func TestDropTypeUnmarshalYAML(t *testing.T) {
   221  	type S struct {
   222  		A DropType
   223  	}
   224  
   225  	tests := []struct {
   226  		input    []byte
   227  		expected DropType
   228  	}{
   229  		{
   230  			input:    []byte("a: oldest\n"),
   231  			expected: DropOldest,
   232  		},
   233  		{
   234  			input:    []byte("a: current\n"),
   235  			expected: DropCurrent,
   236  		},
   237  	}
   238  
   239  	for _, test := range tests {
   240  		var s S
   241  		err := yaml.Unmarshal(test.input, &s)
   242  		require.NoError(t, err)
   243  		assert.Equal(t, test.expected, s.A)
   244  	}
   245  }
   246  
   247  func TestRoundUpToPowerOfTwo(t *testing.T) {
   248  	for _, tt := range []struct {
   249  		in, out int
   250  	}{
   251  		{1, 1},
   252  		{2, 2},
   253  		{3, 4},
   254  		{4, 4},
   255  		{5, 8},
   256  		{7, 8},
   257  		{33, 64},
   258  		{42, 64},
   259  	} {
   260  		assert.Equal(t, tt.out, roundUpToPowerOfTwo(tt.in))
   261  	}
   262  }
   263  
   264  func testNewBuffer(data []byte) protobuf.Buffer { return protobuf.NewBuffer(data, nil) }