blob: adcfcb9f32757878aa49558944e686c44b72ab87 [file] [log] [blame] [edit]
package dkms
import (
"context"
"testing"
"cos.googlesource.com/cos/tools.git/src/pkg/fakes"
"cos.googlesource.com/cos/tools.git/src/pkg/gcs"
)
type Action int
const (
add Action = iota
build
install
remove
unbuild
uninstall
)
// This is used by TestTransitions and TestCachedTransitions to ensure that
// DKMS state transitions behave as expected.
type testTransition struct {
action Action
expectedStatus PackageStatus
}
var baseTransitions = []testTransition{
// tests +1 transition cases
{add, Added},
{build, Built},
{install, Installed},
{remove, Broken},
// tests +2 transition cases
{build, Built},
{remove, Broken},
{add, Added},
{install, Installed},
{remove, Broken},
// tests +3 transition cases
{install, Installed},
{remove, Broken},
// tests -1 transition cases
{install, Installed},
{uninstall, Built},
{unbuild, Added},
{remove, Broken},
// tests -2 transition cases
{install, Installed},
{unbuild, Added},
{install, Installed},
{uninstall, Built},
{remove, Broken},
// tests -3 transition cases
{install, Installed},
{remove, Broken},
}
// test cases where the state is not affected because the target
// state is already reached/passed
var noOpTransitions = []testTransition{
{remove, Broken},
{unbuild, Broken},
{uninstall, Broken},
{add, Added},
{add, Added},
{unbuild, Added},
{uninstall, Added},
{build, Built},
{add, Built},
{build, Built},
{uninstall, Built},
{install, Installed},
{add, Installed},
{build, Installed},
{install, Installed},
}
// test cases that are no-ops even when options.Force is true
var noOpTransitionsForce = []testTransition{
{remove, Broken},
{unbuild, Broken},
{uninstall, Broken},
{add, Added},
{add, Added},
{unbuild, Added},
{uninstall, Added},
{build, Built},
{build, Built},
{uninstall, Built},
{install, Installed},
{install, Installed},
}
// these test cases are no-ops by default because they would transition from
// a higher state to a lower state, but with options.Force, the state is
// lowered before performing the action
var loweringTransitionsForce = []testTransition{
{build, Built},
{add, Added}, // forced Add will remove/unbuild/uninstall, then add
{install, Installed},
{add, Added}, // forced Add will remove/unbuild/uninstall, then add
{install, Installed},
{build, Built}, // forced Build will unbuild/uninstall, then build
}
var transitions = append(baseTransitions, noOpTransitions...)
var transitionsForce = append(append(baseTransitions, noOpTransitionsForce...), loweringTransitionsForce...)
func TestTransitions(t *testing.T) {
options := &Options{
Force: false,
MakeVariables: "",
// the fake testing module does not have a properly formatted version,
// so we skip the version check
ForceVersionOverride: true,
}
trees := &Trees{
Dkms: t.TempDir(),
Source: "testdata/source-tree",
Kernel: "testdata/kernel-sources",
Install: t.TempDir(),
}
pkg := &Package{
Name: "mymodule",
Version: "1.0",
KernelVersion: "6.1.100",
Arch: "x86_64",
BuildId: "18244.151.14",
Trees: trees,
}
for _, transition := range transitions {
t.Logf("testing transition %v", transition)
var err error
switch transition.action {
case add:
err = Add(pkg, options)
case build:
err = Build(pkg, options)
case install:
err = Install(pkg, options)
case remove:
err = Remove(pkg)
case unbuild:
err = Unbuild(pkg)
case uninstall:
err = Uninstall(pkg)
}
if err != nil {
t.Fatalf("%v", err)
}
status := Status(pkg)
if status != transition.expectedStatus {
t.Fatalf("status was expected to be %v; got %v instead", transition.expectedStatus, status)
}
}
}
func TestTransitionsForce(t *testing.T) {
options := &Options{
// setting Force should also skip the version check, so we don't need
// to pass ForceVersionOverride
Force: true,
MakeVariables: "",
}
trees := &Trees{
Dkms: t.TempDir(),
Source: "testdata/source-tree",
Kernel: "testdata/kernel-sources",
Install: t.TempDir(),
}
pkg := &Package{
Name: "mymodule",
Version: "1.0",
KernelVersion: "6.1.100",
Arch: "x86_64",
BuildId: "18244.151.14",
Trees: trees,
}
for _, transition := range transitionsForce {
t.Logf("testing transition %v", transition)
var err error
switch transition.action {
case add:
err = Add(pkg, options)
case build:
err = Build(pkg, options)
case install:
err = Install(pkg, options)
case remove:
err = Remove(pkg)
case unbuild:
err = Unbuild(pkg)
case uninstall:
err = Uninstall(pkg)
}
if err != nil {
t.Fatalf("%v", err)
}
status := Status(pkg)
if status != transition.expectedStatus {
t.Fatalf("status was expected to be %v; got %v instead", transition.expectedStatus, status)
}
}
}
func TestCachedTransitions(t *testing.T) {
options := &Options{
Force: false,
Upload: true,
MakeVariables: "",
// the fake testing module does not have a properly formatted version,
// so we skip the version check
ForceVersionOverride: true,
}
trees := &Trees{
Dkms: t.TempDir(),
Source: "testdata/source-tree",
Kernel: "testdata/kernel-sources",
Install: t.TempDir(),
}
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")
for _, transition := range transitions {
var err error
switch transition.action {
case add:
err = CachedAdd(ctx, pkg, bucket, options)
case build:
err = CachedBuild(ctx, pkg, bucket, options)
case install:
err = CachedInstall(ctx, pkg, bucket, options)
case remove:
err = CachedRemove(ctx, pkg, bucket)
case unbuild:
err = CachedUnbuild(ctx, pkg, bucket)
case uninstall:
err = Uninstall(pkg)
}
if err != nil {
t.Fatalf("%v", err)
}
status := CachedStatus(ctx, pkg, bucket)
if status != transition.expectedStatus {
t.Fatalf("status was expected to be %v; got %v instead", transition.expectedStatus, status)
}
}
}