github.com/m3db/m3@v1.5.0/src/dbnode/network/server/tchannelthrift/cluster/service_test.go (about)

     1  // Copyright (c) 2021 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 cluster
    22  
    23  import (
    24  	"fmt"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/golang/mock/gomock"
    29  	"github.com/stretchr/testify/require"
    30  	"github.com/uber/tchannel-go/thrift"
    31  
    32  	"github.com/m3db/m3/src/dbnode/client"
    33  	"github.com/m3db/m3/src/dbnode/encoding"
    34  	"github.com/m3db/m3/src/dbnode/generated/thrift/rpc"
    35  	"github.com/m3db/m3/src/dbnode/storage/index"
    36  	"github.com/m3db/m3/src/dbnode/topology"
    37  	xtest "github.com/m3db/m3/src/x/test"
    38  )
    39  
    40  func TestSessionOpts(t *testing.T) {
    41  	clientOpts := client.NewOptions().
    42  		SetIterationOptions(index.IterationOptions{
    43  			IterateEqualTimestampStrategy: encoding.IterateLowestValue,
    44  		}).
    45  		SetReadConsistencyLevel(topology.ReadConsistencyLevelMajority)
    46  	rcAll := rpc.ReadConsistency_ALL
    47  	csHighest := rpc.EqualTimestampStrategy_HIGHEST_VALUE
    48  	cases := []struct {
    49  		name     string
    50  		reqOpts  *rpc.ClusterQueryOptions
    51  		sessOpts sessionOpts
    52  	}{
    53  		{
    54  			name: "nil opts",
    55  			sessOpts: sessionOpts{
    56  				readConsistency:        topology.ReadConsistencyLevelMajority,
    57  				equalTimestampStrategy: encoding.IterateLowestValue,
    58  			},
    59  		},
    60  		{
    61  			name:    "not set",
    62  			reqOpts: &rpc.ClusterQueryOptions{},
    63  			sessOpts: sessionOpts{
    64  				readConsistency:        topology.ReadConsistencyLevelMajority,
    65  				equalTimestampStrategy: encoding.IterateLowestValue,
    66  			},
    67  		},
    68  		{
    69  			name: "only read consistency",
    70  			reqOpts: &rpc.ClusterQueryOptions{
    71  				ReadConsistency: &rcAll,
    72  			},
    73  			sessOpts: sessionOpts{
    74  				readConsistency:        topology.ReadConsistencyLevelAll,
    75  				equalTimestampStrategy: encoding.IterateLowestValue,
    76  				consistencyOverride:    true,
    77  			},
    78  		},
    79  		{
    80  			name: "only conflict strategy",
    81  			reqOpts: &rpc.ClusterQueryOptions{
    82  				ConflictResolutionStrategy: &csHighest,
    83  			},
    84  			sessOpts: sessionOpts{
    85  				readConsistency:        topology.ReadConsistencyLevelMajority,
    86  				equalTimestampStrategy: encoding.IterateHighestValue,
    87  			},
    88  		},
    89  		{
    90  			name: "both set",
    91  			reqOpts: &rpc.ClusterQueryOptions{
    92  				ReadConsistency:            &rcAll,
    93  				ConflictResolutionStrategy: &csHighest,
    94  			},
    95  			sessOpts: sessionOpts{
    96  				readConsistency:        topology.ReadConsistencyLevelAll,
    97  				equalTimestampStrategy: encoding.IterateHighestValue,
    98  				consistencyOverride:    true,
    99  			},
   100  		},
   101  	}
   102  
   103  	for _, tc := range cases {
   104  		tc := tc
   105  		t.Run(tc.name, func(t *testing.T) {
   106  			ctrl := xtest.NewController(t)
   107  			defer ctrl.Finish()
   108  
   109  			c := client.NewMockClient(ctrl)
   110  			c.EXPECT().Options().Return(clientOpts).AnyTimes()
   111  			sess := client.NewMockSession(ctrl)
   112  			iters := encoding.NewMockSeriesIterators(ctrl)
   113  			sess.EXPECT().FetchTagged(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(
   114  				iters, client.FetchResponseMetadata{}, nil)
   115  			iters.EXPECT().Len().Return(0)
   116  			iters.EXPECT().Iters().Return(nil)
   117  			iters.EXPECT().Close()
   118  
   119  			ctx, cancel := thrift.NewContext(time.Second)
   120  			defer cancel()
   121  			req := &rpc.QueryRequest{
   122  				ClusterOptions: tc.reqOpts,
   123  			}
   124  			c.EXPECT().NewSessionWithOptions(tc.sessOpts).Return(sess, nil)
   125  			s := NewService(c).(*service)
   126  			res, err := s.Query(ctx, req)
   127  			require.NoError(t, err)
   128  			require.NotNil(t, res)
   129  		})
   130  	}
   131  }
   132  
   133  func (s sessionOpts) Matches(x interface{}) bool {
   134  	if c, ok := x.(client.Options); ok {
   135  		if s.equalTimestampStrategy != c.IterationOptions().IterateEqualTimestampStrategy {
   136  			return false
   137  		}
   138  		if s.readConsistency != c.ReadConsistencyLevel() {
   139  			return false
   140  		}
   141  		if s.consistencyOverride && c.RuntimeOptionsManager() != nil {
   142  			return false
   143  		}
   144  		return true
   145  	}
   146  	return false
   147  }
   148  
   149  func (s sessionOpts) String() string {
   150  	return fmt.Sprintf("%v %v", s.readConsistency, s.equalTimestampStrategy)
   151  }
   152  
   153  var _ gomock.Matcher = &sessionOpts{}