started calldescription testing

This commit is contained in:
Radu Ioan Fericean
2012-02-02 20:31:23 +02:00
parent 1d7c2c0689
commit 03bbe421b4
15 changed files with 223 additions and 192 deletions

View File

@@ -4,18 +4,42 @@ import (
"fmt"
"github.com/fsouza/gokabinet/kc"
"flag"
"time"
"github.com/rif/cgrates/timespans"
)
var (
fileName = flag.String("fileName", "storage.kch", "kyoto storage file")
filename = flag.String("filename", "storage.kch", "kyoto storage file")
)
func main() {
flag.Parse()
db, _ := kc.Open(*fileName, kc.WRITE)
defer db.Close()
db.Set("test", "12223")
db, _ := kc.Open(*filename, kc.WRITE)
defer db.Close()
t1 := time.Date(2012, time.January, 1, 0, 0, 0, 0, time.UTC)
cd1 := &timespans.CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256"}
cd1.AddInterval(t1, &timespans.Interval{
WeekDays: []time.Weekday{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday},
EndHour:"18:00",
ConnectFee: 0,
Price: 0.2,
BillingUnit: 1.0})
cd1.AddInterval(t1, &timespans.Interval{
WeekDays: []time.Weekday{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday},
StartHour:"18:00",
ConnectFee: 0,
Price: 0.1,
BillingUnit: 1.0})
cd1.AddInterval(t1, &timespans.Interval{
WeekDays: []time.Weekday{time.Saturday, time.Sunday},
ConnectFee: 0,
Price: 0.1,
BillingUnit: 1.0})
key := cd1.GetKey()
value := cd1.EncodeValues()
db.Set(key, string(value))
fmt.Println("Done!")
}

View File

@@ -6,7 +6,7 @@ import (
"net"
"net/rpc"
"os"
"github.com/rif/cgrates/timeslots"
"github.com/rif/cgrates/timespans"
)
var (
@@ -16,20 +16,19 @@ var (
)
type Storage struct {
sg timeslots.StorageGetter
sg timespans.StorageGetter
}
func NewStorage(nsg timeslots.StorageGetter) *Storage{
func NewStorage(nsg timespans.StorageGetter) *Storage{
return &Storage{sg: nsg}
}
/*
RPC method providing the rating information from the storage.
*/
func (s *Storage) GetCost(in *timeslots.CallDescription, reply *timeslots.CallCost) (err error) {
r, e := timeslots.GetCost(in, s.sg)
*reply, err = *r, e
return e
func (s *Storage) GetCost(in *timespans.CallDescription, reply *timespans.CallCost) (err error) {
*reply, err = in.GetCost(s.sg)
return nil
}
/*
@@ -44,7 +43,7 @@ func (s *Storage) Shutdown(args string, reply *string) (err error) {
func main() {
flag.Parse()
getter, err := timeslots.NewKyotoStorage("storage.kch")
getter, err := timespans.NewKyotoStorage("storage.kch")
//getter, err := NewRedisStorage("tcp:127.0.0.1:6379")
//defer getter.Close()
if err != nil {

View File

@@ -9,7 +9,7 @@ import (
func main(){
client, _ := jsonrpc.Dial("tcp", "localhost:5090")
runs := int(5 * 10e3);
runs := int(5 * 1e4);
i:= 0
c := make(chan string)
for ; i < runs; i++ {

View File

@@ -49,6 +49,6 @@ print s.recv(4096)
i = 0
result = ""
for i in xrange(5 * int(10e4) + 1):
for i in xrange(5 * int(1e4) + 1):
result = rpc.call("Responder.Get", "test")
print i, result

113
timespans/calldesc.go Normal file
View File

@@ -0,0 +1,113 @@
package timespans
import ("time"; "encoding/json"; "fmt"; "log")
/*
The output structure that will be returned with the call cost information.
*/
type CallCost struct {
TOR int
CstmId, Subject, DestinationPrefix string
Cost, ConnectFee float64
// ratesInfo *RatingProfile
}
/*
The input stucture that contains call information.
*/
type CallDescriptor struct {
TOR int
CstmId, Subject, DestinationPrefix string
TimeStart, TimeEnd time.Time
ActivationPeriods map[time.Time] []*Interval
}
func (cd *CallDescriptor) AddInterval(t time.Time, is ...*Interval) {
if cd.ActivationPeriods == nil {
cd.ActivationPeriods = make(map[time.Time] []*Interval)
}
intervals, ok := cd.ActivationPeriods[t]
for _, i := range is {
intervals = append(intervals, i)
}
// if the intervals is new add it to the map
if !ok {
cd.ActivationPeriods[t] = intervals
}
}
func (cd *CallDescriptor) EncodeValues() []byte {
jo, err := json.Marshal(cd.ActivationPeriods)
if err != nil {
log.Print("Cannot encode intervals: ", err)
}
return jo
}
func (cd *CallDescriptor) GetKey() string {
return fmt.Sprintf("%s:%s:%s", cd.CstmId, cd.Subject, cd.DestinationPrefix)
}
func (cd *CallDescriptor) decodeValues(v []byte) {
err := json.Unmarshal(v, &cd.ActivationPeriods)
if err != nil {
log.Print("Cannot decode intervals: ", err)
}
}
func (cd *CallDescriptor) getActiveIntervals() (is []*Interval) {
now := time.Now()
// add a second in the future to be able to pick the active timestamp
// from the very second it becomes active
sec,_ := time.ParseDuration("1s")
now.Add(sec)
bestTime := time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC)
for time, intervals := range cd.ActivationPeriods {
if time.After(bestTime) && time.Before(now) {
bestTime = time
is = intervals
}
}
return
}
func (cd *CallDescriptor) splitInTimeSpans(intervals []*Interval) (timespans []*TimeSpan) {
ts1 := &TimeSpan{TimeStart: cd.TimeStart, TimeEnd: cd.TimeEnd}
timespans = append(timespans, ts1)
for _, interval := range intervals {
for _, ts := range timespans {
newTs := interval.Split(ts)
if newTs != nil {
timespans = append(timespans, interval.Split(ts))
}
}
}
return
}
/*
*/
func (cd *CallDescriptor) GetCost(sg StorageGetter) (result *CallCost, err error) {
key := cd.GetKey()
values, err := sg.Get(key)
cd.decodeValues([]byte(values))
intervals := cd.getActiveIntervals()
timespans := cd.splitInTimeSpans(intervals)
cost := 0.0
for _, ts := range timespans {
cost += ts.GetCost()
}
cc := &CallCost{TOR: cd.TOR,
CstmId: cd.CstmId,
Subject: cd.Subject,
DestinationPrefix: cd.DestinationPrefix,
Cost: cost,
ConnectFee: timespans[0].Interval.ConnectFee}
return cc, err
}

View File

@@ -0,0 +1,5 @@
package timespans
import (
"testing"
)

View File

@@ -1,4 +1,4 @@
package timeslots
package timespans
import (
"time"

View File

@@ -1,4 +1,4 @@
package timeslots
package timespans
import (
"time"
@@ -14,7 +14,7 @@ type Interval struct {
MonthDay int
WeekDays []time.Weekday
StartHour, EndHour string // ##:## format
Ponder, ConnectFee, Price, BillingUnit float32
Ponder, ConnectFee, Price, BillingUnit float64
}
/*

View File

@@ -1,4 +1,4 @@
package timeslots
package timespans
import (
"log"

View File

@@ -1,4 +1,4 @@
package timeslots
package timespans
import (
"log"

View File

@@ -1,4 +1,4 @@
package timeslots
package timespans
/*
Interface for storage providers.

View File

@@ -1,126 +0,0 @@
package timeslots
import (
"time"
"fmt"
"log"
"encoding/json"
)
/*
A unit in which a call will be split that has a specific price related interval attached to it.
*/
type TimeSpan struct {
TimeStart, TimeEnd time.Time
Interval *Interval
}
/*
Returns the duration of the timespan
*/
func (ts *TimeSpan) GetDuration() time.Duration {
return ts.TimeEnd.Sub(ts.TimeStart)
}
/*
Returns the cost of the timespan according to the relevant cost interval.
If the first parameter is true then it adds the connection fee to the cost.
*/
func (ts *TimeSpan) GetCost(first bool) return (cost float32) {
if ts.Interval.BillingUnit > 0 {
cost = (ts.GetDuration().seconds() / ts.Interval.BillingUnit) * ts.Interval.Price
} else {
cost = ts.GetDuration().seconds() * ts.Interval.Price
}
if first {
cost += ts.Interval.ConnectFee
}
return
}
/*
will set ne interval as spans's interval if new ponder is greater then span's interval ponder
or if the ponders are equal and new price is lower then spans's interval price
*/
func (ts *TimeSpan) SetInterval(i *Interval) {
if ts.Interval == nil || ts.Interval.Ponder < i.Ponder {
ts.Interval = i
}
if ts.Interval.Ponder == i.Ponder && i.Price < ts.Interval.Price {
ts.Interval = i
}
}
/*
A structure containing the time intervals with the cost information and the
ActivationTime when those intervals will be applied.
*/
type ActivationPeriod struct {
ActivationTime time.Time
Intervals []*Interval
}
func (c *ActivationPeriod) AddInterval(is ...*Interval) {
for _, i := range is {
c.Intervals = append(c.Intervals, i)
}
}
/*
The input stucture that contains call information.
*/
type CallDescription struct {
TOR int
CstmId, Subject, Destination string
TimeStart, TimeEnd time.Time
ActivationPeriods []*ActivationPeriod
}
/*
Adds an activation period to the internal slice
*/
func (c *Customer) addActivationPeriod(ap ...*ActivationPeriod) {
for _,a := range ap {
c.ActivationPeriods = append(c.ActivationPeriods, a)
}
}
func (c *Customer) getKey() string {
return fmt.Sprintf("%s%s%s", c.CstmId, c.Subject, c.DestinationPrefix)
}
func (c *Customer) encodeValue() []byte {
jo, err := json.Marshal(c.ActivationPeriods)
if err != nil {
log.Print("Cannot encode intervals: ", err)
}
return jo
}
func (c *Customer) decodeValue(v []byte) {
err := json.Unmarshal(v, &c.ActivationPeriods)
if err != nil {
log.Print("Cannot decode intervals: ", err)
}
}
/*
*/
func (cd *CallDescription) GetCost() (result *CallCost) {
ts := &TimeSpan{TimeStart: cd.TimeStart, TimeEnd: cd.TimeEnd}
c := &Customer{CstmId:, Subject:, DestinationPrefix: }
}
/*
The output structure that will be returned with the call cost information.
*/
type CallCost struct {
TOR int
CstmId, Subject, Prefix string
Cost, ConnectFee float32
// ratesInfo *RatingProfile
}

View File

@@ -1,44 +0,0 @@
package timeslots
import (
"time"
"testing"
)
func TestStorageEncoding(t *testing.T){
i1 := &Interval{Month: time.December, MonthDay: 1, StartHour: "09:00"}
i2 := &Interval{WeekDays: []time.Weekday{time.Sunday}}
i3 := &Interval{Month: time.February, MonthDay: 1, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartHour: "14:30", EndHour: "15:00"}
c := &Customer{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256"}
ap := &ActivationPeriod{ActivationTime: time.Now()}
ap.AddInterval(i1, i2, i3)
c.addActivationPeriod(ap)
received := c.encodeValue()
c.decodeValue(received)
f1 := c.ActivationPeriods[0].Intervals[0]
if f1.Month != i1.Month || f1.MonthDay != i1.MonthDay || f1.StartHour != i1.StartHour {
t.Errorf("Decode values are not the same: %v vs %v", f1, i1)
}
f2 := c.ActivationPeriods[0].Intervals[1]
for i,v := range f2.WeekDays {
if v != i2.WeekDays[i] {
t.Errorf("Decode values are not the same: %v vs %v", f2, i2)
}
}
}
func BenchmarkDecoding(b *testing.B) {
b.StopTimer()
i1 := &Interval{Month: time.December, MonthDay: 1, StartHour: "09:00"}
i2 := &Interval{WeekDays: []time.Weekday{time.Sunday}}
i3 := &Interval{Month: time.February, MonthDay: 1, WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, StartHour: "14:30", EndHour: "15:00"}
c := &Customer{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256"}
ap := &ActivationPeriod{ActivationTime: time.Now()}
ap.AddInterval(i1, i2, i3)
c.addActivationPeriod(ap)
received := c.encodeValue()
b.StartTimer()
for i := 0; i < b.N; i++ {
c.decodeValue(received)
}
}

45
timespans/timespans.go Normal file
View File

@@ -0,0 +1,45 @@
package timespans
import (
"time"
)
/*
A unit in which a call will be split that has a specific price related interval attached to it.
*/
type TimeSpan struct {
TimeStart, TimeEnd time.Time
Interval *Interval
}
/*
Returns the duration of the timespan
*/
func (ts *TimeSpan) GetDuration() time.Duration {
return ts.TimeEnd.Sub(ts.TimeStart)
}
/*
Returns the cost of the timespan according to the relevant cost interval.
*/
func (ts *TimeSpan) GetCost() (cost float64) {
if ts.Interval.BillingUnit > 0 {
cost = (ts.GetDuration().Seconds() / ts.Interval.BillingUnit) * ts.Interval.Price
} else {
cost = ts.GetDuration().Seconds() * ts.Interval.Price
}
return
}
/*
will set ne interval as spans's interval if new ponder is greater then span's interval ponder
or if the ponders are equal and new price is lower then spans's interval price
*/
func (ts *TimeSpan) SetInterval(i *Interval) {
if ts.Interval == nil || ts.Interval.Ponder < i.Ponder {
ts.Interval = i
}
if ts.Interval.Ponder == i.Ponder && i.Price < ts.Interval.Price {
ts.Interval = i
}
}

View File

@@ -0,0 +1,15 @@
package timespans
import (
//"time"
"testing"
)
func TestStorageEncoding(t *testing.T){
}
func BenchmarkDecoding(b *testing.B) {
for i := 0; i < b.N; i++ {
}
}