mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-20 06:38:45 +05:00
Merge branch 'master' of https://github.com/cgrates/cgrates
This commit is contained in:
@@ -62,7 +62,7 @@ func (rsv1 *ResourceSV1) Call(serviceMethod string, args interface{}, reply inte
|
||||
}
|
||||
|
||||
// GetResourcesForEvent returns Resources matching a specific event
|
||||
func (rsv1 *ResourceSV1) GetResourcesForEvent(args utils.ArgRSv1ResourceUsage, reply *[]*engine.ResourceProfile) error {
|
||||
func (rsv1 *ResourceSV1) GetResourcesForEvent(args utils.ArgRSv1ResourceUsage, reply *engine.Resources) error {
|
||||
return rsv1.rls.V1ResourcesForEvent(args, reply)
|
||||
}
|
||||
|
||||
|
||||
@@ -49,17 +49,18 @@ var sTestsRLSV1 = []func(t *testing.T){
|
||||
testV1RsRpcConn,
|
||||
testV1RsFromFolder,
|
||||
testV1RsGetResourcesForEvent,
|
||||
/*testV1RsAllocateResource,
|
||||
testV1RsTTL0,
|
||||
testV1RsAllocateResource,
|
||||
testV1RsAllowUsage,
|
||||
testV1RsReleaseResource,
|
||||
testV1RsGetResourceConfigBeforeSet,
|
||||
testV1RsSetResourceConfig,
|
||||
testV1RsGetResourceConfigAfterSet,
|
||||
testV1RsUpdateResourceConfig,
|
||||
testV1RsGetResourceConfigAfterUpdate,
|
||||
testV1RsRemResourceCOnfig,
|
||||
testV1RsGetResourceConfigAfterDelete,
|
||||
*/
|
||||
testV1RsDBStore,
|
||||
testV1RsGetResourceProfileBeforeSet,
|
||||
testV1RsSetResourceProfile,
|
||||
testV1RsGetResourceProfileAfterSet,
|
||||
testV1RsUpdateResourceProfile,
|
||||
testV1RsGetResourceProfileAfterUpdate,
|
||||
testV1RsRemResourceProfile,
|
||||
testV1RsGetResourceProfileAfterDelete,
|
||||
testV1RsStopEngine,
|
||||
}
|
||||
|
||||
@@ -173,111 +174,336 @@ func testV1RsGetResourcesForEvent(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func testV1RsAllocateResource(t *testing.T) {
|
||||
func testV1RsTTL0(t *testing.T) {
|
||||
// only matching Resource3
|
||||
argsRU := utils.ArgRSv1ResourceUsage{
|
||||
Tenant: "cgrates.org",
|
||||
UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e21",
|
||||
Event: map[string]interface{}{
|
||||
"Account": "3001",
|
||||
"Destination": "3002"},
|
||||
Units: 1,
|
||||
}
|
||||
var reply string
|
||||
if err := rlsV1Rpc.Call("ResourceSV1.AllocateResource", argsRU, &reply); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
// second allocation should be also allowed
|
||||
argsRU = utils.ArgRSv1ResourceUsage{
|
||||
Tenant: "cgrates.org",
|
||||
UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e21",
|
||||
Event: map[string]interface{}{
|
||||
"Account": "3001",
|
||||
"Destination": "3002"},
|
||||
Units: 1,
|
||||
}
|
||||
if err := rlsV1Rpc.Call("ResourceSV1.AllocateResource", argsRU, &reply); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
// too many units should be rejected
|
||||
argsRU = utils.ArgRSv1ResourceUsage{
|
||||
Tenant: "cgrates.org",
|
||||
UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e22",
|
||||
Event: map[string]interface{}{
|
||||
"Account": "3001",
|
||||
"Destination": "3002"},
|
||||
Units: 2,
|
||||
}
|
||||
if err := rlsV1Rpc.Call("ResourceSV1.AllocateResource", argsRU, &reply); err == nil ||
|
||||
err.Error() != utils.ErrResourceUnavailable.Error() {
|
||||
t.Error(err)
|
||||
}
|
||||
// make sure no usage was recorded
|
||||
var rs *engine.Resources
|
||||
args := &utils.ArgRSv1ResourceUsage{
|
||||
Tenant: "cgrates.org",
|
||||
Event: map[string]interface{}{
|
||||
"Account": "3001",
|
||||
"Destination": "3002"}}
|
||||
if err := rlsV1Rpc.Call("ResourceSV1.GetResourcesForEvent", args, &rs); err != nil {
|
||||
t.Error(err)
|
||||
} else if len(*rs) != 1 {
|
||||
t.Errorf("Resources: %+v", rs)
|
||||
} else {
|
||||
res := *rs
|
||||
if len(res[0].Usages) != 0 || len(res[0].TTLIdx) != 0 {
|
||||
t.Errorf("Resource should have no usage records in: %+v", res[0])
|
||||
}
|
||||
}
|
||||
// release should not give out errors
|
||||
var releaseReply string
|
||||
argsRU = utils.ArgRSv1ResourceUsage{
|
||||
Tenant: "cgrates.org",
|
||||
UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e25", // same ID should be accepted by first group since the previous resource should be expired
|
||||
Event: map[string]interface{}{
|
||||
"Account": "3001",
|
||||
"Destination": "3002"},
|
||||
}
|
||||
if err := rlsV1Rpc.Call("ResourceSV1.ReleaseResource", argsRU, &releaseReply); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
attrRU := utils.ArgRSv1ResourceUsage{
|
||||
func testV1RsAllocateResource(t *testing.T) {
|
||||
// first event matching Resource1
|
||||
var reply string
|
||||
argsRU := utils.ArgRSv1ResourceUsage{
|
||||
Tenant: "cgrates.org",
|
||||
UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e51",
|
||||
Event: map[string]interface{}{"Account": "1002", "Subject": "1001", "Destination": "1002"},
|
||||
Units: 3,
|
||||
Event: map[string]interface{}{
|
||||
"Account": "1002",
|
||||
"Subject": "1001",
|
||||
"Destination": "1002"},
|
||||
Units: 3,
|
||||
}
|
||||
if err := rlsV1Rpc.Call("ResourceSV1.AllocateResource", attrRU, &reply); err != nil {
|
||||
if err := rlsV1Rpc.Call("ResourceSV1.AllocateResource", argsRU, &reply); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if reply != "ResGroup1" {
|
||||
t.Errorf("Expecting: %+v, received: %+v", "ResGroup1", reply)
|
||||
eAllocationMsg := "ResGroup1"
|
||||
if reply != eAllocationMsg {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eAllocationMsg, reply)
|
||||
}
|
||||
|
||||
time.Sleep(time.Duration(1000) * time.Millisecond)
|
||||
|
||||
attrRU = utils.ArgRSv1ResourceUsage{
|
||||
// Second event to test matching of exact limit of first resource
|
||||
argsRU = utils.ArgRSv1ResourceUsage{
|
||||
Tenant: "cgrates.org",
|
||||
UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e52",
|
||||
Event: map[string]interface{}{"Destination": "100"},
|
||||
Units: 5,
|
||||
Event: map[string]interface{}{
|
||||
"Account": "1002",
|
||||
"Subject": "1001",
|
||||
"Destination": "1002"},
|
||||
Units: 4,
|
||||
}
|
||||
if err := rlsV1Rpc.Call("ResourceSV1.AllocateResource", attrRU, &reply); err != nil {
|
||||
if err := rlsV1Rpc.Call("ResourceSV1.AllocateResource", argsRU, &reply); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if reply != "ResGroup2" {
|
||||
t.Errorf("Expecting: %+v, received: %+v", "ResGroup2", reply)
|
||||
eAllocationMsg = "ResGroup1"
|
||||
if reply != eAllocationMsg {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eAllocationMsg, reply)
|
||||
}
|
||||
|
||||
time.Sleep(time.Duration(1000) * time.Millisecond)
|
||||
|
||||
attrRU = utils.ArgRSv1ResourceUsage{
|
||||
// Third event testing overflow to second resource which still has one resource available
|
||||
argsRU = utils.ArgRSv1ResourceUsage{
|
||||
Tenant: "cgrates.org",
|
||||
UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e53",
|
||||
Event: map[string]interface{}{"Account": "1002", "Subject": "1001", "Destination": "1002"},
|
||||
Units: 3,
|
||||
Event: map[string]interface{}{
|
||||
"Account": "dan",
|
||||
"Subject": "dan",
|
||||
"Destination": "1002"},
|
||||
Units: 1,
|
||||
}
|
||||
if err := rlsV1Rpc.Call("ResourceSV1.AllocateResource", attrRU, &reply); err != nil {
|
||||
if err := rlsV1Rpc.Call("ResourceSV1.AllocateResource", argsRU, &reply); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if reply != "ResGroup1" {
|
||||
t.Errorf("Expecting: %+v, received: %+v", "ResGroup1", reply)
|
||||
eAllocationMsg = "ResGroup2"
|
||||
if reply != eAllocationMsg {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eAllocationMsg, reply)
|
||||
}
|
||||
// Test resource unavailable
|
||||
argsRU = utils.ArgRSv1ResourceUsage{
|
||||
Tenant: "cgrates.org",
|
||||
UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e54", // same ID should be accepted by first group since the previous resource should be expired
|
||||
Event: map[string]interface{}{
|
||||
"Account": "1002",
|
||||
"Subject": "1001",
|
||||
"Destination": "1002"},
|
||||
Units: 1,
|
||||
}
|
||||
if err := rlsV1Rpc.Call("ResourceSV1.AllocateResource", argsRU, &reply); err == nil || err.Error() != utils.ErrResourceUnavailable.Error() {
|
||||
t.Error(err)
|
||||
}
|
||||
eAllocationMsg = "ResGroup1"
|
||||
time.Sleep(time.Duration(1000) * time.Millisecond) // Give time for allocations on first resource to expire
|
||||
|
||||
argsRU = utils.ArgRSv1ResourceUsage{
|
||||
Tenant: "cgrates.org",
|
||||
UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e55", // same ID should be accepted by first group since the previous resource should be expired
|
||||
Event: map[string]interface{}{
|
||||
"Account": "1002",
|
||||
"Subject": "1001",
|
||||
"Destination": "1002"},
|
||||
Units: 1,
|
||||
}
|
||||
if err := rlsV1Rpc.Call("ResourceSV1.AllocateResource", argsRU, &reply); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
eAllocationMsg = "ResGroup1"
|
||||
if reply != eAllocationMsg {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eAllocationMsg, reply)
|
||||
}
|
||||
}
|
||||
|
||||
func testV1RsAllowUsage(t *testing.T) {
|
||||
var allowed bool
|
||||
attrRU := utils.ArgRSv1ResourceUsage{
|
||||
UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e51",
|
||||
Event: map[string]interface{}{"Account": "1002", "Subject": "1001", "Destination": "1002"},
|
||||
Units: 1,
|
||||
argsRU := utils.ArgRSv1ResourceUsage{
|
||||
Tenant: "cgrates.org",
|
||||
UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e61",
|
||||
Event: map[string]interface{}{
|
||||
"Account": "1002",
|
||||
"Subject": "1001",
|
||||
"Destination": "1002"},
|
||||
Units: 6,
|
||||
}
|
||||
if err := rlsV1Rpc.Call("ResourceSV1.AllowUsage", attrRU, &allowed); err != nil {
|
||||
if err := rlsV1Rpc.Call("ResourceSV1.AllowUsage", argsRU, &allowed); err != nil {
|
||||
t.Error(err)
|
||||
} else if !allowed {
|
||||
t.Errorf("Expecting: %+v, received: %+v", true, allowed)
|
||||
} else if !allowed { // already 3 usages active before allow call, we should have now more than allowed
|
||||
t.Error("resource is not allowed")
|
||||
}
|
||||
|
||||
attrRU = utils.ArgRSv1ResourceUsage{
|
||||
UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e51",
|
||||
Event: map[string]interface{}{"Account": "1002", "Subject": "1001", "Destination": "1002"},
|
||||
Units: 2,
|
||||
argsRU = utils.ArgRSv1ResourceUsage{
|
||||
Tenant: "cgrates.org",
|
||||
UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e61",
|
||||
Event: map[string]interface{}{
|
||||
"Account": "1002",
|
||||
"Subject": "1001",
|
||||
"Destination": "1002"},
|
||||
Units: 7,
|
||||
}
|
||||
if err := rlsV1Rpc.Call("ResourceSV1.AllowUsage", attrRU, &allowed); err != nil { // already
|
||||
if err := rlsV1Rpc.Call("ResourceSV1.AllowUsage", argsRU, &allowed); err != nil {
|
||||
t.Error(err)
|
||||
} else if allowed { // already 3 usages active before allow call, we should have now more than allowed
|
||||
t.Error("Resource allowed")
|
||||
t.Error("resource should not be allowed")
|
||||
}
|
||||
}
|
||||
|
||||
func testV1RsReleaseResource(t *testing.T) {
|
||||
// relase the only resource active for Resource1
|
||||
var reply string
|
||||
attrRU := utils.ArgRSv1ResourceUsage{
|
||||
UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e52",
|
||||
Event: map[string]interface{}{"Destination": "100"},
|
||||
Units: 2,
|
||||
argsRU := utils.ArgRSv1ResourceUsage{
|
||||
Tenant: "cgrates.org",
|
||||
UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e55", // same ID should be accepted by first group since the previous resource should be expired
|
||||
Event: map[string]interface{}{
|
||||
"Account": "1002",
|
||||
"Subject": "1001",
|
||||
"Destination": "1002"},
|
||||
}
|
||||
if err := rlsV1Rpc.Call("ResourceSV1.ReleaseResource", attrRU, &reply); err != nil {
|
||||
if err := rlsV1Rpc.Call("ResourceSV1.ReleaseResource", argsRU, &reply); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
// try reserving with full units for Resource1, case which did not work in previous test
|
||||
// only match Resource1 since we don't want for storing of the resource2 bellow
|
||||
argsRU = utils.ArgRSv1ResourceUsage{
|
||||
Tenant: "cgrates.org",
|
||||
UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e61",
|
||||
Event: map[string]interface{}{
|
||||
"Account": "1002",
|
||||
"Subject": "1001",
|
||||
"Destination": "2002"},
|
||||
Units: 7,
|
||||
}
|
||||
var allowed bool
|
||||
if err := rlsV1Rpc.Call("ResourceSV1.AllowUsage", attrRU, &allowed); err != nil {
|
||||
if err := rlsV1Rpc.Call("ResourceSV1.AllowUsage", argsRU, &allowed); err != nil {
|
||||
t.Error(err)
|
||||
} else if !allowed {
|
||||
t.Error("not allowed")
|
||||
t.Error("resource should be allowed")
|
||||
}
|
||||
attrRU.Units += 7
|
||||
if err := rlsV1Rpc.Call("ResourceSV1.AllowUsage", attrRU, &allowed); err != nil {
|
||||
var rs *engine.Resources
|
||||
args := &utils.ArgRSv1ResourceUsage{
|
||||
Tenant: "cgrates.org",
|
||||
Event: map[string]interface{}{
|
||||
"Account": "1002",
|
||||
"Subject": "1001",
|
||||
"Destination": "1002"}}
|
||||
if err := rlsV1Rpc.Call("ResourceSV1.GetResourcesForEvent", args, &rs); err != nil {
|
||||
t.Error(err)
|
||||
} else if allowed {
|
||||
t.Error("Resource should not be allowed")
|
||||
} else if len(*rs) != 2 {
|
||||
t.Errorf("Resources: %+v", rs)
|
||||
}
|
||||
// make sure Resource1 have no more active resources
|
||||
for _, r := range *rs {
|
||||
if r.ID == "ResGroup1" &&
|
||||
(len(r.Usages) != 0 || len(r.TTLIdx) != 0) {
|
||||
t.Errorf("Unexpected resource: %+v", r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testV1RsGetResourceConfigBeforeSet(t *testing.T) {
|
||||
func testV1RsDBStore(t *testing.T) {
|
||||
argsRU := utils.ArgRSv1ResourceUsage{
|
||||
Tenant: "cgrates.org",
|
||||
UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e71",
|
||||
Event: map[string]interface{}{
|
||||
"Account": "1002",
|
||||
"Subject": "1001",
|
||||
"Destination": "1002"},
|
||||
Units: 1,
|
||||
}
|
||||
var reply string
|
||||
eAllocationMsg := "ResGroup1"
|
||||
if err := rlsV1Rpc.Call("ResourceSV1.AllocateResource", argsRU, &reply); err != nil {
|
||||
t.Error(err)
|
||||
} else if reply != eAllocationMsg {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eAllocationMsg, reply)
|
||||
}
|
||||
var rs *engine.Resources
|
||||
args := &utils.ArgRSv1ResourceUsage{
|
||||
Tenant: "cgrates.org",
|
||||
Event: map[string]interface{}{
|
||||
"Account": "1002",
|
||||
"Subject": "1001",
|
||||
"Destination": "1002"}}
|
||||
if err := rlsV1Rpc.Call("ResourceSV1.GetResourcesForEvent", args, &rs); err != nil {
|
||||
t.Error(err)
|
||||
} else if len(*rs) != 2 {
|
||||
t.Errorf("Resources: %+v", rs)
|
||||
}
|
||||
// count resources before restart
|
||||
for _, r := range *rs {
|
||||
switch r.ID {
|
||||
case "ResGroup1":
|
||||
if len(r.Usages) != 1 || len(r.TTLIdx) != 1 {
|
||||
t.Errorf("Unexpected resource: %+v", r)
|
||||
}
|
||||
case "ResGroup2":
|
||||
if len(r.Usages) != 4 || len(r.TTLIdx) != 4 {
|
||||
t.Errorf("Unexpected resource: %+v", r)
|
||||
}
|
||||
}
|
||||
}
|
||||
if _, err := engine.StopStartEngine(rlsV1CfgPath, resDelay); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var err error
|
||||
rlsV1Rpc, err = jsonrpc.Dial("tcp", rlsV1Cfg.RPCJSONListen) // We connect over JSON so we can also troubleshoot if needed
|
||||
if err != nil {
|
||||
t.Fatal("Could not connect to rater: ", err.Error())
|
||||
}
|
||||
rs = new(engine.Resources)
|
||||
args = &utils.ArgRSv1ResourceUsage{
|
||||
Tenant: "cgrates.org",
|
||||
Event: map[string]interface{}{
|
||||
"Account": "1002",
|
||||
"Subject": "1001",
|
||||
"Destination": "1002"}}
|
||||
if err := rlsV1Rpc.Call("ResourceSV1.GetResourcesForEvent", args, &rs); err != nil {
|
||||
t.Error(err)
|
||||
} else if len(*rs) != 2 {
|
||||
t.Errorf("Resources: %+v", rs)
|
||||
}
|
||||
// count resources after restart
|
||||
for _, r := range *rs {
|
||||
switch r.ID {
|
||||
case "ResGroup1":
|
||||
if len(r.Usages) != 0 || len(r.TTLIdx) != 0 {
|
||||
t.Errorf("Unexpected resource: %+v", r)
|
||||
}
|
||||
case "ResGroup2":
|
||||
if len(r.Usages) != 3 || len(r.TTLIdx) != 3 {
|
||||
t.Errorf("Unexpected resource: %+v", r)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testV1RsGetResourceProfileBeforeSet(t *testing.T) {
|
||||
var reply *string
|
||||
if err := rlsV1Rpc.Call("ApierV1.GetResourceConfig", &utils.TenantID{Tenant: "cgrates.org", ID: "RCFG1"},
|
||||
if err := rlsV1Rpc.Call("ApierV1.GetResourceProfile", &utils.TenantID{Tenant: "cgrates.org", ID: "RCFG1"},
|
||||
&reply); err == nil || err.Error() != utils.ErrNotFound.Error() {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testV1RsSetResourceConfig(t *testing.T) {
|
||||
func testV1RsSetResourceProfile(t *testing.T) {
|
||||
rlsConfig = &engine.ResourceProfile{
|
||||
ID: "RCFG1",
|
||||
Tenant: "cgrates.org",
|
||||
ID: "RCFG1",
|
||||
Filters: []*engine.RequestFilter{
|
||||
&engine.RequestFilter{
|
||||
Type: "type",
|
||||
@@ -298,16 +524,16 @@ func testV1RsSetResourceConfig(t *testing.T) {
|
||||
Thresholds: []string{"Val1", "Val2"},
|
||||
}
|
||||
var result string
|
||||
if err := rlsV1Rpc.Call("ApierV1.SetResourceConfig", rlsConfig, &result); err != nil {
|
||||
if err := rlsV1Rpc.Call("ApierV1.SetResourceProfile", rlsConfig, &result); err != nil {
|
||||
t.Error(err)
|
||||
} else if result != utils.OK {
|
||||
t.Error("Unexpected reply returned", result)
|
||||
}
|
||||
}
|
||||
|
||||
func testV1RsGetResourceConfigAfterSet(t *testing.T) {
|
||||
func testV1RsGetResourceProfileAfterSet(t *testing.T) {
|
||||
var reply *engine.ResourceProfile
|
||||
if err := rlsV1Rpc.Call("ApierV1.GetResourceConfig",
|
||||
if err := rlsV1Rpc.Call("ApierV1.GetResourceProfile",
|
||||
&utils.TenantID{Tenant: "cgrates.org", ID: rlsConfig.ID}, &reply); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(reply, rlsConfig) {
|
||||
@@ -315,7 +541,7 @@ func testV1RsGetResourceConfigAfterSet(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func testV1RsUpdateResourceConfig(t *testing.T) {
|
||||
func testV1RsUpdateResourceProfile(t *testing.T) {
|
||||
var result string
|
||||
rlsConfig.Filters = []*engine.RequestFilter{
|
||||
&engine.RequestFilter{
|
||||
@@ -329,16 +555,16 @@ func testV1RsUpdateResourceConfig(t *testing.T) {
|
||||
Values: []string{"1001", "1002"},
|
||||
},
|
||||
}
|
||||
if err := rlsV1Rpc.Call("ApierV1.SetResourceConfig", rlsConfig, &result); err != nil {
|
||||
if err := rlsV1Rpc.Call("ApierV1.SetResourceProfile", rlsConfig, &result); err != nil {
|
||||
t.Error(err)
|
||||
} else if result != utils.OK {
|
||||
t.Error("Unexpected reply returned", result)
|
||||
}
|
||||
}
|
||||
|
||||
func testV1RsGetResourceConfigAfterUpdate(t *testing.T) {
|
||||
func testV1RsGetResourceProfileAfterUpdate(t *testing.T) {
|
||||
var reply *engine.ResourceProfile
|
||||
if err := rlsV1Rpc.Call("ApierV1.GetResourceConfig",
|
||||
if err := rlsV1Rpc.Call("ApierV1.GetResourceProfile",
|
||||
&utils.TenantID{Tenant: "cgrates.org", ID: rlsConfig.ID}, &reply); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(reply, rlsConfig) {
|
||||
@@ -346,9 +572,9 @@ func testV1RsGetResourceConfigAfterUpdate(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func testV1RsRemResourceCOnfig(t *testing.T) {
|
||||
func testV1RsRemResourceProfile(t *testing.T) {
|
||||
var resp string
|
||||
if err := rlsV1Rpc.Call("ApierV1.RemResourceConfig",
|
||||
if err := rlsV1Rpc.Call("ApierV1.RemResourceProfile",
|
||||
&utils.TenantID{Tenant: "cgrates.org", ID: rlsConfig.ID}, &resp); err != nil {
|
||||
t.Error(err)
|
||||
} else if resp != utils.OK {
|
||||
@@ -356,9 +582,9 @@ func testV1RsRemResourceCOnfig(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func testV1RsGetResourceConfigAfterDelete(t *testing.T) {
|
||||
func testV1RsGetResourceProfileAfterDelete(t *testing.T) {
|
||||
var reply *string
|
||||
if err := rlsV1Rpc.Call("ApierV1.GetResourceConfig",
|
||||
if err := rlsV1Rpc.Call("ApierV1.GetResourceProfile",
|
||||
&utils.TenantID{Tenant: "cgrates.org", ID: "RCFG1"}, &reply); err == nil || err.Error() != utils.ErrNotFound.Error() {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -115,6 +115,7 @@
|
||||
|
||||
"resources": {
|
||||
"enabled": true,
|
||||
"store_interval": "1s",
|
||||
},
|
||||
|
||||
|
||||
|
||||
@@ -108,6 +108,7 @@
|
||||
|
||||
"resources": {
|
||||
"enabled": true,
|
||||
"store_interval": "1s",
|
||||
},
|
||||
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
|
||||
"resources": {
|
||||
"enabled": true,
|
||||
"store_interval": "1s",
|
||||
},
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#Tenant[0],Id[1],FilterType[2],FilterFieldName[3],FilterFieldValues[4],ActivationInterval[5],TTL[6],Limit[7],AllocationMessage[8],Blocker[9],Stored[10],Weight[11],Thresholds[12]
|
||||
cgrates.org,ResGroup1,*string,Account,1001;1002,2014-07-29T15:00:00Z,1s,7,,true,true,20,
|
||||
cgrates.org,ResGroup1,*string,Account,1001;1002,2014-07-29T15:00:00Z,1s,7,,false,false,20,
|
||||
cgrates.org,ResGroup1,*string_prefix,Destination,10;20,,,,,,,,
|
||||
cgrates.org,ResGroup1,*rsr_fields,,Subject(~^1.*1$);Destination(1002),,,,,,,,
|
||||
cgrates.org,ResGroup2,*destinations,Destination,DST_FS,2014-07-29T15:00:00Z,3600s,8,SPECIAL_1002,true,true,10,
|
||||
cgrates.org,ResGroup3,*string,Account,3001,2014-07-29T15:00:00Z,1s,3,,true,true,20,
|
||||
cgrates.org,ResGroup2,*destinations,Destination,DST_FS,2014-07-29T15:00:00Z,3600s,8,SPECIAL_1002,false,true,10,
|
||||
cgrates.org,ResGroup3,*string,Account,3001,2014-07-29T15:00:00Z,0s,1,,true,false,20,
|
||||
#cgrates.org,ResGroup3,*timings,SetupTime,PEAK,,,,,,,,
|
||||
#cgrates.org,ResGroup3,*stats,,CDRST1:*min_ASR:34;CDRST_1001:*min_ASR:20,,,,,,,,
|
||||
|
||||
|
@@ -125,6 +125,7 @@ func (r *Resource) removeExpiredUnits() {
|
||||
}
|
||||
}
|
||||
r.TTLIdx = r.TTLIdx[firstActive:]
|
||||
r.tUsage = nil
|
||||
}
|
||||
|
||||
// totalUsage returns the sum of all usage units
|
||||
@@ -148,6 +149,9 @@ func (r *Resource) recordUsage(ru *ResourceUsage) (err error) {
|
||||
return fmt.Errorf("duplicate resource usage with id: %s", ru.TenantID())
|
||||
}
|
||||
if r.ttl != nil {
|
||||
if *r.ttl == 0 {
|
||||
return // no recording for ttl of 0
|
||||
}
|
||||
ru = ru.Clone() // don't influence the initial ru
|
||||
ru.ExpiryTime = time.Now().Add(*r.ttl)
|
||||
}
|
||||
@@ -211,7 +215,8 @@ func (rs Resources) recordUsage(ru *ResourceUsage) (err error) {
|
||||
// clearUsage gives back the units to the pool
|
||||
func (rs Resources) clearUsage(ruTntID string) (err error) {
|
||||
for _, r := range rs {
|
||||
if errClear := r.clearUsage(ruTntID); errClear != nil {
|
||||
if errClear := r.clearUsage(ruTntID); errClear != nil &&
|
||||
r.ttl != nil && *r.ttl != 0 { // we only consider not found error in case of ttl different than 0
|
||||
utils.Logger.Warning(fmt.Sprintf("<ResourceLimits>, clear ruID: %s, err: %s", ruTntID, errClear.Error()))
|
||||
err = errClear
|
||||
}
|
||||
@@ -236,10 +241,10 @@ func (rs Resources) tenatIDsStr() []string {
|
||||
return ids
|
||||
}
|
||||
|
||||
// AllocateResource attempts allocating resources for a *ResourceUsage
|
||||
// allocateResource attempts allocating resources for a *ResourceUsage
|
||||
// simulates on dryRun
|
||||
// returns utils.ErrResourceUnavailable if allocation is not possible
|
||||
func (rs Resources) AllocateResource(ru *ResourceUsage, dryRun bool) (alcMessage string, err error) {
|
||||
func (rs Resources) allocateResource(ru *ResourceUsage, dryRun bool) (alcMessage string, err error) {
|
||||
if len(rs) == 0 {
|
||||
return "", utils.ErrResourceUnavailable
|
||||
}
|
||||
@@ -248,6 +253,7 @@ func (rs Resources) AllocateResource(ru *ResourceUsage, dryRun bool) (alcMessage
|
||||
defer guardian.Guardian.UnguardIDs(lockIDs...)
|
||||
// Simulate resource usage
|
||||
for _, r := range rs {
|
||||
r.removeExpiredUnits()
|
||||
if r.rPrf.Limit >= r.totalUsage()+ru.Units {
|
||||
if alcMessage == "" {
|
||||
if r.rPrf.AllocationMessage != "" {
|
||||
@@ -363,10 +369,12 @@ func (rS *ResourceService) runBackup() {
|
||||
select {
|
||||
case <-rS.stopBackup:
|
||||
return
|
||||
default:
|
||||
}
|
||||
rS.storeResources()
|
||||
time.Sleep(rS.storeInterval)
|
||||
}
|
||||
time.Sleep(rS.storeInterval)
|
||||
|
||||
}
|
||||
|
||||
// cachedResourcesForEvent attempts to retrieve cached resources for an event
|
||||
@@ -454,10 +462,10 @@ func (rS *ResourceService) matchingResourcesForEvent(tenant string, ev map[strin
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if rPrf.Stored {
|
||||
if rPrf.Stored && r.dirty == nil {
|
||||
r.dirty = utils.BoolPointer(false)
|
||||
}
|
||||
if rPrf.UsageTTL > 0 {
|
||||
if rPrf.UsageTTL >= 0 {
|
||||
r.ttl = utils.DurationPointer(rPrf.UsageTTL)
|
||||
}
|
||||
r.rPrf = rPrf
|
||||
@@ -481,7 +489,7 @@ func (rS *ResourceService) matchingResourcesForEvent(tenant string, ev map[strin
|
||||
}
|
||||
|
||||
// V1ResourcesForEvent returns active resource configs matching the event
|
||||
func (rS *ResourceService) V1ResourcesForEvent(args utils.ArgRSv1ResourceUsage, reply *[]*ResourceProfile) (err error) {
|
||||
func (rS *ResourceService) V1ResourcesForEvent(args utils.ArgRSv1ResourceUsage, reply *Resources) (err error) {
|
||||
if args.Tenant == "" {
|
||||
return utils.NewErrMandatoryIeMissing("Tenant")
|
||||
}
|
||||
@@ -498,10 +506,8 @@ func (rS *ResourceService) V1ResourcesForEvent(args utils.ArgRSv1ResourceUsage,
|
||||
if len(mtcRLs) == 0 {
|
||||
return utils.ErrNotFound
|
||||
}
|
||||
for _, r := range mtcRLs {
|
||||
*reply = append(*reply, r.rPrf)
|
||||
}
|
||||
return nil
|
||||
*reply = mtcRLs
|
||||
return
|
||||
}
|
||||
|
||||
// V1AllowUsage queries service to find if an Usage is allowed
|
||||
@@ -516,7 +522,7 @@ func (rS *ResourceService) V1AllowUsage(args utils.ArgRSv1ResourceUsage, allow *
|
||||
}
|
||||
cache.Set(utils.EventResourcesPrefix+args.TenantID(), mtcRLs.tenantIDs(), true, "")
|
||||
}
|
||||
if _, err = mtcRLs.AllocateResource(
|
||||
if _, err = mtcRLs.allocateResource(
|
||||
&ResourceUsage{
|
||||
Tenant: args.Tenant,
|
||||
ID: args.UsageID,
|
||||
@@ -546,7 +552,8 @@ func (rS *ResourceService) V1AllocateResource(args utils.ArgRSv1ResourceUsage, r
|
||||
} else {
|
||||
wasCached = true
|
||||
}
|
||||
alcMsg, err := mtcRLs.AllocateResource(&ResourceUsage{ID: args.UsageID, Units: args.Units}, false)
|
||||
alcMsg, err := mtcRLs.allocateResource(
|
||||
&ResourceUsage{Tenant: args.Tenant, ID: args.UsageID, Units: args.Units}, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -572,8 +579,8 @@ func (rS *ResourceService) V1AllocateResource(args utils.ArgRSv1ResourceUsage, r
|
||||
rS.StoreResource(r)
|
||||
} else if r.dirty != nil {
|
||||
*r.dirty = true // mark it to be saved
|
||||
rS.storedResources[r.TenantID()] = true
|
||||
}
|
||||
rS.storedResources[r.ID] = true
|
||||
}
|
||||
rS.srMux.Unlock()
|
||||
*reply = alcMsg
|
||||
@@ -604,7 +611,7 @@ func (rS *ResourceService) V1ReleaseResource(args utils.ArgRSv1ResourceUsage, re
|
||||
rS.StoreResource(r)
|
||||
} else {
|
||||
*r.dirty = true // mark it to be saved
|
||||
rS.storedResources[r.ID] = true
|
||||
rS.storedResources[r.TenantID()] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ func TestRSRecordUsage1(t *testing.T) {
|
||||
Tenant: "cgrates.org",
|
||||
ID: "RU1",
|
||||
ExpiryTime: time.Date(2014, 7, 3, 13, 43, 0, 1, time.UTC),
|
||||
Units: 2,
|
||||
Units: 1,
|
||||
}
|
||||
|
||||
ru2 = &ResourceUsage{
|
||||
@@ -113,7 +113,7 @@ func TestRSRemoveExpiredUnits(t *testing.T) {
|
||||
if len(r1.TTLIdx) != 0 {
|
||||
t.Errorf("Expecting: %+v, received: %+v", 0, len(r1.TTLIdx))
|
||||
}
|
||||
if *r1.tUsage != 0 {
|
||||
if r1.tUsage != nil && *r1.tUsage != 0 {
|
||||
t.Errorf("Expecting: %+v, received: %+v", 0, r1.tUsage)
|
||||
}
|
||||
}
|
||||
@@ -123,8 +123,8 @@ func TestRSUsedUnits(t *testing.T) {
|
||||
ru1.ID: ru1,
|
||||
}
|
||||
r1.tUsage = nil
|
||||
if usedUnits := r1.totalUsage(); usedUnits != 2 {
|
||||
t.Errorf("Expecting: %+v, received: %+v", 2, usedUnits)
|
||||
if usedUnits := r1.totalUsage(); usedUnits != 1 {
|
||||
t.Errorf("Expecting: %+v, received: %+v", 1, usedUnits)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,28 +205,21 @@ func TestRSRecordUsages(t *testing.T) {
|
||||
func TestRSAllocateResource(t *testing.T) {
|
||||
rs.clearUsage(ru1.ID)
|
||||
rs.clearUsage(ru2.ID)
|
||||
|
||||
rs[0].rPrf.UsageTTL = time.Duration(20 * time.Second)
|
||||
rs[1].rPrf.UsageTTL = time.Duration(20 * time.Second)
|
||||
//ru1.ExpiryTime = time.Now()
|
||||
//ru2.Time = time.Now()
|
||||
|
||||
if alcMessage, err := rs.AllocateResource(ru1, false); err != nil {
|
||||
ru1.ExpiryTime = time.Now().Add(time.Duration(1 * time.Second))
|
||||
ru2.ExpiryTime = time.Now().Add(time.Duration(1 * time.Second))
|
||||
if alcMessage, err := rs.allocateResource(ru1, false); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else {
|
||||
if alcMessage != "ALLOC" {
|
||||
t.Errorf("Wrong allocation message: %v", alcMessage)
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := rs.AllocateResource(ru2, false); err != utils.ErrResourceUnavailable {
|
||||
if _, err := rs.allocateResource(ru2, false); err != utils.ErrResourceUnavailable {
|
||||
t.Error("Did not receive " + utils.ErrResourceUnavailable.Error() + " error")
|
||||
}
|
||||
|
||||
rs[0].rPrf.Limit = 2
|
||||
rs[0].rPrf.Limit = 1
|
||||
rs[1].rPrf.Limit = 4
|
||||
|
||||
if alcMessage, err := rs.AllocateResource(ru1, true); err != nil {
|
||||
if alcMessage, err := rs.allocateResource(ru1, true); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else {
|
||||
if alcMessage != "RL2" {
|
||||
@@ -234,7 +227,7 @@ func TestRSAllocateResource(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
if alcMessage, err := rs.AllocateResource(ru2, false); err != nil {
|
||||
if alcMessage, err := rs.allocateResource(ru2, false); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else {
|
||||
if alcMessage != "RL2" {
|
||||
@@ -243,7 +236,7 @@ func TestRSAllocateResource(t *testing.T) {
|
||||
}
|
||||
|
||||
ru2.Units = 0
|
||||
if _, err := rs.AllocateResource(ru2, false); err == nil {
|
||||
if _, err := rs.allocateResource(ru2, false); err == nil {
|
||||
t.Error("Duplicate ResourceUsage id should not be allowed")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user