Skip to content

Commit

Permalink
Extending test coverage for compression types
Browse files Browse the repository at this point in the history
  • Loading branch information
rnishtala-sumo committed Sep 20, 2024
1 parent 74b1d10 commit 83cf4e5
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 39 deletions.
5 changes: 5 additions & 0 deletions config/configcompression/compressiontype.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ func (ct *Type) UnmarshalText(in []byte) error {
}

// IsZstd returns true if the compression type is zstd.
// The specified compression level is not validated.
// Because zstd supports returning an encoder level that closest matches the compression ratio of a specific zstd compression level.
// Many input values will provide the same compression level.
func (ct *Type) IsZstd() bool {
parts := strings.Split(string(*ct), "/")
return parts[0] == string(TypeZstd)
Expand All @@ -68,6 +71,7 @@ func (ct *Type) IsGzip() bool {
levelStr == zlib.NoCompression {
return true
}
return false
}
return true
}
Expand All @@ -90,6 +94,7 @@ func (ct *Type) IsZlib() bool {
levelStr == zlib.NoCompression {
return true
}
return false
}
return true
}
Expand Down
113 changes: 113 additions & 0 deletions config/configcompression/compressiontype_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,116 @@ func TestUnmarshalText(t *testing.T) {
})
}
}

func TestIsZstd(t *testing.T) {
tests := []struct {
name string
input Type
expected bool
}{
{
name: "ValidZstd",
input: TypeZstd,
expected: true,
},
{
name: "InvalidZstd",
input: TypeGzip,
expected: false,
},
{
name: "ValidZstdLevel",
input: "zstd/11",
expected: true,
},
{
name: "ValidZstdLevel",
input: "zstd/One",
expected: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.expected, tt.input.IsZstd())
})
}
}

func TestIsGzip(t *testing.T) {
tests := []struct {
name string
input Type
expected bool
}{
{
name: "ValidGzip",
input: TypeGzip,
expected: true,
},
{
name: "InvalidGzip",
input: TypeZlib,
expected: false,
},
{
name: "ValidZlibCompressionLevel",
input: "gzip/1",
expected: true,
},
{
name: "InvalidZlibCompressionLevel",
input: "gzip/10",
expected: false,
},
{
name: "InvalidZlibCompressionLevel",
input: "gzip/one", // Uses the default compression level
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.expected, tt.input.IsGzip())
})
}
}

func TestIsZlib(t *testing.T) {
tests := []struct {
name string
input Type
expected bool
err bool
}{
{
name: "ValidZlib",
input: TypeZlib,
expected: true,
},
{
name: "InvalidZlib",
input: TypeGzip,
expected: false,
},
{
name: "ValidZlibCompressionLevel",
input: "zlib/1",
expected: true,
},
{
name: "InvalidZlibCompressionLevel",
input: "zlib/10",
expected: false,
},
{
name: "InvalidZlibCompressionLevel",
input: "zlib/one", // Uses the default compression level
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.expected, tt.input.IsZlib())
})
}
}
11 changes: 3 additions & 8 deletions config/confighttp/compression.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,6 @@ type compressRoundTripper struct {
compressor *compressor
}

type CompressionOptions struct {
compressionType configcompression.Type
compressionLevel int
}

var availableDecoders = map[string]func(body io.ReadCloser) (io.ReadCloser, error){
"": func(io.ReadCloser) (io.ReadCloser, error) {
// Not a compressed payload. Nothing to do.
Expand Down Expand Up @@ -77,14 +72,14 @@ var availableDecoders = map[string]func(body io.ReadCloser) (io.ReadCloser, erro
},
}

func newCompressRoundTripper(rt http.RoundTripper, compressionopts CompressionOptions) (*compressRoundTripper, error) {
encoder, err := newCompressor(compressionopts)
func newCompressRoundTripper(rt http.RoundTripper, compressionType configcompression.Type) (*compressRoundTripper, error) {
encoder, err := newCompressor(compressionType)
if err != nil {
return nil, err
}
return &compressRoundTripper{
rt: rt,
compressionType: compressionopts.compressionType,
compressionType: compressionType,
compressor: encoder,
}, nil
}
Expand Down
9 changes: 5 additions & 4 deletions config/confighttp/compression_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,13 @@ func TestHTTPClientCompression(t *testing.T) {
Compression: tt.encoding,
}
client, err := clientSettings.ToClient(context.Background(), componenttest.NewNopHost(), componenttest.NewNopTelemetrySettings())
require.NoError(t, err)
res, err := client.Do(req)
if tt.shouldError {
assert.Error(t, err)
return
}
require.NoError(t, err)
res, err := client.Do(req)
require.NoError(t, err)

_, err = io.ReadAll(res.Body)
require.NoError(t, err)
Expand Down Expand Up @@ -296,8 +296,9 @@ func TestHTTPContentCompressionRequestWithNilBody(t *testing.T) {
req, err := http.NewRequest(http.MethodGet, srv.URL, nil)
require.NoError(t, err, "failed to create request to test handler")

client := srv.Client()
client.Transport, err = newCompressRoundTripper(http.DefaultTransport, configcompression.TypeGzip)
client := http.Client{}
// compression := CompressionOptions{configcompression.TypeGzip, gzip.BestSpeed}
client.Transport, err = newCompressRoundTripper(http.DefaultTransport, "gzip/1")
require.NoError(t, err)
res, err := client.Do(req)
require.NoError(t, err)
Expand Down
34 changes: 29 additions & 5 deletions config/confighttp/compressor.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"compress/zlib"
"errors"
"io"
"strconv"
"strings"
"sync"

"github.com/golang/snappy"
Expand All @@ -26,24 +28,46 @@ type compressor struct {
pool sync.Pool
}

type CompressionOptions struct {
compressionType configcompression.Type
compressionLevel int
}

// Gets the compression type and level from the configuration.
func getCompression(compressionField configcompression.Type) (compressionType configcompression.Type, compressionLevel int) {
parts := strings.Split(string(compressionField), "/")

compressionLevel = zlib.DefaultCompression
compressionType = configcompression.Type(parts[0])
if len(parts) > 1 {
levelStr := parts[1]
if level, err := strconv.Atoi(levelStr); err == nil {
compressionLevel = level
}
}
return compressionType, compressionLevel
}

// writerFactory defines writer field in CompressRoundTripper.
// The validity of input is already checked when NewCompressRoundTripper was called in confighttp,
func newCompressor(compressionopts CompressionOptions) (*compressor, error) {
switch compressionopts.compressionType {
func newCompressor(compressionType configcompression.Type) (*compressor, error) {
compressionType, compressionLevel := getCompression(compressionType)

switch compressionType {
case configcompression.TypeGzip:
var _ writeCloserReset = (*gzip.Writer)(nil)
return &compressor{pool: sync.Pool{New: func() any { w, _ := gzip.NewWriterLevel(nil, compressionopts.compressionLevel); return w }}}, nil
return &compressor{pool: sync.Pool{New: func() any { w, _ := gzip.NewWriterLevel(nil, compressionLevel); return w }}}, nil
case configcompression.TypeSnappy:
var _ writeCloserReset = (*snappy.Writer)(nil)
return &compressor{pool: sync.Pool{New: func() any { return snappy.NewBufferedWriter(nil) }}}, nil
case configcompression.TypeZstd:
var _ writeCloserReset = (*zstd.Encoder)(nil)
compression := zstd.EncoderLevelFromZstd(compressionopts.compressionLevel)
compression := zstd.EncoderLevelFromZstd(compressionLevel)
encoderLevel := zstd.WithEncoderLevel(compression)
return &compressor{pool: sync.Pool{New: func() any { zw, _ := zstd.NewWriter(nil, zstd.WithEncoderConcurrency(1), encoderLevel); return zw }}}, nil
case configcompression.TypeZlib, configcompression.TypeDeflate:
var _ writeCloserReset = (*zlib.Writer)(nil)
return &compressor{pool: sync.Pool{New: func() any { w, _ := zlib.NewWriterLevel(nil, compressionopts.compressionLevel); return w }}}, nil
return &compressor{pool: sync.Pool{New: func() any { w, _ := zlib.NewWriterLevel(nil, compressionLevel); return w }}}, nil
}
return nil, errors.New("unsupported compression type")

Check warning on line 72 in config/confighttp/compressor.go

View check run for this annotation

Codecov / codecov/patch

config/confighttp/compressor.go#L72

Added line #L72 was not covered by tests
}
Expand Down
27 changes: 5 additions & 22 deletions config/confighttp/confighttp.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ import (
"net/http"
"net/http/cookiejar"
"net/url"
"strconv"
"strings"
"time"

"github.com/rs/cors"
Expand Down Expand Up @@ -134,21 +132,6 @@ func NewDefaultClientConfig() ClientConfig {
}
}

func setCompression(compressionField configcompression.Type) (compressionType configcompression.Type, compressionLevel int) {
parts := strings.Split(string(compressionField), "/")

// Set compression type
compressionLevel = 1
compressionType = configcompression.Type(parts[0])
if len(parts) > 1 {
levelStr := parts[1]
if level, err := strconv.Atoi(levelStr); err == nil {
compressionLevel = level
}
}
return compressionType, compressionLevel
}

// ToClient creates an HTTP client.
func (hcs *ClientConfig) ToClient(ctx context.Context, host component.Host, settings component.TelemetrySettings) (*http.Client, error) {
tlsCfg, err := hcs.TLSSetting.LoadTLSConfig(ctx)
Expand Down Expand Up @@ -235,16 +218,16 @@ func (hcs *ClientConfig) ToClient(ctx context.Context, host component.Host, sett
// Supporting gzip, zlib, deflate, snappy, and zstd; none is treated as uncompressed.
if hcs.Compression.IsCompressed() {
if hcs.Compression.IsZstd() || hcs.Compression.IsGzip() || hcs.Compression.IsZlib() {
compressionType, compressionLevel := setCompression(hcs.Compression)
compression := CompressionOptions{compressionType, compressionLevel}
clientTransport, err = newCompressRoundTripper(clientTransport, compression)
// compressionType, compressionLevel := getCompression(hcs.Compression)
// compression := CompressionOptions{compressionType, compressionLevel}
clientTransport, err = newCompressRoundTripper(clientTransport, hcs.Compression)
if err != nil {
return nil, err

Check warning on line 225 in config/confighttp/confighttp.go

View check run for this annotation

Codecov / codecov/patch

config/confighttp/confighttp.go#L225

Added line #L225 was not covered by tests
}
} else {
// Use the default if the compression level is not specified.
compressionopts := CompressionOptions{hcs.Compression, -1}
clientTransport, err = newCompressRoundTripper(clientTransport, compressionopts)
// compressionopts := CompressionOptions{hcs.Compression, -1}
clientTransport, err = newCompressRoundTripper(clientTransport, hcs.Compression)
if err != nil {
return nil, err

Check warning on line 232 in config/confighttp/confighttp.go

View check run for this annotation

Codecov / codecov/patch

config/confighttp/confighttp.go#L232

Added line #L232 was not covered by tests
}
Expand Down

0 comments on commit 83cf4e5

Please sign in to comment.