github.com/google/osv-scalibr@v0.4.1/testing/fakeenricher/fake_enricher.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 provides an Enricher implementation to be used in tests.
    16  //
    17  //nolint:plugger // This package contains test only mocks
    18  package fakeenricher
    19  
    20  import (
    21  	"context"
    22  	"fmt"
    23  	"testing"
    24  
    25  	"github.com/gohugoio/hashstructure"
    26  	"github.com/google/osv-scalibr/enricher"
    27  	"github.com/google/osv-scalibr/inventory"
    28  	"github.com/google/osv-scalibr/plugin"
    29  )
    30  
    31  // Enricher is a fake enricher implementation to be used in tests.
    32  type Enricher struct {
    33  	name            string
    34  	version         int
    35  	capabilities    *plugin.Capabilities
    36  	requiredPlugins []string
    37  	wantEnrich      map[uint64]InventoryAndErr
    38  }
    39  
    40  // Config for creating a fake enricher.
    41  type Config struct {
    42  	Name            string
    43  	Version         int
    44  	Capabilities    *plugin.Capabilities
    45  	RequiredPlugins []string
    46  	WantEnrich      map[uint64]InventoryAndErr
    47  }
    48  
    49  // InventoryAndErr is the expected enrichment response for a given input and inventory.
    50  type InventoryAndErr struct {
    51  	Inventory *inventory.Inventory
    52  	Err       error
    53  }
    54  
    55  type inputAndInventory struct {
    56  	Input     *enricher.ScanInput
    57  	Inventory *inventory.Inventory
    58  }
    59  
    60  // New creates a new fake enricher.
    61  //
    62  // The expected usage in tests is to create a fake enricher with the expected input and inventory
    63  // to enrichment response mapping.
    64  // Example:
    65  //
    66  //	key, err := fakeenricher.Hash(tc.scanInput, tc.inventory)
    67  //	if err != nil {
    68  //		t.Fatalf("failed to hash input and inventory: %v", err)
    69  //	}
    70  //	wantEnrich := map[uint64]fakeenricher.InventoryAndErr{
    71  //		key: fakeenricher.InventoryAndErr{
    72  //			Inventory: tc.wantInventory,
    73  //			Err:       tc.wantErr,
    74  //		},
    75  //	}
    76  //	e := fakeenricher.New(&fakeenricher.Config{
    77  //		Name:            "FakeEnricher",
    78  //		Version:         1,
    79  //		Capabilities:    &plugin.Capabilities{},
    80  //		RequiredPlugins: []string{},
    81  //		WantEnrich:      wantEnrich,
    82  //	})
    83  //	err := e.Enrich(ctx, tc.scanInput, tc.inventory)
    84  //	if !cmp.Equal(err, tc.wantErr, cmpopts.EquateErrors()) {
    85  //		t.Fatalf("e.Enrich(%+v, %+v, %+v) error: got %v, want %v\n", ctx, tc.scanInput, tc.inventory, err, tc.wantErr)
    86  //	}
    87  //	if diff := cmp.Diff(tc.wantInventory, tc.inventory); diff != "" {
    88  //		t.Fatalf("e.Enrich(%+v, %+v, %+v) returned unexpected diff (-want +got):\n%s", ctx, tc.scanInput, tc.inventory, diff)
    89  //	}
    90  //
    91  // For convenience, the MustNew and MustHash functions can be used to create a fake enricher and set
    92  // behavior which will fail the test if an error is returned.
    93  func New(cfg *Config) (*Enricher, error) {
    94  	return &Enricher{
    95  		name:            cfg.Name,
    96  		version:         cfg.Version,
    97  		capabilities:    cfg.Capabilities,
    98  		requiredPlugins: cfg.RequiredPlugins,
    99  		wantEnrich:      cfg.WantEnrich,
   100  	}, nil
   101  }
   102  
   103  // MustNew creates a new fake enricher and fails the test if an error is returned.
   104  func MustNew(t *testing.T, cfg *Config) *Enricher {
   105  	t.Helper()
   106  	e, err := New(cfg)
   107  	if err != nil {
   108  		t.Fatalf("failed to create fake enricher: %v", err)
   109  	}
   110  	return e
   111  }
   112  
   113  // Name returns the enricher's name.
   114  func (e *Enricher) Name() string { return e.name }
   115  
   116  // Version returns the enricher's version.
   117  func (e *Enricher) Version() int { return e.version }
   118  
   119  // Requirements about the scanning environment, e.g. "needs to have network access".
   120  func (e *Enricher) Requirements() *plugin.Capabilities { return e.capabilities }
   121  
   122  // RequiredPlugins returns a list of Plugins that need to be enabled for this Enricher to run.
   123  func (e *Enricher) RequiredPlugins() []string { return e.requiredPlugins }
   124  
   125  // Enrich enriches the scan results with additional information.
   126  func (e *Enricher) Enrich(ctx context.Context, input *enricher.ScanInput, inv *inventory.Inventory) error {
   127  	key, err := Hash(input, inv)
   128  	if err != nil {
   129  		return err
   130  	}
   131  	invAndErr, ok := e.wantEnrich[key]
   132  	if !ok {
   133  		return fmt.Errorf("no enrichment response for key %d, input: %v, inventory: %v", key, input, inv)
   134  	}
   135  	newInv := invAndErr.Inventory
   136  	inv.Packages = newInv.Packages
   137  	inv.PackageVulns = newInv.PackageVulns
   138  	inv.GenericFindings = newInv.GenericFindings
   139  	return invAndErr.Err
   140  }
   141  
   142  // Hash returns a hash of the input and inventory. This is used to match the input and inventory
   143  // to the expected enrichment response.
   144  func Hash(input *enricher.ScanInput, inventory *inventory.Inventory) (uint64, error) {
   145  	ii := &inputAndInventory{
   146  		Input:     input,
   147  		Inventory: inventory,
   148  	}
   149  	return hashstructure.Hash(ii, nil)
   150  }
   151  
   152  // MustHash returns a hash of the input and inventory. This is used to match the input and inventory
   153  // to the expected enrichment response.
   154  func MustHash(t *testing.T, input *enricher.ScanInput, inventory *inventory.Inventory) uint64 {
   155  	t.Helper()
   156  	hash, err := Hash(input, inventory)
   157  	if err != nil {
   158  		t.Fatalf("failed to hash input and inventory: %v", err)
   159  	}
   160  	return hash
   161  }