Added tests for resources

This commit is contained in:
Trial97
2021-07-20 15:54:13 +03:00
committed by Dan Christian Bogos
parent 317586873d
commit b0c6e59740
2 changed files with 442 additions and 217 deletions

View File

@@ -121,16 +121,15 @@ func (ru *ResourceUsage) Clone() (cln *ResourceUsage) {
// Resource represents a resource in the system
// not thread safe, needs locking at process level
type Resource struct {
Tenant string
ID string
Usages map[string]*ResourceUsage
TTLIdx []string // holds ordered list of ResourceIDs based on their TTL, empty if feature is disableda
lkID string // ID of the lock used when matching the resource
prflLkID string // ID of the lock used for the profile
ttl *time.Duration // time to leave for this resource, picked up on each Resource initialization out of config
tUsage *float64 // sum of all usages
dirty *bool // the usages were modified, needs save, *bool so we only save if enabled in config
rPrf *ResourceProfile // for ordering purposes
Tenant string
ID string
Usages map[string]*ResourceUsage
TTLIdx []string // holds ordered list of ResourceIDs based on their TTL, empty if feature is disableda
lkID string // ID of the lock used when matching the resource
ttl *time.Duration // time to leave for this resource, picked up on each Resource initialization out of config
tUsage *float64 // sum of all usages
dirty *bool // the usages were modified, needs save, *bool so we only save if enabled in config
rPrf *ResourceProfile // for ordering purposes
}
// resourceLockKey returns the ID used to lock a resource with guardian
@@ -362,14 +361,9 @@ func (rs Resources) allocateResource(ru *ResourceUsage, dryRun bool) (alcMessage
err = fmt.Errorf("empty configuration for resourceID: %s", r.TenantID())
return
}
if r.rPrf.Limit >= r.TotalUsage()+ru.Units || r.rPrf.Limit == -1 {
if alcMessage == "" {
if r.rPrf.AllocationMessage != "" {
alcMessage = r.rPrf.AllocationMessage
} else {
alcMessage = r.rPrf.ID
}
}
if alcMessage == utils.EmptyString &&
(r.rPrf.Limit >= r.TotalUsage()+ru.Units || r.rPrf.Limit == -1) {
alcMessage = utils.FirstNonEmpty(r.rPrf.AllocationMessage, r.rPrf.ID)
}
}
if alcMessage == "" {
@@ -493,6 +487,31 @@ func (rS *ResourceService) storeResource(r *Resource) (err error) {
return
}
// storeMatchedResources will store the list of resources based on the StoreInterval
func (rS *ResourceService) storeMatchedResources(mtcRLs Resources) (err error) {
if rS.cgrcfg.ResourceSCfg().StoreInterval == 0 {
return
}
if rS.cgrcfg.ResourceSCfg().StoreInterval > 0 {
rS.srMux.Lock()
defer rS.srMux.Unlock()
}
for _, r := range mtcRLs {
if r.dirty != nil {
*r.dirty = true // mark it to be saved
if rS.cgrcfg.ResourceSCfg().StoreInterval > 0 {
rS.storedResources.Add(r.TenantID())
continue
}
if err = rS.storeResource(r); err != nil {
return
}
}
}
return
}
// processThresholds will pass the event for resource to ThresholdS
func (rS *ResourceService) processThresholds(rs Resources, opts map[string]interface{}) (err error) {
if len(rS.cgrcfg.ResourceSCfg().ThresholdSConns) == 0 {
@@ -545,7 +564,6 @@ func (rS *ResourceService) processThresholds(rs Resources, opts map[string]inter
// matchingResourcesForEvent returns ordered list of matching resources which are active by the time of the call
func (rS *ResourceService) matchingResourcesForEvent(tnt string, ev *utils.CGREvent,
evUUID string, usageTTL *time.Duration) (rs Resources, err error) {
matchingResources := make(map[string]*Resource)
var rIDs utils.StringSet
evNm := utils.MapStorage{
utils.MetaReq: ev.Event,
@@ -583,6 +601,7 @@ func (rS *ResourceService) matchingResourcesForEvent(tnt string, ev *utils.CGREv
return
}
}
rs = make(Resources, 0, len(rIDs))
for resName := range rIDs {
lkPrflID := guardian.Guardian.GuardIDs("",
config.CgrConfig().GeneralCfg().LockingTimeout,
@@ -594,6 +613,7 @@ func (rS *ResourceService) matchingResourcesForEvent(tnt string, ev *utils.CGREv
if err == utils.ErrNotFound {
continue
}
rs.unlock()
return
}
rPrf.lock(lkPrflID)
@@ -605,6 +625,7 @@ func (rS *ResourceService) matchingResourcesForEvent(tnt string, ev *utils.CGREv
if pass, err := rS.filterS.Pass(tnt, rPrf.FilterIDs,
evNm); err != nil {
rPrf.unlock()
rs.unlock()
return nil, err
} else if !pass {
rPrf.unlock()
@@ -616,7 +637,8 @@ func (rS *ResourceService) matchingResourcesForEvent(tnt string, ev *utils.CGREv
r, err := rS.dm.GetResource(rPrf.Tenant, rPrf.ID, true, true, "")
if err != nil {
guardian.Guardian.UnguardIDs(lkID)
guardian.Guardian.UnguardIDs(lkPrflID)
rPrf.unlock()
rs.unlock()
return nil, err
}
r.lock(lkID) // pass the lock into resource so we have it as reference
@@ -631,17 +653,12 @@ func (rS *ResourceService) matchingResourcesForEvent(tnt string, ev *utils.CGREv
r.ttl = utils.DurationPointer(rPrf.UsageTTL)
}
r.rPrf = rPrf
matchingResources[rPrf.ID] = r
rs = append(rs, r)
}
if len(matchingResources) == 0 {
if len(rs) == 0 {
return nil, utils.ErrNotFound
}
// All good, convert from Map to Slice so we can sort
rs = make(Resources, 0, len(matchingResources))
for _, r := range matchingResources {
rs = append(rs, r)
}
rs.Sort()
for i, r := range rs {
if r.rPrf.Blocker && i != len(rs)-1 { // blocker will stop processing and we are not at last index
@@ -803,21 +820,8 @@ func (rS *ResourceService) V1AllocateResources(args utils.ArgRSv1ResourceUsage,
}
// index it for storing
for _, r := range mtcRLs {
if rS.cgrcfg.ResourceSCfg().StoreInterval != 0 && r.dirty != nil {
if rS.cgrcfg.ResourceSCfg().StoreInterval == -1 {
*r.dirty = true
if err = rS.storeResource(r); err != nil {
return
}
} else {
*r.dirty = true // mark it to be saved
rS.srMux.Lock()
rS.storedResources.Add(r.TenantID())
rS.srMux.Unlock()
}
}
if err = rS.storeMatchedResources(mtcRLs); err != nil {
return
}
if err = rS.processThresholds(mtcRLs, args.APIOpts); err != nil {
return
@@ -863,7 +867,7 @@ func (rS *ResourceService) V1ReleaseResources(args utils.ArgRSv1ResourceUsage, r
var mtcRLs Resources
if mtcRLs, err = rS.matchingResourcesForEvent(tnt, args.CGREvent, args.UsageID,
args.UsageTTL); err != nil {
return err
return
}
defer mtcRLs.unlock()
@@ -872,24 +876,9 @@ func (rS *ResourceService) V1ReleaseResources(args utils.ArgRSv1ResourceUsage, r
}
// Handle storing
if rS.cgrcfg.ResourceSCfg().StoreInterval != -1 {
rS.srMux.Lock()
defer rS.srMux.Unlock()
if err = rS.storeMatchedResources(mtcRLs); err != nil {
return
}
for _, r := range mtcRLs {
if r.dirty != nil {
if rS.cgrcfg.ResourceSCfg().StoreInterval == -1 {
if err = rS.storeResource(r); err != nil {
return
}
} else {
*r.dirty = true // mark it to be saved
rS.storedResources.Add(r.TenantID())
}
}
}
if err = rS.processThresholds(mtcRLs, args.APIOpts); err != nil {
return
}

View File

@@ -2617,166 +2617,18 @@ func TestResourceMatchWithIndexFalse(t *testing.T) {
}
func TestResourceCaching(t *testing.T) {
var dmRES *DataManager
defaultCfg := config.NewDefaultCGRConfig()
data := NewInternalDB(nil, nil, true)
dmRES = NewDataManager(data, config.CgrConfig().CacheCfg(), nil)
defaultCfg.ResourceSCfg().StoreInterval = 1
defaultCfg.ResourceSCfg().StringIndexedFields = nil
defaultCfg.ResourceSCfg().PrefixIndexedFields = nil
resService := NewResourceService(dmRES, defaultCfg,
&FilterS{dm: dmRES, cfg: defaultCfg}, nil)
if err != nil {
t.Errorf("Error: %+v", err)
}
fltrRes1 := &Filter{
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
ID: "FLTR_RES_1",
Rules: []*FilterRule{
{
Type: utils.MetaString,
Element: "~*req.Resources",
Values: []string{"ResourceProfile1"},
},
{
Type: utils.MetaGreaterOrEqual,
Element: "~*req.UsageInterval",
Values: []string{(time.Second).String()},
},
{
Type: utils.MetaGreaterOrEqual,
Element: utils.DynamicDataPrefix + utils.MetaReq + utils.NestingSep + utils.Usage,
Values: []string{(time.Second).String()},
},
{
Type: utils.MetaGreaterOrEqual,
Element: utils.DynamicDataPrefix + utils.MetaReq + utils.NestingSep + utils.Weight,
Values: []string{"9.0"},
},
},
}
dmRES.SetFilter(fltrRes1, true)
fltrRes2 := &Filter{
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
ID: "FLTR_RES_2",
Rules: []*FilterRule{
{
Type: utils.MetaString,
Element: "~*req.Resources",
Values: []string{"ResourceProfile2"},
},
{
Type: utils.MetaGreaterOrEqual,
Element: "~*req.PddInterval",
Values: []string{(time.Second).String()},
},
{
Type: utils.MetaGreaterOrEqual,
Element: utils.DynamicDataPrefix + utils.MetaReq + utils.NestingSep + utils.Usage,
Values: []string{(time.Second).String()},
},
{
Type: utils.MetaGreaterOrEqual,
Element: utils.DynamicDataPrefix + utils.MetaReq + utils.NestingSep + utils.Weight,
Values: []string{"15.0"},
},
},
}
dmRES.SetFilter(fltrRes2, true)
fltrRes3 := &Filter{
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
ID: "FLTR_RES_3",
Rules: []*FilterRule{
{
Type: utils.MetaPrefix,
Element: "~*req.Resources",
Values: []string{"ResourceProfilePrefix"},
},
},
}
dmRES.SetFilter(fltrRes3, true)
resprf := []*ResourceProfile{
{
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
ID: "ResourceProfile1",
FilterIDs: []string{"FLTR_RES_1"},
ActivationInterval: &utils.ActivationInterval{
ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC),
},
UsageTTL: 10 * time.Second,
Limit: 10.00,
AllocationMessage: "AllocationMessage",
Weight: 20.00,
ThresholdIDs: []string{""},
},
{
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
ID: "ResourceProfile2", // identifier of this resource
FilterIDs: []string{"FLTR_RES_2"},
ActivationInterval: &utils.ActivationInterval{
ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC),
},
UsageTTL: 10 * time.Second,
Limit: 10.00,
AllocationMessage: "AllocationMessage",
Weight: 20.00,
ThresholdIDs: []string{""},
},
{
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
ID: "ResourceProfile3",
FilterIDs: []string{"FLTR_RES_3"},
ActivationInterval: &utils.ActivationInterval{
ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC),
},
UsageTTL: 10 * time.Second,
Limit: 10.00,
AllocationMessage: "AllocationMessage",
Weight: 20.00,
ThresholdIDs: []string{""},
},
}
resourceTest := Resources{
{
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
ID: "ResourceProfile1",
Usages: map[string]*ResourceUsage{},
TTLIdx: []string{},
rPrf: resprf[0],
},
{
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
ID: "ResourceProfile2",
Usages: map[string]*ResourceUsage{},
TTLIdx: []string{},
rPrf: resprf[1],
},
{
Tenant: config.CgrConfig().GeneralCfg().DefaultTenant,
ID: "ResourceProfile3",
Usages: map[string]*ResourceUsage{},
TTLIdx: []string{},
rPrf: resprf[2],
},
}
for _, resProfile := range resprf {
dmRES.SetResourceProfile(resProfile, true)
}
for _, res := range resourceTest {
dmRES.SetResource(res)
}
//clear the cache
Cache.Clear(nil)
// start fresh with new dataManager
cfg := config.NewDefaultCGRConfig()
dm := NewDataManager(NewInternalDB(nil, nil, true), config.CgrConfig().CacheCfg(), nil)
dmRES = NewDataManager(data, config.CgrConfig().CacheCfg(), nil)
defaultCfg.ResourceSCfg().StoreInterval = 1
defaultCfg.ResourceSCfg().StringIndexedFields = nil
defaultCfg.ResourceSCfg().PrefixIndexedFields = nil
resService = NewResourceService(dmRES, defaultCfg,
&FilterS{dm: dmRES, cfg: defaultCfg}, nil)
cfg.ResourceSCfg().StoreInterval = 1
cfg.ResourceSCfg().StringIndexedFields = nil
cfg.ResourceSCfg().PrefixIndexedFields = nil
rS := NewResourceService(dm, cfg,
&FilterS{dm: dm, cfg: cfg}, nil)
if err != nil {
t.Errorf("Error: %+v", err)
}
@@ -2822,7 +2674,7 @@ func TestResourceCaching(t *testing.T) {
"Destination": "3002"},
}
mres, err := resService.matchingResourcesForEvent(ev.Tenant, ev,
mres, err := rS.matchingResourcesForEvent(ev.Tenant, ev,
"TestResourceCaching", nil)
if err != nil {
t.Errorf("Error: %+v", err)
@@ -6304,3 +6156,387 @@ func TestResourcesV1ReleaseResourcesProcessThErr(t *testing.T) {
dm.DataDB().Flush(utils.EmptyString)
}
func TestResourcesStoreResourceError(t *testing.T) {
Cache.Clear(nil)
cfg := config.NewDefaultCGRConfig()
cfg.ResourceSCfg().StoreInterval = -1
cfg.RPCConns()["test"] = &config.RPCConn{
Conns: []*config.RemoteHost{{}},
}
cfg.DataDbCfg().RplConns = []string{"test"}
dft := config.CgrConfig()
config.SetCgrConfig(cfg)
defer config.SetCgrConfig(dft)
db := NewInternalDB(nil, nil, true)
dm := NewDataManager(db, cfg.CacheCfg(), NewConnManager(cfg, make(map[string]chan rpcclient.ClientConnector)))
rS := NewResourceService(dm, cfg, NewFilterS(cfg, nil, dm), nil)
rsPrf := &ResourceProfile{
Tenant: "cgrates.org",
ID: "RES1",
FilterIDs: []string{"*string:~*req.Account:1001"},
ThresholdIDs: []string{utils.MetaNone},
AllocationMessage: "Approved",
Weight: 10,
Limit: 10,
UsageTTL: time.Minute,
Stored: true,
}
err := dm.SetResourceProfile(rsPrf, true)
if err != nil {
t.Fatal(err)
}
args := utils.ArgRSv1ResourceUsage{
CGREvent: &utils.CGREvent{
ID: "EventAuthorizeResource",
Event: map[string]interface{}{
utils.AccountField: "1001",
},
},
UsageID: "RU_Test",
UsageTTL: utils.DurationPointer(time.Minute),
Units: 5,
}
cfg.DataDbCfg().Items[utils.MetaResources].Replicate = true
var reply string
if err := rS.V1AllocateResources(args, &reply); err != utils.ErrDisconnected {
t.Error(err)
}
cfg.DataDbCfg().Items[utils.MetaResources].Replicate = false
if err := rS.V1AllocateResources(args, &reply); err != nil {
t.Error(err)
} else if reply != "Approved" {
t.Errorf("Unexpected reply returned: %q", reply)
}
cfg.DataDbCfg().Items[utils.MetaResources].Replicate = true
if err := rS.V1ReleaseResources(args, &reply); err != utils.ErrDisconnected {
t.Error(err)
}
}
func TestResourceMatchingResourcesForEventNotFoundInCache(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
db := NewInternalDB(nil, nil, true)
dmRES := NewDataManager(db, config.CgrConfig().CacheCfg(), nil)
cfg.ResourceSCfg().StoreInterval = 1
cfg.ResourceSCfg().StringIndexedFields = nil
cfg.ResourceSCfg().PrefixIndexedFields = nil
rS := NewResourceService(dmRES, cfg,
&FilterS{dm: dmRES, cfg: cfg}, nil)
Cache.Set(utils.CacheEventResources, "TestResourceMatchingResourcesForEventNotFoundInCache", nil, nil, true, utils.NonTransactional)
_, err := rS.matchingResourcesForEvent("cgrates.org", new(utils.CGREvent),
"TestResourceMatchingResourcesForEventNotFoundInCache", utils.DurationPointer(10*time.Second))
if err != utils.ErrNotFound {
t.Errorf("Error: %+v", err)
}
}
func TestResourceMatchingResourcesForEventNotFoundInDB(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
db := NewInternalDB(nil, nil, true)
dmRES := NewDataManager(db, config.CgrConfig().CacheCfg(), nil)
cfg.ResourceSCfg().StoreInterval = 1
cfg.ResourceSCfg().StringIndexedFields = nil
cfg.ResourceSCfg().PrefixIndexedFields = nil
rS := NewResourceService(dmRES, cfg,
&FilterS{dm: dmRES, cfg: cfg}, nil)
Cache.Set(utils.CacheEventResources, "TestResourceMatchingResourcesForEventNotFoundInDB", utils.StringSet{"Res2": {}}, nil, true, utils.NonTransactional)
_, err := rS.matchingResourcesForEvent("cgrates.org", new(utils.CGREvent),
"TestResourceMatchingResourcesForEventNotFoundInDB", utils.DurationPointer(10*time.Second))
if err != utils.ErrNotFound {
t.Errorf("Error: %+v", err)
}
}
func TestResourceMatchingResourcesForEventLocks(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
db := NewInternalDB(nil, nil, true)
dm := NewDataManager(db, config.CgrConfig().CacheCfg(), nil)
cfg.ResourceSCfg().StoreInterval = 1
cfg.ResourceSCfg().StringIndexedFields = nil
cfg.ResourceSCfg().PrefixIndexedFields = nil
rS := NewResourceService(dm, cfg,
&FilterS{dm: dm, cfg: cfg}, nil)
prfs := make([]*ResourceProfile, 0)
ids := utils.StringSet{}
for i := 0; i < 10; i++ {
rPrf := &ResourceProfile{
Tenant: "cgrates.org",
ID: fmt.Sprintf("RES%d", i),
UsageTTL: 10 * time.Second,
Limit: 10.00,
AllocationMessage: "AllocationMessage",
Weight: 20.00,
ThresholdIDs: []string{utils.MetaNone},
}
dm.SetResourceProfile(rPrf, true)
prfs = append(prfs, rPrf)
ids.Add(rPrf.ID)
}
dm.RemoveResource("cgrates.org", "RES1")
Cache.Set(utils.CacheEventResources, "TestResourceMatchingResourcesForEventLocks", ids, nil, true, utils.NonTransactional)
_, err := rS.matchingResourcesForEvent("cgrates.org", new(utils.CGREvent),
"TestResourceMatchingResourcesForEventLocks", utils.DurationPointer(10*time.Second))
if err != utils.ErrNotFound {
t.Errorf("Error: %+v", err)
}
for _, rPrf := range prfs {
if rPrf.isLocked() {
t.Fatalf("Expected profile to not be locked %q", rPrf.ID)
}
if rPrf.ID == "RES1" {
continue
}
if r, err := dm.GetResource(rPrf.Tenant, rPrf.ID, true, false, utils.NonTransactional); err != nil {
t.Errorf("error %s for <%s>", err, rPrf.ID)
} else if r.isLocked() {
t.Fatalf("Expected resource to not be locked %q", rPrf.ID)
}
}
}
func TestResourceMatchingResourcesForEventLocks2(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
db := NewInternalDB(nil, nil, true)
dm := NewDataManager(db, config.CgrConfig().CacheCfg(), nil)
cfg.ResourceSCfg().StoreInterval = 1
cfg.ResourceSCfg().StringIndexedFields = nil
cfg.ResourceSCfg().PrefixIndexedFields = nil
rS := NewResourceService(dm, cfg,
&FilterS{dm: dm, cfg: cfg}, nil)
prfs := make([]*ResourceProfile, 0)
ids := utils.StringSet{}
for i := 0; i < 10; i++ {
rPrf := &ResourceProfile{
Tenant: "cgrates.org",
ID: fmt.Sprintf("RES%d", i),
UsageTTL: 10 * time.Second,
Limit: 10.00,
AllocationMessage: "AllocationMessage",
Weight: 20.00,
ThresholdIDs: []string{utils.MetaNone},
}
dm.SetResourceProfile(rPrf, true)
prfs = append(prfs, rPrf)
ids.Add(rPrf.ID)
}
rPrf := &ResourceProfile{
Tenant: "cgrates.org",
ID: "RES20",
FilterIDs: []string{"FLTR_RES_201"},
UsageTTL: 10 * time.Second,
Limit: 10.00,
AllocationMessage: "AllocationMessage",
Weight: 20.00,
ThresholdIDs: []string{utils.MetaNone},
}
err = db.SetResourceProfileDrv(rPrf)
if err != nil {
t.Fatal(err)
}
prfs = append(prfs, rPrf)
ids.Add(rPrf.ID)
Cache.Set(utils.CacheEventResources, "TestResourceMatchingResourcesForEventLocks2", ids, nil, true, utils.NonTransactional)
_, err := rS.matchingResourcesForEvent("cgrates.org", new(utils.CGREvent),
"TestResourceMatchingResourcesForEventLocks2", utils.DurationPointer(10*time.Second))
expErr := utils.ErrPrefixNotFound(rPrf.FilterIDs[0])
if err == nil || err.Error() != expErr.Error() {
t.Errorf("Expected error: %s ,received: %+v", expErr, err)
}
for _, rPrf := range prfs {
if rPrf.isLocked() {
t.Fatalf("Expected profile to not be locked %q", rPrf.ID)
}
if rPrf.ID == "RES20" {
continue
}
if r, err := dm.GetResource(rPrf.Tenant, rPrf.ID, true, false, utils.NonTransactional); err != nil {
t.Errorf("error %s for <%s>", err, rPrf.ID)
} else if r.isLocked() {
t.Fatalf("Expected resource to not be locked %q", rPrf.ID)
}
}
}
func TestResourceMatchingResourcesForEventLocksBlocker(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
db := NewInternalDB(nil, nil, true)
dm := NewDataManager(db, config.CgrConfig().CacheCfg(), nil)
cfg.ResourceSCfg().StoreInterval = 1
cfg.ResourceSCfg().StringIndexedFields = nil
cfg.ResourceSCfg().PrefixIndexedFields = nil
rS := NewResourceService(dm, cfg,
&FilterS{dm: dm, cfg: cfg}, nil)
prfs := make([]*ResourceProfile, 0)
ids := utils.StringSet{}
for i := 0; i < 10; i++ {
rPrf := &ResourceProfile{
Tenant: "cgrates.org",
ID: fmt.Sprintf("RES%d", i),
UsageTTL: 10 * time.Second,
Limit: 10.00,
AllocationMessage: "AllocationMessage",
Weight: float64(10 - i),
Blocker: i == 4,
ThresholdIDs: []string{utils.MetaNone},
}
dm.SetResourceProfile(rPrf, true)
prfs = append(prfs, rPrf)
ids.Add(rPrf.ID)
}
Cache.Set(utils.CacheEventResources, "TestResourceMatchingResourcesForEventLocksBlocker", ids, nil, true, utils.NonTransactional)
mres, err := rS.matchingResourcesForEvent("cgrates.org", new(utils.CGREvent),
"TestResourceMatchingResourcesForEventLocksBlocker", utils.DurationPointer(10*time.Second))
if err != nil {
t.Errorf("Error: %+v", err)
}
defer mres.unlock()
if len(mres) != 5 {
t.Fatal("Expected 6 resources")
}
for _, rPrf := range prfs[5:] {
if rPrf.isLocked() {
t.Errorf("Expected profile to not be locked %q", rPrf.ID)
}
if r, err := dm.GetResource(rPrf.Tenant, rPrf.ID, true, false, utils.NonTransactional); err != nil {
t.Errorf("error %s for <%s>", err, rPrf.ID)
} else if r.isLocked() {
t.Fatalf("Expected resource to not be locked %q", rPrf.ID)
}
}
for _, rPrf := range prfs[:5] {
if !rPrf.isLocked() {
t.Errorf("Expected profile to be locked %q", rPrf.ID)
}
if r, err := dm.GetResource(rPrf.Tenant, rPrf.ID, true, false, utils.NonTransactional); err != nil {
t.Errorf("error %s for <%s>", err, rPrf.ID)
} else if !r.isLocked() {
t.Fatalf("Expected resource to be locked %q", rPrf.ID)
}
}
}
func TestResourceMatchingResourcesForEventLocksActivationInterval(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
db := NewInternalDB(nil, nil, true)
dm := NewDataManager(db, config.CgrConfig().CacheCfg(), nil)
cfg.ResourceSCfg().StoreInterval = 1
cfg.ResourceSCfg().StringIndexedFields = nil
cfg.ResourceSCfg().PrefixIndexedFields = nil
rS := NewResourceService(dm, cfg,
&FilterS{dm: dm, cfg: cfg}, nil)
ids := utils.StringSet{}
for i := 0; i < 10; i++ {
rPrf := &ResourceProfile{
Tenant: "cgrates.org",
ID: fmt.Sprintf("RES%d", i),
UsageTTL: 10 * time.Second,
Limit: 10.00,
AllocationMessage: "AllocationMessage",
Weight: 20.00,
ThresholdIDs: []string{utils.MetaNone},
}
dm.SetResourceProfile(rPrf, true)
ids.Add(rPrf.ID)
}
rPrf := &ResourceProfile{
Tenant: "cgrates.org",
ID: "RES21",
UsageTTL: 10 * time.Second,
Limit: 10.00,
AllocationMessage: "AllocationMessage",
Weight: 20.00,
ThresholdIDs: []string{utils.MetaNone},
ActivationInterval: &utils.ActivationInterval{
ExpiryTime: time.Now().Add(-5 * time.Second),
},
}
dm.SetResourceProfile(rPrf, true)
ids.Add(rPrf.ID)
Cache.Set(utils.CacheEventResources, "TestResourceMatchingResourcesForEventLocks2", ids, nil, true, utils.NonTransactional)
mres, err := rS.matchingResourcesForEvent("cgrates.org", &utils.CGREvent{Time: utils.TimePointer(time.Now())},
"TestResourceMatchingResourcesForEventLocks2", utils.DurationPointer(10*time.Second))
if err != nil {
t.Errorf("Error: %+v", err)
}
defer mres.unlock()
if rPrf.isLocked() {
t.Fatalf("Expected profile to not be locked %q", rPrf.ID)
}
if r, err := dm.GetResource(rPrf.Tenant, rPrf.ID, true, false, utils.NonTransactional); err != nil {
t.Errorf("error %s for <%s>", err, rPrf.ID)
} else if r.isLocked() {
t.Fatalf("Expected resource to not be locked %q", rPrf.ID)
}
}
func TestResourceMatchingResourcesForEventLocks3(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
prfs := make([]*ResourceProfile, 0)
Cache.Clear(nil)
db := &DataDBMock{
GetResourceProfileDrvF: func(tnt, id string) (*ResourceProfile, error) {
if id == "RES1" {
return nil, utils.ErrNotImplemented
}
rPrf := &ResourceProfile{
Tenant: "cgrates.org",
ID: id,
UsageTTL: 10 * time.Second,
Limit: 10.00,
AllocationMessage: "AllocationMessage",
Weight: 20.00,
ThresholdIDs: []string{utils.MetaNone},
}
Cache.Set(utils.CacheResources, rPrf.TenantID(), &Resource{
Tenant: rPrf.Tenant,
ID: rPrf.ID,
Usages: make(map[string]*ResourceUsage),
}, nil, true, utils.NonTransactional)
prfs = append(prfs, rPrf)
return rPrf, nil
},
}
dm := NewDataManager(db, config.CgrConfig().CacheCfg(), nil)
cfg.ResourceSCfg().StoreInterval = 1
cfg.ResourceSCfg().StringIndexedFields = nil
cfg.ResourceSCfg().PrefixIndexedFields = nil
rS := NewResourceService(dm, cfg,
&FilterS{dm: dm, cfg: cfg}, nil)
ids := utils.StringSet{}
for i := 0; i < 10; i++ {
ids.Add(fmt.Sprintf("RES%d", i))
}
Cache.Set(utils.CacheEventResources, "TestResourceMatchingResourcesForEventLocks3", ids, nil, true, utils.NonTransactional)
_, err := rS.matchingResourcesForEvent("cgrates.org", new(utils.CGREvent),
"TestResourceMatchingResourcesForEventLocks3", utils.DurationPointer(10*time.Second))
if err != utils.ErrNotImplemented {
t.Errorf("Error: %+v", err)
}
for _, rPrf := range prfs {
if rPrf.isLocked() {
t.Fatalf("Expected profile to not be locked %q", rPrf.ID)
}
// if r, err := dm.GetResource(rPrf.Tenant, rPrf.ID, true, false, utils.NonTransactional); err != nil {
// t.Errorf("error %s for <%s>", err, rPrf.ID)
// } else if r.isLocked() {
// t.Fatalf("Expected resource to not be locked %q", rPrf.ID)
// }
}
}