diff --git a/engine/filters.go b/engine/filters.go index e445f3d50..b4e88ca14 100644 --- a/engine/filters.go +++ b/engine/filters.go @@ -136,15 +136,15 @@ func (f *Filter) Compile() (err error) { } func NewRequestFilter(rfType, fieldName string, vals []string) (*RequestFilter, error) { - if !utils.IsSliceMember([]string{MetaStringPrefix, MetaTimings, MetaRSRFields, MetaStatS, MetaDestinations, + if !utils.IsSliceMember([]string{MetaString, MetaStringPrefix, MetaTimings, MetaRSRFields, MetaStatS, MetaDestinations, MetaLessThan, MetaLessOrEqual, MetaGreaterThan, MetaGreaterOrEqual}, rfType) { return nil, fmt.Errorf("Unsupported filter Type: %s", rfType) } - if fieldName == "" && utils.IsSliceMember([]string{MetaStringPrefix, MetaTimings, MetaDestinations, + if fieldName == "" && utils.IsSliceMember([]string{MetaString, MetaStringPrefix, MetaTimings, MetaDestinations, MetaLessThan, MetaLessOrEqual, MetaGreaterThan, MetaGreaterOrEqual}, rfType) { return nil, fmt.Errorf("FieldName is mandatory for Type: %s", rfType) } - if len(vals) == 0 && utils.IsSliceMember([]string{MetaStringPrefix, MetaTimings, MetaRSRFields, + if len(vals) == 0 && utils.IsSliceMember([]string{MetaString, MetaStringPrefix, MetaTimings, MetaRSRFields, MetaDestinations, MetaDestinations, MetaLessThan, MetaLessOrEqual, MetaGreaterThan, MetaGreaterOrEqual}, rfType) { return nil, fmt.Errorf("Values is mandatory for Type: %s", rfType) } diff --git a/engine/libsuppliers_test.go b/engine/libsuppliers_test.go index 9b433b102..c5a7637d1 100644 --- a/engine/libsuppliers_test.go +++ b/engine/libsuppliers_test.go @@ -20,11 +20,12 @@ package engine import ( "reflect" "testing" + "time" "github.com/cgrates/cgrates/utils" ) -func TestSortedSuppliersSortWeight(t *testing.T) { +func TestLibSuppliersSortCost(t *testing.T) { sSpls := &SortedSuppliers{ SortedSuppliers: []*SortedSupplier{ &SortedSupplier{ @@ -81,3 +82,156 @@ func TestSortedSuppliersSortWeight(t *testing.T) { utils.ToJSON(eOrderedSpls), utils.ToJSON(sSpls)) } } + +func TestLibSuppliersSortWeight(t *testing.T) { + spl := []*Supplier{ + &Supplier{ + ID: "supplier1", + FilterIDs: []string{}, + AccountIDs: []string{}, + RatingPlanIDs: []string{}, + ResourceIDs: []string{}, + StatIDs: []string{}, + Weight: 10.0, + }, + &Supplier{ + ID: "supplier2", + FilterIDs: []string{}, + AccountIDs: []string{}, + RatingPlanIDs: []string{}, + ResourceIDs: []string{}, + StatIDs: []string{}, + Weight: 20.0, + }, + } + eSpls := SortedSuppliers{ + ProfileID: "SPL_WEIGHT_1", + Sorting: utils.MetaWeight, + SortedSuppliers: []*SortedSupplier{ + &SortedSupplier{ + SupplierID: "supplier2", + SortingData: map[string]interface{}{ + "Weight": 20.0, + }, + }, + &SortedSupplier{ + SupplierID: "supplier1", + SortingData: map[string]interface{}{ + "Weight": 10.0, + }, + }, + }, + } + se := &SupplierEvent{ + Tenant: "cgrates.org", + ID: "supplierevent1", + Event: make(map[string]interface{}), + } + ws := NewWeightSorter() + result, err := ws.SortSuppliers("SPL_WEIGHT_1", spl, se) + if err != nil { + t.Error(err) + } + if !reflect.DeepEqual(eSpls.ProfileID, result.ProfileID) { + t.Errorf("Expecting: %+v, received: %+v", eSpls.ProfileID, result.ProfileID) + } else if !reflect.DeepEqual(eSpls.SortedSuppliers, result.SortedSuppliers) { + t.Errorf("Expecting: %+v, received: %+v", eSpls.SortedSuppliers, result.SortedSuppliers) + } else if !reflect.DeepEqual(eSpls.Sorting, result.Sorting) { + t.Errorf("Expecting: %+v, received: %+v", eSpls.Sorting, result.Sorting) + } + +} + +func TestLibSuppliersAnswerTime(t *testing.T) { + event := make(map[string]interface{}) + event[utils.ANSWER_TIME] = time.Now().Local() + se := &SupplierEvent{ + Tenant: "cgrates.org", + ID: "supplierevent1", + Event: event, + } + seErr := &SupplierEvent{ + Tenant: "cgrates.org", + ID: "supplierevent1", + Event: make(map[string]interface{}), + } + answ, err := se.AnswerTime("UTC") + if err != nil { + t.Error(err) + } + if answ != event[utils.ANSWER_TIME] { + t.Errorf("Expecting: %+v, received: %+v", event[utils.ANSWER_TIME], answ) + } + answ, err = seErr.AnswerTime("CET") + if err != utils.ErrNotFound { + t.Error(err) + } +} + +func TestLibSuppliersFieldAsString(t *testing.T) { + event := make(map[string]interface{}) + event["supplierprofile1"] = "Supplier" + event["UsageInterval"] = time.Duration(1 * time.Second) + event["PddInterval"] = "1s" + event["Weight"] = 20.0 + se := &SupplierEvent{ + Tenant: "cgrates.org", + ID: "supplierevent1", + Event: event, + } + answ, err := se.FieldAsString("UsageInterval") + if err != nil { + t.Error(err) + } + if answ != "1s" { + t.Errorf("Expecting: %+v, received: %+v", event["UsageInterval"], answ) + } + answ, err = se.FieldAsString("PddInterval") + if err != nil { + t.Error(err) + } + if answ != event["PddInterval"] { + t.Errorf("Expecting: %+v, received: %+v", event["PddInterval"], answ) + } + answ, err = se.FieldAsString("supplierprofile1") + if err != nil { + t.Error(err) + } + if answ != event["supplierprofile1"] { + t.Errorf("Expecting: %+v, received: %+v", event["supplierprofile1"], answ) + } + answ, err = se.FieldAsString("Weight") + if err != nil { + t.Error(err) + } + if answ != "20" { + t.Errorf("Expecting: %+v, received: %+v", event["Weight"], answ) + } + +} + +func TestLibSuppliersUsage(t *testing.T) { + event := make(map[string]interface{}) + event[utils.USAGE] = time.Duration(20 * time.Second) + se := &SupplierEvent{ + Tenant: "cgrates.org", + ID: "supplierevent1", + Event: event, + } + seErr := &SupplierEvent{ + Tenant: "cgrates.org", + ID: "supplierevent1", + Event: make(map[string]interface{}), + } + answ, err := se.Usage() + if err != nil { + t.Error(err) + } + if answ != event[utils.USAGE] { + t.Errorf("Expecting: %+v, received: %+v", event[utils.USAGE], answ) + } + answ, err = seErr.Usage() + if err != utils.ErrNotFound { + t.Error(err) + } +} diff --git a/engine/suppliers_test.go b/engine/suppliers_test.go new file mode 100644 index 000000000..65d19ac98 --- /dev/null +++ b/engine/suppliers_test.go @@ -0,0 +1,333 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ +package engine + +import ( + "reflect" + "testing" + "time" + + "github.com/cgrates/cgrates/config" + "github.com/cgrates/cgrates/utils" +) + +var ( + splserv SupplierService + sev *SupplierEvent + dmspl *DataManager + sprsmatch SupplierProfiles +) + +func TestSuppliersSort(t *testing.T) { + sprs := SupplierProfiles{ + &SupplierProfile{ + Tenant: "cgrates.org", + ID: "supplierprofile1", + FilterIDs: []string{}, + ActivationInterval: &utils.ActivationInterval{ + ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC).Local(), + ExpiryTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC).Local(), + }, + Sorting: "", + SortingParams: []string{}, + Suppliers: []*Supplier{ + &Supplier{ + ID: "supplier1", + FilterIDs: []string{}, + AccountIDs: []string{}, + RatingPlanIDs: []string{}, + ResourceIDs: []string{}, + StatIDs: []string{}, + Weight: 10.0, + }, + }, + Blocker: false, + Weight: 10, + }, + &SupplierProfile{ + Tenant: "cgrates.org", + ID: "supplierprofile2", + FilterIDs: []string{}, + ActivationInterval: &utils.ActivationInterval{ + ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC).Local(), + ExpiryTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC).Local(), + }, + Sorting: "", + SortingParams: []string{}, + Suppliers: []*Supplier{ + &Supplier{ + ID: "supplier1", + FilterIDs: []string{}, + AccountIDs: []string{}, + RatingPlanIDs: []string{}, + ResourceIDs: []string{}, + StatIDs: []string{}, + Weight: 20.0, + }, + }, + Blocker: false, + Weight: 20.0, + }, + } + eSupplierProfile := SupplierProfiles{ + &SupplierProfile{ + Tenant: "cgrates.org", + ID: "supplierprofile2", + FilterIDs: []string{}, + ActivationInterval: &utils.ActivationInterval{ + ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC).Local(), + ExpiryTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC).Local(), + }, + Sorting: "", + SortingParams: []string{}, + Suppliers: []*Supplier{ + &Supplier{ + ID: "supplier1", + FilterIDs: []string{}, + AccountIDs: []string{}, + RatingPlanIDs: []string{}, + ResourceIDs: []string{}, + StatIDs: []string{}, + Weight: 20.0, + }, + }, + Blocker: false, + Weight: 20.0, + }, + &SupplierProfile{ + Tenant: "cgrates.org", + ID: "supplierprofile1", + FilterIDs: []string{}, + ActivationInterval: &utils.ActivationInterval{ + ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC).Local(), + ExpiryTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC).Local(), + }, + Sorting: "", + SortingParams: []string{}, + Suppliers: []*Supplier{ + &Supplier{ + ID: "supplier1", + FilterIDs: []string{}, + AccountIDs: []string{}, + RatingPlanIDs: []string{}, + ResourceIDs: []string{}, + StatIDs: []string{}, + Weight: 10.0, + }, + }, + Blocker: false, + Weight: 10.0, + }, + } + sprs.Sort() + if !reflect.DeepEqual(eSupplierProfile, sprs) { + t.Errorf("Expecting: %+v, received: %+v", eSupplierProfile, sprs) + } +} + +func TestSuppliersPopulateSupplierService(t *testing.T) { + data, _ := NewMapStorage() + dmspl = NewDataManager(data) + var filters1 []*RequestFilter + var filters2 []*RequestFilter + second := 1 * time.Second + x, err := NewRequestFilter(MetaString, "supplierprofile1", []string{"Supplier"}) + if err != nil { + t.Errorf("Error: %+v", err) + } + filters1 = append(filters1, x) + x, err = NewRequestFilter(MetaGreaterOrEqual, "UsageInterval", []string{second.String()}) + if err != nil { + t.Errorf("Error: %+v", err) + } + filters1 = append(filters1, x) + x, err = NewRequestFilter(MetaGreaterOrEqual, "Weight", []string{"9.0"}) + if err != nil { + t.Errorf("Error: %+v", err) + } + filters1 = append(filters1, x) + x, err = NewRequestFilter(MetaString, "supplierprofile2", []string{"Supplier"}) + if err != nil { + t.Errorf("Error: %+v", err) + } + filters2 = append(filters2, x) + x, err = NewRequestFilter(MetaGreaterOrEqual, "PddInterval", []string{second.String()}) + if err != nil { + t.Errorf("Error: %+v", err) + } + filters2 = append(filters2, x) + x, err = NewRequestFilter(MetaGreaterOrEqual, "Weight", []string{"15.0"}) + if err != nil { + t.Errorf("Error: %+v", err) + } + filters2 = append(filters2, x) + filter1 := &Filter{Tenant: config.CgrConfig().DefaultTenant, ID: "filter1", RequestFilters: filters1} + filter2 := &Filter{Tenant: config.CgrConfig().DefaultTenant, ID: "filter2", RequestFilters: filters2} + dmspl.SetFilter(filter1) + dmspl.SetFilter(filter2) + + ssd := make(map[string]SuppliersSorter) + ssd[utils.MetaWeight] = NewWeightSorter() + splserv = SupplierService{ + dm: dmspl, + filterS: &FilterS{dm: dmspl}, + indexedFields: []string{"supplierprofile1", "supplierprofile2"}, + sorter: ssd, + } + ssd[utils.MetaLeastCost] = NewLeastCostSorter(&splserv) + ev := make(map[string]interface{}) + ev["supplierprofile1"] = "Supplier" + ev["supplierprofile2"] = "Supplier" + ev[utils.ANSWER_TIME] = time.Date(2014, 7, 14, 14, 30, 0, 0, time.UTC).Local() + ev["UsageInterval"] = "1s" + ev["PddInterval"] = "1s" + ev["Weight"] = "20.0" + sev = &SupplierEvent{ + Tenant: "cgrates.org", + ID: "supplierevent1", + Event: ev, + } + sprsmatch = SupplierProfiles{ + &SupplierProfile{ + Tenant: "cgrates.org", + ID: "supplierprofile1", + FilterIDs: []string{"filter1"}, + ActivationInterval: &utils.ActivationInterval{ + ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC).Local(), + ExpiryTime: time.Now().Add(time.Duration(20 * time.Minute)).Local(), + }, + Sorting: utils.MetaWeight, + SortingParams: []string{}, + Suppliers: []*Supplier{ + &Supplier{ + ID: "supplier1", + FilterIDs: []string{"filter1"}, + AccountIDs: []string{}, + RatingPlanIDs: []string{}, + ResourceIDs: []string{}, + StatIDs: []string{}, + Weight: 10.0, + }, + }, + Blocker: false, + Weight: 10, + }, + &SupplierProfile{ + Tenant: "cgrates.org", + ID: "supplierprofile2", + FilterIDs: []string{"filter2"}, + ActivationInterval: &utils.ActivationInterval{ + ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC).Local(), + ExpiryTime: time.Now().Add(time.Duration(20 * time.Minute)).Local(), + }, + Sorting: utils.MetaWeight, + SortingParams: []string{}, + Suppliers: []*Supplier{ + &Supplier{ + ID: "supplier2", + FilterIDs: []string{"filter2"}, + AccountIDs: []string{}, + RatingPlanIDs: []string{}, + ResourceIDs: []string{}, + StatIDs: []string{}, + Weight: 20.0, + }, + &Supplier{ + ID: "supplier3", + FilterIDs: []string{"filter2"}, + AccountIDs: []string{}, + RatingPlanIDs: []string{}, + ResourceIDs: []string{}, + StatIDs: []string{}, + Weight: 10.0, + }, + &Supplier{ + ID: "supplier1", + FilterIDs: []string{"filter2"}, + AccountIDs: []string{}, + RatingPlanIDs: []string{}, + ResourceIDs: []string{}, + StatIDs: []string{}, + Weight: 30.0, + }, + }, + Blocker: false, + Weight: 20.0, + }, + } + for _, spr := range sprsmatch { + dmspl.DataDB().SetSupplierProfileDrv(spr) + } + ref, err := NewReqFilterIndexer(dmspl, utils.SupplierProfilesStringIndex+"cgrates.org") + if err != nil { + t.Errorf("Error: %+v", err) + } + ref.IndexFilters("supplierprofile1", filters1) + ref.IndexFilters("supplierprofile2", filters2) + err = ref.StoreIndexes() + if err != nil { + t.Errorf("Error: %+v", err) + } + +} + +func TestSuppliersmatchingSupplierProfilesForEvent(t *testing.T) { + sprf, err := splserv.matchingSupplierProfilesForEvent(sev) + if err != nil { + t.Errorf("Error: %+v", err) + } + if !reflect.DeepEqual(sprsmatch[1], sprf[0]) { + t.Errorf("Expecting: %+v, received: %+v", sprsmatch[1], sprf[0]) + } else if !reflect.DeepEqual(sprsmatch[0], sprf[1]) { + t.Errorf("Expecting: %+v, received: %+v", sprsmatch[0], sprf[1]) + } +} + +func TestSuppliersSortedForEvent(t *testing.T) { + eFirstSupplierProfile := &SortedSuppliers{ + ProfileID: "supplierprofile2", + Sorting: utils.MetaWeight, + SortedSuppliers: []*SortedSupplier{ + &SortedSupplier{ + SupplierID: "supplier1", + SortingData: map[string]interface{}{ + "Weight": 30.0, + }, + }, + &SortedSupplier{ + SupplierID: "supplier2", + SortingData: map[string]interface{}{ + "Weight": 20.0, + }, + }, + &SortedSupplier{ + SupplierID: "supplier3", + SortingData: map[string]interface{}{ + "Weight": 10.0, + }, + }, + }, + } + sprf, err := splserv.sortedSuppliersForEvent(sev) + if err != nil { + t.Errorf("Error: %+v", err) + } + if !reflect.DeepEqual(eFirstSupplierProfile, sprf) { + t.Errorf("Expecting: %+v, received: %+v", eFirstSupplierProfile, sprf) + } +}