// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved package main import ( "archive/zip" "fmt" "io/ioutil" //nolint: staticcheck "os" "os/exec" "path" "path/filepath" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestSizes(t *testing.T) { if testing.Short() { t.Skip() return } t.Log("test how different arguments affect binary and archive sizes") cases := []struct { file string args []string }{ {"testdata/apigw.go", nil}, {"testdata/noop.go", nil}, {"testdata/noop.go", []string{"-tags", "lambda.norpc"}}, {"testdata/noop.go", []string{"-ldflags=-s -w"}}, {"testdata/noop.go", []string{"-tags", "lambda.norpc", "-ldflags=-s -w"}}, } testDir, err := os.Getwd() require.NoError(t, err) tempDir, err := ioutil.TempDir("/tmp", "build-lambda-zip") require.NoError(t, err) for _, test := range cases { require.NoError(t, os.Chdir(testDir)) testName := fmt.Sprintf("%s, %v", test.file, test.args) t.Run(testName, func(t *testing.T) { binPath := path.Join(tempDir, test.file+".bin") zipPath := path.Join(tempDir, test.file+".zip") buildArgs := []string{"build", "-o", binPath} buildArgs = append(buildArgs, test.args...) buildArgs = append(buildArgs, test.file) gocmd := exec.Command("go", buildArgs...) gocmd.Env = append(os.Environ(), "GOOS=linux") gocmd.Stderr = os.Stderr require.NoError(t, gocmd.Run()) require.NoError(t, os.Chdir(filepath.Dir(binPath))) require.NoError(t, compressExeAndArgs(zipPath, binPath, []string{})) binInfo, err := os.Stat(binPath) require.NoError(t, err) zipInfo, err := os.Stat(zipPath) require.NoError(t, err) t.Logf("zip size = %d Kb, bin size = %d Kb", zipInfo.Size()/1024, binInfo.Size()/1024) }) } } func TestCompressExeAndArgs(t *testing.T) { tempDir, err := ioutil.TempDir("/tmp", "build-lambda-zip") require.NoError(t, err) defer os.RemoveAll(tempDir) fileNames := []string{"the-exe", "the-config", "other-config"} filePaths := make([]string, len(fileNames)) for i, fileName := range fileNames { filePaths[i] = filepath.Join(tempDir, fileName) f, err := os.Create(filePaths[i]) require.NoError(t, err) _, _ = fmt.Fprintf(f, "Hello file %d!", i) err = f.Close() require.NoError(t, err) } outZipPath := filepath.Join(tempDir, "lambda.zip") err = compressExeAndArgs(outZipPath, filePaths[0], filePaths[1:]) require.NoError(t, err) t.Run("handler exe configured in zip root", func(t *testing.T) { require.NotEqual(t, filePaths[0], filepath.Base(filePaths[0]), "test precondition") zipReader, err := zip.OpenReader(outZipPath) require.NoError(t, err) defer zipReader.Close() for _, zf := range zipReader.File { if zf.Name == filepath.Base(filePaths[0]) { assert.True(t, zf.FileInfo().Mode().IsRegular()) permissions := int(zf.FileInfo().Mode() & 0777) assert.Equal(t, 0111, permissions&0111, "file permissions: %#o, aren't executable", permissions) assert.Equal(t, 0444, permissions&0444, "file permissions: %#o, aren't readable", permissions) return } } t.Fatalf("failed to find handler exe in zip") }) t.Run("boostrap is a symlink to handler exe", func(t *testing.T) { zipReader, err := zip.OpenReader(outZipPath) require.NoError(t, err) defer zipReader.Close() var bootstrap *zip.File for _, f := range zipReader.File { if f.Name == "bootstrap" { bootstrap = f } } require.NotNil(t, bootstrap) assert.Equal(t, 0755|os.ModeSymlink, bootstrap.FileInfo().Mode()) link, err := bootstrap.Open() require.NoError(t, err) defer link.Close() linkTarget, err := ioutil.ReadAll(link) require.NoError(t, err) assert.Equal(t, filepath.Base(filePaths[0]), string(linkTarget)) }) t.Run("resource file paths", func(t *testing.T) { zipReader, err := zip.OpenReader(outZipPath) require.NoError(t, err) defer zipReader.Close() eachFile: for _, path := range filePaths[1:] { for _, zipFileEntry := range zipReader.File { if zipFileEntry.Name == path { continue eachFile } } t.Logf("failed to find resource file %s in zip", path) t.Fail() } }) t.Run("file contents match", func(t *testing.T) { zipReader, err := zip.OpenReader(outZipPath) require.NoError(t, err) defer zipReader.Close() expectedIndex := 0 for _, zf := range zipReader.File { if zf.FileInfo().Mode().IsRegular() { f, err := zf.Open() require.NoError(t, err) defer f.Close() content, err := ioutil.ReadAll(f) require.NoError(t, err) assert.Equal(t, fmt.Sprintf("Hello file %d!", expectedIndex), string(content), "in file: %s", zf.Name) expectedIndex++ } } }) }