From 73ee1b0dee59bff253520e2c3e850d60c4cf9b66 Mon Sep 17 00:00:00 2001 From: porosnicuadrian Date: Thu, 11 Mar 2021 13:58:42 +0200 Subject: [PATCH] New index update case for rate profile rate + tests --- engine/libindex.go | 49 ++++++++++++++++++ engine/z_filterindexer_it_test.go | 83 +++++++++++++++++++++++++++++-- 2 files changed, 127 insertions(+), 5 deletions(-) diff --git a/engine/libindex.go b/engine/libindex.go index f3a51436f..95cc1b16a 100644 --- a/engine/libindex.go +++ b/engine/libindex.go @@ -19,6 +19,7 @@ along with this program. If not, see package engine import ( + "errors" "fmt" "strings" @@ -752,6 +753,53 @@ func UpdateFilterIndex(dm *DataManager, oldFlt, newFlt *Filter) (err error) { }); err != nil && err != utils.ErrNotFound { return utils.APIErrorHandler(err) } + + case utils.CacheRateFilterIndexes: + itemIDs := make(map[string]utils.StringSet) + for itemID := range indx { + idSplit := strings.SplitN(itemID, utils.ConcatenatedKeySep, 2) + if len(idSplit) < 2 { + return errors.New("Expected to be 2 values") + } + if itemIDs[idSplit[1]] == nil { + itemIDs[idSplit[1]] = make(utils.StringSet) + } + itemIDs[idSplit[1]].Add(idSplit[0]) + } + for rpID, ids := range itemIDs { + tntCtx := utils.ConcatenatedKey(newFlt.Tenant, rpID) + if err = removeFilterIndexesForFilter(dm, idxItmType, tntCtx, + removeIndexKeys, ids); err != nil { + return + } + var rp *RateProfile + if rp, err = dm.GetRateProfile(newFlt.Tenant, rpID, true, false, utils.NonTransactional); err != nil { + return + } + for itemID := range ids { + rate, has := rp.Rates[itemID] + if !has { + return utils.ErrNotFound + } + refID := guardian.Guardian.GuardIDs(utils.EmptyString, + config.CgrConfig().GeneralCfg().LockingTimeout, idxItmType+tntCtx) + var updIdx map[string]utils.StringSet + if updIdx, err = newFilterIndex(dm, idxItmType, + newFlt.Tenant, rpID, itemID, rate.FilterIDs); err != nil { + guardian.Guardian.UnguardIDs(refID) + return + } + for _, idx := range updIdx { + idx.Add(itemID) + } + if err = dm.SetIndexes(idxItmType, tntCtx, + updIdx, false, utils.NonTransactional); err != nil { + guardian.Guardian.UnguardIDs(refID) + return + } + guardian.Guardian.UnguardIDs(refID) + } + } case utils.CacheAttributeFilterIndexes: for itemID := range indx { var ap *AttributeProfile @@ -843,6 +891,7 @@ func removeFilterIndexesForFilter(dm *DataManager, idxItmType, tnt string, for idx := range itemIDs { remIndx[idxKey].Remove(idx) } + if err = dm.SetIndexes(idxItmType, tnt, remIndx, true, utils.NonTransactional); err != nil { return } diff --git a/engine/z_filterindexer_it_test.go b/engine/z_filterindexer_it_test.go index 13a44bc5d..8d68ab8c4 100644 --- a/engine/z_filterindexer_it_test.go +++ b/engine/z_filterindexer_it_test.go @@ -2238,6 +2238,7 @@ func testITIndexRateProfileRateIndexes(t *testing.T) { t.Errorf("Expecting %+v, received: %+v", utils.ToJSON(eIdxes), utils.ToJSON(rcvIdx)) } } + // update the RateProfile by adding a new Rate rPrf = &RateProfile{ // recreate the profile because if we test on internal Tenant: "cgrates.org", // each update on the original item will update the item from DB @@ -2305,6 +2306,16 @@ func testITIndexRateProfileRateIndexes(t *testing.T) { t.Errorf("Expecting %+v, received: %+v", eIdxes, rcvIdx) } } + + //here we will set a filter + fltr := &Filter{ + Tenant: "cgrates.org", + ID: "FLTR", + Rules: []*FilterRule{{Type: utils.MetaString, Element: "Dan", Values: []string{"~*req.Account", "~*req.Destination", "DAN2"}}}, + } + if err := dataManager.SetFilter(fltr, true); err != nil { + t.Error(err) + } rPrf2 := &RateProfile{ Tenant: "cgrates.org", ID: "RP2", @@ -2317,7 +2328,7 @@ func testITIndexRateProfileRateIndexes(t *testing.T) { Rates: map[string]*Rate{ "CUSTOM_RATE1": { ID: "CUSTOM_RATE1", - FilterIDs: []string{"*string:~*req.Subject:1001"}, + FilterIDs: []string{"*string:~*req.Subject:1001", "FLTR"}, Weights: utils.DynamicWeights{ { Weight: 0, @@ -2348,16 +2359,78 @@ func testITIndexRateProfileRateIndexes(t *testing.T) { "*string:*req.Category:call": { "CUSTOM_RATE2": struct{}{}, }, + "*string:*req.Account:Dan": { + "CUSTOM_RATE1": struct{}{}, + }, + "*string:*req.Destination:Dan": { + "CUSTOM_RATE1": struct{}{}, + }, } if rcvIdx, err := dataManager.GetIndexes( utils.CacheRateFilterIndexes, "cgrates.org:RP2", utils.EmptyString, true, true); err != nil { t.Error(err) - } else { - if !reflect.DeepEqual(eIdxes, rcvIdx) { - t.Errorf("Expecting %+v, received: %+v", eIdxes, rcvIdx) - } + } else if !reflect.DeepEqual(eIdxes, rcvIdx) { + t.Errorf("Expecting %+v, received: %+v", eIdxes, rcvIdx) } + + //here we will check the reverse indexes + eIdxes = map[string]utils.StringSet{ + utils.CacheRateFilterIndexes: { + "CUSTOM_RATE1:RP2": struct{}{}, + }, + } + if rcvIdx, err := dataManager.GetIndexes( + utils.CacheReverseFilterIndexes, "cgrates.org:FLTR", + utils.EmptyString, true, true); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(eIdxes, rcvIdx) { + t.Errorf("Expecting %+v, received: %+v", utils.ToJSON(eIdxes), utils.ToJSON(rcvIdx)) + } + + //now we will update the filter + fltr = &Filter{ + Tenant: "cgrates.org", + ID: "FLTR", + Rules: []*FilterRule{{Type: utils.MetaString, Element: "10m", Values: []string{"~*req.Usage", "~*req.Debited", "DAN2"}}}, + } + if err := dataManager.SetFilter(fltr, true); err != nil { + t.Error(err) + } + + eIdxes = map[string]utils.StringSet{ + "*string:*req.Subject:1001": { + "CUSTOM_RATE1": struct{}{}, + "CUSTOM_RATE2": struct{}{}, + }, + "*string:*req.Category:call": { + "CUSTOM_RATE2": struct{}{}, + }, + "*string:*req.Usage:10m": { + "CUSTOM_RATE1": struct{}{}, + }, + "*string:*req.Debited:10m": { + "CUSTOM_RATE1": struct{}{}, + }, + } + if rcvIdx, err := dataManager.GetIndexes( + utils.CacheRateFilterIndexes, "cgrates.org:RP2", + utils.EmptyString, true, true); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(eIdxes, rcvIdx) { + t.Errorf("Expecting %+v, received: %+v", utils.ToJSON(eIdxes), utils.ToJSON(rcvIdx)) + } + + //invalid or inexisting tenant:context or index key + eIdxes = nil + if rcvIdx, err := dataManager.GetIndexes( + utils.CacheRateFilterIndexes, "cgrates.org:RP4", + utils.EmptyString, true, true); err == nil || err != utils.ErrNotFound { + t.Errorf("Expected %+v, received %+v", utils.ErrNotFound, err) + } else if !reflect.DeepEqual(eIdxes, rcvIdx) { + t.Errorf("Expecting %+v, received: %+v", utils.ToJSON(eIdxes), utils.ToJSON(rcvIdx)) + } + } func testITIndexRateProfileIndexes(t *testing.T) {