mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-15 21:29:52 +05:00
Usage as imported/exported as floated seconds instead of nanoseconds
This commit is contained in:
@@ -133,7 +133,7 @@ func (self *Cdrc) recordToStoredCdr(record []string) (*utils.StoredCdr, error) {
|
||||
return nil, fmt.Errorf("Cannot parse answer time field with value: %s, err: %s", fieldVal, err.Error())
|
||||
}
|
||||
case utils.USAGE:
|
||||
if storedCdr.Usage, err = utils.ParseDurationWithNanosecs(fieldVal); err != nil {
|
||||
if storedCdr.Usage, err = utils.ParseDurationWithSecs(fieldVal); err != nil {
|
||||
return nil, fmt.Errorf("Cannot parse duration field with value: %s, err: %s", fieldVal, err.Error())
|
||||
}
|
||||
default: // Extra fields will not match predefined so they all show up here
|
||||
|
||||
@@ -44,7 +44,7 @@ func TestRecordForkCdr(t *testing.T) {
|
||||
t.Error("Failed to corectly detect missing fields from record")
|
||||
}
|
||||
cdrRow = []string{"ignored", "ignored", utils.VOICE, "acc1", "prepaid", "*out", "cgrates.org", "call", "1001", "1001", "+4986517174963",
|
||||
"2013-02-03 19:50:00", "2013-02-03 19:54:00", "62000000000", "supplier1", "172.16.1.1"}
|
||||
"2013-02-03 19:50:00", "2013-02-03 19:54:00", "62", "supplier1", "172.16.1.1"}
|
||||
rtCdr, err := cdrc.recordToStoredCdr(cdrRow)
|
||||
if err != nil {
|
||||
t.Error("Failed to parse CDR in rated cdr", err)
|
||||
|
||||
@@ -47,7 +47,7 @@ func TestCsvCdrWriter(t *testing.T) {
|
||||
if err := cdre.writeCsv(csvWriter); err != nil {
|
||||
t.Error("Unexpected error: ", err)
|
||||
}
|
||||
expected := `dbafe9c8614c785a65aabd116dd3959c3c56f7f6,default,*voice,dsafdsaf,rated,*out,cgrates.org,call,1001,1001,1002,2013-11-07T08:42:25Z,2013-11-07T08:42:26Z,10000000000,1.0100`
|
||||
expected := `dbafe9c8614c785a65aabd116dd3959c3c56f7f6,default,*voice,dsafdsaf,rated,*out,cgrates.org,call,1001,1001,1002,2013-11-07T08:42:25Z,2013-11-07T08:42:26Z,10,1.0100`
|
||||
result := strings.TrimSpace(writer.String())
|
||||
if result != expected {
|
||||
t.Errorf("Expected: \n%s received: \n%s.", expected, result)
|
||||
@@ -75,7 +75,7 @@ func TestAlternativeFieldSeparator(t *testing.T) {
|
||||
if err := cdre.writeCsv(csvWriter); err != nil {
|
||||
t.Error("Unexpected error: ", err)
|
||||
}
|
||||
expected := `dbafe9c8614c785a65aabd116dd3959c3c56f7f6|default|*voice|dsafdsaf|rated|*out|cgrates.org|call|1001|1001|1002|2013-11-07T08:42:25Z|2013-11-07T08:42:26Z|10000000000|1.0100`
|
||||
expected := `dbafe9c8614c785a65aabd116dd3959c3c56f7f6|default|*voice|dsafdsaf|rated|*out|cgrates.org|call|1001|1001|1002|2013-11-07T08:42:25Z|2013-11-07T08:42:26Z|10|1.0100`
|
||||
result := strings.TrimSpace(writer.String())
|
||||
if result != expected {
|
||||
t.Errorf("Expected: \n%s received: \n%s.", expected, result)
|
||||
|
||||
@@ -69,7 +69,7 @@ func (cgrCdr CgrCdr) AsStoredCdr() *StoredCdr {
|
||||
storCdr.Destination = cgrCdr[DESTINATION]
|
||||
storCdr.SetupTime, _ = ParseTimeDetectLayout(cgrCdr[SETUP_TIME]) // Not interested to process errors, should do them if necessary in a previous step
|
||||
storCdr.AnswerTime, _ = ParseTimeDetectLayout(cgrCdr[ANSWER_TIME])
|
||||
storCdr.Usage, _ = ParseDurationWithNanosecs(cgrCdr[USAGE])
|
||||
storCdr.Usage, _ = ParseDurationWithSecs(cgrCdr[USAGE])
|
||||
storCdr.ExtraFields = cgrCdr.getExtraFields()
|
||||
storCdr.Cost = -1
|
||||
return storCdr
|
||||
|
||||
@@ -34,7 +34,7 @@ func TestCgrCdrInterfaces(t *testing.T) {
|
||||
|
||||
func TestCgrCdrAsStoredCdr(t *testing.T) {
|
||||
cgrCdr := CgrCdr{TOR: VOICE, ACCID: "dsafdsaf", CDRHOST: "192.168.1.1", CDRSOURCE: "internal_test", REQTYPE: "rated", DIRECTION: "*out", TENANT: "cgrates.org", CATEGORY: "call",
|
||||
ACCOUNT: "1001", SUBJECT: "1001", DESTINATION: "1002", SETUP_TIME: "2013-11-07T08:42:20Z", ANSWER_TIME: "2013-11-07T08:42:26Z", USAGE: "10000000000",
|
||||
ACCOUNT: "1001", SUBJECT: "1001", DESTINATION: "1002", SETUP_TIME: "2013-11-07T08:42:20Z", ANSWER_TIME: "2013-11-07T08:42:26Z", USAGE: "10",
|
||||
"field_extr1": "val_extr1", "fieldextr2": "valextr2"}
|
||||
setupTime, _ := ParseTimeDetectLayout(cgrCdr["setup_time"])
|
||||
expctRtCdr := &StoredCdr{CgrId: Sha1(cgrCdr["accid"], setupTime.String()), TOR: VOICE, AccId: cgrCdr["accid"], CdrHost: cgrCdr["cdrhost"], CdrSource: cgrCdr["cdrsource"], ReqType: cgrCdr["reqtype"],
|
||||
|
||||
@@ -208,19 +208,14 @@ func CopyHour(src, dest time.Time) time.Time {
|
||||
return time.Date(dest.Year(), dest.Month(), dest.Day(), src.Hour(), src.Minute(), src.Second(), src.Nanosecond(), src.Location())
|
||||
}
|
||||
|
||||
// Parses duration, considers s as time unit if not provided
|
||||
// Parses duration, considers s as time unit if not provided, seconds as float to specify subunits
|
||||
func ParseDurationWithSecs(durStr string) (time.Duration, error) {
|
||||
if _, err := strconv.Atoi(durStr); err == nil { // No suffix, default to seconds
|
||||
durStr += "s"
|
||||
if durSecs, err := strconv.ParseFloat(durStr, 64); err == nil { // Seconds format considered
|
||||
durNanosecs := int(durSecs * 1000000000)
|
||||
return time.Duration(durNanosecs), nil
|
||||
} else {
|
||||
return time.ParseDuration(durStr)
|
||||
}
|
||||
return time.ParseDuration(durStr)
|
||||
}
|
||||
|
||||
func ParseDurationWithNanosecs(durStr string) (time.Duration, error) {
|
||||
if _, err := strconv.Atoi(durStr); err == nil { // No suffix, default to seconds
|
||||
durStr += "ns"
|
||||
}
|
||||
return time.ParseDuration(durStr)
|
||||
}
|
||||
|
||||
func AccountKey(tenant, account, direction string) string {
|
||||
|
||||
@@ -77,14 +77,8 @@ func (storedCdr *StoredCdr) FormatUsage(layout string) string {
|
||||
return strconv.FormatFloat(Round(storedCdr.Usage.Seconds(), 0, ROUNDING_MIDDLE), 'f', -1, 64)
|
||||
}
|
||||
switch layout {
|
||||
case HOURS:
|
||||
return strconv.FormatFloat(Round(storedCdr.Usage.Seconds(), 0, ROUNDING_MIDDLE), 'f', -1, 64)
|
||||
case MINUTES:
|
||||
return strconv.FormatFloat(Round(storedCdr.Usage.Seconds(), 0, ROUNDING_MIDDLE), 'f', -1, 64)
|
||||
case SECONDS:
|
||||
return strconv.FormatFloat(Round(storedCdr.Usage.Seconds(), 0, ROUNDING_MIDDLE), 'f', -1, 64)
|
||||
default:
|
||||
return strconv.FormatInt(storedCdr.Usage.Nanoseconds(), 10)
|
||||
return strconv.FormatFloat(float64(storedCdr.Usage.Nanoseconds())/1000000000, 'f', -1, 64)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,10 +116,7 @@ func (storedCdr *StoredCdr) FieldAsString(rsrFld *RSRField) string {
|
||||
case ANSWER_TIME:
|
||||
return rsrFld.ParseValue(storedCdr.AnswerTime.String())
|
||||
case USAGE:
|
||||
//if IsSliceMember([]string{DATA, SMS}, storedCdr.TOR) {
|
||||
// return strconv.FormatFloat(Round(storedCdr.Usage.Seconds(), 0, ROUNDING_MIDDLE), 'f', -1, 64)
|
||||
//}
|
||||
return rsrFld.ParseValue(strconv.FormatInt(storedCdr.Usage.Nanoseconds(), 10))
|
||||
return strconv.FormatFloat(Round(storedCdr.Usage.Seconds(), 0, ROUNDING_MIDDLE), 'f', -1, 64)
|
||||
case MEDI_RUNID:
|
||||
return rsrFld.ParseValue(storedCdr.MediationRunId)
|
||||
case RATED_ACCOUNT:
|
||||
@@ -182,7 +173,7 @@ func (storedCdr *StoredCdr) AsHttpForm() url.Values {
|
||||
v.Set(DESTINATION, storedCdr.Destination)
|
||||
v.Set(SETUP_TIME, storedCdr.SetupTime.String())
|
||||
v.Set(ANSWER_TIME, storedCdr.AnswerTime.String())
|
||||
v.Set(USAGE, strconv.FormatInt(storedCdr.Usage.Nanoseconds(), 10))
|
||||
v.Set(USAGE, storedCdr.FormatUsage(SECONDS))
|
||||
return v
|
||||
}
|
||||
|
||||
@@ -301,7 +292,7 @@ func (storedCdr *StoredCdr) ForkCdr(runId string, reqTypeFld, directionFld, tena
|
||||
durStr := storedCdr.FieldAsString(durationFld)
|
||||
if primaryMandatory && len(durStr) == 0 {
|
||||
return nil, errors.New(fmt.Sprintf("%s:%s:%s", ERR_MANDATORY_IE_MISSING, USAGE, durationFld.Id))
|
||||
} else if frkStorCdr.Usage, err = ParseDurationWithNanosecs(durStr); err != nil {
|
||||
} else if frkStorCdr.Usage, err = ParseDurationWithSecs(durStr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
frkStorCdr.ExtraFields = make(map[string]string, len(extraFlds))
|
||||
|
||||
@@ -48,7 +48,7 @@ func TestFieldAsString(t *testing.T) {
|
||||
cdr.FieldAsString(&RSRField{Id: DESTINATION}) != cdr.Destination ||
|
||||
cdr.FieldAsString(&RSRField{Id: SETUP_TIME}) != cdr.SetupTime.String() ||
|
||||
cdr.FieldAsString(&RSRField{Id: ANSWER_TIME}) != cdr.AnswerTime.String() ||
|
||||
cdr.FieldAsString(&RSRField{Id: USAGE}) != "10000000000" ||
|
||||
cdr.FieldAsString(&RSRField{Id: USAGE}) != "10" ||
|
||||
cdr.FieldAsString(&RSRField{Id: MEDI_RUNID}) != cdr.MediationRunId ||
|
||||
cdr.FieldAsString(&RSRField{Id: COST}) != "1.01" ||
|
||||
cdr.FieldAsString(&RSRField{Id: RATED_ACCOUNT}) != "dan" ||
|
||||
@@ -71,7 +71,7 @@ func TestFieldAsString(t *testing.T) {
|
||||
cdr.FieldAsString(&RSRField{Id: DESTINATION}) != cdr.Destination,
|
||||
cdr.FieldAsString(&RSRField{Id: SETUP_TIME}) != cdr.SetupTime.String(),
|
||||
cdr.FieldAsString(&RSRField{Id: ANSWER_TIME}) != cdr.AnswerTime.String(),
|
||||
cdr.FieldAsString(&RSRField{Id: USAGE}) != "10000000000",
|
||||
cdr.FieldAsString(&RSRField{Id: USAGE}) != "10",
|
||||
cdr.FieldAsString(&RSRField{Id: MEDI_RUNID}) != cdr.MediationRunId,
|
||||
cdr.FieldAsString(&RSRField{Id: RATED_ACCOUNT}) != "dan",
|
||||
cdr.FieldAsString(&RSRField{Id: RATED_SUBJECT}) != "dans",
|
||||
@@ -225,7 +225,7 @@ func TestFormatUsage(t *testing.T) {
|
||||
if cdr.FormatUsage(SECONDS) != "10" {
|
||||
t.Error("Wrong usage format: ", cdr.FormatUsage(SECONDS))
|
||||
}
|
||||
if cdr.FormatUsage("default") != "10000000000" {
|
||||
if cdr.FormatUsage("default") != "10" {
|
||||
t.Error("Wrong usage format: ", cdr.FormatUsage("default"))
|
||||
}
|
||||
cdr = StoredCdr{TOR: DATA, Usage: time.Duration(1640113000000000)}
|
||||
@@ -280,8 +280,8 @@ func TestStoredCdrAsHttpForm(t *testing.T) {
|
||||
if cdrForm.Get(ANSWER_TIME) != "2013-11-07 08:42:26 +0000 UTC" {
|
||||
t.Errorf("Expected: %s, received: %s", "2013-11-07 08:42:26 +0000 UTC", cdrForm.Get(ANSWER_TIME))
|
||||
}
|
||||
if cdrForm.Get(USAGE) != "10000000000" {
|
||||
t.Errorf("Expected: %s, received: %s", "10000000000", cdrForm.Get(USAGE))
|
||||
if cdrForm.Get(USAGE) != "10" {
|
||||
t.Errorf("Expected: %s, received: %s", "10", cdrForm.Get(USAGE))
|
||||
}
|
||||
if cdrForm.Get("field_extr1") != "val_extr1" {
|
||||
t.Errorf("Expected: %s, received: %s", "val_extr1", cdrForm.Get("field_extr1"))
|
||||
|
||||
@@ -391,30 +391,6 @@ func TestParseDurationWithSecs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseDurationWithNanosecs(t *testing.T) {
|
||||
durStr := "2"
|
||||
durExpected := time.Duration(2) * time.Nanosecond
|
||||
if parsed, err := ParseDurationWithNanosecs(durStr); err != nil {
|
||||
t.Error(err)
|
||||
} else if parsed != durExpected {
|
||||
t.Error("Parsed different than expected")
|
||||
}
|
||||
durStr = "2s"
|
||||
durExpected = time.Duration(2) * time.Second
|
||||
if parsed, err := ParseDurationWithNanosecs(durStr); err != nil {
|
||||
t.Error(err)
|
||||
} else if parsed != durExpected {
|
||||
t.Error("Parsed different than expected")
|
||||
}
|
||||
durStr = "2ms"
|
||||
durExpected = time.Duration(2) * time.Millisecond
|
||||
if parsed, err := ParseDurationWithNanosecs(durStr); err != nil {
|
||||
t.Error(err)
|
||||
} else if parsed != durExpected {
|
||||
t.Error("Parsed different than expected")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMinDuration(t *testing.T) {
|
||||
d1, _ := time.ParseDuration("1m")
|
||||
d2, _ := time.ParseDuration("59s")
|
||||
|
||||
Reference in New Issue
Block a user