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