github.com/google/osv-scalibr@v0.4.1/common/linux/dpkg/dpkg_test.go (about) 1 // Copyright 2025 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package dpkg 16 17 import ( 18 "context" 19 "errors" 20 "io" 21 "sort" 22 "testing" 23 24 "github.com/google/go-cmp/cmp" 25 "github.com/google/osv-scalibr/common/linux/dpkg/testing/dpkgutil" 26 scalibrfs "github.com/google/osv-scalibr/fs" 27 ) 28 29 func TestConffilePathIterator(t *testing.T) { 30 tests := []struct { 31 name string 32 conffiles map[string]string 33 want []string 34 wantOpen []string 35 }{ 36 { 37 name: "empty info dir", 38 conffiles: map[string]string{}, 39 want: nil, 40 }, 41 { 42 name: "No_conffiles_files", 43 conffiles: map[string]string{ 44 "foo.txt": "foocontents", 45 }, 46 want: nil, 47 }, 48 { 49 name: "one_empty_conffiles_file", 50 conffiles: map[string]string{ 51 "foo.conffiles": "", 52 }, 53 want: []string{""}, 54 }, 55 { 56 name: "one_conffiles_file_with_lines", 57 conffiles: map[string]string{ 58 "foo.conffiles": "/foo\n/bar", 59 }, 60 want: []string{"/foo", "/bar"}, 61 }, 62 { 63 name: "two_conffiles_files", 64 conffiles: map[string]string{ 65 "foo.conffiles": "/foo\n/bar", 66 "baz.conffiles": "/baz", 67 }, 68 want: []string{"/foo", "/bar", "/baz"}, 69 }, 70 { 71 name: "conffiles_file_with_irrelevant_files", 72 conffiles: map[string]string{ 73 "foo.conffiles": "/foo\n/bar", 74 "baz.txt": "bazcontents", 75 }, 76 want: []string{"/foo", "/bar"}, 77 }, 78 } 79 80 for _, tt := range tests { 81 t.Run(tt.name, func(t *testing.T) { 82 root := dpkgutil.SetupDPKGInfo(t, tt.conffiles, false) 83 fs := scalibrfs.RealFSScanRoot(root).FS 84 85 it, err := NewConffilePathIterator(fs) 86 if err != nil { 87 t.Fatalf("NewConffilePathIterator() returned err: %v", err) 88 } 89 defer it.Close() 90 91 var got []string 92 for { 93 path, err := it.Next(t.Context()) 94 if errors.Is(err, io.EOF) { 95 break 96 } 97 if err != nil { 98 t.Fatalf("it.Next() returned err: %v", err) 99 } 100 got = append(got, path) 101 } 102 103 sort.Strings(got) 104 sort.Strings(tt.want) 105 106 if diff := cmp.Diff(tt.want, got); diff != "" { 107 t.Errorf("ConffilePathIterator returned diff (-want +got):\n%s", diff) 108 } 109 }) 110 } 111 } 112 113 func TestConffilePathIteratorContextCancel(t *testing.T) { 114 root := dpkgutil.SetupDPKGInfo(t, map[string]string{ 115 "foo.conffiles": "/foo\n/bar", 116 }, false) 117 fs := scalibrfs.RealFSScanRoot(root).FS 118 119 ctx, cancel := context.WithCancel(t.Context()) 120 it, err := NewConffilePathIterator(fs) 121 if err != nil { 122 t.Fatalf("NewConffilePathIterator() returned err: %v", err) 123 } 124 defer it.Close() 125 cancel() 126 _, err = it.Next(ctx) 127 if !errors.Is(err, context.Canceled) { 128 t.Errorf("it.Next() after context cancel: got err %v, want context.Canceled", err) 129 } 130 } 131 132 func TestConffilePathIteratorMissingInfoDir(t *testing.T) { 133 sfs := scalibrfs.RealFSScanRoot(t.TempDir()).FS 134 it, err := NewConffilePathIterator(sfs) 135 if err != nil { 136 t.Fatalf("NewConffilePathIterator() with missing info dir: got err %v, want nil", err) 137 } 138 defer it.Close() 139 _, err = it.Next(t.Context()) 140 if !errors.Is(err, io.EOF) { 141 t.Errorf("it.Next() with missing info dir: got err %v, want io.EOF", err) 142 } 143 } 144 145 func TestListFilePathIterator(t *testing.T) { 146 tests := []struct { 147 name string 148 list map[string]string 149 want []string 150 wantOpen []string 151 }{ 152 { 153 name: "empty_info_dir", 154 list: map[string]string{}, 155 want: nil, 156 }, 157 { 158 name: "No_list_files", 159 list: map[string]string{ 160 "foo.txt": "foocontents", 161 }, 162 want: nil, 163 }, 164 { 165 name: "one_empty_list_file", 166 list: map[string]string{ 167 "foo.list": "", 168 }, 169 want: []string{""}, 170 }, 171 { 172 name: "one_list_file_with_lines", 173 list: map[string]string{ 174 "foo.list": "/foo\n/bar", 175 }, 176 want: []string{"/foo", "/bar"}, 177 }, 178 { 179 name: "two_list_files", 180 list: map[string]string{ 181 "foo.list": "/foo\n/bar", 182 "baz.list": "/baz", 183 }, 184 want: []string{"/foo", "/bar", "/baz"}, 185 }, 186 { 187 name: "list_file_with_irrelevant_files", 188 list: map[string]string{ 189 "foo.list": "/foo\n/bar", 190 "baz.txt": "bazcontents", 191 }, 192 want: []string{"/foo", "/bar"}, 193 }, 194 } 195 196 for _, tt := range tests { 197 t.Run(tt.name, func(t *testing.T) { 198 root := dpkgutil.SetupDPKGInfo(t, tt.list, false) 199 fs := scalibrfs.RealFSScanRoot(root).FS 200 201 it, err := NewListFilePathIterator(fs) 202 if err != nil { 203 t.Fatalf("NewFileIterator() returned err: %v", err) 204 } 205 defer it.Close() 206 207 var got []string 208 for { 209 path, err := it.Next(t.Context()) 210 if errors.Is(err, io.EOF) { 211 break 212 } 213 if err != nil { 214 t.Fatalf("it.Next() returned err: %v", err) 215 } 216 got = append(got, path) 217 } 218 219 sort.Strings(got) 220 sort.Strings(tt.want) 221 222 if diff := cmp.Diff(tt.want, got); diff != "" { 223 t.Errorf("FileIterator returned diff (-want +got):\n%s", diff) 224 } 225 }) 226 } 227 } 228 229 func TestListFilePathIteratorContextCancel(t *testing.T) { 230 root := dpkgutil.SetupDPKGInfo(t, map[string]string{ 231 "foo.list": "/foo\n/bar", 232 }, false) 233 fs := scalibrfs.RealFSScanRoot(root).FS 234 235 ctx, cancel := context.WithCancel(t.Context()) 236 it, err := NewListFilePathIterator(fs) 237 if err != nil { 238 t.Fatalf("NewFileIterator() returned err: %v", err) 239 } 240 defer it.Close() 241 cancel() 242 _, err = it.Next(ctx) 243 if !errors.Is(err, context.Canceled) { 244 t.Errorf("it.Next() after context cancel: got err %v, want context.Canceled", err) 245 } 246 } 247 248 func TestListFilePathIteratorMissingInfoDir(t *testing.T) { 249 sfs := scalibrfs.RealFSScanRoot(t.TempDir()).FS 250 it, err := NewListFilePathIterator(sfs) 251 if err != nil { 252 t.Fatalf("NewFileIterator() with missing info dir: got err %v, want nil", err) 253 } 254 defer it.Close() 255 _, err = it.Next(t.Context()) 256 if !errors.Is(err, io.EOF) { 257 t.Errorf("it.Next() with missing info dir: got err %v, want io.EOF", err) 258 } 259 }