github.com/containerd/Containerd@v1.4.13/archive/compression/compression_test.go (about) 1 /* 2 Copyright The containerd 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 compression 18 19 import ( 20 "bytes" 21 "compress/gzip" 22 "context" 23 "io" 24 "io/ioutil" 25 "math/rand" 26 "os" 27 "os/exec" 28 "path/filepath" 29 "runtime" 30 "strings" 31 "testing" 32 ) 33 34 func TestMain(m *testing.M) { 35 // Force initPigz to be called, so tests start with the same initial state 36 gzipDecompress(context.Background(), strings.NewReader("")) 37 os.Exit(m.Run()) 38 } 39 40 // generateData generates data that composed of 2 random parts 41 // and single zero-filled part within them. 42 // Typically, the compression ratio would be about 67%. 43 func generateData(t *testing.T, size int) []byte { 44 part0 := size / 3 // random 45 part2 := size / 3 // random 46 part1 := size - part0 - part2 // zero-filled 47 part0Data := make([]byte, part0) 48 if _, err := rand.Read(part0Data); err != nil { 49 t.Fatal(err) 50 } 51 part1Data := make([]byte, part1) 52 part2Data := make([]byte, part2) 53 if _, err := rand.Read(part2Data); err != nil { 54 t.Fatal(err) 55 } 56 return append(part0Data, append(part1Data, part2Data...)...) 57 } 58 59 func testCompressDecompress(t *testing.T, size int, compression Compression) DecompressReadCloser { 60 orig := generateData(t, size) 61 var b bytes.Buffer 62 compressor, err := CompressStream(&b, compression) 63 if err != nil { 64 t.Fatal(err) 65 } 66 if n, err := compressor.Write(orig); err != nil || n != size { 67 t.Fatal(err) 68 } 69 compressor.Close() 70 compressed := b.Bytes() 71 t.Logf("compressed %d bytes to %d bytes (%.2f%%)", 72 len(orig), len(compressed), 100.0*float32(len(compressed))/float32(len(orig))) 73 if compared := bytes.Compare(orig, compressed); (compression == Uncompressed && compared != 0) || 74 (compression != Uncompressed && compared == 0) { 75 t.Fatal("strange compressed data") 76 } 77 78 decompressor, err := DecompressStream(bytes.NewReader(compressed)) 79 if err != nil { 80 t.Fatal(err) 81 } 82 decompressed, err := ioutil.ReadAll(decompressor) 83 if err != nil { 84 t.Fatal(err) 85 } 86 if !bytes.Equal(orig, decompressed) { 87 t.Fatal("strange decompressed data") 88 } 89 90 return decompressor 91 } 92 93 func TestCompressDecompressGzip(t *testing.T) { 94 oldUnpigzPath := unpigzPath 95 unpigzPath = "" 96 defer func() { unpigzPath = oldUnpigzPath }() 97 98 decompressor := testCompressDecompress(t, 1024*1024, Gzip) 99 wrapper := decompressor.(*readCloserWrapper) 100 _, ok := wrapper.Reader.(*gzip.Reader) 101 if !ok { 102 t.Fatalf("unexpected compressor type: %T", wrapper.Reader) 103 } 104 } 105 106 func TestCompressDecompressPigz(t *testing.T) { 107 if _, err := exec.LookPath("unpigz"); err != nil { 108 t.Skip("pigz not installed") 109 } 110 111 decompressor := testCompressDecompress(t, 1024*1024, Gzip) 112 wrapper := decompressor.(*readCloserWrapper) 113 _, ok := wrapper.Reader.(*io.PipeReader) 114 if !ok { 115 t.Fatalf("unexpected compressor type: %T", wrapper.Reader) 116 } 117 } 118 119 func TestCompressDecompressUncompressed(t *testing.T) { 120 testCompressDecompress(t, 1024*1024, Uncompressed) 121 } 122 123 func TestDetectPigz(t *testing.T) { 124 // Create fake PATH with unpigz executable, make sure detectPigz can find it 125 tempPath, err := ioutil.TempDir("", "containerd_temp_") 126 if err != nil { 127 t.Fatal(err) 128 } 129 130 filename := "unpigz" 131 if runtime.GOOS == "windows" { 132 filename = "unpigz.exe" 133 } 134 135 fullPath := filepath.Join(tempPath, filename) 136 137 if err := ioutil.WriteFile(fullPath, []byte(""), 0111); err != nil { 138 t.Fatal(err) 139 } 140 141 defer os.RemoveAll(tempPath) 142 143 oldPath := os.Getenv("PATH") 144 os.Setenv("PATH", tempPath) 145 defer os.Setenv("PATH", oldPath) 146 147 if pigzPath := detectPigz(); pigzPath == "" { 148 t.Fatal("failed to detect pigz path") 149 } else if pigzPath != fullPath { 150 t.Fatalf("wrong pigz found: %s != %s", pigzPath, fullPath) 151 } 152 153 os.Setenv(disablePigzEnv, "1") 154 defer os.Unsetenv(disablePigzEnv) 155 156 if pigzPath := detectPigz(); pigzPath != "" { 157 t.Fatalf("disable via %s doesn't work", disablePigzEnv) 158 } 159 } 160 161 func TestCmdStream(t *testing.T) { 162 out, err := cmdStream(exec.Command("sh", "-c", "echo hello; exit 0"), nil) 163 if err != nil { 164 t.Fatal(err) 165 } 166 167 buf, err := ioutil.ReadAll(out) 168 if err != nil { 169 t.Fatalf("failed to read from stdout: %s", err) 170 } 171 172 if string(buf) != "hello\n" { 173 t.Fatalf("unexpected command output ('%s' != '%s')", string(buf), "hello\n") 174 } 175 } 176 177 func TestCmdStreamBad(t *testing.T) { 178 out, err := cmdStream(exec.Command("sh", "-c", "echo hello; echo >&2 bad result; exit 1"), nil) 179 if err != nil { 180 t.Fatalf("failed to start command: %v", err) 181 } 182 183 if buf, err := ioutil.ReadAll(out); err == nil { 184 t.Fatal("command should have failed") 185 } else if err.Error() != "exit status 1: bad result\n" { 186 t.Fatalf("wrong error: %s", err.Error()) 187 } else if string(buf) != "hello\n" { 188 t.Fatalf("wrong output: %s", string(buf)) 189 } 190 }