github.com/lalkh/containerd@v1.4.3/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  }