Merge branch 'Edwardro22-master'

This commit is contained in:
DanB
2017-02-26 13:42:44 +01:00
14 changed files with 870 additions and 99 deletions

View File

@@ -45,6 +45,10 @@ func init() {
var err error
switch DB {
case "map":
if cgrCfg := config.CgrConfig(); cgrCfg == nil {
cgrCfg, _ = config.NewDefaultCGRConfig()
config.SetCgrConfig(cgrCfg)
}
ratingStorage, _ = NewMapStorage()
accountingStorage, _ = NewMapStorage()
case utils.MONGO:

View File

@@ -21,6 +21,7 @@ import (
"bytes"
"compress/zlib"
"errors"
"fmt"
"io/ioutil"
"strings"
"sync"
@@ -70,11 +71,13 @@ func (s storage) smembers(key string, ms Marshaler) (idMap utils.StringMap, ok b
}
func NewMapStorage() (*MapStorage, error) {
return &MapStorage{dict: make(map[string][]byte), ms: NewCodecMsgpackMarshaler(), cacheCfg: &config.CacheConfig{RatingPlans: &config.CacheParamConfig{Precache: true}}}, nil
return &MapStorage{dict: make(map[string][]byte), ms: NewCodecMsgpackMarshaler(), cacheCfg: config.CgrConfig().CacheConfig}, nil
}
func NewMapStorageJson() (*MapStorage, error) {
return &MapStorage{dict: make(map[string][]byte), ms: new(JSONBufMarshaler), cacheCfg: &config.CacheConfig{RatingPlans: &config.CacheParamConfig{Precache: true}}}, nil
func NewMapStorageJson() (mpStorage *MapStorage, err error) {
mpStorage, err = NewMapStorage()
mpStorage.ms = new(JSONBufMarshaler)
return
}
func (ms *MapStorage) Close() {}
@@ -95,7 +98,7 @@ func (ms *MapStorage) SelectDatabase(dbName string) (err error) {
}
func (ms *MapStorage) RebuildReverseForPrefix(prefix string) error {
// FIXME: should do transaction
// ToDo: should do transaction
keys, err := ms.GetKeysForPrefix(prefix)
if err != nil {
return err
@@ -142,7 +145,6 @@ func (ms *MapStorage) RebuildReverseForPrefix(prefix string) error {
return nil
}
// FixMe
func (ms *MapStorage) LoadRatingCache(dstIDs, rvDstIDs, rplIDs, rpfIDs, actIDs, aplIDs, aapIDs, atrgIDs, sgIDs, lcrIDs, dcIDs []string) error {
if ms.cacheCfg == nil {
return nil
@@ -250,6 +252,119 @@ func (ms *MapStorage) PreloadCacheForPrefix(prefix string) error {
// CacheDataFromDB loads data to cache,
// prefix represents the cache prefix, IDs should be nil if all available data should be loaded
func (ms *MapStorage) CacheDataFromDB(prefix string, IDs []string, mustBeCached bool) (err error) {
if !utils.IsSliceMember([]string{utils.DESTINATION_PREFIX,
utils.REVERSE_DESTINATION_PREFIX,
utils.RATING_PLAN_PREFIX,
utils.RATING_PROFILE_PREFIX,
utils.ACTION_PREFIX,
utils.ACTION_PLAN_PREFIX,
utils.AccountActionPlansPrefix,
utils.ACTION_TRIGGER_PREFIX,
utils.SHARED_GROUP_PREFIX,
utils.DERIVEDCHARGERS_PREFIX,
utils.LCR_PREFIX,
utils.ALIASES_PREFIX,
utils.REVERSE_ALIASES_PREFIX,
utils.ResourceLimitsPrefix}, prefix) {
return utils.NewCGRError(utils.REDIS,
utils.MandatoryIEMissingCaps,
utils.UnsupportedCachePrefix,
fmt.Sprintf("prefix <%s> is not a supported cache prefix", prefix))
}
if IDs == nil {
keyIDs, err := ms.GetKeysForPrefix(prefix)
if err != nil {
return utils.NewCGRError(utils.REDIS,
utils.ServerErrorCaps,
err.Error(),
fmt.Sprintf("MapStorage error <%s> querying keys for prefix: <%s>", prefix))
}
for _, keyID := range keyIDs {
if mustBeCached { // Only consider loading ids which are already in cache
if _, hasIt := cache.Get(keyID); !hasIt {
continue
}
}
IDs = append(IDs, keyID[len(prefix):])
}
var nrItems int
switch prefix {
case utils.DESTINATION_PREFIX:
nrItems = ms.cacheCfg.Destinations.Limit
case utils.REVERSE_DESTINATION_PREFIX:
nrItems = ms.cacheCfg.ReverseDestinations.Limit
case utils.RATING_PLAN_PREFIX:
nrItems = ms.cacheCfg.RatingPlans.Limit
case utils.RATING_PROFILE_PREFIX:
nrItems = ms.cacheCfg.RatingProfiles.Limit
case utils.ACTION_PREFIX:
nrItems = ms.cacheCfg.Actions.Limit
case utils.ACTION_PLAN_PREFIX:
nrItems = ms.cacheCfg.ActionPlans.Limit
case utils.AccountActionPlansPrefix:
nrItems = ms.cacheCfg.AccountActionPlans.Limit
case utils.ACTION_TRIGGER_PREFIX:
nrItems = ms.cacheCfg.ActionTriggers.Limit
case utils.SHARED_GROUP_PREFIX:
nrItems = ms.cacheCfg.SharedGroups.Limit
case utils.DERIVEDCHARGERS_PREFIX:
nrItems = ms.cacheCfg.DerivedChargers.Limit
case utils.LCR_PREFIX:
nrItems = ms.cacheCfg.Lcr.Limit
case utils.ALIASES_PREFIX:
nrItems = ms.cacheCfg.Aliases.Limit
case utils.REVERSE_ALIASES_PREFIX:
nrItems = ms.cacheCfg.ReverseAliases.Limit
case utils.ResourceLimitsPrefix:
nrItems = ms.cacheCfg.ResourceLimits.Limit
}
if nrItems != 0 && nrItems < len(IDs) {
IDs = IDs[:nrItems]
}
}
for _, dataID := range IDs {
if mustBeCached {
if _, hasIt := cache.Get(prefix + dataID); !hasIt { // only cache if previously there
continue
}
}
switch prefix {
case utils.DESTINATION_PREFIX:
_, err = ms.GetDestination(dataID, true, utils.NonTransactional)
case utils.REVERSE_DESTINATION_PREFIX:
_, err = ms.GetReverseDestination(dataID, true, utils.NonTransactional)
case utils.RATING_PLAN_PREFIX:
_, err = ms.GetRatingPlan(dataID, true, utils.NonTransactional)
case utils.RATING_PROFILE_PREFIX:
_, err = ms.GetRatingProfile(dataID, true, utils.NonTransactional)
case utils.ACTION_PREFIX:
_, err = ms.GetActions(dataID, true, utils.NonTransactional)
case utils.ACTION_PLAN_PREFIX:
_, err = ms.GetActionPlan(dataID, true, utils.NonTransactional)
case utils.AccountActionPlansPrefix:
_, err = ms.GetAccountActionPlans(dataID, true, utils.NonTransactional)
case utils.ACTION_TRIGGER_PREFIX:
_, err = ms.GetActionTriggers(dataID, true, utils.NonTransactional)
case utils.SHARED_GROUP_PREFIX:
_, err = ms.GetSharedGroup(dataID, true, utils.NonTransactional)
case utils.DERIVEDCHARGERS_PREFIX:
_, err = ms.GetDerivedChargers(dataID, true, utils.NonTransactional)
case utils.LCR_PREFIX:
_, err = ms.GetLCR(dataID, true, utils.NonTransactional)
case utils.ALIASES_PREFIX:
_, err = ms.GetAlias(dataID, true, utils.NonTransactional)
case utils.REVERSE_ALIASES_PREFIX:
_, err = ms.GetReverseAlias(dataID, true, utils.NonTransactional)
case utils.ResourceLimitsPrefix:
_, err = ms.GetResourceLimit(dataID, true, utils.NonTransactional)
}
if err != nil {
return utils.NewCGRError(utils.REDIS,
utils.ServerErrorCaps,
err.Error(),
fmt.Sprintf("error <%s> querying MapStorage for category: <%s>, dataID: <%s>", prefix, dataID))
}
}
return
}
@@ -343,7 +458,9 @@ func (ms *MapStorage) GetRatingProfile(key string, skipCache bool, transactionID
cCommit := cacheCommit(transactionID)
if values, ok := ms.dict[key]; ok {
rpf = new(RatingProfile)
err = ms.ms.Unmarshal(values, rpf)
if err = ms.ms.Unmarshal(values, &rpf); err != nil {
return nil, err
}
} else {
cache.Set(key, nil, cCommit, transactionID)
return nil, utils.ErrNotFound
@@ -439,14 +556,18 @@ func (ms *MapStorage) GetDestination(key string, skipCache bool, transactionID s
}
r.Close()
dest = new(Destination)
err = ms.ms.Unmarshal(out, dest)
err = ms.ms.Unmarshal(out, &dest)
if err != nil {
cache.Set(key, dest, cCommit, transactionID)
cache.Set(key, nil, cCommit, transactionID)
return nil, utils.ErrNotFound
}
} else {
}
if dest == nil {
cache.Set(key, nil, cCommit, transactionID)
return nil, utils.ErrNotFound
}
cache.Set(key, dest, cCommit, transactionID)
return
}
@@ -508,16 +629,19 @@ func (ms *MapStorage) RemoveDestination(destID string, transactionID string) (er
if err != nil {
return
}
ms.mu.Lock()
delete(ms.dict, key)
ms.mu.Unlock()
cache.RemKey(key, cacheCommit(transactionID), transactionID)
for _, prefix := range d.Prefixes {
ms.mu.Lock()
ms.dict.srem(utils.REVERSE_DESTINATION_PREFIX+prefix, destID, ms.ms)
ms.mu.Unlock()
ms.GetReverseDestination(prefix, true, transactionID) // it will recache the destination
}
return
}
@@ -577,9 +701,9 @@ func (ms *MapStorage) GetActions(key string, skipCache bool, transactionID strin
ms.mu.RLock()
defer ms.mu.RUnlock()
cCommit := cacheCommit(transactionID)
key = utils.ACTION_PREFIX + key
cachekey := utils.ACTION_PREFIX + key
if !skipCache {
if x, err := cache.GetCloned(key); err != nil {
if x, err := cache.GetCloned(cachekey); err != nil {
if err.Error() != utils.ItemNotFound {
return nil, err
}
@@ -589,13 +713,13 @@ func (ms *MapStorage) GetActions(key string, skipCache bool, transactionID strin
return x.(Actions), nil
}
}
if values, ok := ms.dict[key]; ok {
if values, ok := ms.dict[cachekey]; ok {
err = ms.ms.Unmarshal(values, &as)
} else {
cache.Set(key, nil, cCommit, transactionID)
cache.Set(cachekey, nil, cCommit, transactionID)
return nil, utils.ErrNotFound
}
cache.Set(key, as, cCommit, transactionID)
cache.Set(cachekey, as, cCommit, transactionID)
return
}
@@ -603,26 +727,28 @@ func (ms *MapStorage) SetActions(key string, as Actions, transactionID string) (
ms.mu.Lock()
defer ms.mu.Unlock()
cCommit := cacheCommit(transactionID)
cachekey := utils.ACTION_PREFIX + key
result, err := ms.ms.Marshal(&as)
ms.dict[utils.ACTION_PREFIX+key] = result
cache.RemKey(utils.ACTION_PREFIX+key, cCommit, transactionID)
ms.dict[cachekey] = result
cache.RemKey(cachekey, cCommit, transactionID)
return
}
func (ms *MapStorage) RemoveActions(key string, transactionID string) (err error) {
cachekey := utils.ACTION_PREFIX + key
ms.mu.Lock()
defer ms.mu.Unlock()
delete(ms.dict, utils.ACTION_PREFIX+key)
cache.RemKey(utils.ACTION_PREFIX+key, cacheCommit(transactionID), transactionID)
delete(ms.dict, cachekey)
ms.mu.Unlock()
cache.RemKey(cachekey, cacheCommit(transactionID), transactionID)
return
}
func (ms *MapStorage) GetSharedGroup(key string, skipCache bool, transactionID string) (sg *SharedGroup, err error) {
ms.mu.RLock()
defer ms.mu.RUnlock()
key = utils.SHARED_GROUP_PREFIX + key
cachekey := utils.SHARED_GROUP_PREFIX + key
if !skipCache {
if x, ok := cache.Get(key); ok {
if x, ok := cache.Get(cachekey); ok {
if x != nil {
return x.(*SharedGroup), nil
}
@@ -630,13 +756,13 @@ func (ms *MapStorage) GetSharedGroup(key string, skipCache bool, transactionID s
}
}
cCommit := cacheCommit(transactionID)
if values, ok := ms.dict[key]; ok {
if values, ok := ms.dict[cachekey]; ok {
err = ms.ms.Unmarshal(values, &sg)
if err == nil {
cache.Set(key, sg, cCommit, transactionID)
cache.Set(cachekey, sg, cCommit, transactionID)
}
} else {
cache.Set(key, nil, cCommit, transactionID)
cache.Set(cachekey, nil, cCommit, transactionID)
return nil, utils.ErrNotFound
}
return
@@ -654,12 +780,19 @@ func (ms *MapStorage) SetSharedGroup(sg *SharedGroup, transactionID string) (err
func (ms *MapStorage) GetAccount(key string) (ub *Account, err error) {
ms.mu.RLock()
defer ms.mu.RUnlock()
if values, ok := ms.dict[utils.ACCOUNT_PREFIX+key]; ok {
ub = &Account{ID: key}
err = ms.ms.Unmarshal(values, ub)
} else {
values, ok := ms.dict[utils.ACCOUNT_PREFIX+key]
if !ok {
return nil, utils.ErrNotFound
}
ub = &Account{ID: key}
err = ms.ms.Unmarshal(values, &ub)
if err != nil {
return nil, err
}
if len(values) == 0 {
return nil, utils.ErrNotFound
}
return
}
@@ -785,41 +918,40 @@ func (ms *MapStorage) RemoveUser(key string) error {
func (ms *MapStorage) GetAlias(key string, skipCache bool, transactionID string) (al *Alias, err error) {
ms.mu.RLock()
defer ms.mu.RUnlock()
origKey := key
key = utils.ALIASES_PREFIX + key
cacheKey := utils.ALIASES_PREFIX + key
cCommit := cacheCommit(transactionID)
if !skipCache {
if x, ok := cache.Get(key); ok {
if x != nil {
al = &Alias{Values: x.(AliasValues)}
al.SetId(origKey)
return al, nil
if x, ok := cache.Get(cacheKey); ok {
if x == nil {
return nil, utils.ErrNotFound
}
return nil, utils.ErrNotFound
return x.(*Alias), nil
}
}
cCommit := cacheCommit(transactionID)
if values, ok := ms.dict[key]; ok {
if values, ok := ms.dict[cacheKey]; ok {
al = &Alias{Values: make(AliasValues, 0)}
al.SetId(key[len(utils.ALIASES_PREFIX):])
err = ms.ms.Unmarshal(values, &al.Values)
if err == nil {
cache.Set(key, al.Values, cCommit, transactionID)
al.SetId(key)
if err = ms.ms.Unmarshal(values, &al.Values); err != nil {
return nil, err
}
} else {
cache.Set(key, nil, cCommit, transactionID)
cache.Set(cacheKey, nil, cCommit, transactionID)
return nil, utils.ErrNotFound
}
return al, nil
cache.Set(cacheKey, al, cCommit, transactionID)
return
}
func (ms *MapStorage) SetAlias(al *Alias, transactionID string) error {
ms.mu.Lock()
defer ms.mu.Unlock()
result, err := ms.ms.Marshal(al.Values)
if err != nil {
return err
}
key := utils.ALIASES_PREFIX + al.GetId()
ms.mu.Lock()
defer ms.mu.Unlock()
ms.dict[key] = result
cache.RemKey(key, cacheCommit(transactionID), transactionID)
return nil
@@ -837,15 +969,15 @@ func (ms *MapStorage) GetReverseAlias(reverseID string, skipCache bool, transact
return nil, utils.ErrNotFound
}
}
var values []string
cCommit := cacheCommit(transactionID)
if idMap, ok := ms.dict.smembers(key, ms.ms); len(idMap) > 0 && ok {
values = idMap.Slice()
ids = idMap.Slice()
} else {
cache.Set(key, nil, cCommit, transactionID)
return nil, utils.ErrNotFound
}
cache.Set(key, values, cCommit, transactionID)
cache.Set(key, ids, cCommit, transactionID)
return
}
@@ -1027,6 +1159,8 @@ func (ms *MapStorage) GetAllActionPlans() (ats map[string]*ActionPlan, err error
}
func (ms *MapStorage) GetAccountActionPlans(acntID string, skipCache bool, transactionID string) (apIDs []string, err error) {
ms.mu.RLock()
defer ms.mu.RUnlock()
key := utils.AccountActionPlansPrefix + acntID
if !skipCache {
if x, ok := cache.Get(key); ok {
@@ -1036,9 +1170,7 @@ func (ms *MapStorage) GetAccountActionPlans(acntID string, skipCache bool, trans
return x.([]string), nil
}
}
ms.mu.RLock()
values, ok := ms.dict[key]
ms.mu.RUnlock()
if !ok {
cache.Set(key, nil, cacheCommit(transactionID), transactionID)
err = utils.ErrNotFound
@@ -1053,8 +1185,7 @@ func (ms *MapStorage) GetAccountActionPlans(acntID string, skipCache bool, trans
func (ms *MapStorage) SetAccountActionPlans(acntID string, apIDs []string, overwrite bool) (err error) {
if !overwrite {
oldaPlIDs, err := ms.GetAccountActionPlans(acntID, true, utils.NonTransactional)
if err != nil && err != utils.ErrNotFound {
if oldaPlIDs, err := ms.GetAccountActionPlans(acntID, true, utils.NonTransactional); err != nil && err != utils.ErrNotFound {
return err
} else {
for _, oldAPid := range oldaPlIDs {
@@ -1064,7 +1195,6 @@ func (ms *MapStorage) SetAccountActionPlans(acntID string, apIDs []string, overw
}
}
}
ms.mu.Lock()
defer ms.mu.Unlock()
result, err := ms.ms.Marshal(apIDs)
@@ -1072,12 +1202,11 @@ func (ms *MapStorage) SetAccountActionPlans(acntID string, apIDs []string, overw
return err
}
ms.dict[utils.AccountActionPlansPrefix+acntID] = result
return
}
func (ms *MapStorage) RemAccountActionPlans(acntID string, apIDs []string) (err error) {
ms.mu.Lock()
defer ms.mu.Unlock()
key := utils.AccountActionPlansPrefix + acntID
if len(apIDs) == 0 {
delete(ms.dict, key)
@@ -1094,10 +1223,17 @@ func (ms *MapStorage) RemAccountActionPlans(acntID string, apIDs []string) (err
}
i++
}
ms.mu.Lock()
defer ms.mu.Unlock()
if len(oldaPlIDs) == 0 {
delete(ms.dict, key)
return
}
var result []byte
if result, err = ms.ms.Marshal(oldaPlIDs); err != nil {
return err
}
ms.dict[key] = result
return
}
@@ -1277,7 +1413,8 @@ func (ms *MapStorage) SetResourceLimit(rl *ResourceLimit, transactionID string)
if err != nil {
return err
}
ms.dict[utils.ResourceLimitsPrefix+rl.ID] = result
key := utils.ResourceLimitsPrefix + rl.ID
ms.dict[key] = result
return nil
}
@@ -1314,9 +1451,10 @@ func (ms *MapStorage) SetReqFilterIndexes(dbKey string, indexes map[string]map[s
return
}
func (ms *MapStorage) MatchReqFilterIndex(dbKey, fieldValKey string) (itemIDs utils.StringMap, err error) {
cacheKey := dbKey + fieldValKey
ms.mu.RLock()
defer ms.mu.RUnlock()
if x, ok := cache.Get(dbKey + fieldValKey); ok { // Attempt to find in cache first
if x, ok := cache.Get(cacheKey); ok { // Attempt to find in cache first
if x != nil {
return x.(utils.StringMap), nil
}
@@ -1325,7 +1463,7 @@ func (ms *MapStorage) MatchReqFilterIndex(dbKey, fieldValKey string) (itemIDs ut
// Not found in cache, check in DB
values, ok := ms.dict[dbKey]
if !ok {
cache.Set(dbKey+fieldValKey, nil, true, utils.NonTransactional)
cache.Set(cacheKey, nil, true, utils.NonTransactional)
return nil, utils.ErrNotFound
}
var indexes map[string]map[string]utils.StringMap
@@ -1336,7 +1474,12 @@ func (ms *MapStorage) MatchReqFilterIndex(dbKey, fieldValKey string) (itemIDs ut
if _, hasIt := indexes[keySplt[0]]; hasIt {
itemIDs = indexes[keySplt[0]][keySplt[1]]
}
cache.Set(dbKey+fieldValKey, itemIDs, true, utils.NonTransactional)
//Verify items
if len(itemIDs) == 0 {
cache.Set(cacheKey, nil, true, utils.NonTransactional)
return nil, utils.ErrNotFound
}
cache.Set(cacheKey, itemIDs, true, utils.NonTransactional)
return
}

View File

@@ -18,6 +18,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
package migrator
import (
"fmt"
"log"
"strings"
"time"
"github.com/cgrates/cgrates/engine"
@@ -53,6 +56,12 @@ type v1Balance struct {
TimingIDs string
Disabled bool
}
type v1UnitsCounter struct {
Direction string
BalanceType string
// Units float64
Balances v1BalanceChain // first balance is the general one (no destination)
}
func (b *v1Balance) IsDefault() bool {
return (b.DestinationIds == "" || b.DestinationIds == utils.ANY) &&
@@ -64,34 +73,149 @@ func (b *v1Balance) IsDefault() bool {
b.Disabled == false
}
type v1UnitsCounter struct {
Direction string
BalanceType string
// Units float64
Balances v1BalanceChain // first balance is the general one (no destination)
}
type v1ActionTriggers []*v1ActionTrigger
type v1ActionTrigger struct {
Id string
ThresholdType string
ThresholdValue float64
Recurrent bool
MinSleep time.Duration
BalanceId string
BalanceType string
BalanceDirection string
BalanceDestinationIds string
BalanceWeight float64
BalanceExpirationDate time.Time
BalanceTimingTags string
BalanceRatingSubject string
BalanceCategory string
BalanceSharedGroup string
BalanceDisabled bool
Weight float64
ActionsId string
MinQueuedItems int
Executed bool
func (v1Acc v1Account) AsAccount() (ac engine.Account) {
// transfer data into new structure
ac = engine.Account{
ID: v1Acc.Id,
BalanceMap: make(map[string]engine.Balances, len(v1Acc.BalanceMap)),
UnitCounters: make(engine.UnitCounters, len(v1Acc.UnitCounters)),
ActionTriggers: make(engine.ActionTriggers, len(v1Acc.ActionTriggers)),
AllowNegative: v1Acc.AllowNegative,
Disabled: v1Acc.Disabled,
}
idElements := strings.Split(ac.ID, utils.CONCATENATED_KEY_SEP)
if len(idElements) != 3 {
log.Printf("Malformed account ID %s", v1Acc.Id)
}
ac.ID = fmt.Sprintf("%s:%s", idElements[1], idElements[2])
// balances
for oldBalKey, oldBalChain := range v1Acc.BalanceMap {
keyElements := strings.Split(oldBalKey, "*")
newBalKey := "*" + keyElements[1]
newBalDirection := "*" + idElements[0]
ac.BalanceMap[newBalKey] = make(engine.Balances, len(oldBalChain))
for index, oldBal := range oldBalChain {
// check default to set new id
ac.BalanceMap[newBalKey][index] = &engine.Balance{
Uuid: oldBal.Uuid,
ID: oldBal.Id,
Value: oldBal.Value,
Directions: utils.ParseStringMap(newBalDirection),
ExpirationDate: oldBal.ExpirationDate,
Weight: oldBal.Weight,
DestinationIDs: utils.ParseStringMap(oldBal.DestinationIds),
RatingSubject: oldBal.RatingSubject,
Categories: utils.ParseStringMap(oldBal.Category),
SharedGroups: utils.ParseStringMap(oldBal.SharedGroup),
Timings: oldBal.Timings,
TimingIDs: utils.ParseStringMap(oldBal.TimingIDs),
Disabled: oldBal.Disabled,
}
}
}
// unit counters
for _, oldUc := range v1Acc.UnitCounters {
newUc := &engine.UnitCounter{Counters: make(engine.CounterFilters, len(oldUc.Balances))}
for index, oldUcBal := range oldUc.Balances {
bf := &engine.BalanceFilter{}
if oldUcBal.Uuid != "" {
bf.Uuid = utils.StringPointer(oldUcBal.Uuid)
}
if oldUcBal.Id != "" {
bf.ID = utils.StringPointer(oldUcBal.Id)
}
if oldUc.BalanceType != "" {
bf.Type = utils.StringPointer(oldUc.BalanceType)
}
if oldUc.Direction != "" {
bf.Directions = utils.StringMapPointer(utils.ParseStringMap(oldUc.Direction))
}
if !oldUcBal.ExpirationDate.IsZero() {
bf.ExpirationDate = utils.TimePointer(oldUcBal.ExpirationDate)
}
if oldUcBal.Weight != 0 {
bf.Weight = utils.Float64Pointer(oldUcBal.Weight)
}
if oldUcBal.DestinationIds != "" {
bf.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(oldUcBal.DestinationIds))
}
if oldUcBal.RatingSubject != "" {
bf.RatingSubject = utils.StringPointer(oldUcBal.RatingSubject)
}
if oldUcBal.Category != "" {
bf.Categories = utils.StringMapPointer(utils.ParseStringMap(oldUcBal.Category))
}
if oldUcBal.SharedGroup != "" {
bf.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(oldUcBal.SharedGroup))
}
if oldUcBal.TimingIDs != "" {
bf.TimingIDs = utils.StringMapPointer(utils.ParseStringMap(oldUcBal.TimingIDs))
}
if oldUcBal.Disabled != false {
bf.Disabled = utils.BoolPointer(oldUcBal.Disabled)
}
bf.Timings = oldUcBal.Timings
cf := &engine.CounterFilter{
Value: oldUcBal.Value,
Filter: bf,
}
newUc.Counters[index] = cf
}
ac.UnitCounters[oldUc.BalanceType] = append(ac.UnitCounters[oldUc.BalanceType], newUc)
}
//action triggers
for index, oldAtr := range v1Acc.ActionTriggers {
at := &engine.ActionTrigger{
UniqueID: oldAtr.Id,
ThresholdType: oldAtr.ThresholdType,
ThresholdValue: oldAtr.ThresholdValue,
Recurrent: oldAtr.Recurrent,
MinSleep: oldAtr.MinSleep,
Weight: oldAtr.Weight,
ActionsID: oldAtr.ActionsId,
MinQueuedItems: oldAtr.MinQueuedItems,
Executed: oldAtr.Executed,
}
bf := &engine.BalanceFilter{}
if oldAtr.BalanceId != "" {
bf.ID = utils.StringPointer(oldAtr.BalanceId)
}
if oldAtr.BalanceType != "" {
bf.Type = utils.StringPointer(oldAtr.BalanceType)
}
if oldAtr.BalanceRatingSubject != "" {
bf.RatingSubject = utils.StringPointer(oldAtr.BalanceRatingSubject)
}
if oldAtr.BalanceDirection != "" {
bf.Directions = utils.StringMapPointer(utils.ParseStringMap(oldAtr.BalanceDirection))
}
if oldAtr.BalanceDestinationIds != "" {
bf.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(oldAtr.BalanceDestinationIds))
}
if oldAtr.BalanceTimingTags != "" {
bf.TimingIDs = utils.StringMapPointer(utils.ParseStringMap(oldAtr.BalanceTimingTags))
}
if oldAtr.BalanceCategory != "" {
bf.Categories = utils.StringMapPointer(utils.ParseStringMap(oldAtr.BalanceCategory))
}
if oldAtr.BalanceSharedGroup != "" {
bf.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(oldAtr.BalanceSharedGroup))
}
if oldAtr.BalanceWeight != 0 {
bf.Weight = utils.Float64Pointer(oldAtr.BalanceWeight)
}
if oldAtr.BalanceDisabled != false {
bf.Disabled = utils.BoolPointer(oldAtr.BalanceDisabled)
}
if !oldAtr.BalanceExpirationDate.IsZero() {
bf.ExpirationDate = utils.TimePointer(oldAtr.BalanceExpirationDate)
}
at.Balance = bf
ac.ActionTriggers[index] = at
if ac.ActionTriggers[index].ThresholdType == "*min_counter" ||
ac.ActionTriggers[index].ThresholdType == "*max_counter" {
ac.ActionTriggers[index].ThresholdType = strings.Replace(ac.ActionTriggers[index].ThresholdType, "_", "_event_", 1)
}
}
return
}

41
migrator/accounts_test.go Normal file
View File

@@ -0,0 +1,41 @@
/*
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
Copyright (C) ITsysCOM GmbH
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 <http://www.gnu.org/licenses/>
*/
package migrator
import (
"reflect"
"testing"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
func TestV1AccountAsAccount(t *testing.T) {
v1b := &v1Balance{Value: 10, Weight: 10, DestinationIds: "NAT"}
v1Acc := &v1Account{Id: "OUT:CUSTOMER_1:rif", BalanceMap: map[string]v1BalanceChain{utils.VOICE: v1BalanceChain{v1b}, utils.MONETARY: v1BalanceChain{&v1Balance{Value: 21}}}}
v2 := &engine.Balance{Uuid: "", ID: "", Value: 10, Directions: utils.StringMap{"*OUT": true}, Weight: 10, DestinationIDs: utils.StringMap{"NAT": true}, RatingSubject: "", Categories: utils.NewStringMap(""), SharedGroups: utils.NewStringMap(""), TimingIDs: utils.NewStringMap("")}
m2 := &engine.Balance{Uuid: "", ID: "", Value: 21, Directions: utils.StringMap{"*OUT": true}, DestinationIDs: utils.NewStringMap(""), RatingSubject: "", Categories: utils.NewStringMap(""), SharedGroups: utils.NewStringMap(""), TimingIDs: utils.NewStringMap("")}
testAccount := &engine.Account{ID: "CUSTOMER_1:rif", BalanceMap: map[string]engine.Balances{utils.VOICE: engine.Balances{v2}, utils.MONETARY: engine.Balances{m2}}, UnitCounters: engine.UnitCounters{}, ActionTriggers: engine.ActionTriggers{}}
if def := v1b.IsDefault(); def != false {
t.Errorf("Expecting: false, received: true")
}
newAcc := v1Acc.AsAccount()
if !reflect.DeepEqual(*testAccount, newAcc) {
t.Errorf("Expecting: %+v, received: %+v", *testAccount, newAcc)
}
}

86
migrator/action.go Normal file
View File

@@ -0,0 +1,86 @@
/*
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
Copyright (C) ITsysCOM GmbH
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 <http://www.gnu.org/licenses/>
*/
package migrator
import (
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
type v1Action struct {
Id string
ActionType string
BalanceType string
Direction string
ExtraParameters string
ExpirationString string
Weight float64
Balance *v1Balance
}
type v1Actions []*v1Action
func (v1Act v1Action) AsAction() (act engine.Action) {
act = engine.Action{
Id: v1Act.Id,
ActionType: v1Act.ActionType,
ExtraParameters: v1Act.ExtraParameters,
ExpirationString: v1Act.ExpirationString,
Weight: v1Act.Weight,
Balance: &engine.BalanceFilter{},
}
bf := act.Balance
if v1Act.Balance.Uuid != "" {
bf.Uuid = utils.StringPointer(v1Act.Balance.Uuid)
}
if v1Act.Balance.Id != "" {
bf.ID = utils.StringPointer(v1Act.Balance.Id)
}
if v1Act.BalanceType != "" {
bf.Type = utils.StringPointer(v1Act.BalanceType)
}
if v1Act.Balance.Value != 0 {
bf.Value = &utils.ValueFormula{Static: v1Act.Balance.Value}
}
if v1Act.Balance.RatingSubject != "" {
bf.RatingSubject = utils.StringPointer(v1Act.Balance.RatingSubject)
}
if v1Act.Balance.DestinationIds != "" {
bf.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(v1Act.Balance.DestinationIds))
}
if v1Act.Balance.TimingIDs != "" {
bf.TimingIDs = utils.StringMapPointer(utils.ParseStringMap(v1Act.Balance.TimingIDs))
}
if v1Act.Balance.Category != "" {
bf.Categories = utils.StringMapPointer(utils.ParseStringMap(v1Act.Balance.Category))
}
if v1Act.Balance.SharedGroup != "" {
bf.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(v1Act.Balance.SharedGroup))
}
if v1Act.Balance.Weight != 0 {
bf.Weight = utils.Float64Pointer(v1Act.Balance.Weight)
}
if v1Act.Balance.Disabled != false {
bf.Disabled = utils.BoolPointer(v1Act.Balance.Disabled)
}
if !v1Act.Balance.ExpirationDate.IsZero() {
bf.ExpirationDate = utils.TimePointer(v1Act.Balance.ExpirationDate)
}
bf.Timings = v1Act.Balance.Timings
return
}

75
migrator/action_plan.go Normal file
View File

@@ -0,0 +1,75 @@
/*
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
Copyright (C) ITsysCOM GmbH
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 <http://www.gnu.org/licenses/>
*/
package migrator
import (
"fmt"
"strings"
"time"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
type v1ActionPlan struct {
Uuid string // uniquely identify the timing
Id string // informative purpose only
AccountIds []string
Timing *engine.RateInterval
Weight float64
ActionsId string
actions v1Actions
stCache time.Time // cached time of the next start
}
type v1ActionPlans []*v1ActionPlan
func (at *v1ActionPlan) IsASAP() bool {
if at.Timing == nil {
return false
}
return at.Timing.Timing.StartTime == utils.ASAP
}
func (v1AP v1ActionPlan) AsActionPlan() (ap engine.ActionPlan) {
for idx, actionId := range v1AP.AccountIds {
idElements := strings.Split(actionId, utils.CONCATENATED_KEY_SEP)
if len(idElements) != 3 {
continue
}
v1AP.AccountIds[idx] = fmt.Sprintf("%s:%s", idElements[1], idElements[2])
}
ap = engine.ActionPlan{
Id: v1AP.Id,
AccountIDs: make(utils.StringMap),
}
if x := v1AP.IsASAP(); !x {
for _, accID := range v1AP.AccountIds {
if _, exists := ap.AccountIDs[accID]; !exists {
ap.AccountIDs[accID] = true
}
}
}
ap.ActionTimings = append(ap.ActionTimings, &engine.ActionTiming{
Uuid: utils.GenUUID(),
Timing: v1AP.Timing,
ActionsID: v1AP.ActionsId,
Weight: v1AP.Weight,
})
return
}

View File

@@ -0,0 +1,39 @@
/*
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
Copyright (C) ITsysCOM GmbH
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 <http://www.gnu.org/licenses/>
*/
package migrator
import (
"reflect"
"testing"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
func TestV1ActionPlanAsActionPlan(t *testing.T) {
v1ap := &v1ActionPlan{Id: "test", AccountIds: []string{"one"}, Timing: &engine.RateInterval{Timing: new(engine.RITiming)}}
ap := &engine.ActionPlan{Id: "test", AccountIDs: utils.StringMap{"one": true}, ActionTimings: []*engine.ActionTiming{&engine.ActionTiming{Timing: &engine.RateInterval{Timing: new(engine.RITiming)}}}}
newap := v1ap.AsActionPlan()
if ap.Id != newap.Id || !reflect.DeepEqual(ap.AccountIDs, newap.AccountIDs) {
t.Errorf("Expecting: %+v, received: %+v", *ap, newap)
} else if !reflect.DeepEqual(ap.ActionTimings[0].Timing, newap.ActionTimings[0].Timing) {
t.Errorf("Expecting: %+v, received: %+v", ap.ActionTimings[0].Timing, newap.ActionTimings[0].Timing)
} else if ap.ActionTimings[0].Weight != newap.ActionTimings[0].Weight || ap.ActionTimings[0].ActionsID != newap.ActionTimings[0].ActionsID {
t.Errorf("Expecting: %+v, received: %+v", ap.ActionTimings[0].Weight, newap.ActionTimings[0].Weight)
}
}

34
migrator/action_test.go Normal file
View File

@@ -0,0 +1,34 @@
/*
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
Copyright (C) ITsysCOM GmbH
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 <http://www.gnu.org/licenses/>
*/
package migrator
import (
"reflect"
"testing"
"github.com/cgrates/cgrates/engine"
)
func TestV1ActionsAsActions(t *testing.T) {
v1act := &v1Action{Id: "", ActionType: "", BalanceType: "", Direction: "INBOUND", ExtraParameters: "", ExpirationString: "", Balance: &v1Balance{}}
act := &engine.Action{Id: "", ActionType: "", ExtraParameters: "", ExpirationString: "", Weight: 0.00, Balance: &engine.BalanceFilter{}}
newact := v1act.AsAction()
if !reflect.DeepEqual(*act, newact) {
t.Errorf("Expecting: %+v, received: %+v", *act, newact)
}
}

View File

@@ -0,0 +1,89 @@
package migrator
import (
"strings"
"time"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
type v1ActionTrigger struct {
Id string
ThresholdType string
ThresholdValue float64
Recurrent bool
MinSleep time.Duration
BalanceId string
BalanceType string
BalanceDirection string
BalanceDestinationIds string
BalanceWeight float64
BalanceExpirationDate time.Time
BalanceTimingTags string
BalanceRatingSubject string
BalanceCategory string
BalanceSharedGroup string
BalanceDisabled bool
Weight float64
ActionsId string
MinQueuedItems int
Executed bool
}
type v1ActionTriggers []*v1ActionTrigger
func (v1Act v1ActionTrigger) AsActionTrigger() (at engine.ActionTrigger) {
at = engine.ActionTrigger{
UniqueID: v1Act.Id,
ThresholdType: v1Act.ThresholdType,
ThresholdValue: v1Act.ThresholdValue,
Recurrent: v1Act.Recurrent,
MinSleep: v1Act.MinSleep,
Weight: v1Act.Weight,
ActionsID: v1Act.ActionsId,
MinQueuedItems: v1Act.MinQueuedItems,
Executed: v1Act.Executed,
}
bf := &engine.BalanceFilter{}
if v1Act.BalanceId != "" {
bf.ID = utils.StringPointer(v1Act.BalanceId)
}
if v1Act.BalanceType != "" {
bf.Type = utils.StringPointer(v1Act.BalanceType)
}
if v1Act.BalanceRatingSubject != "" {
bf.RatingSubject = utils.StringPointer(v1Act.BalanceRatingSubject)
}
if v1Act.BalanceDirection != "" {
bf.Directions = utils.StringMapPointer(utils.ParseStringMap(v1Act.BalanceDirection))
}
if v1Act.BalanceDestinationIds != "" {
bf.DestinationIDs = utils.StringMapPointer(utils.ParseStringMap(v1Act.BalanceDestinationIds))
}
if v1Act.BalanceTimingTags != "" {
bf.TimingIDs = utils.StringMapPointer(utils.ParseStringMap(v1Act.BalanceTimingTags))
}
if v1Act.BalanceCategory != "" {
bf.Categories = utils.StringMapPointer(utils.ParseStringMap(v1Act.BalanceCategory))
}
if v1Act.BalanceSharedGroup != "" {
bf.SharedGroups = utils.StringMapPointer(utils.ParseStringMap(v1Act.BalanceSharedGroup))
}
if v1Act.BalanceWeight != 0 {
bf.Weight = utils.Float64Pointer(v1Act.BalanceWeight)
}
if v1Act.BalanceDisabled != false {
bf.Disabled = utils.BoolPointer(v1Act.BalanceDisabled)
}
if !v1Act.BalanceExpirationDate.IsZero() {
bf.ExpirationDate = utils.TimePointer(v1Act.BalanceExpirationDate)
}
at.Balance = bf
if at.ThresholdType == "*min_counter" ||
at.ThresholdType == "*max_counter" {
at.ThresholdType = strings.Replace(at.ThresholdType, "_", "_event_", 1)
}
return
}

View File

@@ -0,0 +1,50 @@
/*
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
Copyright (C) ITsysCOM GmbH
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 <http://www.gnu.org/licenses/>
*/
package migrator
import (
"encoding/json"
"reflect"
"testing"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
var v1ActionTriggers1 = `{"BalanceType": "*monetary","BalanceDirection": "*out","ThresholdType":"*max_balance", "ThresholdValue" :2, "ActionsId": "TEST_ACTIONS", "Executed": true}`
func TestV1ActionTriggersAsActionTriggers(t *testing.T) {
atrs := &engine.ActionTrigger{
Balance: &engine.BalanceFilter{
Type: utils.StringPointer(utils.MONETARY),
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
},
ThresholdType: utils.TRIGGER_MAX_BALANCE,
ThresholdValue: 2,
ActionsID: "TEST_ACTIONS",
Executed: true,
}
var v1actstrgrs v1ActionTrigger
if err := json.Unmarshal([]byte(v1ActionTriggers1), &v1actstrgrs); err != nil {
t.Error(err)
}
newatrs := v1actstrgrs.AsActionTrigger()
if !reflect.DeepEqual(*atrs, newatrs) {
t.Errorf("Expecting: %+v, received: %+v", *atrs, newatrs)
}
}

View File

@@ -89,8 +89,8 @@ func (m *Migrator) migrateCostDetails() (err error) {
v1CC := &v1CallCost{Direction: ccDirection.String, Category: ccCategory.String, Tenant: ccTenant.String,
Subject: ccSubject.String, Account: ccAccount.String, Destination: ccDestination.String, TOR: ccTor.String,
Cost: ccCost.Float64, Timespans: v1tmsps}
cc, err := v1CC.AsCallCost()
if err != nil {
cc := v1CC.AsCallCost()
if cc == nil {
utils.Logger.Warning(
fmt.Sprintf("<Migrator> Error: <%s> when converting into CallCost CDR with id: <%d>", err.Error(), id))
continue
@@ -152,7 +152,7 @@ type v1UnitInfo struct {
TOR string
}
func (v1cc *v1CallCost) AsCallCost() (cc *engine.CallCost, err error) {
func (v1cc *v1CallCost) AsCallCost() (cc *engine.CallCost) {
cc = new(engine.CallCost)
cc.Direction = v1cc.Direction
cc.Category = v1cc.Category

View File

@@ -31,9 +31,7 @@ func TestV1CostDetailsAsCostDetails1(t *testing.T) {
t.Error(err)
}
v1CC := &v1CallCost{Timespans: v1tmsps}
if _, err := v1CC.AsCallCost(); err != nil {
t.Error(err)
}
_ = v1CC.AsCallCost()
// ToDo: Test here the content
}
@@ -44,7 +42,6 @@ func TestV1CostDetailsAsCostDetails2(t *testing.T) {
t.Error(err)
}
v1CC := &v1CallCost{Timespans: v1tmsps}
if _, err := v1CC.AsCallCost(); err != nil {
t.Error(err)
}
_ = v1CC.AsCallCost()
}

41
migrator/sharedgroup.go Normal file
View File

@@ -0,0 +1,41 @@
/*
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
Copyright (C) ITsysCOM GmbH
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 <http://www.gnu.org/licenses/>
*/
package migrator
import (
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
type v1SharedGroup struct {
Id string
AccountParameters map[string]*engine.SharingParameters
MemberIds []string
}
func (v1SG v1SharedGroup) AsSharedGroup() (sg engine.SharedGroup) {
sg = engine.SharedGroup{
Id: v1SG.Id,
AccountParameters: v1SG.AccountParameters,
MemberIds: make(utils.StringMap),
}
for _, accID := range v1SG.MemberIds {
sg.MemberIds[accID] = true
}
return
}

View File

@@ -0,0 +1,48 @@
/*
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
Copyright (C) ITsysCOM GmbH
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 <http://www.gnu.org/licenses/>
*/
package migrator
import (
"reflect"
"testing"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
func TestV1SharedGroupAsSharedGroup(t *testing.T) {
v1sg := &v1SharedGroup{
Id: "Test",
AccountParameters: map[string]*engine.SharingParameters{
"test": &engine.SharingParameters{Strategy: "*highest"},
},
MemberIds: []string{"1", "2", "3"},
}
sg := &engine.SharedGroup{
Id: "Test",
AccountParameters: map[string]*engine.SharingParameters{
"test": &engine.SharingParameters{Strategy: "*highest"},
},
MemberIds: utils.NewStringMap("1", "2", "3"),
}
newsg := v1sg.AsSharedGroup()
if !reflect.DeepEqual(*sg, newsg) {
t.Errorf("Expecting: %+v, received: %+v", *sg, newsg)
}
}