github.com/kaituanwang/hyperledger@v2.0.1+incompatible/core/chaincode/platforms/util/writer_test.go (about) 1 /* 2 Copyright London Stock Exchange 2016 All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package util 8 9 import ( 10 "archive/tar" 11 "bytes" 12 "compress/gzip" 13 "errors" 14 "fmt" 15 "io" 16 "io/ioutil" 17 "os" 18 "path/filepath" 19 "runtime" 20 "testing" 21 22 "github.com/stretchr/testify/assert" 23 "github.com/stretchr/testify/require" 24 ) 25 26 func TestWriteFileToPackage(t *testing.T) { 27 tempDir, err := ioutil.TempDir("", "utiltest") 28 require.NoError(t, err) 29 defer os.RemoveAll(tempDir) 30 31 buf := bytes.NewBuffer(nil) 32 gw := gzip.NewWriter(buf) 33 tw := tar.NewWriter(gw) 34 35 // Create a file and write it to tar writer 36 filename := "test.txt" 37 filecontent := "hello" 38 filePath := filepath.Join(tempDir, filename) 39 err = ioutil.WriteFile(filePath, bytes.NewBufferString(filecontent).Bytes(), 0600) 40 require.NoError(t, err, "Error creating file %s", filePath) 41 42 err = WriteFileToPackage(filePath, filename, tw) 43 assert.NoError(t, err, "Error returned by WriteFileToPackage while writing existing file") 44 tw.Close() 45 gw.Close() 46 47 // Read the file from the archive and check the name and file content 48 r := bytes.NewReader(buf.Bytes()) 49 gr, err := gzip.NewReader(r) 50 require.NoError(t, err, "Error creating a gzip reader") 51 defer gr.Close() 52 53 tr := tar.NewReader(gr) 54 header, err := tr.Next() 55 require.NoError(t, err, "Error getting the file from the tar") 56 assert.Equal(t, filename, header.Name, "filename read from archive does not match what was added") 57 58 b := make([]byte, 5) 59 n, err := tr.Read(b) 60 assert.Equal(t, 5, n) 61 assert.True(t, err == nil || err == io.EOF, "Error reading file from the archive") // go1.10 returns io.EOF 62 assert.Equal(t, filecontent, string(b), "file content from archive does not equal original content") 63 64 t.Run("non existent file", func(t *testing.T) { 65 tw := tar.NewWriter(&bytes.Buffer{}) 66 err := WriteFileToPackage("missing-file", "", tw) 67 assert.Error(t, err, "expected error writing a non existent file") 68 assert.Contains(t, err.Error(), "missing-file") 69 }) 70 71 t.Run("closed tar writer", func(t *testing.T) { 72 tw := tar.NewWriter(&bytes.Buffer{}) 73 tw.Close() 74 err := WriteFileToPackage(filePath, "test.txt", tw) 75 assert.EqualError(t, err, fmt.Sprintf("failed to write header for %s: archive/tar: write after close", filePath)) 76 }) 77 78 t.Run("stream write failure", func(t *testing.T) { 79 failWriter := &failingWriter{failAt: 514} 80 tw := tar.NewWriter(failWriter) 81 err := WriteFileToPackage(filePath, "test.txt", tw) 82 assert.EqualError(t, err, fmt.Sprintf("failed to write %s as test.txt: failed-the-write", filePath)) 83 }) 84 } 85 86 type failingWriter struct { 87 written int 88 failAt int 89 } 90 91 func (f *failingWriter) Write(b []byte) (int, error) { 92 f.written += len(b) 93 if f.written < f.failAt { 94 return len(b), nil 95 } 96 return 0, errors.New("failed-the-write") 97 } 98 99 // Success case 1: with include file types and without exclude dir 100 func TestWriteFolderToTarPackage1(t *testing.T) { 101 srcPath := filepath.Join("testdata", "sourcefiles") 102 filePath := "src/src/Hello.java" 103 includeFileTypes := map[string]bool{ 104 ".java": true, 105 } 106 excludeFileTypes := map[string]bool{} 107 108 tarBytes := createTestTar(t, srcPath, []string{}, includeFileTypes, excludeFileTypes) 109 110 // Read the file from the archive and check the name 111 entries := tarContents(t, tarBytes) 112 assert.ElementsMatch(t, []string{filePath}, entries, "archive should only contain one file") 113 } 114 115 // Success case 2: with exclude dir and no include file types 116 func TestWriteFolderToTarPackage2(t *testing.T) { 117 srcPath := filepath.Join("testdata", "sourcefiles") 118 tarBytes := createTestTar(t, srcPath, []string{"src"}, nil, nil) 119 120 entries := tarContents(t, tarBytes) 121 assert.ElementsMatch(t, []string{"src/artifact.xml", "META-INF/statedb/couchdb/indexes/indexOwner.json"}, entries) 122 } 123 124 // Success case 3: with chaincode metadata in META-INF directory 125 func TestWriteFolderToTarPackage3(t *testing.T) { 126 srcPath := filepath.Join("testdata", "sourcefiles") 127 filePath := "META-INF/statedb/couchdb/indexes/indexOwner.json" 128 129 tarBytes := createTestTar(t, srcPath, []string{}, nil, nil) 130 131 // Read the files from the archive and check for the metadata index file 132 entries := tarContents(t, tarBytes) 133 assert.Contains(t, entries, filePath, "should have found statedb index artifact in META-INF directory") 134 } 135 136 // Success case 4: with chaincode metadata in META-INF directory, pass trailing slash in srcPath 137 func TestWriteFolderToTarPackage4(t *testing.T) { 138 srcPath := filepath.Join("testdata", "sourcefiles") + string(filepath.Separator) 139 filePath := "META-INF/statedb/couchdb/indexes/indexOwner.json" 140 141 tarBytes := createTestTar(t, srcPath, []string{}, nil, nil) 142 143 // Read the files from the archive and check for the metadata index file 144 entries := tarContents(t, tarBytes) 145 assert.Contains(t, entries, filePath, "should have found statedb index artifact in META-INF directory") 146 } 147 148 // Success case 5: with hidden files in META-INF directory (hidden files get ignored) 149 func TestWriteFolderToTarPackage5(t *testing.T) { 150 srcPath := filepath.Join("testdata", "sourcefiles") 151 filePath := "META-INF/.hiddenfile" 152 153 assert.FileExists(t, filepath.Join(srcPath, "META-INF", ".hiddenfile")) 154 155 tarBytes := createTestTar(t, srcPath, []string{}, nil, nil) 156 157 // Read the files from the archive and check for the metadata index file 158 entries := tarContents(t, tarBytes) 159 assert.NotContains(t, entries, filePath, "should not contain .hiddenfile in META-INF directory") 160 } 161 162 // Failure case 1: no files in directory 163 func TestWriteFolderToTarPackageFailure1(t *testing.T) { 164 srcPath, err := ioutil.TempDir("", "utiltest") 165 require.NoError(t, err) 166 defer os.RemoveAll(srcPath) 167 168 tw := tar.NewWriter(bytes.NewBuffer(nil)) 169 defer tw.Close() 170 171 err = WriteFolderToTarPackage(tw, srcPath, []string{}, nil, nil) 172 assert.Contains(t, err.Error(), "no source files found") 173 } 174 175 // Failure case 2: with invalid chaincode metadata in META-INF directory 176 func TestWriteFolderToTarPackageFailure2(t *testing.T) { 177 srcPath := filepath.Join("testdata", "BadMetadataInvalidIndex") 178 buf := bytes.NewBuffer(nil) 179 gw := gzip.NewWriter(buf) 180 tw := tar.NewWriter(gw) 181 182 err := WriteFolderToTarPackage(tw, srcPath, []string{}, nil, nil) 183 assert.Error(t, err, "Should have received error writing folder to package") 184 assert.Contains(t, err.Error(), "Index metadata file [META-INF/statedb/couchdb/indexes/bad.json] is not a valid JSON") 185 186 tw.Close() 187 gw.Close() 188 } 189 190 // Failure case 3: with unexpected content in META-INF directory 191 func TestWriteFolderToTarPackageFailure3(t *testing.T) { 192 srcPath := filepath.Join("testdata", "BadMetadataUnexpectedFolderContent") 193 buf := bytes.NewBuffer(nil) 194 gw := gzip.NewWriter(buf) 195 tw := tar.NewWriter(gw) 196 197 err := WriteFolderToTarPackage(tw, srcPath, []string{}, nil, nil) 198 assert.Error(t, err, "Should have received error writing folder to package") 199 assert.Contains(t, err.Error(), "metadata file path must begin with META-INF/statedb") 200 201 tw.Close() 202 gw.Close() 203 } 204 205 // Failure case 4: with lstat failed 206 func Test_WriteFolderToTarPackageFailure4(t *testing.T) { 207 if runtime.GOOS == "windows" { 208 t.Skip("unable to chmod execute permission on windows directory") 209 } 210 211 tempDir, err := ioutil.TempDir("", "WriteFolderToTarPackageFailure4BadFileMode") 212 require.NoError(t, err) 213 defer os.RemoveAll(tempDir) 214 testFile := filepath.Join(tempDir, "test.java") 215 err = ioutil.WriteFile(testFile, []byte("Content"), 0644) 216 require.NoError(t, err, "Error creating file", testFile) 217 err = os.Chmod(tempDir, 0644) 218 require.NoError(t, err) 219 220 buf := bytes.NewBuffer(nil) 221 tw := tar.NewWriter(buf) 222 defer tw.Close() 223 224 err = WriteFolderToTarPackage(tw, tempDir, []string{}, nil, nil) 225 assert.Error(t, err, "Should have received error writing folder to package") 226 assert.Contains(t, err.Error(), "permission denied") 227 228 err = os.Chmod(tempDir, 0700) 229 require.NoError(t, err) 230 } 231 232 func createTestTar(t *testing.T, srcPath string, excludeDir []string, includeFileTypeMap map[string]bool, excludeFileTypeMap map[string]bool) []byte { 233 buf := bytes.NewBuffer(nil) 234 gw := gzip.NewWriter(buf) 235 tw := tar.NewWriter(gw) 236 237 err := WriteFolderToTarPackage(tw, srcPath, excludeDir, includeFileTypeMap, excludeFileTypeMap) 238 assert.NoError(t, err, "Error writing folder to package") 239 240 tw.Close() 241 gw.Close() 242 return buf.Bytes() 243 } 244 245 func tarContents(t *testing.T, buf []byte) []string { 246 br := bytes.NewReader(buf) 247 gr, err := gzip.NewReader(br) 248 require.NoError(t, err) 249 defer gr.Close() 250 251 tr := tar.NewReader(gr) 252 253 var entries []string 254 for { 255 header, err := tr.Next() 256 if err == io.EOF { // No more entries 257 break 258 } 259 require.NoError(t, err, "failed to get next entry") 260 entries = append(entries, header.Name) 261 } 262 263 return entries 264 }