sonic ast visitor approach. now we're getting faster.

BenchmarkParseMessage/relay/jsonstdlib-4              206   8630635 ns/op
BenchmarkParseMessage/relay/easyjson-4                278   4311793 ns/op
BenchmarkParseMessage/relay/simdjson-4                422   2943387 ns/op
BenchmarkParseMessage/relay/sonic-4                   849   1576884 ns/op

BenchmarkParseMessage/client/jsonstdlib-4             196   6140585 ns/op
BenchmarkParseMessage/client/easyjson-4               385   2826706 ns/op
BenchmarkParseMessage/client/simdjson-4               405   2628675 ns/op
BenchmarkParseMessage/client/sonic-4                  552   2413731 ns/op
This commit is contained in:
fiatjaf
2025-03-07 09:43:42 -03:00
parent cb74908f5d
commit 39bde22639
3 changed files with 450 additions and 165 deletions

View File

@ -42,10 +42,9 @@ func BenchmarkParseMessage(b *testing.B) {
}) })
b.Run("sonic", func(b *testing.B) { b.Run("sonic", func(b *testing.B) {
smp := SonicMessageParser{}
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
for _, msg := range messages { for _, msg := range messages {
_, _ = smp.ParseMessage(msg) _, _ = ParseMessageSonic(msg)
} }
} }
}) })

View File

@ -2,184 +2,472 @@ package nostr
import ( import (
"encoding/hex" "encoding/hex"
stdlibjson "encoding/json"
"fmt" "fmt"
"github.com/bytedance/sonic/ast" "github.com/bytedance/sonic/ast"
) )
type SonicMessageParser struct{} type sonicParserPosition int
func (smp *SonicMessageParser) ParseMessage(message []byte) (Envelope, error) { const (
var err error inEnvelope sonicParserPosition = iota
tlarr, _ := ast.NewParser(string(message)).Parse() inEvent
label, _ := tlarr.Index(0).StrictString() inReq
inOk
inEose
inCount
inAuth
inClose
inClosed
inNotice
var v Envelope inFilterObject
switch label { inEventObject
case "EVENT": inCountObject
env := &EventEnvelope{}
sndN := tlarr.Index(1) inSince
var evtN *ast.Node inLimit
switch sndN.TypeSafe() { inUntil
case ast.V_STRING: inIds
subId, _ := sndN.StrictString() inAuthors
env.SubscriptionID = &subId inKinds
evtN = tlarr.Index(2) inSearch
case ast.V_OBJECT: inAFilterTag
evtN = sndN
} inId
err = eventFromSonicAst(&env.Event, evtN) inCreatedAt
v = env inKind
case "REQ": inContent
env := &ReqEnvelope{} inPubkey
nodes, _ := tlarr.ArrayUseNode() inSig
env.SubscriptionID, _ = nodes[1].StrictString() inTags
env.Filters = make(Filters, len(nodes)-2) inAnEventTag
for i, node := range nodes[2:] { )
err = filterFromSonicAst(&env.Filters[i], &node)
} func (spp sonicParserPosition) String() string {
v = env switch spp {
case "COUNT": case inEnvelope:
env := &CountEnvelope{} return "inEnvelope"
env.SubscriptionID, _ = tlarr.Index(1).StrictString() case inEvent:
trdN := tlarr.Index(2) return "inEvent"
if countN := trdN.Get("count"); countN.Exists() { case inReq:
count, _ := countN.Int64() return "inReq"
env.Count = &count case inOk:
hll, _ := trdN.Get("hll").StrictString() return "inOk"
if len(hll) == 512 { case inEose:
env.HyperLogLog, _ = hex.DecodeString(hll) return "inEose"
} case inCount:
} else { return "inCount"
err = filterFromSonicAst(&env.Filter, trdN) case inAuth:
} return "inAuth"
v = env case inClose:
case "NOTICE": return "inClose"
notice, _ := tlarr.Index(1).StrictString() case inClosed:
env := NoticeEnvelope(notice) return "inClosed"
v = &env case inNotice:
case "EOSE": return "inNotice"
subId, _ := tlarr.Index(1).StrictString() case inFilterObject:
env := EOSEEnvelope(subId) return "inFilterObject"
v = &env case inEventObject:
case "OK": return "inEventObject"
env := &OKEnvelope{} case inCountObject:
env.EventID, _ = tlarr.Index(1).StrictString() return "inCountObject"
env.OK, _ = tlarr.Index(2).Bool() case inSince:
env.Reason, _ = tlarr.Index(3).StrictString() return "inSince"
v = env case inLimit:
case "AUTH": return "inLimit"
env := &AuthEnvelope{} case inUntil:
sndN := tlarr.Index(1) return "inUntil"
switch sndN.TypeSafe() { case inIds:
case ast.V_STRING: return "inIds"
challenge, _ := sndN.StrictString() case inAuthors:
env.Challenge = &challenge return "inAuthors"
case ast.V_OBJECT: case inKinds:
err = eventFromSonicAst(&env.Event, sndN) return "inKinds"
} case inAFilterTag:
v = env return "inAFilterTag"
case "CLOSED": case inId:
env := &ClosedEnvelope{} return "inId"
env.SubscriptionID, _ = tlarr.Index(1).StrictString() case inCreatedAt:
env.Reason, _ = tlarr.Index(2).StrictString() return "inCreatedAt"
v = env case inKind:
case "CLOSE": return "inKind"
reason, _ := tlarr.Index(1).StrictString() case inContent:
env := CloseEnvelope(reason) return "inContent"
v = &env case inPubkey:
return "inPubkey"
case inSig:
return "inSig"
case inTags:
return "inTags"
case inAnEventTag:
return "inAnEventTag"
default: default:
return nil, UnknownLabel return "<unexpected-spp>"
} }
return v, err
} }
func eventFromSonicAst(evt *Event, node *ast.Node) error { type SonicMessageParser struct {
evt.ID, _ = node.Get("id").StrictString() event *EventEnvelope
evt.PubKey, _ = node.Get("pubkey").StrictString() req *ReqEnvelope
evt.Content, _ = node.Get("content").StrictString() ok *OKEnvelope
evt.Sig, _ = node.Get("sig").StrictString() eose *EOSEEnvelope
kind, _ := node.Get("kind").Int64() count *CountEnvelope
evt.Kind = int(kind) auth *AuthEnvelope
createdAt, _ := node.Get("created_at").Int64() close *CloseEnvelope
evt.CreatedAt = Timestamp(createdAt) closed *ClosedEnvelope
tagsN, err := node.Get("tags").ArrayUseNode() notice *NoticeEnvelope
if err != nil {
return fmt.Errorf("invalid tags: %w", err) whereWeAre sonicParserPosition
currentEvent *Event
currentEventTag Tag
currentFilter *Filter
currentFilterTagList []string
currentFilterTagName string
mainEnvelope Envelope
}
func (smp *SonicMessageParser) OnArrayBegin(capacity int) error {
// fmt.Println("***", "OnArrayBegin", "==", smp.whereWeAre)
switch smp.whereWeAre {
case inTags:
if smp.currentEvent.Tags == nil {
smp.currentEvent.Tags = make(Tags, 0, 10)
smp.currentEventTag = make(Tag, 0, 20)
} else {
smp.whereWeAre = inAnEventTag
}
case inAFilterTag:
// we have already created this
} }
evt.Tags = make(Tags, len(tagsN))
for i, tagN := range tagsN {
itemsN, err := tagN.ArrayUseNode()
if err != nil {
return fmt.Errorf("invalid tag: %w", err)
}
tag := make(Tag, len(itemsN))
for j, itemN := range itemsN { return nil
tag[j], _ = itemN.StrictString() }
}
evt.Tags[i] = tag func (smp *SonicMessageParser) OnArrayEnd() error {
// fmt.Println("***", "OnArrayEnd", "==", smp.whereWeAre)
switch smp.whereWeAre {
// envelopes
case inEvent:
smp.mainEnvelope = smp.event
case inReq:
smp.mainEnvelope = smp.req
case inOk:
smp.mainEnvelope = smp.ok
case inEose:
smp.mainEnvelope = smp.eose
case inCount:
smp.mainEnvelope = smp.count
case inAuth:
smp.mainEnvelope = smp.auth
case inClose:
smp.mainEnvelope = smp.close
case inClosed:
smp.mainEnvelope = smp.closed
case inNotice:
smp.mainEnvelope = smp.notice
// filter object properties
case inIds, inAuthors, inKinds, inSearch:
smp.whereWeAre = inFilterObject
case inAFilterTag:
smp.currentFilter.Tags[smp.currentFilterTagName] = smp.currentFilterTagList
// reuse the same underlying slice because we know nothing else will be appended to it
smp.currentFilterTagList = smp.currentFilterTagList[len(smp.currentFilterTagList):]
smp.whereWeAre = inFilterObject
// event object properties
case inAnEventTag:
smp.currentEvent.Tags = append(smp.currentEvent.Tags, smp.currentEventTag)
// reuse the same underlying slice because we know nothing else will be appended to it
smp.currentEventTag = smp.currentEventTag[len(smp.currentEventTag):]
smp.whereWeAre = inTags
case inTags:
smp.whereWeAre = inEventObject
default:
return fmt.Errorf("unexpected array end at %v", smp.whereWeAre)
} }
return nil return nil
} }
func filterFromSonicAst(filter *Filter, node *ast.Node) error { func (smp *SonicMessageParser) OnObjectBegin(capacity int) error {
var err error // fmt.Println("***", "OnObjectBegin", "==", smp.whereWeAre)
node.ForEach(func(path ast.Sequence, node *ast.Node) bool { switch smp.whereWeAre {
switch *path.Key { case inEvent:
case "limit": smp.whereWeAre = inEventObject
limit, _ := node.Int64() smp.currentEvent = &Event{}
filter.Limit = int(limit) case inAuth:
filter.LimitZero = filter.Limit == 0 smp.whereWeAre = inEventObject
case "since": smp.currentEvent = &Event{}
since, _ := node.Int64() case inReq:
filter.Since = (*Timestamp)(&since) smp.whereWeAre = inFilterObject
case "until": smp.currentFilter = &Filter{}
until, _ := node.Int64() case inCount:
filter.Until = (*Timestamp)(&until) // set this temporarily, we will switch to a filterObject if we see "count" or "hll"
case "search": smp.whereWeAre = inFilterObject
filter.Search, _ = node.StrictString() smp.currentFilter = &Filter{}
case "ids": default:
idsN, _ := node.ArrayUseNode() return fmt.Errorf("unexpected object begin at %v", smp.whereWeAre)
filter.IDs = make([]string, len(idsN)) }
for i, idN := range idsN {
filter.IDs[i], _ = idN.StrictString() return nil
} }
case "authors":
authorsN, _ := node.ArrayUseNode() func (smp *SonicMessageParser) OnObjectKey(key string) error {
filter.Authors = make([]string, len(authorsN)) // fmt.Println("***", "OnObjectKey", key, "==", smp.whereWeAre)
for i, authorN := range authorsN {
filter.Authors[i], _ = authorN.StrictString() switch smp.whereWeAre {
} case inEventObject:
case "kinds": switch key {
kindsN, _ := node.ArrayUseNode() case "id":
filter.Kinds = make([]int, len(kindsN)) smp.whereWeAre = inId
for i, kindN := range kindsN { case "sig":
kind, _ := kindN.Int64() smp.whereWeAre = inSig
filter.Kinds[i] = int(kind) case "pubkey":
} smp.whereWeAre = inPubkey
case "content":
smp.whereWeAre = inContent
case "created_at":
smp.whereWeAre = inCreatedAt
case "kind":
smp.whereWeAre = inKind
case "tags":
smp.whereWeAre = inTags
default: default:
if len(*path.Key) > 1 && (*path.Key)[0] == '#' { return fmt.Errorf("unexpected event attr %s", key)
if filter.Tags == nil { }
filter.Tags = make(TagMap, 2) case inFilterObject:
switch key {
case "limit":
smp.whereWeAre = inLimit
case "since":
smp.whereWeAre = inSince
case "until":
smp.whereWeAre = inUntil
case "ids":
smp.whereWeAre = inIds
smp.currentFilter.IDs = make([]string, 0, 25)
case "authors":
smp.whereWeAre = inAuthors
smp.currentFilter.Authors = make([]string, 0, 25)
case "kinds":
smp.whereWeAre = inKinds
smp.currentFilter.IDs = make([]string, 0, 12)
case "search":
smp.whereWeAre = inSearch
case "count", "hll":
// oops, switch to a countObject
smp.whereWeAre = inCountObject
default:
if len(key) > 1 && key[0] == '#' {
if smp.currentFilter.Tags == nil {
smp.currentFilter.Tags = make(TagMap, 1)
smp.currentFilterTagList = make([]string, 0, 25)
} }
tagsN, _ := node.ArrayUseNode() smp.whereWeAre = inAFilterTag
tags := make([]string, len(tagsN)) smp.currentFilterTagName = key[1:]
for i, authorN := range tagsN {
tags[i], _ = authorN.StrictString()
}
filter.Tags[(*path.Key)[1:]] = tags
} else { } else {
err = fmt.Errorf("unexpected field '%s'", *path.Key) return fmt.Errorf("unexpected filter attr %s", key)
return false
} }
} }
return true case inCountObject:
}) // we'll judge by the shape of the value so ignore this
default:
return fmt.Errorf("unexpected object key %s at %s", key, smp.whereWeAre)
}
return err return nil
}
func (smp *SonicMessageParser) OnObjectEnd() error {
// fmt.Println("***", "OnObjectEnd", "==", smp.whereWeAre)
switch smp.whereWeAre {
case inEventObject:
if smp.event != nil {
smp.event.Event = *smp.currentEvent
smp.whereWeAre = inEvent
} else {
smp.auth.Event = *smp.currentEvent
smp.whereWeAre = inAuth
}
case inFilterObject:
if smp.req != nil {
smp.req.Filters = append(smp.req.Filters, *smp.currentFilter)
smp.whereWeAre = inReq
} else {
smp.count.Filter = *smp.currentFilter
smp.whereWeAre = inCount
}
case inCountObject:
smp.whereWeAre = inCount
default:
return fmt.Errorf("unexpected object end at %s", smp.whereWeAre)
}
return nil
}
func (smp *SonicMessageParser) OnString(v string) error {
// fmt.Println("***", "OnString", v, "==", smp.whereWeAre)
switch smp.whereWeAre {
case inEnvelope:
switch v {
case "EVENT":
smp.event = &EventEnvelope{}
smp.whereWeAre = inEvent
case "REQ":
smp.req = &ReqEnvelope{Filters: make(Filters, 0, 1)}
smp.whereWeAre = inReq
case "OK":
smp.ok = &OKEnvelope{}
smp.whereWeAre = inOk
case "EOSE":
smp.whereWeAre = inEose
case "COUNT":
smp.count = &CountEnvelope{}
smp.whereWeAre = inCount
case "AUTH":
smp.auth = &AuthEnvelope{}
smp.whereWeAre = inAuth
case "CLOSE":
smp.whereWeAre = inClose
case "CLOSED":
smp.closed = &ClosedEnvelope{}
smp.whereWeAre = inClosed
case "NOTICE":
smp.whereWeAre = inNotice
}
// in an envelope
case inEvent:
smp.event.SubscriptionID = &v
case inReq:
smp.req.SubscriptionID = v
case inOk:
if smp.ok.EventID == "" {
smp.ok.EventID = v
} else {
smp.ok.Reason = v
}
case inEose:
smp.eose = (*EOSEEnvelope)(&v)
case inCount:
smp.count.SubscriptionID = v
case inAuth:
smp.auth.Challenge = &v
case inClose:
smp.close = (*CloseEnvelope)(&v)
case inClosed:
if smp.closed.SubscriptionID == "" {
smp.closed.SubscriptionID = v
} else {
smp.closed.Reason = v
}
case inNotice:
smp.notice = (*NoticeEnvelope)(&v)
// filter object properties
case inIds:
smp.currentFilter.IDs = append(smp.currentFilter.IDs, v)
case inAuthors:
smp.currentFilter.Authors = append(smp.currentFilter.Authors, v)
case inSearch:
smp.currentFilter.Search = v
smp.whereWeAre = inFilterObject
case inAFilterTag:
smp.currentFilterTagList = append(smp.currentFilterTagList, v)
// id object properties
case inId:
smp.currentEvent.ID = v
smp.whereWeAre = inEventObject
case inContent:
smp.currentEvent.Content = v
smp.whereWeAre = inEventObject
case inPubkey:
smp.currentEvent.PubKey = v
smp.whereWeAre = inEventObject
case inSig:
smp.currentEvent.Sig = v
smp.whereWeAre = inEventObject
case inAnEventTag:
smp.currentEventTag = append(smp.currentEventTag, v)
// count object properties
case inCountObject:
smp.count.HyperLogLog, _ = hex.DecodeString(v)
default:
return fmt.Errorf("unexpected string %s at %v", v, smp.whereWeAre)
}
return nil
}
func (smp *SonicMessageParser) OnInt64(v int64, _ stdlibjson.Number) error {
// fmt.Println("***", "OnInt64", v, "==", smp.whereWeAre)
switch smp.whereWeAre {
// event object
case inCreatedAt:
smp.currentEvent.CreatedAt = Timestamp(v)
smp.whereWeAre = inEventObject
case inKind:
smp.currentEvent.Kind = int(v)
smp.whereWeAre = inEventObject
// filter object
case inLimit:
smp.currentFilter.Limit = int(v)
smp.currentFilter.LimitZero = v == 0
case inSince:
smp.currentFilter.Since = (*Timestamp)(&v)
case inUntil:
smp.currentFilter.Until = (*Timestamp)(&v)
case inKinds:
smp.currentFilter.Kinds = append(smp.currentFilter.Kinds, int(v))
// count object
case inCountObject:
smp.count.Count = &v
}
return nil
}
func (smp *SonicMessageParser) OnBool(v bool) error {
// fmt.Println("***", "OnBool", v, "==", smp.whereWeAre)
if smp.whereWeAre == inOk {
smp.ok.OK = v
return nil
} else {
return fmt.Errorf("unexpected boolean")
}
}
func (_ SonicMessageParser) OnNull() error {
return fmt.Errorf("null shouldn't be anywhere in a message")
}
func (_ SonicMessageParser) OnFloat64(v float64, n stdlibjson.Number) error {
return fmt.Errorf("float shouldn't be anywhere in a message")
}
func ParseMessageSonic(message []byte) (Envelope, error) {
smp := &SonicMessageParser{}
smp.whereWeAre = inEnvelope
err := ast.Preorder(string(message), smp, nil)
return smp.mainEnvelope, err
} }

View File

@ -4,7 +4,6 @@ import (
"testing" "testing"
"github.com/minio/simdjson-go" "github.com/minio/simdjson-go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -41,8 +40,8 @@ func TestParseMessage(t *testing.T) {
}, },
{ {
Name: "EVENT envelope with tags", Name: "EVENT envelope with tags",
Message: []byte(`["EVENT",{"kind":3,"id":"9e662bdd7d8abc40b5b15ee1ff5e9320efc87e9274d8d440c58e6eed2dddfbe2","pubkey":"373ebe3d45ec91977296a178d9f19f326c70631d2a1b0bbba5c5ecc2eb53b9e7","created_at":1644844224,"tags":[["p","3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"],["p","75fc5ac2487363293bd27fb0d14fb966477d0f1dbc6361d37806a6a740eda91e"],["p","46d0dfd3a724a302ca9175163bdf788f3606b3fd1bb12d5fe055d1e418cb60ea"]],"content":"{\"wss://nostr-pub.wellorder.net\":{\"read\":true,\"write\":true},\"wss://nostr.bitcoiner.social\":{\"read\":false,\"write\":true},\"wss://expensive-relay.fiatjaf.com\":{\"read\":true,\"write\":true},\"wss://relayer.fiatjaf.com\":{\"read\":true,\"write\":true},\"wss://relay.bitid.nz\":{\"read\":true,\"write\":true},\"wss://nostr.rocks\":{\"read\":true,\"write\":true}}","sig":"811355d3484d375df47581cb5d66bed05002c2978894098304f20b595e571b7e01b2efd906c5650080ffe49cf1c62b36715698e9d88b9e8be43029a2f3fa66be"}]`), Message: []byte(`["EVENT",{"kind":3,"id":"9e662bdd7d8abc40b5b15ee1ff5e9320efc87e9274d8d440c58e6eed2dddfbe2","pubkey":"373ebe3d45ec91977296a178d9f19f326c70631d2a1b0bbba5c5ecc2eb53b9e7","created_at":1644844224,"tags":[["p","3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"],["e","75fc5ac2487363293bd27fb0d14fb966477d0f1dbc6361d37806a6a740eda91e"],["p","46d0dfd3a724a302ca9175163bdf788f3606b3fd1bb12d5fe055d1e418cb60ea"]],"content":"{\"wss://nostr-pub.wellorder.net\":{\"read\":true,\"write\":true},\"wss://nostr.bitcoiner.social\":{\"read\":false,\"write\":true},\"wss://expensive-relay.fiatjaf.com\":{\"read\":true,\"write\":true},\"wss://relayer.fiatjaf.com\":{\"read\":true,\"write\":true},\"wss://relay.bitid.nz\":{\"read\":true,\"write\":true},\"wss://nostr.rocks\":{\"read\":true,\"write\":true}}","sig":"811355d3484d375df47581cb5d66bed05002c2978894098304f20b595e571b7e01b2efd906c5650080ffe49cf1c62b36715698e9d88b9e8be43029a2f3fa66be"}]`),
ExpectedEnvelope: &EventEnvelope{Event: Event{Kind: 3, ID: "9e662bdd7d8abc40b5b15ee1ff5e9320efc87e9274d8d440c58e6eed2dddfbe2", PubKey: "373ebe3d45ec91977296a178d9f19f326c70631d2a1b0bbba5c5ecc2eb53b9e7", CreatedAt: 1644844224, Tags: Tags{Tag{"p", "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"}, Tag{"p", "75fc5ac2487363293bd27fb0d14fb966477d0f1dbc6361d37806a6a740eda91e"}, Tag{"p", "46d0dfd3a724a302ca9175163bdf788f3606b3fd1bb12d5fe055d1e418cb60ea"}}, Content: "{\"wss://nostr-pub.wellorder.net\":{\"read\":true,\"write\":true},\"wss://nostr.bitcoiner.social\":{\"read\":false,\"write\":true},\"wss://expensive-relay.fiatjaf.com\":{\"read\":true,\"write\":true},\"wss://relayer.fiatjaf.com\":{\"read\":true,\"write\":true},\"wss://relay.bitid.nz\":{\"read\":true,\"write\":true},\"wss://nostr.rocks\":{\"read\":true,\"write\":true}}", Sig: "811355d3484d375df47581cb5d66bed05002c2978894098304f20b595e571b7e01b2efd906c5650080ffe49cf1c62b36715698e9d88b9e8be43029a2f3fa66be"}}, ExpectedEnvelope: &EventEnvelope{Event: Event{Kind: 3, ID: "9e662bdd7d8abc40b5b15ee1ff5e9320efc87e9274d8d440c58e6eed2dddfbe2", PubKey: "373ebe3d45ec91977296a178d9f19f326c70631d2a1b0bbba5c5ecc2eb53b9e7", CreatedAt: 1644844224, Tags: Tags{Tag{"p", "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"}, Tag{"e", "75fc5ac2487363293bd27fb0d14fb966477d0f1dbc6361d37806a6a740eda91e"}, Tag{"p", "46d0dfd3a724a302ca9175163bdf788f3606b3fd1bb12d5fe055d1e418cb60ea"}}, Content: "{\"wss://nostr-pub.wellorder.net\":{\"read\":true,\"write\":true},\"wss://nostr.bitcoiner.social\":{\"read\":false,\"write\":true},\"wss://expensive-relay.fiatjaf.com\":{\"read\":true,\"write\":true},\"wss://relayer.fiatjaf.com\":{\"read\":true,\"write\":true},\"wss://relay.bitid.nz\":{\"read\":true,\"write\":true},\"wss://nostr.rocks\":{\"read\":true,\"write\":true}}", Sig: "811355d3484d375df47581cb5d66bed05002c2978894098304f20b595e571b7e01b2efd906c5650080ffe49cf1c62b36715698e9d88b9e8be43029a2f3fa66be"}},
}, },
{ {
Name: "NOTICE envelope", Name: "NOTICE envelope",
@ -115,12 +114,12 @@ func TestParseMessage(t *testing.T) {
} }
if testCase.ExpectedEnvelope == nil { if testCase.ExpectedEnvelope == nil {
assert.Nil(t, envelope, "expected nil but got %v", envelope) require.Nil(t, envelope, "expected nil but got %v", envelope)
return return
} }
assert.NotNil(t, envelope, "expected non-nil envelope but got nil") require.NotNil(t, envelope, "expected non-nil envelope but got nil")
assert.Equal(t, testCase.ExpectedEnvelope.String(), envelope.String()) require.Equal(t, testCase.ExpectedEnvelope.String(), envelope.String())
}) })
} }
}) })
@ -148,10 +147,9 @@ func TestParseMessage(t *testing.T) {
}) })
t.Run("sonic", func(t *testing.T) { t.Run("sonic", func(t *testing.T) {
smp := SonicMessageParser{}
for _, testCase := range testCases { for _, testCase := range testCases {
t.Run(testCase.Name, func(t *testing.T) { t.Run(testCase.Name, func(t *testing.T) {
envelope, err := smp.ParseMessage(testCase.Message) envelope, err := ParseMessageSonic(testCase.Message)
if testCase.ExpectedEnvelope == nil && envelope == nil { if testCase.ExpectedEnvelope == nil && envelope == nil {
return return
@ -164,7 +162,7 @@ func TestParseMessage(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, envelope, "expected non-nil envelope but got nil") require.NotNil(t, envelope, "expected non-nil envelope but got nil")
require.Equal(t, testCase.ExpectedEnvelope.String(), envelope.String()) require.Equal(t, testCase.ExpectedEnvelope, envelope)
}) })
} }
}) })