Add models for Chargers and test for them

This commit is contained in:
TeoV
2018-07-10 08:12:27 -04:00
committed by Dan Christian Bogos
parent 463c974291
commit 43146a9c26
7 changed files with 360 additions and 28 deletions

View File

@@ -116,3 +116,7 @@ func (cS *ChargerService) V1ProcessEvent(args *utils.CGREvent,
return
}
func (cpp *ChargerProfile) TenantID() string {
return utils.ConcatenatedKey(cpp.Tenant, cpp.ID)
}

View File

@@ -2112,7 +2112,6 @@ func APItoModelStats(st *utils.TPStats) (mdls TpStatsS) {
for _, val := range st.Metrics {
if val.Parameters != "" {
paramSlice = append(paramSlice, val.Parameters)
}
}
for i, val := range utils.StringMapFromSlice(paramSlice).Slice() {
@@ -2836,3 +2835,108 @@ func APItoAttributeProfile(tpTH *utils.TPAttributeProfile, timezone string) (th
}
return th, nil
}
type TPChargers []*TPCharger
func (tps TPChargers) AsTPChargers() (result []*utils.TPChargerProfile) {
mst := make(map[string]*utils.TPChargerProfile)
for _, tp := range tps {
tpCPP, found := mst[tp.ID]
if !found {
tpCPP = &utils.TPChargerProfile{
TPid: tp.Tpid,
Tenant: tp.Tenant,
ID: tp.ID,
}
}
if tp.Weight != 0 {
tpCPP.Weight = tp.Weight
}
if len(tp.ActivationInterval) != 0 {
tpCPP.ActivationInterval = new(utils.TPActivationInterval)
aiSplt := strings.Split(tp.ActivationInterval, utils.INFIELD_SEP)
if len(aiSplt) == 2 {
tpCPP.ActivationInterval.ActivationTime = aiSplt[0]
tpCPP.ActivationInterval.ExpiryTime = aiSplt[1]
} else if len(aiSplt) == 1 {
tpCPP.ActivationInterval.ActivationTime = aiSplt[0]
}
}
if tp.FilterIDs != "" {
filterSplit := strings.Split(tp.FilterIDs, utils.INFIELD_SEP)
tpCPP.FilterIDs = append(tpCPP.FilterIDs, filterSplit...)
}
if tp.RunID != "" {
tpCPP.RunID = tp.RunID
}
if tp.AttributeIDs != "" {
attributeSplit := strings.Split(tp.AttributeIDs, utils.INFIELD_SEP)
tpCPP.AttributeIDs = append(tpCPP.AttributeIDs, attributeSplit...)
}
mst[tp.ID] = tpCPP
}
result = make([]*utils.TPChargerProfile, len(mst))
i := 0
for _, tp := range mst {
result[i] = tp
i++
}
return
}
func APItoModelTPCharger(tpCPP *utils.TPChargerProfile) (mdls TPChargers) {
if tpCPP != nil {
mdl := &TPCharger{
Tenant: tpCPP.Tenant,
Tpid: tpCPP.TPid,
ID: tpCPP.ID,
}
mdl.Weight = tpCPP.Weight
mdl.RunID = tpCPP.RunID
for i, val := range tpCPP.AttributeIDs {
if i != 0 {
mdl.AttributeIDs += utils.INFIELD_SEP
}
mdl.AttributeIDs += val
}
for i, val := range tpCPP.FilterIDs {
if i != 0 {
mdl.FilterIDs += utils.INFIELD_SEP
}
mdl.FilterIDs += val
}
if tpCPP.ActivationInterval != nil {
if tpCPP.ActivationInterval.ActivationTime != "" {
mdl.ActivationInterval = tpCPP.ActivationInterval.ActivationTime
}
if tpCPP.ActivationInterval.ExpiryTime != "" {
mdl.ActivationInterval += utils.INFIELD_SEP + tpCPP.ActivationInterval.ExpiryTime
}
}
mdls = append(mdls, mdl)
}
return
}
func APItoChargerProfile(tpCPP *utils.TPChargerProfile, timezone string) (cpp *ChargerProfile, err error) {
cpp = &ChargerProfile{
Tenant: tpCPP.Tenant,
ID: tpCPP.ID,
Weight: tpCPP.Weight,
RunID: tpCPP.RunID,
FilterIDs: []string{},
AttributeIDs: []string{},
}
for _, fli := range tpCPP.FilterIDs {
cpp.FilterIDs = append(cpp.FilterIDs, fli)
}
for _, attribute := range tpCPP.AttributeIDs {
cpp.AttributeIDs = append(cpp.AttributeIDs, attribute)
}
if tpCPP.ActivationInterval != nil {
if cpp.ActivationInterval, err = tpCPP.ActivationInterval.AsActivationInterval(timezone); err != nil {
return nil, err
}
}
return cpp, nil
}

View File

@@ -1329,3 +1329,100 @@ func TestModelAsTPAttribute(t *testing.T) {
t.Errorf("Expecting : %+v, received: %+v", utils.ToJSON(expected), utils.ToJSON(rcv[0]))
}
}
func TestAPItoChargerProfile(t *testing.T) {
tpCPP := &utils.TPChargerProfile{
TPid: "TP1",
Tenant: "cgrates.org",
ID: "Charger1",
FilterIDs: []string{"FLTR_ACNT_dan", "FLTR_DST_DE"},
RunID: "*rated",
ActivationInterval: &utils.TPActivationInterval{
ActivationTime: "2014-07-14T14:35:00Z",
ExpiryTime: "",
},
AttributeIDs: []string{"ATTR1", "ATTR2"},
Weight: 20,
}
expected := &ChargerProfile{
Tenant: "cgrates.org",
ID: "Charger1",
FilterIDs: []string{"FLTR_ACNT_dan", "FLTR_DST_DE"},
ActivationInterval: &utils.ActivationInterval{
ActivationTime: time.Date(2014, 7, 14, 14, 35, 0, 0, time.UTC),
},
RunID: "*rated",
AttributeIDs: []string{"ATTR1", "ATTR2"},
Weight: 20,
}
if rcv, err := APItoChargerProfile(tpCPP, "UTC"); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(expected, rcv) {
t.Errorf("Expecting : %+v, received: %+v", utils.ToJSON(expected), utils.ToJSON(rcv))
}
}
func TestAPItoModelTPCharger(t *testing.T) {
tpCharger := &utils.TPChargerProfile{
TPid: "TP1",
Tenant: "cgrates.org",
ID: "Charger1",
FilterIDs: []string{"FLTR_ACNT_dan", "FLTR_DST_DE"},
RunID: "*rated",
ActivationInterval: &utils.TPActivationInterval{
ActivationTime: "2014-07-14T14:35:00Z",
ExpiryTime: "",
},
AttributeIDs: []string{"ATTR1", "ATTR2"},
Weight: 20,
}
expected := TPChargers{
&TPCharger{
Tpid: "TP1",
Tenant: "cgrates.org",
ID: "Charger1",
FilterIDs: "FLTR_ACNT_dan;FLTR_DST_DE",
RunID: "*rated",
AttributeIDs: "ATTR1;ATTR2",
ActivationInterval: "2014-07-14T14:35:00Z",
Weight: 20,
},
}
rcv := APItoModelTPCharger(tpCharger)
if !reflect.DeepEqual(expected, rcv) {
t.Errorf("Expecting : %+v, received: %+v", utils.ToJSON(expected), utils.ToJSON(rcv))
}
}
func TestModelAsTPChargers(t *testing.T) {
models := TPChargers{
&TPCharger{
Tpid: "TP1",
Tenant: "cgrates.org",
ID: "Charger1",
FilterIDs: "FLTR_ACNT_dan;FLTR_DST_DE",
RunID: "*rated",
AttributeIDs: "ATTR1;ATTR2",
ActivationInterval: "2014-07-14T14:35:00Z",
Weight: 20,
},
}
expected := &utils.TPChargerProfile{
TPid: "TP1",
Tenant: "cgrates.org",
ID: "Charger1",
FilterIDs: []string{"FLTR_ACNT_dan", "FLTR_DST_DE"},
RunID: "*rated",
ActivationInterval: &utils.TPActivationInterval{
ActivationTime: "2014-07-14T14:35:00Z",
ExpiryTime: "",
},
AttributeIDs: []string{"ATTR1", "ATTR2"},
Weight: 20,
}
rcv := models.AsTPChargers()
if !reflect.DeepEqual(expected, rcv[0]) {
t.Errorf("Expecting : %+v, received: %+v", utils.ToJSON(expected), utils.ToJSON(rcv[0]))
}
}

View File

@@ -759,7 +759,7 @@ func (csvs *CSVStorage) GetTPAttributes(tpid, id string) ([]*utils.TPAttributePr
return nil, err
}
if attributeProfile, err := csvLoad(TPAttribute{}, record); err != nil {
log.Print("error loading tpAliasProfile: ", err)
log.Print("error loading tpAttributeProfile: ", err)
return nil, err
} else {
attributeProfile := attributeProfile.(TPAttribute)
@@ -771,31 +771,31 @@ func (csvs *CSVStorage) GetTPAttributes(tpid, id string) ([]*utils.TPAttributePr
}
func (csvs *CSVStorage) GetTPChargers(tpid, id string) ([]*utils.TPChargerProfile, error) {
// csvReader, fp, err := csvs.readerFunc(csvs.chargerProfilesFn, csvs.sep, getColumnCount(TPCharger{}))
// if err != nil {
// //log.Print("Could not load AttributeProfile file: ", err)
// // allow writing of the other values
// return nil, nil
// }
// if fp != nil {
// defer fp.Close()
// }
// var tpAls TPAttributes
// for record, err := csvReader.Read(); err != io.EOF; record, err = csvReader.Read() {
// if err != nil {
// log.Printf("bad line in %s, %s\n", csvs.chargerProfilesFn, err.Error())
// return nil, err
// }
// if attributeProfile, err := csvLoad(TPAttribute{}, record); err != nil {
// log.Print("error loading tpAliasProfile: ", err)
// return nil, err
// } else {
// attributeProfile := attributeProfile.(TPAttribute)
// attributeProfile.Tpid = tpid
// tpAls = append(tpAls, &attributeProfile)
// }
// }
return nil, nil
csvReader, fp, err := csvs.readerFunc(csvs.chargerProfilesFn, csvs.sep, getColumnCount(TPCharger{}))
if err != nil {
//log.Print("Could not load AttributeProfile file: ", err)
// allow writing of the other values
return nil, nil
}
if fp != nil {
defer fp.Close()
}
var tpCPPs TPChargers
for record, err := csvReader.Read(); err != io.EOF; record, err = csvReader.Read() {
if err != nil {
log.Printf("bad line in %s, %s\n", csvs.chargerProfilesFn, err.Error())
return nil, err
}
if cpp, err := csvLoad(TPCharger{}, record); err != nil {
log.Print("error loading tpChargerProfile: ", err)
return nil, err
} else {
cpp := cpp.(TPCharger)
cpp.Tpid = tpid
tpCPPs = append(tpCPPs, &cpp)
}
}
return tpCPPs.AsTPChargers(), nil
}
func (csvs *CSVStorage) GetTpIds(colName string) ([]string, error) {

View File

@@ -738,6 +738,28 @@ func (self *SQLStorage) SetTPAttributes(tpAttrs []*utils.TPAttributeProfile) err
return nil
}
func (self *SQLStorage) SetTPChargers(tpCPPs []*utils.TPChargerProfile) error {
if len(tpCPPs) == 0 {
return nil
}
tx := self.db.Begin()
for _, cpp := range tpCPPs {
// Remove previous
if err := tx.Where(&TPCharger{Tpid: cpp.TPid, ID: cpp.ID}).Delete(TPCharger{}).Error; err != nil {
tx.Rollback()
return err
}
for _, mst := range APItoModelTPCharger(cpp) {
if err := tx.Save(&mst).Error; err != nil {
tx.Rollback()
return err
}
}
}
tx.Commit()
return nil
}
func (self *SQLStorage) SetSMCost(smc *SMCost) error {
if smc.CostDetails == nil {
return nil
@@ -1624,7 +1646,19 @@ func (self *SQLStorage) GetTPAttributes(tpid, id string) ([]*utils.TPAttributePr
}
func (self *SQLStorage) GetTPChargers(tpid, id string) ([]*utils.TPChargerProfile, error) {
return nil, nil
var cpps TPChargers
q := self.db.Where("tpid = ?", tpid)
if len(id) != 0 {
q = q.Where("id = ?", id)
}
if err := q.Find(&cpps).Error; err != nil {
return nil, err
}
arls := cpps.AsTPChargers()
if len(arls) == 0 {
return arls, utils.ErrNotFound
}
return arls, nil
}
// GetVersions returns slice of all versions or a specific version if tag is specified

View File

@@ -58,11 +58,13 @@ type TpReader struct {
filters map[utils.TenantID]*utils.TPFilterProfile
sppProfiles map[utils.TenantID]*utils.TPSupplierProfile
attributeProfiles map[utils.TenantID]*utils.TPAttributeProfile
chargerProfiles map[utils.TenantID]*utils.TPChargerProfile
resources []*utils.TenantID // IDs of resources which need creation based on resourceProfiles
statQueues []*utils.TenantID // IDs of statQueues which need creation based on statQueueProfiles
thresholds []*utils.TenantID // IDs of thresholds which need creation based on thresholdProfiles
suppliers []*utils.TenantID // IDs of suppliers which need creation based on sppProfiles
attrTntID []*utils.TenantID // IDs of suppliers which need creation based on attributeProfiles
chargers []*utils.TenantID // IDs of chargers which need creation based on chargerProfiles
revDests,
revAliases,
acntActionPlans map[string][]string
@@ -138,6 +140,7 @@ func (tpr *TpReader) Init() {
tpr.thProfiles = make(map[utils.TenantID]*utils.TPThreshold)
tpr.sppProfiles = make(map[utils.TenantID]*utils.TPSupplierProfile)
tpr.attributeProfiles = make(map[utils.TenantID]*utils.TPAttributeProfile)
tpr.chargerProfiles = make(map[utils.TenantID]*utils.TPChargerProfile)
tpr.filters = make(map[utils.TenantID]*utils.TPFilterProfile)
tpr.revDests = make(map[string][]string)
tpr.revAliases = make(map[string][]string)
@@ -1738,6 +1741,30 @@ func (tpr *TpReader) LoadAttributeProfiles() error {
return tpr.LoadAttributeProfilesFiltered("")
}
func (tpr *TpReader) LoadChargerProfilesFiltered(tag string) (err error) {
rls, err := tpr.lr.GetTPChargers(tpr.tpid, tag)
if err != nil {
return err
}
mapChargerProfile := make(map[utils.TenantID]*utils.TPChargerProfile)
for _, rl := range rls {
mapChargerProfile[utils.TenantID{Tenant: rl.Tenant, ID: rl.ID}] = rl
}
tpr.chargerProfiles = mapChargerProfile
for tntID, _ := range mapChargerProfile {
if has, err := tpr.dm.HasData(utils.ChargerProfilePrefix, tntID.ID, tntID.Tenant); err != nil {
return err
} else if !has {
tpr.chargers = append(tpr.chargers, &utils.TenantID{Tenant: tntID.Tenant, ID: tntID.ID})
}
}
return nil
}
func (tpr *TpReader) LoadChargerProfiles() error {
return tpr.LoadChargerProfilesFiltered("")
}
func (tpr *TpReader) LoadAll() (err error) {
if err = tpr.LoadDestinations(); err != nil && err.Error() != utils.NotFoundCaps {
return
@@ -1805,6 +1832,9 @@ func (tpr *TpReader) LoadAll() (err error) {
if err = tpr.LoadAttributeProfiles(); err != nil && err.Error() != utils.NotFoundCaps {
return
}
if err = tpr.LoadChargerProfiles(); err != nil && err.Error() != utils.NotFoundCaps {
return
}
return nil
}
@@ -2175,6 +2205,23 @@ func (tpr *TpReader) WriteToDatabase(flush, verbose, disable_reverse bool) (err
}
}
if verbose {
log.Print("ChargerProfiles:")
}
for _, tpTH := range tpr.chargerProfiles {
th, err := APItoChargerProfile(tpTH, tpr.timezone)
if err != nil {
return err
}
if err = tpr.dm.SetChargerProfile(th, true); err != nil {
return err
}
if verbose {
log.Print("\t", th.TenantID())
}
}
if verbose {
log.Print("Timings:")
}
@@ -2284,6 +2331,8 @@ func (tpr *TpReader) ShowStatistics() {
log.Print("SupplierProfiles: ", len(tpr.sppProfiles))
// Attribute profiles
log.Print("AttributeProfiles: ", len(tpr.attributeProfiles))
// Charger profiles
log.Print("ChargerProfiles: ", len(tpr.chargerProfiles))
}
// Returns the identities loaded for a specific category, useful for cache reloads
@@ -2457,6 +2506,14 @@ func (tpr *TpReader) GetLoadedIds(categ string) ([]string, error) {
i++
}
return keys, nil
case utils.ChargerProfilePrefix:
keys := make([]string, len(tpr.chargerProfiles))
i := 0
for k, _ := range tpr.chargerProfiles {
keys[i] = k.TenantID()
i++
}
return keys, nil
}
return nil, errors.New("Unsupported load category")
}
@@ -2722,6 +2779,31 @@ func (tpr *TpReader) RemoveFromDatabase(verbose, disable_reverse bool) (err erro
log.Print("\t", tpTH.Tenant)
}
}
if verbose {
log.Print("AttributeProfiles:")
}
for _, tpTH := range tpr.attributeProfiles {
if err = tpr.dm.RemoveAttributeProfile(tpTH.Tenant, tpTH.ID, tpTH.Contexts, utils.NonTransactional, false); err != nil {
return err
}
if verbose {
log.Print("\t", tpTH.Tenant)
}
}
if verbose {
log.Print("ChargerProfiles:")
}
for _, tpTH := range tpr.chargerProfiles {
if err = tpr.dm.RemoveChargerProfile(tpTH.Tenant, tpTH.ID, utils.NonTransactional, false); err != nil {
return err
}
if verbose {
log.Print("\t", tpTH.Tenant)
}
}
if verbose {
log.Print("Timings:")
}

View File

@@ -295,6 +295,17 @@ func (self *TPExporter) Run() error {
}
}
storDataChargers, err := self.storDb.GetTPChargers(self.tpID, "")
if err != nil && err.Error() != utils.ErrNotFound.Error() {
return err
}
for _, sd := range storDataChargers {
sdModels := APItoModelTPCharger(sd)
for _, sdModel := range sdModels {
toExportMap[utils.ChargersCsv] = append(toExportMap[utils.ChargersCsv], sdModel)
}
}
storDataUsers, err := self.storDb.GetTPUsers(&utils.TPUsers{TPid: self.tpID})
if err != nil && err.Error() != utils.ErrNotFound.Error() {
return err