github.com/siglens/siglens@v0.0.0-20240328180423-f7ce9ae441ed/pkg/querytracker/querytracker_test.go (about) 1 /* 2 Copyright 2023. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package querytracker 18 19 import ( 20 "os" 21 "testing" 22 23 "github.com/stretchr/testify/assert" 24 25 "github.com/siglens/siglens/pkg/config" 26 . "github.com/siglens/siglens/pkg/segment/structs" 27 "github.com/siglens/siglens/pkg/segment/utils" 28 ) 29 30 // used only by tests to reset tracked info 31 func resetInternalQTInfo() { 32 localPersistentAggs = make(map[string]*PersistentAggregation) 33 localPersistentQueries = make(map[string]*PersistentSearchNode) 34 allNodesPQsSorted = []*PersistentSearchNode{} 35 allPersistentAggsSorted = []*PersistentAggregation{} 36 } 37 38 func Test_GetQTUsageInfo(t *testing.T) { 39 resetInternalQTInfo() 40 config.SetPQSEnabled(true) 41 qVal, err := utils.CreateDtypeEnclosure("iOS", 0) 42 assert.Nil(t, err) 43 44 sNode := &SearchNode{ 45 AndSearchConditions: &SearchCondition{ 46 SearchQueries: []*SearchQuery{ 47 { 48 ExpressionFilter: &SearchExpression{ 49 LeftSearchInput: &SearchExpressionInput{ColumnName: "os"}, 50 FilterOp: utils.Equals, 51 RightSearchInput: &SearchExpressionInput{ColumnValue: qVal}, 52 }, 53 SearchType: SimpleExpression, 54 }, 55 }, 56 }, 57 NodeType: ColumnValueQuery, 58 } 59 sNodeHash := GetHashForQuery(sNode) 60 tableName := []string{"ind-tab-v1"} 61 for i := 0; i < 90; i++ { 62 UpdateQTUsage(tableName, sNode, nil) 63 } 64 65 us, err := GetQTUsageInfo(tableName, sNode) 66 assert.Nil(t, err) 67 assert.NotNil(t, us) 68 expected := uint32(90) 69 assert.Equal(t, expected, us.TotalUsage, "expected %v usagecount but got %v", expected, us.TotalUsage) 70 71 ok, err := IsQueryPersistent(tableName, sNode) 72 assert.Nil(t, err) 73 assert.Equal(t, true, ok, "query was supposed to be persistent") 74 75 sNode.AndSearchConditions.SearchQueries[0].ExpressionFilter.LeftSearchInput.ColumnName = "os2" 76 ok, err = IsQueryPersistent(tableName, sNode) 77 assert.Nil(t, err) 78 assert.Equal(t, false, ok, "query was supposed to be NOT persistent") 79 80 res, err := GetTopNPersistentSearches(tableName[0], 0) 81 assert.Nil(t, err) 82 assert.Equal(t, 1, len(res), "There should be 1 persistent query but got=%v", len(res)) 83 84 wildCard, err := utils.CreateDtypeEnclosure("*", 0) 85 assert.Nil(t, err) 86 87 matchAllOne := &SearchNode{ 88 AndSearchConditions: &SearchCondition{ 89 SearchQueries: []*SearchQuery{ 90 { 91 ExpressionFilter: &SearchExpression{ 92 LeftSearchInput: &SearchExpressionInput{ColumnName: "*"}, 93 FilterOp: utils.Equals, 94 RightSearchInput: &SearchExpressionInput{ColumnValue: wildCard}, 95 }, 96 SearchType: SimpleExpression, 97 }, 98 }, 99 }, 100 NodeType: MatchAllQuery, 101 } 102 103 UpdateQTUsage(tableName, matchAllOne, nil) 104 105 _, err = GetQTUsageInfo(tableName, matchAllOne) 106 assert.NotNil(t, err, "match all should not be added to query tracker") 107 108 ok, err = IsQueryPersistent(tableName, matchAllOne) 109 assert.Nil(t, err) 110 assert.Equal(t, false, ok, "query is not persistent") 111 112 matchAllHash := GetHashForQuery(matchAllOne) 113 res, err = GetTopNPersistentSearches(tableName[0], 0) 114 assert.Nil(t, err) 115 assert.Equal(t, 1, len(res), "There should be 1 persistent query but got=%v", len(res)) 116 assert.Contains(t, res, sNodeHash, "sNodeHash=%v should exist in result=%+v", sNodeHash, res) 117 assert.NotContains(t, res, matchAllHash, "matchAllHash=%v should not exist in result=%+v", matchAllHash, res) 118 assert.Equal(t, ColumnValueQuery, res[sNodeHash].NodeType, "non match all result %+v should exist", res[sNodeHash]) 119 assert.Nil(t, res[matchAllHash], "match all result %+v should exist", res[matchAllHash]) 120 } 121 122 func Test_ReadWriteQTUsage(t *testing.T) { 123 resetInternalQTInfo() 124 config.SetPQSEnabled(true) 125 config.SetSSInstanceName("qt-test") 126 err := config.InitDerivedConfig("test") 127 assert.NoError(t, err) 128 _ = os.RemoveAll("./ingestnodes") 129 _ = os.RemoveAll("./querynodes") 130 131 qVal, err := utils.CreateDtypeEnclosure("batch-101", 0) 132 assert.Nil(t, err) 133 sNode := &SearchNode{ 134 AndSearchConditions: &SearchCondition{ 135 SearchQueries: []*SearchQuery{ 136 { 137 ExpressionFilter: &SearchExpression{ 138 LeftSearchInput: &SearchExpressionInput{ColumnName: "batch"}, 139 FilterOp: utils.Equals, 140 RightSearchInput: &SearchExpressionInput{ColumnValue: qVal}, 141 }, 142 SearchType: SimpleExpression, 143 }, 144 }, 145 }, 146 NodeType: ColumnValueQuery, 147 } 148 149 sNodeHash := GetHashForQuery(sNode) 150 tableName := []string{"test-1"} 151 152 aggs := &QueryAggregators{ 153 GroupByRequest: &GroupByRequest{ 154 MeasureOperations: []*MeasureAggregator{ 155 {MeasureCol: "col3", MeasureFunc: utils.Avg}, 156 {MeasureCol: "col4", MeasureFunc: utils.Count}, 157 }, 158 GroupByColumns: []string{"col1", "col2"}, 159 }, 160 } 161 aggsHash := GetHashForAggs(aggs) 162 UpdateQTUsage(tableName, sNode, aggs) 163 164 flushPQueriesToDisk() 165 resetInternalQTInfo() 166 readSavedQueryInfo() 167 assert.Len(t, allNodesPQsSorted, 1) 168 assert.Len(t, localPersistentQueries, 1) 169 assert.Len(t, allPersistentAggsSorted, 1) 170 assert.Len(t, localPersistentAggs, 1) 171 172 assert.Contains(t, localPersistentQueries, sNodeHash) 173 assert.Contains(t, localPersistentAggs, aggsHash) 174 } 175 176 func Test_GetTopPersistentAggs(t *testing.T) { 177 resetInternalQTInfo() 178 config.SetPQSEnabled(true) 179 aggs := &QueryAggregators{ 180 GroupByRequest: &GroupByRequest{ 181 MeasureOperations: []*MeasureAggregator{ 182 {MeasureCol: "col3", MeasureFunc: utils.Avg}, 183 {MeasureCol: "col4", MeasureFunc: utils.Count}, 184 }, 185 GroupByColumns: []string{"col1", "col2"}, 186 }, 187 } 188 tableName := []string{"test-1"} 189 UpdateQTUsage(tableName, nil, aggs) 190 grpCols, measure := GetTopPersistentAggs("test-2") 191 assert.Len(t, grpCols, 0) 192 assert.Len(t, measure, 0) 193 194 grpCols, measure = GetTopPersistentAggs("test-1") 195 assert.Len(t, grpCols, 2) 196 assert.Len(t, measure, 2) 197 assert.Contains(t, grpCols, "col1") 198 assert.Contains(t, grpCols, "col2") 199 200 var mCol3 string 201 var mCol4 string 202 for mcol := range measure { 203 if mcol == "col3" { 204 mCol3 = mcol 205 } else if mcol == "col4" { 206 mCol4 = mcol 207 } 208 } 209 assert.NotEqual(t, "", mCol3) 210 assert.NotEqual(t, "", mCol4) 211 212 aggs2 := &QueryAggregators{ 213 GroupByRequest: &GroupByRequest{ 214 MeasureOperations: []*MeasureAggregator{ 215 {MeasureCol: "col3", MeasureFunc: utils.Cardinality}, 216 }, 217 GroupByColumns: []string{"col3", "col2"}, 218 }, 219 } 220 UpdateQTUsage(tableName, nil, aggs2) 221 grpCols, measure = GetTopPersistentAggs("test-1") 222 assert.Len(t, grpCols, 3) 223 assert.Equal(t, "col2", grpCols[0], "only col2 exists in both usages, so it should be first") 224 var mCol3_1 string 225 mCol4 = "" 226 for m := range measure { 227 if m == "col3" { 228 if mCol3_1 == "" { 229 mCol3_1 = m 230 } 231 } else if m == "col4" { 232 mCol4 = m 233 } 234 } 235 assert.NotEqual(t, "", mCol3_1) 236 assert.NotEqual(t, "", mCol4) 237 } 238 239 func Test_GetTopPersistentAggs_Jaeger(t *testing.T) { 240 resetInternalQTInfo() 241 config.SetPQSEnabled(true) 242 aggs := &QueryAggregators{ 243 GroupByRequest: &GroupByRequest{ 244 MeasureOperations: []*MeasureAggregator{ 245 {MeasureCol: "col3", MeasureFunc: utils.Avg}, 246 {MeasureCol: "col4", MeasureFunc: utils.Count}, 247 }, 248 GroupByColumns: []string{"col1", "col2"}, 249 }, 250 } 251 tableName := []string{"jaeger-1"} 252 UpdateQTUsage(tableName, nil, aggs) 253 254 grpCols, measure := GetTopPersistentAggs("jaeger-1") 255 assert.Len(t, grpCols, 5) 256 assert.Len(t, measure, 3) 257 assert.Contains(t, grpCols, "col1") 258 assert.Contains(t, grpCols, "col2") 259 assert.Contains(t, grpCols, "traceID") 260 assert.Contains(t, grpCols, "serviceName") 261 assert.Contains(t, grpCols, "operationName") 262 263 var mCol3 string 264 var mCol4 string 265 for mcol := range measure { 266 if mcol == "col3" { 267 mCol3 = mcol 268 } else if mcol == "col4" { 269 mCol4 = mcol 270 } 271 } 272 assert.NotEqual(t, "", mCol3) 273 assert.NotEqual(t, "", mCol4) 274 275 aggs2 := &QueryAggregators{ 276 GroupByRequest: &GroupByRequest{ 277 MeasureOperations: []*MeasureAggregator{ 278 {MeasureCol: "startTime", MeasureFunc: utils.Max}, 279 }, 280 GroupByColumns: []string{"col3", "col2"}, 281 }, 282 } 283 UpdateQTUsage(tableName, nil, aggs2) 284 grpCols, measure = GetTopPersistentAggs("jaeger-1") 285 assert.Len(t, grpCols, 6) 286 assert.Equal(t, "traceID", grpCols[0], "traceID exists in both usages, so it should be first") 287 var mCol3_1 string 288 mCol4 = "" 289 for m := range measure { 290 if m == "col3" { 291 if mCol3_1 == "" { 292 mCol3_1 = m 293 } 294 } else if m == "col4" { 295 mCol4 = m 296 } 297 } 298 assert.NotEqual(t, "", mCol3_1) 299 assert.NotEqual(t, "", mCol4) 300 } 301 302 func Test_AggsHasher(t *testing.T) { 303 resetInternalQTInfo() 304 config.SetPQSEnabled(true) 305 aggs1 := &QueryAggregators{ 306 GroupByRequest: &GroupByRequest{ 307 MeasureOperations: []*MeasureAggregator{ 308 {MeasureCol: "col3", MeasureFunc: utils.Avg}, 309 {MeasureCol: "col4", MeasureFunc: utils.Count}, 310 }, 311 GroupByColumns: []string{"col1", "col2"}, 312 }, 313 } 314 id1 := GetHashForAggs(aggs1) 315 aggs2 := &QueryAggregators{ 316 GroupByRequest: &GroupByRequest{ 317 MeasureOperations: []*MeasureAggregator{ 318 {MeasureCol: "col4", MeasureFunc: utils.Count}, 319 {MeasureCol: "col3", MeasureFunc: utils.Avg}, 320 }, 321 GroupByColumns: []string{"col2", "col1"}, 322 }, 323 } 324 id2 := GetHashForAggs(aggs2) 325 assert.Equal(t, id1, id2) 326 327 aggs3 := &QueryAggregators{ 328 GroupByRequest: &GroupByRequest{ 329 MeasureOperations: []*MeasureAggregator{ 330 {MeasureCol: "col4", MeasureFunc: utils.Count}, 331 {MeasureCol: "col3", MeasureFunc: utils.Count}, 332 }, 333 GroupByColumns: []string{"col2", "col1"}, 334 }, 335 } 336 id3 := GetHashForAggs(aggs3) 337 assert.NotEqual(t, id1, id3) 338 } 339 340 func Test_PostPqsClear(t *testing.T) { 341 resetInternalQTInfo() 342 config.SetPQSEnabled(true) 343 qVal, err := utils.CreateDtypeEnclosure("iOS", 0) 344 assert.Nil(t, err) 345 346 sNode := &SearchNode{ 347 AndSearchConditions: &SearchCondition{ 348 SearchQueries: []*SearchQuery{ 349 { 350 ExpressionFilter: &SearchExpression{ 351 LeftSearchInput: &SearchExpressionInput{ColumnName: "os"}, 352 FilterOp: utils.Equals, 353 RightSearchInput: &SearchExpressionInput{ColumnValue: qVal}, 354 }, 355 SearchType: SimpleExpression, 356 }, 357 }, 358 }, 359 NodeType: ColumnValueQuery, 360 } 361 pqid := GetHashForQuery(sNode) 362 tableName := []string{"test-1"} 363 assert.NotNil(t, tableName) 364 UpdateQTUsage(tableName, sNode, nil) 365 366 expected := map[string]interface{}{ 367 "promoted_aggregations": make(map[string]int), 368 "promoted_searches": make(map[string]int), 369 "total_tracked_queries": 0, 370 } 371 var pqsSummary, clearPqsSummary map[string]interface{} 372 pqsSummary = getPQSSummary() 373 assert.NotNil(t, pqsSummary) 374 totalQueries := pqsSummary["total_tracked_queries"] 375 assert.NotNil(t, totalQueries) 376 totalQueriesInt, ok := totalQueries.(int) 377 assert.Equal(t, true, ok, "converting total persistent queries to int did not work") 378 assert.Equal(t, totalQueriesInt, 1, "There should be 1 persistent query but got=%v", totalQueriesInt) 379 380 pqsinfo := getPqsById(pqid) 381 assert.NotNil(t, pqsinfo) 382 ClearPqs() 383 clearPqsSummary = getPQSSummary() 384 assert.NotNil(t, clearPqsSummary) 385 assert.Equal(t, expected, clearPqsSummary, "the pqsinfo was supposed to be cleared") 386 }