github.com/jaypipes/ghw@v0.21.1/pkg/pci/pci_linux_test.go (about)

     1  //
     2  // Use and distribution licensed under the Apache license version 2.
     3  //
     4  // See the COPYING file in the root project directory for full text.
     5  //
     6  
     7  package pci_test
     8  
     9  import (
    10  	"encoding/json"
    11  	"fmt"
    12  	"os"
    13  	"path/filepath"
    14  	"testing"
    15  
    16  	"github.com/jaypipes/ghw/pkg/context"
    17  	"github.com/jaypipes/ghw/pkg/marshal"
    18  	"github.com/jaypipes/ghw/pkg/option"
    19  	"github.com/jaypipes/ghw/pkg/pci"
    20  	"github.com/jaypipes/ghw/pkg/util"
    21  
    22  	"github.com/jaypipes/ghw/testdata"
    23  )
    24  
    25  type pciTestCase struct {
    26  	addr       string
    27  	parentAddr string
    28  	node       int
    29  	revision   string
    30  	driver     string
    31  	iommuGroup string
    32  }
    33  
    34  // nolint: gocyclo
    35  func TestPCINUMANode(t *testing.T) {
    36  	info := pciTestSetupXeon(t)
    37  
    38  	tCases := []pciTestCase{
    39  		{
    40  			addr: "0000:07:03.0",
    41  			// -1 is actually what we get out of the box on the snapshotted box
    42  			node: -1,
    43  		},
    44  		{
    45  			addr: "0000:05:11.0",
    46  			node: 0,
    47  		},
    48  		{
    49  			addr: "0000:05:00.1",
    50  			node: 1,
    51  		},
    52  	}
    53  	for _, tCase := range tCases {
    54  		t.Run(fmt.Sprintf("%s (%d)", tCase.addr, tCase.node), func(t *testing.T) {
    55  			dev := info.GetDevice(tCase.addr)
    56  			if dev == nil {
    57  				t.Fatalf("got nil device for address %q", tCase.addr)
    58  			}
    59  			if dev.Node == nil {
    60  				if tCase.node != -1 {
    61  					t.Fatalf("got nil numa NODE for address %q", tCase.addr)
    62  				}
    63  			} else {
    64  				if dev.Node.ID != tCase.node {
    65  					t.Errorf("got NUMA node info %#v, expected on node %d", dev.Node, tCase.node)
    66  				}
    67  			}
    68  		})
    69  	}
    70  }
    71  
    72  // nolint: gocyclo
    73  func TestPCIDeviceRevision(t *testing.T) {
    74  	info := pciTestSetupXeon(t)
    75  
    76  	var tCases []pciTestCase = []pciTestCase{
    77  		{
    78  			addr:     "0000:07:03.0",
    79  			revision: "0x0a",
    80  		},
    81  		{
    82  			addr:     "0000:05:00.0",
    83  			revision: "0x01",
    84  		},
    85  	}
    86  	for _, tCase := range tCases {
    87  		t.Run(tCase.addr, func(t *testing.T) {
    88  			dev := info.GetDevice(tCase.addr)
    89  			if dev == nil {
    90  				t.Fatalf("got nil device for address %q", tCase.addr)
    91  			}
    92  			if dev.Revision != tCase.revision {
    93  				t.Errorf("device %q got revision %q expected %q", tCase.addr, dev.Revision, tCase.revision)
    94  			}
    95  		})
    96  	}
    97  }
    98  
    99  // nolint: gocyclo
   100  func TestPCIParent(t *testing.T) {
   101  	info := pciTestSetupI7(t)
   102  	tCases := []pciTestCase{
   103  		{
   104  			addr:       "0000:04:00.0",
   105  			parentAddr: "0000:00:06.0",
   106  		},
   107  	}
   108  	for _, tCase := range tCases {
   109  		t.Run(fmt.Sprintf("%s (%s)", tCase.addr, tCase.parentAddr), func(t *testing.T) {
   110  			dev := info.GetDevice(tCase.addr)
   111  			if dev == nil {
   112  				t.Fatalf("got nil device for address %q", tCase.addr)
   113  			}
   114  			if dev.ParentAddress != tCase.parentAddr {
   115  				t.Errorf("got parent %q expected %q", dev.ParentAddress, tCase.parentAddr)
   116  			}
   117  		})
   118  	}
   119  }
   120  
   121  // nolint: gocyclo
   122  func TestPCIIommuGroup(t *testing.T) {
   123  	info := pciTestSetupI7(t)
   124  	tCases := []pciTestCase{
   125  		{
   126  			addr:       "0000:00:1f.0",
   127  			iommuGroup: "13",
   128  		},
   129  		{
   130  			addr:       "0000:00:1f.5",
   131  			iommuGroup: "13",
   132  		},
   133  		{
   134  			addr:       "0000:04:00.0",
   135  			iommuGroup: "14",
   136  		},
   137  	}
   138  	for _, tCase := range tCases {
   139  		t.Run(fmt.Sprintf("%s (%s)", tCase.addr, tCase.iommuGroup), func(t *testing.T) {
   140  			dev := info.GetDevice(tCase.addr)
   141  			if dev == nil {
   142  				t.Fatalf("got nil device for address %q", tCase.addr)
   143  			}
   144  			if dev.IOMMUGroup != tCase.iommuGroup {
   145  				t.Errorf("got iommu_group %q expected %q", dev.IOMMUGroup, tCase.iommuGroup)
   146  			}
   147  		})
   148  	}
   149  }
   150  
   151  // nolint: gocyclo
   152  func TestPCIDriver(t *testing.T) {
   153  	info := pciTestSetupXeon(t)
   154  
   155  	tCases := []pciTestCase{
   156  		{
   157  			addr:   "0000:07:03.0",
   158  			driver: "mgag200",
   159  		},
   160  		{
   161  			addr:   "0000:05:11.0",
   162  			driver: "igbvf",
   163  		},
   164  		{
   165  			addr:   "0000:05:00.1",
   166  			driver: "igb",
   167  		},
   168  	}
   169  	for _, tCase := range tCases {
   170  		t.Run(fmt.Sprintf("%s (%s)", tCase.addr, tCase.driver), func(t *testing.T) {
   171  			dev := info.GetDevice(tCase.addr)
   172  			if dev == nil {
   173  				t.Fatalf("got nil device for address %q", tCase.addr)
   174  			}
   175  			if dev.Driver != tCase.driver {
   176  				t.Errorf("got driver %q expected %q", dev.Driver, tCase.driver)
   177  			}
   178  		})
   179  	}
   180  }
   181  
   182  func TestPCIMarshalJSON(t *testing.T) {
   183  	if _, ok := os.LookupEnv("GHW_TESTING_SKIP_PCI"); ok {
   184  		t.Skip("Skipping PCI tests.")
   185  	}
   186  	info, err := pci.New()
   187  	if err != nil {
   188  		t.Fatalf("Expected no error creating PciInfo, but got %v", err)
   189  	}
   190  
   191  	dev := info.ParseDevice("0000:3c:00.0", "pci:v0000144Dd0000A804sv0000144Dsd0000A801bc01sc08i02\n")
   192  	if dev == nil {
   193  		t.Fatalf("Failed to parse valid modalias")
   194  	}
   195  	s := marshal.SafeJSON(context.FromEnv(), dev, true)
   196  	if s == "" {
   197  		t.Fatalf("Error marshalling device: %v", dev)
   198  	}
   199  }
   200  
   201  // the sriov-device-plugin code has a test like this
   202  func TestPCIMalformedModalias(t *testing.T) {
   203  	if _, ok := os.LookupEnv("GHW_TESTING_SKIP_PCI"); ok {
   204  		t.Skip("Skipping PCI tests.")
   205  	}
   206  	info, err := pci.New()
   207  	if err != nil {
   208  		t.Fatalf("Expected no error creating PciInfo, but got %v", err)
   209  	}
   210  
   211  	var dev *pci.Device
   212  	dev = info.ParseDevice("0000:00:01.0", "pci:junk")
   213  	if dev != nil {
   214  		t.Fatalf("Parsed successfully junk data")
   215  	}
   216  
   217  	dev = info.ParseDevice("0000:00:01.0", "pci:v00008086d00005916sv000017AAsd0000224Bbc03sc00i00extrajunkextradataextraextra")
   218  	if dev == nil {
   219  		t.Fatalf("Failed to parse valid modalias with extra data")
   220  	}
   221  }
   222  
   223  func pciTestSetupXeon(t *testing.T) *pci.Info {
   224  	const snapshotFilename = "linux-amd64-intel-xeon-L5640.tar.gz"
   225  	return pciTestSetup(t, snapshotFilename)
   226  }
   227  
   228  func pciTestSetupI7(t *testing.T) *pci.Info {
   229  	const snapshotFilename = "linux-amd64-intel-i7-1270P.tar.gz"
   230  	return pciTestSetup(t, snapshotFilename)
   231  }
   232  
   233  func pciTestSetup(t *testing.T, snapshotFilename string) *pci.Info {
   234  	if _, ok := os.LookupEnv("GHW_TESTING_SKIP_PCI"); ok {
   235  		t.Skip("Skipping PCI tests.")
   236  	}
   237  
   238  	testdataPath, err := testdata.SnapshotsDirectory()
   239  	if err != nil {
   240  		t.Fatalf("Expected nil err, but got %v", err)
   241  	}
   242  
   243  	snapshot := filepath.Join(testdataPath, snapshotFilename)
   244  	// from now on we use constants reflecting the content of the snapshot we requested,
   245  	// which we reviewed beforehand. IOW, you need to know the content of the
   246  	// snapshot to fully understand this test. Inspect it using
   247  	// GHW_SNAPSHOT_PATH="/path/to/linux-amd64-intel-xeon-L5640.tar.gz" ghwc topology
   248  
   249  	info, err := pci.New(option.WithSnapshot(option.SnapshotOptions{
   250  		Path: snapshot,
   251  	}))
   252  
   253  	if err != nil {
   254  		t.Fatalf("Expected nil err, but got %v", err)
   255  	}
   256  	if info == nil {
   257  		t.Fatalf("Expected non-nil PCIInfo, but got nil")
   258  	}
   259  	return info
   260  }
   261  
   262  // we have this test in pci_linux_test.go (and not in pci_test.go) because `pciFillInfo` is implemented
   263  // only on linux; so having it in the platform-independent tests would lead to false negatives.
   264  func TestPCIMarshalUnmarshal(t *testing.T) {
   265  	data, err := pci.New(option.WithNullAlerter())
   266  	if err != nil {
   267  		t.Fatalf("Expected no error creating pci.Info, but got %v", err)
   268  	}
   269  
   270  	jdata, err := json.Marshal(data)
   271  	if err != nil {
   272  		t.Fatalf("Expected no error marshaling pci.Info, but got %v", err)
   273  	}
   274  
   275  	var topo *pci.Info
   276  
   277  	err = json.Unmarshal(jdata, &topo)
   278  	if err != nil {
   279  		t.Fatalf("Expected no error unmarshaling pci.Info, but got %v", err)
   280  	}
   281  }
   282  
   283  func TestPCIModaliasWithUpperCaseClassID(t *testing.T) {
   284  	if _, ok := os.LookupEnv("GHW_TESTING_SKIP_PCI"); ok {
   285  		t.Skip("Skipping PCI tests.")
   286  	}
   287  	info, err := pci.New()
   288  	if err != nil {
   289  		t.Fatalf("Expected no error creating PciInfo, but got %v", err)
   290  	}
   291  
   292  	dev := info.ParseDevice("0000:00:1f.4", "pci:v00008086d00009D23sv00001028sd000007EAbc0Csc05i00\n")
   293  	if dev == nil {
   294  		t.Fatalf("Failed to parse valid modalias")
   295  	}
   296  	if dev.Class.Name == util.UNKNOWN {
   297  		t.Fatalf("Failed to lookup class name")
   298  	}
   299  }