diff --git a/agents/dnsagent_it_test.go b/agents/dnsagent_it_test.go index eaa2b9a79..735e75924 100644 --- a/agents/dnsagent_it_test.go +++ b/agents/dnsagent_it_test.go @@ -23,6 +23,7 @@ package agents import ( "net/rpc" "path" + "reflect" "testing" "time" @@ -49,6 +50,7 @@ var ( testDNSitClntNAPTRDryRun, testDNSitClntNAPTRAttributes, testDNSitClntNAPTRSuppliers, + testDNSitClntNAPTRNotFoundSuppliers, testDNSitStopEngine, } ) @@ -213,6 +215,105 @@ func testDNSitClntNAPTRSuppliers(t *testing.T) { if answr2.Regexp != "!^(.*)$!sip:1@172.16.1.12!" { t.Errorf("received: <%q>", answr2.Regexp) } + //get stats metrics after restart + expectedMetrics := map[string]string{ + "*sum:1": "1", + } + var metrics2 map[string]string + if err := dnsRPC.Call(utils.StatSv1GetQueueStringMetrics, + &utils.TenantIDWithArgDispatcher{TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: "StatSupplierOne"}}, &metrics2); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expectedMetrics, metrics2) { + t.Errorf("After restat expecting: %+v, received reply: %s", expectedMetrics, metrics2) + } + for i := 0; i < 5; i++ { // send again the same request to check if the stats counter it + if err := dnsClnt.WriteMsg(m); err != nil { + t.Error(err) + } + rply, err := dnsClnt.ReadMsg() + if err != nil { + t.Error(err) + } else if len(rply.Answer) != 2 { + t.Errorf("wrong number of records: %s", utils.ToIJSON(rply.Answer)) + } + if rply.Rcode != dns.RcodeSuccess { + t.Errorf("failed to get an valid answer\n%v", rply) + } + answr := rply.Answer[0].(*dns.NAPTR) + if answr.Order != 100 { + t.Errorf("received: <%v>", answr.Order) + } + if answr.Regexp != "!^(.*)$!sip:1@172.16.1.11!" { + t.Errorf("received: <%q>", answr.Regexp) + } + answr2 := rply.Answer[1].(*dns.NAPTR) + if answr2.Regexp != "!^(.*)$!sip:1@172.16.1.12!" { + t.Errorf("received: <%q>", answr2.Regexp) + } + } + expectedMetrics = map[string]string{ + "*sum:1": "6", + } + if err := dnsRPC.Call(utils.StatSv1GetQueueStringMetrics, + &utils.TenantIDWithArgDispatcher{TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: "StatSupplierOne"}}, &metrics2); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expectedMetrics, metrics2) { + t.Errorf("After restat expecting: %+v, received reply: %s", expectedMetrics, metrics2) + } + +} + +func testDNSitClntNAPTRNotFoundSuppliers(t *testing.T) { + m := new(dns.Msg) + m.SetQuestion("5.6.9.4.7.1.7.1.5.6.8.9.5.e164.arpa.", dns.TypeNAPTR) + if err := dnsClnt.WriteMsg(m); err != nil { + t.Error(err) + } + rply, err := dnsClnt.ReadMsg() + if err != nil { + t.Error(err) + } else if len(rply.Answer) != 0 { + t.Errorf("wrong number of records: %s", utils.ToIJSON(rply.Answer)) + } + if rply.Rcode != dns.RcodeSuccess { + t.Errorf("failed to get an valid answer\n%v", rply) + } + //get stats metrics after restart + expectedMetrics := map[string]string{ + "*sum:1": "1", + } + var metrics2 map[string]string + if err := dnsRPC.Call(utils.StatSv1GetQueueStringMetrics, + &utils.TenantIDWithArgDispatcher{TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: "StatNotFound"}}, &metrics2); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expectedMetrics, metrics2) { + t.Errorf("After restat expecting: %+v, received reply: %s", expectedMetrics, metrics2) + } + for i := 0; i < 5; i++ { // send again the same request to check if the stats counter it + if err := dnsClnt.WriteMsg(m); err != nil { + t.Error(err) + } + rply, err := dnsClnt.ReadMsg() + if err != nil { + t.Error(err) + } else if len(rply.Answer) != 0 { + t.Errorf("wrong number of records: %s", utils.ToIJSON(rply.Answer)) + } + if rply.Rcode != dns.RcodeSuccess { + t.Errorf("failed to get an valid answer\n%v", rply) + } + + } + expectedMetrics = map[string]string{ + "*sum:1": "6", + } + if err := dnsRPC.Call(utils.StatSv1GetQueueStringMetrics, + &utils.TenantIDWithArgDispatcher{TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: "StatNotFound"}}, &metrics2); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expectedMetrics, metrics2) { + t.Errorf("After restat expecting: %+v, received reply: %s", expectedMetrics, metrics2) + } + } func testDNSitStopEngine(t *testing.T) { diff --git a/data/conf/samples/dnsagent_internal/cgrates.json b/data/conf/samples/dnsagent_internal/cgrates.json index 4857efd1a..cd5a90fc0 100644 --- a/data/conf/samples/dnsagent_internal/cgrates.json +++ b/data/conf/samples/dnsagent_internal/cgrates.json @@ -32,6 +32,7 @@ "attributes_conns": ["*localhost"], "rals_conns": ["*internal"], "cdrs_conns": ["*internal"], + "stats_conns": ["*localhost"], "chargers_conns": ["*internal"], "suppliers_conns": ["*localhost"], }, @@ -63,6 +64,13 @@ }, +"stats": { + "enabled": true, + "indexed_selects": false, + "store_interval": "-1", +}, + + "dns_agent": { "enabled": true, "listen": ":2053", diff --git a/data/conf/samples/dnsagent_internal/suppliers.json b/data/conf/samples/dnsagent_internal/suppliers.json index a845df6ef..ec7b62801 100644 --- a/data/conf/samples/dnsagent_internal/suppliers.json +++ b/data/conf/samples/dnsagent_internal/suppliers.json @@ -6,13 +6,32 @@ "id": "NAPTRSuppliersQuery", "filters": ["*string:~*vars.QueryType:NAPTR", "*string:~*vars.E164Address:4986517174965"], - "flags": ["*message", "*suppliers","*continue"], + "flags": ["*event", "*suppliers","*continue"], "request_fields":[ {"tag": "ToR", "path": "*cgreq.Account", "type": "*constant", "value": "1001"}, // so we can match the supplier profile ], - "reply_fields":[ - {"tag": "DispatchReply", "type": "*none", - "blocker": true}, // enforces continue_on_success so we can check answer with filters + }, + { + "id": "NAPTRRoutesQuery2", // this processor will add Account 1002 in event to test the NotFound StatQueue + "filters": ["*string:~*vars.QueryType:NAPTR", + "*string:~*vars.E164Address:5986517174965"], + "flags": ["*event", "*suppliers","*continue"], + "request_fields":[ + {"tag": "ToR", "path": "*cgreq.Account", "type": "*constant", "value": "1002"}, + ], + }, + { + "id": "NAPTRStatSupplierNotFound", + "filters": ["*string:~*vars.QueryType:NAPTR", + "*string:~*cgrep.Error:SUPPLIERS_ERROR:NOT_FOUND"], + "flags": ["*event", "*stats"], + "request_fields":[ + { + "tag": "ErrSupplierNotFound", + "path": "*cgreq.ErrSupplierNotFound", + "type": "*constant", + "value": "NotFoundSuppliers", + } ], }, { @@ -57,6 +76,21 @@ "type": "*group", "value": "."}, ], }, + { + "id": "NAPTRStatSupplier", // this process will pick the first supplier and will send a ProcessEvent to StatQueue + "filters": ["*string:~*vars.QueryType:NAPTR", + "*string:~*vars.E164Address:4986517174965", + "*gte:~*cgrep.Suppliers.Count:1"], + "flags": ["*event", "*stats", "*continue"], + "request_fields":[ + { + "tag": "FirstSupplier", + "path": "*cgreq.FirstSupplier", + "type": "*variable", + "value": "~*cgrep.Suppliers.SortedSuppliers[0].SupplierID", + } + ], + } ], }, diff --git a/data/conf/samples/dnsagent_mongo/cgrates.json b/data/conf/samples/dnsagent_mongo/cgrates.json index bfee9d2f1..1c1d52e6d 100644 --- a/data/conf/samples/dnsagent_mongo/cgrates.json +++ b/data/conf/samples/dnsagent_mongo/cgrates.json @@ -37,6 +37,7 @@ "attributes_conns": ["*localhost"], "rals_conns": ["*internal"], "cdrs_conns": ["*internal"], + "stats_conns": ["*localhost"], "chargers_conns": ["*internal"], "suppliers_conns": ["*localhost"], }, @@ -68,6 +69,12 @@ }, +"stats": { + "enabled": true, + "indexed_selects": false +}, + + "dns_agent": { "enabled": true, "listen": ":2053", diff --git a/data/conf/samples/dnsagent_mongo/suppliers.json b/data/conf/samples/dnsagent_mongo/suppliers.json index 3427261f8..9ff66297e 100644 --- a/data/conf/samples/dnsagent_mongo/suppliers.json +++ b/data/conf/samples/dnsagent_mongo/suppliers.json @@ -15,6 +15,29 @@ "blocker": true}, // enforces continue_on_success so we can check answer with filters ], }, + { + "id": "NAPTRRoutesQuery2", // this processor will add Account 1002 in event to test the NotFound StatQueue + "filters": ["*string:~*vars.QueryType:NAPTR", + "*string:~*vars.E164Address:5986517174965"], + "flags": ["*event", "*suppliers","*continue"], + "request_fields":[ + {"tag": "ToR", "path": "*cgreq.Account", "type": "*constant", "value": "1002"}, + ], + }, + { + "id": "NAPTRStatSupplierNotFound", + "filters": ["*string:~*vars.QueryType:NAPTR", + "*string:~*cgrep.Error:SUPPLIERS_ERROR:NOT_FOUND"], + "flags": ["*event", "*stats"], + "request_fields":[ + { + "tag": "ErrSupplierNotFound", + "path": "*cgreq.ErrSupplierNotFound", + "type": "*constant", + "value": "NotFoundRoutes", + } + ], + }, { "id": "NAPTRSuppliersOneSupplier", "filters": ["*string:~*vars.QueryType:NAPTR", @@ -57,6 +80,21 @@ "type": "*group", "value": "."}, ], }, + { + "id": "NAPTRStatSupplier", // this process will pick the first supplier and will send a ProcessEvent to StatQueue + "filters": ["*string:~*vars.QueryType:NAPTR", + "*string:~*vars.E164Address:4986517174965", + "*gte:~*cgrep.Suppliers.Count:1"], + "flags": ["*event", "*stats", "*continue"], + "request_fields":[ + { + "tag": "FirstSupplier", + "path": "*cgreq.FirstSupplier", + "type": "*variable", + "value": "~*cgrep.Suppliers.SortedSuppliers[0].SupplierID", + } + ], + } ], }, diff --git a/data/conf/samples/dnsagent_mysql/cgrates.json b/data/conf/samples/dnsagent_mysql/cgrates.json index 2dd1ad64d..20271ad6b 100644 --- a/data/conf/samples/dnsagent_mysql/cgrates.json +++ b/data/conf/samples/dnsagent_mysql/cgrates.json @@ -28,6 +28,7 @@ "attributes_conns": ["*localhost"], "rals_conns": ["*internal"], "cdrs_conns": ["*internal"], + "stats_conns": ["*localhost"], "chargers_conns": ["*internal"], "suppliers_conns": ["*localhost"], }, @@ -59,6 +60,12 @@ }, +"stats": { + "enabled": true, + "indexed_selects": false +}, + + "dns_agent": { "enabled": true, "listen": ":2053", diff --git a/data/conf/samples/dnsagent_mysql/suppliers.json b/data/conf/samples/dnsagent_mysql/suppliers.json index 3427261f8..9ff66297e 100644 --- a/data/conf/samples/dnsagent_mysql/suppliers.json +++ b/data/conf/samples/dnsagent_mysql/suppliers.json @@ -15,6 +15,29 @@ "blocker": true}, // enforces continue_on_success so we can check answer with filters ], }, + { + "id": "NAPTRRoutesQuery2", // this processor will add Account 1002 in event to test the NotFound StatQueue + "filters": ["*string:~*vars.QueryType:NAPTR", + "*string:~*vars.E164Address:5986517174965"], + "flags": ["*event", "*suppliers","*continue"], + "request_fields":[ + {"tag": "ToR", "path": "*cgreq.Account", "type": "*constant", "value": "1002"}, + ], + }, + { + "id": "NAPTRStatSupplierNotFound", + "filters": ["*string:~*vars.QueryType:NAPTR", + "*string:~*cgrep.Error:SUPPLIERS_ERROR:NOT_FOUND"], + "flags": ["*event", "*stats"], + "request_fields":[ + { + "tag": "ErrSupplierNotFound", + "path": "*cgreq.ErrSupplierNotFound", + "type": "*constant", + "value": "NotFoundRoutes", + } + ], + }, { "id": "NAPTRSuppliersOneSupplier", "filters": ["*string:~*vars.QueryType:NAPTR", @@ -57,6 +80,21 @@ "type": "*group", "value": "."}, ], }, + { + "id": "NAPTRStatSupplier", // this process will pick the first supplier and will send a ProcessEvent to StatQueue + "filters": ["*string:~*vars.QueryType:NAPTR", + "*string:~*vars.E164Address:4986517174965", + "*gte:~*cgrep.Suppliers.Count:1"], + "flags": ["*event", "*stats", "*continue"], + "request_fields":[ + { + "tag": "FirstSupplier", + "path": "*cgreq.FirstSupplier", + "type": "*variable", + "value": "~*cgrep.Suppliers.SortedSuppliers[0].SupplierID", + } + ], + } ], }, diff --git a/data/tariffplans/dnsagent/Stats.csv b/data/tariffplans/dnsagent/Stats.csv new file mode 100644 index 000000000..a8db219bc --- /dev/null +++ b/data/tariffplans/dnsagent/Stats.csv @@ -0,0 +1,4 @@ +#Tenant[0],Id[1],FilterIDs[2],ActivationInterval[3],QueueLength[4],TTL[5],MinItems[6],Metrics[7],MetricFilterIDs[8],Stored[9],Blocker[10],Weight[11],ThresholdIDs[12] +cgrates.org,StatNotFound,*exists:~*req.ErrSupplierNotFound:,,-1,-1,0,*sum:1,,true,false,30,*none +cgrates.org,StatSupplierOne,*string:~*req.FirstSupplier:supplier1,,-1,-1,0,*sum:1,,true,false,30,*none +cgrates.org,StatSupplierTwo,*string:~*req.FirstSupplier:supplier2,,-1,-1,0,*sum:1,,true,false,30,*none