github.com/Foodji/aws-lambda-go@v1.20.2/cmd/build-lambda-zip/main_test.go (about)

     1  // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved
     2  
     3  package main
     4  
     5  import (
     6  	"archive/zip"
     7  	"fmt"
     8  	"io/ioutil"
     9  	"os"
    10  	"os/exec"
    11  	"path"
    12  	"path/filepath"
    13  	"testing"
    14  
    15  	"github.com/stretchr/testify/assert"
    16  	"github.com/stretchr/testify/require"
    17  )
    18  
    19  func TestSizes(t *testing.T) {
    20  	if testing.Short() {
    21  		t.Skip()
    22  		return
    23  	}
    24  	t.Log("test how different arguments affect binary and archive sizes")
    25  	cases := []struct {
    26  		file string
    27  		args []string
    28  	}{
    29  		{"testdata/apigw.go", nil},
    30  		{"testdata/noop.go", nil},
    31  		{"testdata/noop.go", []string{"-tags", "lambda.norpc"}},
    32  		{"testdata/noop.go", []string{"-ldflags=-s -w"}},
    33  		{"testdata/noop.go", []string{"-tags", "lambda.norpc", "-ldflags=-s -w"}},
    34  	}
    35  	testDir, err := os.Getwd()
    36  	require.NoError(t, err)
    37  	tempDir, err := ioutil.TempDir("/tmp", "build-lambda-zip")
    38  	require.NoError(t, err)
    39  	for _, test := range cases {
    40  		require.NoError(t, os.Chdir(testDir))
    41  		testName := fmt.Sprintf("%s, %v", test.file, test.args)
    42  		t.Run(testName, func(t *testing.T) {
    43  			binPath := path.Join(tempDir, test.file+".bin")
    44  			zipPath := path.Join(tempDir, test.file+".zip")
    45  
    46  			buildArgs := []string{"build", "-o", binPath}
    47  			buildArgs = append(buildArgs, test.args...)
    48  			buildArgs = append(buildArgs, test.file)
    49  
    50  			gocmd := exec.Command("go", buildArgs...)
    51  			gocmd.Env = append(os.Environ(), "GOOS=linux")
    52  			gocmd.Stderr = os.Stderr
    53  			require.NoError(t, gocmd.Run())
    54  			require.NoError(t, os.Chdir(filepath.Dir(binPath)))
    55  			require.NoError(t, compressExeAndArgs(zipPath, binPath, []string{}))
    56  
    57  			binInfo, err := os.Stat(binPath)
    58  			require.NoError(t, err)
    59  			zipInfo, err := os.Stat(zipPath)
    60  			require.NoError(t, err)
    61  
    62  			t.Logf("zip size = %d Kb, bin size = %d Kb", zipInfo.Size()/1024, binInfo.Size()/1024)
    63  		})
    64  	}
    65  
    66  }
    67  
    68  func TestCompressExeAndArgs(t *testing.T) {
    69  	tempDir, err := ioutil.TempDir("/tmp", "build-lambda-zip")
    70  	require.NoError(t, err)
    71  	defer os.RemoveAll(tempDir)
    72  
    73  	fileNames := []string{"the-exe", "the-config", "other-config"}
    74  	filePaths := make([]string, len(fileNames))
    75  	for i, fileName := range fileNames {
    76  		filePaths[i] = filepath.Join(tempDir, fileName)
    77  		f, err := os.Create(filePaths[i])
    78  		require.NoError(t, err)
    79  		_, _ = fmt.Fprintf(f, "Hello file %d!", i)
    80  		err = f.Close()
    81  		require.NoError(t, err)
    82  	}
    83  	outZipPath := filepath.Join(tempDir, "lambda.zip")
    84  
    85  	err = compressExeAndArgs(outZipPath, filePaths[0], filePaths[1:])
    86  	require.NoError(t, err)
    87  
    88  	t.Run("handler exe configured in zip root", func(t *testing.T) {
    89  		require.NotEqual(t, filePaths[0], filepath.Base(filePaths[0]), "test precondition")
    90  		zipReader, err := zip.OpenReader(outZipPath)
    91  		require.NoError(t, err)
    92  		defer zipReader.Close()
    93  		for _, zf := range zipReader.File {
    94  			if zf.Name == filepath.Base(filePaths[0]) {
    95  				assert.True(t, zf.FileInfo().Mode().IsRegular())
    96  				permissions := int(zf.FileInfo().Mode() & 0777)
    97  				assert.Equal(t, 0111, permissions&0111, "file permissions: %#o, aren't executable", permissions)
    98  				assert.Equal(t, 0444, permissions&0444, "file permissions: %#o, aren't readable", permissions)
    99  				return
   100  			}
   101  		}
   102  		t.Fatalf("failed to find handler exe in zip")
   103  	})
   104  
   105  	t.Run("boostrap is a symlink to handler exe", func(t *testing.T) {
   106  		zipReader, err := zip.OpenReader(outZipPath)
   107  		require.NoError(t, err)
   108  		defer zipReader.Close()
   109  		var bootstrap *zip.File
   110  		for _, f := range zipReader.File {
   111  			if f.Name == "bootstrap" {
   112  				bootstrap = f
   113  			}
   114  		}
   115  		require.NotNil(t, bootstrap)
   116  		assert.Equal(t, 0755|os.ModeSymlink, bootstrap.FileInfo().Mode())
   117  		link, err := bootstrap.Open()
   118  		require.NoError(t, err)
   119  		defer link.Close()
   120  		linkTarget, err := ioutil.ReadAll(link)
   121  		require.NoError(t, err)
   122  		assert.Equal(t, filepath.Base(filePaths[0]), string(linkTarget))
   123  	})
   124  
   125  	t.Run("resource file paths", func(t *testing.T) {
   126  		zipReader, err := zip.OpenReader(outZipPath)
   127  		require.NoError(t, err)
   128  		defer zipReader.Close()
   129  	eachFile:
   130  		for _, path := range filePaths[1:] {
   131  			for _, zipFileEntry := range zipReader.File {
   132  				if zipFileEntry.Name == path {
   133  					continue eachFile
   134  				}
   135  			}
   136  			t.Logf("failed to find resource file %s in zip", path)
   137  			t.Fail()
   138  		}
   139  	})
   140  
   141  	t.Run("file contents match", func(t *testing.T) {
   142  		zipReader, err := zip.OpenReader(outZipPath)
   143  		require.NoError(t, err)
   144  		defer zipReader.Close()
   145  		expectedIndex := 0
   146  		for _, zf := range zipReader.File {
   147  			if zf.FileInfo().Mode().IsRegular() {
   148  				f, err := zf.Open()
   149  				require.NoError(t, err)
   150  				defer f.Close()
   151  				content, err := ioutil.ReadAll(f)
   152  				require.NoError(t, err)
   153  				assert.Equal(t, fmt.Sprintf("Hello file %d!", expectedIndex), string(content), "in file: %s", zf.Name)
   154  				expectedIndex++
   155  			}
   156  		}
   157  	})
   158  
   159  }