github.com/m3db/m3@v1.5.0/src/dbnode/encoding/proto/custom_unmarshal_test.go (about)

     1  // Copyright (c) 2019 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 proto
    22  
    23  import (
    24  	"bytes"
    25  	"math"
    26  	"testing"
    27  	"time"
    28  
    29  	"github.com/jhump/protoreflect/dynamic"
    30  	"github.com/stretchr/testify/require"
    31  )
    32  
    33  func TestCustomFieldUnmarshaller(t *testing.T) {
    34  	// Store in a var to prevent the compiler from complaining about overflow errors.
    35  	neg1 := -1
    36  
    37  	testCases := []struct {
    38  		timestamp  time.Time
    39  		latitude   float64
    40  		longitude  float64
    41  		epoch      int64
    42  		deliveryID []byte
    43  		attributes map[string]string
    44  
    45  		expectedSortedCustomFields []unmarshalValue
    46  	}{
    47  		{
    48  			latitude:  0.1,
    49  			longitude: 1.1,
    50  			epoch:     -1,
    51  
    52  			expectedSortedCustomFields: []unmarshalValue{
    53  				{
    54  					fieldNumber: 1,
    55  					v:           math.Float64bits(0.1),
    56  				},
    57  				{
    58  					fieldNumber: 2,
    59  					v:           math.Float64bits(1.1),
    60  				},
    61  				{
    62  					fieldNumber: 3,
    63  					v:           uint64(neg1),
    64  				},
    65  			},
    66  		},
    67  		{
    68  			latitude:   0.1,
    69  			longitude:  1.1,
    70  			epoch:      0,
    71  			deliveryID: []byte("123123123123"),
    72  
    73  			expectedSortedCustomFields: []unmarshalValue{
    74  				{
    75  					fieldNumber: 1,
    76  					v:           math.Float64bits(0.1),
    77  				},
    78  				{
    79  					fieldNumber: 2,
    80  					v:           math.Float64bits(1.1),
    81  				},
    82  				// Note that epoch (field number 3) is not included here because default
    83  				// value are not included in a marshalled protobuf stream (their absence
    84  				// implies a default vlaue for a field) which means they're also not
    85  				// returned by the `sortedCustomFieldValues` method.
    86  				{
    87  					fieldNumber: 4,
    88  					bytes:       []byte("123123123123"),
    89  				},
    90  			},
    91  		},
    92  		{
    93  			latitude:   0.2,
    94  			longitude:  2.2,
    95  			epoch:      1,
    96  			deliveryID: []byte("789789789789"),
    97  			attributes: map[string]string{"key1": "val1"},
    98  
    99  			expectedSortedCustomFields: []unmarshalValue{
   100  				{
   101  					fieldNumber: 1,
   102  					v:           math.Float64bits(0.2),
   103  				},
   104  				{
   105  					fieldNumber: 2,
   106  					v:           math.Float64bits(2.2),
   107  				},
   108  				{
   109  					fieldNumber: 3,
   110  					v:           (1),
   111  				},
   112  				{
   113  					fieldNumber: 4,
   114  					bytes:       []byte("789789789789"),
   115  				},
   116  			},
   117  		},
   118  	}
   119  
   120  	unmarshaller := newCustomFieldUnmarshaller(customUnmarshallerOptions{})
   121  	for _, tc := range testCases {
   122  		vl := newVL(
   123  			tc.latitude, tc.longitude, tc.epoch, tc.deliveryID, tc.attributes)
   124  		marshalledVL, err := vl.Marshal()
   125  		require.NoError(t, err)
   126  
   127  		unmarshaller.resetAndUnmarshal(testVLSchema, marshalledVL)
   128  		sortedCustomFieldValues := unmarshaller.sortedCustomFieldValues()
   129  		require.Equal(t, len(tc.expectedSortedCustomFields), len(sortedCustomFieldValues))
   130  
   131  		lastFieldNum := -1
   132  		for i, curr := range sortedCustomFieldValues {
   133  			var (
   134  				fieldNum = curr.fieldNumber
   135  				expected = tc.expectedSortedCustomFields[i]
   136  			)
   137  			// Make sure iteration is sorted and values match.
   138  			require.True(t, int(fieldNum) > lastFieldNum)
   139  			require.Equal(t, expected, curr)
   140  			switch fieldNum {
   141  			case 1:
   142  				require.Equal(t, tc.latitude, curr.asFloat64())
   143  			case 2:
   144  				require.Equal(t, tc.longitude, curr.asFloat64())
   145  			case 3:
   146  				require.Equal(t, tc.epoch, curr.asInt64())
   147  			case 4:
   148  				require.True(t, bytes.Equal(tc.deliveryID, curr.asBytes()))
   149  			}
   150  			i++
   151  		}
   152  
   153  		if len(tc.attributes) > 0 {
   154  			require.Equal(t, len(tc.attributes), unmarshaller.numNonCustomValues())
   155  			nonCustomFieldValues := unmarshaller.sortedNonCustomFieldValues()
   156  			require.Equal(t, 1, len(nonCustomFieldValues))
   157  			require.Equal(t, int32(5), nonCustomFieldValues[0].fieldNum)
   158  
   159  			assertAttributesEqualMarshalledBytes(
   160  				t,
   161  				nonCustomFieldValues[0].marshalled,
   162  				tc.attributes)
   163  		} else {
   164  			require.Equal(t, 0, unmarshaller.numNonCustomValues())
   165  		}
   166  	}
   167  }
   168  
   169  func assertAttributesEqualMarshalledBytes(
   170  	t *testing.T,
   171  	actualMarshalled []byte,
   172  	attrs map[string]string,
   173  ) {
   174  	m := dynamic.NewMessage(testVLSchema)
   175  	m.SetFieldByName("attributes", attrs)
   176  	expectedMarshalled, err := m.Marshal()
   177  
   178  	require.NoError(t, err)
   179  	require.Equal(t, expectedMarshalled, actualMarshalled)
   180  }