Files
smpp-tester/pdu/pdu_test.go
2024-07-24 19:09:14 +02:00

532 lines
15 KiB
Go

package pdu
import (
"bytes"
"encoding/binary"
"math"
"sync"
"testing"
)
// region encode
func TestEncodeReturnsByteSliceOfLength16(t *testing.T) {
p := &PDU_HEADER{
command_length: 1,
command_id: 1,
command_status: 1,
sequence_number: 1,
}
buf := bytes.NewBuffer(make([]byte, 16))
buf.Reset()
err := p.Encode(buf)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
if buf.Cap() != 16 {
t.Errorf("Expected byte slice of length 16, got %d", buf.Cap())
}
}
func TestEncodeHandlesZeroValues(t *testing.T) {
p := &PDU_HEADER{
command_length: 0,
command_id: 0,
command_status: 0,
sequence_number: 0,
}
buf := bytes.NewBuffer(make([]byte, 16))
buf.Reset()
err := p.Encode(buf)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
expected := make([]byte, 16)
for i, v := range buf.Bytes() {
if v != expected[i] {
t.Errorf("Expected byte slice with zero values, got %v", buf.Bytes())
break
}
}
}
func TestEncodeEncodesProperly(t *testing.T) {
p := &PDU_HEADER{
command_length: 1,
command_id: 2,
command_status: 3,
sequence_number: 4,
}
buf := bytes.NewBuffer(make([]byte, 16))
buf.Reset()
err := p.Encode(buf)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
expected := []byte{0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4}
for i, v := range buf.Bytes() {
if v != expected[i] {
t.Errorf("Expected byte slice with values %v, got %v", expected, buf.Bytes())
break
}
}
}
func TestEncodeEncodesProperlyComplex(t *testing.T) {
p := &PDU_HEADER{
command_length: 13426724,
command_id: 254352,
command_status: 35634264,
sequence_number: 476543523,
}
buf := bytes.NewBuffer(make([]byte, 16))
buf.Reset()
err := p.Encode(buf)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
expected := []byte{0, 204, 224, 36, 0, 3, 225, 144, 2, 31, 188, 88, 28, 103, 122, 35}
for i, v := range buf.Bytes() {
if v != expected[i] {
t.Errorf("Expected byte slice with values %v, got %v", expected, buf.Bytes())
break
}
}
}
func TestEncodeIntoCorrectlyEncodesFields(t *testing.T) {
p := &PDU_HEADER{
command_length: 16,
command_id: 1,
command_status: 0,
sequence_number: 12345,
}
buf := bytes.NewBuffer(make([]byte, 16))
buf.Reset()
err := p.Encode(buf)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
innerbuf := buf.Bytes()
if binary.BigEndian.Uint32(innerbuf[0:4]) != p.command_length {
t.Errorf("Expected command_length %d, got %d", p.command_length, binary.BigEndian.Uint32(innerbuf[0:4]))
}
if binary.BigEndian.Uint32(innerbuf[4:8]) != p.command_id {
t.Errorf("Expected command_id %d, got %d", p.command_id, binary.BigEndian.Uint32(innerbuf[4:8]))
}
if binary.BigEndian.Uint32(innerbuf[8:12]) != p.command_status {
t.Errorf("Expected command_status %d, got %d", p.command_status, binary.BigEndian.Uint32(innerbuf[8:12]))
}
if binary.BigEndian.Uint32(innerbuf[12:16]) != p.sequence_number {
t.Errorf("Expected sequence_number %d, got %d", p.sequence_number, binary.BigEndian.Uint32(innerbuf[12:16]))
}
}
func TestEncodeIntoHandlesLargerBuffer(t *testing.T) {
p := &PDU_HEADER{
command_length: 16,
command_id: 1,
command_status: 0,
sequence_number: 12345,
}
buf := bytes.NewBuffer(make([]byte, 20)) // larger buffer size
buf.Reset()
err := p.Encode(buf)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
innerbuf := buf.Bytes()
if binary.BigEndian.Uint32(innerbuf[0:4]) != p.command_length {
t.Errorf("Expected command_length %d, got %d", p.command_length, binary.BigEndian.Uint32(innerbuf[0:4]))
}
if binary.BigEndian.Uint32(innerbuf[4:8]) != p.command_id {
t.Errorf("Expected command_id %d, got %d", p.command_id, binary.BigEndian.Uint32(innerbuf[4:8]))
}
if binary.BigEndian.Uint32(innerbuf[8:12]) != p.command_status {
t.Errorf("Expected command_status %d, got %d", p.command_status, binary.BigEndian.Uint32(innerbuf[8:12]))
}
if binary.BigEndian.Uint32(innerbuf[12:16]) != p.sequence_number {
t.Errorf("Expected sequence_number %d, got %d", p.sequence_number, binary.BigEndian.Uint32(innerbuf[12:16]))
}
}
func TestEncodeIntoUsesBigEndianEncoding(t *testing.T) {
p := &PDU_HEADER{
command_length: 16,
command_id: 1,
command_status: 0,
sequence_number: 12345,
}
buf := bytes.NewBuffer(make([]byte, 16))
buf.Reset()
err := p.Encode(buf)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
innerbuf := buf.Bytes()
if binary.BigEndian.Uint32(innerbuf[0:4]) != p.command_length {
t.Errorf("Expected command_length %d, got %d", p.command_length, binary.BigEndian.Uint32(innerbuf[0:4]))
}
if binary.BigEndian.Uint32(innerbuf[4:8]) != p.command_id {
t.Errorf("Expected command_id %d, got %d", p.command_id, binary.BigEndian.Uint32(innerbuf[4:8]))
}
if binary.BigEndian.Uint32(innerbuf[8:12]) != p.command_status {
t.Errorf("Expected command_status %d, got %d", p.command_status, binary.BigEndian.Uint32(innerbuf[8:12]))
}
if binary.BigEndian.Uint32(innerbuf[12:16]) != p.sequence_number {
t.Errorf("Expected sequence_number %d, got %d", p.sequence_number, binary.BigEndian.Uint32(innerbuf[12:16]))
}
}
func TestEncodeIntoConcurrencySafety(t *testing.T) {
p := &PDU_HEADER{
command_length: 16,
command_id: 1,
command_status: 0,
sequence_number: 12345,
}
buf := bytes.NewBuffer(make([]byte, 16))
buf.Reset()
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
p.Encode(buf)
}()
}
wg.Wait()
innerbuf := buf.Bytes()
if binary.BigEndian.Uint32(innerbuf[0:4]) != p.command_length {
t.Errorf("Expected command_length %d, got %d", p.command_length, binary.BigEndian.Uint32(innerbuf[0:4]))
}
if binary.BigEndian.Uint32(innerbuf[4:8]) != p.command_id {
t.Errorf("Expected command_id %d, got %d", p.command_id, binary.BigEndian.Uint32(innerbuf[4:8]))
}
if binary.BigEndian.Uint32(innerbuf[8:12]) != p.command_status {
t.Errorf("Expected command_status %d, got %d", p.command_status, binary.BigEndian.Uint32(innerbuf[8:12]))
}
if binary.BigEndian.Uint32(innerbuf[12:16]) != p.sequence_number {
t.Errorf("Expected sequence_number %d, got %d", p.sequence_number, binary.BigEndian.Uint32(innerbuf[12:16]))
}
}
func TestEncodeIntoWithMaximumValues(t *testing.T) {
p := &PDU_HEADER{
command_length: math.MaxUint32,
command_id: math.MaxUint32,
command_status: math.MaxUint32,
sequence_number: math.MaxUint32,
}
buf := bytes.NewBuffer(make([]byte, 16))
buf.Reset()
err := p.Encode(buf)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
innerbuf := buf.Bytes()
if binary.BigEndian.Uint32(innerbuf[0:4]) != p.command_length {
t.Errorf("Expected command_length %d, got %d", p.command_length, binary.BigEndian.Uint32(innerbuf[0:4]))
}
if binary.BigEndian.Uint32(innerbuf[4:8]) != p.command_id {
t.Errorf("Expected command_id %d, got %d", p.command_id, binary.BigEndian.Uint32(innerbuf[4:8]))
}
if binary.BigEndian.Uint32(innerbuf[8:12]) != p.command_status {
t.Errorf("Expected command_status %d, got %d", p.command_status, binary.BigEndian.Uint32(innerbuf[8:12]))
}
if binary.BigEndian.Uint32(innerbuf[12:16]) != p.sequence_number {
t.Errorf("Expected sequence_number %d, got %d", p.sequence_number, binary.BigEndian.Uint32(innerbuf[12:16]))
}
}
func TestEncodeIntoWithBoundaryValues(t *testing.T) {
p := &PDU_HEADER{
command_length: 0,
command_id: 0,
command_status: 0,
sequence_number: 0,
}
buf := bytes.NewBuffer(make([]byte, 16))
buf.Reset()
err := p.Encode(buf)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
innerbuf := buf.Bytes()
if binary.BigEndian.Uint32(innerbuf[0:4]) != p.command_length {
t.Errorf("Expected command_length %d, got %d", p.command_length, binary.BigEndian.Uint32(innerbuf[0:4]))
}
if binary.BigEndian.Uint32(innerbuf[4:8]) != p.command_id {
t.Errorf("Expected command_id %d, got %d", p.command_id, binary.BigEndian.Uint32(innerbuf[4:8]))
}
if binary.BigEndian.Uint32(innerbuf[8:12]) != p.command_status {
t.Errorf("Expected command_status %d, got %d", p.command_status, binary.BigEndian.Uint32(innerbuf[8:12]))
}
if binary.BigEndian.Uint32(innerbuf[12:16]) != p.sequence_number {
t.Errorf("Expected sequence_number %d, got %d", p.sequence_number, binary.BigEndian.Uint32(innerbuf[12:16]))
}
}
// func TestRealScenario(t *testing.T) {
// expected := []byte{0, 0, 0, 54, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 1, 67, 77, 84, 0, 1, 1, 49, 50, 51, 52, 53, 0, 1, 1, 54, 55, 56, 57, 48, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 12, 72, 101, 108, 108, 111, 44, 32, 83, 77, 80, 80, 33}
// p := &SUBMIT_SM{
// header: PDU_HEADER{
// command_length: 0,
// command_id: 4,
// command_status: 0,
// sequence_number: 1,
// },
// service_type: "CMT",
// source_addr_ton: 1,
// source_addr_npi: 1,
// source_addr: "12345",
// dest_addr_ton: 1,
// dest_addr_npi: 1,
// destination_addr: "67890",
// esm_class: 0,
// protocol_id: 0,
// priority_flag: 0,
// schedule_delivery_time: "",
// validity_period: "",
// registered_delivery: 1,
// data_coding: 0,
// sm_default_msg_id: 0,
// short_message: "Hello, SMPP!",
// }
// p.header.command_length = uint32(p.Size())
// p.sm_length = byte(len(p.short_message))
// buf := make([]byte, p.Size())
// err := p.EncodeInto(&buf)
// if err != nil {
// t.Errorf("Expected no error, got %v", err)
// }
// if len(buf) != len(expected) {
// t.Errorf("Expected byte slice of length %d, got %d", len(expected), len(buf))
// }
// for i, v := range buf {
// if v != expected[i] {
// t.Errorf("Expected byte slice with values %v, got %v", expected, buf)
// break
// }
// }
// }
// // region decode
// func TestDecodeHandlesShortByteSlice(t *testing.T) {
// var p PDU_HEADER
// data := []byte{0, 0, 0, 10}
// defer func() {
// if r := recover(); r != nil {
// t.Errorf("Decode panicked with short byte slice")
// }
// }()
// err := p.Decode(data)
// if err != nil {
// t.Errorf("Expected no error, got %v", err)
// }
// }
// func TestDecodeParsesValidByteSlice(t *testing.T) {
// var p PDU_HEADER
// data := []byte{0, 0, 0, 16, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3}
// err := p.Decode(data)
// if err != nil {
// t.Errorf("Expected no error, got %v", err)
// }
// if p.command_length != 16 {
// t.Errorf("Expected command_length to be 16, got %d", p.command_length)
// }
// if p.command_id != 1 {
// t.Errorf("Expected command_id to be 1, got %d", p.command_id)
// }
// if p.command_status != 2 {
// t.Errorf("Expected command_status to be 2, got %d", p.command_status)
// }
// if p.sequence_number != 3 {
// t.Errorf("Expected sequence_number to be 3, got %d", p.sequence_number)
// }
// }
// func TestDecodeHandlesLongerByteSliceWithoutCrashing(t *testing.T) {
// var p PDU_HEADER
// data := make([]byte, 20)
// defer func() {
// if r := recover(); r != nil {
// t.Errorf("Decode panicked with long byte slice")
// }
// }()
// err := p.Decode(data)
// if err != nil {
// t.Errorf("Expected no error, got %v", err)
// }
// }
// func TestDecodeHandlesNilDataInput(t *testing.T) {
// var p PDU_HEADER
// err := p.Decode(nil)
// if err != nil {
// t.Errorf("Expected no error, got %v", err)
// }
// if p.command_length != 0 {
// t.Errorf("Expected command_length to be 0, got %d", p.command_length)
// }
// if p.command_id != 0 {
// t.Errorf("Expected command_id to be 0, got %d", p.command_id)
// }
// if p.command_status != 0 {
// t.Errorf("Expected command_status to be 0, got %d", p.command_status)
// }
// if p.sequence_number != 0 {
// t.Errorf("Expected sequence_number to be 0, got %d", p.sequence_number)
// }
// }
// func TestDecodeHandlesEmptyByteSliceGracefully(t *testing.T) {
// var p PDU_HEADER
// data := []byte{}
// err := p.Decode(data)
// if err != nil {
// t.Errorf("Expected no error, got %v", err)
// }
// if p.command_length != 0 {
// t.Errorf("Expected command_length to be 0, got %d", p.command_length)
// }
// if p.command_id != 0 {
// t.Errorf("Expected command_id to be 0, got %d", p.command_id)
// }
// if p.command_status != 0 {
// t.Errorf("Expected command_status to be 0, got %d", p.command_status)
// }
// if p.sequence_number != 0 {
// t.Errorf("Expected sequence_number to be 0, got %d", p.sequence_number)
// }
// }
// func TestDecodeDoesNotModifyInputByteSlice(t *testing.T) {
// var p PDU_HEADER
// data := []byte{0, 0, 0, 16, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3}
// originalData := make([]byte, len(data))
// copy(originalData, data)
// err := p.Decode(data)
// if err != nil {
// t.Errorf("Expected no error, got %v", err)
// }
// for i := range data {
// if data[i] != originalData[i] {
// t.Errorf("Expected data at index %d to be %d, got %d", i, originalData[i], data[i])
// }
// }
// }
// func TestDecodeHandlesByteSlicesWithMaxUint32Values(t *testing.T) {
// var p PDU_HEADER
// data := []byte{255, 255, 255, 255, 255, 255, 255, 255}
// err := p.Decode(data)
// if err != nil {
// t.Errorf("Expected no error, got %v", err)
// }
// if p.command_length != math.MaxUint32 {
// t.Errorf("Expected command_length to be %d, got %d", math.MaxUint32, p.command_length)
// }
// if p.command_id != math.MaxUint32 {
// t.Errorf("Expected command_id to be %d, got %d", math.MaxUint32, p.command_id)
// }
// }
// func TestDecodeHandlesByteSlicesWithMinimumUint32Values(t *testing.T) {
// var p PDU_HEADER
// data := []byte{0, 0, 0, 0, 0, 0, 0, 0}
// err := p.Decode(data)
// if err != nil {
// t.Errorf("Expected no error, got %v", err)
// }
// if p.command_length != 0 {
// t.Errorf("Expected command_length to be 0, got %d", p.command_length)
// }
// if p.command_id != 0 {
// t.Errorf("Expected command_id to be 0, got %d", p.command_id)
// }
// }
// // region size
// func TestSizeReturns16(t *testing.T) {
// var p PDU_HEADER
// if p.Size() != 16 {
// t.Errorf("Expected size to be 16, got %d", p.Size())
// }
// }
// // region benchmarks
// With buffer pool
func BenchmarkEncodeWithBufferPool(b *testing.B) {
p := &PDU_HEADER{
command_length: 16,
command_id: 1,
command_status: 0,
sequence_number: 12345,
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
buf := ByteBufferPool.Get(p.Size())
p.Encode(buf)
ByteBufferPool.Put(buf)
}
}
// Without buffer pool
func BenchmarkEncodeWithoutBufferPool(b *testing.B) {
p := &PDU_HEADER{
command_length: 16,
command_id: 1,
command_status: 0,
sequence_number: 12345,
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
buf := bytes.Buffer{}
p.Encode(&buf)
}
}
func BenchmarkDecodeBufferPool(b *testing.B) {
p := &PDU_HEADER{}
b.ResetTimer()
for i := 0; i < b.N; i++ {
data := []byte{0, 0, 0, 16, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3}
buf := ByteBufferPool.Get(len(data))
buf.Write(data)
p.Decode(buf)
ByteBufferPool.Put(buf)
}
}