vitess.io/vitess@v0.16.2/go/vt/mysqlctl/compression_test.go (about)

     1  /*
     2  Copyright 2021 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  	http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package mysqlctl
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"errors"
    23  	"fmt"
    24  	"io"
    25  	"reflect"
    26  	"strings"
    27  	"testing"
    28  	"time"
    29  
    30  	"github.com/stretchr/testify/require"
    31  
    32  	"vitess.io/vitess/go/vt/logutil"
    33  )
    34  
    35  func TestGetExtensionFromEngine(t *testing.T) {
    36  	tests := []struct {
    37  		engine, extension string
    38  		err               error
    39  	}{
    40  		{"pgzip", ".gz", nil},
    41  		{"pargzip", ".gz", nil},
    42  		{"lz4", ".lz4", nil},
    43  		{"zstd", ".zst", nil},
    44  		{"foobar", "", errUnsupportedCompressionEngine},
    45  	}
    46  
    47  	for _, tt := range tests {
    48  		t.Run(tt.engine, func(t *testing.T) {
    49  			ext, err := getExtensionFromEngine(tt.engine)
    50  			// if err != tt.err {
    51  			if !errors.Is(err, tt.err) {
    52  				t.Errorf("got err: %v; expected: %v", err, tt.err)
    53  			}
    54  			// }
    55  
    56  			if ext != tt.extension {
    57  				t.Errorf("got err: %v; expected: %v", ext, tt.extension)
    58  			}
    59  		})
    60  	}
    61  }
    62  
    63  func TestBuiltinCompressors(t *testing.T) {
    64  	data := []byte("foo bar foobar")
    65  	logger := logutil.NewMemoryLogger()
    66  
    67  	for _, engine := range []string{"pgzip", "lz4", "zstd"} {
    68  		t.Run(engine, func(t *testing.T) {
    69  			var compressed, decompressed bytes.Buffer
    70  			reader := bytes.NewReader(data)
    71  			compressor, err := newBuiltinCompressor(engine, &compressed, logger)
    72  			if err != nil {
    73  				t.Fatal(err)
    74  			}
    75  			_, err = io.Copy(compressor, reader)
    76  			if err != nil {
    77  				t.Error(err)
    78  				return
    79  			}
    80  			compressor.Close()
    81  			decompressor, err := newBuiltinDecompressor(engine, &compressed, logger)
    82  			if err != nil {
    83  				t.Error(err)
    84  				return
    85  			}
    86  			_, err = io.Copy(&decompressed, decompressor)
    87  			if err != nil {
    88  				t.Error(err)
    89  				return
    90  			}
    91  			decompressor.Close()
    92  			if len(data) != len(decompressed.Bytes()) {
    93  				t.Errorf("Different size of original (%d bytes) and uncompressed (%d bytes) data", len(data), len(decompressed.Bytes()))
    94  			}
    95  
    96  			if !reflect.DeepEqual(data, decompressed.Bytes()) {
    97  				t.Error("decompressed content differs from the original")
    98  			}
    99  		})
   100  	}
   101  }
   102  
   103  func TestUnSupportedBuiltinCompressors(t *testing.T) {
   104  	logger := logutil.NewMemoryLogger()
   105  
   106  	for _, engine := range []string{"external", "foobar"} {
   107  		t.Run(engine, func(t *testing.T) {
   108  			_, err := newBuiltinCompressor(engine, nil, logger)
   109  			require.ErrorContains(t, err, "unsupported engine value for --compression-engine-name. supported values are 'external', 'pgzip', 'pargzip', 'zstd', 'lz4' value:")
   110  		})
   111  	}
   112  }
   113  
   114  func TestExternalCompressors(t *testing.T) {
   115  	data := []byte("foo bar foobar")
   116  	logger := logutil.NewMemoryLogger()
   117  
   118  	tests := []struct {
   119  		compress, decompress string
   120  	}{
   121  		{"gzip", "gzip -d"},
   122  		{"pigz", "pigz -d"},
   123  		{"lz4", "lz4 -d"},
   124  		{"zstd", "zstd -d"},
   125  		{"lzop", "lzop -d"},
   126  		{"bzip2", "bzip2 -d"},
   127  		{"lzma", "lzma -d"},
   128  	}
   129  
   130  	for _, tt := range tests {
   131  		t.Run(tt.compress, func(t *testing.T) {
   132  			var compressed, decompressed bytes.Buffer
   133  			reader := bytes.NewReader(data)
   134  			for _, cmd := range []string{tt.compress, tt.decompress} {
   135  				cmdArgs := strings.Split(cmd, " ")
   136  
   137  				_, err := validateExternalCmd(cmdArgs[0])
   138  				if err != nil {
   139  					t.Skip("Command not available in this host:", err)
   140  				}
   141  			}
   142  			ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
   143  			defer cancel()
   144  			compressor, err := newExternalCompressor(ctx, tt.compress, &compressed, logger)
   145  			if err != nil {
   146  				t.Error(err)
   147  				return
   148  			}
   149  			_, err = io.Copy(compressor, reader)
   150  			if err != nil {
   151  				t.Error(err)
   152  				return
   153  			}
   154  			compressor.Close()
   155  			decompressor, err := newExternalDecompressor(ctx, tt.decompress, &compressed, logger)
   156  			if err != nil {
   157  				t.Error(err)
   158  				return
   159  			}
   160  			_, err = io.Copy(&decompressed, decompressor)
   161  			if err != nil {
   162  				t.Error(err)
   163  				return
   164  			}
   165  			decompressor.Close()
   166  			if len(data) != len(decompressed.Bytes()) {
   167  				t.Errorf("Different size of original (%d bytes) and uncompressed (%d bytes) data", len(data), len(decompressed.Bytes()))
   168  			}
   169  			if !reflect.DeepEqual(data, decompressed.Bytes()) {
   170  				t.Error("decompressed content differs from the original")
   171  			}
   172  
   173  		})
   174  	}
   175  }
   176  
   177  func TestValidateExternalCmd(t *testing.T) {
   178  	tests := []struct {
   179  		cmdName string
   180  		path    string
   181  		errStr  string
   182  	}{
   183  		// this should not find an executable
   184  		{"non_existent_cmd", "", "executable file not found"},
   185  		// we expect ls to be on PATH as it is a basic command part of busybox and most containers
   186  		{"ls", "ls", ""},
   187  	}
   188  
   189  	for i, tt := range tests {
   190  		t.Run(fmt.Sprintf("Test #%d", i+1), func(t *testing.T) {
   191  			CmdName := tt.cmdName
   192  			path, err := validateExternalCmd(CmdName)
   193  			if tt.path != "" {
   194  				if !strings.HasSuffix(path, tt.path) {
   195  					t.Errorf("Expected path \"%s\" to include \"%s\"", path, tt.path)
   196  				}
   197  			}
   198  			if tt.errStr == "" {
   199  				if err != nil {
   200  					t.Errorf("Expected result \"%v\", got \"%v\"", "<nil>", err)
   201  				}
   202  			} else {
   203  				if !strings.Contains(fmt.Sprintf("%v", err), tt.errStr) {
   204  					t.Errorf("Expected result \"%v\", got \"%v\"", tt.errStr, err)
   205  				}
   206  			}
   207  		})
   208  	}
   209  }
   210  
   211  func TestValidateCompressionEngineName(t *testing.T) {
   212  	tests := []struct {
   213  		engineName string
   214  		errStr     string
   215  	}{
   216  		// we expect ls to be on PATH as it is a basic command part of busybox and most containers
   217  		{"external", ""},
   218  		{"foobar", "unsupported engine value for --compression-engine-name. supported values are 'external', 'pgzip', 'pargzip', 'zstd', 'lz4' value: \"foobar\""},
   219  	}
   220  
   221  	for i, tt := range tests {
   222  		t.Run(fmt.Sprintf("Test #%d", i+1), func(t *testing.T) {
   223  			err := validateExternalCompressionEngineName(tt.engineName)
   224  			if tt.errStr == "" {
   225  				if err != nil {
   226  					t.Errorf("Expected result \"%v\", got \"%v\"", "<nil>", err)
   227  				}
   228  			} else {
   229  				if !strings.Contains(fmt.Sprintf("%v", err), tt.errStr) {
   230  					t.Errorf("Expected result \"%v\", got \"%v\"", tt.errStr, err)
   231  				}
   232  			}
   233  		})
   234  	}
   235  }