github.com/opencontainers/umoci@v0.4.8-0.20240508124516-656e4836fb0d/oci/layer/generate_test.go (about) 1 /* 2 * umoci: Umoci Modifies Open Containers' Images 3 * Copyright (C) 2016-2020 SUSE LLC 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package layer 19 20 import ( 21 "archive/tar" 22 "bytes" 23 "io" 24 "io/ioutil" 25 "os" 26 "path/filepath" 27 "testing" 28 29 "github.com/vbatts/go-mtree" 30 ) 31 32 func TestGenerate(t *testing.T) { 33 dir, err := ioutil.TempDir("", "umoci-TestGenerate") 34 if err != nil { 35 t.Fatal(err) 36 } 37 defer os.RemoveAll(dir) 38 39 // Create some files and other fun things. 40 if err := os.MkdirAll(filepath.Join(dir, "some", "parents"), 0755); err != nil { 41 t.Fatal(err) 42 } 43 if err := ioutil.WriteFile(filepath.Join(dir, "some", "fileunchanged"), []byte("unchanged"), 0644); err != nil { 44 t.Fatal(err) 45 } 46 if err := ioutil.WriteFile(filepath.Join(dir, "some", "parents", "filechanged"), []byte("changed"), 0644); err != nil { 47 t.Fatal(err) 48 } 49 if err := ioutil.WriteFile(filepath.Join(dir, "some", "parents", "deleted"), []byte("deleted"), 0644); err != nil { 50 t.Fatal(err) 51 } 52 53 // Get initial. 54 initDh, err := mtree.Walk(dir, nil, append(mtree.DefaultKeywords, "sha256digest"), nil) 55 if err != nil { 56 t.Fatal(err) 57 } 58 59 if err := ioutil.WriteFile(filepath.Join(dir, "some", "parents", "filechanged"), []byte("new contents"), 0644); err != nil { 60 t.Fatal(err) 61 } 62 if err := os.Remove(filepath.Join(dir, "some", "parents", "deleted")); err != nil { 63 t.Fatal(err) 64 } 65 66 // Get post. 67 postDh, err := mtree.Walk(dir, nil, initDh.UsedKeywords(), nil) 68 if err != nil { 69 t.Fatal(err) 70 } 71 72 diffs, err := mtree.Compare(initDh, postDh, initDh.UsedKeywords()) 73 if err != nil { 74 t.Fatal(err) 75 } 76 77 reader, err := GenerateLayer(dir, diffs, &RepackOptions{}) 78 if err != nil { 79 t.Fatal(err) 80 } 81 defer reader.Close() 82 83 var ( 84 gotDeleted bool 85 gotChanged bool 86 gotDir bool 87 ) 88 89 tr := tar.NewReader(reader) 90 for { 91 hdr, err := tr.Next() 92 if err == io.EOF { 93 break 94 } 95 if err != nil { 96 t.Errorf("unexpected error: %s", err) 97 break 98 } 99 switch hdr.Name { 100 case filepath.Join("some", "parents") + "/": 101 if hdr.Typeflag != tar.TypeDir { 102 t.Errorf("directory suddenly stopped being a directory") 103 } 104 gotDir = true 105 case filepath.Join("some", "parents", ".wh.deleted"): 106 if hdr.Size != 0 { 107 t.Errorf("whiteout file has non-zero size: %d", hdr.Size) 108 } 109 gotDeleted = true 110 case filepath.Join("some", "parents", "filechanged"): 111 contents, err := ioutil.ReadAll(tr) 112 if err != nil { 113 t.Errorf("unexpected error reading changed file: %s", err) 114 } 115 if !bytes.Equal(contents, []byte("new contents")) { 116 t.Errorf("did not get expected contents: %s", contents) 117 } 118 gotChanged = true 119 case filepath.Join("some", "fileunchanged"): 120 t.Errorf("got unchanged file in diff layer!") 121 default: 122 t.Errorf("got unexpected file: %s", hdr.Name) 123 } 124 } 125 126 if !gotDeleted { 127 t.Errorf("did not get deleted file!") 128 } 129 if !gotChanged { 130 t.Errorf("did not get changed file!") 131 } 132 if !gotDir { 133 // This for some reason happen on Travis even though it shouldn't. It's 134 // probably caused by some AUFS fun times that I don't want to debug. 135 t.Logf("did not get directory!") 136 } 137 } 138 139 // Make sure that opencontainers/umoci#33 doesn't regress. 140 func TestGenerateMissingFileError(t *testing.T) { 141 dir, err := ioutil.TempDir("", "umoci-TestGenerateError") 142 if err != nil { 143 t.Fatal(err) 144 } 145 defer os.RemoveAll(dir) 146 147 // Create some files and other fun things. 148 if err := os.MkdirAll(filepath.Join(dir, "some", "parents"), 0755); err != nil { 149 t.Fatal(err) 150 } 151 if err := ioutil.WriteFile(filepath.Join(dir, "some", "fileunchanged"), []byte("unchanged"), 0644); err != nil { 152 t.Fatal(err) 153 } 154 if err := ioutil.WriteFile(filepath.Join(dir, "some", "parents", "filechanged"), []byte("changed"), 0644); err != nil { 155 t.Fatal(err) 156 } 157 if err := ioutil.WriteFile(filepath.Join(dir, "some", "parents", "deleted"), []byte("deleted"), 0644); err != nil { 158 t.Fatal(err) 159 } 160 161 // Get initial from the main directory. 162 initDh, err := mtree.Walk(dir, nil, append(mtree.DefaultKeywords, "sha256digest"), nil) 163 if err != nil { 164 t.Fatal(err) 165 } 166 167 if err := ioutil.WriteFile(filepath.Join(dir, "some", "parents", "filechanged"), []byte("new contents"), 0644); err != nil { 168 t.Fatal(err) 169 } 170 if err := os.Remove(filepath.Join(dir, "some", "parents", "deleted")); err != nil { 171 t.Fatal(err) 172 } 173 174 // Get post. 175 postDh, err := mtree.Walk(dir, nil, initDh.UsedKeywords(), nil) 176 if err != nil { 177 t.Fatal(err) 178 } 179 180 diffs, err := mtree.Compare(initDh, postDh, initDh.UsedKeywords()) 181 if err != nil { 182 t.Fatal(err) 183 } 184 185 // Remove the changed file after getting the diffs. This will cause an error. 186 if err := os.Remove(filepath.Join(dir, "some", "parents", "filechanged")); err != nil { 187 t.Fatal(err) 188 } 189 190 // Generate a layer where the changed file is missing after the diff. 191 reader, err := GenerateLayer(dir, diffs, &RepackOptions{}) 192 if err != nil { 193 t.Fatal(err) 194 } 195 defer reader.Close() 196 197 tr := tar.NewReader(reader) 198 for { 199 _, err := tr.Next() 200 if err == io.EOF { 201 t.Errorf("got EOF, not a proper error!") 202 } 203 if err != nil { 204 break 205 } 206 } 207 } 208 209 // Make sure that opencontainers/umoci#33 doesn't regress. 210 func TestGenerateWrongRootError(t *testing.T) { 211 dir, err := ioutil.TempDir("", "umoci-TestGenerateError") 212 if err != nil { 213 t.Fatal(err) 214 } 215 defer os.RemoveAll(dir) 216 217 // Create some files and other fun things. 218 if err := os.MkdirAll(filepath.Join(dir, "some", "parents"), 0755); err != nil { 219 t.Fatal(err) 220 } 221 if err := ioutil.WriteFile(filepath.Join(dir, "some", "fileunchanged"), []byte("unchanged"), 0644); err != nil { 222 t.Fatal(err) 223 } 224 if err := ioutil.WriteFile(filepath.Join(dir, "some", "parents", "filechanged"), []byte("changed"), 0644); err != nil { 225 t.Fatal(err) 226 } 227 if err := ioutil.WriteFile(filepath.Join(dir, "some", "parents", "deleted"), []byte("deleted"), 0644); err != nil { 228 t.Fatal(err) 229 } 230 231 // Get initial from the main directory. 232 initDh, err := mtree.Walk(dir, nil, append(mtree.DefaultKeywords, "sha256digest"), nil) 233 if err != nil { 234 t.Fatal(err) 235 } 236 237 if err := ioutil.WriteFile(filepath.Join(dir, "some", "parents", "filechanged"), []byte("new contents"), 0644); err != nil { 238 t.Fatal(err) 239 } 240 if err := os.Remove(filepath.Join(dir, "some", "parents", "deleted")); err != nil { 241 t.Fatal(err) 242 } 243 244 // Get post. 245 postDh, err := mtree.Walk(dir, nil, initDh.UsedKeywords(), nil) 246 if err != nil { 247 t.Fatal(err) 248 } 249 250 diffs, err := mtree.Compare(initDh, postDh, initDh.UsedKeywords()) 251 if err != nil { 252 t.Fatal(err) 253 } 254 255 // Generate a layer with the wrong root directory. 256 reader, err := GenerateLayer(filepath.Join(dir, "some"), diffs, &RepackOptions{}) 257 if err != nil { 258 t.Fatal(err) 259 } 260 defer reader.Close() 261 262 tr := tar.NewReader(reader) 263 for { 264 _, err := tr.Next() 265 if err == io.EOF { 266 t.Errorf("got EOF, not a proper error!") 267 } 268 if err != nil { 269 break 270 } 271 } 272 }