diff --git a/engine/reslimiter.go b/engine/reslimiter.go index 71ea2528c..6e35b71de 100644 --- a/engine/reslimiter.go +++ b/engine/reslimiter.go @@ -31,9 +31,9 @@ import ( ) type ResourceUsage struct { - ID string - UsageTime time.Time - UsageUnits float64 + ID string // Unique identifier of this resourceUsage, Eg: FreeSWITCH UUID + UsageTime time.Time // So we can expire it later + UsageUnits float64 // Number of units used } // ResourceLimit represents a limit imposed for accessing a resource (eg: new calls) @@ -46,7 +46,7 @@ type ResourceLimit struct { Limit float64 // Limit value ActionTriggers ActionTriggers // Thresholds to check after changing Limit UsageTTL time.Duration // Expire usage after this duration - Usage map[string]*ResourceUsage //Keep a record of usage, bounded with timestamps so we can expire too long records + Usage map[string]*ResourceUsage // Keep a record of usage, bounded with timestamps so we can expire too long records usageCounter float64 // internal counter aggregating real usage of ResourceLimit } diff --git a/engine/reslimiter_test.go b/engine/reslimiter_test.go index d63b98011..2752c9e51 100644 --- a/engine/reslimiter_test.go +++ b/engine/reslimiter_test.go @@ -40,6 +40,7 @@ func TestRLsIndexStringFilters(t *testing.T) { }}, ActivationTime: time.Date(2014, 7, 3, 13, 43, 0, 1, time.UTC), Limit: 2, + Usage: make(map[string]*ResourceUsage), }, &ResourceLimit{ ID: "RL2", @@ -51,6 +52,7 @@ func TestRLsIndexStringFilters(t *testing.T) { ActivationTime: time.Date(2014, 7, 3, 13, 43, 0, 1, time.UTC), Limit: 1, UsageTTL: time.Duration(1 * time.Millisecond), + Usage: make(map[string]*ResourceUsage), }, &ResourceLimit{ ID: "RL4", @@ -60,6 +62,7 @@ func TestRLsIndexStringFilters(t *testing.T) { }, ActivationTime: time.Date(2014, 7, 3, 13, 43, 0, 1, time.UTC), Limit: 1, + Usage: make(map[string]*ResourceUsage), }, &ResourceLimit{ ID: "RL5", @@ -70,6 +73,7 @@ func TestRLsIndexStringFilters(t *testing.T) { ActivationTime: time.Date(2014, 7, 3, 13, 43, 0, 1, time.UTC), Limit: 1, UsageTTL: time.Duration(10 * time.Millisecond), + Usage: make(map[string]*ResourceUsage), }, } for _, rl := range rls { @@ -115,6 +119,7 @@ func TestRLsIndexStringFilters(t *testing.T) { }, ActivationTime: time.Date(2014, 7, 3, 13, 43, 0, 1, time.UTC), Limit: 1, + Usage: make(map[string]*ResourceUsage), } CacheSet(utils.ResourceLimitsPrefix+rl3.ID, rl3) rl6 := &ResourceLimit{ // Add it so we can test expiryTime @@ -126,6 +131,7 @@ func TestRLsIndexStringFilters(t *testing.T) { ActivationTime: time.Date(2014, 7, 3, 13, 43, 0, 1, time.UTC), ExpiryTime: time.Date(2014, 7, 3, 13, 43, 0, 1, time.UTC), Limit: 1, + Usage: make(map[string]*ResourceUsage), } CacheSet(utils.ResourceLimitsPrefix+rl6.ID, rl6) eIndexes = map[string]map[string]utils.StringMap{ @@ -178,6 +184,7 @@ func TestRLsMatchingResourceLimitsForEvent(t *testing.T) { }}, ActivationTime: time.Date(2014, 7, 3, 13, 43, 0, 1, time.UTC), Limit: 2, + Usage: make(map[string]*ResourceUsage), }, "RL2": &ResourceLimit{ ID: "RL2", @@ -189,6 +196,7 @@ func TestRLsMatchingResourceLimitsForEvent(t *testing.T) { ActivationTime: time.Date(2014, 7, 3, 13, 43, 0, 1, time.UTC), Limit: 1, UsageTTL: time.Duration(1 * time.Millisecond), + Usage: make(map[string]*ResourceUsage), }, } if resLimits, err := rLS.matchingResourceLimitsForEvent(map[string]interface{}{"Account": "1002", "Subject": "dan", "Destination": "1002"}); err != nil { @@ -212,3 +220,86 @@ func TestRLsMatchingResourceLimitsForEvent(t *testing.T) { } } + +func TestRLsV1ResourceLimitsForEvent(t *testing.T) { + eLimits := []*ResourceLimit{ + &ResourceLimit{ + ID: "RL1", + Weight: 20, + Filters: []*RequestFilter{ + &RequestFilter{Type: MetaString, FieldName: "Account", Values: []string{"1001", "1002"}}, + &RequestFilter{Type: MetaRSRFields, Values: []string{"Subject(~^1.*1$)", "Destination(1002)"}, + rsrFields: utils.ParseRSRFieldsMustCompile("Subject(~^1.*1$);Destination(1002)", utils.INFIELD_SEP), + }}, + ActivationTime: time.Date(2014, 7, 3, 13, 43, 0, 1, time.UTC), + Limit: 2, + Usage: make(map[string]*ResourceUsage), + }, + &ResourceLimit{ + ID: "RL2", + Weight: 10, + Filters: []*RequestFilter{ + &RequestFilter{Type: MetaString, FieldName: "Account", Values: []string{"dan", "1002"}}, + &RequestFilter{Type: MetaString, FieldName: "Subject", Values: []string{"dan"}}, + }, + ActivationTime: time.Date(2014, 7, 3, 13, 43, 0, 1, time.UTC), + Limit: 1, + UsageTTL: time.Duration(1 * time.Millisecond), + Usage: make(map[string]*ResourceUsage), + }, + } + var rcvLmts []*ResourceLimit + if err := rLS.V1ResourceLimitsForEvent(map[string]interface{}{"Account": "1002", "Subject": "dan", "Destination": "1002"}, &rcvLmts); err != nil { + t.Error(err) + } else if len(eLimits) != len(rcvLmts) { + t.Errorf("Expecting: %+v, received: %+v", eLimits, rcvLmts) + } +} + +func TestRLsV1InitiateResourceUsage(t *testing.T) { + attrRU := utils.AttrRLsResourceUsage{ + ResourceUsageID: "651a8db2-4f67-4cf8-b622-169e8a482e50", + Event: map[string]interface{}{"Account": "1002", "Subject": "dan", "Destination": "1002"}, + RequestedUnits: 1, + } + var reply string + if err := rLS.V1InitiateResourceUsage(attrRU, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Error("Received reply: ", reply) + } + resLimits, err := rLS.matchingResourceLimitsForEvent(attrRU.Event) + if err != nil { + t.Error(err) + } else if len(resLimits) != 2 { + t.Errorf("Received: %+v", resLimits) + } else if resLimits["RL1"].UsedUnits() != 1 { + t.Errorf("RL1: %+v", resLimits["RL1"]) + } else if _, hasKey := resLimits["RL1"].Usage[attrRU.ResourceUsageID]; !hasKey { + t.Errorf("RL1: %+v", resLimits["RL1"]) + } +} + +func TestRLsV1TerminateResourceUsage(t *testing.T) { + attrRU := utils.AttrRLsResourceUsage{ + ResourceUsageID: "651a8db2-4f67-4cf8-b622-169e8a482e50", + Event: map[string]interface{}{"Account": "1002", "Subject": "dan", "Destination": "1002"}, + RequestedUnits: 1, + } + var reply string + if err := rLS.V1TerminateResourceUsage(attrRU, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Error("Received reply: ", reply) + } + resLimits, err := rLS.matchingResourceLimitsForEvent(attrRU.Event) + if err != nil { + t.Error(err) + } else if len(resLimits) != 2 { + t.Errorf("Received: %+v", resLimits) + } else if resLimits["RL1"].UsedUnits() != 0 { + t.Errorf("RL1: %+v", resLimits["RL1"]) + } else if _, hasKey := resLimits["RL1"].Usage[attrRU.ResourceUsageID]; hasKey { + t.Errorf("RL1: %+v", resLimits["RL1"]) + } +}