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)