blob: 477a6625db71d0b396f5b187cfdbc4a43257ecb9 [file] [log] [blame] [edit]
package dkms
import (
"os"
"path"
"path/filepath"
"testing"
"github.com/google/go-cmp/cmp"
)
func TestFindKernelModules(t *testing.T) {
installDir := t.TempDir()
paths := []string{
"a.ko",
"b.txt",
"x/c.ko",
"x/d.ko",
"x/e.txt",
"x/y/f.ko",
"x/y/g.txt",
}
for _, p := range paths {
installPath := path.Join(installDir, p)
if err := os.MkdirAll(filepath.Dir(installPath), 0777); err != nil {
t.Fatalf("%v", err)
}
if _, err := os.Create(path.Join(installDir, p)); err != nil {
t.Fatalf("%v", err)
}
}
kernelModules, err := FindKernelModules(installDir)
if err != nil {
t.Fatalf("could not find kernel modules: %v", err)
}
expected := map[string]string{
"a.ko": path.Join(installDir, "a.ko"),
"c.ko": path.Join(installDir, "x/c.ko"),
"d.ko": path.Join(installDir, "x/d.ko"),
"f.ko": path.Join(installDir, "x/y/f.ko"),
}
diff := cmp.Diff(expected, kernelModules)
if diff != "" {
t.Errorf("found kernel modules did not match expected:\ndiff: %s", diff)
}
}
func TestModuleDependencies(t *testing.T) {
deps, err := ModuleDependencies("ext4")
if err != nil {
t.Fatalf("error getting dependencies for module ext4: %v", err)
}
if len(deps) == 0 {
t.Fatalf("expected to find at least one dependency for module ext4; found none")
}
t.Logf("ext4 dependencies: %v", deps)
}
func TestModuleDependencyGraph(t *testing.T) {
insertedModules, err := InsertedModules()
if err != nil {
t.Fatalf("failed to get inserted modules: %v", err)
}
var moduleNames []string
for module := range insertedModules {
moduleNames = append(moduleNames, module)
}
// Technically, this wouldn't be fully correct if there are multiple kernels
// installed, but any nontrivial dependency graph suffices for this test.
modulePaths, err := FindKernelModules("/lib/modules/")
if err != nil {
t.Fatalf("failed to get kernel module paths")
}
graph, err := ModuleDependencyGraph(moduleNames, modulePaths)
if err != nil {
t.Fatalf("failed to build module dependency graph: %v", err)
}
any_non_empty_deps := false
for _, deps := range graph {
if len(deps) > 0 {
any_non_empty_deps = true
}
}
t.Logf("module dependency graph: %v", graph)
if !any_non_empty_deps {
t.Fatalf("expected to find at least one module with dependencies; found none")
}
}
func TestModuleInsertionOrder(t *testing.T) {
testCases := []struct {
modules []string
graph map[string][]string
expected []string
}{
{
modules: []string{"a", "b", "c", "d"},
graph: map[string][]string{
"a": {},
"b": {"d"},
"c": {"b", "a"},
"d": {},
},
expected: []string{"a", "d", "b", "c"},
},
// This test case is the Lustre kernel module dependency graph, which has
// a non-trivial structure and important tie-breaking.
{
modules: []string{
"ksocklnd",
"in-kernel-ko2iblnd",
"ec",
"fid",
"fld",
"libcfs",
"lmv",
"lnet",
"lov",
"lustre",
"mdc",
"mgc",
"obdclass",
"obdecho",
"osc",
"ptlrpc",
},
graph: map[string][]string{
"ec": {},
"fid": {"obdclass", "ptlrpc", "libcfs"},
"fld": {"obdclass", "ptlrpc", "libcfs"},
"in-kernel-ko2iblnd": {"ib_core", "rdma_cm", "libcfs", "lnet"},
"ksocklnd": {"lnet", "libcfs"},
"libcfs": {},
"lmv": {"fld", "obdclass", "fid", "ptlrpc", "libcfs", "lnet"},
"lnet": {"sunrpc", "libcfs"},
"lov": {"obdclass", "ptlrpc", "fld", "libcfs"},
"lustre": {"lnet", "obdclass", "ptlrpc", "libcfs", "lov", "mdc", "lmv", "fid"},
"mdc": {"ptlrpc", "libcfs", "osc", "obdclass", "lov", "fid"},
"mgc": {"ptlrpc", "obdclass", "libcfs", "lnet"},
"obdclass": {"lnet", "libcfs"},
"obdecho": {"obdclass", "libcfs"},
"osc": {"libcfs", "obdclass", "ptlrpc", "lnet"},
"ptlrpc": {"lnet", "libcfs", "obdclass"},
},
expected: []string{
"libcfs",
"sunrpc",
"lnet",
"ksocklnd",
"ib_core",
"rdma_cm",
"in-kernel-ko2iblnd",
"ec",
"obdclass",
"ptlrpc",
"fid",
"fld",
"lmv",
"lov",
"osc",
"mdc",
"lustre",
"mgc",
"obdecho",
},
},
}
for _, testCase := range testCases {
order := ModuleInsertionOrder(testCase.modules, testCase.graph)
diff := cmp.Diff(order, testCase.expected)
if len(diff) > 0 {
t.Fatalf("order differs from expected: %s", diff)
}
}
}