Skip to content

Commit

Permalink
Fix pretty_dump output for Nested Grouped AVPs (#188)
Browse files Browse the repository at this point in the history
* small refactor on pretty_dump.go
* add pretty_dump unit tests
* fix tests by using UTC time
  • Loading branch information
lwlee2608 authored Dec 4, 2023
1 parent 845be29 commit f6f1377
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 49 deletions.
76 changes: 29 additions & 47 deletions diam/pretty_dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package diam
import (
"bytes"
"fmt"
"io"
"net"
"strings"
"time"
Expand All @@ -13,16 +14,16 @@ import (
)

func (m *Message) PrettyDump() string {
return prettyDumpWithDepth(m, 0)
}

func prettyDumpWithDepth(m *Message, depth int) string {
var b bytes.Buffer
prettyDumpMessage(&b, m, 0)
return b.String()
}

func prettyDumpMessage(w io.Writer, m *Message, depth int) {
requestFlag, errorFlag, proxyFlag, retransmittedFlag := flagsToString(m.Header)

// Print Header
fmt.Fprintf(&b, "%s(%d) %s(%d) %s%s%s%s %d, %d\n",
fmt.Fprintf(w, "%s(%d) %s(%d) %s%s%s%s %d, %d\n",
cmdToString(m.Dictionary(), m.Header),
m.Header.CommandCode,
appIdToString(int(m.Header.ApplicationID)),
Expand All @@ -35,58 +36,39 @@ func prettyDumpWithDepth(m *Message, depth int) string {
m.Header.EndToEndID)

// Print Titles
fmt.Fprintf(&b, " %-40s %8s %5s %s %s %s %-18s %s\n",
fmt.Fprintf(w, " %-40s %8s %5s %s %s %s %-18s %s\n",
"AVP", "Vendor", "Code", "V", "M", "P", "Type", "Value")

indent := strings.Repeat(" ", max(0, depth))

// Print AVPs
for _, a := range m.AVP {
avpName, avpType, avpData, isGrouped := avpToString(m, a)

// Print AVPs
fmt.Fprintf(&b, " %-40s %8d %5d %s %s %s %-18s %s\n",
indent+avpName,
a.VendorID,
a.Code,
boolToSymbol(a.Flags&avp.Vbit == avp.Vbit),
boolToSymbol(a.Flags&avp.Mbit == avp.Mbit),
boolToSymbol(a.Flags&avp.Pbit == avp.Pbit),
avpType,
avpData)

if isGrouped {
fmt.Fprintf(&b, "%s", groupedAVPToString(m, a, depth+1))
}
prettyDumpAVP(w, m, a, depth)
}

return b.String()
}

func groupedAVPToString(m *Message, a *AVP, depth int) string {
var b bytes.Buffer
func prettyDumpGroupedAVP(w io.Writer, m *Message, a *AVP, depth int) {
for _, ga := range a.Data.(*GroupedAVP).AVP {
prettyDumpAVP(w, m, ga, depth)
}
}

func prettyDumpAVP(w io.Writer, m *Message, a *AVP, depth int) {
indent := strings.Repeat(" ", max(0, depth))

for _, ga := range a.Data.(*GroupedAVP).AVP {
avpName, avpType, avpData, isGrouped := avpToString(m, ga)

// Print Grouped AVPs
fmt.Fprintf(&b, " %-40s %8d %5d %s %s %s %-18s %s\n",
indent+avpName,
ga.VendorID,
ga.Code,
boolToSymbol(a.Flags&avp.Vbit == avp.Vbit),
boolToSymbol(a.Flags&avp.Mbit == avp.Mbit),
boolToSymbol(a.Flags&avp.Pbit == avp.Pbit),
avpType,
avpData)

if isGrouped {
fmt.Fprintf(&b, "%s", groupedAVPToString(m, ga, depth+1))
}
}
avpName, avpType, avpData, isGrouped := avpToString(m, a)

return b.String()
fmt.Fprintf(w, " %-40s %8d %5d %s %s %s %-18s %s\n",
indent+avpName,
a.VendorID,
a.Code,
boolToSymbol(a.Flags&avp.Vbit == avp.Vbit),
boolToSymbol(a.Flags&avp.Mbit == avp.Mbit),
boolToSymbol(a.Flags&avp.Pbit == avp.Pbit),
avpType,
avpData)

if isGrouped {
prettyDumpGroupedAVP(w, m, a, depth+1)
}
}

func cmdToString(dictionary *dict.Parser, header *Header) string {
Expand Down
93 changes: 91 additions & 2 deletions diam/pretty_dump_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package diam

import (
"bytes"
"net"
"strings"
"testing"
"time"
"unicode"

"github.com/fiorix/go-diameter/v4/diam/avp"
"github.com/fiorix/go-diameter/v4/diam/datatype"
Expand Down Expand Up @@ -33,7 +36,7 @@ func TestPrettyDump(t *testing.T) {
NewAVP(avp.PSInformation, avp.Mbit, 10415, &GroupedAVP{
AVP: []*AVP{
NewAVP(avp.CalledStationID, avp.Mbit, 0, datatype.UTF8String("10999")),
NewAVP(avp.StartTime, avp.Mbit, 10415, datatype.Time(time.Unix(1377093974, 0))),
NewAVP(avp.StartTime, 0, 10415, datatype.Time(time.Unix(1377093974, 0))),
},
}),
}})
Expand All @@ -43,6 +46,92 @@ func TestPrettyDump(t *testing.T) {

// New PrettyDump() print
t.Logf("Message:\n%s", msg.PrettyDump())
}

func TestPrettyDumpAVP(t *testing.T) {
tests := []struct {
name string
avp *AVP
expected string
}{
{
name: "Unsigned32",
avp: NewAVP(avp.VendorID, avp.Mbit, 0, datatype.Unsigned32(13)),
expected: " Vendor-Id 0 266 ✗ ✓ ✗ Unsigned32 13",
},
{
name: "UTF8String",
avp: NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String("abc-1234567")),
expected: " Session-Id 0 263 ✗ ✓ ✗ UTF8String abc-1234567",
},
{
name: "Address",
avp: NewAVP(avp.HostIPAddress, avp.Mbit, 0, datatype.Address(net.ParseIP("10.1.0.1"))),
expected: " Host-IP-Address 0 257 ✗ ✓ ✗ Address 10.1.0.1",
},
{
name: "AddressIPv6",
avp: NewAVP(avp.GGSNAddress, avp.Mbit, 10415, datatype.Address(net.ParseIP("2001:0db8::ff00:0042:8329"))),
expected: " GGSN-Address 10415 847 ✓ ✓ ✗ Address 2001:db8::ff00:42:8329",
},
{
name: "Enumerated",
avp: NewAVP(avp.CCRequestType, avp.Mbit, 0, datatype.Enumerated(1)),
expected: " CC-Request-Type 0 416 ✗ ✓ ✗ Enumerated 1",
},
{
name: "GroupedAVP",
avp: NewAVP(avp.MultipleServicesCreditControl, avp.Mbit, 0, &GroupedAVP{
AVP: []*AVP{
NewAVP(avp.ServiceIdentifier, avp.Mbit, 0, datatype.Unsigned32(7786)),
NewAVP(avp.RatingGroup, avp.Mbit, 0, datatype.Unsigned32(7786)),
NewAVP(avp.TGPPRATType, avp.Mbit, 10415, datatype.OctetString("1234")),
},
}),
expected: strings.Join([]string{
" Multiple-Services-Credit-Control 0 456 ✗ ✓ ✗ Grouped",
" Service-Identifier 0 439 ✗ ✓ ✗ Unsigned32 7786",
" Rating-Group 0 432 ✗ ✓ ✗ Unsigned32 7786",
" TGPP-RAT-Type 10415 21 ✓ ✓ ✗ OctetString 1234",
}, "\n"),
},
{
name: "NestedGroupedAVP",
avp: NewAVP(avp.ServiceInformation, avp.Mbit, 10415, &GroupedAVP{
AVP: []*AVP{
NewAVP(avp.PSInformation, avp.Mbit, 10415, &GroupedAVP{
AVP: []*AVP{
NewAVP(avp.CalledStationID, avp.Mbit, 0, datatype.UTF8String("10999")),
NewAVP(avp.StartTime, 0, 10415, datatype.Time(time.Date(2023, 8, 21, 22, 06, 14, 0, time.UTC))),
},
}),
}}),
expected: strings.Join([]string{
" Service-Information 10415 873 ✓ ✓ ✗ Grouped",
" PS-Information 10415 874 ✓ ✓ ✗ Grouped",
" Called-Station-Id 0 30 ✗ ✓ ✗ UTF8String 10999",
" Start-Time 10415 2041 ✓ ✗ ✗ Time 2023-08-21 22:06:14 +0000 UTC",
}, "\n"),
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
msg := NewMessage(CreditControl, RequestFlag, CHARGING_CONTROL_APP_ID, 0xa8cc407d, 0xa8c1b2b4, dict.Default)

var b bytes.Buffer
prettyDumpAVP(&b, msg, tc.avp, 0)

lines := strings.Split(b.String(), "\n")
for i, line := range lines {
lines[i] = strings.TrimRightFunc(line, unicode.IsSpace)
}
actual := strings.Join(lines, "\n")
actual = strings.TrimSuffix(actual, "\n")

// TODO Maybe make PrettyDump() testable and assert the output
if actual != tc.expected {
t.Errorf("\nActual:\n%v\nExpected:\n%v\n", actual, tc.expected)
}
})
}
}

0 comments on commit f6f1377

Please sign in to comment.