mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 10:06:24 +05:00
added *gigawords DataConverter
This commit is contained in:
committed by
Dan Christian Bogos
parent
2867be100a
commit
8e89b84e03
@@ -3070,3 +3070,203 @@ func TestCacheRadiusPacket(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestGigawordsCalculateTotalOctets(t *testing.T) { // Renamed for clarity
|
||||
var gigawordMultiplier int64 = 4294967296
|
||||
configTemplate := `
|
||||
{
|
||||
"diameter_agent": {
|
||||
"request_processors": [
|
||||
{
|
||||
"id": "test_proc",
|
||||
"filters": [],
|
||||
"flags": [],
|
||||
"request_fields": [
|
||||
%s
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}`
|
||||
|
||||
inputFieldConfig := `{
|
||||
"tag": "TotalUsageInput",
|
||||
"path": "*cgreq.TotalUsageInput",
|
||||
"type": "*sum",
|
||||
"value": "~*req.Acct-Input-Gigawords{*gigawords};~*req.Acct-Input-Octets"
|
||||
}`
|
||||
outputFieldConfig := `{
|
||||
"tag": "TotalUsageOutput",
|
||||
"path": "*cgreq.TotalUsageOutput",
|
||||
"type": "*sum",
|
||||
"value": "~*req.Acct-Output-Gigawords{*gigawords};~*req.Acct-Output-Octets"
|
||||
}`
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
fieldConfig string
|
||||
inputDP utils.MapStorage
|
||||
expectedValue int64
|
||||
expectErr bool
|
||||
err error
|
||||
}{
|
||||
|
||||
{
|
||||
name: "Input: Zero GW, Zero Octets",
|
||||
fieldConfig: inputFieldConfig,
|
||||
inputDP: utils.MapStorage{
|
||||
"Acct-Input-Gigawords": 0,
|
||||
"Acct-Input-Octets": 0,
|
||||
},
|
||||
expectedValue: 0,
|
||||
},
|
||||
{
|
||||
name: "Input: Zero GW, Some Octets",
|
||||
fieldConfig: inputFieldConfig,
|
||||
inputDP: utils.MapStorage{
|
||||
"Acct-Input-Gigawords": 0,
|
||||
"Acct-Input-Octets": 12345,
|
||||
},
|
||||
expectedValue: 12345,
|
||||
},
|
||||
{
|
||||
name: "Input: Some GW (2), Zero Octets",
|
||||
fieldConfig: inputFieldConfig,
|
||||
inputDP: utils.MapStorage{
|
||||
"Acct-Input-Gigawords": 2,
|
||||
"Acct-Input-Octets": 0,
|
||||
},
|
||||
expectedValue: 2 * gigawordMultiplier,
|
||||
},
|
||||
{
|
||||
name: "Input: Some GW (3), Some Octets (1000)",
|
||||
fieldConfig: inputFieldConfig,
|
||||
inputDP: utils.MapStorage{
|
||||
"Acct-Input-Gigawords": 3,
|
||||
"Acct-Input-Octets": 1000,
|
||||
},
|
||||
expectedValue: (3 * gigawordMultiplier) + 1000,
|
||||
},
|
||||
{
|
||||
name: "Input: Missing GW, Some Octets",
|
||||
fieldConfig: inputFieldConfig,
|
||||
inputDP: utils.MapStorage{
|
||||
"Acct-Input-Octets": 50000,
|
||||
},
|
||||
expectedValue: 0,
|
||||
expectErr: true,
|
||||
err: utils.ErrNotFound,
|
||||
},
|
||||
{
|
||||
name: "Input: Some GW, Missing Octets",
|
||||
fieldConfig: inputFieldConfig,
|
||||
inputDP: utils.MapStorage{
|
||||
"Acct-Input-Gigawords": 1,
|
||||
},
|
||||
expectErr: true,
|
||||
err: utils.ErrNotFound,
|
||||
},
|
||||
{
|
||||
name: "Input: Both GW and Octets Missing",
|
||||
fieldConfig: inputFieldConfig,
|
||||
inputDP: utils.MapStorage{},
|
||||
expectedValue: 0,
|
||||
expectErr: true,
|
||||
err: utils.ErrNotFound,
|
||||
},
|
||||
{
|
||||
name: "Input: GW as String '2', Octets as String '333'",
|
||||
fieldConfig: inputFieldConfig,
|
||||
inputDP: utils.MapStorage{
|
||||
"Acct-Input-Gigawords": "2",
|
||||
"Acct-Input-Octets": "333",
|
||||
},
|
||||
expectedValue: (2 * gigawordMultiplier) + 333,
|
||||
},
|
||||
|
||||
{
|
||||
name: "Output: Zero GW, Zero Octets",
|
||||
fieldConfig: outputFieldConfig,
|
||||
inputDP: utils.MapStorage{
|
||||
"Acct-Output-Gigawords": 0,
|
||||
"Acct-Output-Octets": 0,
|
||||
},
|
||||
expectedValue: 0,
|
||||
},
|
||||
{
|
||||
name: "Output: Zero GW, Some Octets",
|
||||
fieldConfig: outputFieldConfig,
|
||||
inputDP: utils.MapStorage{
|
||||
"Acct-Output-Gigawords": 0,
|
||||
"Acct-Output-Octets": 98765,
|
||||
},
|
||||
expectedValue: 98765,
|
||||
},
|
||||
{
|
||||
name: "Output: Some GW (1), Zero Octets",
|
||||
fieldConfig: outputFieldConfig,
|
||||
inputDP: utils.MapStorage{
|
||||
"Acct-Output-Gigawords": 1,
|
||||
"Acct-Output-Octets": 0,
|
||||
},
|
||||
expectedValue: 1 * gigawordMultiplier,
|
||||
},
|
||||
{
|
||||
name: "Output: Some GW (4), Some Octets (20000)",
|
||||
fieldConfig: outputFieldConfig,
|
||||
inputDP: utils.MapStorage{
|
||||
"Acct-Output-Gigawords": 4,
|
||||
"Acct-Output-Octets": 20000,
|
||||
},
|
||||
expectedValue: (4 * gigawordMultiplier) + 20000,
|
||||
},
|
||||
{
|
||||
name: "Output: Missing GW, Some Octets",
|
||||
fieldConfig: outputFieldConfig,
|
||||
inputDP: utils.MapStorage{
|
||||
"Acct-Output-Octets": 777,
|
||||
},
|
||||
expectedValue: 0,
|
||||
expectErr: true,
|
||||
err: utils.ErrNotFound,
|
||||
},
|
||||
{
|
||||
name: "Output: Some GW, Missing Octets",
|
||||
fieldConfig: outputFieldConfig,
|
||||
inputDP: utils.MapStorage{
|
||||
"Acct-Output-Gigawords": 2,
|
||||
},
|
||||
expectErr: true,
|
||||
err: utils.ErrNotFound,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
fullConf := fmt.Sprintf(configTemplate, tc.fieldConfig)
|
||||
cgrconf, err := config.NewCGRConfigFromJSONStringWithDefaults(fullConf)
|
||||
if err != nil {
|
||||
t.Fatalf("Config parsing failed: %v", err)
|
||||
}
|
||||
agReq := NewAgentRequest(tc.inputDP, nil, nil, nil, nil, nil, "cgrates.org", "", nil, nil)
|
||||
fieldDef := cgrconf.DiameterAgentCfg().RequestProcessors[0].RequestFields[0]
|
||||
out, err := agReq.ParseField(fieldDef)
|
||||
if tc.expectErr {
|
||||
if err == nil || err.Error() != tc.err.Error() {
|
||||
t.Fatalf("Expected error <%v>, but got <%v>", tc.err, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("ParseField failed unexpectedly: %v", err)
|
||||
}
|
||||
resultInt64, ok := out.(int64)
|
||||
if !ok {
|
||||
t.Fatal("ParseField result type is not int64")
|
||||
} else {
|
||||
if resultInt64 != tc.expectedValue {
|
||||
t.Errorf("Expected result %d, but got %d", tc.expectedValue, resultInt64)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1165,6 +1165,7 @@ const (
|
||||
MetaTpDispatchers = "*tp_dispatchers"
|
||||
MetaDurationSeconds = "*duration_seconds"
|
||||
MetaDurationNanoseconds = "*duration_nanoseconds"
|
||||
MetaGigawords = "*gigawords"
|
||||
CapAttributes = "Attributes"
|
||||
CapResourceAllocation = "ResourceAllocation"
|
||||
CapMaxUsage = "MaxUsage"
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/url"
|
||||
@@ -129,6 +130,8 @@ func NewDataConverter(params string) (conv DataConverter, err error) {
|
||||
return NewRandomConverter(params[len(MetaRandom)+1:])
|
||||
case strings.HasPrefix(params, MetaStrip):
|
||||
return NewStripConverter(params)
|
||||
case strings.HasPrefix(params, MetaGigawords):
|
||||
return new(GigawordsConverter), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported converter definition: <%s>", params)
|
||||
}
|
||||
@@ -787,3 +790,15 @@ func (URLEncodeConverter) Convert(in any) (any, error) {
|
||||
}
|
||||
return parsedURL.String(), nil
|
||||
}
|
||||
|
||||
// GigawordsConverter converts a value in Gigawords to octects
|
||||
type GigawordsConverter struct{}
|
||||
|
||||
func (GigawordsConverter) Convert(in any) (any, error) {
|
||||
gigawordsValue, err := IfaceAsInt64(in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
totalOctects := (gigawordsValue * int64(math.Pow(2, 32))) // 2^32
|
||||
return totalOctects, nil
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"math"
|
||||
"net"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -1814,3 +1815,82 @@ func TestStripConverterConvert(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
func TestGigaWordsConverter(t *testing.T) {
|
||||
converter := GigawordsConverter{}
|
||||
multiplier := int64(4294967296)
|
||||
testCases := []struct {
|
||||
name string
|
||||
input any
|
||||
expectedValue int64
|
||||
expectError bool
|
||||
errorContains string
|
||||
}{
|
||||
{
|
||||
name: "Input Zero (int)",
|
||||
input: int(0),
|
||||
expectedValue: 0,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Input Zero (int32)",
|
||||
input: int32(0),
|
||||
expectedValue: 0,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Input One (int)",
|
||||
input: int(1),
|
||||
expectedValue: multiplier,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Input Two (int64)",
|
||||
input: int64(2),
|
||||
expectedValue: 2 * multiplier,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Input Three (string)",
|
||||
input: "3",
|
||||
expectedValue: 3 * multiplier,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Input Nil",
|
||||
input: nil,
|
||||
expectedValue: 0,
|
||||
expectError: true,
|
||||
errorContains: "cannot convert",
|
||||
},
|
||||
{
|
||||
name: "Input Invalid String",
|
||||
input: "abc",
|
||||
expectedValue: 0,
|
||||
expectError: true,
|
||||
errorContains: "strconv.ParseInt: parsing \"abc\": invalid syntax",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
output, err := converter.Convert(tc.input)
|
||||
if tc.expectError {
|
||||
if err == nil || !strings.Contains(err.Error(), tc.errorContains) {
|
||||
t.Errorf("Expected error '%s', but got '%v'", tc.errorContains, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, but got: %v", err)
|
||||
}
|
||||
|
||||
outputInt64, ok := output.(int64)
|
||||
if !ok {
|
||||
t.Fatalf("Expected output type int64, but got %T (%v)", output, output)
|
||||
}
|
||||
if outputInt64 != tc.expectedValue {
|
||||
t.Errorf("Expected output %d, but got %d", tc.expectedValue, outputInt64)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user