diff --git a/apier/cdre.go b/apier/cdre.go index b79687634..0a76d15bd 100644 --- a/apier/cdre.go +++ b/apier/cdre.go @@ -71,7 +71,7 @@ func (self *ApierV1) ExportCdrsToFile(attr utils.AttrExpFileCdrs, reply *utils.E maskLen = attr.MaskLength } cdrs, err := self.CdrDb.GetStoredCdrs(attr.CgrIds, attr.MediationRunId, attr.TOR, attr.CdrHost, attr.CdrSource, attr.ReqType, attr.Direction, - attr.Tenant, attr.Category, attr.Account, attr.Subject, attr.DestinationPrefix, attr.OrderIdStart, attr.OrderIdEnd, tStart, tEnd, attr.SkipErrors, attr.SkipRated) + attr.Tenant, attr.Category, attr.Account, attr.Subject, attr.DestinationPrefix, attr.OrderIdStart, attr.OrderIdEnd, tStart, tEnd, attr.SkipErrors, attr.SkipRated, false) if err != nil { return err } else if len(cdrs) == 0 { diff --git a/apier/cdrs.go b/apier/cdrs.go index 975b3b017..77ba81af9 100644 --- a/apier/cdrs.go +++ b/apier/cdrs.go @@ -22,6 +22,7 @@ import ( "fmt" "github.com/cgrates/cgrates/engine" "github.com/cgrates/cgrates/utils" + "time" ) type AttrGetCallCost struct { @@ -43,3 +44,27 @@ func (apier *ApierV1) GetCallCostLog(attrs AttrGetCallCost, reply *engine.CallCo } return nil } + +// Retrieves CDRs based on the filters +func (apier *ApierV1) GetCdrs(attrs utils.AttrGetCdrs, reply *[]*utils.StoredCdr) error { + var tStart, tEnd time.Time + var err error + if len(attrs.TimeStart) != 0 { + if tStart, err = utils.ParseTimeDetectLayout(attrs.TimeStart); err != nil { + return err + } + } + if len(attrs.TimeEnd) != 0 { + if tEnd, err = utils.ParseTimeDetectLayout(attrs.TimeEnd); err != nil { + return err + } + } + if cdrs, err := apier.CdrDb.GetStoredCdrs(attrs.CgrIds, attrs.MediationRunId, attrs.TOR, attrs.CdrHost, attrs.CdrSource, attrs.ReqType, attrs.Direction, + attrs.Tenant, attrs.Category, attrs.Account, attrs.Subject, attrs.DestinationPrefix, + attrs.OrderIdStart, attrs.OrderIdEnd, tStart, tEnd, attrs.SkipErrors, attrs.SkipRated, false); err != nil { + return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) + } else { + *reply = cdrs + } + return nil +} diff --git a/cdre/csv_test.go b/cdre/csv_test.go index 29dbd3aa8..82e385f19 100644 --- a/cdre/csv_test.go +++ b/cdre/csv_test.go @@ -40,7 +40,7 @@ func TestCsvCdrWriter(t *testing.T) { } csvCdrWriter.WriteCdr(ratedCdr) csvCdrWriter.Close() - expected := `dbafe9c8614c785a65aabd116dd3959c3c56f7f6,default,*voice,dsafdsaf,192.168.1.1,rated,*out,cgrates.org,call,1001,1001,1002,2013-11-07 08:42:25 +0000 UTC,2013-11-07 08:42:26 +0000 UTC,10,1.0100,val_extra3,"",val_extra1` + expected := `dbafe9c8614c785a65aabd116dd3959c3c56f7f6,default,*voice,dsafdsaf,192.168.1.1,rated,*out,cgrates.org,call,1001,1001,1002,2013-11-07 08:42:25 +0000 UTC,2013-11-07 08:42:26 +0000 UTC,10000000000,1.0100,val_extra3,"",val_extra1` result := strings.TrimSpace(writer.String()) if result != expected { t.Errorf("Expected: \n%s received: \n%s.", expected, result) diff --git a/cdre/fixedwidth.go b/cdre/fixedwidth.go index 84482f971..136ff350c 100644 --- a/cdre/fixedwidth.go +++ b/cdre/fixedwidth.go @@ -120,6 +120,8 @@ func (fwv *FixedWidthCdrWriter) cdrFieldValue(cdr *utils.StoredCdr, cfgHdr, layo } case utils.COST: cdrVal = cdr.FormatCost(fwv.costShiftDigits, fwv.roundDecimals) + case utils.DURATION: + cdrVal = cdr.FormatDuration(layout) case utils.SETUP_TIME: cdrVal = cdr.SetupTime.Format(layout) case utils.ANSWER_TIME: // Format time based on layout diff --git a/cdre/fixedwidth_test.go b/cdre/fixedwidth_test.go index 8cc7ccad1..cfa6ef619 100644 --- a/cdre/fixedwidth_test.go +++ b/cdre/fixedwidth_test.go @@ -47,7 +47,7 @@ var contentCfgFlds = []*config.CgrXmlCfgCdrField{ &config.CgrXmlCfgCdrField{Name: "TOR", Type: CONSTANT, Value: "02", Width: 2}, &config.CgrXmlCfgCdrField{Name: "SubtypeTOR", Type: CONSTANT, Value: "11", Width: 4, Padding: "right"}, &config.CgrXmlCfgCdrField{Name: "SetupTime", Type: CDRFIELD, Value: utils.SETUP_TIME, Width: 12, Strip: "right", Padding: "right", Layout: "020106150400"}, - &config.CgrXmlCfgCdrField{Name: "Duration", Type: CDRFIELD, Value: utils.DURATION, Width: 6, Strip: "right", Padding: "right"}, + &config.CgrXmlCfgCdrField{Name: "Duration", Type: CDRFIELD, Value: utils.DURATION, Width: 6, Strip: "right", Padding: "right", Layout: utils.SECONDS}, &config.CgrXmlCfgCdrField{Name: "DataVolume", Type: FILLER, Width: 6}, &config.CgrXmlCfgCdrField{Name: "TaxCode", Type: CONSTANT, Value: "1", Width: 1}, &config.CgrXmlCfgCdrField{Name: "OperatorCode", Type: CDRFIELD, Value: "opercode", Width: 2, Strip: "right", Padding: "right"}, diff --git a/data/storage/mysql/alter_tables_rc4_rc5.sql b/data/storage/mysql/alter_tables_rc4_rc5.sql new file mode 100644 index 000000000..1a54a26f1 --- /dev/null +++ b/data/storage/mysql/alter_tables_rc4_rc5.sql @@ -0,0 +1,48 @@ +ALTER TABLE cdrs_primary + CHANGE COLUMN tor category varchar(16) NOT NULL, + CHANGE COLUMN duration `usage` bigint(20) NOT NULL, + ADD COLUMN tor varchar(16) NOT NULL AFTER cgrid; + +UPDATE cdrs_primary SET tor="*voice"; + +ALTER TABLE cost_details + DROP COLUMN accid, + MODIFY COLUMN cost_time datetime NOT NULL AFTER tbid, + CHANGE COLUMN `source` cost_source varchar(64) NOT NULL AFTER cost_time, + MODIFY COLUMN runid varchar(64) NOT NULL AFTER cgrid, + CHANGE COLUMN tor category varchar(32) NOT NULL AFTER tenant, + ADD COLUMN tor varchar(16) NOT NULL after runid, + MODIFY COLUMN direction varchar(8) NOT NULL AFTER tor; + +UPDATE cost_details SET tor="*voice"; + +ALTER TABLE rated_cdrs + MODIFY COLUMN mediation_time datetime NOT NULL AFTER tbid, + MODIFY COLUMN subject varchar(128) NOT NULL, + ADD COLUMN reqtype varchar(24) NOT NULL AFTER runid, + ADD COLUMN direction varchar(8) NOT NULL AFTER reqtype, + ADD COLUMN tenant varchar(64) NOT NULL AFTER direction, + ADD COLUMN category varchar(16) NOT NULL AFTER tenant, + ADD COLUMN account varchar(128) NOT NULL AFTER category, + ADD COLUMN destination varchar(128) NOT NULL AFTER subject, + ADD COLUMN setup_time datetime NOT NULL AFTER destination, + ADD COLUMN answer_time datetime NOT NULL AFTER setup_time, + ADD COLUMN `usage` bigint(20) NOT NULL AFTER answer_time; + +ALTER TABLE tp_rates + DROP COLUMN rounding_method, + DROP COLUMN rounding_decimals; + +ALTER TABLE tp_destination_rates + ADD COLUMN rounding_method varchar(255) NOT NULL, + ADD COLUMN rounding_decimals tinyint(4) NOT NULL; + +ALTER TABLE tp_rating_profiles + DROP KEY tpid_loadid_tenant_tor_dir_subj_atime, + CHANGE COLUMN tor category varchar(16) NOT NULL, + ADD UNIQUE KEY `tpid_loadid_tenant_category_dir_subj_atime` (`tpid`,`loadid`,`tenant`,`category`,`direction`,`subject`,`activation_time`); + + + + + diff --git a/engine/storage_interface.go b/engine/storage_interface.go index 02eda7bae..6774c86f4 100644 --- a/engine/storage_interface.go +++ b/engine/storage_interface.go @@ -113,7 +113,7 @@ type CdrStorage interface { SetCdr(*utils.StoredCdr) error SetRatedCdr(*utils.StoredCdr, string) error GetStoredCdrs([]string, []string, []string, []string, []string, []string, []string, []string, []string, []string, []string, []string, - int64, int64, time.Time, time.Time, bool, bool) ([]*utils.StoredCdr, error) + int64, int64, time.Time, time.Time, bool, bool, bool) ([]*utils.StoredCdr, error) RemStoredCdrs([]string) error } diff --git a/engine/storage_sql.go b/engine/storage_sql.go index cd47fe3c7..e7685c618 100644 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -23,6 +23,7 @@ import ( "database/sql" "encoding/json" "fmt" + "github.com/go-sql-driver/mysql" "io/ioutil" "strings" "time" @@ -607,35 +608,66 @@ func (self *SQLStorage) SetRatedCdr(storedCdr *utils.StoredCdr, extraInfo string // ignoreErr - do not consider cdrs with rating errors // ignoreRated - do not consider cdrs which were already rated, including here the ones with errors func (self *SQLStorage) GetStoredCdrs(cgrIds, runIds, tors, cdrHosts, cdrSources, reqTypes, directions, tenants, categories, accounts, subjects, destPrefixes []string, orderIdStart, orderIdEnd int64, - timeStart, timeEnd time.Time, ignoreErr, ignoreRated bool) ([]*utils.StoredCdr, error) { + timeStart, timeEnd time.Time, ignoreErr, ignoreRated, ignoreDerived bool) ([]*utils.StoredCdr, error) { var cdrs []*utils.StoredCdr - q := bytes.NewBufferString(fmt.Sprintf("SELECT %s.cgrid,%s.tbid,%s.tor,%s.accid,%s.cdrhost,%s.cdrsource,%s.reqtype,%s.direction,%s.tenant,%s.category,%s.account,%s.subject,%s.destination,%s.setup_time,%s.answer_time,%s.`usage`,%s.extra_fields,%s.runid,%s.cost FROM %s LEFT JOIN %s ON %s.cgrid=%s.cgrid LEFT JOIN %s ON %s.cgrid=%s.cgrid", - utils.TBL_CDRS_PRIMARY, - utils.TBL_CDRS_PRIMARY, - utils.TBL_CDRS_PRIMARY, - utils.TBL_CDRS_PRIMARY, - utils.TBL_CDRS_PRIMARY, - utils.TBL_CDRS_PRIMARY, - utils.TBL_CDRS_PRIMARY, - utils.TBL_CDRS_PRIMARY, - utils.TBL_CDRS_PRIMARY, - utils.TBL_CDRS_PRIMARY, - utils.TBL_CDRS_PRIMARY, - utils.TBL_CDRS_PRIMARY, - utils.TBL_CDRS_PRIMARY, - utils.TBL_CDRS_PRIMARY, - utils.TBL_CDRS_PRIMARY, - utils.TBL_CDRS_PRIMARY, - utils.TBL_CDRS_EXTRA, - utils.TBL_RATED_CDRS, - utils.TBL_RATED_CDRS, - utils.TBL_CDRS_PRIMARY, - utils.TBL_CDRS_EXTRA, - utils.TBL_CDRS_PRIMARY, - utils.TBL_CDRS_EXTRA, - utils.TBL_RATED_CDRS, - utils.TBL_CDRS_PRIMARY, - utils.TBL_RATED_CDRS)) + var q *bytes.Buffer // Need to query differently since in case of primary, unmediated CDRs some values will be missing + if ignoreDerived { + q = bytes.NewBufferString(fmt.Sprintf("SELECT %s.cgrid,%s.tbid,%s.tor,%s.accid,%s.cdrhost,%s.cdrsource,%s.reqtype,%s.direction,%s.tenant,%s.category,%s.account,%s.subject,%s.destination,%s.setup_time,%s.answer_time,%s.`usage`,%s.extra_fields,%s.runid,%s.cost FROM %s LEFT JOIN %s ON %s.cgrid=%s.cgrid LEFT JOIN %s ON %s.cgrid=%s.cgrid", + utils.TBL_CDRS_PRIMARY, + utils.TBL_CDRS_PRIMARY, + utils.TBL_CDRS_PRIMARY, + utils.TBL_CDRS_PRIMARY, + utils.TBL_CDRS_PRIMARY, + utils.TBL_CDRS_PRIMARY, + utils.TBL_CDRS_PRIMARY, + utils.TBL_CDRS_PRIMARY, + utils.TBL_CDRS_PRIMARY, + utils.TBL_CDRS_PRIMARY, + utils.TBL_CDRS_PRIMARY, + utils.TBL_CDRS_PRIMARY, + utils.TBL_CDRS_PRIMARY, + utils.TBL_CDRS_PRIMARY, + utils.TBL_CDRS_PRIMARY, + utils.TBL_CDRS_PRIMARY, + utils.TBL_CDRS_EXTRA, + utils.TBL_RATED_CDRS, + utils.TBL_RATED_CDRS, + utils.TBL_CDRS_PRIMARY, + utils.TBL_CDRS_EXTRA, + utils.TBL_CDRS_PRIMARY, + utils.TBL_CDRS_EXTRA, + utils.TBL_RATED_CDRS, + utils.TBL_CDRS_PRIMARY, + utils.TBL_RATED_CDRS)) + } else { + q = bytes.NewBufferString(fmt.Sprintf("SELECT %s.cgrid,%s.tbid,%s.tor,%s.accid,%s.cdrhost,%s.cdrsource,%s.reqtype,%s.direction,%s.tenant,%s.category,%s.account,%s.subject,%s.destination,%s.setup_time,%s.answer_time,%s.`usage`,%s.extra_fields,%s.runid,%s.cost FROM %s LEFT JOIN %s ON %s.cgrid=%s.cgrid LEFT JOIN %s ON %s.cgrid=%s.cgrid", + utils.TBL_CDRS_PRIMARY, + utils.TBL_CDRS_PRIMARY, + utils.TBL_CDRS_PRIMARY, + utils.TBL_CDRS_PRIMARY, + utils.TBL_CDRS_PRIMARY, + utils.TBL_CDRS_PRIMARY, + utils.TBL_RATED_CDRS, + utils.TBL_RATED_CDRS, + utils.TBL_RATED_CDRS, + utils.TBL_RATED_CDRS, + utils.TBL_RATED_CDRS, + utils.TBL_RATED_CDRS, + utils.TBL_RATED_CDRS, + utils.TBL_RATED_CDRS, + utils.TBL_RATED_CDRS, + utils.TBL_RATED_CDRS, + utils.TBL_CDRS_EXTRA, + utils.TBL_RATED_CDRS, + utils.TBL_RATED_CDRS, + utils.TBL_CDRS_PRIMARY, + utils.TBL_CDRS_EXTRA, + utils.TBL_CDRS_PRIMARY, + utils.TBL_CDRS_EXTRA, + utils.TBL_RATED_CDRS, + utils.TBL_CDRS_PRIMARY, + utils.TBL_RATED_CDRS)) + } fltr := new(bytes.Buffer) if len(cgrIds) != 0 { qIds := bytes.NewBufferString(" (") @@ -844,6 +876,12 @@ func (self *SQLStorage) GetStoredCdrs(cgrIds, runIds, tors, cdrHosts, cdrSources } fltr.WriteString(fmt.Sprintf(" (%s.cost!=-1 OR %s.cost IS NULL)", utils.TBL_RATED_CDRS, utils.TBL_RATED_CDRS)) } + if ignoreDerived { + if fltr.Len() != 0 { + fltr.WriteString(" AND") + } + fltr.WriteString(fmt.Sprintf(" (%s.runid='%s' OR %s.cost IS NULL)", utils.TBL_RATED_CDRS, utils.DEFAULT_RUNID, utils.TBL_RATED_CDRS)) + } if fltr.Len() != 0 { q.WriteString(fmt.Sprintf(" WHERE %s", fltr.String())) } @@ -853,11 +891,11 @@ func (self *SQLStorage) GetStoredCdrs(cgrIds, runIds, tors, cdrHosts, cdrSources } defer rows.Close() for rows.Next() { - var cgrid, tor, accid, cdrhost, cdrsrc, reqtype, direction, tenant, category, account, subject, destination string + var cgrid, tor, accid, cdrhost, cdrsrc, reqtype, direction, tenant, category, account, subject, destination, runid sql.NullString var extraFields []byte - var setupTime, answerTime time.Time - var runid sql.NullString // So we can export unmediated CDRs - var orderid, usage int64 + var setupTime, answerTime mysql.NullTime + var orderid int64 + var usage sql.NullInt64 var cost sql.NullFloat64 // So we can export unmediated CDRs var extraFieldsMp map[string]string if err := rows.Scan(&cgrid, &orderid, &tor, &accid, &cdrhost, &cdrsrc, &reqtype, &direction, &tenant, &category, &account, &subject, &destination, &setupTime, &answerTime, &usage, @@ -868,8 +906,10 @@ func (self *SQLStorage) GetStoredCdrs(cgrIds, runIds, tors, cdrHosts, cdrSources return nil, fmt.Errorf("JSON unmarshal error for cgrid: %s, runid: %v, error: %s", cgrid, runid, err.Error()) } storCdr := &utils.StoredCdr{ - CgrId: cgrid, OrderId: orderid, TOR: tor, AccId: accid, CdrHost: cdrhost, CdrSource: cdrsrc, ReqType: reqtype, Direction: direction, Tenant: tenant, - Category: category, Account: account, Subject: subject, Destination: destination, SetupTime: setupTime, AnswerTime: answerTime, Duration: time.Duration(usage), + CgrId: cgrid.String, OrderId: orderid, TOR: tor.String, AccId: accid.String, CdrHost: cdrhost.String, CdrSource: cdrsrc.String, ReqType: reqtype.String, + Direction: direction.String, Tenant: tenant.String, + Category: category.String, Account: account.String, Subject: subject.String, Destination: destination.String, + SetupTime: setupTime.Time, AnswerTime: answerTime.Time, Duration: time.Duration(usage.Int64), ExtraFields: extraFieldsMp, MediationRunId: runid.String, Cost: cost.Float64, } cdrs = append(cdrs, storCdr) diff --git a/engine/storage_sql_local_test.go b/engine/storage_sql_local_test.go index 1512eef4b..e9b6a4c32 100644 --- a/engine/storage_sql_local_test.go +++ b/engine/storage_sql_local_test.go @@ -33,15 +33,15 @@ README: Enable these tests by passing '-local' to the go test command - Only database supported for now is MySQL. Postgres could be easily extended if needed. + Only database supported for now is mysqlDb. Postgres could be easily extended if needed. It is expected that the data folder of CGRateS exists at path /usr/share/cgrates/data. Prior running the tests, create database and users by running: - mysql -pyourrootpwd < /usr/share/cgrates/storage/mysql/create_mysql_with_users.sql + mysqlDb -pyourrootpwd < /usr/share/cgrates/storage/mysqlDb/create_mysqlDb_with_users.sql */ -var mysql *MySQLStorage +var mysqlDb *MySQLStorage func TestCreateTables(t *testing.T) { if !*testLocal { @@ -52,16 +52,16 @@ func TestCreateTables(t *testing.T) { t.Error("Error on opening database connection: ", err) return } else { - mysql = d.(*MySQLStorage) + mysqlDb = d.(*MySQLStorage) } for _, scriptName := range []string{CREATE_CDRS_TABLES_SQL, CREATE_TARIFFPLAN_TABLES_SQL} { - if err := mysql.CreateTablesFromScript(path.Join(*dataDir, "storage", "mysql", scriptName)); err != nil { - t.Error("Error on mysql creation: ", err.Error()) + if err := mysqlDb.CreateTablesFromScript(path.Join(*dataDir, "storage", "mysql", scriptName)); err != nil { + t.Error("Error on mysqlDb creation: ", err.Error()) return // No point in going further } } for _, tbl := range []string{utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_EXTRA} { - if _, err := mysql.Db.Query(fmt.Sprintf("SELECT 1 from %s", tbl)); err != nil { + if _, err := mysqlDb.Db.Query(fmt.Sprintf("SELECT 1 from %s", tbl)); err != nil { t.Error(err.Error()) } } @@ -73,19 +73,19 @@ func TestRemoveData(t *testing.T) { } // Create Timings tm := &utils.TPTiming{Id: "ALWAYS", StartTime: "00:00:00"} - if err := mysql.SetTPTiming(TEST_SQL, tm); err != nil { + if err := mysqlDb.SetTPTiming(TEST_SQL, tm); err != nil { t.Error(err.Error()) } - if tmgs, err := mysql.GetTpTimings(TEST_SQL, tm.Id); err != nil { + if tmgs, err := mysqlDb.GetTpTimings(TEST_SQL, tm.Id); err != nil { t.Error(err.Error()) } else if len(tmgs) == 0 { t.Error("Could not store TPTiming") } // Remove Timings - if err := mysql.RemTPData(utils.TBL_TP_TIMINGS, TEST_SQL, tm.Id); err != nil { + if err := mysqlDb.RemTPData(utils.TBL_TP_TIMINGS, TEST_SQL, tm.Id); err != nil { t.Error(err.Error()) } - if tmgs, err := mysql.GetTpTimings(TEST_SQL, tm.Id); err != nil { + if tmgs, err := mysqlDb.GetTpTimings(TEST_SQL, tm.Id); err != nil { t.Error(err.Error()) } else if len(tmgs) != 0 { t.Error("Did not remove TPTiming") @@ -93,19 +93,19 @@ func TestRemoveData(t *testing.T) { // Create RatingProfile ras := []*utils.TPRatingActivation{&utils.TPRatingActivation{ActivationTime: "2012-01-01T00:00:00Z", RatingPlanId: "RETAIL1"}} rp := &utils.TPRatingProfile{TPid: TEST_SQL, LoadId: TEST_SQL, Tenant: "cgrates.org", Category: "call", Direction: "*out", Subject: "*any", RatingPlanActivations: ras} - if err := mysql.SetTPRatingProfiles(TEST_SQL, map[string]*utils.TPRatingProfile{rp.KeyId(): rp}); err != nil { + if err := mysqlDb.SetTPRatingProfiles(TEST_SQL, map[string]*utils.TPRatingProfile{rp.KeyId(): rp}); err != nil { t.Error(err.Error()) } - if rps, err := mysql.GetTpRatingProfiles(rp); err != nil { + if rps, err := mysqlDb.GetTpRatingProfiles(rp); err != nil { t.Error(err.Error()) } else if len(rps) == 0 { t.Error("Could not store TPRatingProfile") } // Remove RatingProfile - if err := mysql.RemTPData(utils.TBL_TP_RATE_PROFILES, rp.TPid, rp.LoadId, rp.Tenant, rp.Category, rp.Direction, rp.Subject); err != nil { + if err := mysqlDb.RemTPData(utils.TBL_TP_RATE_PROFILES, rp.TPid, rp.LoadId, rp.Tenant, rp.Category, rp.Direction, rp.Subject); err != nil { t.Error(err.Error()) } - if rps, err := mysql.GetTpRatingProfiles(rp); err != nil { + if rps, err := mysqlDb.GetTpRatingProfiles(rp); err != nil { t.Error(err.Error()) } else if len(rps) != 0 { t.Error("Did not remove TPRatingProfile") @@ -114,19 +114,19 @@ func TestRemoveData(t *testing.T) { // Create AccountActions aa := &utils.TPAccountActions{TPid: TEST_SQL, LoadId: TEST_SQL, Tenant: "cgrates.org", Account: "1001", Direction: "*out", ActionPlanId: "PREPAID_10", ActionTriggersId: "STANDARD_TRIGGERS"} - if err := mysql.SetTPAccountActions(aa.TPid, map[string]*utils.TPAccountActions{aa.KeyId(): aa}); err != nil { + if err := mysqlDb.SetTPAccountActions(aa.TPid, map[string]*utils.TPAccountActions{aa.KeyId(): aa}); err != nil { t.Error(err.Error()) } - if aas, err := mysql.GetTpAccountActions(aa); err != nil { + if aas, err := mysqlDb.GetTpAccountActions(aa); err != nil { t.Error(err.Error()) } else if len(aas) == 0 { t.Error("Could not create TPAccountActions") } // Remove AccountActions - if err := mysql.RemTPData(utils.TBL_TP_ACCOUNT_ACTIONS, aa.TPid, aa.LoadId, aa.Tenant, aa.Account, aa.Direction); err != nil { + if err := mysqlDb.RemTPData(utils.TBL_TP_ACCOUNT_ACTIONS, aa.TPid, aa.LoadId, aa.Tenant, aa.Account, aa.Direction); err != nil { t.Error(err.Error()) } - if aas, err := mysql.GetTpAccountActions(aa); err != nil { + if aas, err := mysqlDb.GetTpAccountActions(aa); err != nil { t.Error(err.Error()) } else if len(aas) != 0 { t.Error("Did not remove TPAccountActions") @@ -157,7 +157,7 @@ func TestSetCdr(t *testing.T) { utils.ANSWER_TIME: "2013-11-07T08:42:26Z", utils.DURATION: "15s", "field_extr1": "val_extr1", "fieldextr2": "valextr2", "cdrsource": TEST_SQL} for _, cdr := range []*utils.CgrCdr{cgrCdr1, cgrCdr2, cgrCdr3, cgrCdr4, cgrCdr5} { - if err := mysql.SetCdr(cdr.AsStoredCdr()); err != nil { + if err := mysqlDb.SetCdr(cdr.AsStoredCdr()); err != nil { t.Error(err.Error()) } } @@ -181,7 +181,7 @@ func TestSetCdr(t *testing.T) { strCdr3.CgrId = utils.Sha1(strCdr3.AccId, strCdr3.SetupTime.String()) for _, cdr := range []*utils.StoredCdr{strCdr1, strCdr2, strCdr3} { - if err := mysql.SetCdr(cdr); err != nil { + if err := mysqlDb.SetCdr(cdr); err != nil { t.Error(err.Error()) } } @@ -211,7 +211,7 @@ func TestSetRatedCdr(t *testing.T) { strCdr3.CgrId = utils.Sha1(strCdr3.AccId, strCdr3.SetupTime.String()) for _, cdr := range []*utils.StoredCdr{strCdr1, strCdr2, strCdr3} { - if err := mysql.SetRatedCdr(cdr, ""); err != nil { + if err := mysqlDb.SetRatedCdr(cdr, ""); err != nil { t.Error(err.Error()) } } @@ -223,159 +223,174 @@ func TestGetStoredCdrs(t *testing.T) { } var timeStart, timeEnd time.Time // All CDRs, no filter - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 8 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on cgrids - if storedCdrs, err := mysql.GetStoredCdrs([]string{utils.Sha1("bbb1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), + if storedCdrs, err := mysqlDb.GetStoredCdrs([]string{utils.Sha1("bbb1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), utils.Sha1("bbb2", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String())}, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false); err != nil { + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 2 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on cgrids plus reqType - if storedCdrs, err := mysql.GetStoredCdrs([]string{utils.Sha1("bbb1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), + if storedCdrs, err := mysqlDb.GetStoredCdrs([]string{utils.Sha1("bbb1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), utils.Sha1("bbb2", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String())}, - nil, nil, nil, nil, []string{"prepaid"}, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false); err != nil { + nil, nil, nil, nil, []string{"prepaid"}, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 1 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on runId - if storedCdrs, err := mysql.GetStoredCdrs(nil, []string{utils.DEFAULT_RUNID}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, []string{utils.DEFAULT_RUNID}, + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 2 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on TOR - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, []string{utils.SMS}, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, []string{utils.SMS}, + nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 0 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on multiple TOR - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, []string{utils.SMS, utils.VOICE}, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, []string{utils.SMS, utils.VOICE}, + nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 8 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on cdrHost - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, []string{"192.168.1.2"}, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, []string{"192.168.1.2"}, + nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 3 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on multiple cdrHost - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, []string{"192.168.1.1", "192.168.1.2"}, nil, nil, nil, nil, nil, nil, nil, nil, - 0, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, []string{"192.168.1.1", "192.168.1.2"}, nil, nil, nil, nil, nil, nil, nil, nil, + 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 8 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on cdrSource - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, nil, []string{"UNKNOWN"}, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, []string{"UNKNOWN"}, + nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 1 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on multiple cdrSource - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, nil, []string{"UNKNOWN", "UNKNOWN2"}, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, []string{"UNKNOWN", "UNKNOWN2"}, + nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 2 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on reqType - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, nil, nil, []string{"prepaid"}, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, []string{"prepaid"}, + nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 2 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on multiple reqType - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, nil, nil, []string{"prepaid", "pseudoprepaid"}, nil, nil, nil, nil, nil, nil, - 0, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, []string{"prepaid", "pseudoprepaid"}, nil, nil, nil, nil, nil, nil, + 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 3 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on direction - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, nil, nil, nil, []string{"*out"}, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, []string{"*out"}, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 8 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on tenant - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, []string{"itsyscom.com"}, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, []string{"itsyscom.com"}, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 3 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on multiple tenants - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, []string{"itsyscom.com", "cgrates.org"}, nil, nil, nil, nil, - 0, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, []string{"itsyscom.com", "cgrates.org"}, nil, nil, nil, nil, + 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 8 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on tor - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, []string{"premium_call"}, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, []string{"premium_call"}, + nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 1 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on multiple tor - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, []string{"premium_call", "call"}, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, []string{"premium_call", "call"}, + nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 8 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on account - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, []string{"1002"}, nil, nil, 0, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, []string{"1002"}, + nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 3 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on multiple account - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, []string{"1001", "1002"}, nil, nil, 0, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, []string{"1001", "1002"}, + nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 8 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on subject - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, []string{"1000"}, nil, 0, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, []string{"1000"}, + nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 1 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on multiple subject - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, []string{"1000", "1002"}, nil, 0, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, []string{"1000", "1002"}, + nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 3 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on destPrefix - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, []string{"+498651"}, 0, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, []string{"+498651"}, 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 3 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on multiple destPrefixes - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, []string{"1001", "+498651"}, 0, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, []string{"1001", "+498651"}, + 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 4 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on ignoreErr - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, true, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, true, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 8 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on ignoreRated var orderIdStart, orderIdEnd int64 // Capture also orderIds for the next test - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, true); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, true, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 5 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) @@ -390,37 +405,45 @@ func TestGetStoredCdrs(t *testing.T) { } } // Filter on orderIdStart - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, orderIdStart, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, orderIdStart, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 8 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on orderIdStart and orderIdEnd - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, orderIdStart, orderIdEnd+1, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, orderIdStart, orderIdEnd+1, timeStart, timeEnd, + false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 5 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on timeStart timeStart = time.Date(2013, 11, 8, 8, 0, 0, 0, time.UTC) - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 5 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Filter on timeStart and timeEnd timeEnd = time.Date(2013, 12, 1, 8, 0, 0, 0, time.UTC) - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 2 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } // Combined filter - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, nil, nil, []string{"rated"}, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, []string{"rated"}, nil, nil, nil, nil, nil, + nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 1 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) } + // Filter on ignoreDerived + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, true); err != nil { + t.Error(err.Error()) + } else if len(storedCdrs) != 2 { // ToDo: Recheck this value + t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) + } } func TestCallCost(t *testing.T) { @@ -440,10 +463,10 @@ func TestCallCost(t *testing.T) { }, }, } - if err := mysql.LogCallCost(cgrId, TEST_SQL, TEST_SQL, cc); err != nil { + if err := mysqlDb.LogCallCost(cgrId, TEST_SQL, TEST_SQL, cc); err != nil { t.Error(err.Error()) } - if ccRcv, err := mysql.GetCallCostLog(cgrId, TEST_SQL, TEST_SQL); err != nil { + if ccRcv, err := mysqlDb.GetCallCostLog(cgrId, TEST_SQL, TEST_SQL); err != nil { t.Error(err.Error()) } else if !reflect.DeepEqual(cc, ccRcv) { t.Errorf("Expecting call cost: %v, received: %v", cc, ccRcv) @@ -456,10 +479,10 @@ func TestRemStoredCdrs(t *testing.T) { } var timeStart, timeEnd time.Time cgrIdB1 := utils.Sha1("bbb1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()) - if err := mysql.RemStoredCdrs([]string{cgrIdB1}); err != nil { + if err := mysqlDb.RemStoredCdrs([]string{cgrIdB1}); err != nil { t.Error(err.Error()) } - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 7 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) @@ -476,11 +499,11 @@ func TestRemStoredCdrs(t *testing.T) { cgrIdA5 := utils.Sha1("aaa5", tm.String()) cgrIdB2 := utils.Sha1("bbb2", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()) cgrIdB3 := utils.Sha1("bbb3", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()) - if err := mysql.RemStoredCdrs([]string{cgrIdA1, cgrIdA2, cgrIdA3, cgrIdA4, cgrIdA5, + if err := mysqlDb.RemStoredCdrs([]string{cgrIdA1, cgrIdA2, cgrIdA3, cgrIdA4, cgrIdA5, cgrIdB2, cgrIdB3}); err != nil { t.Error(err.Error()) } - if storedCdrs, err := mysql.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false); err != nil { + if storedCdrs, err := mysqlDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, false, false, false); err != nil { t.Error(err.Error()) } else if len(storedCdrs) != 0 { t.Error("Unexpected number of StoredCdrs returned: ", storedCdrs) @@ -502,10 +525,10 @@ func TestSetGetTPActionTriggers(t *testing.T) { ActionsId: "LOG_BALANCE", } mpAtrgs := map[string][]*utils.TPActionTrigger{TEST_SQL: []*utils.TPActionTrigger{atrg}} - if err := mysql.SetTPActionTriggers(TEST_SQL+"1", mpAtrgs); err != nil { + if err := mysqlDb.SetTPActionTriggers(TEST_SQL+"1", mpAtrgs); err != nil { t.Error("Unexpected error: ", err.Error()) } - if rcvMpAtrgs, err := mysql.GetTpActionTriggers(TEST_SQL+"1", TEST_SQL); err != nil { + if rcvMpAtrgs, err := mysqlDb.GetTpActionTriggers(TEST_SQL+"1", TEST_SQL); err != nil { t.Error("Unexpected error: ", err.Error()) } else if !reflect.DeepEqual(mpAtrgs, rcvMpAtrgs) { t.Errorf("Expecting: %v, received: %v", mpAtrgs, rcvMpAtrgs) diff --git a/mediator/mediator.go b/mediator/mediator.go index 4ce3ac6b2..b068a4391 100644 --- a/mediator/mediator.go +++ b/mediator/mediator.go @@ -156,7 +156,7 @@ func (self *Mediator) RateCdr(storedCdr *utils.StoredCdr) error { } func (self *Mediator) RateCdrs(timeStart, timeEnd time.Time, rerateErrors, rerateRated bool) error { - cdrs, err := self.cdrDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, !rerateErrors, !rerateRated) + cdrs, err := self.cdrDb.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, timeStart, timeEnd, !rerateErrors, !rerateRated, true) if err != nil { return err } diff --git a/mediator/mediator_local_test.go b/mediator/mediator_local_test.go index 52deb09ad..475fa335d 100644 --- a/mediator/mediator_local_test.go +++ b/mediator/mediator_local_test.go @@ -150,12 +150,12 @@ func TestPostCdrs(t *testing.T) { } } time.Sleep(100 * time.Millisecond) // Give time for CDRs to reach database - if storedCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, false, false); err != nil { + if storedCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, false, false, false); err != nil { t.Error(err) } else if len(storedCdrs) != 4 { // Make sure CDRs made it into StorDb t.Error(fmt.Sprintf("Unexpected number of CDRs stored: %d", len(storedCdrs))) } - if nonErrorCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, true, false); err != nil { + if nonErrorCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, true, false, false); err != nil { t.Error(err) } else if len(nonErrorCdrs) != 0 { // Just two of them should be without errors t.Error(fmt.Sprintf("Unexpected number of CDRs stored: %d", len(nonErrorCdrs))) @@ -178,12 +178,12 @@ func TestInjectCdrs(t *testing.T) { t.Error(err) } } - if storedCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, false, false); err != nil { + if storedCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, false, false, false); err != nil { t.Error(err) } else if len(storedCdrs) != 6 { // Make sure CDRs made it into StorDb t.Error(fmt.Sprintf("Unexpected number of CDRs stored: %d", len(storedCdrs))) } - if nonRatedCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, true, true); err != nil { + if nonRatedCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, true, true, false); err != nil { t.Error(err) } else if len(nonRatedCdrs) != 2 { // Just two of them should be non-rated t.Error(fmt.Sprintf("Unexpected number of CDRs non-rated: %d", len(nonRatedCdrs))) @@ -215,12 +215,12 @@ func TestRateCdrs(t *testing.T) { } else if reply != utils.OK { t.Errorf("Unexpected reply: %s", reply) } - if nonRatedCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, true, true); err != nil { + if nonRatedCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, true, true, false); err != nil { t.Error(err) - } else if len(nonRatedCdrs) != 0 { // Just two of them should be non-rated + } else if len(nonRatedCdrs) != 0 { // All CDRs should be rated t.Error(fmt.Sprintf("Unexpected number of CDRs non-rated: %d", len(nonRatedCdrs))) } - if errRatedCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, false, true); err != nil { + if errRatedCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, false, true, false); err != nil { t.Error(err) } else if len(errRatedCdrs) != 4 { // The first 2 with errors should be still there before rerating t.Error(fmt.Sprintf("Unexpected number of CDRs with errors: %d", len(errRatedCdrs))) @@ -230,7 +230,7 @@ func TestRateCdrs(t *testing.T) { } else if reply != utils.OK { t.Errorf("Unexpected reply: %s", reply) } - if errRatedCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, false, true); err != nil { + if errRatedCdrs, err := cdrStor.GetStoredCdrs(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0, 0, time.Time{}, time.Time{}, false, true, false); err != nil { t.Error(err) } else if len(errRatedCdrs) != 2 { t.Error(fmt.Sprintf("Unexpected number of CDRs with errors: %d", len(errRatedCdrs))) diff --git a/utils/apitpdata.go b/utils/apitpdata.go index 2f00919d0..4424b9e58 100644 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -360,6 +360,27 @@ type ExportedFileCdrs struct { } +type AttrGetCdrs struct { + CgrIds []string // If provided, it will filter based on the cgrids present in list + MediationRunId []string // If provided, it will filter on mediation runid + TOR []string // If provided, filter on TypeOfRecord + CdrHost []string // If provided, it will filter cdrhost + CdrSource []string // If provided, it will filter cdrsource + ReqType []string // If provided, it will fiter reqtype + Direction []string // If provided, it will fiter direction + Tenant []string // If provided, it will filter tenant + Category []string // If provided, it will filter çategory + Account []string // If provided, it will filter account + Subject []string // If provided, it will filter the rating subject + DestinationPrefix []string // If provided, it will filter on destination prefix + OrderIdStart int64 // Export from this order identifier + OrderIdEnd int64 // Export smaller than this order identifier + TimeStart string // If provided, it will represent the starting of the CDRs interval (>=) + TimeEnd string // If provided, it will represent the end of the CDRs interval (<) + SkipErrors bool // Do not export errored CDRs + SkipRated bool // Do not export rated CDRs +} + type AttrRemCdrs struct { CgrIds []string // List of CgrIds to remove from storeDb } diff --git a/utils/consts.go b/utils/consts.go index 8aeed220b..c20cfa9ea 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -111,6 +111,10 @@ const ( DATA = "*data" VOICE = "*voice" TOR = "tor" + HOURS = "hours" + MINUTES = "minutes" + NANOSECONDS = "nanoseconds" + SECONDS = "seconds" ) var ( diff --git a/utils/coreutils.go b/utils/coreutils.go index 6d0b56fed..1a670a868 100644 --- a/utils/coreutils.go +++ b/utils/coreutils.go @@ -201,6 +201,13 @@ func ParseDurationWithSecs(durStr string) (time.Duration, error) { 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 BalanceKey(tenant, account, direction string) string { return fmt.Sprintf("%s:%s:%s", direction, tenant, account) } diff --git a/utils/storedcdr.go b/utils/storedcdr.go index f05db8226..eebf529ce 100644 --- a/utils/storedcdr.go +++ b/utils/storedcdr.go @@ -59,6 +59,19 @@ func (storedCdr *StoredCdr) FormatCost(shiftDecimals, roundDecimals int) string return strconv.FormatFloat(cost, 'f', roundDecimals, 64) } +func (storedCdr *StoredCdr) FormatDuration(layout string) string { + switch layout { + case HOURS: + return strconv.FormatFloat(storedCdr.Duration.Hours(), 'f', -1, 64) + case MINUTES: + return strconv.FormatFloat(storedCdr.Duration.Minutes(), 'f', -1, 64) + case SECONDS: + return strconv.FormatFloat(storedCdr.Duration.Seconds(), 'f', -1, 64) + default: + return strconv.FormatInt(storedCdr.Duration.Nanoseconds(), 10) + } +} + // Used to retrieve fields as string, primary fields are const labeled func (storedCdr *StoredCdr) FieldAsString(rsrFld *RSRField) string { switch rsrFld.Id { @@ -93,7 +106,7 @@ func (storedCdr *StoredCdr) FieldAsString(rsrFld *RSRField) string { case ANSWER_TIME: return rsrFld.ParseValue(storedCdr.AnswerTime.String()) case DURATION: - return rsrFld.ParseValue(strconv.FormatFloat(storedCdr.Duration.Seconds(), 'f', -1, 64)) + return rsrFld.ParseValue(strconv.FormatInt(storedCdr.Duration.Nanoseconds(), 10)) case MEDI_RUNID: return rsrFld.ParseValue(storedCdr.MediationRunId) case COST: @@ -126,7 +139,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(DURATION, strconv.FormatFloat(storedCdr.Duration.Seconds(), 'f', -1, 64)) + v.Set(DURATION, strconv.FormatInt(storedCdr.Duration.Nanoseconds(), 10)) return v } @@ -216,7 +229,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, DURATION, durationFld.Id)) - } else if frkStorCdr.Duration, err = ParseDurationWithSecs(durStr); err != nil { + } else if frkStorCdr.Duration, err = ParseDurationWithNanosecs(durStr); err != nil { return nil, err } frkStorCdr.ExtraFields = make(map[string]string, len(extraFlds)) diff --git a/utils/storedcdr_test.go b/utils/storedcdr_test.go index 11d43f2bb..774128e12 100644 --- a/utils/storedcdr_test.go +++ b/utils/storedcdr_test.go @@ -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: DURATION}) != "10" || + cdr.FieldAsString(&RSRField{Id: DURATION}) != "10000000000" || cdr.FieldAsString(&RSRField{Id: MEDI_RUNID}) != cdr.MediationRunId || cdr.FieldAsString(&RSRField{Id: COST}) != "1.01" || cdr.FieldAsString(&RSRField{Id: "field_extr1"}) != cdr.ExtraFields["field_extr1"] || @@ -69,7 +69,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: DURATION}) != "10", + cdr.FieldAsString(&RSRField{Id: DURATION}) != "10000000000", cdr.FieldAsString(&RSRField{Id: MEDI_RUNID}) != cdr.MediationRunId, cdr.FieldAsString(&RSRField{Id: COST}) != "1.01", cdr.FieldAsString(&RSRField{Id: "field_extr1"}) != cdr.ExtraFields["field_extr1"], @@ -98,6 +98,16 @@ func TestFormatCost(t *testing.T) { } } +func TestFormatDuration(t *testing.T) { + cdr := StoredCdr{Duration: time.Duration(10) * time.Second} + if cdr.FormatDuration(SECONDS) != "10" { + t.Error("Wrong duration format: ", cdr.FormatDuration(SECONDS)) + } + if cdr.FormatDuration("default") != "10000000000" { + t.Error("Wrong duration format: ", cdr.FormatDuration("default")) + } +} + func TestStoredCdrAsHttpForm(t *testing.T) { storCdr := StoredCdr{CgrId: Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: UNIT_TEST, ReqType: "rated", Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", @@ -144,8 +154,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(DURATION) != "10" { - t.Errorf("Expected: %s, received: %s", "10", cdrForm.Get(DURATION)) + if cdrForm.Get(DURATION) != "10000000000" { + t.Errorf("Expected: %s, received: %s", "10000000000", cdrForm.Get(DURATION)) } if cdrForm.Get("field_extr1") != "val_extr1" { t.Errorf("Expected: %s, received: %s", "val_extr1", cdrForm.Get("field_extr1")) diff --git a/utils/utils_test.go b/utils/utils_test.go index 9cc4d343c..df7737a82 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -375,6 +375,30 @@ 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")