github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/x/serialize/encoder_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 serialize
    22  
    23  import (
    24  	"strings"
    25  	"testing"
    26  
    27  	"github.com/m3db/m3/src/x/checked"
    28  	"github.com/m3db/m3/src/x/ident"
    29  
    30  	"github.com/golang/mock/gomock"
    31  	"github.com/stretchr/testify/require"
    32  )
    33  
    34  func newTestEncoderOpts() TagEncoderOptions {
    35  	return NewTagEncoderOptions()
    36  }
    37  
    38  func newTestTagEncoder() TagEncoder {
    39  	return newTagEncoder(defaultNewCheckedBytesFn, newTestEncoderOpts(), nil)
    40  }
    41  
    42  func TestEmptyEncode(t *testing.T) {
    43  	e := newTestTagEncoder()
    44  	require.NoError(t, e.Encode(ident.EmptyTagIterator))
    45  
    46  	bc, ok := e.Data()
    47  	require.True(t, ok)
    48  	require.NotNil(t, bc)
    49  	b := bc.Bytes()
    50  	require.Len(t, b, 4)
    51  	require.Equal(t, headerMagicBytes, b[:2])
    52  	require.Equal(t, []byte{0x0, 0x0}, b[2:4])
    53  }
    54  
    55  func TestEncodeResetTwice(t *testing.T) {
    56  	e := newTestTagEncoder()
    57  	require.NoError(t, e.Encode(ident.EmptyTagIterator))
    58  	e.Reset()
    59  	e.Reset()
    60  	require.NoError(t, e.Encode(ident.EmptyTagIterator))
    61  }
    62  
    63  func TestInuseEncode(t *testing.T) {
    64  	e := newTestTagEncoder()
    65  	require.NoError(t, e.Encode(ident.EmptyTagIterator))
    66  	require.Error(t, e.Encode(ident.EmptyTagIterator))
    67  }
    68  
    69  func TestTagEncoderLeavesOriginalIterator(t *testing.T) {
    70  	e := newTestTagEncoder()
    71  	tags := ident.NewTagsIterator(ident.NewTags(
    72  		ident.StringTag("abc", "defg"),
    73  		ident.StringTag("x", "bar"),
    74  	))
    75  
    76  	require.Equal(t, 2, tags.Remaining())
    77  	require.NoError(t, e.Encode(tags))
    78  	require.Equal(t, 2, tags.Remaining())
    79  }
    80  
    81  func TestTagEncoderEmpty(t *testing.T) {
    82  	e := newTestTagEncoder()
    83  	tags := ident.MustNewTagStringsIterator("abc", "")
    84  	require.NoError(t, e.Encode(tags))
    85  
    86  	e = newTestTagEncoder()
    87  	tags = ident.MustNewTagStringsIterator("", "abc")
    88  	require.Error(t, e.Encode(tags))
    89  }
    90  
    91  func TestSimpleEncode(t *testing.T) {
    92  	e := newTestTagEncoder()
    93  
    94  	tags := ident.NewTagsIterator(ident.NewTags(
    95  		ident.StringTag("abc", "defg"),
    96  		ident.StringTag("x", "bar"),
    97  	))
    98  	require.NoError(t, e.Encode(tags))
    99  
   100  	bc, ok := e.Data()
   101  	require.True(t, ok)
   102  	require.NotNil(t, bc)
   103  	b := bc.Bytes()
   104  	numExpectedBytes := 2 /* header */ + 2 /* num tags */ +
   105  		2 /* abc length */ + len("abc") +
   106  		2 /* defg length */ + len("defg") +
   107  		2 /* x length */ + len("x") +
   108  		2 /* bar length */ + len("bar")
   109  	require.Len(t, b, numExpectedBytes)
   110  	require.Equal(t, headerMagicBytes, b[:2])
   111  	require.Equal(t, encodeUInt16(2, make([]byte, 2)), b[2:4])
   112  	require.Equal(t, uint16(3), decodeUInt16(b[4:6])) /* len abc */
   113  	require.Equal(t, "abc", string(b[6:9]))
   114  	require.Equal(t, uint16(4), decodeUInt16(b[9:11])) /* len defg */
   115  	require.Equal(t, "defg", string(b[11:15]))
   116  	require.Equal(t, uint16(1), decodeUInt16(b[15:17])) /* len x */
   117  	require.Equal(t, "x", string(b[17:18]))
   118  	require.Equal(t, uint16(3), decodeUInt16(b[18:20])) /* len bar */
   119  	require.Equal(t, "bar", string(b[20:23]))
   120  }
   121  
   122  func TestTagEncoderErrorEncoding(t *testing.T) {
   123  	opts := NewTagEncoderOptions()
   124  	e := newTagEncoder(defaultNewCheckedBytesFn, opts, nil)
   125  	maxLiteralLen := int(opts.TagSerializationLimits().MaxTagLiteralLength())
   126  	tags := ident.NewTagsIterator(ident.NewTags(
   127  		ident.StringTag("abc", "defg"),
   128  		ident.StringTag("x", strings.Repeat("x", 1+maxLiteralLen)),
   129  	))
   130  
   131  	require.Error(t, e.Encode(tags))
   132  	d, ok := e.Data()
   133  	require.Nil(t, d)
   134  	require.False(t, ok)
   135  
   136  	e.Reset()
   137  	tags = ident.NewTagsIterator(ident.NewTags(
   138  		ident.StringTag("abc", "defg"),
   139  		ident.StringTag("x", strings.Repeat("x", maxLiteralLen)),
   140  	))
   141  	require.NoError(t, e.Encode(tags))
   142  }
   143  
   144  func TestEmptyTagIterEncode(t *testing.T) {
   145  	ctrl := gomock.NewController(t)
   146  	defer ctrl.Finish()
   147  
   148  	mockBytes := checked.NewMockBytes(ctrl)
   149  	newBytesFn := func([]byte, checked.BytesOptions) checked.Bytes {
   150  		return mockBytes
   151  	}
   152  
   153  	iter := ident.NewMockTagIterator(ctrl)
   154  
   155  	mockBytes.EXPECT().IncRef()
   156  	mockBytes.EXPECT().Reset(gomock.Any())
   157  	gomock.InOrder(
   158  		mockBytes.EXPECT().NumRef().Return(0),
   159  		iter.EXPECT().Rewind(),
   160  		iter.EXPECT().Remaining().Return(0),
   161  		iter.EXPECT().Next().Return(false),
   162  		iter.EXPECT().Err().Return(nil),
   163  		iter.EXPECT().Rewind(),
   164  	)
   165  
   166  	enc := newTagEncoder(newBytesFn, newTestEncoderOpts(), nil)
   167  	require.NoError(t, enc.Encode(iter))
   168  }
   169  
   170  func TestTooManyTags(t *testing.T) {
   171  	ctrl := gomock.NewController(t)
   172  	defer ctrl.Finish()
   173  
   174  	iter := ident.NewMockTagIterator(ctrl)
   175  	testOpts := newTestEncoderOpts()
   176  
   177  	maxNumTags := testOpts.TagSerializationLimits().MaxNumberTags()
   178  	gomock.InOrder(
   179  		iter.EXPECT().Rewind(),
   180  		iter.EXPECT().Remaining().Return(1+int(maxNumTags)),
   181  		iter.EXPECT().Rewind(),
   182  	)
   183  
   184  	enc := newTagEncoder(defaultNewCheckedBytesFn, testOpts, nil)
   185  	require.Error(t, enc.Encode(iter))
   186  }
   187  
   188  func TestSingleValueTagIterEncode(t *testing.T) {
   189  	ctrl := gomock.NewController(t)
   190  	defer ctrl.Finish()
   191  
   192  	mockBytes := checked.NewMockBytes(ctrl)
   193  	newBytesFn := func([]byte, checked.BytesOptions) checked.Bytes {
   194  		return mockBytes
   195  	}
   196  
   197  	iter := ident.NewMockTagIterator(ctrl)
   198  
   199  	mockBytes.EXPECT().IncRef()
   200  	mockBytes.EXPECT().Reset(gomock.Any())
   201  	gomock.InOrder(
   202  		mockBytes.EXPECT().NumRef().Return(0),
   203  		iter.EXPECT().Rewind(),
   204  		iter.EXPECT().Remaining().Return(1),
   205  		iter.EXPECT().Next().Return(true),
   206  		iter.EXPECT().Current().Return(
   207  			ident.StringTag("some", "tag"),
   208  		),
   209  		iter.EXPECT().Next().Return(false),
   210  		iter.EXPECT().Err().Return(nil),
   211  		iter.EXPECT().Rewind(),
   212  	)
   213  
   214  	enc := newTagEncoder(newBytesFn, newTestEncoderOpts(), nil)
   215  	require.NoError(t, enc.Encode(iter))
   216  
   217  	mockBytes.EXPECT().NumRef().Return(1)
   218  	require.Error(t, enc.Encode(iter))
   219  
   220  	mockBytes.EXPECT().NumRef().Return(1)
   221  	mockBytes.EXPECT().Reset(nil)
   222  	mockBytes.EXPECT().DecRef()
   223  	enc.Reset()
   224  }