You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lal/pkg/rtmp/amf0_test.go

335 lines
11 KiB
Go

// Copyright 2019, Chef. All rights reserved.
// https://github.com/q191201771/lal
//
// Use of this source code is governed by a MIT-style license
// that can be found in the License file.
//
// Author: Chef (191201771@qq.com)
package rtmp_test
import (
"bytes"
"encoding/hex"
"errors"
"strings"
"testing"
"github.com/q191201771/lal/pkg/base"
. "github.com/q191201771/lal/pkg/rtmp"
"github.com/q191201771/naza/pkg/assert"
"github.com/q191201771/naza/pkg/fake"
)
func TestAmf0_WriteNumber_ReadNumber(t *testing.T) {
cases := []float64{
0,
1,
0xff,
1.2,
}
for _, item := range cases {
out := &bytes.Buffer{}
err := Amf0.WriteNumber(out, item)
assert.Equal(t, nil, err)
v, l, err := Amf0.ReadNumber(out.Bytes())
assert.Equal(t, item, v)
assert.Equal(t, l, 9)
assert.Equal(t, nil, err)
}
}
func TestAmf0_WriteString_ReadString(t *testing.T) {
cases := []string{
"a",
"ab",
"111",
"~!@#$%^&*()_+",
}
for _, item := range cases {
out := &bytes.Buffer{}
err := Amf0.WriteString(out, item)
assert.Equal(t, nil, err)
v, l, err := Amf0.ReadString(out.Bytes())
assert.Equal(t, item, v)
assert.Equal(t, l, len(item)+3)
assert.Equal(t, nil, err)
}
longStr := strings.Repeat("1", 65536)
out := &bytes.Buffer{}
err := Amf0.WriteString(out, longStr)
assert.Equal(t, nil, err)
v, l, err := Amf0.ReadString(out.Bytes())
assert.Equal(t, longStr, v)
assert.Equal(t, l, len(longStr)+5)
assert.Equal(t, nil, err)
}
func TestAmf0_WriteObject_ReadObject(t *testing.T) {
out := &bytes.Buffer{}
objs := []ObjectPair{
{Key: "air", Value: 3},
{Key: "ban", Value: "cat"},
{Key: "dog", Value: true},
}
err := Amf0.WriteObject(out, objs)
assert.Equal(t, nil, err)
v, _, err := Amf0.ReadObject(out.Bytes())
assert.Equal(t, nil, err)
assert.Equal(t, 3, len(v))
assert.Equal(t, float64(3), v.Find("air"))
assert.Equal(t, "cat", v.Find("ban"))
assert.Equal(t, true, v.Find("dog"))
}
func TestAmf0_WriteNull_readNull(t *testing.T) {
out := &bytes.Buffer{}
err := Amf0.WriteNull(out)
assert.Equal(t, nil, err)
l, err := Amf0.ReadNull(out.Bytes())
assert.Equal(t, 1, l)
assert.Equal(t, nil, err)
}
func TestAmf0_WriteBoolean_ReadBoolean(t *testing.T) {
cases := []bool{true, false}
for i := range cases {
out := &bytes.Buffer{}
err := Amf0.WriteBoolean(out, cases[i])
assert.Equal(t, nil, err)
v, l, err := Amf0.ReadBoolean(out.Bytes())
assert.Equal(t, cases[i], v)
assert.Equal(t, 2, l)
assert.Equal(t, nil, err)
}
}
func TestAmf0_ReadArray(t *testing.T) {
gold := []byte{0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x00, 0x40, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x00, 0x40, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x72, 0x61, 0x74, 0x65, 0x00, 0x40, 0x69, 0xe8, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x00, 0x40, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x63, 0x69, 0x64, 0x00, 0x40, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x72, 0x61, 0x74, 0x65, 0x00, 0x40, 0x3d, 0x54, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x61, 0x74, 0x65, 0x00, 0x40, 0xe5, 0x88, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x73, 0x74, 0x65, 0x72, 0x65, 0x6f, 0x01, 0x01, 0x00, 0x0c, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x63, 0x69, 0x64, 0x00, 0x40, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x5f, 0x62, 0x72, 0x61, 0x6e, 0x64, 0x02, 0x00, 0x04, 0x69, 0x73, 0x6f, 0x6d, 0x00, 0x0d, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x02, 0x00, 0x03, 0x35, 0x31, 0x32, 0x00, 0x11, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x72, 0x61, 0x6e, 0x64, 0x73, 0x02, 0x00, 0x10, 0x69, 0x73, 0x6f, 0x6d, 0x69, 0x73, 0x6f, 0x32, 0x61, 0x76, 0x63, 0x31, 0x6d, 0x70, 0x34, 0x31, 0x00, 0x07, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x02, 0x00, 0x0d, 0x4c, 0x61, 0x76, 0x66, 0x35, 0x37, 0x2e, 0x38, 0x33, 0x2e, 0x31, 0x30, 0x30, 0x00, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09}
ops, l, err := Amf0.ReadArray(gold)
assert.Equal(t, nil, err)
assert.Equal(t, 16, len(ops))
assert.Equal(t, 359, len(gold))
assert.Equal(t, 359, l)
Log.Debug(ops)
}
func TestAmf0_ReadCase1(t *testing.T) {
// ZLMediaKit connect result的object中存在null type
// https://github.com/q191201771/lal/issues/102
//
gold := "030000000000b614000000000200075f726573756c74003ff000000000000003000c6361706162696c697469657300403f0000000000000006666d7356657202000d464d532f332c302c312c313233000009030004636f646502001d4e6574436f6e6e656374696f6e2e436f6e6e6563742e53756363657373000b6465736372697074696f6e020015436f6e6e656374696f6e207375636365656465642e00056c6576656c020006737461747573000e6f626a656374456e636f64696e6705000009"
goldbytes, err := hex.DecodeString(gold)
assert.Equal(t, nil, err)
index := 12
s, l, err := Amf0.ReadString(goldbytes[index:])
assert.Equal(t, nil, err)
assert.Equal(t, "_result", s)
index += l
n, l, err := Amf0.ReadNumber(goldbytes[index:])
assert.Equal(t, nil, err)
assert.Equal(t, float64(1), n)
index += l
o, l, err := Amf0.ReadObject(goldbytes[index:])
assert.Equal(t, nil, err)
i, err := o.FindNumber("capabilities")
assert.Equal(t, nil, err)
assert.Equal(t, 31, i)
s, err = o.FindString("fmsVer")
assert.Equal(t, nil, err)
assert.Equal(t, "FMS/3,0,1,123", s)
index += l
o, l, err = Amf0.ReadObject(goldbytes[index:])
assert.Equal(t, nil, err)
s, err = o.FindString("code")
assert.Equal(t, nil, err)
assert.Equal(t, "NetConnection.Connect.Success", s)
s, err = o.FindString("description")
assert.Equal(t, nil, err)
assert.Equal(t, "Connection succeeded.", s)
s, err = o.FindString("level")
assert.Equal(t, nil, err)
assert.Equal(t, "status", s)
index += l
assert.Equal(t, len(goldbytes), index)
}
func TestAmf0Corner(t *testing.T) {
var (
mw *fake.Writer
err error
b []byte
str string
l int
num float64
flag bool
objs []ObjectPair
)
mw = fake.NewWriter(fake.WriterTypeReturnError)
err = Amf0.WriteNumber(mw, 0)
assert.IsNotNil(t, err)
mw = fake.NewWriter(fake.WriterTypeReturnError)
err = Amf0.WriteBoolean(mw, true)
assert.IsNotNil(t, err)
// WriteString 调用 三次写
mw = fake.NewWriter(fake.WriterTypeDoNothing)
mw.SetSpecificType(map[uint32]fake.WriterType{0: fake.WriterTypeReturnError})
err = Amf0.WriteString(mw, "0")
assert.IsNotNil(t, err)
mw = fake.NewWriter(fake.WriterTypeDoNothing)
mw.SetSpecificType(map[uint32]fake.WriterType{1: fake.WriterTypeReturnError})
err = Amf0.WriteString(mw, "1")
assert.IsNotNil(t, err)
mw = fake.NewWriter(fake.WriterTypeDoNothing)
mw.SetSpecificType(map[uint32]fake.WriterType{2: fake.WriterTypeReturnError})
err = Amf0.WriteString(mw, "2")
assert.IsNotNil(t, err)
longStr := strings.Repeat("1", 65536)
mw = fake.NewWriter(fake.WriterTypeDoNothing)
mw.SetSpecificType(map[uint32]fake.WriterType{0: fake.WriterTypeReturnError})
err = Amf0.WriteString(mw, longStr)
assert.IsNotNil(t, err)
mw = fake.NewWriter(fake.WriterTypeDoNothing)
mw.SetSpecificType(map[uint32]fake.WriterType{1: fake.WriterTypeReturnError})
err = Amf0.WriteString(mw, longStr)
assert.IsNotNil(t, err)
mw = fake.NewWriter(fake.WriterTypeDoNothing)
mw.SetSpecificType(map[uint32]fake.WriterType{2: fake.WriterTypeReturnError})
err = Amf0.WriteString(mw, longStr)
assert.IsNotNil(t, err)
objs = []ObjectPair{
{Key: "air", Value: 3},
{Key: "ban", Value: "cat"},
{Key: "dog", Value: true},
}
for i := uint32(0); i < 14; i++ {
mw = fake.NewWriter(fake.WriterTypeDoNothing)
mw.SetSpecificType(map[uint32]fake.WriterType{i: fake.WriterTypeReturnError})
err = Amf0.WriteObject(mw, objs)
assert.IsNotNil(t, err)
}
b = nil
str, l, err = Amf0.ReadStringWithoutType(b)
assert.Equal(t, str, "")
assert.Equal(t, 0, l)
assert.Equal(t, true, errors.Is(err, base.ErrAmfTooShort))
b = []byte{1, 1}
str, l, err = Amf0.ReadStringWithoutType(b)
assert.Equal(t, str, "")
assert.Equal(t, 0, l)
assert.Equal(t, true, errors.Is(err, base.ErrAmfTooShort))
b = nil
str, l, err = Amf0.ReadLongStringWithoutType(b)
assert.Equal(t, str, "")
assert.Equal(t, 0, l)
assert.Equal(t, true, errors.Is(err, base.ErrAmfTooShort))
b = []byte{1, 1, 1, 1}
str, l, err = Amf0.ReadLongStringWithoutType(b)
assert.Equal(t, str, "")
assert.Equal(t, 0, l)
assert.Equal(t, true, errors.Is(err, base.ErrAmfTooShort))
b = nil
str, l, err = Amf0.ReadString(b)
assert.Equal(t, str, "")
assert.Equal(t, 0, l)
assert.Equal(t, true, errors.Is(err, base.ErrAmfTooShort))
b = []byte{1}
str, l, err = Amf0.ReadString(b)
assert.Equal(t, str, "")
assert.Equal(t, 0, l)
assert.Equal(t, true, errors.Is(err, base.ErrAmfInvalidType))
b = nil
num, l, err = Amf0.ReadNumber(b)
assert.Equal(t, int(num), 0)
assert.Equal(t, 0, l)
assert.Equal(t, true, errors.Is(err, base.ErrAmfTooShort))
str = strings.Repeat("1", 16)
b = []byte(str)
num, l, err = Amf0.ReadNumber(b)
assert.Equal(t, int(num), 0)
assert.Equal(t, 0, l)
assert.Equal(t, true, errors.Is(err, base.ErrAmfInvalidType))
b = nil
flag, l, err = Amf0.ReadBoolean(b)
assert.Equal(t, flag, false)
assert.Equal(t, 0, l)
assert.Equal(t, true, errors.Is(err, base.ErrAmfTooShort))
b = []byte{0, 0}
flag, l, err = Amf0.ReadBoolean(b)
assert.Equal(t, flag, false)
assert.Equal(t, 0, l)
assert.Equal(t, true, errors.Is(err, base.ErrAmfInvalidType))
b = nil
l, err = Amf0.ReadNull(b)
assert.Equal(t, 0, l)
assert.Equal(t, true, errors.Is(err, base.ErrAmfTooShort))
b = []byte{0}
l, err = Amf0.ReadNull(b)
assert.Equal(t, 0, l)
assert.Equal(t, true, errors.Is(err, base.ErrAmfInvalidType))
b = nil
objs, l, err = Amf0.ReadObject(b)
assert.Equal(t, nil, objs)
assert.Equal(t, 0, l)
assert.Equal(t, true, errors.Is(err, base.ErrAmfTooShort))
b = []byte{0}
objs, l, err = Amf0.ReadObject(b)
assert.Equal(t, nil, objs)
assert.Equal(t, 0, l)
assert.Equal(t, true, errors.Is(err, base.ErrAmfInvalidType))
defer func() {
recover()
}()
objs = []ObjectPair{
{Key: "key", Value: []byte{1}},
}
_ = Amf0.WriteObject(mw, objs)
}
func BenchmarkAmf0_ReadObject(b *testing.B) {
out := &bytes.Buffer{}
objs := []ObjectPair{
{Key: "air", Value: 3},
{Key: "ban", Value: "cat"},
{Key: "dog", Value: true},
}
_ = Amf0.WriteObject(out, objs)
for i := 0; i < b.N; i++ {
_, _, _ = Amf0.ReadObject(out.Bytes())
}
}
func BenchmarkAmf0_WriteObject(b *testing.B) {
out := &bytes.Buffer{}
objs := []ObjectPair{
{Key: "air", Value: 3},
{Key: "ban", Value: "cat"},
{Key: "dog", Value: true},
}
for i := 0; i < b.N; i++ {
_ = Amf0.WriteObject(out, objs)
}
}