github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/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) }