From ee53a1b3de73417d11201dce5be595fcedb51e4a Mon Sep 17 00:00:00 2001 From: DanB Date: Sun, 27 Mar 2016 20:45:23 +0200 Subject: [PATCH] Storage.GetSMCost -> Storage.GetSMCosts, prefix match for OriginID when querying --- apier/v1/apier_local_test.go | 2 +- apier/v1/cdrs.go | 6 ++--- cdre/cdrexporter.go | 6 ++--- engine/cdrs.go | 14 +++++------ engine/storage_cdrs_it_test.go | 23 ++++++++++++++---- engine/storage_interface.go | 2 +- engine/storage_mongo_stordb.go | 20 ++++++++++------ engine/storage_sql.go | 44 +++++++++++++++++++--------------- 8 files changed, 72 insertions(+), 45 deletions(-) diff --git a/apier/v1/apier_local_test.go b/apier/v1/apier_local_test.go index 88ad8c819..3f8a03b7a 100644 --- a/apier/v1/apier_local_test.go +++ b/apier/v1/apier_local_test.go @@ -1359,7 +1359,7 @@ func TestApierGetCallCostLog(t *testing.T) { } attrs.CgrId = "dummyid" attrs.RunId = "default" - if err := rater.Call("ApierV1.GetCallCostLog", attrs, &cc); err == nil || err.Error() != "SERVER_ERROR: record not found" { + if err := rater.Call("ApierV1.GetCallCostLog", attrs, &cc); err == nil || err.Error() != utils.ErrNotFound.Error() { t.Error("ApierV1.GetCallCostLog: should return NOT_FOUND, got:", err) } } diff --git a/apier/v1/cdrs.go b/apier/v1/cdrs.go index b8fc0deec..4e87a2120 100644 --- a/apier/v1/cdrs.go +++ b/apier/v1/cdrs.go @@ -33,12 +33,12 @@ func (apier *ApierV1) GetCallCostLog(attrs utils.AttrGetCallCost, reply *engine. if attrs.RunId == "" { attrs.RunId = utils.META_DEFAULT } - if smc, err := apier.CdrDb.GetSMCost(attrs.CgrId, attrs.RunId, "", ""); err != nil { + if smcs, err := apier.CdrDb.GetSMCosts(attrs.CgrId, attrs.RunId, "", ""); err != nil { return utils.NewErrServerError(err) - } else if smc == nil { + } else if len(smcs) == 0 { return utils.ErrNotFound } else { - *reply = *smc + *reply = *smcs[0] } return nil } diff --git a/cdre/cdrexporter.go b/cdre/cdrexporter.go index 112f135fd..e90b88e03 100644 --- a/cdre/cdrexporter.go +++ b/cdre/cdrexporter.go @@ -116,13 +116,13 @@ type CdrExporter struct { // Return Json marshaled callCost attached to // Keep it separately so we test only this part in local tests func (cdre *CdrExporter) getCdrCostDetails(CGRID, runId string) (string, error) { - cc, err := cdre.cdrDb.GetSMCost(CGRID, runId, "", "") + smcs, err := cdre.cdrDb.GetSMCosts(CGRID, runId, "", "") if err != nil { return "", err - } else if cc == nil { + } else if len(smcs) == 0 { return "", nil } - ccJson, _ := json.Marshal(cc) + ccJson, _ := json.Marshal(smcs[0].CostDetails) return string(ccJson), nil } diff --git a/engine/cdrs.go b/engine/cdrs.go index babf82f2c..1b2d2e563 100644 --- a/engine/cdrs.go +++ b/engine/cdrs.go @@ -117,11 +117,11 @@ func (self *CdrServer) StoreSMCost(smCost *SMCost, checkDuplicate bool) error { } if checkDuplicate { _, err := self.guard.Guard(func() (interface{}, error) { - cc, err := self.cdrDb.GetSMCost(smCost.CGRID, smCost.RunID, "", "") - if err != nil && err != gorm.RecordNotFound && err != mgov2.ErrNotFound { + smCosts, err := self.cdrDb.GetSMCosts(smCost.CGRID, smCost.RunID, "", "") + if err != nil { return nil, err } - if cc != nil { + if len(smCosts) != 0 { return nil, utils.ErrExists } return nil, self.cdrDb.SetSMCost(smCost) @@ -343,10 +343,10 @@ func (self *CdrServer) rateCDR(cdr *CDR) error { delay := utils.Fib() var usage float64 for i := 0; i < 4; i++ { - qrySMC, err := self.cdrDb.GetSMCost(cdr.CGRID, cdr.RunID, cdr.OriginHost, cdr.ExtraFields[utils.OriginIDPrefix]) - if err == nil { - qryCC = qrySMC.CostDetails - usage = qrySMC.Usage + smCosts, err := self.cdrDb.GetSMCosts(cdr.CGRID, cdr.RunID, cdr.OriginHost, cdr.ExtraFields[utils.OriginIDPrefix]) + if err == nil && len(smCosts) != 0 { + qryCC = smCosts[0].CostDetails + usage = smCosts[0].Usage break } time.Sleep(delay()) diff --git a/engine/storage_cdrs_it_test.go b/engine/storage_cdrs_it_test.go index 5e23e7976..656098885 100644 --- a/engine/storage_cdrs_it_test.go +++ b/engine/storage_cdrs_it_test.go @@ -19,10 +19,11 @@ along with this program. If not, see package engine import ( + "errors" "flag" "fmt" "path" - //"reflect" + "strconv" "testing" "time" @@ -226,10 +227,24 @@ func testSMCosts(cfg *config.CGRConfig) error { CostSource: utils.UNIT_TEST, CostDetails: cc}); err != nil { return err } - if rcvSMC, err := cdrStorage.GetSMCost("164b0422fdc6a5117031b427439482c6a4f90e41", utils.META_DEFAULT, "", ""); err != nil { + if rcvSMC, err := cdrStorage.GetSMCosts("164b0422fdc6a5117031b427439482c6a4f90e41", utils.META_DEFAULT, "", ""); err != nil { return err - } else if len(cc.Timespans) != len(rcvSMC.CostDetails.Timespans) { // cc.Timespans[0].RateInterval.Rating.Rates[0], rcvCC.Timespans[0].RateInterval.Rating.Rates[0]) - return fmt.Errorf("Expecting: %+v, received: %+s", cc, utils.ToIJSON(rcvSMC)) + } else if len(rcvSMC) == 0 { + return errors.New("No SMCosts received") + } else if len(cc.Timespans) != len(rcvSMC[0].CostDetails.Timespans) { // cc.Timespans[0].RateInterval.Rating.Rates[0], rcvCC.Timespans[0].RateInterval.Rating.Rates[0]) + return fmt.Errorf("Expecting: %+v, received: %+s", cc, utils.ToIJSON(rcvSMC[0])) + } + // Test query per prefix + for i := 0; i < 3; i++ { + if err := cdrStorage.SetSMCost(&SMCost{CGRID: "164b0422fdc6a5117031b427439482c6a4f90e5" + strconv.Itoa(i), RunID: utils.META_DEFAULT, OriginHost: "localhost", OriginID: "abc" + strconv.Itoa(i), + CostSource: utils.UNIT_TEST, CostDetails: cc}); err != nil { + return err + } + } + if rcvSMC, err := cdrStorage.GetSMCosts("", utils.META_DEFAULT, "localhost", "abc"); err != nil { + return err + } else if len(rcvSMC) != 3 { + return fmt.Errorf("Expecting 3, received: %d", len(rcvSMC)) } return nil } diff --git a/engine/storage_interface.go b/engine/storage_interface.go index 53f990880..c2123970e 100644 --- a/engine/storage_interface.go +++ b/engine/storage_interface.go @@ -98,7 +98,7 @@ type CdrStorage interface { Storage SetCDR(*CDR, bool) error SetSMCost(smc *SMCost) error - GetSMCost(cgrid, runid, originHost, originIDPrfx string) (*SMCost, error) + GetSMCosts(cgrid, runid, originHost, originIDPrfx string) ([]*SMCost, error) GetCDRs(*utils.CDRsFilter, bool) ([]*CDR, int64, error) } diff --git a/engine/storage_mongo_stordb.go b/engine/storage_mongo_stordb.go index c6c557862..4edd9ae8e 100644 --- a/engine/storage_mongo_stordb.go +++ b/engine/storage_mongo_stordb.go @@ -1,6 +1,7 @@ package engine import ( + "fmt" "regexp" "strings" "time" @@ -702,16 +703,21 @@ func (ms *MongoStorage) SetSMCost(smc *SMCost) error { return ms.db.C(utils.TBLSMCosts).Insert(smc) } -func (ms *MongoStorage) GetSMCost(cgrid, runid, originHost, originIDPrefix string) (smc *SMCost, err error) { - var result SMCost +func (ms *MongoStorage) GetSMCosts(cgrid, runid, originHost, originIDPrefix string) (smcs []*SMCost, err error) { + filter := bson.M{CGRIDLow: cgrid, RunIDLow: runid} if originIDPrefix != "" { - if err = ms.db.C(utils.TBLSMCosts).Find(bson.M{OriginHostLow: originHost, OriginIDLow: originIDPrefix, RunIDLow: runid}).One(&result); err != nil { // FixMe for prefix - return nil, err - } - } else if err = ms.db.C(utils.TBLSMCosts).Find(bson.M{CGRIDLow: cgrid, RunIDLow: runid}).One(&result); err != nil { + filter = bson.M{OriginIDLow: bson.M{"$regex": bson.RegEx{Pattern: fmt.Sprintf("^%s", originIDPrefix)}}, OriginHostLow: originHost, RunIDLow: runid} + } + // Execute query + iter := ms.db.C(utils.TBLSMCosts).Find(filter).Iter() + var smCost SMCost + for iter.Next(&smCost) { + smcs = append(smcs, &smCost) + } + if err := iter.Err(); err != nil { return nil, err } - return &result, nil + return smcs, nil } func (ms *MongoStorage) SetCDR(cdr *CDR, allowUpdate bool) (err error) { diff --git a/engine/storage_sql.go b/engine/storage_sql.go index 40b316cf4..365211043 100644 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -597,29 +597,35 @@ func (self *SQLStorage) SetSMCost(smc *SMCost) error { return nil } -func (self *SQLStorage) GetSMCost(cgrid, runid, originHost, originIDPrefix string) (*SMCost, error) { - var tpCostDetail TBLSMCosts +// GetSMCosts is used to retrieve one or multiple SMCosts based on filter +func (self *SQLStorage) GetSMCosts(cgrid, runid, originHost, originIDPrefix string) ([]*SMCost, error) { + var smCosts []*SMCost + q := self.db.Where(&TBLSMCosts{Cgrid: cgrid, RunID: runid}) if originIDPrefix != "" { - if err := self.db.Where(&TBLSMCosts{OriginHost: originHost, OriginID: originIDPrefix, RunID: runid}).First(&tpCostDetail).Error; err != nil { // FixMe with originPrefix + q = self.db.Where(&TBLSMCosts{OriginHost: originHost, RunID: runid}).Where(fmt.Sprintf("origin_id LIKE '%s%%'", originIDPrefix)) + } + results := make([]*TBLSMCosts, 0) + if err := q.Find(&results).Error; err != nil { + return nil, err + } + for _, result := range results { + if len(result.CostDetails) == 0 { + continue + } + smc := &SMCost{ + CGRID: result.Cgrid, + RunID: result.RunID, + CostSource: result.CostSource, + Usage: result.Usage, + CostDetails: &CallCost{}, + } + if err := json.Unmarshal([]byte(result.CostDetails), smc.CostDetails); err != nil { return nil, err } - } else if err := self.db.Where(&TBLSMCosts{Cgrid: cgrid, RunID: runid}).First(&tpCostDetail).Error; err != nil { - return nil, err + smCosts = append(smCosts, smc) } - if len(tpCostDetail.CostDetails) == 0 { - return nil, nil // No costs returned - } - smc := &SMCost{ - CGRID: tpCostDetail.Cgrid, - RunID: tpCostDetail.RunID, - CostSource: tpCostDetail.CostSource, - Usage: tpCostDetail.Usage, - CostDetails: &CallCost{}, - } - if err := json.Unmarshal([]byte(tpCostDetail.CostDetails), smc.CostDetails); err != nil { - return nil, err - } - return smc, nil + + return smCosts, nil } func (self *SQLStorage) LogActionTrigger(ubId, source string, at *ActionTrigger, as Actions) (err error) {