github.com/google/osv-scalibr@v0.4.1/testing/fakeenricher/fake_enricher_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 fakeenricher_test 16 17 import ( 18 "io/fs" 19 "testing" 20 "testing/fstest" 21 22 "github.com/google/go-cmp/cmp" 23 "github.com/google/go-cmp/cmp/cmpopts" 24 "github.com/google/osv-scalibr/enricher" 25 "github.com/google/osv-scalibr/extractor" 26 scalibrfs "github.com/google/osv-scalibr/fs" 27 "github.com/google/osv-scalibr/inventory" 28 "github.com/google/osv-scalibr/plugin" 29 "github.com/google/osv-scalibr/testing/fakeenricher" 30 osvpb "github.com/ossf/osv-schema/bindings/go/osvschema" 31 "google.golang.org/protobuf/testing/protocmp" 32 ) 33 34 func TestName(t *testing.T) { 35 tests := []struct { 36 name string 37 cfg *fakeenricher.Config 38 }{ 39 { 40 name: "no_name", 41 cfg: &fakeenricher.Config{}, 42 }, 43 { 44 name: "name", 45 cfg: &fakeenricher.Config{Name: "some enricher"}, 46 }, 47 } 48 49 for _, tc := range tests { 50 t.Run(tc.name, func(t *testing.T) { 51 e := fakeenricher.MustNew(t, tc.cfg) 52 got := e.Name() 53 if got != tc.cfg.Name { 54 t.Errorf("Enricher{%+v}.Name() = %q, want %q", tc.cfg, got, tc.cfg.Name) 55 } 56 }) 57 } 58 } 59 60 func TestVersion(t *testing.T) { 61 tests := []struct { 62 name string 63 cfg *fakeenricher.Config 64 }{ 65 { 66 name: "zero_version", 67 cfg: &fakeenricher.Config{}, 68 }, 69 { 70 name: "positive_version", 71 cfg: &fakeenricher.Config{Version: 7}, 72 }, 73 } 74 75 for _, tc := range tests { 76 t.Run(tc.name, func(t *testing.T) { 77 e := fakeenricher.MustNew(t, tc.cfg) 78 got := e.Version() 79 if got != tc.cfg.Version { 80 t.Errorf("Enricher{%+v}.Version() = %d, want %d", tc.cfg, got, tc.cfg.Version) 81 } 82 }) 83 } 84 } 85 86 func TestRequirements(t *testing.T) { 87 tests := []struct { 88 name string 89 cfg *fakeenricher.Config 90 }{ 91 { 92 name: "no_requirements", 93 cfg: &fakeenricher.Config{}, 94 }, 95 { 96 name: "some_requirements", 97 cfg: &fakeenricher.Config{ 98 Capabilities: &plugin.Capabilities{ 99 Network: plugin.NetworkOnline, 100 DirectFS: true, 101 }, 102 }, 103 }, 104 } 105 106 for _, tc := range tests { 107 t.Run(tc.name, func(t *testing.T) { 108 e := fakeenricher.MustNew(t, tc.cfg) 109 got := e.Requirements() 110 if diff := cmp.Diff(tc.cfg.Capabilities, got); diff != "" { 111 t.Errorf("Enricher{%+v}.Requirements() returned unexpected diff (-want +got):\n%s", tc.cfg, diff) 112 } 113 }) 114 } 115 } 116 117 func TestRequiredPlugins(t *testing.T) { 118 tests := []struct { 119 name string 120 cfg *fakeenricher.Config 121 }{ 122 { 123 name: "no_required_plugins", 124 cfg: &fakeenricher.Config{}, 125 }, 126 { 127 name: "some_required_plugins", 128 cfg: &fakeenricher.Config{RequiredPlugins: []string{"plugin1", "plugin2"}}, 129 }, 130 } 131 132 for _, tc := range tests { 133 t.Run(tc.name, func(t *testing.T) { 134 e := fakeenricher.MustNew(t, tc.cfg) 135 got := e.RequiredPlugins() 136 if diff := cmp.Diff(tc.cfg.RequiredPlugins, got); diff != "" { 137 t.Errorf("Enricher{%+v}.RequiredPlugins() returned unexpected diff (-want +got):\n%s", tc.cfg, diff) 138 } 139 }) 140 } 141 } 142 143 func TestEnrich(t *testing.T) { 144 input1 := &enricher.ScanInput{ 145 ScanRoot: &scalibrfs.ScanRoot{ 146 FS: fstest.MapFS{ 147 "/some/file.text": {Mode: fs.ModePerm}, 148 "/another/file.md": {Mode: fs.ModePerm}, 149 }, 150 Path: "root", 151 }, 152 } 153 inventory1 := &inventory.Inventory{ 154 Packages: []*extractor.Package{{ 155 Name: "package1", 156 Version: "1.0", 157 }}, 158 PackageVulns: []*inventory.PackageVuln{ 159 { 160 Vulnerability: &osvpb.Vulnerability{Id: "CVE-9012"}, 161 }, 162 }, 163 GenericFindings: []*inventory.GenericFinding{{ 164 Adv: &inventory.GenericFindingAdvisory{ 165 ID: &inventory.AdvisoryID{ 166 Publisher: "CVE", 167 Reference: "CVE-2024-12345", 168 }, 169 }, 170 }}, 171 } 172 173 inventory2 := &inventory.Inventory{ 174 Packages: []*extractor.Package{{ 175 Name: "package2", 176 Version: "2.0", 177 }, { 178 Name: "package3", 179 Version: "3.0", 180 }}, 181 PackageVulns: []*inventory.PackageVuln{{ 182 Vulnerability: &osvpb.Vulnerability{Id: "CVE-9012"}, 183 }}, 184 GenericFindings: []*inventory.GenericFinding{{ 185 Adv: &inventory.GenericFindingAdvisory{ 186 ID: &inventory.AdvisoryID{ 187 Publisher: "CVE", 188 Reference: "CVE-2024-12345", 189 }, 190 }, 191 }, { 192 Adv: &inventory.GenericFindingAdvisory{ 193 ID: &inventory.AdvisoryID{ 194 Publisher: "CVE", 195 Reference: "CVE-2024-67890", 196 }, 197 Recommendation: "do something", 198 }, 199 Target: &inventory.GenericFindingTargetDetails{ 200 Extra: "extra info", 201 }, 202 }}, 203 } 204 205 tests := []struct { 206 name string 207 cfg *fakeenricher.Config 208 input *enricher.ScanInput 209 inv *inventory.Inventory 210 wantInv *inventory.Inventory 211 wantErr error 212 }{ 213 { 214 name: "nothing_to_enrich", 215 cfg: &fakeenricher.Config{ 216 WantEnrich: map[uint64]fakeenricher.InventoryAndErr{ 217 fakeenricher.MustHash(t, nil, &inventory.Inventory{}): fakeenricher.InventoryAndErr{ 218 Inventory: &inventory.Inventory{}, 219 }, 220 }, 221 }, 222 inv: &inventory.Inventory{}, 223 wantInv: &inventory.Inventory{}, 224 }, 225 { 226 name: "enrich_packages_and_findings", 227 cfg: &fakeenricher.Config{ 228 WantEnrich: map[uint64]fakeenricher.InventoryAndErr{ 229 fakeenricher.MustHash(t, input1, inventory1): fakeenricher.InventoryAndErr{ 230 Inventory: inventory2, 231 }, 232 }, 233 }, 234 input: input1, 235 inv: inventory1, 236 wantInv: inventory2, 237 }, 238 } 239 240 for _, tc := range tests { 241 t.Run(tc.name, func(t *testing.T) { 242 e := fakeenricher.MustNew(t, tc.cfg) 243 gotErr := e.Enrich(t.Context(), tc.input, tc.inv) 244 if !cmp.Equal(gotErr, tc.wantErr, cmpopts.EquateErrors()) { 245 t.Errorf("Enricher{%+v}.Enrich(%+v, %+v) error: got %v, want %v\n", tc.cfg, tc.input, tc.inv, gotErr, tc.wantErr) 246 } 247 if diff := cmp.Diff(tc.wantInv, tc.inv, protocmp.Transform()); diff != "" { 248 t.Errorf("Enricher{%+v}.Enrich(%+v, %+v) returned unexpected diff (-want +got):\n%s", tc.cfg, tc.input, tc.inv, diff) 249 } 250 }) 251 } 252 }