Merge fixes

This commit is contained in:
DanB
2017-11-21 19:27:55 +01:00
153 changed files with 3691 additions and 3646 deletions

View File

@@ -116,13 +116,13 @@ type RateSlot struct {
// Used to set the durations we need out of strings
func (self *RateSlot) SetDurations() error {
var err error
if self.rateUnitDur, err = ParseDurationWithSecs(self.RateUnit); err != nil {
if self.rateUnitDur, err = ParseDurationWithNanosecs(self.RateUnit); err != nil {
return err
}
if self.rateIncrementDur, err = ParseDurationWithSecs(self.RateIncrement); err != nil {
if self.rateIncrementDur, err = ParseDurationWithNanosecs(self.RateIncrement); err != nil {
return err
}
if self.groupIntervalStartDur, err = ParseDurationWithSecs(self.GroupIntervalStart); err != nil {
if self.groupIntervalStartDur, err = ParseDurationWithNanosecs(self.GroupIntervalStart); err != nil {
return err
}
return nil
@@ -738,7 +738,6 @@ type AttrExpFileCdrs struct {
CdrHosts []string // If provided, it will filter cdrhost
CdrSources []string // If provided, it will filter cdrsource
ReqTypes []string // If provided, it will fiter reqtype
Directions []string // If provided, it will fiter direction
Tenants []string // If provided, it will filter tenant
Categories []string // If provided, it will filter çategory
Accounts []string // If provided, it will filter account
@@ -763,7 +762,6 @@ func (self *AttrExpFileCdrs) AsCDRsFilter(timezone string) (*CDRsFilter, error)
OriginHosts: self.CdrHosts,
Sources: self.CdrSources,
RequestTypes: self.ReqTypes,
Directions: self.Directions,
Tenants: self.Tenants,
Categories: self.Categories,
Accounts: self.Accounts,
@@ -837,7 +835,6 @@ func (self *AttrGetCdrs) AsCDRsFilter(timezone string) (*CDRsFilter, error) {
OriginHosts: self.CdrHosts,
Sources: self.CdrSources,
RequestTypes: self.ReqTypes,
Directions: self.Directions,
Tenants: self.Tenants,
Categories: self.Categories,
Accounts: self.Accounts,
@@ -881,7 +878,6 @@ type AttrRateCdrs struct {
CdrHosts []string // If provided, it will filter cdrhost
CdrSources []string // If provided, it will filter cdrsource
ReqTypes []string // If provided, it will fiter reqtype
Directions []string // If provided, it will fiter direction
Tenants []string // If provided, it will filter tenant
Categories []string // If provided, it will filter çategory
Accounts []string // If provided, it will filter account
@@ -904,7 +900,6 @@ func (attrRateCDRs *AttrRateCdrs) AsCDRsFilter(timezone string) (*CDRsFilter, er
Sources: attrRateCDRs.CdrSources,
ToRs: attrRateCDRs.TORs,
RequestTypes: attrRateCDRs.ReqTypes,
Directions: attrRateCDRs.Directions,
Tenants: attrRateCDRs.Tenants,
Categories: attrRateCDRs.Categories,
Accounts: attrRateCDRs.Accounts,
@@ -1015,8 +1010,6 @@ type CDRsFilter struct {
NotToRs []string // Filter specific TORs out
RequestTypes []string // If provided, it will fiter reqtype
NotRequestTypes []string // Filter out specific request types
Directions []string // If provided, it will fiter direction
NotDirections []string // Filter out specific directions
Tenants []string // If provided, it will filter tenant
NotTenants []string // If provided, it will filter tenant
Categories []string // If provided, it will filter çategory
@@ -1027,10 +1020,6 @@ type CDRsFilter struct {
NotSubjects []string // Filter out specific subjects
DestinationPrefixes []string // If provided, it will filter on destination prefix
NotDestinationPrefixes []string // Filter out specific destination prefixes
Suppliers []string // If provided, it will filter the supplier
NotSuppliers []string // Filter out specific suppliers
DisconnectCauses []string // Filter for disconnect Cause
NotDisconnectCauses []string // Filter out specific disconnect causes
Costs []float64 // Query based on costs specified
NotCosts []float64 // Filter out specific costs out from result
ExtraFields map[string]string // Query based on extra fields content
@@ -1047,8 +1036,6 @@ type CDRsFilter struct {
UpdatedAtEnd *time.Time // End interval, smaller than
MinUsage string // Start of the usage interval (>=)
MaxUsage string // End of the usage interval (<)
MinPDD string // Start of the pdd interval (>=)
MaxPDD string // End of the pdd interval (<)
MinCost *float64 // Start of the cost interval (>=)
MaxCost *float64 // End of the usage interval (<)
Unscoped bool // Include soft-deleted records in results
@@ -1071,8 +1058,6 @@ type RPCCDRsFilter struct {
NotToRs []string // Filter specific TORs out
RequestTypes []string // If provided, it will fiter reqtype
NotRequestTypes []string // Filter out specific request types
Directions []string // If provided, it will fiter direction
NotDirections []string // Filter out specific directions
Tenants []string // If provided, it will filter tenant
NotTenants []string // If provided, it will filter tenant
Categories []string // If provided, it will filter çategory
@@ -1083,10 +1068,6 @@ type RPCCDRsFilter struct {
NotSubjects []string // Filter out specific subjects
DestinationPrefixes []string // If provided, it will filter on destination prefix
NotDestinationPrefixes []string // Filter out specific destination prefixes
Suppliers []string // If provided, it will filter the supplier
NotSuppliers []string // Filter out specific suppliers
DisconnectCauses []string // Filter for disconnect Cause
NotDisconnectCauses []string // Filter out specific disconnect causes
Costs []float64 // Query based on costs specified
NotCosts []float64 // Filter out specific costs out from result
ExtraFields map[string]string // Query based on extra fields content
@@ -1103,8 +1084,6 @@ type RPCCDRsFilter struct {
UpdatedAtEnd string // End interval, smaller than
MinUsage string // Start of the usage interval (>=)
MaxUsage string // End of the usage interval (<)
MinPDD string // Start of the pdd interval (>=)
MaxPDD string // End of the pdd interval (<)
MinCost *float64 // Start of the cost interval (>=)
MaxCost *float64 // End of the usage interval (<)
Paginator // Add pagination
@@ -1124,8 +1103,6 @@ func (self *RPCCDRsFilter) AsCDRsFilter(timezone string) (*CDRsFilter, error) {
NotSources: self.NotSources,
RequestTypes: self.RequestTypes,
NotRequestTypes: self.NotRequestTypes,
Directions: self.Directions,
NotDirections: self.NotDirections,
Tenants: self.Tenants,
NotTenants: self.NotTenants,
Categories: self.Categories,
@@ -1136,23 +1113,17 @@ func (self *RPCCDRsFilter) AsCDRsFilter(timezone string) (*CDRsFilter, error) {
NotSubjects: self.NotSubjects,
DestinationPrefixes: self.DestinationPrefixes,
NotDestinationPrefixes: self.NotDestinationPrefixes,
Suppliers: self.Suppliers,
NotSuppliers: self.NotSuppliers,
DisconnectCauses: self.DisconnectCauses,
NotDisconnectCauses: self.NotDisconnectCauses,
Costs: self.Costs,
NotCosts: self.NotCosts,
ExtraFields: self.ExtraFields,
NotExtraFields: self.NotExtraFields,
OrderIDStart: self.OrderIDStart,
OrderIDEnd: self.OrderIDEnd,
MinUsage: self.MinUsage,
MaxUsage: self.MaxUsage,
MinPDD: self.MinPDD,
MaxPDD: self.MaxPDD,
MinCost: self.MinCost,
MaxCost: self.MaxCost,
Paginator: self.Paginator,
Costs: self.Costs,
NotCosts: self.NotCosts,
ExtraFields: self.ExtraFields,
NotExtraFields: self.NotExtraFields,
OrderIDStart: self.OrderIDStart,
OrderIDEnd: self.OrderIDEnd,
MinUsage: self.MinUsage,
MaxUsage: self.MaxUsage,
MinCost: self.MinCost,
MaxCost: self.MaxCost,
Paginator: self.Paginator,
}
if len(self.SetupTimeStart) != 0 {
if sTimeStart, err := ParseTimeDetectLayout(self.SetupTimeStart, timezone); err != nil {

View File

@@ -113,9 +113,10 @@ const (
TBLTPStats = "tp_stats"
TBLTPThresholds = "tp_thresholds"
TBLTPFilters = "tp_filters"
TBLTPLcr = "tp_lcr"
TBLSMCosts = "sm_costs"
TBLCDRs = "cdrs"
SMCostsTBL = "sm_costs"
CDRsTBL = "cdrs"
TBLTPLCRProfiles = "tp_lcr"
TBLTPLcr = "tp_lcrs"
TBLVersions = "versions"
TIMINGS_CSV = "Timings.csv"
DESTINATIONS_CSV = "Destinations.csv"
@@ -409,7 +410,6 @@ const (
UnsupportedMigrationTask = "unsupported migration task"
NoStorDBConnection = "not connected to StorDB"
UndefinedVersion = "undefined version"
MetaSetVersions = "*set_versions"
UnsupportedDB = "unsupported database"
ACCOUNT_SUMMARY = "AccountSummary"
TxtSuffix = ".txt"
@@ -434,13 +434,6 @@ const (
MetaEveryMinute = "*every_minute"
MetaHourly = "*hourly"
ID = "ID"
MetaASR = "*asr"
MetaACD = "*acd"
MetaTCD = "*tcd"
MetaACC = "*acc"
MetaTCC = "*tcc"
MetaPDD = "*pdd"
MetaDDC = "*ddc"
CacheDestinations = "destinations"
CacheReverseDestinations = "reverse_destinations"
CacheRatingPlans = "rating_plans"
@@ -491,6 +484,7 @@ const (
StatUpdate = "StatUpdate"
ResourceUpdate = "ResourceUpdate"
CDR = "CDR"
CDRs = "CDRs"
ExpiryTime = "ExpiryTime"
AllowNegative = "AllowNegative"
Disabled = "Disabled"
@@ -577,6 +571,26 @@ const (
MetaTpRatingProfile = "*TpRatingProfile"
MetaStorDB = "*StorDB"
MetaDataDB = "*DataDB"
SMGenericV2UpdateSession = "SMGenericV2.UpdateSession"
SMGenericV2InitiateSession = "SMGenericV2.InitiateSession"
SMGenericV1UpdateSession = "SMGenericV1.UpdateSession"
SMGenericV1InitiateSession = "SMGenericV1.InitiateSession"
)
//Meta
const (
MetaASR = "*asr"
MetaACD = "*acd"
MetaTCD = "*tcd"
MetaACC = "*acc"
MetaTCC = "*tcc"
MetaPDD = "*pdd"
MetaDDC = "*ddc"
)
//Migrator Metas
const (
MetaSetVersions = "*set_versions"
)
func buildCacheInstRevPrefixes() {

View File

@@ -289,6 +289,17 @@ func ParseDurationWithSecs(durStr string) (d time.Duration, err error) {
return time.ParseDuration(durStr)
}
// Parses duration, considers s as time unit if not provided, seconds as float to specify subunits
func ParseDurationWithNanosecs(durStr string) (d time.Duration, err error) {
if durStr == "" {
return
}
if _, err = strconv.ParseFloat(durStr, 64); err == nil { // Seconds format considered
durStr += "ns"
}
return time.ParseDuration(durStr)
}
func AccountKey(tenant, account string) string {
return fmt.Sprintf("%s:%s", tenant, account)
}
@@ -304,10 +315,15 @@ func MinDuration(d1, d2 time.Duration) time.Duration {
// ParseZeroRatingSubject will parse the subject in the balance
// returns duration if able to extract it from subject
// returns error if not able to parse duration (ie: if ratingSubject is standard one)
func ParseZeroRatingSubject(rateSubj string) (time.Duration, error) {
func ParseZeroRatingSubject(tor, rateSubj string) (time.Duration, error) {
rateSubj = strings.TrimSpace(rateSubj)
if rateSubj == "" || rateSubj == ANY {
rateSubj = ZERO_RATING_SUBJECT_PREFIX + "1s"
switch tor {
case VOICE:
rateSubj = ZERO_RATING_SUBJECT_PREFIX + "1s"
default:
rateSubj = ZERO_RATING_SUBJECT_PREFIX + "1ns"
}
}
if !strings.HasPrefix(rateSubj, ZERO_RATING_SUBJECT_PREFIX) {
return 0, errors.New("malformed rating subject: " + rateSubj)
@@ -479,34 +495,6 @@ func LogFull(v interface{}) {
log.Print(ToIJSON(v))
}
// Used to convert from generic interface type towards string value
func ConvertIfaceToString(fld interface{}) (string, bool) {
var strVal string
var converted bool
switch fld.(type) {
case string:
strVal = fld.(string)
converted = true
case int:
strVal = strconv.Itoa(fld.(int))
converted = true
case int64:
strVal = strconv.FormatInt(fld.(int64), 10)
converted = true
case bool:
strVal = strconv.FormatBool(fld.(bool))
converted = true
case []uint8:
var byteVal []byte
if byteVal, converted = fld.([]byte); converted {
strVal = string(byteVal)
}
default: // Maybe we are lucky and the value converts to string
strVal, converted = fld.(string)
}
return strVal, converted
}
// Simple object cloner, b should be a pointer towards a value into which we want to decode
func Clone(a, b interface{}) error {
buff := new(bytes.Buffer)

View File

@@ -416,7 +416,7 @@ func TestParseZeroRatingSubject(t *testing.T) {
subj := []string{"", "*zero1s", "*zero5m", "*zero10h"}
dur := []time.Duration{time.Second, time.Second, 5 * time.Minute, 10 * time.Hour}
for i, s := range subj {
if d, err := ParseZeroRatingSubject(s); err != nil || d != dur[i] {
if d, err := ParseZeroRatingSubject(VOICE, s); err != nil || d != dur[i] {
t.Error("Error parsing rating subject: ", s, d, err)
}
}
@@ -434,25 +434,6 @@ func TestConcatenatedKey(t *testing.T) {
}
}
func TestConvertIfaceToString(t *testing.T) {
val := interface{}("string1")
if resVal, converted := ConvertIfaceToString(val); !converted || resVal != "string1" {
t.Error(resVal, converted)
}
val = interface{}(123)
if resVal, converted := ConvertIfaceToString(val); !converted || resVal != "123" {
t.Error(resVal, converted)
}
val = interface{}([]byte("byte_val"))
if resVal, converted := ConvertIfaceToString(val); !converted || resVal != "byte_val" {
t.Error(resVal, converted)
}
val = interface{}(true)
if resVal, converted := ConvertIfaceToString(val); !converted || resVal != "true" {
t.Error(resVal, converted)
}
}
func TestMandatory(t *testing.T) {
_, err := FmtFieldWidth("", "", 0, "", "", true)
if err == nil {

View File

@@ -46,6 +46,7 @@ var (
ErrResourceUnavailable = errors.New("RESOURCE_UNAVAILABLE")
ErrNoActiveSession = errors.New("NO_ACTIVE_SESSION")
ErrPartiallyExecuted = errors.New("PARTIALLY_EXECUTED")
ErrMaxUsageExceeded = errors.New("MAX_USAGE_EXCEEDED")
)
// NewCGRError initialises a new CGRError

View File

@@ -30,9 +30,6 @@ func CastFieldIfToString(fld interface{}) (string, bool) {
var strVal string
var converted bool
switch fld.(type) {
case string:
strVal = fld.(string)
converted = true
case int:
strVal = strconv.Itoa(fld.(int))
converted = true

View File

@@ -218,6 +218,22 @@ func TestStringToInterface(t *testing.T) {
}
func TestCastFieldIfToString(t *testing.T) {
val := interface{}("string1")
if resVal, converted := CastFieldIfToString(val); !converted || resVal != "string1" {
t.Error(resVal, converted)
}
val = interface{}(123)
if resVal, converted := CastFieldIfToString(val); !converted || resVal != "123" {
t.Error(resVal, converted)
}
val = interface{}([]byte("byte_val"))
if resVal, converted := CastFieldIfToString(val); !converted || resVal != "byte_val" {
t.Error(resVal, converted)
}
val = interface{}(true)
if resVal, converted := CastFieldIfToString(val); !converted || resVal != "true" {
t.Error(resVal, converted)
}
if strVal, cast := CastFieldIfToString(time.Duration(1 * time.Second)); !cast {
t.Error("cannot cast time.Duration")
} else if strVal != "1s" {

View File

@@ -33,9 +33,12 @@ type ValueFormula struct {
Static float64
}
func ParseBalanceFilterValue(val string) (*ValueFormula, error) {
u, err := strconv.ParseFloat(val, 64)
if err == nil {
func ParseBalanceFilterValue(tor string, val string) (*ValueFormula, error) {
if tor == VOICE { // VOICE balance is parsed as nanoseconds with support for time duration strings
if d, err := ParseDurationWithNanosecs(val); err == nil {
return &ValueFormula{Static: float64(d.Nanoseconds())}, err
}
} else if u, err := strconv.ParseFloat(val, 64); err == nil {
return &ValueFormula{Static: u}, err
}
var vf ValueFormula

View File

@@ -19,6 +19,7 @@ package utils
import (
"encoding/json"
"reflect"
"testing"
"time"
)
@@ -54,3 +55,24 @@ func TestValueFormulaDayYear(t *testing.T) {
t.Error("error caclulating value using formula: ", x)
}
}
func TestValueFormulaParseBalanceFilterValue(t *testing.T) {
eVF := &ValueFormula{Static: 10000000000.0}
if vf, err := ParseBalanceFilterValue(VOICE, "10s"); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eVF, vf) {
t.Errorf("Expecting: %+v, received: %+v", eVF, vf)
}
eVF = &ValueFormula{Static: 1024.0}
if vf, err := ParseBalanceFilterValue(DATA, "1024"); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eVF, vf) {
t.Errorf("Expecting: %+v, received: %+v", eVF, vf)
}
eVF = &ValueFormula{Static: 10.0}
if vf, err := ParseBalanceFilterValue(MONETARY, "10"); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eVF, vf) {
t.Errorf("Expecting: %+v, received: %+v", eVF, vf)
}
}