Usage as imported/exported as floated seconds instead of nanoseconds

This commit is contained in:
DanB
2014-09-23 11:54:43 +02:00
parent bfcb317501
commit a67def57b9
9 changed files with 21 additions and 59 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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"],

View File

@@ -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 {

View File

@@ -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))

View File

@@ -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"))

View File

@@ -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")