mirror of https://github.com/hashicorp/boundary
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
446 lines
11 KiB
446 lines
11 KiB
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package bsr_test
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/hashicorp/boundary/internal/bsr"
|
|
"github.com/hashicorp/go-kms-wrapping/v2/extras/crypto"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestNewChunkScanner(t *testing.T) {
|
|
ctx := context.Background()
|
|
cases := []struct {
|
|
name string
|
|
reader io.Reader
|
|
opts []bsr.Option
|
|
wantErr error
|
|
}{
|
|
{
|
|
"valid",
|
|
bytes.NewBuffer([]byte(
|
|
string(bsr.Magic) +
|
|
"",
|
|
)),
|
|
nil,
|
|
nil,
|
|
},
|
|
{
|
|
"valid-with-sha256sum",
|
|
bytes.NewBuffer([]byte(
|
|
string(bsr.Magic) +
|
|
"",
|
|
)),
|
|
[]bsr.Option{bsr.WithSha256Sum([]byte("797cf38f8e3efa3da3ae95449466ffd62cfe084abd1c1134f9e74474e79570f0"))},
|
|
nil,
|
|
},
|
|
{
|
|
"nil-reader",
|
|
nil,
|
|
[]bsr.Option{bsr.WithSha256Sum([]byte("797cf38f8e3efa3da3ae95449466ffd62cfe084abd1c1134f9e74474e79570f0"))},
|
|
fmt.Errorf("bsr.NewChunkScanner: reader is nil: invalid parameter"),
|
|
},
|
|
{
|
|
"no-magic",
|
|
bytes.NewBuffer([]byte("NOT_BSR_MAGIC")),
|
|
nil,
|
|
fmt.Errorf("bsr.NewChunkScanner: bsr.ReadMagic: invalid magic string"),
|
|
},
|
|
{
|
|
"not-enough-data",
|
|
bytes.NewBuffer(bsr.Magic.Bytes()[:2]),
|
|
nil,
|
|
fmt.Errorf("bsr.NewChunkScanner: bsr.ReadMagic: crypto.(Sha256SumReader).Read: EOF"),
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := bsr.NewChunkScanner(ctx, tc.reader, tc.opts...)
|
|
if tc.wantErr != nil {
|
|
require.EqualError(t, err, tc.wantErr.Error())
|
|
return
|
|
}
|
|
require.NoError(t, err)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestChunkScanner(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
ts := time.Date(2023, time.March, 16, 10, 47, 3, 14, time.UTC)
|
|
|
|
cases := []struct {
|
|
name string
|
|
reader io.Reader
|
|
opts []bsr.Option
|
|
want bsr.Chunk
|
|
wantErr error
|
|
}{
|
|
{
|
|
"header",
|
|
bytes.NewBuffer([]byte(
|
|
string(bsr.Magic) +
|
|
"\x00\x00\x00\x10" + // length
|
|
"TEST" + // protocol
|
|
"HEAD" + // type
|
|
"\x01" + // direction
|
|
"\x00\x00\x00\x00\x64\x12\xf3\xa7" + // time seconds
|
|
"\x00\x00\x00\x0e" + // time nanoseconds
|
|
"\x00" + // compression method
|
|
"\x00" + // encryption method
|
|
"sess_123456789" + // data
|
|
"\xbe\x4c\x7c\x20" + // crc
|
|
"",
|
|
)),
|
|
nil,
|
|
&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,
|
|
},
|
|
{
|
|
"checksum-eof",
|
|
bytes.NewBuffer([]byte(
|
|
string(bsr.Magic) +
|
|
"\x00\x00\x00\x10" + // length
|
|
"TEST" + // protocol
|
|
"HEAD" + // type
|
|
"\x01" + // direction
|
|
"\x00\x00\x00\x00\x64\x12\xf3\xa7" + // time seconds
|
|
"\x00\x00\x00\x0e" + // time nanoseconds
|
|
"\x00" + // compression method
|
|
"\x00" + // encryption method
|
|
"sess_123456789" + // data
|
|
"\xbe\x4c\x7c\x20" + // crc
|
|
"",
|
|
)),
|
|
[]bsr.Option{bsr.WithSha256Sum([]byte("foo"))},
|
|
&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,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
scanner, err := bsr.NewChunkScanner(ctx, tc.reader, tc.opts...)
|
|
require.NoError(t, err)
|
|
|
|
got, err := scanner.Scan(ctx)
|
|
if tc.wantErr != nil {
|
|
require.EqualError(t, err, tc.wantErr.Error())
|
|
return
|
|
}
|
|
require.Equal(t, tc.want, got)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestChunkWalk(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
ts := time.Date(2023, time.March, 16, 10, 47, 3, 14, time.UTC)
|
|
|
|
headerTest := []byte(
|
|
string(bsr.Magic) +
|
|
"\x00\x00\x00\x10" + // length
|
|
"TEST" + // protocol
|
|
"HEAD" + // type
|
|
"\x01" + // direction
|
|
"\x00\x00\x00\x00\x64\x12\xf3\xa7" + // time seconds
|
|
"\x00\x00\x00\x0e" + // time nanoseconds
|
|
"\x00" + // compression method
|
|
"\x00" + // encryption method
|
|
"sess_123456789" + // data
|
|
"\xbe\x4c\x7c\x20" + // crc
|
|
"" + // test
|
|
"\x00\x00\x00\x03" + // length
|
|
"TEST" + // protocol
|
|
"TEST" + // type
|
|
"\x01" + // direction
|
|
"\x00\x00\x00\x00\x64\x12\xf3\xa7" + // time seconds
|
|
"\x00\x00\x00\x0e" + // time nanoseconds
|
|
"foo" + // data
|
|
"\xa4\x6e\x48\x70" + // crc
|
|
"",
|
|
)
|
|
headerTestEnd := append(headerTest, []byte(
|
|
""+ // end
|
|
"\x00\x00\x00\x00"+ // length
|
|
"TEST"+ // protocol
|
|
"DONE"+ // type
|
|
"\x01"+ // direction
|
|
"\x00\x00\x00\x00\x64\x12\xf3\xa7"+ // time seconds
|
|
"\x00\x00\x00\x13"+ // time nanoseconds
|
|
"\x50\x91\xfe\x72"+ // crc
|
|
"",
|
|
)...)
|
|
|
|
cases := []struct {
|
|
name string
|
|
reader io.Reader
|
|
opts []bsr.Option
|
|
f func(t *testing.T, got *[]bsr.Chunk) bsr.ChunkReadFunc
|
|
want []bsr.Chunk
|
|
wantErr error
|
|
}{
|
|
{
|
|
"no-chunk",
|
|
bytes.NewBuffer([]byte(
|
|
string(bsr.Magic) +
|
|
"",
|
|
)),
|
|
nil,
|
|
func(t *testing.T, _ *[]bsr.Chunk) bsr.ChunkReadFunc {
|
|
return func(_ context.Context, c bsr.Chunk) error {
|
|
assert.Fail(t, "read func should not be called")
|
|
return nil
|
|
}
|
|
},
|
|
[]bsr.Chunk{},
|
|
nil,
|
|
},
|
|
{
|
|
"header-test-end",
|
|
bytes.NewBuffer(headerTestEnd),
|
|
nil,
|
|
func(t *testing.T, got *[]bsr.Chunk) bsr.ChunkReadFunc {
|
|
return func(_ context.Context, c bsr.Chunk) error {
|
|
*got = append(*got, c)
|
|
return nil
|
|
}
|
|
},
|
|
[]bsr.Chunk{
|
|
&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",
|
|
},
|
|
&testChunk{
|
|
BaseChunk: &bsr.BaseChunk{
|
|
Protocol: "TEST",
|
|
Direction: bsr.Inbound,
|
|
Timestamp: bsr.NewTimestamp(ts),
|
|
Type: "TEST",
|
|
},
|
|
Data: []byte("foo"),
|
|
},
|
|
&bsr.EndChunk{
|
|
BaseChunk: &bsr.BaseChunk{
|
|
Protocol: "TEST",
|
|
Direction: bsr.Inbound,
|
|
Timestamp: bsr.NewTimestamp(ts.Add(time.Nanosecond * 5)),
|
|
Type: bsr.ChunkEnd,
|
|
},
|
|
},
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"header-test-end-checksumed",
|
|
bytes.NewBuffer(headerTestEnd),
|
|
[]bsr.Option{bsr.WithSha256Sum(func() []byte {
|
|
b, err := crypto.Sha256Sum(ctx, bytes.NewBuffer(headerTestEnd), crypto.WithHexEncoding(true))
|
|
require.NoError(t, err)
|
|
return b
|
|
}())},
|
|
func(t *testing.T, got *[]bsr.Chunk) bsr.ChunkReadFunc {
|
|
return func(_ context.Context, c bsr.Chunk) error {
|
|
*got = append(*got, c)
|
|
return nil
|
|
}
|
|
},
|
|
[]bsr.Chunk{
|
|
&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",
|
|
},
|
|
&testChunk{
|
|
BaseChunk: &bsr.BaseChunk{
|
|
Protocol: "TEST",
|
|
Direction: bsr.Inbound,
|
|
Timestamp: bsr.NewTimestamp(ts),
|
|
Type: "TEST",
|
|
},
|
|
Data: []byte("foo"),
|
|
},
|
|
&bsr.EndChunk{
|
|
BaseChunk: &bsr.BaseChunk{
|
|
Protocol: "TEST",
|
|
Direction: bsr.Inbound,
|
|
Timestamp: bsr.NewTimestamp(ts.Add(time.Nanosecond * 5)),
|
|
Type: bsr.ChunkEnd,
|
|
},
|
|
},
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"header-test-no-end",
|
|
bytes.NewBuffer(headerTest),
|
|
nil,
|
|
func(t *testing.T, got *[]bsr.Chunk) bsr.ChunkReadFunc {
|
|
return func(_ context.Context, c bsr.Chunk) error {
|
|
*got = append(*got, c)
|
|
return nil
|
|
}
|
|
},
|
|
[]bsr.Chunk{
|
|
&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",
|
|
},
|
|
&testChunk{
|
|
BaseChunk: &bsr.BaseChunk{
|
|
Protocol: "TEST",
|
|
Direction: bsr.Inbound,
|
|
Timestamp: bsr.NewTimestamp(ts),
|
|
Type: "TEST",
|
|
},
|
|
Data: []byte("foo"),
|
|
},
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"header-test-no-end-checksumed",
|
|
bytes.NewBuffer(headerTest),
|
|
[]bsr.Option{bsr.WithSha256Sum(func() []byte {
|
|
b, err := crypto.Sha256Sum(ctx, bytes.NewBuffer(headerTest), crypto.WithHexEncoding(true))
|
|
require.NoError(t, err)
|
|
return b
|
|
}())},
|
|
func(t *testing.T, got *[]bsr.Chunk) bsr.ChunkReadFunc {
|
|
return func(_ context.Context, c bsr.Chunk) error {
|
|
*got = append(*got, c)
|
|
return nil
|
|
}
|
|
},
|
|
[]bsr.Chunk{
|
|
&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",
|
|
},
|
|
&testChunk{
|
|
BaseChunk: &bsr.BaseChunk{
|
|
Protocol: "TEST",
|
|
Direction: bsr.Inbound,
|
|
Timestamp: bsr.NewTimestamp(ts),
|
|
Type: "TEST",
|
|
},
|
|
Data: []byte("foo"),
|
|
},
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"func-errors",
|
|
bytes.NewBuffer([]byte(
|
|
string(bsr.Magic) +
|
|
"\x00\x00\x00\x10" + // length
|
|
"TEST" + // protocol
|
|
"HEAD" + // type
|
|
"\x01" + // direction
|
|
"\x00\x00\x00\x00\x64\x12\xf3\xa7" + // time seconds
|
|
"\x00\x00\x00\x0e" + // time nanoseconds
|
|
"\x00" + // compression method
|
|
"\x00" + // encryption method
|
|
"sess_123456789" + // data
|
|
"\xbe\x4c\x7c\x20" + // crc
|
|
"",
|
|
)),
|
|
nil,
|
|
func(t *testing.T, got *[]bsr.Chunk) bsr.ChunkReadFunc {
|
|
return func(_ context.Context, c bsr.Chunk) error {
|
|
return fmt.Errorf("error in walk function")
|
|
}
|
|
},
|
|
nil,
|
|
fmt.Errorf("bsr.ChunkWalk: error in walk function"),
|
|
},
|
|
{
|
|
"incorrect-checksum",
|
|
bytes.NewBuffer(headerTestEnd),
|
|
[]bsr.Option{bsr.WithSha256Sum([]byte("f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2"))},
|
|
func(t *testing.T, got *[]bsr.Chunk) bsr.ChunkReadFunc {
|
|
return func(_ context.Context, c bsr.Chunk) error {
|
|
*got = append(*got, c)
|
|
return nil
|
|
}
|
|
},
|
|
nil,
|
|
fmt.Errorf("bsr.ChunkWalk: bsr.(ChunkScanner).Scan: computed checksum did NOT match"),
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
scanner, err := bsr.NewChunkScanner(ctx, tc.reader, tc.opts...)
|
|
require.NoError(t, err)
|
|
got := make([]bsr.Chunk, 0, len(tc.want))
|
|
err = bsr.ChunkWalk(ctx, scanner, tc.f(t, &got))
|
|
if tc.wantErr != nil {
|
|
require.EqualError(t, err, tc.wantErr.Error())
|
|
return
|
|
}
|
|
require.NoError(t, err)
|
|
require.Equal(t, tc.want, got)
|
|
})
|
|
}
|
|
}
|