mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-15 05:09:54 +05:00
Added test for IntService
This commit is contained in:
committed by
Dan Christian Bogos
parent
904a6817e4
commit
5b150b7da9
@@ -1031,12 +1031,12 @@ func TestConfigSanityStatS(t *testing.T) {
|
||||
Enabled: true,
|
||||
ThresholdSConns: []string{utils.MetaInternal},
|
||||
}
|
||||
expected := "<ThresholdS> not enabled but requested by <Stats> component"
|
||||
expected := "<ThresholdS> not enabled but requested by <StatS> component"
|
||||
if err := cfg.checkConfigSanity(); err == nil || err.Error() != expected {
|
||||
t.Errorf("Expecting: %+q received: %+q", expected, err)
|
||||
}
|
||||
cfg.statsCfg.ThresholdSConns = []string{"test"}
|
||||
expected = "<Stats> connection with id: <test> not defined"
|
||||
expected = "<StatS> connection with id: <test> not defined"
|
||||
if err := cfg.checkConfigSanity(); err == nil || err.Error() != expected {
|
||||
t.Errorf("Expecting: %+q received: %+q", expected, err)
|
||||
}
|
||||
@@ -1619,7 +1619,7 @@ func TestConfigSanityDataDB(t *testing.T) {
|
||||
cfg.resourceSCfg.Enabled = false
|
||||
|
||||
cfg.statsCfg.Enabled = true
|
||||
expected = "<Stats> the StoreInterval field needs to be -1 when DataBD is *internal, received : 0"
|
||||
expected = "<StatS> the StoreInterval field needs to be -1 when DataBD is *internal, received : 0"
|
||||
if err := cfg.checkConfigSanity(); err == nil || err.Error() != expected {
|
||||
t.Errorf("Expecting: %+q received: %+q", expected, err)
|
||||
}
|
||||
@@ -1749,7 +1749,7 @@ func TestConfigSanityFilterS(t *testing.T) {
|
||||
cfg = NewDefaultCGRConfig()
|
||||
cfg.filterSCfg.StatSConns = []string{utils.MetaInternal}
|
||||
|
||||
if err := cfg.checkConfigSanity(); err == nil || err.Error() != "<Stats> not enabled but requested by <FilterS> component" {
|
||||
if err := cfg.checkConfigSanity(); err == nil || err.Error() != "<StatS> not enabled but requested by <FilterS> component" {
|
||||
t.Error(err)
|
||||
}
|
||||
cfg.filterSCfg.StatSConns = []string{"test"}
|
||||
|
||||
@@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package engine
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
@@ -137,6 +138,7 @@ func NewServiceWithName(val interface{}, name string, useName bool) (_ IntServic
|
||||
if srv, err = birpc.NewService(val, name, useName); err != nil {
|
||||
return
|
||||
}
|
||||
srv.Methods["Ping"] = pingM
|
||||
s := IntService{srv.Name: srv}
|
||||
for m, v := range srv.Methods {
|
||||
m = strings.TrimPrefix(m, "BiRPC")
|
||||
@@ -174,6 +176,7 @@ func NewDispatcherService(val interface{}) (_ IntService, err error) {
|
||||
if srv, err = birpc.NewService(val, utils.EmptyString, false); err != nil {
|
||||
return
|
||||
}
|
||||
srv.Methods["Ping"] = pingM
|
||||
s := IntService{srv.Name: srv}
|
||||
for m, v := range srv.Methods {
|
||||
key := srv.Name
|
||||
@@ -226,11 +229,16 @@ func NewDispatcherService(val interface{}) (_ IntService, err error) {
|
||||
case strings.HasPrefix(m, utils.CDRs):
|
||||
m = strings.TrimPrefix(m, utils.CDRs)
|
||||
key = utils.CDRs
|
||||
|
||||
case len(m) < 2 || m[0] != 'V':
|
||||
}
|
||||
if len(m) < 2 || unicode.ToLower(rune(m[0])) != 'v' {
|
||||
continue
|
||||
}
|
||||
key += "v" + string(m[1])
|
||||
if unicode.IsLower(rune(key[len(key)-1])) {
|
||||
key += "V"
|
||||
} else {
|
||||
key += "v"
|
||||
}
|
||||
key += string(m[1])
|
||||
srv2, has := s[key]
|
||||
if !has {
|
||||
srv2 = new(birpc.Service)
|
||||
@@ -247,8 +255,12 @@ func NewDispatcherService(val interface{}) (_ IntService, err error) {
|
||||
|
||||
type IntService map[string]*birpc.Service
|
||||
|
||||
func (s IntService) Call(ctx *context.Context, method string, args, reply interface{}) error {
|
||||
return s[strings.Split(method, utils.NestingSep)[0]].Call(ctx, method, args, reply)
|
||||
func (s IntService) Call(ctx *context.Context, serviceMethod string, args, reply interface{}) error {
|
||||
service, has := s[strings.Split(serviceMethod, utils.NestingSep)[0]]
|
||||
if !has {
|
||||
return errors.New("rpc: can't find service " + serviceMethod)
|
||||
}
|
||||
return service.Call(ctx, serviceMethod, args, reply)
|
||||
}
|
||||
|
||||
func ping(_ interface{}, _ *context.Context, _ *utils.CGREvent, reply *string) error {
|
||||
|
||||
@@ -20,6 +20,7 @@ package engine
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -109,3 +110,133 @@ func TestLibengineNewRPCConnectionInternal(t *testing.T) {
|
||||
t.Error("Connections don't match")
|
||||
}
|
||||
}
|
||||
|
||||
type TestRPCSrvMock struct{} // exported for service
|
||||
|
||||
func (TestRPCSrvMock) Do(*context.Context, interface{}, *string) error { return nil }
|
||||
func (TestRPCSrvMock) V1Do(*context.Context, interface{}, *string) error { return nil }
|
||||
func (TestRPCSrvMock) V2Do(*context.Context, interface{}, *string) error { return nil }
|
||||
|
||||
type TestRPCSrvMockS struct{} // exported for service
|
||||
|
||||
func (TestRPCSrvMockS) Do(*context.Context, interface{}, *string) error { return nil }
|
||||
func (TestRPCSrvMockS) V1Do(*context.Context, interface{}, *string) error { return nil }
|
||||
func (TestRPCSrvMockS) V2Do(*context.Context, interface{}, *string) error { return nil }
|
||||
|
||||
func getMethods(s IntService) (methods map[string][]string) {
|
||||
methods = map[string][]string{}
|
||||
for _, v := range s {
|
||||
for m := range v.Methods {
|
||||
methods[v.Name] = append(methods[v.Name], m)
|
||||
}
|
||||
}
|
||||
for k := range methods {
|
||||
sort.Strings(methods[k])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func TestIntServiceNewService(t *testing.T) {
|
||||
expErrMsg := `rpc.Register: no service name for type struct {}`
|
||||
if _, err := NewService(struct{}{}); err == nil || err.Error() != expErrMsg {
|
||||
t.Errorf("Expeceted: %v, received: %v", expErrMsg, err)
|
||||
}
|
||||
s, err := NewService(new(TestRPCSrvMock))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(s) != 3 {
|
||||
t.Errorf("Not all rpc APIs were registerd")
|
||||
}
|
||||
methods := getMethods(s)
|
||||
exp := map[string][]string{
|
||||
"TestRPCSrvMock": {"Do", "Ping", "V1Do", "V2Do"},
|
||||
"TestRPCSrvMockV1": {"Do", "Ping"},
|
||||
"TestRPCSrvMockV2": {"Do", "Ping"},
|
||||
}
|
||||
if !reflect.DeepEqual(exp, methods) {
|
||||
t.Errorf("Expeceted: %v, received: %v", utils.ToJSON(exp), utils.ToJSON(methods))
|
||||
}
|
||||
|
||||
s, err = NewService(new(TestRPCSrvMockS))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(s) != 3 {
|
||||
t.Errorf("Not all rpc APIs were registerd")
|
||||
}
|
||||
methods = getMethods(s)
|
||||
exp = map[string][]string{
|
||||
"TestRPCSrvMockS": {"Do", "Ping", "V1Do", "V2Do"},
|
||||
"TestRPCSrvMockSv1": {"Do", "Ping"},
|
||||
"TestRPCSrvMockSv2": {"Do", "Ping"},
|
||||
}
|
||||
if !reflect.DeepEqual(exp, methods) {
|
||||
t.Errorf("Expeceted: %v, received: %v", utils.ToJSON(exp), utils.ToJSON(methods))
|
||||
}
|
||||
|
||||
var rply string
|
||||
if err := s.Call(context.Background(), "TestRPCSrvMockSv1.Ping", new(utils.CGREvent), &rply); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if rply != utils.Pong {
|
||||
t.Errorf("Expeceted: %q, received: %q", utils.Pong, rply)
|
||||
}
|
||||
|
||||
expErrMsg = `rpc: can't find service TestRPCSrvMockv1.Ping`
|
||||
if err := s.Call(context.Background(), "TestRPCSrvMockv1.Ping", new(utils.CGREvent), &rply); err == nil || err.Error() != expErrMsg {
|
||||
t.Errorf("Expeceted: %v, received: %v", expErrMsg, err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type TestRPCDspMock struct{} // exported for service
|
||||
|
||||
func (TestRPCDspMock) AccountSv1Do(*context.Context, interface{}, *string) error { return nil }
|
||||
func (TestRPCDspMock) ActionSv1Do(*context.Context, interface{}, *string) error { return nil }
|
||||
func (TestRPCDspMock) AttributeSv1Do(*context.Context, interface{}, *string) error { return nil }
|
||||
func (TestRPCDspMock) CacheSv1Do(*context.Context, interface{}, *string) error { return nil }
|
||||
func (TestRPCDspMock) ChargerSv1Do(*context.Context, interface{}, *string) error { return nil }
|
||||
func (TestRPCDspMock) ConfigSv1Do(*context.Context, interface{}, *string) error { return nil }
|
||||
func (TestRPCDspMock) DispatcherSv1Do(*context.Context, interface{}, *string) error { return nil }
|
||||
func (TestRPCDspMock) GuardianSv1Do(*context.Context, interface{}, *string) error { return nil }
|
||||
func (TestRPCDspMock) RateSv1Do(*context.Context, interface{}, *string) error { return nil }
|
||||
func (TestRPCDspMock) ReplicatorSv1Do(*context.Context, interface{}, *string) error { return nil }
|
||||
func (TestRPCDspMock) ResourceSv1Do(*context.Context, interface{}, *string) error { return nil }
|
||||
func (TestRPCDspMock) RouteSv1Do(*context.Context, interface{}, *string) error { return nil }
|
||||
func (TestRPCDspMock) SessionSv1Do(*context.Context, interface{}, *string) error { return nil }
|
||||
func (TestRPCDspMock) StatSv1Do(*context.Context, interface{}, *string) error { return nil }
|
||||
func (TestRPCDspMock) ThresholdSv1Do(*context.Context, interface{}, *string) error { return nil }
|
||||
func (TestRPCDspMock) CDRsv1Do(*context.Context, interface{}, *string) error { return nil }
|
||||
func TestIntServiceNewDispatcherService(t *testing.T) {
|
||||
expErrMsg := `rpc.Register: no service name for type struct {}`
|
||||
if _, err := NewDispatcherService(struct{}{}); err == nil || err.Error() != expErrMsg {
|
||||
t.Errorf("Expeceted: %v, received: %v", expErrMsg, err)
|
||||
}
|
||||
|
||||
s, err := NewDispatcherService(new(TestRPCDspMock))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
methods := getMethods(s)
|
||||
exp := map[string][]string{
|
||||
"AccountSv1": {"Do", "Ping"},
|
||||
"ActionSv1": {"Do", "Ping"},
|
||||
"AttributeSv1": {"Do", "Ping"},
|
||||
"CDRsV1": {"Do", "Ping"},
|
||||
"CacheSv1": {"Do", "Ping"},
|
||||
"ChargerSv1": {"Do", "Ping"},
|
||||
"ConfigSv1": {"Do", "Ping"},
|
||||
"DispatcherSv1": {"Do", "Ping"},
|
||||
"GuardianSv1": {"Do", "Ping"},
|
||||
"RateSv1": {"Do", "Ping"},
|
||||
"ResourceSv1": {"Do", "Ping"},
|
||||
"RouteSv1": {"Do", "Ping"},
|
||||
"SessionSv1": {"Do", "Ping"},
|
||||
"StatSv1": {"Do", "Ping"},
|
||||
"TestRPCDspMock": {"AccountSv1Do", "ActionSv1Do", "AttributeSv1Do", "CDRsv1Do", "CacheSv1Do", "ChargerSv1Do", "ConfigSv1Do", "DispatcherSv1Do", "GuardianSv1Do", "Ping", "RateSv1Do", "ReplicatorSv1Do", "ResourceSv1Do", "RouteSv1Do", "SessionSv1Do", "StatSv1Do", "ThresholdSv1Do"},
|
||||
"ThresholdSv1": {"Do", "Ping"},
|
||||
}
|
||||
if !reflect.DeepEqual(exp, methods) {
|
||||
t.Errorf("Expeceted: %v, received: %v", utils.ToJSON(exp), utils.ToJSON(methods))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ func (vers Versions) Compare(curent Versions, storType string, isDataDB bool) st
|
||||
// CurrentDataDBVersions returns the needed DataDB versions
|
||||
func CurrentDataDBVersions() Versions {
|
||||
return Versions{
|
||||
utils.StatS: 4,
|
||||
utils.Stats: 4,
|
||||
utils.Accounts: 3,
|
||||
utils.Actions: 2,
|
||||
utils.Thresholds: 4,
|
||||
|
||||
@@ -72,7 +72,7 @@ func TestVersionCompare(t *testing.T) {
|
||||
|
||||
func TestCurrentDBVersions(t *testing.T) {
|
||||
expVersDataDB := Versions{
|
||||
utils.StatS: 4, utils.Accounts: 3, utils.Actions: 2,
|
||||
utils.Stats: 4, utils.Accounts: 3, utils.Actions: 2,
|
||||
utils.Thresholds: 4, utils.Routes: 2, utils.Attributes: 7,
|
||||
utils.RQF: 5, utils.Resource: 1,
|
||||
utils.Subscribers: 1,
|
||||
|
||||
@@ -404,7 +404,7 @@ func testUpdateVersionsRoutes(t *testing.T) {
|
||||
|
||||
func testUpdateVersionsStats(t *testing.T) {
|
||||
newVersions := CurrentDataDBVersions()
|
||||
newVersions[utils.StatS] = 3
|
||||
newVersions[utils.Stats] = 3
|
||||
if err := dm3.DataDB().SetVersions(newVersions, true); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
2
go.mod
2
go.mod
@@ -17,7 +17,7 @@ require (
|
||||
github.com/cenkalti/rpc2 v0.0.0-20210220005819-4a29bc83afe1
|
||||
github.com/cgrates/aringo v0.0.0-20201113143849-3b299e4e636d
|
||||
github.com/cgrates/baningo v0.0.0-20210413080722-004ffd5e429f
|
||||
github.com/cgrates/birpc v1.3.1-0.20210517105830-c9cc855bcec5
|
||||
github.com/cgrates/birpc v1.3.1-0.20211117095917-5b0ff29f3084
|
||||
github.com/cgrates/cron v0.0.0-20201022095836-3522d5b72c70
|
||||
github.com/cgrates/fsock v0.0.0-20191107070144-e7a331109df7
|
||||
github.com/cgrates/kamevapi v0.0.0-20191001125829-7dbc3ad58817
|
||||
|
||||
4
go.sum
4
go.sum
@@ -86,8 +86,8 @@ github.com/cgrates/aringo v0.0.0-20201113143849-3b299e4e636d/go.mod h1:mMAzSIjK1
|
||||
github.com/cgrates/baningo v0.0.0-20210413080722-004ffd5e429f h1:dCp5BflGB8I8wlhWn4R5g0o4ok2pZRmcYHyzIks9Pbc=
|
||||
github.com/cgrates/baningo v0.0.0-20210413080722-004ffd5e429f/go.mod h1:3SwVROaS1Iml5lqEhj0gRhDRtmbBgypZpKcEkVTSleU=
|
||||
github.com/cgrates/birpc v1.3.1-0.20210413080448-f81834a37fd3/go.mod h1:z/PmNnDPqSQALedKJv5T8+eXIq6XHa9J0St1YsvAVns=
|
||||
github.com/cgrates/birpc v1.3.1-0.20210517105830-c9cc855bcec5 h1:Pn9VGy13xCMm3zW5QaUCoIa3dsPbTIajgnCt4rcXJ2w=
|
||||
github.com/cgrates/birpc v1.3.1-0.20210517105830-c9cc855bcec5/go.mod h1:z/PmNnDPqSQALedKJv5T8+eXIq6XHa9J0St1YsvAVns=
|
||||
github.com/cgrates/birpc v1.3.1-0.20211117095917-5b0ff29f3084 h1:YIEepjEOjeHaFrewWaar/JkXYiDgO7gRw/R1zWITxEw=
|
||||
github.com/cgrates/birpc v1.3.1-0.20211117095917-5b0ff29f3084/go.mod h1:z/PmNnDPqSQALedKJv5T8+eXIq6XHa9J0St1YsvAVns=
|
||||
github.com/cgrates/cron v0.0.0-20201022095836-3522d5b72c70 h1:/O+Dr12jcizDiCoIG2oK6wyE1pNRVQc62Wz+TfPWDhU=
|
||||
github.com/cgrates/cron v0.0.0-20201022095836-3522d5b72c70/go.mod h1:I9cUDn/uzkakr0hmYTjXkQqf6wagg44L2p01gSYRRz0=
|
||||
github.com/cgrates/fsock v0.0.0-20191107070144-e7a331109df7 h1:dxtBWRAr62vRRKkExmJZ0u1EbCw/y0vOkSfdFND5qXw=
|
||||
|
||||
@@ -92,7 +92,7 @@ func (m *Migrator) migrateCurrentStats() (err error) {
|
||||
if err := m.dmIN.DataManager().RemoveStatQueueProfile(context.TODO(), tntID[0], tntID[1], false); err != nil {
|
||||
return err
|
||||
}
|
||||
m.stats[utils.StatS]++
|
||||
m.stats[utils.Stats]++
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -141,7 +141,7 @@ func (m *Migrator) migrateV2Stats(v2Stats *engine.StatQueue) (v3Stats *engine.St
|
||||
func (m *Migrator) migrateStats() (err error) {
|
||||
var vrs engine.Versions
|
||||
current := engine.CurrentDataDBVersions()
|
||||
if vrs, err = m.getVersions(utils.StatS); err != nil {
|
||||
if vrs, err = m.getVersions(utils.Stats); err != nil {
|
||||
return
|
||||
}
|
||||
migrated := true
|
||||
@@ -151,12 +151,12 @@ func (m *Migrator) migrateStats() (err error) {
|
||||
var v2Stats *engine.StatQueue
|
||||
var v3Stats *engine.StatQueue
|
||||
for {
|
||||
version := vrs[utils.StatS]
|
||||
version := vrs[utils.Stats]
|
||||
for {
|
||||
switch version {
|
||||
default:
|
||||
return fmt.Errorf("Unsupported version %v", version)
|
||||
case current[utils.StatS]:
|
||||
case current[utils.Stats]:
|
||||
migrated = false
|
||||
if m.sameDataDB {
|
||||
break
|
||||
@@ -187,7 +187,7 @@ func (m *Migrator) migrateStats() (err error) {
|
||||
}
|
||||
version = 4
|
||||
}
|
||||
if version == current[utils.StatS] || err == utils.ErrNoMoreData {
|
||||
if version == current[utils.Stats] || err == utils.ErrNoMoreData {
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -195,7 +195,7 @@ func (m *Migrator) migrateStats() (err error) {
|
||||
break
|
||||
}
|
||||
if !m.dryRun {
|
||||
if vrs[utils.StatS] == 1 {
|
||||
if vrs[utils.Stats] == 1 {
|
||||
if err = m.dmOut.DataManager().SetFilter(context.TODO(), filter, true); err != nil {
|
||||
return
|
||||
}
|
||||
@@ -210,7 +210,7 @@ func (m *Migrator) migrateStats() (err error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
m.stats[utils.StatS]++
|
||||
m.stats[utils.Stats]++
|
||||
}
|
||||
if m.dryRun || !migrated {
|
||||
return nil
|
||||
@@ -218,7 +218,7 @@ func (m *Migrator) migrateStats() (err error) {
|
||||
// call the remove function here
|
||||
|
||||
// All done, update version wtih current one
|
||||
if err = m.setVersions(utils.StatS); err != nil {
|
||||
if err = m.setVersions(utils.Stats); err != nil {
|
||||
return err
|
||||
}
|
||||
return m.ensureIndexesDataDB(engine.ColSqs)
|
||||
|
||||
@@ -376,7 +376,7 @@ func testStsITMigrateFromv1(t *testing.T) {
|
||||
t.Error("Error when setting v1Stat ", err.Error())
|
||||
}
|
||||
|
||||
if err := stsMigrator.dmIN.DataManager().DataDB().SetVersions(engine.Versions{utils.StatS: 1}, true); err != nil {
|
||||
if err := stsMigrator.dmIN.DataManager().DataDB().SetVersions(engine.Versions{utils.Stats: 1}, true); err != nil {
|
||||
t.Errorf("error: <%s> when updating Stats version into dataDB", err.Error())
|
||||
}
|
||||
|
||||
@@ -384,10 +384,10 @@ func testStsITMigrateFromv1(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if vrs, err := stsMigrator.dmOut.DataManager().DataDB().GetVersions(utils.StatS); err != nil {
|
||||
if vrs, err := stsMigrator.dmOut.DataManager().DataDB().GetVersions(utils.Stats); err != nil {
|
||||
t.Errorf("error: <%s> when updating Stats version into dataDB", err.Error())
|
||||
} else if vrs[utils.StatS] != 4 {
|
||||
t.Errorf("Expecting: 4, received: %+v", vrs[utils.StatS])
|
||||
} else if vrs[utils.Stats] != 4 {
|
||||
t.Errorf("Expecting: 4, received: %+v", vrs[utils.Stats])
|
||||
}
|
||||
|
||||
//from V1 to V2
|
||||
|
||||
@@ -163,7 +163,7 @@ func TestDataDBReloadBadType(t *testing.T) {
|
||||
}()
|
||||
|
||||
err = dbConn.SetVersions(engine.Versions{
|
||||
utils.StatS: 4,
|
||||
utils.Stats: 4,
|
||||
utils.Accounts: 3,
|
||||
utils.Actions: 2,
|
||||
utils.Thresholds: 4,
|
||||
@@ -309,7 +309,7 @@ func TestDataDBStartVersion(t *testing.T) {
|
||||
dbConn.Close()
|
||||
}()
|
||||
err = dbConn.SetVersions(engine.Versions{
|
||||
utils.StatS: 4,
|
||||
utils.Stats: 4,
|
||||
utils.Accounts: 3,
|
||||
utils.Actions: 2,
|
||||
utils.Thresholds: 4,
|
||||
@@ -363,7 +363,7 @@ func TestDataDBReloadCastError(t *testing.T) {
|
||||
}()
|
||||
|
||||
err = dbConn.SetVersions(engine.Versions{
|
||||
utils.StatS: 4,
|
||||
utils.Stats: 4,
|
||||
utils.Accounts: 3,
|
||||
utils.Actions: 2,
|
||||
utils.Thresholds: 4,
|
||||
|
||||
@@ -434,7 +434,7 @@ const (
|
||||
Attributes = "Attributes"
|
||||
Chargers = "Chargers"
|
||||
Dispatchers = "Dispatchers"
|
||||
StatS = "Stats"
|
||||
StatS = "StatS"
|
||||
LoadIDsVrs = "LoadIDs"
|
||||
GlobalVarS = "GlobalVarS"
|
||||
CostSource = "CostSource"
|
||||
|
||||
Reference in New Issue
Block a user