diff --git a/utils/apitpdata.go b/utils/apitpdata.go index 49f0aba4c..dddeeea21 100755 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -456,83 +456,6 @@ type AttrGetAccountsCount struct { Tenant string } -type AttrExpFileCdrs struct { - CdrFormat *string // Cdr output file format - FieldSeparator *string // Separator used between fields - ExportId *string // Optional exportid - ExportDir *string // If provided it overwrites the configured export directory - ExportFileName *string // If provided the output filename will be set to this - ExportTemplate *string // Exported fields template <""|fld1,fld2|*xml:instance_name> - CgrIds []string // If provided, it will filter based on the cgrids present in list - MediationRunIds []string // If provided, it will filter on mediation runid - TORs []string // If provided, filter on TypeOfRecord - CdrHosts []string // If provided, it will filter cdrhost - CdrSources []string // If provided, it will filter cdrsource - ReqTypes []string // If provided, it will fiter reqtype - Tenants []string // If provided, it will filter tenant - Categories []string // If provided, it will filter çategory - Accounts []string // If provided, it will filter account - Subjects []string // If provided, it will filter the rating subject - DestinationPrefixes []string // If provided, it will filter on destination prefix - OrderIdStart *int64 // Export from this order identifier - OrderIdEnd *int64 // Export smaller than this order identifier - TimeStart string // If provided, it will represent the starting of the CDRs interval (>=) - TimeEnd string // If provided, it will represent the end of the CDRs interval (<) - SkipErrors bool // Do not export errored CDRs - SkipRated bool // Do not export rated CDRs - SuppressCgrIds bool // Disable CgrIds reporting in reply/ExportedCgrIds and reply/UnexportedCgrIds - Paginator -} - -func (aefc *AttrExpFileCdrs) AsCDRsFilter(timezone string) (*CDRsFilter, error) { - cdrFltr := &CDRsFilter{ - CGRIDs: aefc.CgrIds, - RunIDs: aefc.MediationRunIds, - ToRs: aefc.TORs, - OriginHosts: aefc.CdrHosts, - Sources: aefc.CdrSources, - RequestTypes: aefc.ReqTypes, - Tenants: aefc.Tenants, - Categories: aefc.Categories, - Accounts: aefc.Accounts, - Subjects: aefc.Subjects, - DestinationPrefixes: aefc.DestinationPrefixes, - OrderIDStart: aefc.OrderIdStart, - OrderIDEnd: aefc.OrderIdEnd, - Paginator: aefc.Paginator, - } - if len(aefc.TimeStart) != 0 { - if answerTimeStart, err := ParseTimeDetectLayout(aefc.TimeStart, timezone); err != nil { - return nil, err - } else { - cdrFltr.AnswerTimeStart = &answerTimeStart - } - } - if len(aefc.TimeEnd) != 0 { - if answerTimeEnd, err := ParseTimeDetectLayout(aefc.TimeEnd, timezone); err != nil { - return nil, err - } else { - cdrFltr.AnswerTimeEnd = &answerTimeEnd - } - } - if aefc.SkipRated { - cdrFltr.MaxCost = Float64Pointer(-1.0) - } else if aefc.SkipErrors { - cdrFltr.MinCost = Float64Pointer(0.0) - cdrFltr.MaxCost = Float64Pointer(-1.0) - } - return cdrFltr, nil -} - -type ExportedFileCdrs struct { - ExportedFilePath string // Full path to the newly generated export file - TotalRecords int // Number of CDRs to be exported - TotalCost float64 // Sum of all costs in exported CDRs - FirstOrderId, LastOrderId int64 // The order id of the last exported CDR - ExportedCgrIds []string // List of successfuly exported cgrids in the file - UnexportedCgrIds map[string]string // Map of errored CDRs, map key is cgrid, value will be the error string -} - type AttrGetCdrs struct { CgrIds []string // If provided, it will filter based on the cgrids present in list MediationRunIds []string // If provided, it will filter on mediation runid diff --git a/utils/apitpdata_test.go b/utils/apitpdata_test.go index c11f7df11..45f0f231f 100644 --- a/utils/apitpdata_test.go +++ b/utils/apitpdata_test.go @@ -368,85 +368,6 @@ func TestTPAccountActionsKeyId(t *testing.T) { } -func TestAttrExpFileCdrsAsCDRsFilter(t *testing.T) { - attrExpFileCdrs := &AttrExpFileCdrs{ - TimeStart: "2020-04-04T11:45:26.371Z", - TimeEnd: "2020-04-04T11:46:26.371Z", - SkipRated: true, - CgrIds: []string{"CGRID"}, - TORs: []string{VOICE}, - Accounts: []string{"1001"}, - Subjects: []string{"1001"}, - } - eOut := &CDRsFilter{ - CGRIDs: attrExpFileCdrs.CgrIds, - RunIDs: attrExpFileCdrs.MediationRunIds, - ToRs: attrExpFileCdrs.TORs, - OriginHosts: attrExpFileCdrs.CdrHosts, - Sources: attrExpFileCdrs.CdrSources, - RequestTypes: attrExpFileCdrs.ReqTypes, - Tenants: attrExpFileCdrs.Tenants, - Categories: attrExpFileCdrs.Categories, - Accounts: attrExpFileCdrs.Accounts, - Subjects: attrExpFileCdrs.Subjects, - DestinationPrefixes: attrExpFileCdrs.DestinationPrefixes, - OrderIDStart: attrExpFileCdrs.OrderIdStart, - OrderIDEnd: attrExpFileCdrs.OrderIdEnd, - Paginator: attrExpFileCdrs.Paginator, - MaxCost: Float64Pointer(-1.0), - } - //check with wrong time-zone - rcv, err := attrExpFileCdrs.AsCDRsFilter("wrongtimezone") - if err == nil { - t.Errorf("ParseTimeDetectLayout error") - } - //check with wrong TimeStart - attrExpFileCdrs.TimeStart = "wrongtimeStart" - rcv, err = attrExpFileCdrs.AsCDRsFilter("") - if err == nil { - t.Errorf("Wrong AnswerTimeStart not processed") - } - //check with wrong TimeEnd - attrExpFileCdrs.TimeStart = "2020-04-04T11:45:26.371Z" - attrExpFileCdrs.TimeEnd = "wrongtimeEnd" - rcv, err = attrExpFileCdrs.AsCDRsFilter("") - if err == nil { - t.Errorf("Wrong AnswerTimeEnd not processed") - } - - //check with SkipRated = true & normal timeStar/timeEnd - attrExpFileCdrs.TimeStart = "2020-04-04T11:45:26.371Z" - attrExpFileCdrs.TimeEnd = "2020-04-04T11:46:26.371Z" - - TimeStart, _ := ParseTimeDetectLayout("2020-04-04T11:45:26.371Z", "") - eOut.AnswerTimeStart = &TimeStart - timeEnd, _ := ParseTimeDetectLayout("2020-04-04T11:46:26.371Z", "") - eOut.AnswerTimeEnd = &timeEnd - - rcv, err = attrExpFileCdrs.AsCDRsFilter("") - if err != nil { - t.Errorf("ParseTimeDetectLayout error") - } - - if !reflect.DeepEqual(eOut, rcv) { - t.Errorf("Expected: %s ,received: %s ", ToJSON(eOut), ToJSON(rcv)) - } - - //check with SkipRated = false - attrExpFileCdrs.SkipRated = false - attrExpFileCdrs.SkipErrors = true - eOut.MinCost = Float64Pointer(0.0) - rcv, err = attrExpFileCdrs.AsCDRsFilter("") - - if err != nil { - t.Errorf("ParseTimeDetectLayout error") - } - - if !reflect.DeepEqual(eOut, rcv) { - t.Errorf("Expected: %s ,received: %s ", ToJSON(eOut), ToJSON(rcv)) - } -} - //now working here func TestAttrGetCdrsAsCDRsFilter(t *testing.T) { attrGetCdrs := &AttrGetCdrs{ diff --git a/utils/coreutils.go b/utils/coreutils.go index aca31fa8d..3d03e964c 100644 --- a/utils/coreutils.go +++ b/utils/coreutils.go @@ -31,7 +31,6 @@ import ( "errors" "fmt" "io" - "log" "math" math_rand "math/rand" "os" @@ -134,10 +133,7 @@ func Sha1(attrs ...string) string { // helper function for uuid generation func GenUUID() string { b := make([]byte, 16) - _, err := io.ReadFull(rand.Reader, b) - if err != nil { - log.Fatal(err) - } + io.ReadFull(rand.Reader, b) b[6] = (b[6] & 0x0F) | 0x40 b[8] = (b[8] &^ 0x40) | 0x80 return fmt.Sprintf("%x-%x-%x-%x-%x", b[:4], b[4:6], b[6:8], b[8:10], @@ -565,35 +561,6 @@ func FmtFieldWidth(fieldID, source string, width int, strip, padding string, man return source, nil } -// Returns the string representation of iface or error if not convertible -func CastIfToString(iface interface{}) (strVal string, casts bool) { - switch iface.(type) { - case string: - strVal = iface.(string) - casts = true - case int: - strVal = strconv.Itoa(iface.(int)) - casts = true - case int64: - strVal = strconv.FormatInt(iface.(int64), 10) - casts = true - case float64: - strVal = strconv.FormatFloat(iface.(float64), 'f', -1, 64) - casts = true - case bool: - strVal = strconv.FormatBool(iface.(bool)) - casts = true - case []uint8: - var byteVal []byte - if byteVal, casts = iface.([]byte); casts { - strVal = string(byteVal) - } - default: // Maybe we are lucky and the value converts to string - strVal, casts = iface.(string) - } - return strVal, casts -} - func GetEndOfMonth(ref time.Time) time.Time { if ref.IsZero() { return time.Now() @@ -688,13 +655,6 @@ func (slc Int64Slice) Less(i, j int) bool { return slc[i] < slc[j] } -// CapitalizeErrorMessage returns the capitalized version of an error, useful in APIs -func CapitalizedMessage(errMessage string) (capStr string) { - capStr = strings.ToUpper(errMessage) - capStr = strings.Replace(capStr, " ", "_", -1) - return -} - func GetCGRVersion() (vers string, err error) { vers = fmt.Sprintf("%s@%s", CGRateS, VERSION) if GitLastLog == "" { diff --git a/utils/coreutils_test.go b/utils/coreutils_test.go index 9d1e89dd6..e61e25598 100644 --- a/utils/coreutils_test.go +++ b/utils/coreutils_test.go @@ -852,51 +852,6 @@ func TestFmtFieldWidth(t *testing.T) { } } -func TestCastIfToString(t *testing.T) { - v := interface{}("somestr") - if sOut, casts := CastIfToString(v); !casts { - t.Error("Does not cast") - } else if sOut != "somestr" { - t.Errorf("Received: %+v", sOut) - } - v = interface{}(1) - if sOut, casts := CastIfToString(v); !casts { - t.Error("Does not cast") - } else if sOut != "1" { - t.Errorf("Received: %+v", sOut) - } - v = interface{}((int64)(1)) - if sOut, casts := CastIfToString(v); !casts { - t.Error("Does not cast") - } else if sOut != "1" { - t.Errorf("Received: %+v", sOut) - } - v = interface{}(true) - if sOut, casts := CastIfToString(v); !casts { - t.Error("Does not cast") - } else if sOut != "true" { - t.Errorf("Received: %+v", sOut) - } - v = interface{}([]byte("test")) - if sOut, casts := CastIfToString(v); !casts { - t.Error("Does not cast") - } else if sOut != "test" { - t.Errorf("Received: %+v", sOut) - } - v = interface{}(1.2) - if sOut, casts := CastIfToString(v); !casts { - t.Error("Does not cast") - } else if sOut != "1.2" { - t.Errorf("Received: %+v", sOut) - } - //default - v = interface{}([]string{"test"}) - if _, casts := CastIfToString(v); casts { - t.Error("Does cast") - } - -} - func TestEndOfMonth(t *testing.T) { eom := GetEndOfMonth(time.Date(2016, time.February, 5, 10, 1, 2, 3, time.UTC)) expected := time.Date(2016, time.February, 29, 23, 59, 59, 0, time.UTC) @@ -1197,12 +1152,6 @@ func TestLess(t *testing.T) { } } -func TestCapitalizedMessage(t *testing.T) { - if capMsg := CapitalizedMessage(ServiceAlreadyRunning); capMsg != "SERVICE_ALREADY_RUNNING" { - t.Errorf("Received: <%s>", capMsg) - } -} - func TestGetCGRVersion(t *testing.T) { GitLastLog = `commit 73014daa0c1d7edcb532d5fe600b8a20d588cdf8 Author: DanB diff --git a/utils/map.go b/utils/map.go index ef8158751..e5dadd81c 100644 --- a/utils/map.go +++ b/utils/map.go @@ -23,46 +23,6 @@ import ( "strings" ) -// Converts map[string]string into map[string]interface{} -func ConvertMapValStrIf(inMap map[string]string) map[string]interface{} { - outMap := make(map[string]interface{}) - for field, val := range inMap { - outMap[field] = val - } - return outMap -} - -// Mirrors key/val -func MirrorMap(mapIn map[string]string) map[string]string { - mapOut := make(map[string]string, len(mapIn)) - for key, val := range mapIn { - mapOut[val] = key - } - return mapOut -} - -// Returns mising keys in a map -func MissingMapKeys(inMap map[string]string, requiredKeys []string) []string { - missingKeys := []string{} - for _, reqKey := range requiredKeys { - if val, hasKey := inMap[reqKey]; !hasKey || val == EmptyString { - missingKeys = append(missingKeys, reqKey) - } - } - return missingKeys -} - -// Return map keys -func MapKeys(m map[string]string) []string { - n := make([]string, len(m)) - i := 0 - for k := range m { - n[i] = k - i++ - } - return n -} - type StringMap map[string]bool func NewStringMap(s ...string) StringMap { @@ -173,21 +133,6 @@ func (sm StringMap) HasKey(key string) (has bool) { return } -// Used to merge multiple maps (eg: output of struct having ExtraFields) -func MergeMapsStringIface(mps ...map[string]interface{}) (outMp map[string]interface{}) { - outMp = make(map[string]interface{}) - for i, mp := range mps { - if i == 0 { - outMp = mp - continue - } - for k, v := range mp { - outMp[k] = v - } - } - return -} - func MapStringToInt64(in map[string]string) (out map[string]int64, err error) { mapout := make(map[string]int64, len(in)) for key, val := range in { diff --git a/utils/map_test.go b/utils/map_test.go index 6a4cbd621..80e349aea 100644 --- a/utils/map_test.go +++ b/utils/map_test.go @@ -23,85 +23,6 @@ import ( "testing" ) -func TestConvertMapValStrIf(t *testing.T) { - var mapIn map[string]string - var mapOut map[string]interface{} - if rcv := ConvertMapValStrIf(mapIn); reflect.TypeOf(rcv) != reflect.TypeOf(mapOut) { - t.Errorf("Expecting: %+v, received: %+v", reflect.TypeOf(mapOut), reflect.TypeOf(rcv)) - } - mapIn = map[string]string{"test1": "_test1_", "test2": "_test2_"} - if rcv := ConvertMapValStrIf(mapIn); reflect.TypeOf(rcv) != reflect.TypeOf(mapOut) { - t.Errorf("Expecting: %+v, received: %+v", reflect.TypeOf(mapOut), reflect.TypeOf(rcv)) - } else if !reflect.DeepEqual(mapIn["test1"], rcv["test1"]) { - t.Errorf("Expecting: %+v, received: %+v", mapIn["test1"], rcv["test1"]) - } else if len(rcv) != len(mapIn) { - t.Errorf("Expecting: %+v, received: %+v", len(mapIn), len(rcv)) - } -} - -func TestMirrorMap(t *testing.T) { - var mapIn map[string]string - if rcv := MirrorMap(mapIn); reflect.DeepEqual(rcv, mapIn) { - t.Errorf("Expecting: %+v, received: %+v", reflect.TypeOf(mapIn), reflect.TypeOf(rcv)) - } else if len(rcv) != 0 { - t.Errorf("Expecting: %+v, received: %+v", 0, len(rcv)) - } - mapIn = map[string]string{"test1": "_test1_", "test2": "_test2_"} - eOut := map[string]string{"_test1_": "test1", "_test2_": "test2"} - if rcv := MirrorMap(mapIn); reflect.DeepEqual(rcv, mapIn) { - t.Errorf("Expecting: %+v, received: %+v", reflect.TypeOf(mapIn), reflect.TypeOf(rcv)) - } else if !reflect.DeepEqual(eOut, rcv) { - t.Errorf("Expecting: %+v, received: %+v", eOut, rcv) - } -} - -func TestMissingMapKeys(t *testing.T) { - mapIn := map[string]string{} - requiredKeys := []string{} - if rcv := MissingMapKeys(mapIn, requiredKeys); len(rcv) != 0 { - t.Errorf("Expecting: %+v, received: %+v", 0, len(rcv)) - } - - mapIn = map[string]string{"test1": "_test1_", "test2": "_test2_"} - requiredKeys = []string{"test1", "test2"} - if rcv := MissingMapKeys(mapIn, requiredKeys); len(rcv) != 0 { - t.Errorf("Expecting: %+v, received: %+v", 0, len(rcv)) - } - - mapIn = map[string]string{"test1": "_test1_", "test2": "_test2_"} - requiredKeys = []string{"test2", "test3"} - if rcv := MissingMapKeys(mapIn, requiredKeys); len(rcv) != 1 { - t.Errorf("Expecting: %+v, received: %+v", 1, len(rcv)) - } else if !reflect.DeepEqual([]string{"test3"}, rcv) { - t.Errorf("Expecting: %+v, received: %+v", []string{"test3"}, rcv) - } - - requiredKeys = []string{"test3", "test4"} - eOut := []string{"test3", "test4"} - if rcv := MissingMapKeys(mapIn, requiredKeys); len(rcv) != 2 { - t.Errorf("Expecting: %+v, received: %+v", 2, len(rcv)) - } else if !reflect.DeepEqual(eOut, rcv) { - t.Errorf("Expecting: %+v, received: %+v", eOut, rcv) - } -} - -func TestMapKeys(t *testing.T) { - mapIn := map[string]string{"test1": "_test1_", "test2": "_test2_"} - eOut := []string{"test1", "test2"} - rcv := MapKeys(mapIn) - sort.Slice(rcv, func(i, j int) bool { return rcv[i] < rcv[j] }) - if !reflect.DeepEqual(eOut, rcv) { - t.Errorf("Expecting: %+v, received: %+v", eOut, rcv) - } - mapIn = map[string]string{"test1": "_test1_", "test2": "_test2_", "test3": "_test3_", "test4": "_test4_"} - eOut = []string{"test1", "test2", "test3", "test4"} - rcv = MapKeys(mapIn) - sort.Slice(rcv, func(i, j int) bool { return rcv[i] < rcv[j] }) - if !reflect.DeepEqual(eOut, rcv) { - t.Errorf("Expecting: %+v, received: %+v", eOut, rcv) - } -} - func TestMapKeysStringMapParse(t *testing.T) { if sm := ParseStringMap(EmptyString); len(sm) != 0 { t.Errorf("Expecting %+v, received %+v", 0, len(sm)) @@ -133,27 +54,6 @@ func TestMapKeysStringMapParse(t *testing.T) { } } -func TestMapMergeMapsStringIface(t *testing.T) { - mp1 := map[string]interface{}{ - "Hdr1": "Val1", - "Hdr2": "Val2", - "Hdr3": "Val3", - } - mp2 := map[string]interface{}{ - "Hdr3": "Val4", - "Hdr4": "Val4", - } - eMergedMap := map[string]interface{}{ - "Hdr1": "Val1", - "Hdr2": "Val2", - "Hdr3": "Val4", - "Hdr4": "Val4", - } - if mergedMap := MergeMapsStringIface(mp1, mp2); !reflect.DeepEqual(eMergedMap, mergedMap) { - t.Errorf("Expecting: %+v, received: %+v", eMergedMap, mergedMap) - } -} - func TestEqual(t *testing.T) { t1 := NewStringMap("val1") t2 := NewStringMap("val2") diff --git a/utils/net_test.go b/utils/net_test.go index 93aaa1382..77496beb8 100644 --- a/utils/net_test.go +++ b/utils/net_test.go @@ -94,3 +94,19 @@ func TestDecodeServerRequest(t *testing.T) { t.Errorf("Expecting: %+v, received: %+v", err, rcvErr) } } + +func TestWriteServerResponse(t *testing.T) { + writer := bytes.NewBufferString(EmptyString) + var id *json.RawMessage + var result interface{} = "OK" + var errMessage interface{} + slsByte := []byte("10") + id = (*json.RawMessage)(&slsByte) + + if err := WriteServerResponse(writer, id, result, errMessage); err != nil { + t.Errorf("Expecting: , received: <%+v>", err) + } + if writer.String() != "{\"id\":10,\"result\":\"OK\",\"error\":null}\n" { + t.Errorf("Expecting: <{\"id\":10,\"result\":\"OK\",\"error\":null}>, received: <%+v>", writer.String()) + } +} diff --git a/utils/reflect.go b/utils/reflect.go index 09dc55a01..164912a8e 100644 --- a/utils/reflect.go +++ b/utils/reflect.go @@ -360,23 +360,6 @@ func IfaceAsSliceString(fld interface{}) (out []string, err error) { return } -// AsMapStringIface converts an item (mostly struct) as map[string]interface{} -func AsMapStringIface(item interface{}) (map[string]interface{}, error) { - out := make(map[string]interface{}) - v := reflect.ValueOf(item) - if v.Kind() == reflect.Ptr { - v = v.Elem() - } - if v.Kind() != reflect.Struct { // Only structs for now - return nil, fmt.Errorf("AsMapStringIface only accepts structs; got %T", v) - } - typ := v.Type() - for i := 0; i < v.NumField(); i++ { - out[typ.Field(i).Name] = v.Field(i).Interface() - } - return out, nil -} - func GetUniformType(item interface{}) (interface{}, error) { valItm := reflect.ValueOf(item) switch valItm.Kind() { // convert evreting to float64 diff --git a/utils/reflect_test.go b/utils/reflect_test.go index b89f42859..9b637b2d8 100644 --- a/utils/reflect_test.go +++ b/utils/reflect_test.go @@ -121,28 +121,6 @@ func TestReflectFieldAsStringOnMap(t *testing.T) { } } -func TestReflectAsMapStringIface(t *testing.T) { - mystruct := struct { - Title string - Count int - Count64 int64 - Val float64 - ExtraFields map[string]interface{} - }{"Title1", 5, 6, 7.3, map[string]interface{}{"a": "Title2", "b": 15, "c": int64(16), "d": 17.3}} - expectOutMp := map[string]interface{}{ - "Title": "Title1", - "Count": 5, - "Count64": int64(6), - "Val": 7.3, - "ExtraFields": map[string]interface{}{"a": "Title2", "b": 15, "c": int64(16), "d": 17.3}, - } - if outMp, err := AsMapStringIface(mystruct); err != nil { - t.Error(err) - } else if !reflect.DeepEqual(expectOutMp, outMp) { - t.Errorf("Expecting: %+v, received: %+v", expectOutMp, outMp) - } -} - func TestGreaterThan(t *testing.T) { if gte, err := GreaterThan(1, 1.2, false); err != nil { t.Error(err) diff --git a/utils/slice.go b/utils/slice.go index 229783bb8..cdc716bb4 100644 --- a/utils/slice.go +++ b/utils/slice.go @@ -36,46 +36,6 @@ func SliceHasMember(ss []string, s string) bool { return i < len(ss) && ss[i] == s } -// SliceWithoutMember removes s string from slice ss (if found) -func SliceWithoutMember(ss []string, s string) []string { - sort.Strings(ss) - if i := sort.SearchStrings(ss, s); i < len(ss) && ss[i] == s { - ss[i], ss = ss[len(ss)-1], ss[:len(ss)-1] - } - return ss -} - -// Iterates over slice members and returns true if one starts with prefix -func SliceMemberHasPrefix(ss []string, prfx string) bool { - for _, mbr := range ss { - if strings.HasPrefix(mbr, prfx) { - return true - } - } - return false -} - -// Avg returns the average of a float64 slice -func Avg(values []float64) float64 { - if len(values) == 0 { - return 0.0 - } - var sum float64 - for _, val := range values { - sum += val - } - return sum / float64(len(values)) -} - -// AvgNegative returns the average of a float64 slice -// if is called with an empty slice return -1 -func AvgNegative(values []float64) float64 { - if len(values) == 0 { - return -1 // return -1 if no data - } - return Avg(values) -} - // PrefixSliceItems iterates through slice and add a prefix before every element func PrefixSliceItems(slc []string, prfx string) (out []string) { out = make([]string, len(slc)) @@ -85,14 +45,6 @@ func PrefixSliceItems(slc []string, prfx string) (out []string) { return } -// StripSlicePrefix will strip a number of items from the beginning of the slice -func StripSlicePrefix(slc []string, nrItems int) []string { - if len(slc) < nrItems { - return []string{} - } - return slc[nrItems:] -} - // SliceStringToIface converts slice of strings into a slice of interfaces func SliceStringToIface(slc []string) (ifc []interface{}) { ifc = make([]interface{}, len(slc)) diff --git a/utils/slice_test.go b/utils/slice_test.go index 42bfd6759..69a0b40eb 100644 --- a/utils/slice_test.go +++ b/utils/slice_test.go @@ -49,29 +49,6 @@ func TestFlaot64SliceHasMember(t *testing.T) { t.Error("Expecting: true, received: false") } } -func TestSliceWithoutMember(t *testing.T) { - rcv := SliceWithoutMember([]string{"1", "2", "3", "4", "5"}, "5") - sort.Strings(rcv) - eOut := []string{"1", "2", "3", "4"} - if !reflect.DeepEqual(eOut, rcv) { - t.Errorf("Expecting: %+v, received: %+v", eOut, rcv) - } - rcv = SliceWithoutMember([]string{"1", "2", "3", "4", "5"}, "6") - sort.Strings(rcv) - eOut = []string{"1", "2", "3", "4", "5"} - if !reflect.DeepEqual(eOut, rcv) { - t.Errorf("Expecting: %+v, received: %+v", eOut, rcv) - } -} - -func TestSliceMemberHasPrefix(t *testing.T) { - if !SliceMemberHasPrefix([]string{"1", "*2", "3", "4", "5"}, "*") { - t.Error("Expecting: true, received: false") - } - if SliceMemberHasPrefix([]string{"1", "2", "3", "4", "5"}, "*") { - t.Error("Expecting: true, received: false") - } -} func TestHasPrefixSlice(t *testing.T) { if !HasPrefixSlice([]string{"1", "2", "3", "4", "5"}, "123") { @@ -82,30 +59,6 @@ func TestHasPrefixSlice(t *testing.T) { } } -func TestAvg(t *testing.T) { - if rcv := Avg([]float64{}); rcv != 0 { - t.Errorf("Expecting: 0, received: %+v", rcv) - } - if rcv := Avg([]float64{1, 2, 3}); rcv != 2 { - t.Errorf("Expecting: 2, received: %+v", rcv) - } - if rcv := Avg([]float64{1.5, 2.75, 3.25}); rcv != 2.5 { - t.Errorf("Expecting: 2.5, received: %+v", rcv) - } -} - -func TestAvgNegative(t *testing.T) { - if rcv := AvgNegative([]float64{}); rcv != -1 { - t.Errorf("Expecting: -1, received: %+v", rcv) - } - if rcv := AvgNegative([]float64{1, 2, 3}); rcv != 2 { - t.Errorf("Expecting: 2, received: %+v", rcv) - } - if rcv := Avg([]float64{1.5, 2.75, 3.25}); rcv != 2.5 { - t.Errorf("Expecting: 2.5, received: %+v", rcv) - } -} - func TestPrefixSliceItems(t *testing.T) { rcv := PrefixSliceItems([]string{"1", "2", "3", "4", "5"}, "*") sort.Strings(rcv) @@ -115,21 +68,6 @@ func TestPrefixSliceItems(t *testing.T) { } } -func TestStripSlicePrefix(t *testing.T) { - eSlc := make([]string, 0) - if retSlc := StripSlicePrefix([]string{}, 2); !reflect.DeepEqual(eSlc, retSlc) { - t.Errorf("expecting: %+v, received: %+v", eSlc, retSlc) - } - eSlc = []string{"1", "2"} - if retSlc := StripSlicePrefix([]string{"0", "1", "2"}, 1); !reflect.DeepEqual(eSlc, retSlc) { - t.Errorf("expecting: %+v, received: %+v", eSlc, retSlc) - } - eSlc = []string{} - if retSlc := StripSlicePrefix([]string{"0", "1", "2"}, 3); !reflect.DeepEqual(eSlc, retSlc) { - t.Errorf("expecting: %+v, received: %+v", eSlc, retSlc) - } -} - func TestSliceStringToIface(t *testing.T) { exp := []interface{}{"*default", "ToR", "*voice"} if rply := SliceStringToIface([]string{"*default", "ToR", "*voice"}); !reflect.DeepEqual(exp, rply) { diff --git a/utils/struct.go b/utils/struct.go index fc721476b..990a3ac1a 100644 --- a/utils/struct.go +++ b/utils/struct.go @@ -19,10 +19,8 @@ along with this program. If not, see package utils import ( - "errors" "fmt" "reflect" - "strconv" "strings" ) @@ -44,30 +42,6 @@ func MissingStructFields(s interface{}, mandatories []string) []string { return missing } -// Detects nonempty struct fields, s should be a pointer to a struct -// Useful to not overwrite db fields with non defined params in api -func NonemptyStructFields(s interface{}) map[string]interface{} { - fields := make(map[string]interface{}) - for i := 0; i < reflect.ValueOf(s).Elem().NumField(); i++ { - fld := reflect.ValueOf(s).Elem().Field(i) - switch fld.Kind() { - case reflect.Bool: - fields[reflect.TypeOf(s).Elem().Field(i).Name] = fld.Bool() - case reflect.Int: - fieldVal := fld.Int() - if fieldVal != 0 { - fields[reflect.TypeOf(s).Elem().Field(i).Name] = fieldVal - } - case reflect.String: - fieldVal := fld.String() - if fieldVal != "" { - fields[reflect.TypeOf(s).Elem().Field(i).Name] = fieldVal - } - } - } - return fields -} - // MissingMapFields detects missing field values based on mandatory field names from a map[string]interface{} func MissingMapFields(s map[string]interface{}, mandatories []string) []string { missing := []string{} @@ -90,158 +64,6 @@ func MissingMapFields(s map[string]interface{}, mandatories []string) []string { return missing } -// Converts a struct to map[string]string -func ToMapStringString(in interface{}) map[string]string { - out := make(map[string]string) - - v := reflect.ValueOf(in) - if v.Kind() == reflect.Ptr { - v = v.Elem() - in = v.Interface() - } - typ := reflect.TypeOf(in) - for i := 0; i < v.NumField(); i++ { - // gets us a StructField - typField := typ.Field(i) - field := v.Field(i) - if field.Kind() == reflect.String { - out[typField.Name] = field.String() - } - } - return out -} - -func GetMapExtraFields(in interface{}, extraFields string) map[string]string { - out := make(map[string]string) - v := reflect.ValueOf(in) - if v.Kind() == reflect.Ptr { - v = v.Elem() - } - field := v.FieldByName(extraFields) - if field.Kind() == reflect.Map { - keys := field.MapKeys() - for _, key := range keys { - out[key.String()] = field.MapIndex(key).String() - } - } - return out -} - -func SetMapExtraFields(in interface{}, values map[string]string, extraFields string) { - v := reflect.ValueOf(in) - if v.Kind() == reflect.Ptr { - v = v.Elem() - } - efField := v.FieldByName(extraFields) - if efField.IsValid() && efField.Kind() == reflect.Map { - keys := efField.MapKeys() - for _, key := range keys { - if efField.MapIndex(key).String() != "" { - if val, found := values[key.String()]; found { - efField.SetMapIndex(key, reflect.ValueOf(val)) - } - } - } - } - return -} - -func FromMapStringString(m map[string]string, in interface{}) { - v := reflect.ValueOf(in) - if v.Kind() == reflect.Ptr { - v = v.Elem() - } - for fieldName, fieldValue := range m { - field := v.FieldByName(fieldName) - if field.IsValid() { - if field.Kind() == reflect.String { - if field.String() != "" && field.CanSet() { - field.SetString(fieldValue) - } - } - } - } - return -} - -func FromMapStringInterface(m map[string]interface{}, in interface{}) error { - v := reflect.ValueOf(in) - if v.Kind() == reflect.Ptr { - v = v.Elem() - } - for fieldName, fieldValue := range m { - field := v.FieldByName(fieldName) - if field.IsValid() { - if !field.IsValid() || !field.CanSet() { - continue - } - structFieldType := field.Type() - val := reflect.ValueOf(fieldValue) - if structFieldType != val.Type() { - return errors.New("Provided value type didn't match obj field type") - } - field.Set(val) - } - } - return nil -} - -// initial intent was to use it with *cgr_rpc but does not handle slice and structure fields -func FromMapStringInterfaceValue(m map[string]interface{}, v reflect.Value) (interface{}, error) { - if v.Kind() == reflect.Ptr { - v = v.Elem() - } - for fieldName, fieldValue := range m { - field := v.FieldByName(fieldName) - if field.IsValid() { - if !field.IsValid() || !field.CanSet() { - continue - } - val := reflect.ValueOf(fieldValue) - structFieldType := field.Type() - if structFieldType.Kind() == reflect.Ptr { - field.Set(reflect.New(field.Type().Elem())) - field = field.Elem() - } - structFieldType = field.Type() - if structFieldType != val.Type() { - return nil, fmt.Errorf("provided value type didn't match obj field type: %v vs %v (%v vs %v)", structFieldType, val.Type(), structFieldType.Kind(), val.Type().Kind()) - } - field.Set(val) - } - } - return v.Interface(), nil -} - -// Update struct with map fields, returns not matching map keys, s is a struct to be updated -func UpdateStructWithStrMap(s interface{}, m map[string]string) []string { // Not tested and declared and used only here - notMatched := []string{} - for key, val := range m { - fld := reflect.ValueOf(s).Elem().FieldByName(key) - if fld.IsValid() { - switch fld.Kind() { - case reflect.Bool: - if valBool, err := strconv.ParseBool(val); err != nil { - notMatched = append(notMatched, key) - } else { - fld.SetBool(valBool) - } - case reflect.Int: - if valInt, err := strconv.ParseInt(val, 10, 64); err != nil { - notMatched = append(notMatched, key) - } else { - fld.SetInt(valInt) - } - case reflect.String: - fld.SetString(val) - } - } else { - notMatched = append(notMatched, key) - } - } - return notMatched -} - // UpdateStructWithIfaceMap will update struct fields with values coming from map // if map values are not matching the ones in struct convertion is being attempted // ToDo: add here more fields diff --git a/utils/struct_test.go b/utils/struct_test.go index 12587b818..993af8e8b 100644 --- a/utils/struct_test.go +++ b/utils/struct_test.go @@ -36,164 +36,6 @@ func TestMissingStructFieldsCorrect(t *testing.T) { } } -func TestStructMapStruct(t *testing.T) { - type TestStruct struct { - Name string - Surname string - Address string - Other string - } - ts := &TestStruct{ - Name: "1", - Surname: "2", - Address: "3", - Other: "", - } - nts := &TestStruct{ - Name: "1", - Surname: "2", - Address: "3", - Other: "", - } - m := ToMapStringString(ts) - - FromMapStringString(m, ts) - if !reflect.DeepEqual(ts, nts) { - t.Log(m) - t.Errorf("Expected: %+v got: %+v", ts, nts) - } -} - -func TestMapStructAddStructs(t *testing.T) { - type TestStruct struct { - Name string - Surname string - Address string - Other string - } - ts := &TestStruct{ - Name: "1", - Surname: "2", - Address: "3", - Other: "", - } - nts := &TestStruct{ - Name: "1", - Surname: "2", - Address: "3", - Other: "", - } - m := ToMapStringString(ts) - m["Test"] = "4" - FromMapStringString(m, ts) - - if !reflect.DeepEqual(ts, nts) { - t.Log(m) - t.Errorf("Expected: %+v got: %+v", ts, nts) - } -} - -func TestStructExtraFields(t *testing.T) { - ts := struct { - Name string - Surname string - Address string - ExtraFields map[string]string - }{ - Name: "1", - Surname: "2", - Address: "3", - ExtraFields: map[string]string{ - "k1": "v1", - "k2": "v2", - "k3": "v3", - }, - } - efMap := GetMapExtraFields(ts, "ExtraFields") - - if !reflect.DeepEqual(efMap, ts.ExtraFields) { - t.Errorf("expected: %v got: %v", ts.ExtraFields, efMap) - } -} - -func TestSetStructExtraFields(t *testing.T) { - ts := struct { - Name string - Surname string - Address string - ExtraFields map[string]string - }{ - Name: "1", - Surname: "2", - Address: "3", - ExtraFields: make(map[string]string), - } - s := "ExtraFields" - m := map[string]string{ - "k1": "v1", - "k2": "v2", - "k3": "v3", - } - SetMapExtraFields(ts, m, s) - efMap := GetMapExtraFields(ts, "ExtraFields") - if !reflect.DeepEqual(efMap, ts.ExtraFields) { - t.Errorf("expected: %v got: %v", ts.ExtraFields, efMap) - } -} - -func TestStructFromMapStringInterface(t *testing.T) { - ts := &struct { - Name string - Class *string - List []string - Elements struct { - Type string - Value float64 - } - }{} - s := "test2" - m := map[string]interface{}{ - "Name": "test1", - "Class": &s, - "List": []string{"test3", "test4"}, - "Elements": struct { - Type string - Value float64 - }{ - Type: "test5", - Value: 9.8, - }, - } - if err := FromMapStringInterface(m, ts); err != nil { - t.Logf("ts: %+v", ToJSON(ts)) - t.Error("Error converting map to struct: ", err) - } -} - -func TestStructFromMapStringInterfaceValue(t *testing.T) { - type T struct { - Name string - Disabled *bool - Members []string - } - ts := &T{} - vts := reflect.ValueOf(ts) - x, err := FromMapStringInterfaceValue(map[string]interface{}{ - "Name": "test", - "Disabled": true, - "Members": []string{"1", "2", "3"}, - }, vts) - rt := x.(T) - if err != nil { - t.Fatalf("error converting structure value: %v", err) - } - if rt.Name != "test" || - *rt.Disabled != true || - !reflect.DeepEqual(rt.Members, []string{"1", "2", "3"}) { - t.Errorf("error converting structure value: %s", ToIJSON(rt)) - } -} - func TestUpdateStructWithIfaceMap(t *testing.T) { type myStruct struct { String string @@ -236,26 +78,6 @@ func TestUpdateStructWithIfaceMap(t *testing.T) { } } -func TestNonemptyStructFields(t *testing.T) { - var attr = struct { - Tenant string - Direction bool - Account string - Type string - ActionTimingsId string - }{"bevoip.eu", true, "testaccount", META_PREPAID, ""} - mapStruct := NonemptyStructFields(&attr) - expMapStruct := map[string]interface{}{ - "Tenant": "bevoip.eu", - "Direction": true, - "Account": "testaccount", - "Type": META_PREPAID, - } - if !reflect.DeepEqual(expMapStruct, mapStruct) { - t.Errorf("expecting: %+v, received: %+v", expMapStruct, mapStruct) - } -} - func TestMissingMapFields(t *testing.T) { var attr = map[string]interface{}{ Tenant: "cgrates.org",