github.com/m3db/m3@v1.5.0/src/query/api/v1/handler/database/kvstore_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 database 22 23 import ( 24 "encoding/json" 25 "errors" 26 "testing" 27 28 "github.com/gogo/protobuf/jsonpb" 29 "github.com/golang/mock/gomock" 30 "github.com/stretchr/testify/require" 31 "go.uber.org/zap" 32 "google.golang.org/protobuf/runtime/protoiface" 33 34 "github.com/m3db/m3/src/cluster/generated/proto/commonpb" 35 "github.com/m3db/m3/src/cluster/generated/proto/kvpb" 36 "github.com/m3db/m3/src/cluster/kv" 37 "github.com/m3db/m3/src/dbnode/kvconfig" 38 ) 39 40 func TestUpdateQueryLimits(t *testing.T) { 41 ctrl := gomock.NewController(t) 42 defer ctrl.Finish() 43 44 tests := []struct { 45 name string 46 limits *kvpb.QueryLimits 47 commit bool 48 expectedError string 49 }{ 50 { 51 name: `nil`, 52 limits: nil, 53 commit: true, 54 }, 55 { 56 name: `empty`, 57 limits: &kvpb.QueryLimits{}, 58 commit: true, 59 }, 60 { 61 name: `only block - commit`, 62 limits: &kvpb.QueryLimits{ 63 MaxRecentlyQueriedSeriesBlocks: &kvpb.QueryLimit{ 64 Limit: 1, 65 LookbackSeconds: 15, 66 ForceExceeded: true, 67 }, 68 }, 69 commit: true, 70 }, 71 { 72 name: `only metadata - commit`, 73 limits: &kvpb.QueryLimits{ 74 MaxRecentlyQueriedMetadataRead: &kvpb.QueryLimit{ 75 Limit: 1, 76 LookbackSeconds: 15, 77 ForceExceeded: true, 78 }, 79 }, 80 commit: true, 81 }, 82 { 83 name: `only block - no commit`, 84 limits: &kvpb.QueryLimits{ 85 MaxRecentlyQueriedSeriesBlocks: &kvpb.QueryLimit{ 86 Limit: 1, 87 LookbackSeconds: 15, 88 ForceExceeded: true, 89 }, 90 }, 91 commit: false, 92 }, 93 { 94 name: `all - commit`, 95 limits: &kvpb.QueryLimits{ 96 MaxRecentlyQueriedSeriesBlocks: &kvpb.QueryLimit{ 97 Limit: 1, 98 LookbackSeconds: 15, 99 ForceExceeded: true, 100 }, 101 MaxRecentlyQueriedSeriesDiskBytesRead: &kvpb.QueryLimit{ 102 Limit: 1, 103 LookbackSeconds: 15, 104 ForceExceeded: true, 105 }, 106 MaxRecentlyQueriedSeriesDiskRead: &kvpb.QueryLimit{ 107 Limit: 1, 108 LookbackSeconds: 15, 109 ForceExceeded: true, 110 }, 111 MaxRecentlyQueriedMetadataRead: &kvpb.QueryLimit{ 112 Limit: 1, 113 LookbackSeconds: 15, 114 ForceExceeded: true, 115 }, 116 }, 117 commit: true, 118 }, 119 { 120 name: `all - no commit`, 121 limits: &kvpb.QueryLimits{ 122 MaxRecentlyQueriedSeriesBlocks: &kvpb.QueryLimit{ 123 Limit: 1, 124 LookbackSeconds: 15, 125 ForceExceeded: true, 126 }, 127 MaxRecentlyQueriedSeriesDiskBytesRead: &kvpb.QueryLimit{ 128 Limit: 1, 129 LookbackSeconds: 15, 130 ForceExceeded: true, 131 }, 132 MaxRecentlyQueriedSeriesDiskRead: &kvpb.QueryLimit{ 133 Limit: 1, 134 LookbackSeconds: 15, 135 ForceExceeded: true, 136 }, 137 }, 138 commit: false, 139 }, 140 } 141 142 for _, test := range tests { 143 limitJSON, err := json.Marshal(test.limits) 144 require.NoError(t, err) 145 146 update := &KeyValueUpdate{ 147 Key: kvconfig.QueryLimits, 148 Value: json.RawMessage(limitJSON), 149 Commit: test.commit, 150 } 151 152 storeMock := kv.NewMockStore(ctrl) 153 154 // (A) test no old value. 155 storeMock.EXPECT().Get(kvconfig.QueryLimits).Return(nil, kv.ErrNotFound) 156 if test.commit { 157 storeMock.EXPECT().Set(kvconfig.QueryLimits, gomock.Any()).Return(0, nil) 158 } 159 160 handler := &KeyValueStoreHandler{} 161 r, err := handler.update(zap.NewNop(), storeMock, update) 162 require.NoError(t, err) 163 require.Equal(t, kvconfig.QueryLimits, r.Key) 164 require.Equal(t, json.RawMessage("{}"), r.Old) 165 require.Equal(t, json.RawMessage(limitJSON), r.New) 166 require.Equal(t, 0, r.Version) 167 168 // (B) test old value. 169 oldLimits := &kvpb.QueryLimits{ 170 MaxRecentlyQueriedSeriesBlocks: &kvpb.QueryLimit{ 171 Limit: 10, 172 LookbackSeconds: 30, 173 ForceExceeded: false, 174 }, 175 MaxRecentlyQueriedSeriesDiskRead: &kvpb.QueryLimit{ 176 Limit: 100, 177 LookbackSeconds: 300, 178 ForceExceeded: false, 179 }, 180 } 181 mockVal := kv.NewMockValue(ctrl) 182 storeMock.EXPECT().Get(kvconfig.QueryLimits).Return(mockVal, nil) 183 mockVal.EXPECT().Unmarshal(gomock.Any()).DoAndReturn(func(v *kvpb.QueryLimits) error { 184 v.MaxRecentlyQueriedSeriesBlocks = oldLimits.MaxRecentlyQueriedSeriesBlocks 185 v.MaxRecentlyQueriedSeriesDiskRead = oldLimits.MaxRecentlyQueriedSeriesDiskRead 186 return nil 187 }) 188 if test.commit { 189 storeMock.EXPECT().Set(kvconfig.QueryLimits, gomock.Any()).Return(0, nil) 190 } 191 192 handler = &KeyValueStoreHandler{} 193 r, err = handler.update(zap.NewNop(), storeMock, update) 194 require.NoError(t, err) 195 196 var oldResult kvpb.QueryLimits 197 err = jsonpb.UnmarshalString(string(r.Old), &oldResult) 198 require.NoError(t, err) 199 200 require.Equal(t, kvconfig.QueryLimits, r.Key) 201 require.Equal(t, *oldLimits.MaxRecentlyQueriedSeriesBlocks, *oldResult.MaxRecentlyQueriedSeriesBlocks) 202 require.Nil(t, oldResult.MaxRecentlyQueriedSeriesDiskBytesRead) 203 require.Equal(t, *oldLimits.MaxRecentlyQueriedSeriesDiskRead, *oldResult.MaxRecentlyQueriedSeriesDiskRead) 204 require.Equal(t, json.RawMessage(limitJSON), r.New) 205 require.Equal(t, 0, r.Version) 206 } 207 } 208 209 func TestProtoParser(t *testing.T) { 210 handler := &KeyValueStoreHandler{ 211 kvStoreProtoParser: func(k string) (protoiface.MessageV1, error) { 212 if k == "test-key" { 213 return &commonpb.Int64Proto{}, nil 214 } 215 return nil, errors.New("invalid") 216 }, 217 } 218 219 s, err := handler.newKVProtoMessage("not-present") 220 require.Error(t, err) 221 require.Nil(t, s) 222 223 s, err = handler.newKVProtoMessage("test-key") 224 require.NoError(t, err) 225 require.NotNil(t, s) 226 227 s, err = handler.newKVProtoMessage(kvconfig.NamespacesKey) 228 require.NoError(t, err) 229 require.NotNil(t, s) 230 }