diff --git a/data/conf/samples/analyzers_doc/cgrates.json b/data/conf/samples/analyzers_doc/cgrates.json new file mode 100644 index 000000000..a2217efbf --- /dev/null +++ b/data/conf/samples/analyzers_doc/cgrates.json @@ -0,0 +1,43 @@ +{ + + "general": { + "log_level": 7, + "reply_timeout": "30s" + }, + + "listen": { + "rpc_json": ":2012", + "rpc_gob": ":2013", + "http": ":2080" + }, + + "data_db": { + "db_type": "redis", + "db_name": "10" + }, + + "admins": { + "enabled": true + }, + + "attributes": { + "enabled": true, + "prefix_indexed_fields":["*req.Destination", "*req.Account"], + "opts":{ + "*processRuns": [ + { + "Tenant": "cgrates.org", + "FilterIDs": [], + "Value": 2 + } + ] + } + }, + + "analyzers":{ + "enabled": true, + "db_path": "/tmp/analyzers" + } + +} + \ No newline at end of file diff --git a/general_tests/analyzers_doc_it_test.go b/general_tests/analyzers_doc_it_test.go new file mode 100644 index 000000000..8632c9757 --- /dev/null +++ b/general_tests/analyzers_doc_it_test.go @@ -0,0 +1,658 @@ +//go:build integration +// +build integration + +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package general_tests + +import ( + "fmt" + "os" + "path" + "reflect" + "sort" + "testing" + "time" + + "github.com/cgrates/birpc" + "github.com/cgrates/birpc/context" + "github.com/cgrates/cgrates/analyzers" + "github.com/cgrates/cgrates/config" + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +var ( + anzDocCfgPath string + anzDocCfg *config.CGRConfig + anzDocRPC *birpc.Client + timeVar string // will be used to query results based on date + + sTestsAnzDoc = []func(t *testing.T){ + testAnzDocInitCfg, + testAnzDocInitDataDb, + testAnzDocStartEngine, + testAnzDocRPCConn, + + /* + Generate traffic. The following API methods will be stored in the blevesearch db: + - 2 * CoreSv1.Status + - 5 * AttributeSv1.SetAttributeProfile + - 1 * AttributeSv1.GetAttributeProfiles + - 3 * AttributeSv1.ProcessEvent + - ? * CacheSv1.ReloadCache + */ + testAnzDocCoreSStatus, + testPopulateTimeVariable, + testAnzDocSetAttributeProfiles, + testAnzDocCheckAttributeProfiles, + testAnzDocAttributeSProcessEvent, + testAnzDocCoreSStatus, + // make queries to the AnalyzerS db using only HeaderFilters + testAnzDocQueryWithHeaderFilters, + // make queries to the AnalyzerS db using only ContentFilters + // testAnzDocQueryWithContentFiltersFilters, + // make queries to the AnalyzerS db using a combination of both types of filters + testAnzDocQuery, + testAnzDocKillEngine, + } +) + +func TestAnzDocIT(t *testing.T) { + for _, stest := range sTestsAnzDoc { + t.Run("TestAnzDocIT", stest) + } +} + +func testAnzDocInitDataDb(t *testing.T) { + if err := engine.InitDataDB(anzDocCfg); err != nil { + t.Fatal(err) + } +} + +func testAnzDocStartEngine(t *testing.T) { + if _, err := engine.StopStartEngine(anzDocCfgPath, *waitRater); err != nil { + t.Fatal(err) + } +} + +func testAnzDocInitCfg(t *testing.T) { + var err error + if err := os.RemoveAll("/tmp/analyzers/"); err != nil { + t.Fatal(err) + } + if err = os.MkdirAll("/tmp/analyzers/", 0700); err != nil { + t.Fatal(err) + } + anzDocCfgPath = path.Join(*dataDir, "conf", "samples", "analyzers_doc") + anzDocCfg, err = config.NewCGRConfigFromPath(context.Background(), anzDocCfgPath) + if err != nil { + t.Error(err) + } +} + +func testAnzDocRPCConn(t *testing.T) { + var err error + anzDocRPC, err = newRPCClient(anzDocCfg.ListenCfg()) + if err != nil { + t.Fatal(err) + } +} + +func testAnzDocKillEngine(t *testing.T) { + if err := engine.KillEngine(100); err != nil { + t.Error(err) + } + if err := os.RemoveAll(anzDocCfg.AnalyzerSCfg().DBPath); err != nil { + t.Fatal(err) + } +} + +func testAnzDocCoreSStatus(t *testing.T) { + var status map[string]interface{} + if err = anzDocRPC.Call(context.Background(), utils.CoreSv1Status, utils.TenantWithAPIOpts{}, &status); err != nil { + return + } +} + +func testPopulateTimeVariable(t *testing.T) { + time.Sleep(time.Second) + timeVar = time.Now().Format("2006-01-02T15:04:05Z07:00") +} + +func testAnzDocSetAttributeProfiles(t *testing.T) { + attributeProfiles := []*engine.APIAttributeProfileWithAPIOpts{ + { + APIAttributeProfile: &engine.APIAttributeProfile{ + ID: "ATTR_1001", + Tenant: "cgrates.org", + FilterIDs: []string{"*string:~*req.Account:1001"}, + Weights: utils.DynamicWeights{ + { + Weight: 30, + }, + }, + Attributes: []*engine.ExternalAttribute{ + { + FilterIDs: []string{"*notexists:~*req.RequestType:"}, + Path: "*req.RequestType", + Type: utils.MetaConstant, + Value: "*rated", + }, + }, + }, + }, + { + APIAttributeProfile: &engine.APIAttributeProfile{ + ID: "ATTR_1002", + Tenant: "cgrates.org", + FilterIDs: []string{"*string:~*req.Account:1002"}, + Weights: utils.DynamicWeights{ + { + Weight: 10, + }, + }, + Attributes: []*engine.ExternalAttribute{ + { + FilterIDs: []string{"*notexists:~*req.RequestType:"}, + Path: "*req.RequestType", + Type: utils.MetaConstant, + Value: "*postpaid", + }, + }, + }, + }, + { + APIAttributeProfile: &engine.APIAttributeProfile{ + ID: "ATTR_1101", + Tenant: "cgrates.org", + FilterIDs: []string{"*string:~*req.Account:1101"}, + Weights: utils.DynamicWeights{ + { + Weight: 20, + }, + }, + Attributes: []*engine.ExternalAttribute{ + { + FilterIDs: []string{"*notexists:~*req.RequestType:"}, + Path: "*req.RequestType", + Type: utils.MetaConstant, + Value: "*prepaid", + }, + }, + }, + }, + { + APIAttributeProfile: &engine.APIAttributeProfile{ + ID: "ATTR_1102", + Tenant: "cgrates.org", + FilterIDs: []string{"*string:~*req.Account:1102"}, + Weights: utils.DynamicWeights{ + { + Weight: 5, + }, + }, + Attributes: []*engine.ExternalAttribute{ + { + FilterIDs: []string{"*notexists:~*req.RequestType:"}, + Path: "*req.RequestType", + Type: utils.MetaConstant, + Value: "*pseudoprepaid", + }, + }, + }, + }, + { + APIAttributeProfile: &engine.APIAttributeProfile{ + ID: "ATTR_PRF_11", + Tenant: "cgrates.org", + FilterIDs: []string{"*prefix:~*req.Account:11"}, + Weights: utils.DynamicWeights{ + { + Weight: 25, + }, + }, + Attributes: []*engine.ExternalAttribute{ + { + FilterIDs: []string{"*prefix:~*req.Destination:10"}, + Path: "*req.Cost", + Type: utils.MetaConstant, + Value: "0", + }, + }, + }, + }, + } + + var reply string + for _, attributeProfile := range attributeProfiles { + if err := anzDocRPC.Call(context.Background(), utils.AdminSv1SetAttributeProfile, + attributeProfile, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Error(err) + } + } +} + +func testAnzDocCheckAttributeProfiles(t *testing.T) { + expectedAttributeProfiles := []*engine.APIAttributeProfile{ + { + ID: "ATTR_1001", + Tenant: "cgrates.org", + FilterIDs: []string{"*string:~*req.Account:1001"}, + Weights: utils.DynamicWeights{ + { + Weight: 30, + }, + }, + Attributes: []*engine.ExternalAttribute{ + { + FilterIDs: []string{"*notexists:~*req.RequestType:"}, + Path: "*req.RequestType", + Type: utils.MetaConstant, + Value: "*rated", + }, + }, + }, + { + ID: "ATTR_1002", + Tenant: "cgrates.org", + FilterIDs: []string{"*string:~*req.Account:1002"}, + Weights: utils.DynamicWeights{ + { + Weight: 10, + }, + }, + Attributes: []*engine.ExternalAttribute{ + { + FilterIDs: []string{"*notexists:~*req.RequestType:"}, + Path: "*req.RequestType", + Type: utils.MetaConstant, + Value: "*postpaid", + }, + }, + }, + { + ID: "ATTR_1101", + Tenant: "cgrates.org", + FilterIDs: []string{"*string:~*req.Account:1101"}, + Weights: utils.DynamicWeights{ + { + Weight: 20, + }, + }, + Attributes: []*engine.ExternalAttribute{ + { + FilterIDs: []string{"*notexists:~*req.RequestType:"}, + Path: "*req.RequestType", + Type: utils.MetaConstant, + Value: "*prepaid", + }, + }, + }, + { + ID: "ATTR_1102", + Tenant: "cgrates.org", + FilterIDs: []string{"*string:~*req.Account:1102"}, + Weights: utils.DynamicWeights{ + { + Weight: 5, + }, + }, + Attributes: []*engine.ExternalAttribute{ + { + FilterIDs: []string{"*notexists:~*req.RequestType:"}, + Path: "*req.RequestType", + Type: utils.MetaConstant, + Value: "*pseudoprepaid", + }, + }, + }, + { + ID: "ATTR_PRF_11", + Tenant: "cgrates.org", + FilterIDs: []string{"*prefix:~*req.Account:11"}, + Weights: utils.DynamicWeights{ + { + Weight: 25, + }, + }, + Attributes: []*engine.ExternalAttribute{ + { + FilterIDs: []string{"*prefix:~*req.Destination:10"}, + Path: "*req.Cost", + Type: utils.MetaConstant, + Value: "0", + }, + }, + }, + } + var replyAttributeProfiles []*engine.APIAttributeProfile + if err := anzDocRPC.Call(context.Background(), utils.AdminSv1GetAttributeProfiles, + &utils.ArgsItemIDs{ + Tenant: "cgrates.org", + }, &replyAttributeProfiles); err != nil { + t.Error(err) + } else { + sort.Slice(replyAttributeProfiles, func(i, j int) bool { + return replyAttributeProfiles[i].ID < replyAttributeProfiles[j].ID + }) + if !reflect.DeepEqual(replyAttributeProfiles, expectedAttributeProfiles) { + t.Errorf("expected: <%+v>, \nreceived: <%+v>", + utils.ToJSON(expectedAttributeProfiles), utils.ToJSON(replyAttributeProfiles)) + } + } +} + +func testAnzDocAttributeSProcessEvent(t *testing.T) { + eventCall1001to1002 := &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "call1001to1002", + Event: map[string]interface{}{ + utils.ToR: utils.MetaVoice, + utils.OriginID: "abcdef", + utils.OriginHost: "192.168.1.1", + utils.Tenant: "cgrates.org", + utils.Category: "call", + utils.AccountField: "1001", + utils.Subject: "1001", + utils.Destination: "1002", + utils.SetupTime: time.Unix(1383813745, 0).UTC(), + utils.AnswerTime: time.Unix(1383813748, 0).UTC(), + utils.Usage: 10 * time.Second, + utils.RunID: utils.MetaDefault, + utils.Cost: 1.01, + }, + } + + eventCall1101to1002 := &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "call1011to1002", + Event: map[string]interface{}{ + utils.ToR: utils.MetaVoice, + utils.OriginID: "ghijkl", + utils.OriginHost: "192.168.1.1", + utils.Tenant: "cgrates.org", + utils.Category: "call", + utils.AccountField: "1101", + utils.Subject: "1101", + utils.Destination: "1002", + utils.SetupTime: time.Unix(1383813748, 0).UTC(), + utils.AnswerTime: time.Unix(1383813755, 0).UTC(), + utils.Usage: 15 * time.Second, + utils.RunID: utils.MetaDefault, + utils.Cost: 1.51, + }, + } + eventCall1102to1001 := &utils.CGREvent{ + Tenant: "cgrates.org", + ID: "call1102to1001", + Event: map[string]interface{}{ + utils.ToR: utils.MetaVoice, + utils.OriginID: "uvwxyz", + utils.OriginHost: "192.168.1.1", + utils.Tenant: "cgrates.org", + utils.Category: "call", + utils.AccountField: "1102", + utils.Subject: "1102", + utils.Destination: "1001", + utils.SetupTime: time.Unix(1383813755, 0).UTC(), + utils.AnswerTime: time.Unix(1383813762, 0).UTC(), + utils.Usage: 20 * time.Second, + utils.RunID: utils.MetaDefault, + utils.Cost: 2.01, + }, + } + expectedReply := `{"AlteredFields":[{"MatchedProfileID":"cgrates.org:ATTR_1001","Fields":["*req.RequestType"]}],"Tenant":"cgrates.org","ID":"call1001to1002","Event":{"Account":"1001","AnswerTime":"2013-11-07T08:42:28Z","Category":"call","Cost":1.01,"Destination":"1002","OriginHost":"192.168.1.1","OriginID":"abcdef","RequestType":"*rated","RunID":"*default","SetupTime":"2013-11-07T08:42:25Z","Subject":"1001","Tenant":"cgrates.org","ToR":"*voice","Usage":10000000000},"APIOpts":{}}` + var rplyEv engine.AttrSProcessEventReply + if err := anzDocRPC.Call(context.Background(), utils.AttributeSv1ProcessEvent, + eventCall1001to1002, &rplyEv); err != nil { + t.Error(err) + } else if jsonReply := utils.ToJSON(rplyEv); jsonReply != expectedReply { + t.Errorf("expected: <%+v>, \nreceived: <%+v>", + expectedReply, jsonReply) + } + expectedReply = `{"AlteredFields":[{"MatchedProfileID":"cgrates.org:ATTR_PRF_11","Fields":["*req.Cost"]},{"MatchedProfileID":"cgrates.org:ATTR_1101","Fields":["*req.RequestType"]}],"Tenant":"cgrates.org","ID":"call1011to1002","Event":{"Account":"1101","AnswerTime":"2013-11-07T08:42:35Z","Category":"call","Cost":"0","Destination":"1002","OriginHost":"192.168.1.1","OriginID":"ghijkl","RequestType":"*prepaid","RunID":"*default","SetupTime":"2013-11-07T08:42:28Z","Subject":"1101","Tenant":"cgrates.org","ToR":"*voice","Usage":15000000000},"APIOpts":{}}` + if err := anzDocRPC.Call(context.Background(), utils.AttributeSv1ProcessEvent, + eventCall1101to1002, &rplyEv); err != nil { + t.Error(err) + } else if jsonReply := utils.ToJSON(rplyEv); jsonReply != expectedReply { + t.Errorf("expected: <%+v>, \nreceived: <%+v>", + expectedReply, jsonReply) + } + expectedReply = `{"AlteredFields":[{"MatchedProfileID":"cgrates.org:ATTR_PRF_11","Fields":["*req.Cost"]},{"MatchedProfileID":"cgrates.org:ATTR_1102","Fields":["*req.RequestType"]}],"Tenant":"cgrates.org","ID":"call1102to1001","Event":{"Account":"1102","AnswerTime":"2013-11-07T08:42:42Z","Category":"call","Cost":"0","Destination":"1001","OriginHost":"192.168.1.1","OriginID":"uvwxyz","RequestType":"*pseudoprepaid","RunID":"*default","SetupTime":"2013-11-07T08:42:35Z","Subject":"1102","Tenant":"cgrates.org","ToR":"*voice","Usage":20000000000},"APIOpts":{}}` + if err := anzDocRPC.Call(context.Background(), utils.AttributeSv1ProcessEvent, + eventCall1102to1001, &rplyEv); err != nil { + t.Error(err) + } else if jsonReply := utils.ToJSON(rplyEv); jsonReply != expectedReply { + t.Errorf("expected: <%+v>, \nreceived: <%+v>", + expectedReply, jsonReply) + } + +} + +func testAnzDocQueryWithHeaderFilters(t *testing.T) { + time.Sleep(500 * time.Millisecond) + var result []map[string]interface{} + + // Query results for the AdminSv1.SetAttributeProfile request method using HeaderFilters + if err := anzDocRPC.Call(context.Background(), utils.AnalyzerSv1StringQuery, &analyzers.QueryArgs{ + HeaderFilters: `+RequestMethod:"AdminSv1.SetAttributeProfile"`, + ContentFilters: []string{}, + }, &result); err != nil { + t.Error(err) + } else if len(result) != 5 { + t.Errorf("Unexpected result: %s", utils.ToJSON(result)) + } + + // Query results for the AdminSv1.GetAttributeProfiles request method using HeaderFilters + if err := anzDocRPC.Call(context.Background(), utils.AnalyzerSv1StringQuery, &analyzers.QueryArgs{ + HeaderFilters: `+RequestMethod:"AdminSv1.GetAttributeProfiles"`, + ContentFilters: []string{}, + }, &result); err != nil { + t.Error(err) + } else if len(result) != 1 { + t.Errorf("Unexpected result: %s", utils.ToJSON(result)) + } + + // Query results for the AttributeSv1.ProcessEvent request method using HeaderFilters + if err := anzDocRPC.Call(context.Background(), utils.AnalyzerSv1StringQuery, &analyzers.QueryArgs{ + HeaderFilters: `+RequestMethod:"AttributeSv1.ProcessEvent"`, + ContentFilters: []string{}, + }, &result); err != nil { + t.Error(err) + } else if len(result) != 3 { + t.Errorf("Unexpected result: %s", utils.ToJSON(result)) + } + + // Query results for the CoreSv1.Status request method using HeaderFilters + if err := anzDocRPC.Call(context.Background(), utils.AnalyzerSv1StringQuery, &analyzers.QueryArgs{ + HeaderFilters: `+RequestMethod:"CoreSv1.Status"`, + ContentFilters: []string{}, + }, &result); err != nil { + t.Error(err) + } else if len(result) != 2 { + t.Errorf("Unexpected result: %s", utils.ToJSON(result)) + } + + // Query results for the CacheSv1.ReloadCache request method using HeaderFilters + if err := anzDocRPC.Call(context.Background(), utils.AnalyzerSv1StringQuery, &analyzers.QueryArgs{ + HeaderFilters: `+RequestMethod:"CacheSv1.ReloadCache"`, + ContentFilters: []string{}, + }, &result); err != nil { + t.Error(err) + } else if len(result) != 5 { + t.Errorf("Unexpected result: %s", utils.ToJSON(result)) + } + + // Query all results for the requests made to the AdminS service using regular expressions + if err := anzDocRPC.Call(context.Background(), utils.AnalyzerSv1StringQuery, &analyzers.QueryArgs{ + HeaderFilters: `+RequestMethod:"/AdminSv1.*/"`, + ContentFilters: []string{}, + }, &result); err != nil { + t.Error(err) + } else if len(result) != 6 { + t.Errorf("Unexpected result: %s", utils.ToJSON(result)) + } + + // Query results that happen before a given time + headerFltr := `+RequestStartTime:<"%s"` + headerFltr = fmt.Sprintf(headerFltr, timeVar) + if err := anzDocRPC.Call(context.Background(), utils.AnalyzerSv1StringQuery, &analyzers.QueryArgs{ + HeaderFilters: headerFltr, + ContentFilters: []string{}, + }, &result); err != nil { + t.Error(err) + } else if len(result) != 1 { + t.Errorf("Unexpected result: %s", utils.ToJSON(result)) + } + + // Query results for API calls with RequestID smaller or equal to 2 + if err := anzDocRPC.Call(context.Background(), utils.AnalyzerSv1StringQuery, &analyzers.QueryArgs{ + HeaderFilters: `+RequestID:<=2`, + ContentFilters: []string{}, + }, &result); err != nil { + t.Error(err) + } else if len(result) != 7 { + fmt.Println(len(result)) + t.Errorf("Unexpected result: %s", utils.ToJSON(result)) + } +} + +func testAnzDocQueryWithContentFiltersFilters(t *testing.T) { + var result []map[string]interface{} + // Query results for the AdminSv1.SetAttributeProfile request method using ContentFilters + if err := anzDocRPC.Call(context.Background(), utils.AnalyzerSv1StringQuery, &analyzers.QueryArgs{ + HeaderFilters: "", + ContentFilters: []string{"*string:~*hdr.RequestMethod:AdminSv1.SetAttributeProfile"}, + }, &result); err != nil { + t.Error(err) + } else if len(result) != 5 { + t.Errorf("Unexpected result: %s", utils.ToJSON(result)) + } + + // Query results for the AdminSv1.GetAttributeProfile request method using ContentFilters + if err := anzDocRPC.Call(context.Background(), utils.AnalyzerSv1StringQuery, &analyzers.QueryArgs{ + HeaderFilters: "", + ContentFilters: []string{"*string:~*hdr.RequestMethod:AdminSv1.GetAttributeProfiles"}, + }, &result); err != nil { + t.Error(err) + } else if len(result) != 1 { + t.Errorf("Unexpected result: %s", utils.ToJSON(result)) + } + + // Query results for the AttributeSv1.ProcessEvent request method using ContentFilters + if err := anzDocRPC.Call(context.Background(), utils.AnalyzerSv1StringQuery, &analyzers.QueryArgs{ + HeaderFilters: "", + ContentFilters: []string{"*string:~*hdr.RequestMethod:AttributeSv1.ProcessEvent"}, + }, &result); err != nil { + t.Error(err) + } else if len(result) != 3 { + t.Errorf("Unexpected result: %s", utils.ToJSON(result)) + } + + // Query results for the CoreSv1.Status request method using ContentFilters + if err := anzDocRPC.Call(context.Background(), utils.AnalyzerSv1StringQuery, &analyzers.QueryArgs{ + HeaderFilters: "", + ContentFilters: []string{"*string:~*hdr.RequestMethod:CoreSv1.Status"}, + }, &result); err != nil { + t.Error(err) + } else if len(result) != 2 { + t.Errorf("Unexpected result: %s", utils.ToJSON(result)) + } + + // Query results for the CacheSv1.ReloadCache request method using ContentFilters + if err := anzDocRPC.Call(context.Background(), utils.AnalyzerSv1StringQuery, &analyzers.QueryArgs{ + HeaderFilters: "", + ContentFilters: []string{"*string:~*hdr.RequestMethod:CacheSv1.ReloadCache"}, + }, &result); err != nil { + t.Error(err) + } else if len(result) != 5 { + t.Errorf("Unexpected result: %s", utils.ToJSON(result)) + } + + // Query all results for the requests made to the AdminS service using prefix filter + if err := anzDocRPC.Call(context.Background(), utils.AnalyzerSv1StringQuery, &analyzers.QueryArgs{ + HeaderFilters: "", + ContentFilters: []string{"*prefix:~*hdr.RequestMethod:AdminSv1."}, + }, &result); err != nil { + t.Error(err) + } else if len(result) != 6 { + t.Errorf("Unexpected result: %s", utils.ToJSON(result)) + } + + // Query results that happen before a given time + contentFltr := "*lt:~*hdr.RequestStartTime:%s" + contentFltr = fmt.Sprintf(contentFltr, timeVar) + if err := anzDocRPC.Call(context.Background(), utils.AnalyzerSv1StringQuery, &analyzers.QueryArgs{ + HeaderFilters: "", + ContentFilters: []string{contentFltr}, + }, &result); err != nil { + t.Error(err) + } else if len(result) != 1 { + t.Errorf("Unexpected result: %s", utils.ToJSON(result)) + } + + // Query results for API calls with RequestID smaller or equal to 2 + if err := anzDocRPC.Call(context.Background(), utils.AnalyzerSv1StringQuery, &analyzers.QueryArgs{ + HeaderFilters: "", + ContentFilters: []string{"*lte:~*hdr.RequestID:2"}, + }, &result); err != nil { + t.Error(err) + } else if len(result) != 7 { + fmt.Println(len(result)) + t.Errorf("Unexpected result: %s", utils.ToJSON(result)) + } + + // Query results for API calls with with an execution duration longer than 30ms + if err := anzDocRPC.Call(context.Background(), utils.AnalyzerSv1StringQuery, &analyzers.QueryArgs{ + HeaderFilters: "", + ContentFilters: []string{"*gt:~*hdr.RequestDuration:30ms"}, + }, &result); err != nil { + t.Error(err) + } else if len(result) != 7 { + fmt.Println(len(result)) + t.Errorf("Unexpected result: %s", utils.ToJSON(result)) + } +} + +func testAnzDocQuery(t *testing.T) { + var result []map[string]interface{} + + // Get results for AttributeSv1.ProcessEvent request replies whose events have a non-null cost + if err := anzDocRPC.Call(context.Background(), utils.AnalyzerSv1StringQuery, &analyzers.QueryArgs{ + HeaderFilters: `+RequestMethod:"AttributeSv1.ProcessEvent"`, + ContentFilters: []string{"*notstring:~*rep.Event.Cost:0"}, + }, &result); err != nil { + t.Error(err) + } else if len(result) != 1 { + t.Errorf("Unexpected result: %s", utils.ToJSON(result)) + } + + // Get results for CoreSv1.Status request replies that state a higher number of goroutines than 42 + if err := anzDocRPC.Call(context.Background(), utils.AnalyzerSv1StringQuery, &analyzers.QueryArgs{ + HeaderFilters: `+RequestMethod:"CoreSv1.Status"`, + ContentFilters: []string{"*gt:~*rep.ActiveGoroutines:42"}, + }, &result); err != nil { + t.Error(err) + } else if len(result) != 1 { + t.Errorf("Unexpected result: %s", utils.ToJSON(result)) + } +}