Files
threshold/internal/bsr/chunk_header_test.go
T
Timothy Messier fe870fc989 feat(bsr): Add ChunkDecoder
A ChunkDecoder can be used to BSR Chunks. Each call to Decode will read
the next chunk from the decoder's io.Reader. It handles decompressing
any compressed chunk data, and verifying the CRCs of each chunk.
2023-05-31 12:18:20 +00:00

335 lines
7.3 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package bsr_test
import (
"context"
"errors"
"testing"
"time"
"github.com/hashicorp/boundary/internal/bsr"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestNewHeaderChunk(t *testing.T) {
ctx := context.Background()
now := time.Now()
cases := []struct {
name string
p bsr.Protocol
d bsr.Direction
t *bsr.Timestamp
c bsr.Compression
e bsr.Encryption
sessionId string
want *bsr.HeaderChunk
wantErr error
}{
{
"valid-nocompression-noencrpytion",
bsr.Protocol("TEST"),
bsr.Inbound,
bsr.NewTimestamp(now),
bsr.NoCompression,
bsr.NoEncryption,
"sess_123456789",
&bsr.HeaderChunk{
BaseChunk: &bsr.BaseChunk{
Protocol: bsr.Protocol("TEST"),
Direction: bsr.Inbound,
Timestamp: bsr.NewTimestamp(now),
Type: bsr.ChunkHeader,
},
Compression: bsr.NoCompression,
Encryption: bsr.NoEncryption,
SessionId: "sess_123456789",
},
nil,
},
{
"valid-gzip-noencrpytion",
bsr.Protocol("TEST"),
bsr.Inbound,
bsr.NewTimestamp(now),
bsr.GzipCompression,
bsr.NoEncryption,
"sess_123456789",
&bsr.HeaderChunk{
BaseChunk: &bsr.BaseChunk{
Protocol: bsr.Protocol("TEST"),
Direction: bsr.Inbound,
Timestamp: bsr.NewTimestamp(now),
Type: bsr.ChunkHeader,
},
Compression: bsr.GzipCompression,
Encryption: bsr.NoEncryption,
SessionId: "sess_123456789",
},
nil,
},
{
"invalid-protocol",
bsr.Protocol("TEST_INVALID"),
bsr.Inbound,
bsr.NewTimestamp(now),
bsr.NoCompression,
bsr.NoEncryption,
"sess_123456789",
nil,
errors.New("bsr.NewBaseChunk: protocol name cannot be greater than 4 characters: invalid parameter"),
},
{
"invalid-direction",
bsr.Protocol("TEST"),
bsr.UnknownDirection,
bsr.NewTimestamp(now),
bsr.NoCompression,
bsr.NoEncryption,
"sess_123456789",
nil,
errors.New("bsr.NewBaseChunk: invalid direction: invalid parameter"),
},
{
"invalid-timestamp",
bsr.Protocol("TEST"),
bsr.Inbound,
nil,
bsr.NoCompression,
bsr.NoEncryption,
"sess_123456789",
nil,
errors.New("bsr.NewBaseChunk: timestamp must not be nil: invalid parameter"),
},
{
"invalid-compression",
bsr.Protocol("TEST"),
bsr.Inbound,
bsr.NewTimestamp(now),
bsr.Compression(255),
bsr.NoEncryption,
"sess_123456789",
nil,
errors.New("bsr.NewHeader: invalid compression: invalid parameter"),
},
{
"invalid-encryption",
bsr.Protocol("TEST"),
bsr.Inbound,
bsr.NewTimestamp(now),
bsr.NoCompression,
bsr.Encryption(255),
"sess_123456789",
nil,
errors.New("bsr.NewHeader: invalid encryption: invalid parameter"),
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
got, err := bsr.NewHeader(ctx, tc.p, tc.d, tc.t, tc.c, tc.e, tc.sessionId)
if tc.wantErr != nil {
assert.EqualError(t, tc.wantErr, err.Error())
return
}
require.NoError(t, err)
assert.Equal(t, tc.want, got)
})
}
}
func TestHeaderMarshalData(t *testing.T) {
ctx := context.Background()
now := time.Now()
cases := []struct {
name string
h *bsr.HeaderChunk
want []byte
}{
{
"nocompression-noencrpytion",
&bsr.HeaderChunk{
BaseChunk: &bsr.BaseChunk{
Protocol: bsr.Protocol("TEST"),
Direction: bsr.Inbound,
Timestamp: bsr.NewTimestamp(now),
Type: bsr.ChunkHeader,
},
Compression: bsr.NoCompression,
Encryption: bsr.NoEncryption,
SessionId: "sess_123456789",
},
[]byte("\x00\x00sess_123456789"),
},
{
"gzip-noencrpytion",
&bsr.HeaderChunk{
BaseChunk: &bsr.BaseChunk{
Protocol: bsr.Protocol("TEST"),
Direction: bsr.Inbound,
Timestamp: bsr.NewTimestamp(now),
Type: bsr.ChunkHeader,
},
Compression: bsr.GzipCompression,
Encryption: bsr.NoEncryption,
SessionId: "sess_123456789",
},
[]byte("\x01\x00sess_123456789"),
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
got, err := tc.h.MarshalData(ctx)
require.NoError(t, err)
assert.Equal(t, tc.want, got)
})
}
}
func TestDecodeHeader(t *testing.T) {
ctx := context.Background()
ts := time.Date(2023, time.March, 16, 10, 47, 3, 14, time.UTC)
cases := []struct {
name string
bc *bsr.BaseChunk
encoded []byte
want bsr.Chunk
wantErr error
}{
{
"header-no-compression",
&bsr.BaseChunk{
Protocol: "TEST",
Direction: bsr.Inbound,
Timestamp: bsr.NewTimestamp(ts),
Type: bsr.ChunkHeader,
},
[]byte(
"" + // so everything else aligns better
"\x00" + // compression method
"\x00" + // encryption method
"sess_123456789" + // data
"",
),
&bsr.HeaderChunk{
BaseChunk: &bsr.BaseChunk{
Protocol: "TEST",
Direction: bsr.Inbound,
Timestamp: bsr.NewTimestamp(ts),
Type: bsr.ChunkHeader,
},
Compression: bsr.NoCompression,
Encryption: bsr.NoEncryption,
SessionId: "sess_123456789",
},
nil,
},
{
"header-gzip-compression",
&bsr.BaseChunk{
Protocol: "TEST",
Direction: bsr.Inbound,
Timestamp: bsr.NewTimestamp(ts),
Type: bsr.ChunkHeader,
},
[]byte(
"" + // so everything else aligns better
"\x01" + // compression method
"\x00" + // encryption method
"sess_123456789" + // data
"",
),
&bsr.HeaderChunk{
BaseChunk: &bsr.BaseChunk{
Protocol: "TEST",
Direction: bsr.Inbound,
Timestamp: bsr.NewTimestamp(ts),
Type: bsr.ChunkHeader,
},
Compression: bsr.GzipCompression,
Encryption: bsr.NoEncryption,
SessionId: "sess_123456789",
},
nil,
},
{
"header-wrong-type",
&bsr.BaseChunk{
Protocol: "TEST",
Direction: bsr.Inbound,
Timestamp: bsr.NewTimestamp(ts),
Type: "TEST",
},
[]byte(
"" + // so everything else aligns better
"\x01" + // compression method
"\x00" + // encryption method
"sess_123456789" + // data
"",
),
nil,
errors.New("bsr.DecodeHeader: invalid chunk type TEST"),
},
{
"header-nil-base-chunk",
nil,
[]byte(
"" + // so everything else aligns better
"\x01" + // compression method
"\x00" + // encryption method
"sess_123456789" + // data
"",
),
nil,
errors.New("bsr.DecodeHeader: nil base chunk: invalid parameter"),
},
{
"header-no-data",
&bsr.BaseChunk{
Protocol: "TEST",
Direction: bsr.Inbound,
Timestamp: bsr.NewTimestamp(ts),
Type: bsr.ChunkHeader,
},
nil,
nil,
errors.New("bsr.DecodeHeader: not enough data"),
},
{
"header-not-enough-data",
&bsr.BaseChunk{
Protocol: "TEST",
Direction: bsr.Inbound,
Timestamp: bsr.NewTimestamp(ts),
Type: bsr.ChunkHeader,
},
[]byte(
"" + // so everything else aligns better
"\x01" + // compression method
"",
),
nil,
errors.New("bsr.DecodeHeader: not enough data"),
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
got, err := bsr.DecodeHeader(ctx, tc.bc, tc.encoded)
if tc.wantErr != nil {
require.EqualError(t, err, tc.wantErr.Error())
return
}
require.NoError(t, err)
assert.Equal(t, tc.want, got)
})
}
}