diff --git a/timespans/activationperiod.go b/timespans/activationperiod.go
index 05f7c8c0a..70e3ac0fc 100644
--- a/timespans/activationperiod.go
+++ b/timespans/activationperiod.go
@@ -97,34 +97,3 @@ func (ap *ActivationPeriod) restore(input string) {
ap.Intervals = append(ap.Intervals, i)
}
}
-
-type RatingProfile struct {
- Id string `bson:"_id,omitempty"`
- DestinationInfo string
- FallbackKey string
- ActivationPeriods []*ActivationPeriod
-}
-
-func (rp *RatingProfile) store() (result string) {
- result += rp.Id + ">"
- result += rp.DestinationInfo + ">"
- result += rp.FallbackKey + ">"
- for _, ap := range rp.ActivationPeriods {
- result += ap.store() + "<"
- }
- result = strings.TrimRight(result, "<")
- return
-}
-
-func (rp *RatingProfile) restore(input string) {
- elements := strings.Split(input, ">")
- rp.Id = elements[0]
- rp.DestinationInfo = elements[1]
- rp.FallbackKey = elements[2]
- apsList := strings.Split(elements[3], "<")
- for _, aps := range apsList {
- ap := new(ActivationPeriod)
- ap.restore(aps)
- rp.ActivationPeriods = append(rp.ActivationPeriods, ap)
- }
-}
diff --git a/timespans/activationperiod_test.go b/timespans/activationperiod_test.go
index 961afdb9e..c057b521c 100644
--- a/timespans/activationperiod_test.go
+++ b/timespans/activationperiod_test.go
@@ -64,7 +64,7 @@ func TestApRestoreFromStorage(t *testing.T) {
Tenant: "CUSTOMER_1",
Subject: "rif:from:tm",
Destination: "49"}
- cd.SearchStorageForPrefix()
+ cd.LoadActivationPeriods()
if len(cd.ActivationPeriods) != 2 {
t.Error("Error restoring activation periods: ", len(cd.ActivationPeriods))
}
@@ -110,7 +110,7 @@ func TestApStoreRestoreBlank(t *testing.T) {
func TestFallbackDirect(t *testing.T) {
cd := &CallDescriptor{TOR: "0", Direction: "OUT", Tenant: "CUSTOMER_2", Subject: "danb:87.139.12.167", Destination: "41"}
- cd.SearchStorageForPrefix()
+ cd.LoadActivationPeriods()
if len(cd.ActivationPeriods) != 1 {
t.Error("Error restoring activation periods: ", len(cd.ActivationPeriods))
}
@@ -118,7 +118,7 @@ func TestFallbackDirect(t *testing.T) {
func TestFallbackWithBackTrace(t *testing.T) {
cd := &CallDescriptor{TOR: "0", Direction: "OUT", Tenant: "CUSTOMER_2", Subject: "danb:87.139.12.167", Destination: "4123"}
- cd.SearchStorageForPrefix()
+ cd.LoadActivationPeriods()
if len(cd.ActivationPeriods) != 1 {
t.Error("Error restoring activation periods: ", len(cd.ActivationPeriods))
}
@@ -126,7 +126,7 @@ func TestFallbackWithBackTrace(t *testing.T) {
func TestFallbackDefault(t *testing.T) {
cd := &CallDescriptor{TOR: "0", Direction: "OUT", Tenant: "CUSTOMER_2", Subject: "danb:87.139.12.167", Destination: "4123"}
- cd.SearchStorageForPrefix()
+ cd.LoadActivationPeriods()
if len(cd.ActivationPeriods) != 1 {
t.Error("Error restoring activation periods: ", len(cd.ActivationPeriods))
}
@@ -134,7 +134,7 @@ func TestFallbackDefault(t *testing.T) {
func TestFallbackNoInfiniteLoop(t *testing.T) {
cd := &CallDescriptor{Tenant: "vdf", Subject: "rif", Destination: "0721"}
- cd.SearchStorageForPrefix()
+ cd.LoadActivationPeriods()
if len(cd.ActivationPeriods) != 0 {
t.Error("Error restoring activation periods: ", len(cd.ActivationPeriods))
}
diff --git a/timespans/calldesc.go b/timespans/calldesc.go
index e37b88800..97b6640a5 100644
--- a/timespans/calldesc.go
+++ b/timespans/calldesc.go
@@ -36,11 +36,8 @@ func init() {
}
const (
- // the minimum length for a destination prefix to be matched.
- MinPrefixLength = 2
- RecursionMaxDepth = 4
- FallbackDestination = "fallback" // the string to be used to mark the fallback destination
- FallbackSubject = "*all"
+ RECURSION_MAX_DEPTH = 4
+ FALLBACK_SUBJECT = "*all"
)
var (
@@ -80,7 +77,6 @@ type CallDescriptor struct {
Amount float64
FallbackSubject string // the subject to check for destination if not found on primary subject
ActivationPeriods []*ActivationPeriod
- FallbackKey string
userBalance *UserBalance
}
@@ -89,22 +85,6 @@ func (cd *CallDescriptor) AddActivationPeriod(aps ...*ActivationPeriod) {
cd.ActivationPeriods = append(cd.ActivationPeriods, aps...)
}
-// Adds an activation period that applyes to current call descriptor if not already present.
-func (cd *CallDescriptor) AddActivationPeriodIfNotPresent(aps ...*ActivationPeriod) {
- for _, ap := range aps {
- found := false
- for _, eap := range cd.ActivationPeriods {
- if ap.Equal(eap) {
- found = true
- break
- }
- }
- if !found {
- cd.ActivationPeriods = append(cd.ActivationPeriods, ap)
- }
- }
-}
-
// Returns the key used to retrive the user balance involved in this call
func (cd *CallDescriptor) GetUserBalanceKey() string {
subj := cd.Subject
@@ -148,31 +128,18 @@ func SetDebitPeriod(d time.Duration) {
/*
Restores the activation periods for the specified prefix from storage.
*/
-func (cd *CallDescriptor) SearchStorageForPrefix() (destPrefix string, err error) {
+func (cd *CallDescriptor) LoadActivationPeriods() (destPrefix string, err error) {
if val, err := cache.GetXCached(cd.GetKey()); err == nil {
xaps := val.(xCachedActivationPeriods)
cd.ActivationPeriods = xaps.aps
return xaps.destPrefix, nil
}
- cd.ActivationPeriods = make([]*ActivationPeriod, 0)
- base := fmt.Sprintf("%s:%s:%s:%s:", cd.Direction, cd.Tenant, cd.TOR, cd.Subject)
- destPrefix = cd.Destination
- key := base + destPrefix
- values, err := cd.getActivationPeriodsOrFallback(key, base, destPrefix, 1)
+ destPrefix, values, err := cd.getActivationPeriodsForPrefix(cd.GetKey(), cd.Destination, 1)
if err != nil {
- // use the default destination
- key := base + FallbackDestination
- values, err = cd.getActivationPeriodsOrFallback(key, base, destPrefix, 1)
- }
- if err != nil {
- // use the default subject
- base = fmt.Sprintf("%s:%s:%s:%s:", cd.Direction, cd.Tenant, cd.TOR, FallbackSubject)
- key = base + destPrefix
- values, err = cd.getActivationPeriodsOrFallback(key, base, destPrefix, 1)
if err != nil {
- // use the default destination
- key := base + FallbackDestination
- values, err = cd.getActivationPeriodsOrFallback(key, base, destPrefix, 1)
+ fallbackKey := fmt.Sprintf("%s:%s:%s", cd.Direction, cd.Tenant, cd.TOR, FALLBACK_SUBJECT)
+ // use the default subject
+ destPrefix, values, err = cd.getActivationPeriodsForPrefix(fallbackKey, cd.Destination, 1)
}
}
//load the activation preriods
@@ -184,37 +151,23 @@ func (cd *CallDescriptor) SearchStorageForPrefix() (destPrefix string, err error
return
}
-func (cd *CallDescriptor) getRatinPprofile(key, base, destPrefix string, recursionDepth int) (values []*ActivationPeriod, err error) {
- if recursionDepth > RecursionMaxDepth {
+func (cd *CallDescriptor) getActivationPeriodsForPrefix(key, prefix string, recursionDepth int) (foundPrefix string, aps []*ActivationPeriod, err error) {
+ if recursionDepth > RECURSION_MAX_DEPTH {
err = errors.New("Max fallback recursion depth reached!" + key)
return
}
rp, err := storageGetter.GetRatingProfile(key)
- if rp.FallbackKey != "" {
- base = rp.FallbackKey + ":"
- key = base + destPrefix
- recursionDepth++
- return cd.getRatingProfile(key, base, destPrefix, recursionDepth)
+ if err != nil {
+ return "", nil, err
}
-
- //get for a smaller prefix if the orignal one was not found
- for i := len(cd.Destination); err != nil || fallbackKey != ""; {
- if fallbackKey != "" {
- base = fallbackKey + ":"
- key = base + destPrefix
+ foundPrefix, aps, err = rp.GetActivationPeriodsForPrefix(prefix)
+ if err != nil {
+ if rp.FallbackKey != "" {
recursionDepth++
- return cd.getRatingProfile(key, base, destPrefix, recursionDepth)
+ return cd.getActivationPeriodsForPrefix(rp.FallbackKey, prefix, recursionDepth)
}
-
- i--
- if i >= MinPrefixLength {
- destPrefix = cd.Destination[:i]
- key = base + destPrefix
- } else {
- break
- }
- values, fallbackKey, err = storageGetter.GetRatingProfile(key)
}
+
return
}
@@ -306,7 +259,7 @@ func (cd *CallDescriptor) splitTimeSpan(firstSpan *TimeSpan) (timespans []*TimeS
Creates a CallCost structure with the cost information calculated for the received CallDescriptor.
*/
func (cd *CallDescriptor) GetCost() (*CallCost, error) {
- destPrefix, err := cd.SearchStorageForPrefix()
+ destPrefix, err := cd.LoadActivationPeriods()
timespans := cd.splitInTimeSpans()
cost := 0.0
connectionFee := 0.0
@@ -336,7 +289,7 @@ and will decrease it by 10% for nine times. So if the user has little credit it
If the user has no credit then it will return 0.
*/
func (cd *CallDescriptor) GetMaxSessionTime() (seconds float64, err error) {
- _, err = cd.SearchStorageForPrefix()
+ _, err = cd.LoadActivationPeriods()
now := time.Now()
availableCredit, availableSeconds := 0.0, 0.0
if userBalance, err := cd.getUserBalance(); err == nil && userBalance != nil {
diff --git a/timespans/calldesc_test.go b/timespans/calldesc_test.go
index 81d15a1c2..6619cc002 100644
--- a/timespans/calldesc_test.go
+++ b/timespans/calldesc_test.go
@@ -57,7 +57,7 @@ func TestSplitSpans(t *testing.T) {
t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC)
cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
- cd.SearchStorageForPrefix()
+ cd.LoadActivationPeriods()
timespans := cd.splitInTimeSpans()
if len(timespans) != 2 {
t.Log(cd.ActivationPeriods)
@@ -70,7 +70,7 @@ func TestRedisSplitSpans(t *testing.T) {
t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC)
cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0257", TimeStart: t1, TimeEnd: t2}
- cd.SearchStorageForPrefix()
+ cd.LoadActivationPeriods()
timespans := cd.splitInTimeSpans()
if len(timespans) != 2 {
t.Log(cd.ActivationPeriods)
@@ -215,22 +215,6 @@ func TestMaxSessionTimeNoCredit(t *testing.T) {
}
}
-func TestApAddAPIfNotPresent(t *testing.T) {
- ap1 := &ActivationPeriod{ActivationTime: time.Date(2012, time.July, 2, 14, 24, 30, 0, time.UTC)}
- ap2 := &ActivationPeriod{ActivationTime: time.Date(2012, time.July, 2, 14, 24, 30, 0, time.UTC)}
- ap3 := &ActivationPeriod{ActivationTime: time.Date(2012, time.July, 2, 14, 24, 30, 1, time.UTC)}
- cd := &CallDescriptor{}
- cd.AddActivationPeriodIfNotPresent(ap1)
- cd.AddActivationPeriodIfNotPresent(ap2)
- if len(cd.ActivationPeriods) != 1 {
- t.Error("Wronfully appended activation period ;)", len(cd.ActivationPeriods))
- }
- cd.AddActivationPeriodIfNotPresent(ap3)
- if len(cd.ActivationPeriods) != 2 {
- t.Error("Wronfully not appended activation period ;)", len(cd.ActivationPeriods))
- }
-}
-
/*********************************** BENCHMARKS ***************************************/
func BenchmarkStorageGetting(b *testing.B) {
b.StopTimer()
@@ -239,7 +223,7 @@ func BenchmarkStorageGetting(b *testing.B) {
cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
b.StartTimer()
for i := 0; i < b.N; i++ {
- storageGetter.GetActivationPeriodsOrFallback(cd.GetKey())
+ storageGetter.GetRatingProfile(cd.GetKey())
}
}
@@ -250,7 +234,7 @@ func BenchmarkStorageRestoring(b *testing.B) {
cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
b.StartTimer()
for i := 0; i < b.N; i++ {
- cd.SearchStorageForPrefix()
+ cd.LoadActivationPeriods()
}
}
@@ -270,7 +254,7 @@ func BenchmarkSplitting(b *testing.B) {
t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC)
t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC)
cd := &CallDescriptor{Direction: "OUT", TOR: "0", Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
- cd.SearchStorageForPrefix()
+ cd.LoadActivationPeriods()
b.StartTimer()
for i := 0; i < b.N; i++ {
cd.splitInTimeSpans()
diff --git a/timespans/csvreader.go b/timespans/csvreader.go
index 67cdfb233..5a20b8f01 100644
--- a/timespans/csvreader.go
+++ b/timespans/csvreader.go
@@ -39,7 +39,7 @@ type CSVReader struct {
rates map[string][]*Rate
timings map[string][]*Timing
activationPeriods map[string]*ActivationPeriod
- ratingProfiles map[string]CallDescriptors
+ ratingProfiles map[string]*RatingProfile
}
func NewFileCSVReader() *CSVReader {
@@ -50,7 +50,7 @@ func NewFileCSVReader() *CSVReader {
c.rates = make(map[string][]*Rate)
c.timings = make(map[string][]*Timing)
c.activationPeriods = make(map[string]*ActivationPeriod)
- c.ratingProfiles = make(map[string]CallDescriptors)
+ c.ratingProfiles = make(map[string]*RatingProfile)
c.readerFunc = openFileCSVReader
return c
}
@@ -98,15 +98,13 @@ func (csvr *CSVReader) WriteToDatabase(storage StorageGetter, flush, verbose boo
if verbose {
log.Print("Rating profiles")
}
- for _, cds := range csvr.ratingProfiles {
- for _, cd := range cds {
- err = storage.SetActivationPeriodsOrFallback(cd.GetKey(), cd.ActivationPeriods, cd.FallbackKey)
- if err != nil {
- return err
- }
- if verbose {
- log.Print(cd.GetKey())
- }
+ for _, rp := range csvr.ratingProfiles {
+ err = storage.SetRatingProfile(rp)
+ if err != nil {
+ return err
+ }
+ if verbose {
+ log.Print(rp.Id)
}
}
if verbose {
@@ -283,46 +281,24 @@ func (csvr *CSVReader) LoadRatingProfiles(fn string, comma rune) (err error) {
if err != nil {
return errors.New(fmt.Sprintf("Cannot parse activation time from %v", record[6]))
}
+ key := fmt.Sprintf("%s:%s:%s:%s", direction, tenant, tor, subject)
+ rp, ok := csvr.ratingProfiles[key]
+ if !ok {
+ rp = &RatingProfile{Id: key}
+ csvr.ratingProfiles[key] = rp
+ }
for _, d := range csvr.destinations {
- for _, p := range d.Prefixes { //destinations
- // Search for a CallDescriptor with the same key
- var cd *CallDescriptor
- key := fmt.Sprintf("%s:%s:%s:%s:%s", direction, tenant, tor, subject, p)
- for _, c := range csvr.ratingProfiles[p] {
- if c.GetKey() == key {
- cd = c
- }
- }
- if cd == nil {
- cd = &CallDescriptor{
- Direction: direction,
- Tenant: tenant,
- TOR: tor,
- Subject: subject,
- Destination: p,
- }
- csvr.ratingProfiles[p] = append(csvr.ratingProfiles[p], cd)
- }
+ for _, p := range d.Prefixes { //destinations
ap, exists := csvr.activationPeriods[record[5]]
if !exists {
return errors.New(fmt.Sprintf("Could not load ratinTiming for tag: ", record[5]))
}
- newAP := &ActivationPeriod{}
+ newAP := &ActivationPeriod{ActivationTime: at}
//copy(newAP.Intervals, ap.Intervals)
newAP.Intervals = append(newAP.Intervals, ap.Intervals...)
- newAP.ActivationTime = at
- cd.AddActivationPeriodIfNotPresent(newAP)
- if fallbacksubject != "" &&
- csvr.ratingProfiles[p].getKey(fmt.Sprintf("%s:%s:%s:%s:%s", direction, tenant, tor, subject, FallbackDestination)) == nil {
- cd = &CallDescriptor{
- Direction: direction,
- Tenant: tenant,
- TOR: tor,
- Subject: subject,
- Destination: FallbackDestination,
- FallbackKey: fmt.Sprintf("%s:%s:%s:%s", direction, tenant, tor, fallbacksubject),
- }
- csvr.ratingProfiles[p] = append(csvr.ratingProfiles[p], cd)
+ rp.AddActivationPeriodIfNotPresent(p, newAP)
+ if fallbacksubject != "" {
+ rp.FallbackKey = fmt.Sprintf("%s:%s:%s:%s", direction, tenant, tor, fallbacksubject)
}
}
}
diff --git a/timespans/csvreader_helpers.go b/timespans/csvreader_helpers.go
index 6b30ffe6d..443b7511c 100644
--- a/timespans/csvreader_helpers.go
+++ b/timespans/csvreader_helpers.go
@@ -118,17 +118,6 @@ func (rt *RateTiming) GetInterval(r *Rate) (i *Interval) {
return
}
-type CallDescriptors []*CallDescriptor
-
-func (cds CallDescriptors) getKey(key string) *CallDescriptor {
- for _, cd := range cds {
- if cd.GetKey() == key {
- return cd
- }
- }
- return nil
-}
-
func ValidateCSVData(fn string, re *regexp.Regexp) (err error) {
fin, err := os.Open(fn)
if err != nil {
diff --git a/timespans/csvreader_test.go b/timespans/csvreader_test.go
index efc341639..b1a5da15a 100644
--- a/timespans/csvreader_test.go
+++ b/timespans/csvreader_test.go
@@ -129,7 +129,7 @@ func TestLoadRateTimings(t *testing.T) {
}
func TestLoadRatingProfiles(t *testing.T) {
- if len(csvr.ratingProfiles) != 7 {
+ if len(csvr.ratingProfiles) != 6 {
t.Error("Failed to load rating profiles: ", len(csvr.ratingProfiles), csvr.ratingProfiles)
}
}
diff --git a/timespans/destinations.go b/timespans/destinations.go
index 8d5a4c9dd..e011101a0 100644
--- a/timespans/destinations.go
+++ b/timespans/destinations.go
@@ -52,7 +52,7 @@ func (d *Destination) containsPrefix(prefix string) (bool, int) {
if d == nil {
return false, 0
}
- for i := len(prefix); i >= MinPrefixLength; {
+ for i := len(prefix); i >= MIN_PREFIX_LENGTH; {
for _, p := range d.Prefixes {
if p == prefix[:i] {
return true, i
diff --git a/timespans/ratingprofile.go b/timespans/ratingprofile.go
new file mode 100644
index 000000000..029eee3a0
--- /dev/null
+++ b/timespans/ratingprofile.go
@@ -0,0 +1,105 @@
+/*
+Rating system designed to be used in VoIP Carriers World
+Copyright (C) 2012 Radu Ioan Fericean
+
+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 timespans
+
+import (
+ "errors"
+ "strings"
+)
+
+const (
+ // the minimum length for a destination prefix to be matched.
+ MIN_PREFIX_LENGTH = 2
+)
+
+type RatingProfile struct {
+ Id string `bson:"_id,omitempty"`
+ FallbackKey string
+ DestinationMap map[string][]*ActivationPeriod
+}
+
+func (rp *RatingProfile) store() (result string) {
+ result += rp.FallbackKey + ">"
+ for k, aps := range rp.DestinationMap {
+ result += k + "="
+ for _, ap := range aps {
+ result += ap.store() + "<"
+ }
+ result = strings.TrimRight(result, "<")
+ result += ">"
+ }
+ result = strings.TrimRight(result, ">")
+ return
+}
+
+func (rp *RatingProfile) restore(input string) {
+ if rp.DestinationMap == nil {
+ rp.DestinationMap = make(map[string][]*ActivationPeriod, 1)
+ }
+ elements := strings.Split(input, ">")
+ rp.FallbackKey = elements[0]
+ for _, kv := range elements[1:] {
+ pair := strings.SplitN(kv, "=", 2)
+ apList := strings.Split(pair[1], "<")
+ var newAps []*ActivationPeriod
+ for _, aps := range apList {
+ ap := new(ActivationPeriod)
+ ap.restore(aps)
+ newAps = append(newAps, ap)
+ }
+ rp.DestinationMap[pair[0]] = newAps
+ }
+}
+
+// Adds an activation period that applyes to current rating profile if not already present.
+func (rp *RatingProfile) AddActivationPeriodIfNotPresent(destInfo string, aps ...*ActivationPeriod) {
+ if rp.DestinationMap == nil {
+ rp.DestinationMap = make(map[string][]*ActivationPeriod, 1)
+ }
+ for _, ap := range aps {
+ found := false
+ for _, eap := range rp.DestinationMap[destInfo] {
+ if ap.Equal(eap) {
+ found = true
+ break
+ }
+ }
+ if !found {
+ rp.DestinationMap[destInfo] = append(rp.DestinationMap[destInfo], ap)
+ }
+ }
+}
+
+func (rp *RatingProfile) GetActivationPeriodsForPrefix(destPrefix string) (foundPrefix string, aps []*ActivationPeriod, err error) {
+ var found = false
+ foundPrefix = destPrefix
+ for i := len(foundPrefix); !found; {
+ if i >= MIN_PREFIX_LENGTH {
+ foundPrefix = foundPrefix[:i]
+ } else {
+ break
+ }
+ aps, found = rp.DestinationMap[foundPrefix]
+ i--
+ }
+ if !found {
+ return "", nil, errors.New("not found")
+ }
+ return
+}
diff --git a/timespans/ratingprofile_test.go b/timespans/ratingprofile_test.go
new file mode 100644
index 000000000..228173d8a
--- /dev/null
+++ b/timespans/ratingprofile_test.go
@@ -0,0 +1,64 @@
+/*
+Rating system designed to be used in VoIP Carriers World
+Copyright (C) 2012 Radu Ioan Fericean
+
+This program is free software: you can Storagetribute 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 timespans
+
+import (
+ "reflect"
+ "testing"
+ "time"
+)
+
+func TestRpStoreRestore(t *testing.T) {
+ d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC)
+ i := &Interval{
+ Months: Months{time.February},
+ MonthDays: MonthDays{1},
+ WeekDays: []time.Weekday{time.Wednesday, time.Thursday},
+ StartTime: "14:30:00",
+ EndTime: "15:00:00"}
+ ap := &ActivationPeriod{ActivationTime: d}
+ ap.AddInterval(i)
+ rp := &RatingProfile{FallbackKey: "test"}
+ rp.AddActivationPeriodIfNotPresent("0723", ap)
+ result := rp.store()
+ expected := "test>0723=1328106601000000000|;2;1;3,4;14:30:00;15:00:00;0;0;0;0;0"
+ if result != expected {
+ t.Errorf("Expected %q was %q", expected, result)
+ }
+ ap1 := ActivationPeriod{}
+ ap1.restore(result)
+ if reflect.DeepEqual(ap, ap1) {
+ t.Errorf("Expected %v was %v", ap, ap1)
+ }
+}
+func TestRpAddAPIfNotPresent(t *testing.T) {
+ ap1 := &ActivationPeriod{ActivationTime: time.Date(2012, time.July, 2, 14, 24, 30, 0, time.UTC)}
+ ap2 := &ActivationPeriod{ActivationTime: time.Date(2012, time.July, 2, 14, 24, 30, 0, time.UTC)}
+ ap3 := &ActivationPeriod{ActivationTime: time.Date(2012, time.July, 2, 14, 24, 30, 1, time.UTC)}
+ rp := &RatingProfile{}
+ rp.AddActivationPeriodIfNotPresent("test", ap1)
+ rp.AddActivationPeriodIfNotPresent("test", ap2)
+ if len(rp.DestinationMap["test"]) != 1 {
+ t.Error("Wronfully appended activation period ;)", len(rp.DestinationMap["test"]))
+ }
+ rp.AddActivationPeriodIfNotPresent("test", ap3)
+ if len(rp.DestinationMap["test"]) != 2 {
+ t.Error("Wronfully not appended activation period ;)", len(rp.DestinationMap["test"]))
+ }
+}
diff --git a/timespans/storage_interface.go b/timespans/storage_interface.go
index 9ccea8be4..f49718074 100644
--- a/timespans/storage_interface.go
+++ b/timespans/storage_interface.go
@@ -120,13 +120,13 @@ func (mm *MyMarshaler) Marshal(v interface{}) (data []byte, err error) {
case []*Action:
result := ""
for _, a := range v.([]*Action) {
- result += a.store() + "\n"
+ result += a.store() + "+"
}
return []byte(result), nil
case []*ActionTiming:
result := ""
for _, at := range v.([]*ActionTiming) {
- result += at.store() + "\n"
+ result += at.store() + "+"
}
return []byte(result), nil
case storer:
@@ -144,7 +144,7 @@ func (mm *MyMarshaler) Unmarshal(data []byte, v interface{}) (err error) {
switch v.(type) {
case *[]*Action:
as := v.(*[]*Action)
- for _, a_string := range strings.Split(string(data), "\n") {
+ for _, a_string := range strings.Split(string(data), "+") {
if len(a_string) > 0 {
a := &Action{}
a.restore(a_string)
@@ -154,7 +154,7 @@ func (mm *MyMarshaler) Unmarshal(data []byte, v interface{}) (err error) {
return nil
case *[]*ActionTiming:
ats := v.(*[]*ActionTiming)
- for _, at_string := range strings.Split(string(data), "\n") {
+ for _, at_string := range strings.Split(string(data), "+") {
if len(at_string) > 0 {
at := &ActionTiming{}
at.restore(at_string)
diff --git a/timespans/storage_map.go b/timespans/storage_map.go
index d5861884d..3ca820ef4 100644
--- a/timespans/storage_map.go
+++ b/timespans/storage_map.go
@@ -52,7 +52,7 @@ func (ms *MapStorage) GetRatingProfile(key string) (rp *RatingProfile, err error
}
func (ms *MapStorage) SetRatingProfile(rp *RatingProfile) (err error) {
- result, err := ms.ms.Marshal(rp.Id)
+ result, err := ms.ms.Marshal(rp)
ms.dict[rp.Id] = result
return
}
diff --git a/timespans/storage_redis.go b/timespans/storage_redis.go
index c4c1275e3..d1337ea65 100644
--- a/timespans/storage_redis.go
+++ b/timespans/storage_redis.go
@@ -71,6 +71,7 @@ func (rs *RedisStorage) GetDestination(key string) (dest *Destination, err error
}
return
}
+
func (rs *RedisStorage) SetDestination(dest *Destination) (err error) {
result, err := rs.ms.Marshal(dest)
return rs.db.Set(dest.Id, result)