mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Synched Http CDR with CDR object
This commit is contained in:
committed by
Dan Christian Bogos
parent
1a6d0dbc4a
commit
c408254743
@@ -33,15 +33,20 @@ var cdrServer *CDRServer // Share the server so we can use it in http handlers
|
||||
|
||||
// cgrCdrHandler handles CDRs received over HTTP REST
|
||||
func cgrCdrHandler(w http.ResponseWriter, r *http.Request) {
|
||||
cgrCdr, err := NewCgrCdrFromHttpReq(r,
|
||||
cdrServer.cgrCfg.GeneralCfg().DefaultTimezone)
|
||||
cgrCdr, err := NewCgrCdrFromHttpReq(r)
|
||||
if err != nil {
|
||||
utils.Logger.Warning(
|
||||
fmt.Sprintf("<%s> could not create CDR entry from http: %+v, err <%s>",
|
||||
utils.CDRs, r.Form, err.Error()))
|
||||
return
|
||||
}
|
||||
cdr := cgrCdr.AsCDR(cdrServer.cgrCfg.GeneralCfg().DefaultTimezone)
|
||||
cdr, err := cgrCdr.AsCDR(cdrServer.cgrCfg.GeneralCfg().DefaultTimezone)
|
||||
if err != nil {
|
||||
utils.Logger.Warning(
|
||||
fmt.Sprintf("<%s> could not create CDR entry from rawCDR: %+v, err <%s>",
|
||||
utils.CDRs, cgrCdr, err.Error()))
|
||||
return
|
||||
}
|
||||
var ignored string
|
||||
if err := cdrServer.V1ProcessCDR(&CDRWithOpts{CDR: cdr}, &ignored); err != nil {
|
||||
utils.Logger.Warning(
|
||||
|
||||
@@ -19,13 +19,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package engine
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
func NewCgrCdrFromHttpReq(req *http.Request, timezone string) (CgrCdr, error) {
|
||||
func NewCgrCdrFromHttpReq(req *http.Request) (CgrCdr, error) {
|
||||
if req.Form == nil {
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, err
|
||||
@@ -41,7 +42,7 @@ func NewCgrCdrFromHttpReq(req *http.Request, timezone string) (CgrCdr, error) {
|
||||
|
||||
type CgrCdr map[string]string
|
||||
|
||||
func (cgrCdr CgrCdr) getCGRID(timezone string) string {
|
||||
func (cgrCdr CgrCdr) getCGRID() string {
|
||||
if CGRID, hasIt := cgrCdr[utils.CGRID]; hasIt {
|
||||
return CGRID
|
||||
}
|
||||
@@ -58,29 +59,61 @@ func (cgrCdr CgrCdr) getExtraFields() map[string]string {
|
||||
return extraFields
|
||||
}
|
||||
|
||||
func (cgrCdr CgrCdr) AsCDR(timezone string) *CDR {
|
||||
storCdr := new(CDR)
|
||||
storCdr.CGRID = cgrCdr.getCGRID(timezone)
|
||||
storCdr.ToR = cgrCdr[utils.ToR]
|
||||
storCdr.OriginID = cgrCdr[utils.OriginID]
|
||||
storCdr.OriginHost = cgrCdr[utils.OriginHost]
|
||||
storCdr.Source = cgrCdr[utils.Source]
|
||||
storCdr.RequestType = cgrCdr[utils.RequestType]
|
||||
storCdr.Tenant = cgrCdr[utils.Tenant]
|
||||
storCdr.Category = cgrCdr[utils.Category]
|
||||
storCdr.Account = cgrCdr[utils.Account]
|
||||
storCdr.Subject = cgrCdr[utils.Subject]
|
||||
storCdr.Destination = cgrCdr[utils.Destination]
|
||||
storCdr.SetupTime, _ = utils.ParseTimeDetectLayout(cgrCdr[utils.SetupTime], timezone) // Not interested to process errors, should do them if necessary in a previous step
|
||||
storCdr.AnswerTime, _ = utils.ParseTimeDetectLayout(cgrCdr[utils.AnswerTime], timezone)
|
||||
storCdr.Usage, _ = utils.ParseDurationWithNanosecs(cgrCdr[utils.Usage])
|
||||
storCdr.ExtraFields = cgrCdr.getExtraFields()
|
||||
func (cgrCdr CgrCdr) AsCDR(timezone string) (storCdr *CDR, err error) {
|
||||
storCdr = &CDR{
|
||||
CGRID: cgrCdr.getCGRID(),
|
||||
RunID: cgrCdr[utils.RunID],
|
||||
OriginHost: cgrCdr[utils.OriginHost],
|
||||
Source: cgrCdr[utils.Source],
|
||||
OriginID: cgrCdr[utils.OriginID],
|
||||
ToR: cgrCdr[utils.ToR],
|
||||
RequestType: cgrCdr[utils.RequestType],
|
||||
Tenant: cgrCdr[utils.Tenant],
|
||||
Category: cgrCdr[utils.Category],
|
||||
Account: cgrCdr[utils.Account],
|
||||
Subject: cgrCdr[utils.Subject],
|
||||
Destination: cgrCdr[utils.Destination],
|
||||
ExtraFields: cgrCdr.getExtraFields(),
|
||||
ExtraInfo: cgrCdr[utils.ExtraInfo],
|
||||
CostSource: cgrCdr[utils.CostSource],
|
||||
}
|
||||
if orderID, hasIt := cgrCdr[utils.OrderID]; hasIt {
|
||||
if storCdr.OrderID, err = strconv.ParseInt(orderID, 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
storCdr.SetupTime, err = utils.ParseTimeDetectLayout(cgrCdr[utils.SetupTime], timezone) // Not interested to process errors, should do them if necessary in a previous step
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
storCdr.AnswerTime, err = utils.ParseTimeDetectLayout(cgrCdr[utils.AnswerTime], timezone)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
storCdr.Usage, err = utils.ParseDurationWithNanosecs(cgrCdr[utils.Usage])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if partial, hasIt := cgrCdr[utils.Partial]; hasIt {
|
||||
if storCdr.Partial, err = strconv.ParseBool(partial); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if ratedStr, hasIt := cgrCdr[utils.PreRated]; hasIt {
|
||||
if storCdr.PreRated, err = strconv.ParseBool(ratedStr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
storCdr.Cost = -1
|
||||
if costStr, hasIt := cgrCdr[utils.COST]; hasIt {
|
||||
storCdr.Cost, _ = strconv.ParseFloat(costStr, 64)
|
||||
if storCdr.Cost, err = strconv.ParseFloat(costStr, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if ratedStr, hasIt := cgrCdr[utils.RATED]; hasIt {
|
||||
storCdr.PreRated, _ = strconv.ParseBool(ratedStr)
|
||||
if costDetails, hasIt := cgrCdr[utils.CostDetails]; hasIt {
|
||||
if err = json.Unmarshal([]byte(costDetails), &storCdr.CostDetails); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return storCdr
|
||||
return
|
||||
}
|
||||
|
||||
@@ -29,21 +29,31 @@ import (
|
||||
curl --data "OriginID=asbfdsaf&OriginHost=192.168.1.1&RequestType=rated&tenant=cgrates.org&tor=call&account=1001&subject=1001&destination=1002&time_answer=1383813746&duration=10&field_extr1=val_extr1&fieldextr2=valextr2" http://ipbxdev:2080/cgr
|
||||
*/
|
||||
|
||||
func TestCgrCdrInterfaces(t *testing.T) {
|
||||
var _ RawCdr = make(CgrCdr)
|
||||
}
|
||||
|
||||
func TestCgrCdrAsCDR(t *testing.T) {
|
||||
cgrCdr := CgrCdr{utils.ToR: utils.VOICE, utils.OriginID: "dsafdsaf",
|
||||
utils.OriginHost: "192.168.1.1", utils.Source: "internal_test",
|
||||
cgrCdr := CgrCdr{
|
||||
utils.ToR: utils.VOICE,
|
||||
utils.OriginID: "dsafdsaf",
|
||||
utils.OriginHost: "192.168.1.1",
|
||||
utils.Source: "internal_test",
|
||||
utils.OrderID: "23",
|
||||
utils.RequestType: utils.META_RATED,
|
||||
utils.Tenant: "cgrates.org", utils.Category: "call",
|
||||
utils.Account: "1001", utils.Subject: "1001", utils.Destination: "1002",
|
||||
utils.SetupTime: "2013-11-07T08:42:20Z", utils.AnswerTime: "2013-11-07T08:42:26Z",
|
||||
utils.Usage: "10s", "field_extr1": "val_extr1", "fieldextr2": "valextr2"}
|
||||
utils.Tenant: "cgrates.org",
|
||||
utils.Category: "call",
|
||||
utils.Account: "1001",
|
||||
utils.Subject: "1001",
|
||||
utils.Destination: "1002",
|
||||
utils.Partial: "true",
|
||||
utils.SetupTime: "2013-11-07T08:42:20Z",
|
||||
utils.AnswerTime: "2013-11-07T08:42:26Z",
|
||||
utils.Usage: "10s", "field_extr1": "val_extr1", "fieldextr2": "valextr2",
|
||||
utils.CostDetails: `{ "CGRID": "randomID", "RunID": "thisID"}`,
|
||||
}
|
||||
// setupTime, _ := utils.ParseTimeDetectLayout(cgrCdr[utils.SetupTime], "")
|
||||
expctRtCdr := &CDR{CGRID: utils.Sha1(cgrCdr[utils.OriginID], cgrCdr[utils.OriginHost]),
|
||||
ToR: utils.VOICE, OriginID: cgrCdr[utils.OriginID],
|
||||
expctRtCdr := &CDR{
|
||||
CGRID: utils.Sha1(cgrCdr[utils.OriginID], cgrCdr[utils.OriginHost]),
|
||||
ToR: utils.VOICE,
|
||||
OrderID: 23,
|
||||
OriginID: cgrCdr[utils.OriginID],
|
||||
OriginHost: cgrCdr[utils.OriginHost],
|
||||
Source: cgrCdr[utils.Source],
|
||||
RequestType: cgrCdr[utils.RequestType],
|
||||
@@ -52,10 +62,19 @@ func TestCgrCdrAsCDR(t *testing.T) {
|
||||
Destination: cgrCdr[utils.Destination],
|
||||
SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC),
|
||||
AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
|
||||
Usage: 10 * time.Second, Cost: -1,
|
||||
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}}
|
||||
if CDR := cgrCdr.AsCDR(""); !reflect.DeepEqual(expctRtCdr, CDR) {
|
||||
t.Errorf("Expecting %v, received: %v", expctRtCdr, CDR)
|
||||
Usage: 10 * time.Second,
|
||||
Cost: -1,
|
||||
Partial: true,
|
||||
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
CostDetails: &EventCost{
|
||||
CGRID: "randomID",
|
||||
RunID: "thisID",
|
||||
},
|
||||
}
|
||||
if CDR, err := cgrCdr.AsCDR(""); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(expctRtCdr, CDR) {
|
||||
t.Errorf("Expecting %v \n, received: %v", utils.ToJSON(expctRtCdr), utils.ToJSON(CDR))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,8 +92,8 @@ func TestReplicatedCgrCdrAsCDR(t *testing.T) {
|
||||
utils.SetupTime: "2013-11-07T08:42:20Z",
|
||||
utils.AnswerTime: "2013-11-07T08:42:26Z",
|
||||
utils.Usage: "10s", utils.COST: "0.12",
|
||||
utils.RATED: "true", "field_extr1": "val_extr1",
|
||||
"fieldextr2": "valextr2"}
|
||||
utils.PreRated: "true",
|
||||
}
|
||||
expctRtCdr := &CDR{
|
||||
CGRID: cgrCdr[utils.CGRID],
|
||||
ToR: cgrCdr[utils.ToR],
|
||||
@@ -87,13 +106,96 @@ func TestReplicatedCgrCdrAsCDR(t *testing.T) {
|
||||
Account: cgrCdr[utils.Account],
|
||||
Subject: cgrCdr[utils.Subject],
|
||||
Destination: cgrCdr[utils.Destination],
|
||||
ExtraFields: map[string]string{},
|
||||
SetupTime: time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC),
|
||||
AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC),
|
||||
Usage: 10 * time.Second,
|
||||
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
|
||||
Cost: 0.12, PreRated: true,
|
||||
Cost: 0.12,
|
||||
PreRated: true,
|
||||
}
|
||||
if CDR := cgrCdr.AsCDR(""); !reflect.DeepEqual(expctRtCdr, CDR) {
|
||||
if CDR, err := cgrCdr.AsCDR(""); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(expctRtCdr, CDR) {
|
||||
t.Errorf("Expecting %v, received: %v", expctRtCdr, CDR)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCgrCdrAsCDROrderIDError(t *testing.T) {
|
||||
cgrCdr := CgrCdr{
|
||||
utils.OrderID: "25.3",
|
||||
}
|
||||
expected := "strconv.ParseInt: parsing \"25.3\": invalid syntax"
|
||||
if _, err := cgrCdr.AsCDR(""); err == nil || err.Error() != expected {
|
||||
t.Errorf("Expecting %v, received: %v", expected, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCgrCdrAsCDRSetupTimeError(t *testing.T) {
|
||||
cgrCdr := CgrCdr{
|
||||
utils.SetupTime: "invalideTimeFormat",
|
||||
}
|
||||
expected := "Unsupported time format"
|
||||
if _, err := cgrCdr.AsCDR(""); err == nil || err.Error() != expected {
|
||||
t.Errorf("Expecting %v, received: %v", expected, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCgrCdrAsCDRAnswerTimeError(t *testing.T) {
|
||||
cgrCdr := CgrCdr{
|
||||
utils.AnswerTime: "invalideTimeFormat",
|
||||
}
|
||||
expected := "Unsupported time format"
|
||||
if _, err := cgrCdr.AsCDR(""); err == nil || err.Error() != expected {
|
||||
t.Errorf("Expecting %v, received: %v", expected, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCgrCdrAsCDRUsageError(t *testing.T) {
|
||||
cgrCdr := CgrCdr{
|
||||
utils.Usage: "1ss",
|
||||
}
|
||||
expected := "time: unknown unit \"ss\" in duration \"1ss\""
|
||||
if _, err := cgrCdr.AsCDR(""); err == nil || err.Error() != expected {
|
||||
t.Errorf("Expecting %v, received: %v", expected, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCgrCdrAsCDRPartialError(t *testing.T) {
|
||||
cgrCdr := CgrCdr{
|
||||
utils.Partial: "InvalidBoolFormat",
|
||||
}
|
||||
expected := "strconv.ParseBool: parsing \"InvalidBoolFormat\": invalid syntax"
|
||||
if _, err := cgrCdr.AsCDR(""); err == nil || err.Error() != expected {
|
||||
t.Errorf("Expecting %v, received: %v", expected, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCgrCdrAsCDRPreRatedError(t *testing.T) {
|
||||
cgrCdr := CgrCdr{
|
||||
utils.PreRated: "InvalidBoolFormat",
|
||||
}
|
||||
expected := "strconv.ParseBool: parsing \"InvalidBoolFormat\": invalid syntax"
|
||||
if _, err := cgrCdr.AsCDR(""); err == nil || err.Error() != expected {
|
||||
t.Errorf("Expecting %v, received: %v", expected, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCgrCdrAsCDRCostError(t *testing.T) {
|
||||
cgrCdr := CgrCdr{
|
||||
utils.Cost: "InvalidFlaotFormat",
|
||||
}
|
||||
expected := "strconv.ParseFloat: parsing \"InvalidFlaotFormat\": invalid syntax"
|
||||
if _, err := cgrCdr.AsCDR(""); err == nil || err.Error() != expected {
|
||||
t.Errorf("Expecting %v, received: %v", expected, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCgrCdrAsCDRCostDetailsError(t *testing.T) {
|
||||
cgrCdr := CgrCdr{
|
||||
utils.CostDetails: `{ "CGRID": "randomID", "RunID": 1234}`,
|
||||
}
|
||||
expected := "json: cannot unmarshal number into Go struct field EventCost.RunID of type string"
|
||||
if _, err := cgrCdr.AsCDR(""); err == nil || err.Error() != expected {
|
||||
t.Errorf("Expecting %v, received: %v", expected, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,10 +392,6 @@ var body = []byte(`{
|
||||
|
||||
var fsCdrCfg *config.CGRConfig
|
||||
|
||||
func TestFsCdrInterfaces(t *testing.T) {
|
||||
var _ RawCdr = new(FSCdr)
|
||||
}
|
||||
|
||||
func TestFsCdrFirstNonEmpty(t *testing.T) {
|
||||
fsCdrCfg, _ = config.NewDefaultCGRConfig()
|
||||
fsCdr, err := NewFSCdr(body, fsCdrCfg)
|
||||
|
||||
Reference in New Issue
Block a user