diff --git a/data/conf/samples/ees_ooma/cgrates.json b/data/conf/samples/ees_ooma/cgrates.json
deleted file mode 100644
index 1b759693e..000000000
--- a/data/conf/samples/ees_ooma/cgrates.json
+++ /dev/null
@@ -1,628 +0,0 @@
-{
-// Sample CGRateS Configuration file for EEs
-//
-// Copyright (C) ITsysCOM GmbH
-
-"logger": {
- "level": 7
-},
-
-"listen": {
- "rpc_json": ":2012",
- "rpc_gob": ":2013",
- "http": ":2080",
-},
-
-"data_db": {
- "db_type": "redis",
- "db_port": 6379,
- "db_name": "10",
-},
-
-
-"stor_db": {
- "db_password": "CGRateS.org",
-},
-
-
-"rates": {
- "enabled": true,
-},
-
-
-"cdrs": {
- "enabled": true,
- "chargers_conns": ["*localhost"],
- "rates_conns": ["*internal"],
- "session_cost_retries": 0,
-},
-
-
-"chargers": {
- "enabled": true,
- "attributes_conns": ["*internal"],
-},
-
-
-"attributes": {
- "enabled": true,
-},
-
-
-"ees": {
- "attributes_conns": [],
- "cache": {
- "*file_csv": {
- "limit": -1,
- "static_ttl": false,
- "ttl": "5s"
- },
- "*sql": {
- "limit": -1,
- "static_ttl": false,
- "ttl": "1h"
- }
- },
- "enabled": true,
- "exporters": [
- {
- "attempts": 2,
- "attribute_context": "",
- "attribute_ids": [],
- "export_path": "mysql://cgrates:CGRateS.org@127.0.0.1:3306",
- "fields": [
- {
- "tag": "RequiredTemplate",
- "type": "*template",
- "value": "requiredFields"
- }
- ],
- "filters": [
- "*prefix:~*req.SetupTime:2022-02"
- ],
- "flags": [],
- "id": "monthly_cdrs_1",
- "opts": {
- "sqlConnMaxLifetime": "0",
- "sqlDBName": "cgrates2",
- "sqlMaxIdleConns": 10,
- "sqlMaxOpenConns": 100,
- "sqlTableName": "cdrs",
- "pgSSLMode": "disable"
- },
- "tenant": "",
- "timezone": "",
- "type": "*sql"
- },
- {
- "attempts": 2,
- "attribute_context": "",
- "attribute_ids": [],
- "export_path": "mysql://cgrates:CGRateS.org@127.0.0.1:3306",
- "fields": [
- {
- "tag": "RequiredTemplate",
- "type": "*template",
- "value": "requiredFields"
- }
- ],
- "filters": [
- "*prefix:~*req.SetupTime:2022-03"
- ],
- "flags": [],
- "id": "monthly_cdrs_2",
- "opts": {
- "sqlConnMaxLifetime": "0",
- "sqlDBName": "cgrates2",
- "sqlMaxIdleConns": 10,
- "sqlMaxOpenConns": 100,
- "sqlTableName": "cdrs",
- "pgSSLMode": "disable"
- },
- "tenant": "",
- "timezone": "",
- "type": "*sql"
- },
- {
- "attempts": 2,
- "attribute_context": "",
- "attribute_ids": [],
- "export_path": "mysql://cgrates:CGRateS.org@127.0.0.1:3306",
- "fields": [
- {
- "tag": "RequiredTemplate",
- "type": "*template",
- "value": "requiredFields"
- }
- ],
- "filters": [
- "*prefix:~*req.SetupTime:2022-04"
- ],
- "flags": [],
- "id": "monthly_cdrs_3",
- "opts": {
- "sqlConnMaxLifetime": "0",
- "sqlDBName": "cgrates2",
- "sqlMaxIdleConns": 10,
- "sqlMaxOpenConns": 100,
- "sqlTableName": "cdrs",
- "pgSSLMode": "disable"
- },
- "tenant": "",
- "timezone": "",
- "type": "*sql"
- },
- {
- "attempts": 2,
- "attribute_context": "",
- "attribute_ids": [],
- "export_path": "mysql://cgrates:CGRateS.org@127.0.0.1:3306",
- "fields": [
- {
- "tag": "RequiredTemplate",
- "type": "*template",
- "value": "requiredFields"
- }
- ],
- "filters": [
- "*prefix:~*req.SetupTime:2022-05"
- ],
- "flags": [],
- "id": "monthly_cdrs_4",
- "opts": {
- "sqlConnMaxLifetime": "0",
- "sqlDBName": "cgrates2",
- "sqlMaxIdleConns": 10,
- "sqlMaxOpenConns": 100,
- "sqlTableName": "cdrs",
- "pgSSLMode": "disable"
- },
- "tenant": "",
- "timezone": "",
- "type": "*sql"
- },
- {
- "attempts": 2,
- "attribute_context": "",
- "attribute_ids": [],
- "export_path": "mysql://cgrates:CGRateS.org@127.0.0.1:3306",
- "fields": [
- {
- "tag": "RequiredTemplate",
- "type": "*template",
- "value": "requiredFields"
- }
- ],
- "filters": [
- "*prefix:~*req.SetupTime:2022-06"
- ],
- "flags": [],
- "id": "monthly_cdrs_5",
- "opts": {
- "sqlConnMaxLifetime": "0",
- "sqlDBName": "cgrates2",
- "sqlMaxIdleConns": 10,
- "sqlMaxOpenConns": 100,
- "sqlTableName": "cdrs",
- "pgSSLMode": "disable"
- },
- "tenant": "",
- "timezone": "",
- "type": "*sql"
- },
- {
- "attempts": 2,
- "attribute_context": "",
- "attribute_ids": [],
- "export_path": "mysql://cgrates:CGRateS.org@127.0.0.1:3306",
- "fields": [
- {
- "tag": "RequiredTemplate",
- "type": "*template",
- "value": "requiredFields"
- }
- ],
- "filters": [
- "*prefix:~*req.SetupTime:2022-07"
- ],
- "flags": [],
- "id": "monthly_cdrs_6",
- "opts": {
- "sqlConnMaxLifetime": "0",
- "sqlDBName": "cgrates2",
- "sqlMaxIdleConns": 10,
- "sqlMaxOpenConns": 100,
- "sqlTableName": "cdrs",
- "pgSSLMode": "disable"
- },
- "tenant": "",
- "timezone": "",
- "type": "*sql"
- },
- {
- "attempts": 2,
- "attribute_context": "",
- "attribute_ids": [],
- "export_path": "mysql://cgrates:CGRateS.org@127.0.0.1:3306",
- "fields": [
- {
- "tag": "RequiredTemplate",
- "type": "*template",
- "value": "requiredFields"
- }
- ],
- "filters": [
- "*prefix:~*req.SetupTime:2022-08"
- ],
- "flags": [],
- "id": "monthly_cdrs_7",
- "opts": {
- "sqlConnMaxLifetime": "0",
- "sqlDBName": "cgrates2",
- "sqlMaxIdleConns": 10,
- "sqlMaxOpenConns": 100,
- "sqlTableName": "cdrs",
- "pgSSLMode": "disable"
- },
- "tenant": "",
- "timezone": "",
- "type": "*sql"
- },
- {
- "attempts": 2,
- "attribute_context": "",
- "attribute_ids": [],
- "export_path": "mysql://cgrates:CGRateS.org@127.0.0.1:3306",
- "fields": [
- {
- "tag": "RequiredTemplate",
- "type": "*template",
- "value": "requiredFields"
- }
- ],
- "filters": [
- "*prefix:~*req.SetupTime:2022-09"
- ],
- "flags": [],
- "id": "monthly_cdrs_8",
- "opts": {
- "sqlConnMaxLifetime": "0",
- "sqlDBName": "cgrates2",
- "sqlMaxIdleConns": 10,
- "sqlMaxOpenConns": 100,
- "sqlTableName": "cdrs",
- "pgSSLMode": "disable"
- },
- "tenant": "",
- "timezone": "",
- "type": "*sql"
- },
- {
- "attempts": 2,
- "attribute_context": "",
- "attribute_ids": [],
- "export_path": "mysql://cgrates:CGRateS.org@127.0.0.1:3306",
- "fields": [
- {
- "tag": "RequiredTemplate",
- "type": "*template",
- "value": "requiredFields"
- }
- ],
- "filters": [
- "*prefix:~*req.SetupTime:2022-10"
- ],
- "flags": [],
- "id": "monthly_cdrs_9",
- "opts": {
- "sqlConnMaxLifetime": "0",
- "sqlDBName": "cgrates2",
- "sqlMaxIdleConns": 10,
- "sqlMaxOpenConns": 100,
- "sqlTableName": "cdrs",
- "pgSSLMode": "disable"
- },
- "tenant": "",
- "timezone": "",
- "type": "*sql"
- },
- {
- "attempts": 2,
- "attribute_context": "",
- "attribute_ids": [],
- "export_path": "mysql://cgrates:CGRateS.org@127.0.0.1:3306",
- "fields": [
- {
- "tag": "RequiredTemplate",
- "type": "*template",
- "value": "requiredFields"
- }
- ],
- "filters": [
- "*prefix:~*req.SetupTime:2022-11"
- ],
- "flags": [],
- "id": "monthly_cdrs_10",
- "opts": {
- "sqlConnMaxLifetime": "0",
- "sqlDBName": "cgrates2",
- "sqlMaxIdleConns": 10,
- "sqlMaxOpenConns": 100,
- "sqlTableName": "cdrs",
- "pgSSLMode": "disable"
- },
- "tenant": "",
- "timezone": "",
- "type": "*sql"
- },
- {
- "attempts": 2,
- "attribute_context": "",
- "attribute_ids": [],
- "export_path": "mysql://cgrates:CGRateS.org@127.0.0.1:3306",
- "fields": [
- {
- "tag": "RequiredTemplate",
- "type": "*template",
- "value": "requiredFields"
- }
- ],
- "filters": [
- "*prefix:~*req.SetupTime:2022-12"
- ],
- "flags": [],
- "id": "monthly_cdrs_11",
- "opts": {
- "sqlConnMaxLifetime": "0",
- "sqlDBName": "cgrates2",
- "sqlMaxIdleConns": 10,
- "sqlMaxOpenConns": 100,
- "sqlTableName": "cdrs",
- "pgSSLMode": "disable"
- },
- "tenant": "",
- "timezone": "",
- "type": "*sql"
- },
- {
- "attempts": 2,
- "attribute_context": "",
- "attribute_ids": [],
- "export_path": "mysql://cgrates:CGRateS.org@127.0.0.1:3306",
- "fields": [
- {
- "tag": "RequiredTemplate",
- "type": "*template",
- "value": "requiredFields"
- }
- ],
- "filters": [
- "*prefix:~*req.SetupTime:2023-01"
- ],
- "flags": [],
- "id": "monthly_cdrs_12",
- "opts": {
- "sqlConnMaxLifetime": "0",
- "sqlDBName": "cgrates2",
- "sqlMaxIdleConns": 10,
- "sqlMaxOpenConns": 100,
- "sqlTableName": "cdrs",
- "pgSSLMode": "disable"
- },
- "tenant": "",
- "timezone": "",
- "type": "*sql"
- },
- {
- "attempts": 2,
- "attribute_context": "",
- "attribute_ids": [],
- "export_path": "mysql://cgrates:CGRateS.org@127.0.0.1:3306",
- "fields": [
- {
- "tag": "RequiredTemplate",
- "type": "*template",
- "value": "requiredFields"
- }
- ],
- "filters": [
- "*prefix:~*req.SetupTime:2023-02"
- ],
- "flags": [],
- "id": "monthly_cdrs_13",
- "opts": {
- "sqlConnMaxLifetime": "0",
- "sqlDBName": "cgrates2",
- "sqlMaxIdleConns": 10,
- "sqlMaxOpenConns": 100,
- "sqlTableName": "cdrs",
- "pgSSLMode": "disable"
- },
- "tenant": "",
- "timezone": "",
- "type": "*sql"
- }
- ]
-},
-
-
-"apiers": {
- "enabled": true,
-},
-
-
-"templates": {
- "requiredFields": [
- {
- "path": "*exp.cgrid",
- "tag": "cgrid",
- "type": "*variable",
- "value": "~*req.CGRID"
- },
- {
- "path": "*exp.run_id",
- "tag": "run_id",
- "type": "*variable",
- "value": "~*req.RunID"
- },
- {
- "path": "*exp.origin_host",
- "tag": "origin_host",
- "type": "*variable",
- "value": "~*req.OriginHost"
- },
- {
- "path": "*exp.source",
- "tag": "source",
- "type": "*variable",
- "value": "~*req.Source"
- },
- {
- "path": "*exp.origin_id",
- "tag": "origin_id",
- "type": "*variable",
- "value": "~*req.OriginID"
- },
- {
- "path": "*exp.tor",
- "tag": "tor",
- "type": "*variable",
- "value": "~*req.ToR"
- },
- {
- "path": "*exp.request_type",
- "tag": "request_type",
- "type": "*variable",
- "value": "~*req.RequestType"
- },
- {
- "path": "*exp.tenant",
- "tag": "tenant",
- "type": "*variable",
- "value": "~*req.Tenant"
- },
- {
- "path": "*exp.category",
- "tag": "category",
- "type": "*variable",
- "value": "~*req.Category"
- },
- {
- "path": "*exp.account",
- "tag": "account",
- "type": "*variable",
- "value": "~*req.Account"
- },
- {
- "path": "*exp.subject",
- "tag": "subject",
- "type": "*variable",
- "value": "~*req.Subject"
- },
- {
- "path": "*exp.destination",
- "tag": "destination",
- "type": "*variable",
- "value": "~*req.Destination"
- },
- {
- "path": "*exp.setup_time",
- "tag": "setup_time",
- "type": "*variable",
- "value": "~*req.SetupTime"
- },
- {
- "path": "*exp.answer_time",
- "tag": "answer_time",
- "type": "*variable",
- "value": "~*req.AnswerTime"
- },
- {
- "path": "*exp.`usage`",
- "tag": "usage",
- "type": "*variable",
- "value": "~*req.Usage{*duration_nanoseconds}"
- },
- {
- "path": "*exp.cost_source",
- "tag": "cost_source",
- "type": "*variable",
- "value": "~*req.CostSource"
- },
- {
- "path": "*exp.cost",
- "tag": "cost",
- "type": "*variable",
- "value": "~*req.Cost"
- },
- {
- "path": "*exp.cost_details",
- "tag": "cost_details",
- "type": "*variable",
- "value": "~*req.CostDetails"
- },
- {
- "path": "*exp.extra_info",
- "tag": "extra_info",
- "type": "*variable",
- "value": "~*req.ExtraInfo"
- },
- {
- "path": "*exp.disconnect_cause",
- "tag": "disconnect_cause",
- "type": "*variable",
- "value": "~*req.DisconnectCause"
- },
- {
- "path": "*exp.route",
- "tag": "route",
- "type": "*variable",
- "value": "~*req.Route"
- },
- {
- "path": "*exp.caller_is_determined_in_areas",
- "tag": "caller_is_determined_in_areas",
- "type": "*variable",
- "value": "~*req.caller_is_determined_in_areas"
- },
- {
- "path": "*exp.caller_is_determined",
- "tag": "caller_is_determined",
- "type": "*variable",
- "value": "~*req.variable_caller_is_determined"
- },
- {
- "path": "*exp.origination",
- "tag": "origination",
- "type": "*variable",
- "value": "~*req.Account"
- },
- {
- "path": "*exp.e164_destination",
- "tag": "e164_destination",
- "type": "*variable",
- "value": "~*req.variable_e164_destination"
- },
- {
- "path": "*exp.rn_destination",
- "tag": "rn_destination",
- "type": "*variable",
- "value": "~*req.variable_rn_destination"
- },
- {
- "path": "*exp.original_destination",
- "tag": "original_destination",
- "type": "*variable",
- "value": "~*req.variable_original_destination"
- },
- {
- "path": "*exp.original_account",
- "tag": "original_account",
- "type": "*variable",
- "value": "~*req.variable_original_account"
- }
- ]
-},
-
-
-}
diff --git a/resources/apis.go b/resources/apis.go
new file mode 100644
index 000000000..6b1186314
--- /dev/null
+++ b/resources/apis.go
@@ -0,0 +1,381 @@
+/*
+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 resources
+
+import (
+ "time"
+
+ "github.com/cgrates/birpc/context"
+ "github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/engine"
+ "github.com/cgrates/cgrates/utils"
+ "github.com/cgrates/guardian"
+)
+
+// V1GetResourcesForEvent returns active resource configs matching the event
+func (rS *ResourceS) V1GetResourcesForEvent(ctx *context.Context, args *utils.CGREvent, reply *Resources) (err error) {
+ if args == nil {
+ return utils.NewErrMandatoryIeMissing(utils.Event)
+ }
+ if missing := utils.MissingStructFields(args, []string{utils.ID, utils.Event}); len(missing) != 0 { //Params missing
+ return utils.NewErrMandatoryIeMissing(missing...)
+ }
+
+ var usageID string
+ if usageID, err = engine.GetStringOpts(ctx, args.Tenant, args.AsDataProvider(), nil, rS.fltrS, rS.cfg.ResourceSCfg().Opts.UsageID,
+ utils.OptsResourcesUsageID); err != nil {
+ return
+ }
+
+ var ttl time.Duration
+ if ttl, err = engine.GetDurationOpts(ctx, args.Tenant, args.AsDataProvider(), nil, rS.fltrS, rS.cfg.ResourceSCfg().Opts.UsageTTL,
+ utils.OptsResourcesUsageTTL); err != nil {
+ return
+ }
+ usageTTL := utils.DurationPointer(ttl)
+
+ if usageID == utils.EmptyString {
+ return utils.NewErrMandatoryIeMissing(utils.UsageID)
+ }
+ tnt := args.Tenant
+ if tnt == utils.EmptyString {
+ tnt = rS.cfg.GeneralCfg().DefaultTenant
+ }
+
+ // RPC caching
+ if config.CgrConfig().CacheCfg().Partitions[utils.CacheRPCResponses].Limit != 0 {
+ cacheKey := utils.ConcatenatedKey(utils.ResourceSv1GetResourcesForEvent, utils.ConcatenatedKey(tnt, args.ID))
+ refID := guardian.Guardian.GuardIDs("",
+ config.CgrConfig().GeneralCfg().LockingTimeout, cacheKey) // RPC caching needs to be atomic
+ defer guardian.Guardian.UnguardIDs(refID)
+ if itm, has := engine.Cache.Get(utils.CacheRPCResponses, cacheKey); has {
+ cachedResp := itm.(*utils.CachedRPCResponse)
+ if cachedResp.Error == nil {
+ *reply = *cachedResp.Result.(*Resources)
+ }
+ return cachedResp.Error
+ }
+ defer engine.Cache.Set(ctx, utils.CacheRPCResponses, cacheKey,
+ &utils.CachedRPCResponse{Result: reply, Error: err},
+ nil, true, utils.NonTransactional)
+ }
+ // end of RPC caching
+
+ var mtcRLs Resources
+ if mtcRLs, err = rS.matchingResourcesForEvent(ctx, tnt, args, usageID, usageTTL); err != nil {
+ return err
+ }
+ *reply = mtcRLs
+ mtcRLs.unlock()
+ return
+}
+
+// V1AuthorizeResources queries service to find if an Usage is allowed
+func (rS *ResourceS) V1AuthorizeResources(ctx *context.Context, args *utils.CGREvent, reply *string) (err error) {
+ if args == nil {
+ return utils.NewErrMandatoryIeMissing(utils.Event)
+ }
+ if missing := utils.MissingStructFields(args, []string{utils.ID, utils.Event}); len(missing) != 0 { //Params missing
+ return utils.NewErrMandatoryIeMissing(missing...)
+ }
+
+ var usageID string
+ if usageID, err = engine.GetStringOpts(ctx, args.Tenant, args.AsDataProvider(), nil, rS.fltrS, rS.cfg.ResourceSCfg().Opts.UsageID,
+ utils.OptsResourcesUsageID); err != nil {
+ return
+ }
+
+ var units float64
+ if units, err = engine.GetFloat64Opts(ctx, args.Tenant, args.AsDataProvider(), nil, rS.fltrS, rS.cfg.ResourceSCfg().Opts.Units,
+ utils.OptsResourcesUnits); err != nil {
+ return
+ }
+
+ var ttl time.Duration
+ if ttl, err = engine.GetDurationOpts(ctx, args.Tenant, args.AsDataProvider(), nil, rS.fltrS, rS.cfg.ResourceSCfg().Opts.UsageTTL,
+ utils.OptsResourcesUsageTTL); err != nil {
+ return
+ }
+ usageTTL := utils.DurationPointer(ttl)
+
+ if usageID == utils.EmptyString {
+ return utils.NewErrMandatoryIeMissing(utils.UsageID)
+ }
+
+ tnt := args.Tenant
+ if tnt == utils.EmptyString {
+ tnt = rS.cfg.GeneralCfg().DefaultTenant
+ }
+
+ // RPC caching
+ if config.CgrConfig().CacheCfg().Partitions[utils.CacheRPCResponses].Limit != 0 {
+ cacheKey := utils.ConcatenatedKey(utils.ResourceSv1AuthorizeResources, utils.ConcatenatedKey(tnt, args.ID))
+ refID := guardian.Guardian.GuardIDs("",
+ config.CgrConfig().GeneralCfg().LockingTimeout, cacheKey) // RPC caching needs to be atomic
+ defer guardian.Guardian.UnguardIDs(refID)
+ if itm, has := engine.Cache.Get(utils.CacheRPCResponses, cacheKey); has {
+ cachedResp := itm.(*utils.CachedRPCResponse)
+ if cachedResp.Error == nil {
+ *reply = *cachedResp.Result.(*string)
+ }
+ return cachedResp.Error
+ }
+ defer engine.Cache.Set(ctx, utils.CacheRPCResponses, cacheKey,
+ &utils.CachedRPCResponse{Result: reply, Error: err},
+ nil, true, utils.NonTransactional)
+ }
+ // end of RPC caching
+
+ var mtcRLs Resources
+ if mtcRLs, err = rS.matchingResourcesForEvent(ctx, tnt, args, usageID, usageTTL); err != nil {
+ return err
+ }
+ defer mtcRLs.unlock()
+
+ var alcMessage string
+ if alcMessage, err = mtcRLs.allocateResource(&utils.ResourceUsage{
+ Tenant: tnt,
+ ID: usageID,
+ Units: units}, true); err != nil {
+ if err == utils.ErrResourceUnavailable {
+ err = utils.ErrResourceUnauthorized
+ }
+ return
+ }
+ *reply = alcMessage
+ return
+}
+
+// V1AllocateResources is called when a resource requires allocation
+func (rS *ResourceS) V1AllocateResources(ctx *context.Context, args *utils.CGREvent, reply *string) (err error) {
+ if args == nil {
+ return utils.NewErrMandatoryIeMissing(utils.Event)
+ }
+ if missing := utils.MissingStructFields(args, []string{utils.ID, utils.Event}); len(missing) != 0 { //Params missing
+ return utils.NewErrMandatoryIeMissing(missing...)
+ }
+
+ var usageID string
+ if usageID, err = engine.GetStringOpts(ctx, args.Tenant, args.AsDataProvider(), nil, rS.fltrS, rS.cfg.ResourceSCfg().Opts.UsageID,
+ utils.OptsResourcesUsageID); err != nil {
+ return
+ }
+
+ var units float64
+ if units, err = engine.GetFloat64Opts(ctx, args.Tenant, args.AsDataProvider(), nil, rS.fltrS, rS.cfg.ResourceSCfg().Opts.Units,
+ utils.OptsResourcesUnits); err != nil {
+ return
+ }
+
+ var ttl time.Duration
+ if ttl, err = engine.GetDurationOpts(ctx, args.Tenant, args.AsDataProvider(), nil, rS.fltrS, rS.cfg.ResourceSCfg().Opts.UsageTTL,
+ utils.OptsResourcesUsageTTL); err != nil {
+ return
+ }
+ usageTTL := utils.DurationPointer(ttl)
+
+ if usageID == utils.EmptyString {
+ return utils.NewErrMandatoryIeMissing(utils.UsageID)
+ }
+
+ tnt := args.Tenant
+ if tnt == utils.EmptyString {
+ tnt = rS.cfg.GeneralCfg().DefaultTenant
+ }
+
+ // RPC caching
+ if config.CgrConfig().CacheCfg().Partitions[utils.CacheRPCResponses].Limit != 0 {
+ cacheKey := utils.ConcatenatedKey(utils.ResourceSv1AllocateResources, utils.ConcatenatedKey(tnt, args.ID))
+ refID := guardian.Guardian.GuardIDs("",
+ config.CgrConfig().GeneralCfg().LockingTimeout, cacheKey) // RPC caching needs to be atomic
+ defer guardian.Guardian.UnguardIDs(refID)
+ if itm, has := engine.Cache.Get(utils.CacheRPCResponses, cacheKey); has {
+ cachedResp := itm.(*utils.CachedRPCResponse)
+ if cachedResp.Error == nil {
+ *reply = *cachedResp.Result.(*string)
+ }
+ return cachedResp.Error
+ }
+ defer engine.Cache.Set(ctx, utils.CacheRPCResponses, cacheKey,
+ &utils.CachedRPCResponse{Result: reply, Error: err},
+ nil, true, utils.NonTransactional)
+ }
+ // end of RPC caching
+
+ var mtcRLs Resources
+ if mtcRLs, err = rS.matchingResourcesForEvent(ctx, tnt, args, usageID,
+ usageTTL); err != nil {
+ return err
+ }
+ defer mtcRLs.unlock()
+
+ var alcMsg string
+ if alcMsg, err = mtcRLs.allocateResource(&utils.ResourceUsage{Tenant: tnt, ID: usageID,
+ Units: units}, false); err != nil {
+ return
+ }
+
+ // index it for storing
+ if err = rS.storeMatchedResources(ctx, mtcRLs); err != nil {
+ return
+ }
+ if err = rS.processThresholds(ctx, mtcRLs, args.APIOpts); err != nil {
+ return
+ }
+ *reply = alcMsg
+ return
+}
+
+// V1ReleaseResources is called when we need to clear an allocation
+func (rS *ResourceS) V1ReleaseResources(ctx *context.Context, args *utils.CGREvent, reply *string) (err error) {
+ if args == nil {
+ return utils.NewErrMandatoryIeMissing(utils.Event)
+ }
+ if missing := utils.MissingStructFields(args, []string{utils.ID, utils.Event}); len(missing) != 0 { //Params missing
+ return utils.NewErrMandatoryIeMissing(missing...)
+ }
+
+ var usageID string
+ if usageID, err = engine.GetStringOpts(ctx, args.Tenant, args.AsDataProvider(), nil, rS.fltrS, rS.cfg.ResourceSCfg().Opts.UsageID,
+ utils.OptsResourcesUsageID); err != nil {
+ return
+ }
+
+ var ttl time.Duration
+ if ttl, err = engine.GetDurationOpts(ctx, args.Tenant, args.AsDataProvider(), nil, rS.fltrS, rS.cfg.ResourceSCfg().Opts.UsageTTL,
+ utils.OptsResourcesUsageTTL); err != nil {
+ return
+ }
+ usageTTL := utils.DurationPointer(ttl)
+
+ if usageID == utils.EmptyString {
+ return utils.NewErrMandatoryIeMissing(utils.UsageID)
+ }
+
+ tnt := args.Tenant
+ if tnt == utils.EmptyString {
+ tnt = rS.cfg.GeneralCfg().DefaultTenant
+ }
+
+ // RPC caching
+ if config.CgrConfig().CacheCfg().Partitions[utils.CacheRPCResponses].Limit != 0 {
+ cacheKey := utils.ConcatenatedKey(utils.ResourceSv1ReleaseResources, utils.ConcatenatedKey(tnt, args.ID))
+ refID := guardian.Guardian.GuardIDs("",
+ config.CgrConfig().GeneralCfg().LockingTimeout, cacheKey) // RPC caching needs to be atomic
+ defer guardian.Guardian.UnguardIDs(refID)
+ if itm, has := engine.Cache.Get(utils.CacheRPCResponses, cacheKey); has {
+ cachedResp := itm.(*utils.CachedRPCResponse)
+ if cachedResp.Error == nil {
+ *reply = *cachedResp.Result.(*string)
+ }
+ return cachedResp.Error
+ }
+ defer engine.Cache.Set(ctx, utils.CacheRPCResponses, cacheKey,
+ &utils.CachedRPCResponse{Result: reply, Error: err},
+ nil, true, utils.NonTransactional)
+ }
+ // end of RPC caching
+
+ var mtcRLs Resources
+ if mtcRLs, err = rS.matchingResourcesForEvent(ctx, tnt, args, usageID,
+ usageTTL); err != nil {
+ return
+ }
+ defer mtcRLs.unlock()
+
+ if err = mtcRLs.clearUsage(usageID); err != nil {
+ return
+ }
+
+ // Handle storing
+ if err = rS.storeMatchedResources(ctx, mtcRLs); err != nil {
+ return
+ }
+ if err = rS.processThresholds(ctx, mtcRLs, args.APIOpts); err != nil {
+ return
+ }
+
+ *reply = utils.OK
+ return
+}
+
+// V1GetResource returns a resource configuration
+func (rS *ResourceS) V1GetResource(ctx *context.Context, arg *utils.TenantIDWithAPIOpts, reply *utils.Resource) error {
+ if missing := utils.MissingStructFields(arg, []string{utils.ID}); len(missing) != 0 { //Params missing
+ return utils.NewErrMandatoryIeMissing(missing...)
+ }
+ tnt := arg.Tenant
+ if tnt == utils.EmptyString {
+ tnt = rS.cfg.GeneralCfg().DefaultTenant
+ }
+
+ // make sure resource is locked at process level
+ lkID := guardian.Guardian.GuardIDs(utils.EmptyString,
+ config.CgrConfig().GeneralCfg().LockingTimeout,
+ utils.ResourceLockKey(tnt, arg.ID))
+ defer guardian.Guardian.UnguardIDs(lkID)
+
+ res, err := rS.dm.GetResource(ctx, tnt, arg.ID, true, true, utils.NonTransactional)
+ if err != nil {
+ return err
+ }
+ *reply = *res
+ return nil
+}
+
+func (rS *ResourceS) V1GetResourceWithConfig(ctx *context.Context, arg *utils.TenantIDWithAPIOpts, reply *utils.ResourceWithConfig) (err error) {
+ if missing := utils.MissingStructFields(arg, []string{utils.ID}); len(missing) != 0 { //Params missing
+ return utils.NewErrMandatoryIeMissing(missing...)
+ }
+ tnt := arg.Tenant
+ if tnt == utils.EmptyString {
+ tnt = rS.cfg.GeneralCfg().DefaultTenant
+ }
+
+ // make sure resource is locked at process level
+ lkID := guardian.Guardian.GuardIDs(utils.EmptyString,
+ config.CgrConfig().GeneralCfg().LockingTimeout,
+ utils.ResourceLockKey(tnt, arg.ID))
+ defer guardian.Guardian.UnguardIDs(lkID)
+
+ var res *utils.Resource
+ res, err = rS.dm.GetResource(ctx, tnt, arg.ID, true, true, utils.NonTransactional)
+ if err != nil {
+ return
+ }
+
+ // make sure resourceProfile is locked at process level
+ lkPrflID := guardian.Guardian.GuardIDs(utils.EmptyString,
+ config.CgrConfig().GeneralCfg().LockingTimeout,
+ utils.ResourceProfileLockKey(tnt, arg.ID))
+ defer guardian.Guardian.UnguardIDs(lkPrflID)
+
+ var cfg *utils.ResourceProfile
+ cfg, err = rS.dm.GetResourceProfile(ctx, tnt, arg.ID, true, true, utils.NonTransactional)
+ if err != nil {
+ return
+ }
+
+ *reply = utils.ResourceWithConfig{
+ Resource: res,
+ Config: cfg,
+ }
+
+ return
+}
diff --git a/resources/apis_test.go b/resources/apis_test.go
new file mode 100644
index 000000000..d90134434
--- /dev/null
+++ b/resources/apis_test.go
@@ -0,0 +1,2809 @@
+/*
+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 resources
+
+import (
+ "reflect"
+ "testing"
+ "time"
+
+ "github.com/cgrates/birpc"
+ "github.com/cgrates/birpc/context"
+ "github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/engine"
+ "github.com/cgrates/rpcclient"
+
+ "github.com/cgrates/cgrates/utils"
+)
+
+func TestResourceV1AuthorizeResourceMissingStruct(t *testing.T) {
+ var dmRES *engine.DataManager
+ cfg := config.NewDefaultCGRConfig()
+
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dmRES = engine.NewDataManager(data, cfg, nil)
+ cfg.ResourceSCfg().StoreInterval = 1
+ cfg.ResourceSCfg().StringIndexedFields = nil
+ cfg.ResourceSCfg().PrefixIndexedFields = nil
+ fltrs := engine.NewFilterS(cfg, nil, dmRES)
+ resService := NewResourceService(dmRES, cfg,
+ fltrs, nil)
+ var reply *string
+ argsMissingTenant := &utils.CGREvent{
+ ID: "id1",
+ Event: map[string]any{},
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "test1",
+ utils.OptsResourcesUnits: 20,
+ },
+ }
+ argsMissingUsageID := &utils.CGREvent{
+ Tenant: "cgrates.org",
+ ID: "id1",
+ Event: map[string]any{},
+ APIOpts: map[string]any{
+ utils.OptsResourcesUnits: 20,
+ },
+ }
+ if err := resService.V1AuthorizeResources(context.TODO(), argsMissingTenant, reply); err != nil && err.Error() != "MANDATORY_IE_MISSING: [Event]" {
+ t.Error(err.Error())
+ }
+ if err := resService.V1AuthorizeResources(context.TODO(), argsMissingUsageID, reply); err != nil && err.Error() != "MANDATORY_IE_MISSING: [Event]" {
+ t.Error(err.Error())
+ }
+}
+
+func TestResourceAllocateResourceOtherDB(t *testing.T) {
+ rProf := &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RL_DB",
+ FilterIDs: []string{"*string:~*opts.Resource:RL_DB"},
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 100,
+ }},
+ Limit: 2,
+ ThresholdIDs: []string{utils.MetaNone},
+ UsageTTL: -time.Nanosecond,
+ }
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ idb, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ if err != nil {
+ t.Error(err)
+ }
+ dm := engine.NewDataManager(idb, cfg, nil)
+ fltS := engine.NewFilterS(cfg, nil, dm)
+ rs := NewResourceService(dm, cfg, fltS, nil)
+ if err := dm.SetResourceProfile(context.TODO(), rProf, true); err != nil {
+ t.Fatal(err)
+ }
+ if err := dm.SetResource(context.TODO(), &utils.Resource{
+ Tenant: "cgrates.org",
+ ID: "RL_DB",
+ Usages: map[string]*utils.ResourceUsage{
+ "RU1": { // the resource in DB is expired (should be cleaned when the next allocate is called)
+ Tenant: "cgrates.org",
+ ID: "RU1",
+ ExpiryTime: time.Date(2014, 7, 3, 13, 43, 0, 1, time.UTC),
+ Units: 1,
+ },
+ },
+ TTLIdx: []string{"RU1"},
+ }); err != nil { // simulate how the resource is stored in redis or mongo(non-exported fields are not populated)
+ t.Fatal(err)
+ }
+ var reply string
+ exp := rProf.ID
+ if err := rs.V1AllocateResources(context.TODO(), &utils.CGREvent{
+ Tenant: "cgrates.org",
+ ID: "ef0f554",
+ Event: map[string]any{"": ""},
+ APIOpts: map[string]any{
+ "Resource": "RL_DB",
+ utils.OptsResourcesUsageID: "56156434-2e44-4f16-a766-086f10b413cd",
+ utils.OptsResourcesUnits: 1,
+ },
+ }, &reply); err != nil {
+ t.Fatal(err)
+ } else if reply != exp {
+ t.Errorf("Expected: %q, received: %q", exp, reply)
+ }
+
+}
+
+func TestResourcesV1ResourcesForEventOK(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+ rsPrf := &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ AllocationMessage: "Approved",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: 10,
+ UsageTTL: time.Minute,
+ }
+ rs := &utils.Resource{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ TTLIdx: []string{},
+ Usages: map[string]*utils.ResourceUsage{
+ "RU1": {
+ Tenant: "cgrates.org",
+ ID: "RU1",
+ Units: 10,
+ },
+ },
+ }
+ err := dm.SetResourceProfile(context.Background(), rsPrf, true)
+ if err != nil {
+ t.Error(err)
+ }
+ err = dm.SetResource(context.Background(), rs)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "ResourcesForEventTest",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_TEST1",
+ },
+ }
+
+ exp := Resources{
+ {
+ Resource: &utils.Resource{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ TTLIdx: []string{},
+ Usages: map[string]*utils.ResourceUsage{
+ "RU1": {
+ Tenant: "cgrates.org",
+ ID: "RU1",
+ Units: 10,
+ },
+ },
+ },
+ rPrf: &resourceProfile{ResourceProfile: rsPrf},
+ ttl: utils.DurationPointer(72 * time.Hour),
+ },
+ }
+ var reply Resources
+ if err := rS.V1GetResourcesForEvent(context.Background(), args, &reply); err != nil {
+ t.Error(err)
+ } else if !reflect.DeepEqual(reply, exp) {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>",
+ utils.ToJSON(exp), utils.ToJSON(reply))
+ }
+}
+
+func TestResourcesV1ResourcesForEventNotFound(t *testing.T) {
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ rsPrf := &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: 10,
+ UsageTTL: time.Minute,
+ }
+ rs := &utils.Resource{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ Usages: map[string]*utils.ResourceUsage{
+ "RU1": {
+ Tenant: "cgrates.org",
+ ID: "RU1",
+ Units: 10,
+ },
+ },
+ }
+ err := dm.SetResourceProfile(context.Background(), rsPrf, true)
+ if err != nil {
+ t.Error(err)
+ }
+ err = dm.SetResource(context.Background(), rs)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ Tenant: "cgrates.org",
+ ID: "ResourcesForEventTest",
+ Event: map[string]any{
+ utils.AccountField: "1002",
+ },
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_TEST1",
+ },
+ }
+
+ var reply Resources
+ if err := rS.V1GetResourcesForEvent(context.Background(), args, &reply); err == nil ||
+ err.Error() != utils.ErrNotFound.Error() {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err)
+ }
+}
+
+func TestResourcesV1ResourcesForEventMissingParameters(t *testing.T) {
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ rsPrf := &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: 10,
+ UsageTTL: time.Minute,
+ }
+ rs := &utils.Resource{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ Usages: map[string]*utils.ResourceUsage{
+ "RU1": {
+ Tenant: "cgrates.org",
+ ID: "RU1",
+ Units: 10,
+ },
+ },
+ }
+ err := dm.SetResourceProfile(context.Background(), rsPrf, true)
+ if err != nil {
+ t.Error(err)
+ }
+ err = dm.SetResource(context.Background(), rs)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ experr := `MANDATORY_IE_MISSING: [Event]`
+ var reply Resources
+ if err := rS.V1GetResourcesForEvent(context.Background(), nil, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+
+ args := &utils.CGREvent{
+ Tenant: "cgrates.org",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_TEST2",
+ },
+ }
+
+ experr = `MANDATORY_IE_MISSING: [ID]`
+ if err := rS.V1GetResourcesForEvent(context.Background(), args, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+
+ args = &utils.CGREvent{
+ Tenant: "cgrates.org",
+ ID: "ResourcesForEventTest",
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_TEST3",
+ },
+ }
+
+ experr = `MANDATORY_IE_MISSING: [Event]`
+ if err := rS.V1GetResourcesForEvent(context.Background(), args, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+
+ args = &utils.CGREvent{
+ Tenant: "cgrates.org",
+ ID: "ResourcesForEventTest",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ }
+
+ experr = `MANDATORY_IE_MISSING: [UsageID]`
+ if err := rS.V1GetResourcesForEvent(context.Background(), args, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+}
+
+func TestResourcesV1ResourcesForEventCacheReplyExists(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
+ config.SetCgrConfig(cfg)
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+ cacheKey := utils.ConcatenatedKey(utils.ResourceSv1GetResourcesForEvent,
+ utils.ConcatenatedKey("cgrates.org", "ResourcesForEventTest"))
+ rsPrf := &resourceProfile{
+ ResourceProfile: &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ AllocationMessage: "Approved",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: 10,
+ UsageTTL: time.Minute,
+ },
+ }
+ rs := &utils.Resource{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ Usages: map[string]*utils.ResourceUsage{
+ "RU1": {
+ Tenant: "cgrates.org",
+ ID: "RU1",
+ Units: 10,
+ },
+ },
+ TTLIdx: []string{},
+ }
+ err := dm.SetResourceProfile(context.Background(), rsPrf.ResourceProfile, true)
+ if err != nil {
+ t.Error(err)
+ }
+ err = dm.SetResource(context.Background(), rs)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "ResourcesForEventTest",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_TEST1",
+ },
+ }
+
+ cacheReply := Resources{
+ {
+ Resource: &utils.Resource{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ Usages: map[string]*utils.ResourceUsage{
+ "RU1": {
+ Tenant: "cgrates.org",
+ ID: "RU1",
+ Units: 10,
+ },
+ },
+ TTLIdx: []string{},
+ },
+ rPrf: rsPrf,
+ dirty: utils.BoolPointer(false),
+ tUsage: utils.Float64Pointer(10),
+ ttl: utils.DurationPointer(time.Minute),
+ },
+ }
+ engine.Cache.Set(context.Background(), utils.CacheRPCResponses, cacheKey,
+ &utils.CachedRPCResponse{Result: &cacheReply, Error: nil},
+ nil, true, utils.NonTransactional)
+ var reply Resources
+ if err := rS.V1GetResourcesForEvent(context.Background(), args, &reply); err != nil {
+ t.Error(err)
+ } else if !reflect.DeepEqual(reply, cacheReply) {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>",
+ utils.ToJSON(cacheReply), utils.ToJSON(reply))
+ }
+
+ config.SetCgrConfig(config.NewDefaultCGRConfig())
+}
+
+func TestResourcesV1ResourcesForEventCacheReplySet(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
+ config.SetCgrConfig(cfg)
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+ cacheKey := utils.ConcatenatedKey(utils.ResourceSv1GetResourcesForEvent,
+ utils.ConcatenatedKey("cgrates.org", "ResourcesForEventTest"))
+ rsPrf := &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ AllocationMessage: "Approved",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: 10,
+ UsageTTL: time.Minute,
+ }
+ rs := &utils.Resource{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ Usages: map[string]*utils.ResourceUsage{
+ "RU1": {
+ Tenant: "cgrates.org",
+ ID: "RU1",
+ Units: 10,
+ },
+ },
+ TTLIdx: []string{},
+ }
+ err := dm.SetResourceProfile(context.Background(), rsPrf, true)
+ if err != nil {
+ t.Error(err)
+ }
+ err = dm.SetResource(context.Background(), rs)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "ResourcesForEventTest",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_TEST1",
+ },
+ }
+
+ exp := &Resources{
+ {
+ Resource: &utils.Resource{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ Usages: map[string]*utils.ResourceUsage{
+ "RU1": {
+ Tenant: "cgrates.org",
+ ID: "RU1",
+ Units: 10,
+ },
+ },
+ TTLIdx: []string{},
+ },
+ ttl: utils.DurationPointer(72 * time.Hour),
+ rPrf: &resourceProfile{
+ ResourceProfile: rsPrf,
+ },
+ },
+ }
+ var reply Resources
+ if err := rS.V1GetResourcesForEvent(context.Background(), args, &reply); err != nil {
+ t.Error(err)
+ } else if !reflect.DeepEqual(reply, *exp) {
+ t.Errorf("expected: <%v>, received: <%v>", exp, reply)
+ }
+
+ if itm, has := engine.Cache.Get(utils.CacheRPCResponses, cacheKey); has {
+ resp := itm.(*utils.CachedRPCResponse)
+ if !reflect.DeepEqual(resp.Result, exp) {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ToJSON(exp), utils.ToJSON(resp.Result))
+ }
+ }
+
+ config.SetCgrConfig(config.NewDefaultCGRConfig())
+}
+
+func TestResourcesV1GetResourceOK(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+
+ rs := &utils.Resource{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ Usages: map[string]*utils.ResourceUsage{
+ "RU1": {
+ Tenant: "cgrates.org",
+ ID: "RU1",
+ Units: 10,
+ },
+ },
+ TTLIdx: []string{},
+ }
+ err := dm.SetResource(context.Background(), rs)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ exp := utils.Resource{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ TTLIdx: []string{},
+ Usages: map[string]*utils.ResourceUsage{
+ "RU1": {
+ Tenant: "cgrates.org",
+ ID: "RU1",
+ Units: 10,
+ },
+ },
+ }
+
+ args := &utils.TenantIDWithAPIOpts{
+ TenantID: &utils.TenantID{
+ ID: "RES1",
+ },
+ }
+ var reply utils.Resource
+ if err := rS.V1GetResource(context.Background(), args, &reply); err != nil {
+ t.Error(err)
+ } else if !reflect.DeepEqual(reply, exp) {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>",
+ utils.ToJSON(exp), utils.ToJSON(reply))
+ }
+}
+
+func TestResourcesV1GetResourceNotFound(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+
+ rs := &utils.Resource{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ Usages: map[string]*utils.ResourceUsage{
+ "RU1": {
+ Tenant: "cgrates.org",
+ ID: "RU1",
+ Units: 10,
+ },
+ },
+ TTLIdx: []string{},
+ }
+ err := dm.SetResource(context.Background(), rs)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.TenantIDWithAPIOpts{
+ TenantID: &utils.TenantID{
+ Tenant: "cgrates.org",
+ ID: "RES2",
+ },
+ }
+ var reply utils.Resource
+ if err := rS.V1GetResource(context.Background(), args, &reply); err == nil ||
+ err.Error() != utils.ErrNotFound.Error() {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err)
+ }
+}
+
+func TestResourcesV1GetResourceMissingParameters(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+
+ rs := &utils.Resource{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ Usages: map[string]*utils.ResourceUsage{
+ "RU1": {
+ Tenant: "cgrates.org",
+ ID: "RU1",
+ Units: 10,
+ },
+ },
+ TTLIdx: []string{},
+ }
+ err := dm.SetResource(context.Background(), rs)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.TenantIDWithAPIOpts{
+ TenantID: &utils.TenantID{},
+ }
+
+ experr := `MANDATORY_IE_MISSING: [ID]`
+ var reply utils.Resource
+ if err := rS.V1GetResource(context.Background(), args, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+}
+
+func TestResourcesV1GetResourceWithConfigOK(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+
+ rsPrf := &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ AllocationMessage: "Approved",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: 10,
+ UsageTTL: time.Minute,
+ }
+ err := dm.SetResourceProfile(context.Background(), rsPrf, true)
+ if err != nil {
+ t.Error(err)
+ }
+ rs := &utils.Resource{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ Usages: map[string]*utils.ResourceUsage{
+ "RU1": {
+ Tenant: "cgrates.org",
+ ID: "RU1",
+ Units: 10,
+ },
+ },
+ TTLIdx: []string{},
+ }
+ err = dm.SetResource(context.Background(), rs)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ exp := utils.ResourceWithConfig{
+ Resource: &utils.Resource{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ Usages: map[string]*utils.ResourceUsage{
+ "RU1": {
+ Tenant: "cgrates.org",
+ ID: "RU1",
+ Units: 10,
+ },
+ },
+ TTLIdx: []string{},
+ },
+ Config: rsPrf,
+ }
+
+ args := &utils.TenantIDWithAPIOpts{
+ TenantID: &utils.TenantID{
+ ID: "RES1",
+ },
+ }
+ var reply utils.ResourceWithConfig
+ if err := rS.V1GetResourceWithConfig(context.Background(), args, &reply); err != nil {
+ t.Error(err)
+ } else if !reflect.DeepEqual(reply, exp) {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>",
+ utils.ToJSON(exp), utils.ToJSON(reply))
+ }
+}
+
+func TestResourcesV1GetResourceWithConfigNilrPrfProfileNotFound(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+
+ rsPrf := &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES2",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ AllocationMessage: "Approved",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: 10,
+ UsageTTL: time.Minute,
+ }
+ err := dm.SetResourceProfile(context.Background(), rsPrf, true)
+ if err != nil {
+ t.Error(err)
+ }
+ rs := &utils.Resource{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ Usages: map[string]*utils.ResourceUsage{
+ "RU1": {
+ Tenant: "cgrates.org",
+ ID: "RU1",
+ Units: 10,
+ },
+ },
+ TTLIdx: []string{},
+ }
+ err = dm.SetResource(context.Background(), rs)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.TenantIDWithAPIOpts{
+ TenantID: &utils.TenantID{
+ ID: "RES1",
+ },
+ }
+ var reply utils.ResourceWithConfig
+ if err := rS.V1GetResourceWithConfig(context.Background(), args, &reply); err == nil ||
+ err != utils.ErrNotFound {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err)
+ }
+}
+
+func TestResourcesV1GetResourceWithConfigResourceNotFound(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+
+ rs := &utils.Resource{
+ Tenant: "cgrates.org",
+ ID: "RES2",
+ Usages: map[string]*utils.ResourceUsage{
+ "RU1": {
+ Tenant: "cgrates.org",
+ ID: "RU1",
+ Units: 10,
+ },
+ },
+ TTLIdx: []string{},
+ }
+ err := dm.SetResource(context.Background(), rs)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.TenantIDWithAPIOpts{
+ TenantID: &utils.TenantID{
+ ID: "RES1",
+ },
+ }
+ var reply utils.ResourceWithConfig
+ if err := rS.V1GetResourceWithConfig(context.Background(), args, &reply); err == nil || err != utils.ErrNotFound {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err)
+ }
+}
+
+func TestResourcesV1GetResourceWithConfigMissingParameters(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+
+ rs := &utils.Resource{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ Usages: map[string]*utils.ResourceUsage{
+ "RU1": {
+ Tenant: "cgrates.org",
+ ID: "RU1",
+ Units: 10,
+ },
+ },
+ TTLIdx: []string{},
+ }
+ err := dm.SetResource(context.Background(), rs)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ experr := `MANDATORY_IE_MISSING: [ID]`
+ args := &utils.TenantIDWithAPIOpts{
+ TenantID: &utils.TenantID{},
+ }
+ var reply utils.ResourceWithConfig
+ if err := rS.V1GetResourceWithConfig(context.Background(), args, &reply); err == nil || err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+}
+
+func TestResourcesV1AuthorizeResourcesOK(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+
+ rsPrf := &resourceProfile{
+ ResourceProfile: &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ AllocationMessage: "Approved",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: 10,
+ UsageTTL: time.Minute,
+ },
+ }
+
+ err := dm.SetResourceProfile(context.Background(), rsPrf.ResourceProfile, true)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "EventAuthorizeResource",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_Test",
+ utils.OptsResourcesUnits: 5,
+ utils.OptsResourcesUsageTTL: time.Minute,
+ },
+ }
+ var reply string
+
+ if err := rS.V1AuthorizeResources(context.Background(), args, &reply); err != nil {
+ t.Error(err)
+ } else if reply != "Approved" {
+ t.Errorf("Unexpected reply returned: %q", reply)
+ }
+}
+
+func TestResourcesV1AuthorizeResourcesNotAuthorized(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+
+ rsPrf := &resourceProfile{
+ ResourceProfile: &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ AllocationMessage: "Approved",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: 0,
+ UsageTTL: time.Minute,
+ },
+ }
+
+ err := dm.SetResourceProfile(context.Background(), rsPrf.ResourceProfile, true)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ Tenant: "cgrates.org",
+ ID: "EventAuthorizeResource",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_Test",
+ utils.OptsResourcesUnits: 5,
+ utils.OptsResourcesUsageTTL: time.Minute,
+ },
+ }
+ var reply string
+
+ if err := rS.V1AuthorizeResources(context.Background(), args, &reply); err == nil ||
+ err != utils.ErrResourceUnauthorized {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrResourceUnauthorized, err)
+ }
+}
+
+func TestResourcesV1AuthorizeResourcesNoMatch(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+
+ rsPrf := &resourceProfile{
+ ResourceProfile: &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ AllocationMessage: "Approved",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: 10,
+ UsageTTL: time.Minute,
+ },
+ }
+
+ err := dm.SetResourceProfile(context.Background(), rsPrf.ResourceProfile, true)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ Tenant: "cgrates.org",
+ ID: "EventAuthorizeResource",
+ Event: map[string]any{
+ utils.AccountField: "1002",
+ },
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_Test",
+ utils.OptsResourcesUnits: 5,
+ utils.OptsResourcesUsageTTL: time.Minute,
+ },
+ }
+ var reply string
+
+ if err := rS.V1AuthorizeResources(context.Background(), args, &reply); err == nil ||
+ err != utils.ErrNotFound {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err)
+ }
+}
+
+func TestResourcesV1AuthorizeResourcesNilCGREvent(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+
+ rsPrf := &resourceProfile{
+ ResourceProfile: &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ AllocationMessage: "Approved",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: 10,
+ UsageTTL: time.Minute,
+ },
+ }
+
+ err := dm.SetResourceProfile(context.Background(), rsPrf.ResourceProfile, true)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ experr := `MANDATORY_IE_MISSING: [Event]`
+ var reply string
+
+ if err := rS.V1AuthorizeResources(context.Background(), nil, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+}
+
+func TestResourcesV1AuthorizeResourcesMissingUsageID(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+
+ rsPrf := &resourceProfile{
+ ResourceProfile: &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ AllocationMessage: "Approved",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: 10,
+ UsageTTL: time.Minute,
+ },
+ }
+
+ err := dm.SetResourceProfile(context.Background(), rsPrf.ResourceProfile, true)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "EventAuthorizeResource",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ utils.OptsResourcesUnits: 5,
+ utils.OptsResourcesUsageTTL: time.Minute,
+ },
+ }
+ experr := `MANDATORY_IE_MISSING: [UsageID]`
+ var reply string
+
+ if err := rS.V1AuthorizeResources(context.Background(), args, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+}
+
+func TestResourcesV1AuthorizeResourcesCacheReplyExists(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
+ config.SetCgrConfig(cfg)
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+ cacheKey := utils.ConcatenatedKey(utils.ResourceSv1AuthorizeResources,
+ utils.ConcatenatedKey("cgrates.org", "EventAuthorizeResource"))
+
+ rsPrf := &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ AllocationMessage: "Approved",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: 10,
+ UsageTTL: time.Minute,
+ }
+ rs := &utils.Resource{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ Usages: map[string]*utils.ResourceUsage{
+ "RU1": {
+ Tenant: "cgrates.org",
+ ID: "RU1",
+ Units: 10,
+ },
+ },
+ TTLIdx: []string{},
+ }
+
+ err := dm.SetResourceProfile(context.Background(), rsPrf, true)
+ if err != nil {
+ t.Error(err)
+ }
+ err = dm.SetResource(context.Background(), rs)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "EventAuthorizeResource",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_Test",
+ utils.OptsResourcesUnits: 5,
+ utils.OptsResourcesUsageTTL: time.Minute,
+ },
+ }
+
+ cacheReply := "Approved"
+ engine.Cache.Set(context.Background(), utils.CacheRPCResponses, cacheKey,
+ &utils.CachedRPCResponse{Result: &cacheReply, Error: nil},
+ nil, true, utils.NonTransactional)
+
+ var reply string
+ if err := rS.V1AuthorizeResources(context.Background(), args, &reply); err != nil {
+ t.Error(err)
+ } else if reply != cacheReply {
+ t.Errorf("Unexpected reply returned: %q", reply)
+ }
+ config.SetCgrConfig(config.NewDefaultCGRConfig())
+}
+
+func TestResourcesV1AuthorizeResourcesCacheReplySet(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
+ config.SetCgrConfig(cfg)
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+ cacheKey := utils.ConcatenatedKey(utils.ResourceSv1AuthorizeResources,
+ utils.ConcatenatedKey("cgrates.org", "EventAuthorizeResource"))
+
+ rsPrf := &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ AllocationMessage: "Approved",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: -1,
+ UsageTTL: time.Minute,
+ }
+ rs := &utils.Resource{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ Usages: map[string]*utils.ResourceUsage{
+ "RU1": {
+ Tenant: "cgrates.org",
+ ID: "RU1",
+ Units: 4,
+ },
+ },
+ TTLIdx: []string{},
+ }
+
+ err := dm.SetResourceProfile(context.Background(), rsPrf, true)
+ if err != nil {
+ t.Error(err)
+ }
+ err = dm.SetResource(context.Background(), rs)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "EventAuthorizeResource",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_Test",
+ utils.OptsResourcesUnits: 2,
+ utils.OptsResourcesUsageTTL: time.Minute,
+ },
+ }
+
+ var reply string
+ if err := rS.V1AuthorizeResources(context.Background(), args, &reply); err != nil {
+ t.Error(err)
+ } else if reply != "Approved" {
+ t.Errorf("Unexpected reply returned: %q", reply)
+ }
+
+ if itm, has := engine.Cache.Get(utils.CacheRPCResponses, cacheKey); has {
+ resp := itm.(*utils.CachedRPCResponse)
+ if *resp.Result.(*string) != "Approved" {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>",
+ "Approved", *resp.Result.(*string))
+ }
+ }
+
+ config.SetCgrConfig(config.NewDefaultCGRConfig())
+}
+
+func TestResourcesV1AllocateResourcesOK(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+
+ rsPrf := &resourceProfile{
+ ResourceProfile: &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ AllocationMessage: "Approved",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: 10,
+ UsageTTL: time.Minute,
+ },
+ }
+
+ err := dm.SetResourceProfile(context.Background(), rsPrf.ResourceProfile, true)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "EventAuthorizeResource",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_Test",
+ utils.OptsResourcesUnits: 5,
+ utils.OptsResourcesUsageTTL: time.Minute,
+ },
+ }
+ var reply string
+
+ if err := rS.V1AllocateResources(context.Background(), args, &reply); err != nil {
+ t.Error(err)
+ } else if reply != "Approved" {
+ t.Errorf("Unexpected reply returned: %q", reply)
+ }
+}
+
+func TestResourcesV1AllocateResourcesNoMatch(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+
+ rsPrf := &resourceProfile{
+ ResourceProfile: &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ AllocationMessage: "Approved",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: 10,
+ UsageTTL: time.Minute,
+ },
+ }
+
+ err := dm.SetResourceProfile(context.Background(), rsPrf.ResourceProfile, true)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "EventAuthorizeResource",
+ Event: map[string]any{
+ utils.AccountField: "1002",
+ },
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_Test",
+ utils.OptsResourcesUnits: 5,
+ utils.OptsResourcesUsageTTL: time.Minute,
+ },
+ }
+ var reply string
+
+ if err := rS.V1AllocateResources(context.Background(), args, &reply); err == nil ||
+ err != utils.ErrNotFound {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err)
+ }
+}
+
+func TestResourcesV1AllocateResourcesMissingParameters(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+
+ rsPrf := &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ AllocationMessage: "Approved",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: 10,
+ UsageTTL: time.Minute,
+ }
+
+ err := dm.SetResourceProfile(context.Background(), rsPrf, true)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "EventAuthorizeResource",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ utils.OptsResourcesUnits: 5,
+ utils.OptsResourcesUsageTTL: time.Minute,
+ },
+ }
+ var reply string
+
+ experr := `MANDATORY_IE_MISSING: [UsageID]`
+ if err := rS.V1AllocateResources(context.Background(), args, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+
+ args = &utils.CGREvent{
+ ID: "EventAuthorizeResource",
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_Test",
+ utils.OptsResourcesUnits: 5,
+ utils.OptsResourcesUsageTTL: time.Minute,
+ },
+ }
+
+ experr = `MANDATORY_IE_MISSING: [Event]`
+ if err := rS.V1AllocateResources(context.Background(), args, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+
+ args = &utils.CGREvent{
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_Test",
+ utils.OptsResourcesUnits: 5,
+ utils.OptsResourcesUsageTTL: time.Minute,
+ },
+ }
+
+ experr = `MANDATORY_IE_MISSING: [ID]`
+ if err := rS.V1AllocateResources(context.Background(), args, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+
+ experr = `MANDATORY_IE_MISSING: [Event]`
+ if err := rS.V1AllocateResources(context.Background(), nil, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+}
+
+func TestResourcesV1AllocateResourcesCacheReplyExists(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
+ config.SetCgrConfig(cfg)
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+ cacheKey := utils.ConcatenatedKey(utils.ResourceSv1AllocateResources,
+ utils.ConcatenatedKey("cgrates.org", "EventAllocateResource"))
+
+ rsPrf := &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ AllocationMessage: "Approved",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: -1,
+ UsageTTL: time.Minute,
+ }
+ rs := &utils.Resource{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ Usages: map[string]*utils.ResourceUsage{
+ "RU1": {
+ Tenant: "cgrates.org",
+ ID: "RU1",
+ Units: 10,
+ },
+ },
+ TTLIdx: []string{},
+ }
+
+ err := dm.SetResourceProfile(context.Background(), rsPrf, true)
+ if err != nil {
+ t.Error(err)
+ }
+ err = dm.SetResource(context.Background(), rs)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "EventAllocateResource",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_Test",
+ utils.OptsResourcesUnits: 5,
+ utils.OptsResourcesUsageTTL: time.Minute,
+ },
+ }
+
+ cacheReply := "cacheApproved"
+ engine.Cache.Set(context.Background(), utils.CacheRPCResponses, cacheKey,
+ &utils.CachedRPCResponse{Result: &cacheReply, Error: nil},
+ nil, true, utils.NonTransactional)
+
+ var reply string
+ if err := rS.V1AllocateResources(context.Background(), args, &reply); err != nil {
+ t.Error(err)
+ } else if reply != cacheReply {
+ t.Errorf("Unexpected reply returned: %q", reply)
+ }
+ config.SetCgrConfig(config.NewDefaultCGRConfig())
+}
+
+func TestResourcesV1AllocateResourcesCacheReplySet(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
+ config.SetCgrConfig(cfg)
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+ cacheKey := utils.ConcatenatedKey(utils.ResourceSv1AllocateResources,
+ utils.ConcatenatedKey("cgrates.org", "EventAllocateResource"))
+
+ rsPrf := &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ AllocationMessage: "Approved",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: -1,
+ UsageTTL: time.Minute,
+ }
+ rs := &utils.Resource{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ Usages: map[string]*utils.ResourceUsage{
+ "RU1": {
+ Tenant: "cgrates.org",
+ ID: "RU1",
+ Units: 4,
+ },
+ },
+ TTLIdx: []string{},
+ }
+
+ err := dm.SetResourceProfile(context.Background(), rsPrf, true)
+ if err != nil {
+ t.Error(err)
+ }
+ err = dm.SetResource(context.Background(), rs)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "EventAllocateResource",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_Test",
+ utils.OptsResourcesUnits: 2,
+ utils.OptsResourcesUsageTTL: time.Minute,
+ },
+ }
+
+ var reply string
+ if err := rS.V1AllocateResources(context.Background(), args, &reply); err != nil {
+ t.Error(err)
+ } else if reply != "Approved" {
+ t.Errorf("Unexpected reply returned: %q", reply)
+ }
+
+ if itm, has := engine.Cache.Get(utils.CacheRPCResponses, cacheKey); has {
+ resp := itm.(*utils.CachedRPCResponse)
+ if *resp.Result.(*string) != "Approved" {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>",
+ "Approved", *resp.Result.(*string))
+ }
+ }
+
+ config.SetCgrConfig(config.NewDefaultCGRConfig())
+}
+
+func TestResourcesV1AllocateResourcesResAllocErr(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+
+ rsPrf := &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ AllocationMessage: "",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: -1,
+ UsageTTL: time.Minute,
+ }
+ err := dm.SetResourceProfile(context.Background(), rsPrf, true)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "EventAuthorizeResource",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_Test",
+ utils.OptsResourcesUnits: 5,
+ utils.OptsResourcesUsageTTL: time.Minute,
+ },
+ }
+ var reply string
+
+ if err := rS.V1AllocateResources(context.Background(), args, &reply); err == nil ||
+ err != utils.ErrResourceUnavailable {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrResourceUnavailable, err)
+ }
+}
+
+type ccMock struct {
+ calls map[string]func(ctx *context.Context, args any, reply any) error
+}
+
+func (ccM *ccMock) Call(ctx *context.Context, serviceMethod string, args any, reply any) (err error) {
+ if call, has := ccM.calls[serviceMethod]; !has {
+ return rpcclient.ErrUnsupporteServiceMethod
+ } else {
+ return call(ctx, args, reply)
+ }
+}
+
+func TestResourcesV1AllocateResourcesProcessThErr(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.ResourceSCfg().StoreInterval = 2
+ cfg.ResourceSCfg().ThresholdSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds)}
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+
+ rsPrf := &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds)},
+ AllocationMessage: "Approved",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: -1,
+ UsageTTL: time.Minute,
+ }
+ rs := &utils.Resource{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ Usages: map[string]*utils.ResourceUsage{
+ "RU1": {
+ Tenant: "cgrates.org",
+ ID: "RU1",
+ Units: 10,
+ },
+ },
+ TTLIdx: []string{},
+ }
+
+ err := dm.SetResourceProfile(context.Background(), rsPrf, true)
+ if err != nil {
+ t.Error(err)
+ }
+ err = dm.SetResource(context.Background(), rs)
+ if err != nil {
+ t.Error(err)
+ }
+
+ ccM := &ccMock{
+ calls: map[string]func(ctx *context.Context, args any, reply any) error{
+ utils.ThresholdSv1ProcessEvent: func(ctx *context.Context, args, reply any) error {
+ return utils.ErrExists
+ },
+ },
+ }
+ rpcInternal := make(chan birpc.ClientConnector, 1)
+ rpcInternal <- ccM
+ cM := engine.NewConnManager(cfg)
+ cM.AddInternalConn(utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds), utils.ThresholdSv1, rpcInternal)
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, cM)
+
+ args := &utils.CGREvent{
+ ID: "EventAuthorizeResource",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_Test",
+ utils.OptsResourcesUnits: 5,
+ utils.OptsResourcesUsageTTL: time.Minute,
+ },
+ }
+ var reply string
+
+ if err := rS.V1AllocateResources(context.Background(), args, &reply); err == nil ||
+ err != utils.ErrPartiallyExecuted {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrPartiallyExecuted, err)
+ }
+ dm.DataDB().Flush(utils.EmptyString)
+}
+
+func TestResourcesV1ReleaseResourcesOK(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+
+ rsPrf := &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ AllocationMessage: "Approved",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: 10,
+ UsageTTL: time.Minute,
+ }
+
+ err := dm.SetResourceProfile(context.Background(), rsPrf, true)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "EventAuthorizeResource",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_Test",
+ utils.OptsResourcesUnits: 5,
+ utils.OptsResourcesUsageTTL: time.Minute,
+ },
+ }
+ var reply string
+ if err := rS.V1AllocateResources(context.Background(), args, &reply); err != nil {
+ t.Error(err)
+ } else if reply != "Approved" {
+ t.Errorf("Unexpected reply returned: %q", reply)
+ }
+
+ if err := rS.V1ReleaseResources(context.Background(), args, &reply); err != nil {
+ t.Error(err)
+ } else if reply != utils.OK {
+ t.Errorf("Unexpected reply returned: %q", reply)
+ }
+}
+
+func TestResourcesV1ReleaseResourcesUsageNotFound(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+
+ rsPrf := &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ AllocationMessage: "Approved",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: 10,
+ UsageTTL: 0,
+ }
+
+ err := dm.SetResourceProfile(context.Background(), rsPrf, true)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "EventAuthorizeResource",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_Test",
+ utils.OptsResourcesUnits: 5,
+ utils.OptsResourcesUsageTTL: time.Minute,
+ },
+ }
+ var reply string
+ if err := rS.V1AllocateResources(context.Background(), args, &reply); err != nil {
+ t.Error(err)
+ } else if reply != "Approved" {
+ t.Errorf("Unexpected reply returned: %q", reply)
+ }
+
+ args = &utils.CGREvent{
+ ID: "EventAuthorizeResource",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_Test2",
+ utils.OptsResourcesUnits: 5,
+ utils.OptsResourcesUsageTTL: time.Minute,
+ },
+ }
+
+ experr := `cannot find usage record with id: RU_Test2`
+ if err := rS.V1ReleaseResources(context.Background(), args, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+}
+
+func TestResourcesV1ReleaseResourcesNoMatch(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+
+ rsPrf := &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ AllocationMessage: "Approved",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: 10,
+ UsageTTL: time.Minute,
+ }
+
+ err := dm.SetResourceProfile(context.Background(), rsPrf, true)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "EventAuthorizeResource",
+ Event: map[string]any{
+ utils.AccountField: "1002",
+ },
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_Test",
+ utils.OptsResourcesUnits: 5,
+ utils.OptsResourcesUsageTTL: time.Minute,
+ },
+ }
+ var reply string
+
+ if err := rS.V1ReleaseResources(context.Background(), args, &reply); err == nil ||
+ err != utils.ErrNotFound {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err)
+ }
+}
+
+func TestResourcesV1ReleaseResourcesMissingParameters(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+
+ rsPrf := &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ AllocationMessage: "Approved",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: 10,
+ UsageTTL: time.Minute,
+ }
+
+ err := dm.SetResourceProfile(context.Background(), rsPrf, true)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "EventAuthorizeResource",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ utils.OptsResourcesUnits: 5,
+ utils.OptsResourcesUsageTTL: time.Minute,
+ },
+ }
+ var reply string
+
+ experr := `MANDATORY_IE_MISSING: [UsageID]`
+ if err := rS.V1ReleaseResources(context.Background(), args, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+
+ args = &utils.CGREvent{
+ ID: "EventAuthorizeResource",
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_Test",
+ utils.OptsResourcesUnits: 5,
+ utils.OptsResourcesUsageTTL: time.Minute,
+ },
+ }
+
+ experr = `MANDATORY_IE_MISSING: [Event]`
+ if err := rS.V1ReleaseResources(context.Background(), args, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+
+ args = &utils.CGREvent{
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_Test",
+ utils.OptsResourcesUnits: 5,
+ utils.OptsResourcesUsageTTL: time.Minute,
+ },
+ }
+
+ experr = `MANDATORY_IE_MISSING: [ID]`
+ if err := rS.V1ReleaseResources(context.Background(), args, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+
+ experr = `MANDATORY_IE_MISSING: [Event]`
+ if err := rS.V1ReleaseResources(context.Background(), nil, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+}
+
+func TestResourcesV1ReleaseResourcesCacheReplyExists(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
+ config.SetCgrConfig(cfg)
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+ cacheKey := utils.ConcatenatedKey(utils.ResourceSv1ReleaseResources,
+ utils.ConcatenatedKey("cgrates.org", "EventReleaseResource"))
+
+ rsPrf := &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ AllocationMessage: "Approved",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: -1,
+ UsageTTL: time.Minute,
+ }
+ rs := &utils.Resource{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ Usages: map[string]*utils.ResourceUsage{
+ "RU1": {
+ Tenant: "cgrates.org",
+ ID: "RU1",
+ Units: 10,
+ },
+ },
+ TTLIdx: []string{},
+ }
+
+ err := dm.SetResourceProfile(context.Background(), rsPrf, true)
+ if err != nil {
+ t.Error(err)
+ }
+ err = dm.SetResource(context.Background(), rs)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ Tenant: "cgrates.org",
+ ID: "EventReleaseResource",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_Test",
+ utils.OptsResourcesUnits: 5,
+ utils.OptsResourcesUsageTTL: time.Minute,
+ },
+ }
+ cacheReply := "cacheReply"
+ engine.Cache.Set(context.Background(), utils.CacheRPCResponses, cacheKey,
+ &utils.CachedRPCResponse{Result: &cacheReply, Error: nil},
+ nil, true, utils.NonTransactional)
+
+ var reply string
+ if err := rS.V1ReleaseResources(context.Background(), args, &reply); err != nil {
+ t.Error(err)
+ } else if reply != cacheReply {
+ t.Errorf("Unexpected reply returned: %q", reply)
+ }
+ config.SetCgrConfig(config.NewDefaultCGRConfig())
+}
+
+func TestResourcesV1ReleaseResourcesCacheReplySet(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
+ config.SetCgrConfig(cfg)
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+ cacheKey := utils.ConcatenatedKey(utils.ResourceSv1ReleaseResources,
+ utils.ConcatenatedKey("cgrates.org", "EventReleaseResource"))
+
+ rsPrf := &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ AllocationMessage: "Approved",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: -1,
+ UsageTTL: time.Minute,
+ }
+ rs := &utils.Resource{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ Usages: map[string]*utils.ResourceUsage{
+ "RU1": {
+ Tenant: "cgrates.org",
+ ID: "RU1",
+ Units: 4,
+ },
+ },
+ TTLIdx: []string{},
+ }
+
+ err := dm.SetResourceProfile(context.Background(), rsPrf, true)
+ if err != nil {
+ t.Error(err)
+ }
+ err = dm.SetResource(context.Background(), rs)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "EventReleaseResource",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_Test",
+ utils.OptsResourcesUnits: 2,
+ utils.OptsResourcesUsageTTL: time.Minute,
+ },
+ }
+
+ var reply string
+ experr := `cannot find usage record with id: RU_Test`
+ if err := rS.V1ReleaseResources(context.Background(), args, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+
+ if itm, has := engine.Cache.Get(utils.CacheRPCResponses, cacheKey); has {
+ resp := itm.(*utils.CachedRPCResponse)
+ if *resp.Result.(*string) != "" {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>",
+ "", *resp.Result.(*string))
+ }
+ }
+
+ config.SetCgrConfig(config.NewDefaultCGRConfig())
+}
+
+func TestResourcesV1ReleaseResourcesProcessThErr(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.ResourceSCfg().StoreInterval = 2
+ cfg.ResourceSCfg().ThresholdSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds)}
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+ ccM := &ccMock{
+ calls: map[string]func(ctx *context.Context, args any, reply any) error{
+ utils.ThresholdSv1ProcessEvent: func(ctx *context.Context, args, reply any) error {
+ return utils.ErrExists
+ },
+ },
+ }
+ rpcInternal := make(chan birpc.ClientConnector, 1)
+ rpcInternal <- ccM
+ cM := engine.NewConnManager(cfg)
+ cM.AddInternalConn(utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds), utils.ThresholdSv1, rpcInternal)
+
+ rsPrf := &resourceProfile{
+ ResourceProfile: &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds)},
+ AllocationMessage: "Approved",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: -1,
+ UsageTTL: time.Minute,
+ },
+ }
+ rs := &resource{
+ Resource: &utils.Resource{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ Usages: map[string]*utils.ResourceUsage{
+ "RU_Test": {
+ Tenant: "cgrates.org",
+ ID: "RU_Test",
+ Units: 4,
+ },
+ },
+ TTLIdx: []string{},
+ },
+ dirty: utils.BoolPointer(false),
+ tUsage: utils.Float64Pointer(10),
+ ttl: utils.DurationPointer(time.Minute),
+ rPrf: rsPrf,
+ }
+
+ err := dm.SetResourceProfile(context.Background(), rsPrf.ResourceProfile, true)
+ if err != nil {
+ t.Error(err)
+ }
+ err = dm.SetResource(context.Background(), rs.Resource)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, cM)
+
+ args := &utils.CGREvent{
+ ID: "EventAuthorizeResource",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_Test",
+ utils.OptsResourcesUnits: 5,
+ utils.OptsResourcesUsageTTL: time.Minute,
+ },
+ }
+ var reply string
+ var resources Resources
+ resources = append(resources, rs)
+ if _, err := resources.allocateResource(&utils.ResourceUsage{
+ Tenant: "cgrates.org",
+ ID: "RU_ID",
+ Units: 1}, true); err != nil {
+ t.Error(err)
+ }
+
+ if err := rS.V1ReleaseResources(context.Background(), args, &reply); err == nil ||
+ err != utils.ErrPartiallyExecuted {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrPartiallyExecuted, err)
+ }
+
+ dm.DataDB().Flush(utils.EmptyString)
+}
+
+func TestResourcesStoreResourceError(t *testing.T) {
+ engine.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, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(db, cfg, engine.NewConnManager(cfg))
+
+ rS := NewResourceService(dm, cfg, engine.NewFilterS(cfg, nil, dm), nil)
+
+ rsPrf := &utils.ResourceProfile{
+ Tenant: "cgrates.org",
+ ID: "RES1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ ThresholdIDs: []string{utils.MetaNone},
+ AllocationMessage: "Approved",
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ }},
+ Limit: 10,
+ UsageTTL: time.Minute,
+ Stored: true,
+ }
+
+ err := dm.SetResourceProfile(context.Background(), rsPrf, true)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ args := &utils.CGREvent{
+ ID: "EventAuthorizeResource",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{
+ utils.OptsResourcesUsageID: "RU_Test",
+ utils.OptsResourcesUnits: 5,
+ utils.OptsResourcesUsageTTL: time.Minute,
+ },
+ }
+ cfg.DataDbCfg().Items[utils.MetaResources].Replicate = true
+ var reply string
+ if err := rS.V1AllocateResources(context.Background(), args, &reply); err != utils.ErrDisconnected {
+ t.Error(err)
+ }
+ cfg.DataDbCfg().Items[utils.MetaResources].Replicate = false
+
+ if err := rS.V1AllocateResources(context.Background(), 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(context.Background(), args, &reply); err != utils.ErrDisconnected {
+ t.Error(err)
+ }
+}
+
+func TestResourcesV1ResourcesForEventErrRetrieveUsageID(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.ResourceSCfg().Opts.UsageID = []*config.DynamicStringOpt{
+ config.NewDynamicStringOpt([]string{"FLTR_Invalid"}, "*any", "value", nil),
+ }
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "ResourcesForEventTest",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{},
+ }
+
+ experr := `NOT_FOUND:FLTR_Invalid`
+ var reply Resources
+ if err := rS.V1GetResourcesForEvent(context.Background(), args, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+}
+
+func TestResourcesV1ResourcesForEventErrRetrieveUsageTTL(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.ResourceSCfg().Opts.UsageTTL = []*config.DynamicDurationOpt{
+ config.NewDynamicDurationOpt([]string{"FLTR_Invalid"}, "*any", time.Minute, nil),
+ }
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "ResourcesForEventTest",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{},
+ }
+
+ experr := `NOT_FOUND:FLTR_Invalid`
+ var reply Resources
+ if err := rS.V1GetResourcesForEvent(context.Background(), args, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+}
+
+func TestResourcesV1AuthorizeResourcesErrRetrieveUsageID(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.ResourceSCfg().Opts.UsageID = []*config.DynamicStringOpt{
+ config.NewDynamicStringOpt([]string{"FLTR_Invalid"}, "*any", "value", nil),
+ }
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "ResourcesForEventTest",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{},
+ }
+
+ experr := `NOT_FOUND:FLTR_Invalid`
+ var reply string
+ if err := rS.V1AuthorizeResources(context.Background(), args, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+}
+
+func TestResourcesV1AuthorizeResourcesErrRetrieveUnits(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.ResourceSCfg().Opts.Units = []*config.DynamicFloat64Opt{
+ config.NewDynamicFloat64Opt([]string{"FLTR_Invalid"}, "*any", 3, nil),
+ }
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "ResourcesForEventTest",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{},
+ }
+
+ experr := `NOT_FOUND:FLTR_Invalid`
+ var reply string
+ if err := rS.V1AuthorizeResources(context.Background(), args, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+}
+
+func TestResourcesV1AuthorizeResourcesErrRetrieveUsageTTL(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.ResourceSCfg().Opts.UsageTTL = []*config.DynamicDurationOpt{
+ config.NewDynamicDurationOpt([]string{"FLTR_Invalid"}, "*any", time.Minute, nil),
+ }
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "ResourcesForEventTest",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{},
+ }
+
+ experr := `NOT_FOUND:FLTR_Invalid`
+ var reply string
+ if err := rS.V1AuthorizeResources(context.Background(), args, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+}
+
+func TestResourcesV1AllocateResourcesErrRetrieveUsageID(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.ResourceSCfg().Opts.UsageID = []*config.DynamicStringOpt{
+ config.NewDynamicStringOpt([]string{"FLTR_Invalid"}, "*any", "value", nil),
+ }
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "ResourcesForEventTest",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{},
+ }
+
+ experr := `NOT_FOUND:FLTR_Invalid`
+ var reply string
+ if err := rS.V1AllocateResources(context.Background(), args, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+}
+
+func TestResourcesV1AllocateResourcesErrRetrieveUsageTTL(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.ResourceSCfg().Opts.UsageTTL = []*config.DynamicDurationOpt{
+ config.NewDynamicDurationOpt([]string{"FLTR_Invalid"}, "*any", time.Minute, nil),
+ }
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "ResourcesForEventTest",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{},
+ }
+
+ experr := `NOT_FOUND:FLTR_Invalid`
+ var reply string
+ if err := rS.V1AllocateResources(context.Background(), args, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+}
+
+func TestResourcesV1AllocateResourcesErrRetrieveUnits(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.ResourceSCfg().Opts.Units = []*config.DynamicFloat64Opt{
+ config.NewDynamicFloat64Opt([]string{"FLTR_Invalid"}, "*any", 3, nil),
+ }
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "ResourcesForEventTest",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{},
+ }
+
+ experr := `NOT_FOUND:FLTR_Invalid`
+ var reply string
+ if err := rS.V1AllocateResources(context.Background(), args, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+}
+
+func TestResourcesV1ReleaseResourcesErrRetrieveUsageID(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.ResourceSCfg().Opts.UsageID = []*config.DynamicStringOpt{
+ config.NewDynamicStringOpt([]string{"FLTR_Invalid"}, "*any", "value", nil),
+ }
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "ResourcesForEventTest",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{},
+ }
+
+ experr := `NOT_FOUND:FLTR_Invalid`
+ var reply string
+ if err := rS.V1ReleaseResources(context.Background(), args, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+}
+
+func TestResourcesV1ReleaseResourcesErrRetrieveUsageTTL(t *testing.T) {
+ tmp := engine.Cache
+ defer func() {
+ engine.Cache = tmp
+ }()
+
+ engine.Cache.Clear(nil)
+ cfg := config.NewDefaultCGRConfig()
+ cfg.ResourceSCfg().Opts.UsageTTL = []*config.DynamicDurationOpt{
+ config.NewDynamicDurationOpt([]string{"FLTR_Invalid"}, "*any", time.Minute, nil),
+ }
+ data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
+ dm := engine.NewDataManager(data, cfg, nil)
+ engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
+ fltrs := engine.NewFilterS(cfg, nil, dm)
+ rS := NewResourceService(dm, cfg, fltrs, nil)
+
+ args := &utils.CGREvent{
+ ID: "ResourcesForEventTest",
+ Event: map[string]any{
+ utils.AccountField: "1001",
+ },
+ APIOpts: map[string]any{},
+ }
+
+ experr := `NOT_FOUND:FLTR_Invalid`
+ var reply string
+ if err := rS.V1ReleaseResources(context.Background(), args, &reply); err == nil ||
+ err.Error() != experr {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
+ }
+}
diff --git a/resources/resources.go b/resources/resources.go
index 29791a517..d6256398c 100644
--- a/resources/resources.go
+++ b/resources/resources.go
@@ -589,355 +589,3 @@ func (rS *ResourceS) matchingResourcesForEvent(ctx *context.Context, tnt string,
}
return
}
-
-// V1GetResourcesForEvent returns active resource configs matching the event
-func (rS *ResourceS) V1GetResourcesForEvent(ctx *context.Context, args *utils.CGREvent, reply *Resources) (err error) {
- if args == nil {
- return utils.NewErrMandatoryIeMissing(utils.Event)
- }
- if missing := utils.MissingStructFields(args, []string{utils.ID, utils.Event}); len(missing) != 0 { //Params missing
- return utils.NewErrMandatoryIeMissing(missing...)
- }
-
- var usageID string
- if usageID, err = engine.GetStringOpts(ctx, args.Tenant, args.AsDataProvider(), nil, rS.fltrS, rS.cfg.ResourceSCfg().Opts.UsageID,
- utils.OptsResourcesUsageID); err != nil {
- return
- }
-
- var ttl time.Duration
- if ttl, err = engine.GetDurationOpts(ctx, args.Tenant, args.AsDataProvider(), nil, rS.fltrS, rS.cfg.ResourceSCfg().Opts.UsageTTL,
- utils.OptsResourcesUsageTTL); err != nil {
- return
- }
- usageTTL := utils.DurationPointer(ttl)
-
- if usageID == utils.EmptyString {
- return utils.NewErrMandatoryIeMissing(utils.UsageID)
- }
- tnt := args.Tenant
- if tnt == utils.EmptyString {
- tnt = rS.cfg.GeneralCfg().DefaultTenant
- }
-
- // RPC caching
- if config.CgrConfig().CacheCfg().Partitions[utils.CacheRPCResponses].Limit != 0 {
- cacheKey := utils.ConcatenatedKey(utils.ResourceSv1GetResourcesForEvent, utils.ConcatenatedKey(tnt, args.ID))
- refID := guardian.Guardian.GuardIDs("",
- config.CgrConfig().GeneralCfg().LockingTimeout, cacheKey) // RPC caching needs to be atomic
- defer guardian.Guardian.UnguardIDs(refID)
- if itm, has := engine.Cache.Get(utils.CacheRPCResponses, cacheKey); has {
- cachedResp := itm.(*utils.CachedRPCResponse)
- if cachedResp.Error == nil {
- *reply = *cachedResp.Result.(*Resources)
- }
- return cachedResp.Error
- }
- defer engine.Cache.Set(ctx, utils.CacheRPCResponses, cacheKey,
- &utils.CachedRPCResponse{Result: reply, Error: err},
- nil, true, utils.NonTransactional)
- }
- // end of RPC caching
-
- var mtcRLs Resources
- if mtcRLs, err = rS.matchingResourcesForEvent(ctx, tnt, args, usageID, usageTTL); err != nil {
- return err
- }
- *reply = mtcRLs
- mtcRLs.unlock()
- return
-}
-
-// V1AuthorizeResources queries service to find if an Usage is allowed
-func (rS *ResourceS) V1AuthorizeResources(ctx *context.Context, args *utils.CGREvent, reply *string) (err error) {
- if args == nil {
- return utils.NewErrMandatoryIeMissing(utils.Event)
- }
- if missing := utils.MissingStructFields(args, []string{utils.ID, utils.Event}); len(missing) != 0 { //Params missing
- return utils.NewErrMandatoryIeMissing(missing...)
- }
-
- var usageID string
- if usageID, err = engine.GetStringOpts(ctx, args.Tenant, args.AsDataProvider(), nil, rS.fltrS, rS.cfg.ResourceSCfg().Opts.UsageID,
- utils.OptsResourcesUsageID); err != nil {
- return
- }
-
- var units float64
- if units, err = engine.GetFloat64Opts(ctx, args.Tenant, args.AsDataProvider(), nil, rS.fltrS, rS.cfg.ResourceSCfg().Opts.Units,
- utils.OptsResourcesUnits); err != nil {
- return
- }
-
- var ttl time.Duration
- if ttl, err = engine.GetDurationOpts(ctx, args.Tenant, args.AsDataProvider(), nil, rS.fltrS, rS.cfg.ResourceSCfg().Opts.UsageTTL,
- utils.OptsResourcesUsageTTL); err != nil {
- return
- }
- usageTTL := utils.DurationPointer(ttl)
-
- if usageID == utils.EmptyString {
- return utils.NewErrMandatoryIeMissing(utils.UsageID)
- }
-
- tnt := args.Tenant
- if tnt == utils.EmptyString {
- tnt = rS.cfg.GeneralCfg().DefaultTenant
- }
-
- // RPC caching
- if config.CgrConfig().CacheCfg().Partitions[utils.CacheRPCResponses].Limit != 0 {
- cacheKey := utils.ConcatenatedKey(utils.ResourceSv1AuthorizeResources, utils.ConcatenatedKey(tnt, args.ID))
- refID := guardian.Guardian.GuardIDs("",
- config.CgrConfig().GeneralCfg().LockingTimeout, cacheKey) // RPC caching needs to be atomic
- defer guardian.Guardian.UnguardIDs(refID)
- if itm, has := engine.Cache.Get(utils.CacheRPCResponses, cacheKey); has {
- cachedResp := itm.(*utils.CachedRPCResponse)
- if cachedResp.Error == nil {
- *reply = *cachedResp.Result.(*string)
- }
- return cachedResp.Error
- }
- defer engine.Cache.Set(ctx, utils.CacheRPCResponses, cacheKey,
- &utils.CachedRPCResponse{Result: reply, Error: err},
- nil, true, utils.NonTransactional)
- }
- // end of RPC caching
-
- var mtcRLs Resources
- if mtcRLs, err = rS.matchingResourcesForEvent(ctx, tnt, args, usageID, usageTTL); err != nil {
- return err
- }
- defer mtcRLs.unlock()
-
- var alcMessage string
- if alcMessage, err = mtcRLs.allocateResource(&utils.ResourceUsage{
- Tenant: tnt,
- ID: usageID,
- Units: units}, true); err != nil {
- if err == utils.ErrResourceUnavailable {
- err = utils.ErrResourceUnauthorized
- }
- return
- }
- *reply = alcMessage
- return
-}
-
-// V1AllocateResources is called when a resource requires allocation
-func (rS *ResourceS) V1AllocateResources(ctx *context.Context, args *utils.CGREvent, reply *string) (err error) {
- if args == nil {
- return utils.NewErrMandatoryIeMissing(utils.Event)
- }
- if missing := utils.MissingStructFields(args, []string{utils.ID, utils.Event}); len(missing) != 0 { //Params missing
- return utils.NewErrMandatoryIeMissing(missing...)
- }
-
- var usageID string
- if usageID, err = engine.GetStringOpts(ctx, args.Tenant, args.AsDataProvider(), nil, rS.fltrS, rS.cfg.ResourceSCfg().Opts.UsageID,
- utils.OptsResourcesUsageID); err != nil {
- return
- }
-
- var units float64
- if units, err = engine.GetFloat64Opts(ctx, args.Tenant, args.AsDataProvider(), nil, rS.fltrS, rS.cfg.ResourceSCfg().Opts.Units,
- utils.OptsResourcesUnits); err != nil {
- return
- }
-
- var ttl time.Duration
- if ttl, err = engine.GetDurationOpts(ctx, args.Tenant, args.AsDataProvider(), nil, rS.fltrS, rS.cfg.ResourceSCfg().Opts.UsageTTL,
- utils.OptsResourcesUsageTTL); err != nil {
- return
- }
- usageTTL := utils.DurationPointer(ttl)
-
- if usageID == utils.EmptyString {
- return utils.NewErrMandatoryIeMissing(utils.UsageID)
- }
-
- tnt := args.Tenant
- if tnt == utils.EmptyString {
- tnt = rS.cfg.GeneralCfg().DefaultTenant
- }
-
- // RPC caching
- if config.CgrConfig().CacheCfg().Partitions[utils.CacheRPCResponses].Limit != 0 {
- cacheKey := utils.ConcatenatedKey(utils.ResourceSv1AllocateResources, utils.ConcatenatedKey(tnt, args.ID))
- refID := guardian.Guardian.GuardIDs("",
- config.CgrConfig().GeneralCfg().LockingTimeout, cacheKey) // RPC caching needs to be atomic
- defer guardian.Guardian.UnguardIDs(refID)
- if itm, has := engine.Cache.Get(utils.CacheRPCResponses, cacheKey); has {
- cachedResp := itm.(*utils.CachedRPCResponse)
- if cachedResp.Error == nil {
- *reply = *cachedResp.Result.(*string)
- }
- return cachedResp.Error
- }
- defer engine.Cache.Set(ctx, utils.CacheRPCResponses, cacheKey,
- &utils.CachedRPCResponse{Result: reply, Error: err},
- nil, true, utils.NonTransactional)
- }
- // end of RPC caching
-
- var mtcRLs Resources
- if mtcRLs, err = rS.matchingResourcesForEvent(ctx, tnt, args, usageID,
- usageTTL); err != nil {
- return err
- }
- defer mtcRLs.unlock()
-
- var alcMsg string
- if alcMsg, err = mtcRLs.allocateResource(&utils.ResourceUsage{Tenant: tnt, ID: usageID,
- Units: units}, false); err != nil {
- return
- }
-
- // index it for storing
- if err = rS.storeMatchedResources(ctx, mtcRLs); err != nil {
- return
- }
- if err = rS.processThresholds(ctx, mtcRLs, args.APIOpts); err != nil {
- return
- }
- *reply = alcMsg
- return
-}
-
-// V1ReleaseResources is called when we need to clear an allocation
-func (rS *ResourceS) V1ReleaseResources(ctx *context.Context, args *utils.CGREvent, reply *string) (err error) {
- if args == nil {
- return utils.NewErrMandatoryIeMissing(utils.Event)
- }
- if missing := utils.MissingStructFields(args, []string{utils.ID, utils.Event}); len(missing) != 0 { //Params missing
- return utils.NewErrMandatoryIeMissing(missing...)
- }
-
- var usageID string
- if usageID, err = engine.GetStringOpts(ctx, args.Tenant, args.AsDataProvider(), nil, rS.fltrS, rS.cfg.ResourceSCfg().Opts.UsageID,
- utils.OptsResourcesUsageID); err != nil {
- return
- }
-
- var ttl time.Duration
- if ttl, err = engine.GetDurationOpts(ctx, args.Tenant, args.AsDataProvider(), nil, rS.fltrS, rS.cfg.ResourceSCfg().Opts.UsageTTL,
- utils.OptsResourcesUsageTTL); err != nil {
- return
- }
- usageTTL := utils.DurationPointer(ttl)
-
- if usageID == utils.EmptyString {
- return utils.NewErrMandatoryIeMissing(utils.UsageID)
- }
-
- tnt := args.Tenant
- if tnt == utils.EmptyString {
- tnt = rS.cfg.GeneralCfg().DefaultTenant
- }
-
- // RPC caching
- if config.CgrConfig().CacheCfg().Partitions[utils.CacheRPCResponses].Limit != 0 {
- cacheKey := utils.ConcatenatedKey(utils.ResourceSv1ReleaseResources, utils.ConcatenatedKey(tnt, args.ID))
- refID := guardian.Guardian.GuardIDs("",
- config.CgrConfig().GeneralCfg().LockingTimeout, cacheKey) // RPC caching needs to be atomic
- defer guardian.Guardian.UnguardIDs(refID)
- if itm, has := engine.Cache.Get(utils.CacheRPCResponses, cacheKey); has {
- cachedResp := itm.(*utils.CachedRPCResponse)
- if cachedResp.Error == nil {
- *reply = *cachedResp.Result.(*string)
- }
- return cachedResp.Error
- }
- defer engine.Cache.Set(ctx, utils.CacheRPCResponses, cacheKey,
- &utils.CachedRPCResponse{Result: reply, Error: err},
- nil, true, utils.NonTransactional)
- }
- // end of RPC caching
-
- var mtcRLs Resources
- if mtcRLs, err = rS.matchingResourcesForEvent(ctx, tnt, args, usageID,
- usageTTL); err != nil {
- return
- }
- defer mtcRLs.unlock()
-
- if err = mtcRLs.clearUsage(usageID); err != nil {
- return
- }
-
- // Handle storing
- if err = rS.storeMatchedResources(ctx, mtcRLs); err != nil {
- return
- }
- if err = rS.processThresholds(ctx, mtcRLs, args.APIOpts); err != nil {
- return
- }
-
- *reply = utils.OK
- return
-}
-
-// V1GetResource returns a resource configuration
-func (rS *ResourceS) V1GetResource(ctx *context.Context, arg *utils.TenantIDWithAPIOpts, reply *utils.Resource) error {
- if missing := utils.MissingStructFields(arg, []string{utils.ID}); len(missing) != 0 { //Params missing
- return utils.NewErrMandatoryIeMissing(missing...)
- }
- tnt := arg.Tenant
- if tnt == utils.EmptyString {
- tnt = rS.cfg.GeneralCfg().DefaultTenant
- }
-
- // make sure resource is locked at process level
- lkID := guardian.Guardian.GuardIDs(utils.EmptyString,
- config.CgrConfig().GeneralCfg().LockingTimeout,
- utils.ResourceLockKey(tnt, arg.ID))
- defer guardian.Guardian.UnguardIDs(lkID)
-
- res, err := rS.dm.GetResource(ctx, tnt, arg.ID, true, true, utils.NonTransactional)
- if err != nil {
- return err
- }
- *reply = *res
- return nil
-}
-
-func (rS *ResourceS) V1GetResourceWithConfig(ctx *context.Context, arg *utils.TenantIDWithAPIOpts, reply *utils.ResourceWithConfig) (err error) {
- if missing := utils.MissingStructFields(arg, []string{utils.ID}); len(missing) != 0 { //Params missing
- return utils.NewErrMandatoryIeMissing(missing...)
- }
- tnt := arg.Tenant
- if tnt == utils.EmptyString {
- tnt = rS.cfg.GeneralCfg().DefaultTenant
- }
-
- // make sure resource is locked at process level
- lkID := guardian.Guardian.GuardIDs(utils.EmptyString,
- config.CgrConfig().GeneralCfg().LockingTimeout,
- utils.ResourceLockKey(tnt, arg.ID))
- defer guardian.Guardian.UnguardIDs(lkID)
-
- var res *utils.Resource
- res, err = rS.dm.GetResource(ctx, tnt, arg.ID, true, true, utils.NonTransactional)
- if err != nil {
- return
- }
-
- // make sure resourceProfile is locked at process level
- lkPrflID := guardian.Guardian.GuardIDs(utils.EmptyString,
- config.CgrConfig().GeneralCfg().LockingTimeout,
- utils.ResourceProfileLockKey(tnt, arg.ID))
- defer guardian.Guardian.UnguardIDs(lkPrflID)
-
- var cfg *utils.ResourceProfile
- cfg, err = rS.dm.GetResourceProfile(ctx, tnt, arg.ID, true, true, utils.NonTransactional)
- if err != nil {
- return
- }
-
- *reply = utils.ResourceWithConfig{
- Resource: res,
- Config: cfg,
- }
-
- return
-}
diff --git a/resources/resources_test.go b/resources/resources_test.go
index 45e8914e1..60bcf2364 100644
--- a/resources/resources_test.go
+++ b/resources/resources_test.go
@@ -15,6 +15,7 @@ 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 resources
import (
@@ -679,42 +680,6 @@ func TestRSCacheSetGet(t *testing.T) {
t.Errorf("Expecting: %+v, received: %+v", r, x)
}
}
-func TestResourceV1AuthorizeResourceMissingStruct(t *testing.T) {
- var dmRES *engine.DataManager
- cfg := config.NewDefaultCGRConfig()
-
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dmRES = engine.NewDataManager(data, cfg, nil)
- cfg.ResourceSCfg().StoreInterval = 1
- cfg.ResourceSCfg().StringIndexedFields = nil
- cfg.ResourceSCfg().PrefixIndexedFields = nil
- fltrs := engine.NewFilterS(cfg, nil, dmRES)
- resService := NewResourceService(dmRES, cfg,
- fltrs, nil)
- var reply *string
- argsMissingTenant := &utils.CGREvent{
- ID: "id1",
- Event: map[string]any{},
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "test1",
- utils.OptsResourcesUnits: 20,
- },
- }
- argsMissingUsageID := &utils.CGREvent{
- Tenant: "cgrates.org",
- ID: "id1",
- Event: map[string]any{},
- APIOpts: map[string]any{
- utils.OptsResourcesUnits: 20,
- },
- }
- if err := resService.V1AuthorizeResources(context.TODO(), argsMissingTenant, reply); err != nil && err.Error() != "MANDATORY_IE_MISSING: [Event]" {
- t.Error(err.Error())
- }
- if err := resService.V1AuthorizeResources(context.TODO(), argsMissingUsageID, reply); err != nil && err.Error() != "MANDATORY_IE_MISSING: [Event]" {
- t.Error(err.Error())
- }
-}
func TestResourceAddResourceProfile(t *testing.T) {
var dmRES *engine.DataManager
@@ -2657,66 +2622,6 @@ func TestResourcesRecordUsageClearErr(t *testing.T) {
}
}
-func TestResourceAllocateResourceOtherDB(t *testing.T) {
- rProf := &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RL_DB",
- FilterIDs: []string{"*string:~*opts.Resource:RL_DB"},
- Weights: utils.DynamicWeights{
- {
- Weight: 100,
- }},
- Limit: 2,
- ThresholdIDs: []string{utils.MetaNone},
- UsageTTL: -time.Nanosecond,
- }
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- idb, err := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- if err != nil {
- t.Error(err)
- }
- dm := engine.NewDataManager(idb, cfg, nil)
- fltS := engine.NewFilterS(cfg, nil, dm)
- rs := NewResourceService(dm, cfg, fltS, nil)
- if err := dm.SetResourceProfile(context.TODO(), rProf, true); err != nil {
- t.Fatal(err)
- }
- if err := dm.SetResource(context.TODO(), &utils.Resource{
- Tenant: "cgrates.org",
- ID: "RL_DB",
- Usages: map[string]*utils.ResourceUsage{
- "RU1": { // the resource in DB is expired (should be cleaned when the next allocate is called)
- Tenant: "cgrates.org",
- ID: "RU1",
- ExpiryTime: time.Date(2014, 7, 3, 13, 43, 0, 1, time.UTC),
- Units: 1,
- },
- },
- TTLIdx: []string{"RU1"},
- }); err != nil { // simulate how the resource is stored in redis or mongo(non-exported fields are not populated)
- t.Fatal(err)
- }
- var reply string
- exp := rProf.ID
- if err := rs.V1AllocateResources(context.TODO(), &utils.CGREvent{
- Tenant: "cgrates.org",
- ID: "ef0f554",
- Event: map[string]any{"": ""},
- APIOpts: map[string]any{
- "Resource": "RL_DB",
- utils.OptsResourcesUsageID: "56156434-2e44-4f16-a766-086f10b413cd",
- utils.OptsResourcesUnits: 1,
- },
- }, &reply); err != nil {
- t.Fatal(err)
- } else if reply != exp {
- t.Errorf("Expected: %q, received: %q", exp, reply)
- }
-
-}
-
func TestResourceClearUsageErr(t *testing.T) {
tmpLogger := utils.Logger
defer func() {
@@ -3205,2355 +3110,6 @@ func TestResourcesProcessThresholdsThdConnMetaNone(t *testing.T) {
}
}
-type ccMock struct {
- calls map[string]func(ctx *context.Context, args any, reply any) error
-}
-
-func (ccM *ccMock) Call(ctx *context.Context, serviceMethod string, args any, reply any) (err error) {
- if call, has := ccM.calls[serviceMethod]; !has {
- return rpcclient.ErrUnsupporteServiceMethod
- } else {
- return call(ctx, args, reply)
- }
-}
-
-func TestResourcesV1ResourcesForEventOK(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
- rsPrf := &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- AllocationMessage: "Approved",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: 10,
- UsageTTL: time.Minute,
- }
- rs := &utils.Resource{
- Tenant: "cgrates.org",
- ID: "RES1",
- TTLIdx: []string{},
- Usages: map[string]*utils.ResourceUsage{
- "RU1": {
- Tenant: "cgrates.org",
- ID: "RU1",
- Units: 10,
- },
- },
- }
- err := dm.SetResourceProfile(context.Background(), rsPrf, true)
- if err != nil {
- t.Error(err)
- }
- err = dm.SetResource(context.Background(), rs)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "ResourcesForEventTest",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_TEST1",
- },
- }
-
- exp := Resources{
- {
- Resource: &utils.Resource{
- Tenant: "cgrates.org",
- ID: "RES1",
- TTLIdx: []string{},
- Usages: map[string]*utils.ResourceUsage{
- "RU1": {
- Tenant: "cgrates.org",
- ID: "RU1",
- Units: 10,
- },
- },
- },
- rPrf: &resourceProfile{ResourceProfile: rsPrf},
- ttl: utils.DurationPointer(72 * time.Hour),
- },
- }
- var reply Resources
- if err := rS.V1GetResourcesForEvent(context.Background(), args, &reply); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(reply, exp) {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>",
- utils.ToJSON(exp), utils.ToJSON(reply))
- }
-}
-
-func TestResourcesV1ResourcesForEventNotFound(t *testing.T) {
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- rsPrf := &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: 10,
- UsageTTL: time.Minute,
- }
- rs := &utils.Resource{
- Tenant: "cgrates.org",
- ID: "RES1",
- Usages: map[string]*utils.ResourceUsage{
- "RU1": {
- Tenant: "cgrates.org",
- ID: "RU1",
- Units: 10,
- },
- },
- }
- err := dm.SetResourceProfile(context.Background(), rsPrf, true)
- if err != nil {
- t.Error(err)
- }
- err = dm.SetResource(context.Background(), rs)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- Tenant: "cgrates.org",
- ID: "ResourcesForEventTest",
- Event: map[string]any{
- utils.AccountField: "1002",
- },
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_TEST1",
- },
- }
-
- var reply Resources
- if err := rS.V1GetResourcesForEvent(context.Background(), args, &reply); err == nil ||
- err.Error() != utils.ErrNotFound.Error() {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err)
- }
-}
-
-func TestResourcesV1ResourcesForEventMissingParameters(t *testing.T) {
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- rsPrf := &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: 10,
- UsageTTL: time.Minute,
- }
- rs := &utils.Resource{
- Tenant: "cgrates.org",
- ID: "RES1",
- Usages: map[string]*utils.ResourceUsage{
- "RU1": {
- Tenant: "cgrates.org",
- ID: "RU1",
- Units: 10,
- },
- },
- }
- err := dm.SetResourceProfile(context.Background(), rsPrf, true)
- if err != nil {
- t.Error(err)
- }
- err = dm.SetResource(context.Background(), rs)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- experr := `MANDATORY_IE_MISSING: [Event]`
- var reply Resources
- if err := rS.V1GetResourcesForEvent(context.Background(), nil, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-
- args := &utils.CGREvent{
- Tenant: "cgrates.org",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_TEST2",
- },
- }
-
- experr = `MANDATORY_IE_MISSING: [ID]`
- if err := rS.V1GetResourcesForEvent(context.Background(), args, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-
- args = &utils.CGREvent{
- Tenant: "cgrates.org",
- ID: "ResourcesForEventTest",
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_TEST3",
- },
- }
-
- experr = `MANDATORY_IE_MISSING: [Event]`
- if err := rS.V1GetResourcesForEvent(context.Background(), args, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-
- args = &utils.CGREvent{
- Tenant: "cgrates.org",
- ID: "ResourcesForEventTest",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- }
-
- experr = `MANDATORY_IE_MISSING: [UsageID]`
- if err := rS.V1GetResourcesForEvent(context.Background(), args, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-}
-
-func TestResourcesV1ResourcesForEventCacheReplyExists(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
- config.SetCgrConfig(cfg)
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
- cacheKey := utils.ConcatenatedKey(utils.ResourceSv1GetResourcesForEvent,
- utils.ConcatenatedKey("cgrates.org", "ResourcesForEventTest"))
- rsPrf := &resourceProfile{
- ResourceProfile: &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- AllocationMessage: "Approved",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: 10,
- UsageTTL: time.Minute,
- },
- }
- rs := &utils.Resource{
- Tenant: "cgrates.org",
- ID: "RES1",
- Usages: map[string]*utils.ResourceUsage{
- "RU1": {
- Tenant: "cgrates.org",
- ID: "RU1",
- Units: 10,
- },
- },
- TTLIdx: []string{},
- }
- err := dm.SetResourceProfile(context.Background(), rsPrf.ResourceProfile, true)
- if err != nil {
- t.Error(err)
- }
- err = dm.SetResource(context.Background(), rs)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "ResourcesForEventTest",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_TEST1",
- },
- }
-
- cacheReply := Resources{
- {
- Resource: &utils.Resource{
- Tenant: "cgrates.org",
- ID: "RES1",
- Usages: map[string]*utils.ResourceUsage{
- "RU1": {
- Tenant: "cgrates.org",
- ID: "RU1",
- Units: 10,
- },
- },
- TTLIdx: []string{},
- },
- rPrf: rsPrf,
- dirty: utils.BoolPointer(false),
- tUsage: utils.Float64Pointer(10),
- ttl: utils.DurationPointer(time.Minute),
- },
- }
- engine.Cache.Set(context.Background(), utils.CacheRPCResponses, cacheKey,
- &utils.CachedRPCResponse{Result: &cacheReply, Error: nil},
- nil, true, utils.NonTransactional)
- var reply Resources
- if err := rS.V1GetResourcesForEvent(context.Background(), args, &reply); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(reply, cacheReply) {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>",
- utils.ToJSON(cacheReply), utils.ToJSON(reply))
- }
-
- config.SetCgrConfig(config.NewDefaultCGRConfig())
-}
-
-func TestResourcesV1ResourcesForEventCacheReplySet(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
- config.SetCgrConfig(cfg)
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
- cacheKey := utils.ConcatenatedKey(utils.ResourceSv1GetResourcesForEvent,
- utils.ConcatenatedKey("cgrates.org", "ResourcesForEventTest"))
- rsPrf := &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- AllocationMessage: "Approved",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: 10,
- UsageTTL: time.Minute,
- }
- rs := &utils.Resource{
- Tenant: "cgrates.org",
- ID: "RES1",
- Usages: map[string]*utils.ResourceUsage{
- "RU1": {
- Tenant: "cgrates.org",
- ID: "RU1",
- Units: 10,
- },
- },
- TTLIdx: []string{},
- }
- err := dm.SetResourceProfile(context.Background(), rsPrf, true)
- if err != nil {
- t.Error(err)
- }
- err = dm.SetResource(context.Background(), rs)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "ResourcesForEventTest",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_TEST1",
- },
- }
-
- exp := &Resources{
- {
- Resource: &utils.Resource{
- Tenant: "cgrates.org",
- ID: "RES1",
- Usages: map[string]*utils.ResourceUsage{
- "RU1": {
- Tenant: "cgrates.org",
- ID: "RU1",
- Units: 10,
- },
- },
- TTLIdx: []string{},
- },
- ttl: utils.DurationPointer(72 * time.Hour),
- rPrf: &resourceProfile{
- ResourceProfile: rsPrf,
- },
- },
- }
- var reply Resources
- if err := rS.V1GetResourcesForEvent(context.Background(), args, &reply); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(reply, *exp) {
- t.Errorf("expected: <%v>, received: <%v>", exp, reply)
- }
-
- if itm, has := engine.Cache.Get(utils.CacheRPCResponses, cacheKey); has {
- resp := itm.(*utils.CachedRPCResponse)
- if !reflect.DeepEqual(resp.Result, exp) {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ToJSON(exp), utils.ToJSON(resp.Result))
- }
- }
-
- config.SetCgrConfig(config.NewDefaultCGRConfig())
-}
-
-func TestResourcesV1GetResourceOK(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
-
- rs := &utils.Resource{
- Tenant: "cgrates.org",
- ID: "RES1",
- Usages: map[string]*utils.ResourceUsage{
- "RU1": {
- Tenant: "cgrates.org",
- ID: "RU1",
- Units: 10,
- },
- },
- TTLIdx: []string{},
- }
- err := dm.SetResource(context.Background(), rs)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- exp := utils.Resource{
- Tenant: "cgrates.org",
- ID: "RES1",
- TTLIdx: []string{},
- Usages: map[string]*utils.ResourceUsage{
- "RU1": {
- Tenant: "cgrates.org",
- ID: "RU1",
- Units: 10,
- },
- },
- }
-
- args := &utils.TenantIDWithAPIOpts{
- TenantID: &utils.TenantID{
- ID: "RES1",
- },
- }
- var reply utils.Resource
- if err := rS.V1GetResource(context.Background(), args, &reply); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(reply, exp) {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>",
- utils.ToJSON(exp), utils.ToJSON(reply))
- }
-}
-
-func TestResourcesV1GetResourceNotFound(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
-
- rs := &utils.Resource{
- Tenant: "cgrates.org",
- ID: "RES1",
- Usages: map[string]*utils.ResourceUsage{
- "RU1": {
- Tenant: "cgrates.org",
- ID: "RU1",
- Units: 10,
- },
- },
- TTLIdx: []string{},
- }
- err := dm.SetResource(context.Background(), rs)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.TenantIDWithAPIOpts{
- TenantID: &utils.TenantID{
- Tenant: "cgrates.org",
- ID: "RES2",
- },
- }
- var reply utils.Resource
- if err := rS.V1GetResource(context.Background(), args, &reply); err == nil ||
- err.Error() != utils.ErrNotFound.Error() {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err)
- }
-}
-
-func TestResourcesV1GetResourceMissingParameters(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
-
- rs := &utils.Resource{
- Tenant: "cgrates.org",
- ID: "RES1",
- Usages: map[string]*utils.ResourceUsage{
- "RU1": {
- Tenant: "cgrates.org",
- ID: "RU1",
- Units: 10,
- },
- },
- TTLIdx: []string{},
- }
- err := dm.SetResource(context.Background(), rs)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.TenantIDWithAPIOpts{
- TenantID: &utils.TenantID{},
- }
-
- experr := `MANDATORY_IE_MISSING: [ID]`
- var reply utils.Resource
- if err := rS.V1GetResource(context.Background(), args, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-}
-
-func TestResourcesV1GetResourceWithConfigOK(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
-
- rsPrf := &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- AllocationMessage: "Approved",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: 10,
- UsageTTL: time.Minute,
- }
- err := dm.SetResourceProfile(context.Background(), rsPrf, true)
- if err != nil {
- t.Error(err)
- }
- rs := &utils.Resource{
- Tenant: "cgrates.org",
- ID: "RES1",
- Usages: map[string]*utils.ResourceUsage{
- "RU1": {
- Tenant: "cgrates.org",
- ID: "RU1",
- Units: 10,
- },
- },
- TTLIdx: []string{},
- }
- err = dm.SetResource(context.Background(), rs)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- exp := utils.ResourceWithConfig{
- Resource: &utils.Resource{
- Tenant: "cgrates.org",
- ID: "RES1",
- Usages: map[string]*utils.ResourceUsage{
- "RU1": {
- Tenant: "cgrates.org",
- ID: "RU1",
- Units: 10,
- },
- },
- TTLIdx: []string{},
- },
- Config: rsPrf,
- }
-
- args := &utils.TenantIDWithAPIOpts{
- TenantID: &utils.TenantID{
- ID: "RES1",
- },
- }
- var reply utils.ResourceWithConfig
- if err := rS.V1GetResourceWithConfig(context.Background(), args, &reply); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(reply, exp) {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>",
- utils.ToJSON(exp), utils.ToJSON(reply))
- }
-}
-
-func TestResourcesV1GetResourceWithConfigNilrPrfProfileNotFound(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
-
- rsPrf := &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES2",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- AllocationMessage: "Approved",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: 10,
- UsageTTL: time.Minute,
- }
- err := dm.SetResourceProfile(context.Background(), rsPrf, true)
- if err != nil {
- t.Error(err)
- }
- rs := &utils.Resource{
- Tenant: "cgrates.org",
- ID: "RES1",
- Usages: map[string]*utils.ResourceUsage{
- "RU1": {
- Tenant: "cgrates.org",
- ID: "RU1",
- Units: 10,
- },
- },
- TTLIdx: []string{},
- }
- err = dm.SetResource(context.Background(), rs)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.TenantIDWithAPIOpts{
- TenantID: &utils.TenantID{
- ID: "RES1",
- },
- }
- var reply utils.ResourceWithConfig
- if err := rS.V1GetResourceWithConfig(context.Background(), args, &reply); err == nil ||
- err != utils.ErrNotFound {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err)
- }
-}
-
-func TestResourcesV1GetResourceWithConfigResourceNotFound(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
-
- rs := &utils.Resource{
- Tenant: "cgrates.org",
- ID: "RES2",
- Usages: map[string]*utils.ResourceUsage{
- "RU1": {
- Tenant: "cgrates.org",
- ID: "RU1",
- Units: 10,
- },
- },
- TTLIdx: []string{},
- }
- err := dm.SetResource(context.Background(), rs)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.TenantIDWithAPIOpts{
- TenantID: &utils.TenantID{
- ID: "RES1",
- },
- }
- var reply utils.ResourceWithConfig
- if err := rS.V1GetResourceWithConfig(context.Background(), args, &reply); err == nil || err != utils.ErrNotFound {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err)
- }
-}
-
-func TestResourcesV1GetResourceWithConfigMissingParameters(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
-
- rs := &utils.Resource{
- Tenant: "cgrates.org",
- ID: "RES1",
- Usages: map[string]*utils.ResourceUsage{
- "RU1": {
- Tenant: "cgrates.org",
- ID: "RU1",
- Units: 10,
- },
- },
- TTLIdx: []string{},
- }
- err := dm.SetResource(context.Background(), rs)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- experr := `MANDATORY_IE_MISSING: [ID]`
- args := &utils.TenantIDWithAPIOpts{
- TenantID: &utils.TenantID{},
- }
- var reply utils.ResourceWithConfig
- if err := rS.V1GetResourceWithConfig(context.Background(), args, &reply); err == nil || err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-}
-
-func TestResourcesV1AuthorizeResourcesOK(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
-
- rsPrf := &resourceProfile{
- ResourceProfile: &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- AllocationMessage: "Approved",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: 10,
- UsageTTL: time.Minute,
- },
- }
-
- err := dm.SetResourceProfile(context.Background(), rsPrf.ResourceProfile, true)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "EventAuthorizeResource",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_Test",
- utils.OptsResourcesUnits: 5,
- utils.OptsResourcesUsageTTL: time.Minute,
- },
- }
- var reply string
-
- if err := rS.V1AuthorizeResources(context.Background(), args, &reply); err != nil {
- t.Error(err)
- } else if reply != "Approved" {
- t.Errorf("Unexpected reply returned: %q", reply)
- }
-}
-
-func TestResourcesV1AuthorizeResourcesNotAuthorized(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
-
- rsPrf := &resourceProfile{
- ResourceProfile: &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- AllocationMessage: "Approved",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: 0,
- UsageTTL: time.Minute,
- },
- }
-
- err := dm.SetResourceProfile(context.Background(), rsPrf.ResourceProfile, true)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- Tenant: "cgrates.org",
- ID: "EventAuthorizeResource",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_Test",
- utils.OptsResourcesUnits: 5,
- utils.OptsResourcesUsageTTL: time.Minute,
- },
- }
- var reply string
-
- if err := rS.V1AuthorizeResources(context.Background(), args, &reply); err == nil ||
- err != utils.ErrResourceUnauthorized {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrResourceUnauthorized, err)
- }
-}
-
-func TestResourcesV1AuthorizeResourcesNoMatch(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
-
- rsPrf := &resourceProfile{
- ResourceProfile: &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- AllocationMessage: "Approved",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: 10,
- UsageTTL: time.Minute,
- },
- }
-
- err := dm.SetResourceProfile(context.Background(), rsPrf.ResourceProfile, true)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- Tenant: "cgrates.org",
- ID: "EventAuthorizeResource",
- Event: map[string]any{
- utils.AccountField: "1002",
- },
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_Test",
- utils.OptsResourcesUnits: 5,
- utils.OptsResourcesUsageTTL: time.Minute,
- },
- }
- var reply string
-
- if err := rS.V1AuthorizeResources(context.Background(), args, &reply); err == nil ||
- err != utils.ErrNotFound {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err)
- }
-}
-
-func TestResourcesV1AuthorizeResourcesNilCGREvent(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
-
- rsPrf := &resourceProfile{
- ResourceProfile: &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- AllocationMessage: "Approved",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: 10,
- UsageTTL: time.Minute,
- },
- }
-
- err := dm.SetResourceProfile(context.Background(), rsPrf.ResourceProfile, true)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- experr := `MANDATORY_IE_MISSING: [Event]`
- var reply string
-
- if err := rS.V1AuthorizeResources(context.Background(), nil, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-}
-
-func TestResourcesV1AuthorizeResourcesMissingUsageID(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
-
- rsPrf := &resourceProfile{
- ResourceProfile: &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- AllocationMessage: "Approved",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: 10,
- UsageTTL: time.Minute,
- },
- }
-
- err := dm.SetResourceProfile(context.Background(), rsPrf.ResourceProfile, true)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "EventAuthorizeResource",
- Event: map[string]any{
- utils.AccountField: "1001",
- utils.OptsResourcesUnits: 5,
- utils.OptsResourcesUsageTTL: time.Minute,
- },
- }
- experr := `MANDATORY_IE_MISSING: [UsageID]`
- var reply string
-
- if err := rS.V1AuthorizeResources(context.Background(), args, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-}
-
-func TestResourcesV1AuthorizeResourcesCacheReplyExists(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
- config.SetCgrConfig(cfg)
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
- cacheKey := utils.ConcatenatedKey(utils.ResourceSv1AuthorizeResources,
- utils.ConcatenatedKey("cgrates.org", "EventAuthorizeResource"))
-
- rsPrf := &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- AllocationMessage: "Approved",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: 10,
- UsageTTL: time.Minute,
- }
- rs := &utils.Resource{
- Tenant: "cgrates.org",
- ID: "RES1",
- Usages: map[string]*utils.ResourceUsage{
- "RU1": {
- Tenant: "cgrates.org",
- ID: "RU1",
- Units: 10,
- },
- },
- TTLIdx: []string{},
- }
-
- err := dm.SetResourceProfile(context.Background(), rsPrf, true)
- if err != nil {
- t.Error(err)
- }
- err = dm.SetResource(context.Background(), rs)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "EventAuthorizeResource",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_Test",
- utils.OptsResourcesUnits: 5,
- utils.OptsResourcesUsageTTL: time.Minute,
- },
- }
-
- cacheReply := "Approved"
- engine.Cache.Set(context.Background(), utils.CacheRPCResponses, cacheKey,
- &utils.CachedRPCResponse{Result: &cacheReply, Error: nil},
- nil, true, utils.NonTransactional)
-
- var reply string
- if err := rS.V1AuthorizeResources(context.Background(), args, &reply); err != nil {
- t.Error(err)
- } else if reply != cacheReply {
- t.Errorf("Unexpected reply returned: %q", reply)
- }
- config.SetCgrConfig(config.NewDefaultCGRConfig())
-}
-
-func TestResourcesV1AuthorizeResourcesCacheReplySet(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
- config.SetCgrConfig(cfg)
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
- cacheKey := utils.ConcatenatedKey(utils.ResourceSv1AuthorizeResources,
- utils.ConcatenatedKey("cgrates.org", "EventAuthorizeResource"))
-
- rsPrf := &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- AllocationMessage: "Approved",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: -1,
- UsageTTL: time.Minute,
- }
- rs := &utils.Resource{
- Tenant: "cgrates.org",
- ID: "RES1",
- Usages: map[string]*utils.ResourceUsage{
- "RU1": {
- Tenant: "cgrates.org",
- ID: "RU1",
- Units: 4,
- },
- },
- TTLIdx: []string{},
- }
-
- err := dm.SetResourceProfile(context.Background(), rsPrf, true)
- if err != nil {
- t.Error(err)
- }
- err = dm.SetResource(context.Background(), rs)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "EventAuthorizeResource",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_Test",
- utils.OptsResourcesUnits: 2,
- utils.OptsResourcesUsageTTL: time.Minute,
- },
- }
-
- var reply string
- if err := rS.V1AuthorizeResources(context.Background(), args, &reply); err != nil {
- t.Error(err)
- } else if reply != "Approved" {
- t.Errorf("Unexpected reply returned: %q", reply)
- }
-
- if itm, has := engine.Cache.Get(utils.CacheRPCResponses, cacheKey); has {
- resp := itm.(*utils.CachedRPCResponse)
- if *resp.Result.(*string) != "Approved" {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>",
- "Approved", *resp.Result.(*string))
- }
- }
-
- config.SetCgrConfig(config.NewDefaultCGRConfig())
-}
-
-func TestResourcesV1AllocateResourcesOK(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
-
- rsPrf := &resourceProfile{
- ResourceProfile: &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- AllocationMessage: "Approved",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: 10,
- UsageTTL: time.Minute,
- },
- }
-
- err := dm.SetResourceProfile(context.Background(), rsPrf.ResourceProfile, true)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "EventAuthorizeResource",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_Test",
- utils.OptsResourcesUnits: 5,
- utils.OptsResourcesUsageTTL: time.Minute,
- },
- }
- var reply string
-
- if err := rS.V1AllocateResources(context.Background(), args, &reply); err != nil {
- t.Error(err)
- } else if reply != "Approved" {
- t.Errorf("Unexpected reply returned: %q", reply)
- }
-}
-
-func TestResourcesV1AllocateResourcesNoMatch(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
-
- rsPrf := &resourceProfile{
- ResourceProfile: &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- AllocationMessage: "Approved",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: 10,
- UsageTTL: time.Minute,
- },
- }
-
- err := dm.SetResourceProfile(context.Background(), rsPrf.ResourceProfile, true)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "EventAuthorizeResource",
- Event: map[string]any{
- utils.AccountField: "1002",
- },
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_Test",
- utils.OptsResourcesUnits: 5,
- utils.OptsResourcesUsageTTL: time.Minute,
- },
- }
- var reply string
-
- if err := rS.V1AllocateResources(context.Background(), args, &reply); err == nil ||
- err != utils.ErrNotFound {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err)
- }
-}
-
-func TestResourcesV1AllocateResourcesMissingParameters(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
-
- rsPrf := &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- AllocationMessage: "Approved",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: 10,
- UsageTTL: time.Minute,
- }
-
- err := dm.SetResourceProfile(context.Background(), rsPrf, true)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "EventAuthorizeResource",
- Event: map[string]any{
- utils.AccountField: "1001",
- utils.OptsResourcesUnits: 5,
- utils.OptsResourcesUsageTTL: time.Minute,
- },
- }
- var reply string
-
- experr := `MANDATORY_IE_MISSING: [UsageID]`
- if err := rS.V1AllocateResources(context.Background(), args, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-
- args = &utils.CGREvent{
- ID: "EventAuthorizeResource",
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_Test",
- utils.OptsResourcesUnits: 5,
- utils.OptsResourcesUsageTTL: time.Minute,
- },
- }
-
- experr = `MANDATORY_IE_MISSING: [Event]`
- if err := rS.V1AllocateResources(context.Background(), args, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-
- args = &utils.CGREvent{
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_Test",
- utils.OptsResourcesUnits: 5,
- utils.OptsResourcesUsageTTL: time.Minute,
- },
- }
-
- experr = `MANDATORY_IE_MISSING: [ID]`
- if err := rS.V1AllocateResources(context.Background(), args, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-
- experr = `MANDATORY_IE_MISSING: [Event]`
- if err := rS.V1AllocateResources(context.Background(), nil, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-}
-
-func TestResourcesV1AllocateResourcesCacheReplyExists(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
- config.SetCgrConfig(cfg)
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
- cacheKey := utils.ConcatenatedKey(utils.ResourceSv1AllocateResources,
- utils.ConcatenatedKey("cgrates.org", "EventAllocateResource"))
-
- rsPrf := &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- AllocationMessage: "Approved",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: -1,
- UsageTTL: time.Minute,
- }
- rs := &utils.Resource{
- Tenant: "cgrates.org",
- ID: "RES1",
- Usages: map[string]*utils.ResourceUsage{
- "RU1": {
- Tenant: "cgrates.org",
- ID: "RU1",
- Units: 10,
- },
- },
- TTLIdx: []string{},
- }
-
- err := dm.SetResourceProfile(context.Background(), rsPrf, true)
- if err != nil {
- t.Error(err)
- }
- err = dm.SetResource(context.Background(), rs)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "EventAllocateResource",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_Test",
- utils.OptsResourcesUnits: 5,
- utils.OptsResourcesUsageTTL: time.Minute,
- },
- }
-
- cacheReply := "cacheApproved"
- engine.Cache.Set(context.Background(), utils.CacheRPCResponses, cacheKey,
- &utils.CachedRPCResponse{Result: &cacheReply, Error: nil},
- nil, true, utils.NonTransactional)
-
- var reply string
- if err := rS.V1AllocateResources(context.Background(), args, &reply); err != nil {
- t.Error(err)
- } else if reply != cacheReply {
- t.Errorf("Unexpected reply returned: %q", reply)
- }
- config.SetCgrConfig(config.NewDefaultCGRConfig())
-}
-
-func TestResourcesV1AllocateResourcesCacheReplySet(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
- config.SetCgrConfig(cfg)
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
- cacheKey := utils.ConcatenatedKey(utils.ResourceSv1AllocateResources,
- utils.ConcatenatedKey("cgrates.org", "EventAllocateResource"))
-
- rsPrf := &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- AllocationMessage: "Approved",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: -1,
- UsageTTL: time.Minute,
- }
- rs := &utils.Resource{
- Tenant: "cgrates.org",
- ID: "RES1",
- Usages: map[string]*utils.ResourceUsage{
- "RU1": {
- Tenant: "cgrates.org",
- ID: "RU1",
- Units: 4,
- },
- },
- TTLIdx: []string{},
- }
-
- err := dm.SetResourceProfile(context.Background(), rsPrf, true)
- if err != nil {
- t.Error(err)
- }
- err = dm.SetResource(context.Background(), rs)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "EventAllocateResource",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_Test",
- utils.OptsResourcesUnits: 2,
- utils.OptsResourcesUsageTTL: time.Minute,
- },
- }
-
- var reply string
- if err := rS.V1AllocateResources(context.Background(), args, &reply); err != nil {
- t.Error(err)
- } else if reply != "Approved" {
- t.Errorf("Unexpected reply returned: %q", reply)
- }
-
- if itm, has := engine.Cache.Get(utils.CacheRPCResponses, cacheKey); has {
- resp := itm.(*utils.CachedRPCResponse)
- if *resp.Result.(*string) != "Approved" {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>",
- "Approved", *resp.Result.(*string))
- }
- }
-
- config.SetCgrConfig(config.NewDefaultCGRConfig())
-}
-
-func TestResourcesV1AllocateResourcesResAllocErr(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
-
- rsPrf := &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- AllocationMessage: "",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: -1,
- UsageTTL: time.Minute,
- }
- err := dm.SetResourceProfile(context.Background(), rsPrf, true)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "EventAuthorizeResource",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_Test",
- utils.OptsResourcesUnits: 5,
- utils.OptsResourcesUsageTTL: time.Minute,
- },
- }
- var reply string
-
- if err := rS.V1AllocateResources(context.Background(), args, &reply); err == nil ||
- err != utils.ErrResourceUnavailable {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrResourceUnavailable, err)
- }
-}
-
-func TestResourcesV1AllocateResourcesProcessThErr(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- cfg.ResourceSCfg().StoreInterval = 2
- cfg.ResourceSCfg().ThresholdSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds)}
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
-
- rsPrf := &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds)},
- AllocationMessage: "Approved",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: -1,
- UsageTTL: time.Minute,
- }
- rs := &utils.Resource{
- Tenant: "cgrates.org",
- ID: "RES1",
- Usages: map[string]*utils.ResourceUsage{
- "RU1": {
- Tenant: "cgrates.org",
- ID: "RU1",
- Units: 10,
- },
- },
- TTLIdx: []string{},
- }
-
- err := dm.SetResourceProfile(context.Background(), rsPrf, true)
- if err != nil {
- t.Error(err)
- }
- err = dm.SetResource(context.Background(), rs)
- if err != nil {
- t.Error(err)
- }
-
- ccM := &ccMock{
- calls: map[string]func(ctx *context.Context, args any, reply any) error{
- utils.ThresholdSv1ProcessEvent: func(ctx *context.Context, args, reply any) error {
- return utils.ErrExists
- },
- },
- }
- rpcInternal := make(chan birpc.ClientConnector, 1)
- rpcInternal <- ccM
- cM := engine.NewConnManager(cfg)
- cM.AddInternalConn(utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds), utils.ThresholdSv1, rpcInternal)
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, cM)
-
- args := &utils.CGREvent{
- ID: "EventAuthorizeResource",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_Test",
- utils.OptsResourcesUnits: 5,
- utils.OptsResourcesUsageTTL: time.Minute,
- },
- }
- var reply string
-
- if err := rS.V1AllocateResources(context.Background(), args, &reply); err == nil ||
- err != utils.ErrPartiallyExecuted {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrPartiallyExecuted, err)
- }
- dm.DataDB().Flush(utils.EmptyString)
-}
-
-func TestResourcesV1ReleaseResourcesOK(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
-
- rsPrf := &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- AllocationMessage: "Approved",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: 10,
- UsageTTL: time.Minute,
- }
-
- err := dm.SetResourceProfile(context.Background(), rsPrf, true)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "EventAuthorizeResource",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_Test",
- utils.OptsResourcesUnits: 5,
- utils.OptsResourcesUsageTTL: time.Minute,
- },
- }
- var reply string
- if err := rS.V1AllocateResources(context.Background(), args, &reply); err != nil {
- t.Error(err)
- } else if reply != "Approved" {
- t.Errorf("Unexpected reply returned: %q", reply)
- }
-
- if err := rS.V1ReleaseResources(context.Background(), args, &reply); err != nil {
- t.Error(err)
- } else if reply != utils.OK {
- t.Errorf("Unexpected reply returned: %q", reply)
- }
-}
-
-func TestResourcesV1ReleaseResourcesUsageNotFound(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
-
- rsPrf := &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- AllocationMessage: "Approved",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: 10,
- UsageTTL: 0,
- }
-
- err := dm.SetResourceProfile(context.Background(), rsPrf, true)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "EventAuthorizeResource",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_Test",
- utils.OptsResourcesUnits: 5,
- utils.OptsResourcesUsageTTL: time.Minute,
- },
- }
- var reply string
- if err := rS.V1AllocateResources(context.Background(), args, &reply); err != nil {
- t.Error(err)
- } else if reply != "Approved" {
- t.Errorf("Unexpected reply returned: %q", reply)
- }
-
- args = &utils.CGREvent{
- ID: "EventAuthorizeResource",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_Test2",
- utils.OptsResourcesUnits: 5,
- utils.OptsResourcesUsageTTL: time.Minute,
- },
- }
-
- experr := `cannot find usage record with id: RU_Test2`
- if err := rS.V1ReleaseResources(context.Background(), args, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-}
-
-func TestResourcesV1ReleaseResourcesNoMatch(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
-
- rsPrf := &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- AllocationMessage: "Approved",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: 10,
- UsageTTL: time.Minute,
- }
-
- err := dm.SetResourceProfile(context.Background(), rsPrf, true)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "EventAuthorizeResource",
- Event: map[string]any{
- utils.AccountField: "1002",
- },
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_Test",
- utils.OptsResourcesUnits: 5,
- utils.OptsResourcesUsageTTL: time.Minute,
- },
- }
- var reply string
-
- if err := rS.V1ReleaseResources(context.Background(), args, &reply); err == nil ||
- err != utils.ErrNotFound {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err)
- }
-}
-
-func TestResourcesV1ReleaseResourcesMissingParameters(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
-
- rsPrf := &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- AllocationMessage: "Approved",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: 10,
- UsageTTL: time.Minute,
- }
-
- err := dm.SetResourceProfile(context.Background(), rsPrf, true)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "EventAuthorizeResource",
- Event: map[string]any{
- utils.AccountField: "1001",
- utils.OptsResourcesUnits: 5,
- utils.OptsResourcesUsageTTL: time.Minute,
- },
- }
- var reply string
-
- experr := `MANDATORY_IE_MISSING: [UsageID]`
- if err := rS.V1ReleaseResources(context.Background(), args, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-
- args = &utils.CGREvent{
- ID: "EventAuthorizeResource",
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_Test",
- utils.OptsResourcesUnits: 5,
- utils.OptsResourcesUsageTTL: time.Minute,
- },
- }
-
- experr = `MANDATORY_IE_MISSING: [Event]`
- if err := rS.V1ReleaseResources(context.Background(), args, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-
- args = &utils.CGREvent{
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_Test",
- utils.OptsResourcesUnits: 5,
- utils.OptsResourcesUsageTTL: time.Minute,
- },
- }
-
- experr = `MANDATORY_IE_MISSING: [ID]`
- if err := rS.V1ReleaseResources(context.Background(), args, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-
- experr = `MANDATORY_IE_MISSING: [Event]`
- if err := rS.V1ReleaseResources(context.Background(), nil, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-}
-
-func TestResourcesV1ReleaseResourcesCacheReplyExists(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
- config.SetCgrConfig(cfg)
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
- cacheKey := utils.ConcatenatedKey(utils.ResourceSv1ReleaseResources,
- utils.ConcatenatedKey("cgrates.org", "EventReleaseResource"))
-
- rsPrf := &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- AllocationMessage: "Approved",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: -1,
- UsageTTL: time.Minute,
- }
- rs := &utils.Resource{
- Tenant: "cgrates.org",
- ID: "RES1",
- Usages: map[string]*utils.ResourceUsage{
- "RU1": {
- Tenant: "cgrates.org",
- ID: "RU1",
- Units: 10,
- },
- },
- TTLIdx: []string{},
- }
-
- err := dm.SetResourceProfile(context.Background(), rsPrf, true)
- if err != nil {
- t.Error(err)
- }
- err = dm.SetResource(context.Background(), rs)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- Tenant: "cgrates.org",
- ID: "EventReleaseResource",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_Test",
- utils.OptsResourcesUnits: 5,
- utils.OptsResourcesUsageTTL: time.Minute,
- },
- }
- cacheReply := "cacheReply"
- engine.Cache.Set(context.Background(), utils.CacheRPCResponses, cacheKey,
- &utils.CachedRPCResponse{Result: &cacheReply, Error: nil},
- nil, true, utils.NonTransactional)
-
- var reply string
- if err := rS.V1ReleaseResources(context.Background(), args, &reply); err != nil {
- t.Error(err)
- } else if reply != cacheReply {
- t.Errorf("Unexpected reply returned: %q", reply)
- }
- config.SetCgrConfig(config.NewDefaultCGRConfig())
-}
-
-func TestResourcesV1ReleaseResourcesCacheReplySet(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- cfg.CacheCfg().Partitions[utils.CacheRPCResponses].Limit = 1
- config.SetCgrConfig(cfg)
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
- cacheKey := utils.ConcatenatedKey(utils.ResourceSv1ReleaseResources,
- utils.ConcatenatedKey("cgrates.org", "EventReleaseResource"))
-
- rsPrf := &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- AllocationMessage: "Approved",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: -1,
- UsageTTL: time.Minute,
- }
- rs := &utils.Resource{
- Tenant: "cgrates.org",
- ID: "RES1",
- Usages: map[string]*utils.ResourceUsage{
- "RU1": {
- Tenant: "cgrates.org",
- ID: "RU1",
- Units: 4,
- },
- },
- TTLIdx: []string{},
- }
-
- err := dm.SetResourceProfile(context.Background(), rsPrf, true)
- if err != nil {
- t.Error(err)
- }
- err = dm.SetResource(context.Background(), rs)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "EventReleaseResource",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_Test",
- utils.OptsResourcesUnits: 2,
- utils.OptsResourcesUsageTTL: time.Minute,
- },
- }
-
- var reply string
- experr := `cannot find usage record with id: RU_Test`
- if err := rS.V1ReleaseResources(context.Background(), args, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-
- if itm, has := engine.Cache.Get(utils.CacheRPCResponses, cacheKey); has {
- resp := itm.(*utils.CachedRPCResponse)
- if *resp.Result.(*string) != "" {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>",
- "", *resp.Result.(*string))
- }
- }
-
- config.SetCgrConfig(config.NewDefaultCGRConfig())
-}
-
-func TestResourcesV1ReleaseResourcesProcessThErr(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- cfg.ResourceSCfg().StoreInterval = 2
- cfg.ResourceSCfg().ThresholdSConns = []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds)}
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
- ccM := &ccMock{
- calls: map[string]func(ctx *context.Context, args any, reply any) error{
- utils.ThresholdSv1ProcessEvent: func(ctx *context.Context, args, reply any) error {
- return utils.ErrExists
- },
- },
- }
- rpcInternal := make(chan birpc.ClientConnector, 1)
- rpcInternal <- ccM
- cM := engine.NewConnManager(cfg)
- cM.AddInternalConn(utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds), utils.ThresholdSv1, rpcInternal)
-
- rsPrf := &resourceProfile{
- ResourceProfile: &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds)},
- AllocationMessage: "Approved",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: -1,
- UsageTTL: time.Minute,
- },
- }
- rs := &resource{
- Resource: &utils.Resource{
- Tenant: "cgrates.org",
- ID: "RES1",
- Usages: map[string]*utils.ResourceUsage{
- "RU_Test": {
- Tenant: "cgrates.org",
- ID: "RU_Test",
- Units: 4,
- },
- },
- TTLIdx: []string{},
- },
- dirty: utils.BoolPointer(false),
- tUsage: utils.Float64Pointer(10),
- ttl: utils.DurationPointer(time.Minute),
- rPrf: rsPrf,
- }
-
- err := dm.SetResourceProfile(context.Background(), rsPrf.ResourceProfile, true)
- if err != nil {
- t.Error(err)
- }
- err = dm.SetResource(context.Background(), rs.Resource)
- if err != nil {
- t.Error(err)
- }
-
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, cM)
-
- args := &utils.CGREvent{
- ID: "EventAuthorizeResource",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_Test",
- utils.OptsResourcesUnits: 5,
- utils.OptsResourcesUsageTTL: time.Minute,
- },
- }
- var reply string
- var resources Resources
- resources = append(resources, rs)
- if _, err := resources.allocateResource(&utils.ResourceUsage{
- Tenant: "cgrates.org",
- ID: "RU_ID",
- Units: 1}, true); err != nil {
- t.Error(err)
- }
-
- if err := rS.V1ReleaseResources(context.Background(), args, &reply); err == nil ||
- err != utils.ErrPartiallyExecuted {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrPartiallyExecuted, err)
- }
-
- dm.DataDB().Flush(utils.EmptyString)
-}
-
-func TestResourcesStoreResourceError(t *testing.T) {
- engine.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, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(db, cfg, engine.NewConnManager(cfg))
-
- rS := NewResourceService(dm, cfg, engine.NewFilterS(cfg, nil, dm), nil)
-
- rsPrf := &utils.ResourceProfile{
- Tenant: "cgrates.org",
- ID: "RES1",
- FilterIDs: []string{"*string:~*req.Account:1001"},
- ThresholdIDs: []string{utils.MetaNone},
- AllocationMessage: "Approved",
- Weights: utils.DynamicWeights{
- {
- Weight: 10,
- }},
- Limit: 10,
- UsageTTL: time.Minute,
- Stored: true,
- }
-
- err := dm.SetResourceProfile(context.Background(), rsPrf, true)
- if err != nil {
- t.Fatal(err)
- }
-
- args := &utils.CGREvent{
- ID: "EventAuthorizeResource",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{
- utils.OptsResourcesUsageID: "RU_Test",
- utils.OptsResourcesUnits: 5,
- utils.OptsResourcesUsageTTL: time.Minute,
- },
- }
- cfg.DataDbCfg().Items[utils.MetaResources].Replicate = true
- var reply string
- if err := rS.V1AllocateResources(context.Background(), args, &reply); err != utils.ErrDisconnected {
- t.Error(err)
- }
- cfg.DataDbCfg().Items[utils.MetaResources].Replicate = false
-
- if err := rS.V1AllocateResources(context.Background(), 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(context.Background(), args, &reply); err != utils.ErrDisconnected {
- t.Error(err)
- }
-}
-
func TestResourceMatchingResourcesForEventNotFoundInCache(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
db, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
@@ -6125,338 +3681,7 @@ func TestResourcesMatchingResourcesForEventFinalCacheSetErr(t *testing.T) {
}
}
-func TestResourcesV1ResourcesForEventErrRetrieveUsageID(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- cfg.ResourceSCfg().Opts.UsageID = []*config.DynamicStringOpt{
- config.NewDynamicStringOpt([]string{"FLTR_Invalid"}, "*any", "value", nil),
- }
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "ResourcesForEventTest",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{},
- }
-
- experr := `NOT_FOUND:FLTR_Invalid`
- var reply Resources
- if err := rS.V1GetResourcesForEvent(context.Background(), args, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-}
-
-func TestResourcesV1ResourcesForEventErrRetrieveUsageTTL(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- cfg.ResourceSCfg().Opts.UsageTTL = []*config.DynamicDurationOpt{
- config.NewDynamicDurationOpt([]string{"FLTR_Invalid"}, "*any", time.Minute, nil),
- }
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "ResourcesForEventTest",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{},
- }
-
- experr := `NOT_FOUND:FLTR_Invalid`
- var reply Resources
- if err := rS.V1GetResourcesForEvent(context.Background(), args, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-}
-
-func TestResourcesV1AuthorizeResourcesErrRetrieveUsageID(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- cfg.ResourceSCfg().Opts.UsageID = []*config.DynamicStringOpt{
- config.NewDynamicStringOpt([]string{"FLTR_Invalid"}, "*any", "value", nil),
- }
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "ResourcesForEventTest",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{},
- }
-
- experr := `NOT_FOUND:FLTR_Invalid`
- var reply string
- if err := rS.V1AuthorizeResources(context.Background(), args, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-}
-
-func TestResourcesV1AuthorizeResourcesErrRetrieveUnits(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- cfg.ResourceSCfg().Opts.Units = []*config.DynamicFloat64Opt{
- config.NewDynamicFloat64Opt([]string{"FLTR_Invalid"}, "*any", 3, nil),
- }
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "ResourcesForEventTest",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{},
- }
-
- experr := `NOT_FOUND:FLTR_Invalid`
- var reply string
- if err := rS.V1AuthorizeResources(context.Background(), args, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-}
-
-func TestResourcesV1AuthorizeResourcesErrRetrieveUsageTTL(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- cfg.ResourceSCfg().Opts.UsageTTL = []*config.DynamicDurationOpt{
- config.NewDynamicDurationOpt([]string{"FLTR_Invalid"}, "*any", time.Minute, nil),
- }
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "ResourcesForEventTest",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{},
- }
-
- experr := `NOT_FOUND:FLTR_Invalid`
- var reply string
- if err := rS.V1AuthorizeResources(context.Background(), args, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-}
-
-func TestResourcesV1AllocateResourcesErrRetrieveUsageID(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- cfg.ResourceSCfg().Opts.UsageID = []*config.DynamicStringOpt{
- config.NewDynamicStringOpt([]string{"FLTR_Invalid"}, "*any", "value", nil),
- }
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "ResourcesForEventTest",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{},
- }
-
- experr := `NOT_FOUND:FLTR_Invalid`
- var reply string
- if err := rS.V1AllocateResources(context.Background(), args, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-}
-
-func TestResourcesV1AllocateResourcesErrRetrieveUsageTTL(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- cfg.ResourceSCfg().Opts.UsageTTL = []*config.DynamicDurationOpt{
- config.NewDynamicDurationOpt([]string{"FLTR_Invalid"}, "*any", time.Minute, nil),
- }
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "ResourcesForEventTest",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{},
- }
-
- experr := `NOT_FOUND:FLTR_Invalid`
- var reply string
- if err := rS.V1AllocateResources(context.Background(), args, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-}
-
-func TestResourcesV1AllocateResourcesErrRetrieveUnits(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- cfg.ResourceSCfg().Opts.Units = []*config.DynamicFloat64Opt{
- config.NewDynamicFloat64Opt([]string{"FLTR_Invalid"}, "*any", 3, nil),
- }
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "ResourcesForEventTest",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{},
- }
-
- experr := `NOT_FOUND:FLTR_Invalid`
- var reply string
- if err := rS.V1AllocateResources(context.Background(), args, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-}
-
-func TestResourcesV1ReleaseResourcesErrRetrieveUsageID(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- cfg.ResourceSCfg().Opts.UsageID = []*config.DynamicStringOpt{
- config.NewDynamicStringOpt([]string{"FLTR_Invalid"}, "*any", "value", nil),
- }
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "ResourcesForEventTest",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{},
- }
-
- experr := `NOT_FOUND:FLTR_Invalid`
- var reply string
- if err := rS.V1ReleaseResources(context.Background(), args, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-}
-
-func TestResourcesV1ReleaseResourcesErrRetrieveUsageTTL(t *testing.T) {
- tmp := engine.Cache
- defer func() {
- engine.Cache = tmp
- }()
-
- engine.Cache.Clear(nil)
- cfg := config.NewDefaultCGRConfig()
- cfg.ResourceSCfg().Opts.UsageTTL = []*config.DynamicDurationOpt{
- config.NewDynamicDurationOpt([]string{"FLTR_Invalid"}, "*any", time.Minute, nil),
- }
- data, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
- dm := engine.NewDataManager(data, cfg, nil)
- engine.Cache = engine.NewCacheS(cfg, dm, nil, nil)
- fltrs := engine.NewFilterS(cfg, nil, dm)
- rS := NewResourceService(dm, cfg, fltrs, nil)
-
- args := &utils.CGREvent{
- ID: "ResourcesForEventTest",
- Event: map[string]any{
- utils.AccountField: "1001",
- },
- APIOpts: map[string]any{},
- }
-
- experr := `NOT_FOUND:FLTR_Invalid`
- var reply string
- if err := rS.V1ReleaseResources(context.Background(), args, &reply); err == nil ||
- err.Error() != experr {
- t.Errorf("expected: <%+v>, \nreceived: <%+v>", experr, err)
- }
-}
-
func TestResourceMatchingResourcesForEventWeightFromDynamicsErr(t *testing.T) {
-
defer func() {
engine.Cache = engine.NewCacheS(config.NewDefaultCGRConfig(), nil, nil, nil)
}()