Move archive to pkg/archive
Signed-off-by: Derek McGowan <derek@mcg.dev>
This commit is contained in:
		
							
								
								
									
										228
									
								
								pkg/archive/compression/compression_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								pkg/archive/compression/compression_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,228 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package compression
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"compress/gzip"
 | 
			
		||||
	"context"
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestMain(m *testing.M) {
 | 
			
		||||
	// Force initPigz to be called, so tests start with the same initial state
 | 
			
		||||
	gzipDecompress(context.Background(), strings.NewReader(""))
 | 
			
		||||
	os.Exit(m.Run())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// generateData generates data that composed of 2 random parts
 | 
			
		||||
// and single zero-filled part within them.
 | 
			
		||||
// Typically, the compression ratio would be about 67%.
 | 
			
		||||
func generateData(t testing.TB, size int) []byte {
 | 
			
		||||
	part0 := size / 3             // random
 | 
			
		||||
	part2 := size / 3             // random
 | 
			
		||||
	part1 := size - part0 - part2 // zero-filled
 | 
			
		||||
	part0Data := make([]byte, part0)
 | 
			
		||||
	if _, err := rand.Read(part0Data); err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	part1Data := make([]byte, part1)
 | 
			
		||||
	part2Data := make([]byte, part2)
 | 
			
		||||
	if _, err := rand.Read(part2Data); err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	return append(part0Data, append(part1Data, part2Data...)...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testCompress(t testing.TB, orig []byte, compression Compression) []byte {
 | 
			
		||||
	size := len(orig)
 | 
			
		||||
	var b bytes.Buffer
 | 
			
		||||
	compressor, err := CompressStream(&b, compression)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	if n, err := compressor.Write(orig); err != nil || n != size {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	compressor.Close()
 | 
			
		||||
 | 
			
		||||
	return b.Bytes()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testDecompress(t testing.TB, compressed []byte) ([]byte, DecompressReadCloser) {
 | 
			
		||||
	decompressor, err := DecompressStream(bytes.NewReader(compressed))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	decompressed, err := io.ReadAll(decompressor)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	return decompressed, decompressor
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testCompressDecompress(t testing.TB, size int, compression Compression) DecompressReadCloser {
 | 
			
		||||
	orig := generateData(t, size)
 | 
			
		||||
	compressed := testCompress(t, orig, compression)
 | 
			
		||||
	t.Logf("compressed %d bytes to %d bytes (%.2f%%)",
 | 
			
		||||
		len(orig), len(compressed), 100.0*float32(len(compressed))/float32(len(orig)))
 | 
			
		||||
	if compared := bytes.Compare(orig, compressed); (compression == Uncompressed && compared != 0) ||
 | 
			
		||||
		(compression != Uncompressed && compared == 0) {
 | 
			
		||||
		t.Fatal("strange compressed data")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	decompressed, decompressor := testDecompress(t, compressed)
 | 
			
		||||
	if !bytes.Equal(orig, decompressed) {
 | 
			
		||||
		t.Fatal("strange decompressed data")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return decompressor
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCompressDecompressGzip(t *testing.T) {
 | 
			
		||||
	oldUnpigzPath := gzipPath
 | 
			
		||||
	gzipPath = ""
 | 
			
		||||
	defer func() { gzipPath = oldUnpigzPath }()
 | 
			
		||||
 | 
			
		||||
	decompressor := testCompressDecompress(t, 1024*1024, Gzip)
 | 
			
		||||
	wrapper := decompressor.(*readCloserWrapper)
 | 
			
		||||
	_, ok := wrapper.Reader.(*gzip.Reader)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		t.Fatalf("unexpected compressor type: %T", wrapper.Reader)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCompressDecompressPigz(t *testing.T) {
 | 
			
		||||
	if _, err := exec.LookPath("unpigz"); err != nil {
 | 
			
		||||
		t.Skip("pigz not installed")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	decompressor := testCompressDecompress(t, 1024*1024, Gzip)
 | 
			
		||||
	wrapper := decompressor.(*readCloserWrapper)
 | 
			
		||||
	_, ok := wrapper.Reader.(*io.PipeReader)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		t.Fatalf("unexpected compressor type: %T", wrapper.Reader)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCompressDecompressUncompressed(t *testing.T) {
 | 
			
		||||
	testCompressDecompress(t, 1024*1024, Uncompressed)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDetectPigz(t *testing.T) {
 | 
			
		||||
	// Create fake PATH with unpigz executable, make sure detectPigz can find it
 | 
			
		||||
	tempPath := t.TempDir()
 | 
			
		||||
 | 
			
		||||
	filename := "unpigz"
 | 
			
		||||
	if runtime.GOOS == "windows" {
 | 
			
		||||
		filename = "unpigz.exe"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fullPath := filepath.Join(tempPath, filename)
 | 
			
		||||
 | 
			
		||||
	if err := os.WriteFile(fullPath, []byte(""), 0111); err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	t.Setenv("PATH", tempPath)
 | 
			
		||||
 | 
			
		||||
	if pigzPath := detectCommand("unpigz", disablePigzEnv); pigzPath == "" {
 | 
			
		||||
		t.Fatal("failed to detect pigz path")
 | 
			
		||||
	} else if pigzPath != fullPath {
 | 
			
		||||
		t.Fatalf("wrong pigz found: %s != %s", pigzPath, fullPath)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	t.Setenv(disablePigzEnv, "1")
 | 
			
		||||
 | 
			
		||||
	if pigzPath := detectCommand("unpigz", disablePigzEnv); pigzPath != "" {
 | 
			
		||||
		t.Fatalf("disable via %s doesn't work", disablePigzEnv)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCmdStream(t *testing.T) {
 | 
			
		||||
	out, err := cmdStream(exec.Command("sh", "-c", "echo hello; exit 0"), nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	buf, err := io.ReadAll(out)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("failed to read from stdout: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if string(buf) != "hello\n" {
 | 
			
		||||
		t.Fatalf("unexpected command output ('%s' != '%s')", string(buf), "hello\n")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCmdStreamBad(t *testing.T) {
 | 
			
		||||
	out, err := cmdStream(exec.Command("sh", "-c", "echo hello; echo >&2 bad result; exit 1"), nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("failed to start command: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if buf, err := io.ReadAll(out); err == nil {
 | 
			
		||||
		t.Fatal("command should have failed")
 | 
			
		||||
	} else if err.Error() != "exit status 1: bad result\n" {
 | 
			
		||||
		t.Fatalf("wrong error: %s", err.Error())
 | 
			
		||||
	} else if string(buf) != "hello\n" {
 | 
			
		||||
		t.Fatalf("wrong output: %s", string(buf))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDetectCompressionZstd(t *testing.T) {
 | 
			
		||||
	for _, tc := range []struct {
 | 
			
		||||
		source   []byte
 | 
			
		||||
		expected Compression
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			// test zstd compression without skippable frames.
 | 
			
		||||
			source: []byte{
 | 
			
		||||
				0x28, 0xb5, 0x2f, 0xfd, // magic number of Zstandard frame: 0xFD2FB528
 | 
			
		||||
				0x04, 0x00, 0x31, 0x00, 0x00, // frame header
 | 
			
		||||
				0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, // data block "docker"
 | 
			
		||||
				0x16, 0x0e, 0x21, 0xc3, // content checksum
 | 
			
		||||
			},
 | 
			
		||||
			expected: Zstd,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			// test zstd compression with skippable frames.
 | 
			
		||||
			source: []byte{
 | 
			
		||||
				0x50, 0x2a, 0x4d, 0x18, // magic number of skippable frame: 0x184D2A50 to 0x184D2A5F
 | 
			
		||||
				0x04, 0x00, 0x00, 0x00, // frame size
 | 
			
		||||
				0x5d, 0x00, 0x00, 0x00, // user data
 | 
			
		||||
				0x28, 0xb5, 0x2f, 0xfd, // magic number of Zstandard frame: 0xFD2FB528
 | 
			
		||||
				0x04, 0x00, 0x31, 0x00, 0x00, // frame header
 | 
			
		||||
				0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, // data block "docker"
 | 
			
		||||
				0x16, 0x0e, 0x21, 0xc3, // content checksum
 | 
			
		||||
			},
 | 
			
		||||
			expected: Zstd,
 | 
			
		||||
		},
 | 
			
		||||
	} {
 | 
			
		||||
		compression := DetectCompression(tc.source)
 | 
			
		||||
		if compression != tc.expected {
 | 
			
		||||
			t.Fatalf("Unexpected compression %v, expected %v", compression, tc.expected)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user