github.com/opencontainers/umoci@v0.4.8-0.20240508124516-656e4836fb0d/pkg/mtreefilter/mask_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 mtreefilter 19 20 import ( 21 "io/ioutil" 22 "os" 23 "path/filepath" 24 "testing" 25 26 "github.com/vbatts/go-mtree" 27 ) 28 29 func isParent(a, b string) bool { 30 a = filepath.Clean(a) 31 b = filepath.Clean(b) 32 33 for a != b && b != filepath.Dir(b) { 34 b = filepath.Dir(b) 35 } 36 return a == b 37 } 38 39 func TestMaskDeltas(t *testing.T) { 40 dir, err := ioutil.TempDir("", "TestMaskDeltas-") 41 if err != nil { 42 t.Fatal(err) 43 } 44 defer os.RemoveAll(dir) 45 46 mtreeKeywords := append(mtree.DefaultKeywords, "sha256digest") 47 48 // Create some files. 49 if err != ioutil.WriteFile(filepath.Join(dir, "file1"), []byte("contents"), 0644) { 50 t.Fatal(err) 51 } 52 if err != ioutil.WriteFile(filepath.Join(dir, "file2"), []byte("another content"), 0644) { 53 t.Fatal(err) 54 } 55 if err != os.MkdirAll(filepath.Join(dir, "dir", "child"), 0755) { 56 t.Fatal(err) 57 } 58 if err != os.MkdirAll(filepath.Join(dir, "dir", "child2"), 0755) { 59 t.Fatal(err) 60 } 61 if err != ioutil.WriteFile(filepath.Join(dir, "dir", "file 3"), []byte("more content"), 0644) { 62 t.Fatal(err) 63 } 64 if err != ioutil.WriteFile(filepath.Join(dir, "dir", "child2", "4 files"), []byte("very content"), 0644) { 65 t.Fatal(err) 66 } 67 68 // Generate a diff. 69 originalDh, err := mtree.Walk(dir, nil, mtreeKeywords, nil) 70 if err != nil { 71 t.Fatal(err) 72 } 73 74 // Modify the root. 75 if err := os.RemoveAll(filepath.Join(dir, "file2")); err != nil { 76 t.Fatal(err) 77 } 78 if err := ioutil.WriteFile(filepath.Join(dir, "dir", "new"), []byte("more content"), 0755); err != nil { 79 t.Fatal(err) 80 } 81 if err := ioutil.WriteFile(filepath.Join(dir, "file1"), []byte("different contents"), 0666); err != nil { 82 t.Fatal(err) 83 } 84 85 // Generate the set of diffs. 86 newDh, err := mtree.Walk(dir, nil, mtreeKeywords, nil) 87 if err != nil { 88 t.Fatal(err) 89 } 90 diff, err := mtree.Compare(originalDh, newDh, mtreeKeywords) 91 if err != nil { 92 t.Fatal(err) 93 } 94 95 for _, test := range []struct { 96 paths []string 97 }{ 98 {nil}, 99 {[]string{"/"}}, 100 {[]string{"dir"}}, 101 {[]string{filepath.Join("dir", "child2")}}, 102 {[]string{"file2"}}, 103 {[]string{"/", "file2"}}, 104 {[]string{"file2", filepath.Join("dir", "child2")}}, 105 } { 106 simpleDiff := FilterDeltas(diff, MaskFilter(test.paths)) 107 for _, delta := range simpleDiff { 108 if len(test.paths) == 0 { 109 if len(simpleDiff) != len(diff) { 110 t.Errorf("expected diff={} to give %d got %d", len(diff), len(simpleDiff)) 111 } 112 } else { 113 found := false 114 for _, path := range test.paths { 115 if !isParent(path, delta.Path()) { 116 found = true 117 } 118 } 119 if !found { 120 t.Errorf("expected one of %v to not be a parent of %q", test.paths, delta.Path()) 121 } 122 } 123 } 124 } 125 } 126 127 func TestSimplifyFilter(t *testing.T) { 128 dir, err := ioutil.TempDir("", "TestSimplifyFilter-") 129 if err != nil { 130 t.Fatal(err) 131 } 132 defer os.RemoveAll(dir) 133 134 mtreeKeywords := append(mtree.DefaultKeywords, "sha256digest") 135 136 // Create some nested directories we can remove. 137 if err != os.MkdirAll(filepath.Join(dir, "some", "path", "to", "remove"), 0755) { 138 t.Fatal(err) 139 } 140 if err != ioutil.WriteFile(filepath.Join(dir, "some", "path", "to", "remove", "child"), []byte("very content"), 0644) { 141 t.Fatal(err) 142 } 143 144 // Generate a diff. 145 originalDh, err := mtree.Walk(dir, nil, mtreeKeywords, nil) 146 if err != nil { 147 t.Fatal(err) 148 } 149 150 // Modify the root. 151 if err := os.RemoveAll(filepath.Join(dir, "some")); err != nil { 152 t.Fatal(err) 153 } 154 155 // Generate the set of diffs. 156 newDh, err := mtree.Walk(dir, nil, mtreeKeywords, nil) 157 if err != nil { 158 t.Fatal(err) 159 } 160 diff, err := mtree.Compare(originalDh, newDh, mtreeKeywords) 161 if err != nil { 162 t.Fatal(err) 163 } 164 165 // We expect to see a deletion for each entry. 166 var sawDeletions int 167 for _, delta := range diff { 168 if delta.Type() == mtree.Missing { 169 sawDeletions++ 170 } 171 } 172 if sawDeletions != 5 { 173 t.Errorf("expected to see 5 deletions with stock Compare, saw %v", sawDeletions) 174 } 175 176 // Simplify the diffs. 177 simpleDiff := FilterDeltas(diff, SimplifyFilter(diff)) 178 if len(simpleDiff) >= len(diff) { 179 t.Errorf("expected simplified diff to be shorter (%v >= %v)", len(simpleDiff), len(diff)) 180 } 181 var sawSimpleDeletions int 182 for _, delta := range simpleDiff { 183 if delta.Type() == mtree.Missing { 184 sawSimpleDeletions++ 185 } 186 } 187 if sawSimpleDeletions != 1 { 188 t.Errorf("expected to see 1 deletion with simplified filter, saw %v", sawSimpleDeletions) 189 } 190 }