blob: 15c5800a734bfeecf195cf9086e12b5da0e1c883 [file] [log] [blame]
package dkms
import (
"context"
"os"
"path"
"sort"
"strings"
"testing"
"cos.googlesource.com/cos/tools.git/src/pkg/fakes"
"cos.googlesource.com/cos/tools.git/src/pkg/fs"
"cos.googlesource.com/cos/tools.git/src/pkg/gcs"
"github.com/google/go-cmp/cmp"
)
func TestBuild(t *testing.T) {
options := &Options{
Force: false,
MakeVariables: "",
InstallBuildDependencies: false,
}
trees := &Trees{
Dkms: t.TempDir(),
Source: "testdata/source-tree",
Kernel: "testdata/kernel-source/lib/modules/6.1.100/build",
}
pkg := &Package{
Name: "mymodule",
Version: "1.0",
KernelVersion: "6.1.100",
Arch: "x86_64",
BuildId: "18244.151.14",
Trees: trees,
}
err := Build(pkg, options)
if err != nil {
t.Fatalf("%v", err)
}
makefilePath := path.Join(trees.Dkms, "mymodule", "1.0", "6.1.100", "x86_64", "18244.151.14", "source", "Makefile")
if !fs.IsFile(makefilePath) {
t.Fatalf("expected to find file %s after adding sources", makefilePath)
}
buildMakefilePath := path.Join(trees.Dkms, "mymodule", "1.0", "6.1.100", "x86_64", "18244.151.14", "build", "Makefile")
if !fs.IsFile(buildMakefilePath) {
t.Fatalf("expected to find file %s after building", buildMakefilePath)
}
builtModulePath := path.Join(trees.Dkms, "mymodule", "1.0", "6.1.100", "x86_64", "18244.151.14", "build", "mymodule.ko")
if !fs.IsFile(builtModulePath) {
t.Fatalf("expected to find file %s after building", builtModulePath)
}
}
func TestBuildModuleSigning(t *testing.T) {
signingDir := t.TempDir()
options := &Options{
Force: false,
MakeVariables: "",
InstallBuildDependencies: false,
Hash: "sha256",
PrivateKeyPath: path.Join(signingDir, "rsaKey.pem"),
CertificatePath: path.Join(signingDir, "cert.der"),
}
trees := &Trees{
Dkms: t.TempDir(),
Source: "testdata/source-tree",
Kernel: "testdata/kernel-source/lib/modules/6.1.100/build",
}
pkg := &Package{
Name: "mymodule",
Version: "1.0",
KernelVersion: "6.1.100",
Arch: "x86_64",
BuildId: "18244.151.14",
Trees: trees,
}
key, keyBytes, err := generateRSAPrivateKey()
if err != nil {
t.Fatalf("failed to generate rsa key: %v", err)
}
if err = os.WriteFile(options.PrivateKeyPath, keyBytes, 0600); err != nil {
t.Fatalf("failed to write rsa key to file (%s): %v", options.PrivateKeyPath, err)
}
certBytes, err := generateCertificate(key)
if err != nil {
t.Fatalf("failed to generate certificate: %v", err)
}
if err = os.WriteFile(options.CertificatePath, certBytes, 0600); err != nil {
t.Fatalf("failed to write certificate to file (%s): %v", options.CertificatePath, err)
}
err = Build(pkg, options)
if err != nil {
t.Fatalf("%v", err)
}
builtModulePath := path.Join(trees.Dkms, "mymodule", "1.0", "6.1.100", "x86_64", "18244.151.14", "build", "mymodule.ko")
if !fs.IsFile(builtModulePath) {
t.Fatalf("expected to find file %s after building", builtModulePath)
}
moduleBytes, err := os.ReadFile(builtModulePath)
if err != nil {
t.Fatalf("failed to read module: %s", builtModulePath)
}
expectedMessage := []byte("~Module signature appended~\n")
diff := cmp.Diff(expectedMessage, moduleBytes[len(moduleBytes)-len(expectedMessage):])
if diff != "" {
t.Fatalf("expected signature did not match\ndiff: %s", diff)
}
}
func TestCachedBuild(t *testing.T) {
options := &Options{
Force: false,
MakeVariables: "",
InstallBuildDependencies: false,
Upload: true,
}
trees := &Trees{
Dkms: t.TempDir(),
Source: "testdata/source-tree",
Kernel: "testdata/kernel-source/lib/modules/6.1.100/build",
}
pkg := &Package{
Name: "mymodule",
Version: "1.0",
KernelVersion: "6.1.100",
Arch: "x86_64",
BuildId: "18244.151.14",
Trees: trees,
}
ctx := context.Background()
fakeGCS := fakes.GCSForTest(t)
fakeGCS.LogMissing = false
bucket := gcs.NewGCSBucket(fakeGCS.Client, "test", "dkms")
err := CachedBuild(ctx, pkg, bucket, options)
if err != nil {
t.Fatalf("%v", err)
}
cacheMakefilePath := path.Join("mymodule", "1.0", "6.1.100", "x86_64", "18244.151.14", "source", "Makefile")
makefilePath := path.Join(trees.Dkms, cacheMakefilePath)
if !fs.IsFile(makefilePath) {
t.Fatalf("expected to find file %s after adding sources", makefilePath)
}
buildMakefilePath := path.Join(trees.Dkms, "mymodule", "1.0", "6.1.100", "x86_64", "18244.151.14", "build", "Makefile")
if !fs.IsFile(buildMakefilePath) {
t.Fatalf("expected to find file %s after building", makefilePath)
}
cacheBuiltModulePath := path.Join("mymodule", "1.0", "6.1.100", "x86_64", "18244.151.14", "build", "mymodule.ko")
builtModulePath := path.Join(trees.Dkms, cacheBuiltModulePath)
if !fs.IsFile(builtModulePath) {
t.Fatalf("expected to find file %s after building", makefilePath)
}
cachedMakefileExists, err := bucket.Exists(ctx, cacheMakefilePath)
if err != nil {
t.Fatalf("failed to check if %s exists", cacheMakefilePath)
}
if !cachedMakefileExists {
t.Fatalf("expected to find file %s in cache after adding sources", cacheMakefilePath)
}
cachedModuleExists, err := bucket.Exists(ctx, cacheBuiltModulePath)
if err != nil {
t.Fatalf("failed to check if %s exists", cacheBuiltModulePath)
}
if !cachedModuleExists {
t.Fatalf("expected to find file %s in cache after building modules", cacheBuiltModulePath)
}
}
func TestDefaultMakeVariables(t *testing.T) {
trees := &Trees{
Kernel: "testdata/kernel-sources",
}
pkg := &Package{
Arch: "abc",
Trees: trees,
}
variables, err := DefaultMakeVariables(pkg)
if err != nil {
t.Fatalf("%v", err)
}
expectedList := []string{
"ARCH=abc",
// because CC and CXX are loaded from toolchain_env, the arch will be
// arch from the file and not the argument to DefaultMakeVariables
"CC=toolchain/bin/x86_64-cros-linux-gnu-clang",
"CXX=toolchain/bin/x86_64-cros-linux-gnu-clang++",
"LD=toolchain/bin/abc-cros-linux-gnu-ld.lld",
"STRIP=toolchain/bin/llvm-strip",
"OBJCOPY=toolchain/bin/llvm-objcopy",
"HOSTCC=abc-pc-linux-gnu-clang",
"HOSTCXX=abc-pc-linux-gnu-clang++",
"HOSTLD=abc-pc-linux-gnu-clang",
}
sort.Strings(expectedList)
expected := strings.Join(expectedList, " ")
diff := cmp.Diff(expected, variables)
if diff != "" {
t.Fatalf("default variables did not match expected\ndiff: %s", diff)
}
}
func TestApplyPatch(t *testing.T) {
buildDir := t.TempDir()
if err := fs.CopyDir("testdata/source-tree/mymodule-1.0", buildDir, 0777); err != nil {
t.Fatalf("%v", err)
}
patchPath := path.Join(buildDir, "patches", "a.patch")
if err := ApplyPatch(buildDir, patchPath); err != nil {
t.Fatalf("%v", err)
}
contents, err := os.ReadFile(path.Join(buildDir, "mymodule.c"))
if err != nil {
t.Fatalf("%v", err)
}
text := string(contents)
if !strings.Contains(text, "patched") {
t.Fatalf("expected mymodule.c to have comment `//patched` after patch is applied")
}
}
func TestInstallBuildDependencies(t *testing.T) {
downloader := fakeDownloader{}
ctx := context.Background()
targetDir := t.TempDir()
defer os.RemoveAll(targetDir)
err := installBuildDependencies(ctx, &downloader, targetDir)
if err != nil {
t.Errorf("failed to install build dependencies headers: %v", err)
}
if !KernelHeadersInstalled(targetDir) {
t.Errorf("expected headers to be installed")
}
if !CompilerToolchainInstalled(targetDir) {
t.Errorf("expected compiler toolchain to be installed")
}
}