| 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) |
| } |
| } |
| } |