debit buget functions operational

This commit is contained in:
Radu Ioan Fericean
2012-02-23 14:27:45 +02:00
parent f8b080be30
commit 7c3f46d563
7 changed files with 232 additions and 44 deletions

13
README
View File

@@ -1,10 +1,9 @@
Rating system designed to be used in VoIP Carriers World.
Features
- Fast RatingEngine, holds all rating information into memory
- Unlimited spanned timebased rating: considers both ActiveFrom/RateStartsAt
- Unlimited rate profiles chanining for fallback
- Rating Fields: ConnectFee, RateIn, RateOut
- High accuracy rating: configurable to miliseconds
- Flexible rates storage - plugin based rates loading
- Flexibility to rate various information from the cdrs as rating subject.
* Fast RatingEngine, holds all rating information into memory
* Unlimited spanned timebased rating: considers both ActiveFrom/RateStartsAt
* Unlimited rate profiles chanining for fallback
* Rating Fields: ConnectFee, RateIn, RateOut
* High accuracy rating: configurable to miliseconds
* Flexible rates storage - plugin based rates loading

View File

@@ -28,7 +28,7 @@ RPC method providing the rating information from the storage.
*/
func (s *Storage) GetCost(cd timespans.CallDescriptor, reply *timespans.CallCost) (err error) {
descriptor := &cd
descriptor.storageGetter = s.sg
descriptor.StorageGetter = s.sg
r, e := descriptor.GetCost()
*reply, err = *r, e
return nil

View File

@@ -34,12 +34,14 @@ func main() {
getter, _ := timespans.NewRedisStorage("", 10)
defer getter.Close()
cd.StorageGetter = getter
i := 0
log.Printf("Runnning %d cycles...", *runs)
for j := 0; j < *runs; j++ {
result, _ = cd.GetCost(getter)
result, _ = cd.GetCost()
}
log.Print(result)

View File

@@ -37,7 +37,7 @@ type CallDescriptor struct {
CstmId, Subject, DestinationPrefix string
TimeStart, TimeEnd time.Time
ActivationPeriods []*ActivationPeriod
storageGetter StorageGetter
StorageGetter StorageGetter
}
/*
@@ -57,10 +57,10 @@ func (cd *CallDescriptor) RestoreFromStorage() (destPrefix string, err error) {
base := fmt.Sprintf("%s:%s:", cd.CstmId, cd.Subject)
destPrefix = cd.DestinationPrefix
key := base + destPrefix
values, err := cd.storageGetter.GetActivationPeriods(key)
values, err := cd.StorageGetter.GetActivationPeriods(key)
//get for a smaller prefix if the orignal one was not found
for i := len(cd.DestinationPrefix); err != nil && i >= MinPrefixLength; values, err = cd.storageGetter.GetActivationPeriods(key) {
for i := len(cd.DestinationPrefix); err != nil && i >= MinPrefixLength; values, err = cd.StorageGetter.GetActivationPeriods(key) {
i--
destPrefix = cd.DestinationPrefix[:i]
key = base + destPrefix
@@ -92,9 +92,10 @@ Splits the received timespan into sub time spans according to the activation per
*/
func (cd *CallDescriptor) splitTimeSpan(firstSpan *TimeSpan) (timespans []*TimeSpan) {
timespans = append(timespans, firstSpan)
// split on (free) minute buckets
if userBudget, err := cd.storageGetter.GetUserBudget(cd.Subject); err == nil && userBudget != nil {
_, bucketList := userBudget.getSecondsForPrefix(cd.storageGetter, cd.DestinationPrefix)
// split on (free) minute buckets
if userBudget, err := cd.StorageGetter.GetUserBudget(cd.Subject); err == nil && userBudget != nil {
userBudget.mux.RLock()
_, bucketList := userBudget.getSecondsForPrefix(cd.StorageGetter, cd.DestinationPrefix)
for _, mb := range bucketList {
for i := 0; i < len(timespans); i++ {
if timespans[i].MinuteInfo != nil {
@@ -108,7 +109,9 @@ func (cd *CallDescriptor) splitTimeSpan(firstSpan *TimeSpan) (timespans []*TimeS
}
}
}
userBudget.mux.RUnlock()
}
if firstSpan.MinuteInfo != nil {
return // all the timespans are on minutes
}
@@ -206,7 +209,7 @@ Returns the cost of a second in the present time conditions.
func (cd *CallDescriptor) GetMaxSessionTime(maxSessionSeconds int) (seconds int, err error) {
_, err = cd.RestoreFromStorage()
now := time.Now()
maxDuration, _ := time.ParseDuration(fmt.Sprintf("%ds", maxSessionSeconds))
maxDuration, _ := time.ParseDuration(fmt.Sprintf("%vs", maxSessionSeconds))
ts := &TimeSpan{TimeStart: now, TimeEnd: now.Add(maxDuration)}
timespans := cd.splitTimeSpan(ts)

View File

@@ -12,7 +12,7 @@ func TestKyotoSplitSpans(t *testing.T) {
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{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, StorageGetter: getter}
cd.RestoreFromStorage()
timespans := cd.splitInTimeSpans()
@@ -27,7 +27,7 @@ func TestRedisSplitSpans(t *testing.T) {
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{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257", TimeStart: t1, TimeEnd: t2, StorageGetter: getter}
cd.RestoreFromStorage()
timespans := cd.splitInTimeSpans()
@@ -43,13 +43,13 @@ func TestKyotoGetCost(t *testing.T) {
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{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, StorageGetter: getter}
result, _ := cd.GetCost()
expected := &CallCost{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", Cost: 540, ConnectFee: 0}
if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee {
t.Errorf("Expected %v was %v", expected, result)
}
cd = &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
cd = &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257", TimeStart: t1, TimeEnd: t2, StorageGetter: getter}
result, _ = cd.GetCost()
expected = &CallCost{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257", Cost: 540, ConnectFee: 0}
}
@@ -60,7 +60,7 @@ func TestRedisGetCost(t *testing.T) {
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{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, StorageGetter: getter}
result, _ := cd.GetCost()
expected := &CallCost{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", Cost: 540, ConnectFee: 0}
if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee {
@@ -74,7 +74,7 @@ func TestMongoGetCost(t *testing.T) {
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{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, StorageGetter: getter}
result, _ := cd.GetCost()
expected := &CallCost{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", Cost: 540, ConnectFee: 0}
if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee {
@@ -88,7 +88,7 @@ func TestFullDestNotFound(t *testing.T) {
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{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256308200", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256308200", TimeStart: t1, TimeEnd: t2, StorageGetter: getter}
result, _ := cd.GetCost()
expected := &CallCost{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", Cost: 540, ConnectFee: 0}
if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee {
@@ -102,7 +102,7 @@ func TestMultipleActivationPeriods(t *testing.T) {
t1 := time.Date(2012, time.February, 8, 17, 30, 0, 0, time.UTC)
t2 := time.Date(2012, time.February, 8, 18, 30, 0, 0, time.UTC)
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257308200", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257308200", TimeStart: t1, TimeEnd: t2, StorageGetter: getter}
result, _ := cd.GetCost()
expected := &CallCost{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257", Cost: 330, ConnectFee: 0}
if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee {
@@ -118,7 +118,7 @@ func TestSpansMultipleActivationPeriods(t *testing.T) {
t1 := time.Date(2012, time.February, 7, 23, 50, 0, 0, time.UTC)
t2 := time.Date(2012, time.February, 8, 0, 30, 0, 0, time.UTC)
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257308200", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257308200", TimeStart: t1, TimeEnd: t2, StorageGetter: getter}
result, _ := cd.GetCost()
expected := &CallCost{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257", Cost: 360, ConnectFee: 0}
if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee {
@@ -132,7 +132,7 @@ func TestLessThanAMinute(t *testing.T) {
t1 := time.Date(2012, time.February, 8, 23, 50, 0, 0, time.UTC)
t2 := time.Date(2012, time.February, 8, 23, 50, 30, 0, time.UTC)
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257308200", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257308200", TimeStart: t1, TimeEnd: t2, StorageGetter: getter}
result, _ := cd.GetCost()
expected := &CallCost{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257", Cost: 0.5, ConnectFee: 0}
if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee {
@@ -146,7 +146,7 @@ func TestUniquePrice(t *testing.T) {
t1 := time.Date(2012, time.February, 8, 22, 50, 0, 0, time.UTC)
t2 := time.Date(2012, time.February, 8, 23, 50, 21, 0, time.UTC)
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0723045326", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0723045326", TimeStart: t1, TimeEnd: t2, StorageGetter: getter}
result, _ := cd.GetCost()
expected := &CallCost{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0723", Cost: 60.35, ConnectFee: 0}
if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee {
@@ -160,7 +160,7 @@ func TestPresentSecodCost(t *testing.T) {
t1 := time.Date(2012, time.February, 8, 22, 50, 0, 0, time.UTC)
t2 := time.Date(2012, time.February, 8, 23, 50, 21, 0, time.UTC)
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0723", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0723", TimeStart: t1, TimeEnd: t2, StorageGetter: getter}
result, _ := cd.getPresentSecondCost()
expected := 0.016
if result != expected {
@@ -174,7 +174,7 @@ func TestMinutesCost(t *testing.T) {
t1 := time.Date(2012, time.February, 8, 22, 50, 0, 0, time.UTC)
t2 := time.Date(2012, time.February, 8, 23, 50, 21, 0, time.UTC)
cd := &CallDescriptor{CstmId: "vdf", Subject: "minutosu", DestinationPrefix: "0723", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
cd := &CallDescriptor{CstmId: "vdf", Subject: "minutosu", DestinationPrefix: "0723", TimeStart: t1, TimeEnd: t2, StorageGetter: getter}
result, _ := cd.GetCost()
expected := &CallCost{CstmId: "vdf", Subject: "minutosu", DestinationPrefix: "0723", Cost: 0, ConnectFee: 0}
if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee {
@@ -204,7 +204,7 @@ func BenchmarkRedisRestoring(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{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, StorageGetter: getter}
b.StartTimer()
for i := 0; i < b.N; i++ {
cd.RestoreFromStorage()
@@ -218,7 +218,7 @@ func BenchmarkRedisGetCost(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{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, StorageGetter: getter}
b.StartTimer()
for i := 0; i < b.N; i++ {
cd.GetCost()
@@ -232,7 +232,7 @@ func BenchmarkKyotoGetting(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{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, StorageGetter: getter}
b.StartTimer()
for i := 0; i < b.N; i++ {
key := cd.GetKey()
@@ -247,7 +247,7 @@ func BenchmarkKyotoRestoring(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{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, StorageGetter: getter}
b.StartTimer()
for i := 0; i < b.N; i++ {
cd.RestoreFromStorage()
@@ -261,7 +261,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{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, StorageGetter: getter}
cd.RestoreFromStorage()
b.StartTimer()
for i := 0; i < b.N; i++ {
@@ -276,7 +276,7 @@ func BenchmarkKyotoGetCost(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{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, StorageGetter: getter}
b.StartTimer()
for i := 0; i < b.N; i++ {
cd.GetCost()
@@ -304,7 +304,7 @@ func BenchmarkMongoGetCost(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{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, StorageGetter: getter}
b.StartTimer()
for i := 0; i < b.N; i++ {
cd.GetCost()

View File

@@ -5,6 +5,7 @@ import (
"sort"
"strconv"
"strings"
"sync"
)
/*
@@ -18,22 +19,29 @@ type UserBudget struct {
TariffPlanId string
tariffPlan *TariffPlan
MinuteBuckets []*MinuteBucket
mux sync.RWMutex
}
type AmountTooBig byte
func (a AmountTooBig) Error() string {
return "Amount excedes budget!"
}
/*
Structure to store minute buckets according to priority, precision or price.
*/
type BucketSorter []*MinuteBucket
type bucketsorter []*MinuteBucket
func (bs BucketSorter) Len() int {
func (bs bucketsorter) Len() int {
return len(bs)
}
func (bs BucketSorter) Swap(i, j int) {
func (bs bucketsorter) Swap(i, j int) {
bs[i], bs[j] = bs[j], bs[i]
}
func (bs BucketSorter) Less(j, i int) bool {
func (bs bucketsorter) Less(j, i int) bool {
return bs[i].Priority < bs[j].Priority ||
bs[i].precision < bs[j].precision ||
bs[i].Price > bs[j].Price
@@ -92,14 +100,14 @@ func (ub *UserBudget) getTariffPlan(storage StorageGetter) (tp *TariffPlan) {
/*
Returns user's avaliable minutes for the specified destination
*/
func (ub *UserBudget) getSecondsForPrefix(storage StorageGetter, prefix string) (seconds float64, bucketList BucketSorter) {
func (ub *UserBudget) getSecondsForPrefix(sg StorageGetter, prefix string) (seconds float64, bucketList bucketsorter) {
if len(ub.MinuteBuckets) == 0 {
log.Print("There are no minute buckets to check for user", ub.Id)
return
}
for _, mb := range ub.MinuteBuckets {
d := mb.getDestination(storage)
d := mb.getDestination(sg)
if d == nil {
continue
}
@@ -115,8 +123,60 @@ func (ub *UserBudget) getSecondsForPrefix(storage StorageGetter, prefix string)
credit := ub.Credit
for _, mb := range bucketList {
s := mb.GetSecondsForCredit(credit)
credit -= s
credit -= s * mb.Price
seconds += s
}
return
}
/*
Debits some amount of user's money credit. Returns the remaining credit in user's budget.
*/
func (ub *UserBudget) debitMoneyBudget(sg StorageGetter, amount float64) float64 {
ub.mux.Lock()
defer ub.mux.Unlock()
ub.Credit -= amount
sg.SetUserBudget(ub)
return ub.Credit
}
/*
Debits the recived amount of seconds from user's minute buckets.
All the appropriate buckets will be debited until all amount of minutes is consumed.
If the amount is bigger than the sum of all seconds in the minute buckets than nothing will be
debited and an error will be returned.
*/
func (ub *UserBudget) debitMinutesBudget(sg StorageGetter, amount float64, prefix string) error {
ub.mux.Lock()
defer ub.mux.Unlock()
avaliableNbSeconds, bucketList := ub.getSecondsForPrefix(sg, prefix)
if avaliableNbSeconds < amount {
return new(AmountTooBig)
}
for _, mb := range bucketList {
if mb.Seconds < amount {
amount -= mb.Seconds
mb.Seconds = 0
} else {
mb.Seconds -= amount
break
}
}
sg.SetUserBudget(ub)
return nil
}
/*
Debits some amount of user's SMS budget. Returns the remaining SMS in user's budget.
If the amount is bigger than the budget than nothing wil be debited and an error will be returned
*/
func (ub *UserBudget) debitSMSBuget(sg StorageGetter, amount int) (int, error) {
ub.mux.Lock()
defer ub.mux.Unlock()
if ub.SmsCredit < amount {
return ub.SmsCredit, new(AmountTooBig)
}
ub.SmsCredit -= amount
sg.SetUserBudget(ub)
return ub.SmsCredit, nil
}

View File

@@ -91,6 +91,130 @@ func TestUserBudgetMongoStore(t *testing.T) {
}
}
func TestDebitMoneyBudget(t *testing.T) {
getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
defer getter.Close()
b1 := &MinuteBucket{Seconds: 10, Priority: 10, Price: 0.01, DestinationId: "nationale"}
b2 := &MinuteBucket{Seconds: 100, Priority: 20, Price: 0.0, DestinationId: "retea"}
rifsBudget := &UserBudget{Id: "o4her", MinuteBuckets: []*MinuteBucket{b1, b2}, Credit: 21, ResetDayOfTheMonth: 10}
result := rifsBudget.debitMoneyBudget(getter, 6)
if rifsBudget.Credit != 15 || result != rifsBudget.Credit {
t.Errorf("Expected %v was %v", 15, rifsBudget.Credit)
}
}
func TestDebitAllMoneyBudget(t *testing.T) {
getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
defer getter.Close()
b1 := &MinuteBucket{Seconds: 10, Priority: 10, Price: 0.01, DestinationId: "nationale"}
b2 := &MinuteBucket{Seconds: 100, Priority: 20, Price: 0.0, DestinationId: "retea"}
rifsBudget := &UserBudget{Id: "other", MinuteBuckets: []*MinuteBucket{b1, b2}, Credit: 21, ResetDayOfTheMonth: 10}
rifsBudget.debitMoneyBudget(getter, 21)
result := rifsBudget.debitMoneyBudget(getter, 0)
if rifsBudget.Credit != 0 || result != rifsBudget.Credit {
t.Errorf("Expected %v was %v", 0, rifsBudget.Credit)
}
}
func TestDebitMoreMoneyBudget(t *testing.T) {
getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
defer getter.Close()
b1 := &MinuteBucket{Seconds: 10, Priority: 10, Price: 0.0, DestinationId: "nationale"}
b2 := &MinuteBucket{Seconds: 100, Priority: 20, Price: 0.0, DestinationId: "retea"}
rifsBudget := &UserBudget{Id: "other", MinuteBuckets: []*MinuteBucket{b1, b2}, Credit: 21, ResetDayOfTheMonth: 10}
result := rifsBudget.debitMoneyBudget(getter, 22)
if rifsBudget.Credit != -1 || result != rifsBudget.Credit {
t.Errorf("Expected %v was %v", -1, rifsBudget.Credit)
}
}
func TestDebitMinuteBudget(t *testing.T) {
getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
defer getter.Close()
b1 := &MinuteBucket{Seconds: 10, Priority: 10, Price: 0.0, DestinationId: "nationale"}
b2 := &MinuteBucket{Seconds: 100, Priority: 20, Price: 0.0, DestinationId: "retea"}
rifsBudget := &UserBudget{Id: "other", MinuteBuckets: []*MinuteBucket{b1, b2}, Credit: 21, ResetDayOfTheMonth: 10}
err := rifsBudget.debitMinutesBudget(getter, 6, "0723")
if b2.Seconds != 94 || err != nil {
t.Log(err)
t.Errorf("Expected %v was %v", 94, b2.Seconds)
}
}
func TestDebitMultipleBucketsMinuteBudget(t *testing.T) {
getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
defer getter.Close()
b1 := &MinuteBucket{Seconds: 10, Priority: 10, Price: 0.0, DestinationId: "nationale"}
b2 := &MinuteBucket{Seconds: 100, Priority: 20, Price: 0.0, DestinationId: "retea"}
rifsBudget := &UserBudget{Id: "other", MinuteBuckets: []*MinuteBucket{b1, b2}, Credit: 21, ResetDayOfTheMonth: 10}
err := rifsBudget.debitMinutesBudget(getter, 105, "0723")
if b2.Seconds != 0 || b1.Seconds != 5 || err != nil {
t.Log(err)
t.Errorf("Expected %v was %v", 0, b2.Seconds)
}
}
func TestDebitAllMinuteBudget(t *testing.T) {
getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
defer getter.Close()
b1 := &MinuteBucket{Seconds: 10, Priority: 10, Price: 0.0, DestinationId: "nationale"}
b2 := &MinuteBucket{Seconds: 100, Priority: 20, Price: 0.0, DestinationId: "retea"}
rifsBudget := &UserBudget{Id: "other", MinuteBuckets: []*MinuteBucket{b1, b2}, Credit: 21, ResetDayOfTheMonth: 10}
err := rifsBudget.debitMinutesBudget(getter, 110, "0723")
if b2.Seconds != 0 || b1.Seconds != 0 || err != nil {
t.Log(err)
t.Errorf("Expected %v was %v", 0, b2.Seconds)
}
}
func TestDebitMoreMinuteBudget(t *testing.T) {
getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
defer getter.Close()
b1 := &MinuteBucket{Seconds: 10, Priority: 10, Price: 0.0, DestinationId: "nationale"}
b2 := &MinuteBucket{Seconds: 100, Priority: 20, Price: 0.0, DestinationId: "retea"}
rifsBudget := &UserBudget{Id: "other", MinuteBuckets: []*MinuteBucket{b1, b2}, Credit: 21, ResetDayOfTheMonth: 10}
err := rifsBudget.debitMinutesBudget(getter, 115, "0723")
if b2.Seconds != 100 || b1.Seconds != 10 || err == nil {
t.Errorf("Expected %v was %v", 1000, b2.Seconds)
}
}
func TestDebitSMSBudget(t *testing.T) {
getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
defer getter.Close()
b1 := &MinuteBucket{Seconds: 10, Priority: 10, Price: 0.0, DestinationId: "nationale"}
b2 := &MinuteBucket{Seconds: 100, Priority: 20, Price: 0.0, DestinationId: "retea"}
rifsBudget := &UserBudget{Id: "other", MinuteBuckets: []*MinuteBucket{b1, b2}, Credit: 21, SmsCredit: 100, ResetDayOfTheMonth: 10}
result, err := rifsBudget.debitSMSBuget(getter, 12)
if rifsBudget.SmsCredit != 88 || result != rifsBudget.SmsCredit || err != nil {
t.Errorf("Expected %v was %v", 88, rifsBudget.SmsCredit)
}
}
func TestDebitAllSMSBudget(t *testing.T) {
getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
defer getter.Close()
b1 := &MinuteBucket{Seconds: 10, Priority: 10, Price: 0.0, DestinationId: "nationale"}
b2 := &MinuteBucket{Seconds: 100, Priority: 20, Price: 0.0, DestinationId: "retea"}
rifsBudget := &UserBudget{Id: "other", MinuteBuckets: []*MinuteBucket{b1, b2}, Credit: 21, SmsCredit: 100, ResetDayOfTheMonth: 10}
result, err := rifsBudget.debitSMSBuget(getter, 100)
if rifsBudget.SmsCredit != 0 || result != rifsBudget.SmsCredit || err != nil {
t.Errorf("Expected %v was %v", 0, rifsBudget.SmsCredit)
}
}
func TestDebitMoreSMSBudget(t *testing.T) {
getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
defer getter.Close()
b1 := &MinuteBucket{Seconds: 10, Priority: 10, Price: 0.0, DestinationId: "nationale"}
b2 := &MinuteBucket{Seconds: 100, Priority: 20, Price: 0.0, DestinationId: "retea"}
rifsBudget := &UserBudget{Id: "other", MinuteBuckets: []*MinuteBucket{b1, b2}, Credit: 21, SmsCredit: 100, ResetDayOfTheMonth: 10}
result, err := rifsBudget.debitSMSBuget(getter, 110)
if rifsBudget.SmsCredit != 100 || result != rifsBudget.SmsCredit || err == nil {
t.Errorf("Expected %v was %v", 100, rifsBudget.SmsCredit)
}
}
/*********************************** Benchmarks *******************************/
func BenchmarkGetSecondForPrefix(b *testing.B) {