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 }