Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit d81cdd6

Browse files
committedJun 19, 2023
pkg/topology: get sysfs parsing from containers/nri-plugins
A proper upstream for the sysfs topology parsing is containers/nri-plugins se we can drop the duplicated code. At the same time, we no longer need to carry scripts/ttar and the sys.ttar unpacking for the tests because the remaining testdata becomes easier to maintain (the original testdata contained PCI BDF paths that trigged issues). Signed-off-by: Mikko Ylinen <mikko.ylinen@intel.com>
1 parent 6ab2833 commit d81cdd6

File tree

13 files changed

+19
-1106
lines changed

13 files changed

+19
-1106
lines changed
 

‎Makefile

+3-11
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL)
2626
OLM_MANIFESTS = deployments/operator/manifests
2727
BUNDLE_DIR = community-operators/operators/intel-device-plugins-operator/$(TAG)
2828

29-
TESTDATA_DIR = pkg/topology/testdata
30-
3129
EXTRA_BUILD_ARGS += --build-arg GOLICENSES_VERSION=$(GOLICENSES_VERSION)
3230

3331
pkgs = $(shell $(GO) list ./... | grep -v vendor | grep -v e2e | grep -v envtest)
@@ -50,13 +48,7 @@ go-mod-tidy:
5048
$(GO) mod download all
5149
@report=`$(GO) mod tidy -v 2>&1` ; if [ -n "$$report" ]; then echo "$$report"; exit 1; fi
5250

53-
update-fixture:
54-
@scripts/ttar -C $(TESTDATA_DIR) -c -f $(TESTDATA_DIR)/sys.ttar sys/
55-
56-
fixture:
57-
@scripts/ttar --recursive-unlink -C $(TESTDATA_DIR) -x -f $(TESTDATA_DIR)/sys.ttar
58-
59-
test: fixture
51+
test:
6052
ifndef WHAT
6153
@$(GO) test -tags $(BUILDTAGS) -race -coverprofile=coverage.txt -covermode=atomic $(pkgs)
6254
else
@@ -68,7 +60,7 @@ else
6860
exit $$rc
6961
endif
7062

71-
test-with-kind: fixture intel-sgx-admissionwebhook intel-fpga-admissionwebhook intel-deviceplugin-operator install-tools
63+
test-with-kind: intel-sgx-admissionwebhook intel-fpga-admissionwebhook intel-deviceplugin-operator install-tools
7264
# Build a Cluster with KinD & Load Images & Install Cert-Manager
7365
kind create cluster
7466
kind load docker-image $(REG)intel-sgx-admissionwebhook:$(TAG)
@@ -241,7 +233,7 @@ check-github-actions:
241233
jq -e '$(images_json) - [$(skip_images)] - .jobs.image.strategy.matrix.image == []' > /dev/null || \
242234
(echo "Make sure all images are listed in .github/workflows/ci.yaml"; exit 1)
243235

244-
.PHONY: all format test lint build images $(cmds) $(images) lock-images vendor pre-pull set-version check-github-actions envtest fixture update-fixture install-tools test-image-base-layer
236+
.PHONY: all format test lint build images $(cmds) $(images) lock-images vendor pre-pull set-version check-github-actions envtest install-tools test-image-base-layer
245237

246238
SPHINXOPTS =
247239
SPHINXBUILD = sphinx-build

‎go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/intel/intel-device-plugins-for-kubernetes
33
go 1.20
44

55
require (
6+
github.com/containers/nri-plugins/pkg/topology v0.0.0-20230417061637-0847843000f8
67
github.com/fsnotify/fsnotify v1.6.0
78
github.com/go-ini/ini v1.67.0
89
github.com/go-logr/logr v1.2.4

‎go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH
7272
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
7373
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
7474
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k=
75+
github.com/containers/nri-plugins/pkg/topology v0.0.0-20230417061637-0847843000f8 h1:fcv6mtBBQd+woQSqZN1QJ1g91TRwUNNijj1WKjqub5Q=
76+
github.com/containers/nri-plugins/pkg/topology v0.0.0-20230417061637-0847843000f8/go.mod h1:XHuUl2t6TVLTfGsy8+w3MdxOjSn2hN0lc1PuaxOEFEc=
7577
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
7678
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
7779
github.com/coreos/go-systemd/v22 v22.4.0 h1:y9YHcjnjynCd/DVbg5j9L/33jQM3MxJlbj/zWskzfGU=

‎pkg/topology/testdata/sys.ttar

-125
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
0-7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1,2,3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
0-7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
0-7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
4,5,6

‎pkg/topology/topology.go

+3-268
Original file line numberDiff line numberDiff line change
@@ -15,288 +15,23 @@
1515
package topology
1616

1717
import (
18-
"fmt"
19-
"os"
20-
"path/filepath"
2118
"sort"
2219
"strconv"
2320
"strings"
24-
"syscall"
2521

22+
topo "github.com/containers/nri-plugins/pkg/topology"
2623
"github.com/pkg/errors"
27-
"golang.org/x/sys/unix"
2824
pluginapi "k8s.io/kubelet/pkg/apis/deviceplugin/v1beta1"
2925
)
3026

31-
// Path to the directory to mock in tests.
32-
var (
33-
mockRoot = ""
34-
)
35-
36-
const (
37-
// ProviderKubelet is a constant to distinguish that topology hint comes
38-
// from parameters passed to CRI create/update requests from Kubelet.
39-
ProviderKubelet = "kubelet"
40-
)
41-
42-
// Hint represents various hints that can be detected from sysfs for the device.
43-
type Hint struct {
44-
Provider string
45-
CPUs string
46-
NUMAs string
47-
Sockets string
48-
}
49-
50-
// Hints represents set of hints collected from multiple providers.
51-
type Hints map[string]Hint
52-
53-
func getDevicesFromVirtual(realDevPath string) (devs []string, err error) {
54-
relPath, err := filepath.Rel("/sys/devices/virtual", realDevPath)
55-
if err != nil {
56-
return nil, errors.Wrap(err, "unable to find relative path")
57-
}
58-
59-
if strings.HasPrefix(relPath, "..") {
60-
return nil, errors.Errorf("%s is not a virtual device", realDevPath)
61-
}
62-
63-
dir, file := filepath.Split(relPath)
64-
switch dir {
65-
case "vfio/":
66-
iommuGroup := filepath.Join(mockRoot, "/sys/kernel/iommu_groups", file, "devices")
67-
68-
files, err := os.ReadDir(iommuGroup)
69-
if err != nil {
70-
return nil, errors.Wrapf(err, "failed to read IOMMU group %s", iommuGroup)
71-
}
72-
73-
for _, file := range files {
74-
realDev, err := filepath.EvalSymlinks(filepath.Join(iommuGroup, file.Name()))
75-
if err != nil {
76-
return nil, errors.Wrapf(err, "failed to get real path for %s", file.Name())
77-
}
78-
79-
devs = append(devs, realDev)
80-
}
81-
82-
return devs, nil
83-
default:
84-
return nil, nil
85-
}
86-
}
87-
88-
func getTopologyHint(sysFSPath string) (*Hint, error) {
89-
hint := Hint{Provider: sysFSPath}
90-
fileMap := map[string]*string{
91-
"local_cpulist": &hint.CPUs,
92-
"numa_node": &hint.NUMAs,
93-
}
94-
95-
if err := readFilesInDirectory(fileMap, sysFSPath); err != nil {
96-
return nil, err
97-
}
98-
99-
// Workarounds for broken information provided by kernel
100-
if hint.NUMAs == "-1" {
101-
// non-NUMA aware device or system, ignore it
102-
hint.NUMAs = ""
103-
}
104-
105-
if hint.NUMAs != "" && hint.CPUs == "" {
106-
// broken topology hint. BIOS reports socket id as NUMA node
107-
// First, try to get hints from parent device or bus.
108-
parentHints, er := NewTopologyHints(filepath.Dir(sysFSPath))
109-
if er == nil {
110-
cpulist := map[string]bool{}
111-
numalist := map[string]bool{}
112-
113-
for _, h := range parentHints {
114-
if h.CPUs != "" {
115-
cpulist[h.CPUs] = true
116-
}
117-
118-
if h.NUMAs != "" {
119-
numalist[h.NUMAs] = true
120-
}
121-
}
122-
123-
if cpus := strings.Join(mapKeys(cpulist), ","); cpus != "" {
124-
hint.CPUs = cpus
125-
}
126-
127-
if numas := strings.Join(mapKeys(numalist), ","); numas != "" {
128-
hint.NUMAs = numas
129-
}
130-
}
131-
// if after parent hints we still don't have CPUs hints, use numa hint as sockets.
132-
if hint.CPUs == "" && hint.NUMAs != "" {
133-
hint.Sockets = hint.NUMAs
134-
hint.NUMAs = ""
135-
}
136-
}
137-
138-
return &hint, nil
139-
}
140-
141-
// NewTopologyHints return array of hints for the main device and its
142-
// dependend devices (e.g. RAID).
143-
func NewTopologyHints(devPath string) (hints Hints, err error) {
144-
hints = make(Hints)
145-
146-
realDevPath, err := filepath.EvalSymlinks(devPath)
147-
if err != nil {
148-
return nil, errors.Wrapf(err, "failed get realpath for %s", devPath)
149-
}
150-
151-
for p := realDevPath; strings.HasPrefix(p, mockRoot+"/sys/devices/"); p = filepath.Dir(p) {
152-
hint, er := getTopologyHint(p)
153-
if er != nil {
154-
return nil, er
155-
}
156-
157-
if hint.CPUs != "" || hint.NUMAs != "" || hint.Sockets != "" {
158-
hints[hint.Provider] = *hint
159-
break
160-
}
161-
}
162-
163-
fromVirtual, _ := getDevicesFromVirtual(realDevPath)
164-
deps, _ := filepath.Glob(filepath.Join(realDevPath, "slaves/*"))
165-
166-
for _, device := range append(deps, fromVirtual...) {
167-
deviceHints, er := NewTopologyHints(device)
168-
if er != nil {
169-
return nil, er
170-
}
171-
172-
hints = MergeTopologyHints(hints, deviceHints)
173-
}
174-
175-
return hints, err
176-
}
177-
178-
// MergeTopologyHints combines org and hints.
179-
func MergeTopologyHints(org, hints Hints) (res Hints) {
180-
if org != nil {
181-
res = org
182-
} else {
183-
res = make(Hints)
184-
}
185-
186-
for k, v := range hints {
187-
if _, ok := res[k]; ok {
188-
continue
189-
}
190-
191-
res[k] = v
192-
}
193-
194-
return
195-
}
196-
197-
// String returns the hints as a string.
198-
func (h *Hint) String() string {
199-
cpus, nodes, sockets, sep := "", "", "", ""
200-
201-
if h.CPUs != "" {
202-
cpus = "CPUs:" + h.CPUs
203-
sep = ", "
204-
}
205-
206-
if h.NUMAs != "" {
207-
nodes = sep + "NUMAs:" + h.NUMAs
208-
sep = ", "
209-
}
210-
211-
if h.Sockets != "" {
212-
sockets = sep + "sockets:" + h.Sockets
213-
}
214-
215-
return "<hints " + cpus + nodes + sockets + " (from " + h.Provider + ")>"
216-
}
217-
218-
// FindSysFsDevice for given argument returns physical device where it is linked to.
219-
// For device nodes it will return path for device itself. For regular files or directories
220-
// this function returns physical device where this inode resides (storage device).
221-
// If result device is a virtual one (e.g. tmpfs), error will be returned.
222-
// For non-existing path, no error returned and path is empty.
223-
func FindSysFsDevice(dev string) (string, error) {
224-
fi, err := os.Stat(dev)
225-
if err != nil {
226-
if os.IsNotExist(err) {
227-
return "", nil
228-
}
229-
230-
return "", errors.Wrapf(err, "unable to get stat for %s", dev)
231-
}
232-
233-
devType := "block"
234-
rdev := fi.Sys().(*syscall.Stat_t).Dev
235-
236-
if mode := fi.Mode(); mode&os.ModeDevice != 0 {
237-
rdev = fi.Sys().(*syscall.Stat_t).Rdev
238-
239-
if mode&os.ModeCharDevice != 0 {
240-
devType = "char"
241-
}
242-
}
243-
244-
major := unix.Major(rdev)
245-
minor := unix.Minor(rdev)
246-
247-
if major == 0 {
248-
return "", errors.Errorf("%s is a virtual device node", dev)
249-
}
250-
251-
devPath := fmt.Sprintf("/sys/dev/%s/%d:%d", devType, major, minor)
252-
253-
realDevPath, err := filepath.EvalSymlinks(devPath)
254-
if err != nil {
255-
return "", errors.Wrapf(err, "failed get realpath for %s", devPath)
256-
}
257-
258-
return filepath.Join(mockRoot, realDevPath), nil
259-
}
260-
261-
// readFilesInDirectory small helper to fill struct with content from sysfs entry.
262-
func readFilesInDirectory(fileMap map[string]*string, dir string) error {
263-
for k, v := range fileMap {
264-
b, err := os.ReadFile(filepath.Join(dir, k))
265-
if err != nil {
266-
if os.IsNotExist(err) {
267-
continue
268-
}
269-
270-
return errors.Wrapf(err, "%s: unable to read file %q", dir, k)
271-
}
272-
273-
*v = strings.TrimSpace(string(b))
274-
}
275-
276-
return nil
277-
}
278-
279-
// mapKeys is a small helper that returns slice of keys for a given map.
280-
func mapKeys(m map[string]bool) []string {
281-
ret := make([]string, len(m))
282-
i := 0
283-
284-
for k := range m {
285-
ret[i] = k
286-
i++
287-
}
288-
289-
return ret
290-
}
291-
29227
// GetTopologyInfo returns topology information for the list of device nodes.
29328
func GetTopologyInfo(devs []string) (*pluginapi.TopologyInfo, error) {
29429
var result pluginapi.TopologyInfo
29530

29631
nodeIDs := map[int64]struct{}{}
29732

29833
for _, dev := range devs {
299-
sysfsDevice, err := FindSysFsDevice(dev)
34+
sysfsDevice, err := topo.FindSysFsDevice(dev)
30035
if err != nil {
30136
return nil, err
30237
}
@@ -305,7 +40,7 @@ func GetTopologyInfo(devs []string) (*pluginapi.TopologyInfo, error) {
30540
return nil, errors.Errorf("device %s doesn't exist", dev)
30641
}
30742

308-
hints, err := NewTopologyHints(sysfsDevice)
43+
hints, err := topo.NewTopologyHints(sysfsDevice)
30944
if err != nil {
31045
return nil, err
31146
}

‎pkg/topology/topology_test.go

+4-289
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ import (
1818
"os"
1919
"path/filepath"
2020
"reflect"
21-
"sort"
2221
"testing"
2322

23+
topo "github.com/containers/nri-plugins/pkg/topology"
2424
pluginapi "k8s.io/kubelet/pkg/apis/deviceplugin/v1beta1"
2525
)
2626

@@ -34,300 +34,15 @@ func setupTestEnv(t *testing.T) func() {
3434
pwd = path
3535
}
3636

37-
mockRoot = pwd + "/testdata"
37+
topo.SetSysRoot(pwd + "/testdata")
38+
3839
teardown := func() {
39-
mockRoot = ""
40+
topo.SetSysRoot("")
4041
}
4142

4243
return teardown
4344
}
4445

45-
func TestMapKeys(t *testing.T) {
46-
cases := []struct {
47-
name string
48-
input map[string]bool
49-
output []string
50-
}{
51-
{
52-
name: "empty",
53-
input: map[string]bool{},
54-
output: []string{},
55-
},
56-
{
57-
name: "one",
58-
input: map[string]bool{"a": false},
59-
output: []string{"a"},
60-
},
61-
{
62-
name: "multiple",
63-
input: map[string]bool{"a": false, "b": true, "c": false},
64-
output: []string{"a", "b", "c"},
65-
},
66-
}
67-
for _, tc := range cases {
68-
test := tc
69-
t.Run(test.name, func(t *testing.T) {
70-
t.Parallel()
71-
output := mapKeys(test.input)
72-
sort.Strings(output)
73-
if !reflect.DeepEqual(output, test.output) {
74-
t.Fatalf("expected output: %+v got: %+v", test.output, output)
75-
}
76-
})
77-
}
78-
}
79-
80-
func TestFindSysFsDevice(t *testing.T) {
81-
if testing.Short() {
82-
t.Skip("skipping test in short mode.")
83-
}
84-
85-
teardown := setupTestEnv(t)
86-
defer teardown()
87-
88-
cases := []struct {
89-
name string
90-
input string
91-
output string
92-
expectedErr bool
93-
}{
94-
{
95-
name: "empty",
96-
input: "",
97-
output: "",
98-
expectedErr: false,
99-
},
100-
{
101-
name: "null",
102-
input: "/dev/null",
103-
output: "/sys/devices/virtual/mem/null",
104-
expectedErr: false,
105-
},
106-
{
107-
name: "proc",
108-
input: "/proc/self",
109-
output: "",
110-
expectedErr: true,
111-
},
112-
}
113-
for _, tc := range cases {
114-
test := tc
115-
t.Run(test.name, func(t *testing.T) {
116-
t.Parallel()
117-
output, err := FindSysFsDevice(test.input)
118-
switch {
119-
case err != nil && !test.expectedErr:
120-
t.Fatalf("unexpected error returned: %+v", err)
121-
case err == nil && test.expectedErr:
122-
t.Fatalf("unexpected success: %+v", output)
123-
case output != test.output:
124-
t.Fatalf("expected: %q got: %q", test.output, output)
125-
}
126-
})
127-
}
128-
}
129-
130-
func TestReadFilesInDirectory(t *testing.T) {
131-
var file, empty string
132-
133-
fname := "test-a"
134-
content := []byte(" something\n")
135-
expectedContent := "something"
136-
137-
fileMap := map[string]*string{
138-
fname: &file,
139-
"non_existing": &empty,
140-
}
141-
142-
dir, err := os.MkdirTemp("", "readFilesInDirectory")
143-
if err != nil {
144-
t.Fatalf("unable to create test directory: %+v", err)
145-
}
146-
147-
defer os.RemoveAll(dir)
148-
149-
if err = os.WriteFile(filepath.Join(dir, fname), content, 0600); err != nil {
150-
t.Fatalf("unexpected failure: %v", err)
151-
}
152-
153-
if err = readFilesInDirectory(fileMap, dir); err != nil {
154-
t.Fatalf("unexpected failure: %v", err)
155-
}
156-
157-
if empty != "" {
158-
t.Fatalf("unexpected content: %q", empty)
159-
}
160-
161-
if file != expectedContent {
162-
t.Fatalf("unexpected content: %q expected: %q", file, expectedContent)
163-
}
164-
}
165-
166-
func TestGetDevicesFromVirtual(t *testing.T) {
167-
teardown := setupTestEnv(t)
168-
defer teardown()
169-
170-
cases := []struct {
171-
name string
172-
input string
173-
output []string
174-
expectedErr bool
175-
}{
176-
{
177-
name: "vfio",
178-
input: "/sys/devices/virtual/vfio/42",
179-
output: []string{mockRoot + "/sys/devices/pci0000:00/0000:00:02.0"},
180-
expectedErr: false,
181-
},
182-
{
183-
name: "misc",
184-
input: "/sys/devices/virtual/misc/vfio",
185-
output: nil,
186-
expectedErr: false,
187-
},
188-
{
189-
name: "missing-iommu-group",
190-
input: "/sys/devices/virtual/vfio/84",
191-
output: nil,
192-
expectedErr: true,
193-
},
194-
{
195-
name: "non-virtual",
196-
input: "/sys/devices/pci0000:00/0000:00:02.0",
197-
output: nil,
198-
expectedErr: true,
199-
},
200-
{
201-
name: "garbage",
202-
input: "./sys/devices/virtual/vfio/42",
203-
output: nil,
204-
expectedErr: true,
205-
},
206-
}
207-
208-
for _, tc := range cases {
209-
test := tc
210-
t.Run(test.name, func(t *testing.T) {
211-
output, err := getDevicesFromVirtual(test.input)
212-
switch {
213-
case err != nil && !test.expectedErr:
214-
t.Fatalf("unexpected error returned: %+v", err)
215-
case err == nil && test.expectedErr:
216-
t.Fatalf("unexpected success: %+v", output)
217-
case len(output) != len(test.output):
218-
t.Fatalf("expected: %q got: %q", len(test.output), len(output))
219-
}
220-
for i, p := range test.output {
221-
if test.output[i] != p {
222-
t.Fatalf("expected: %q got: %q", test.output[i], p)
223-
}
224-
}
225-
})
226-
}
227-
}
228-
229-
func TestMergeTopologyHints(t *testing.T) {
230-
cases := []struct {
231-
inputA Hints
232-
inputB Hints
233-
expectedOutput Hints
234-
name string
235-
expectedErr bool
236-
}{
237-
{
238-
name: "empty",
239-
inputA: nil,
240-
inputB: nil,
241-
expectedOutput: Hints{},
242-
},
243-
{
244-
name: "one,nil",
245-
inputA: Hints{"test": Hint{Provider: "test", CPUs: "0"}},
246-
inputB: nil,
247-
expectedOutput: Hints{"test": Hint{Provider: "test", CPUs: "0"}},
248-
},
249-
{
250-
name: "nil, one",
251-
inputA: nil,
252-
inputB: Hints{"test": Hint{Provider: "test", CPUs: "0"}},
253-
expectedOutput: Hints{"test": Hint{Provider: "test", CPUs: "0"}},
254-
},
255-
{
256-
name: "duplicate",
257-
inputA: Hints{"test": Hint{Provider: "test", CPUs: "0"}},
258-
inputB: Hints{"test": Hint{Provider: "test", CPUs: "0"}},
259-
expectedOutput: Hints{"test": Hint{Provider: "test", CPUs: "0"}},
260-
},
261-
{
262-
name: "two",
263-
inputA: Hints{"test1": Hint{Provider: "test1", CPUs: "0"}},
264-
inputB: Hints{"test2": Hint{Provider: "test2", CPUs: "1"}},
265-
expectedOutput: Hints{
266-
"test1": Hint{Provider: "test1", CPUs: "0"},
267-
"test2": Hint{Provider: "test2", CPUs: "1"},
268-
},
269-
},
270-
}
271-
for _, tc := range cases {
272-
test := tc
273-
t.Run(test.name, func(t *testing.T) {
274-
t.Parallel()
275-
output := MergeTopologyHints(test.inputA, test.inputB)
276-
if !reflect.DeepEqual(output, test.expectedOutput) {
277-
t.Fatalf("expected output: %+v got: %+v", test.expectedOutput, output)
278-
}
279-
})
280-
}
281-
}
282-
283-
func TestNewTopologyHints(t *testing.T) {
284-
if testing.Short() {
285-
t.Skip("skipping test in short mode.")
286-
}
287-
288-
teardown := setupTestEnv(t)
289-
defer teardown()
290-
291-
cases := []struct {
292-
output Hints
293-
name string
294-
input string
295-
expectedErr bool
296-
}{
297-
{
298-
name: "empty",
299-
input: "non-existing",
300-
output: nil,
301-
expectedErr: true,
302-
},
303-
{
304-
name: "pci card1",
305-
input: mockRoot + "/sys/devices/pci0000:00/0000:00:02.0/drm/card1",
306-
output: Hints{
307-
mockRoot + "/sys/devices/pci0000:00/0000:00:02.0": Hint{
308-
Provider: mockRoot + "/sys/devices/pci0000:00/0000:00:02.0",
309-
CPUs: "0-7",
310-
NUMAs: "",
311-
Sockets: ""},
312-
},
313-
expectedErr: false,
314-
},
315-
}
316-
for _, test := range cases {
317-
t.Run(test.name, func(t *testing.T) {
318-
output, err := NewTopologyHints(test.input)
319-
switch {
320-
case err != nil && !test.expectedErr:
321-
t.Fatalf("unexpected error returned: %+v", err)
322-
case err == nil && test.expectedErr:
323-
t.Fatalf("unexpected success: %+v", output)
324-
case !reflect.DeepEqual(output, test.output):
325-
t.Fatalf("expected: %q got: %q", test.output, output)
326-
}
327-
})
328-
}
329-
}
330-
33146
func TestGetTopologyInfo(t *testing.T) {
33247
if testing.Short() {
33348
t.Skip("skipping test in short mode.")

‎scripts/ttar

-413
This file was deleted.

0 commit comments

Comments
 (0)
Please sign in to comment.