Skip to content

Commit

Permalink
Functional test housekeeping
Browse files Browse the repository at this point in the history
Remove unused/legacy functional test flags/environment variables.

Unify [TestMain] control flow, so there is only one exit call, and
`defer` is used to run cleanup after the tests are run.

Standardize UVM `default[L|W]COWOptions` to accept a context, and add
context parameter to `namespacedContext`

Remove all build tags aside from `functional`, since features are used
to select the tests to run. This standardizes the functional tests with
the cri-containerd tests, even though the feature names themselves are
different.

Add `test/pkg/uvm.CreateWCOW` function to mirror `CreateLCOW`, and add
`Create` and `CreateAndStart` functions that pick LCOW or WCOW based on
the options provided.

Have uVM scratch and image layers be created under a dedicated and
persisted folder within `%TEMP%` that is excluded from Windows defender.
(The folder will be removed during OS restart, regardless of contents.)

Remove copied OCI spec options from `test/internal/oci`, add new
options for creating HostProcess containers.

Add a `internal\sync.OnceValue`(`Ctx`) function that mirrors
`sync.OnceValues` (introduced in go1.21) to have a type-safe `Once`
function.

Check that required privileges are held (only once) when unpacking
Windows layers.

Fix LCOW tests in `lcow_test.go` that were setting `KernelDirect`
without also updating `KernelFile`.

Signed-off-by: Hamza El-Saawy <hamzaelsaawy@microsoft.com>
  • Loading branch information
helsaawy committed Nov 8, 2023
1 parent a690ec4 commit 1e84e8c
Show file tree
Hide file tree
Showing 32 changed files with 729 additions and 416 deletions.
94 changes: 62 additions & 32 deletions .github/workflows/ci.yml
Expand Up @@ -5,8 +5,14 @@ on:

env:
GO_VERSION: "1.19.x"

GO_BUILD_CMD: "go build \"-ldflags=-s -w\" -trimpath"
GO_BUILD_TEST_CMD: "go test -mod=mod -gcflags=all=-d=checkptr -c -tags functional"

GOTESTSUM_VERSION: "latest"
GOTESTCMD: "gotestsum --format standard-verbose --debug --"

GOTESTSUM_CMD: "gotestsum --format standard-verbose --debug --"
GOTESTSUM_CMD_RAW: "gotestsum --format standard-verbose --debug --raw-command -- go tool test2json -t"

jobs:
lint:
Expand Down Expand Up @@ -269,19 +275,19 @@ jobs:
run: go install gotest.tools/gotestsum@${{ env.GOTESTSUM_VERSION }}

- name: Test standard security policy
run: ${{ env.GOTESTCMD }} -timeout=30m -gcflags=all=-d=checkptr ./pkg/securitypolicy/...
run: ${{ env.GOTESTSUM_CMD }} -timeout=30m -gcflags=all=-d=checkptr ./pkg/securitypolicy/...

- name: Test rego security policy
run: ${{ env.GOTESTCMD }} -tags=rego -timeout=30m -gcflags=all=-d=checkptr ./pkg/securitypolicy/...
run: ${{ env.GOTESTSUM_CMD }} -tags=rego -timeout=30m -gcflags=all=-d=checkptr ./pkg/securitypolicy/...

- name: Test rego policy interpreter
run: ${{ env.GOTESTCMD }} -gcflags=all=-d=checkptr ./internal/regopolicyinterpreter/...
run: ${{ env.GOTESTSUM_CMD }} -gcflags=all=-d=checkptr ./internal/regopolicyinterpreter/...

- name: Run guest code unit tests
run: ${{ env.GOTESTCMD }} -gcflags=all=-d=checkptr ./internal/guest/...
run: ${{ env.GOTESTSUM_CMD }} -gcflags=all=-d=checkptr ./internal/guest/...

- name: Build gcs Testing Binary
run: go test -mod=mod -gcflags=all=-d=checkptr -c -tags functional ./gcs
run: ${{ env.GO_BUILD_TEST_CMD }} ./gcs
working-directory: test

test-windows:
Expand Down Expand Up @@ -310,34 +316,45 @@ jobs:

# run tests
- name: Test repo
run: ${{ env.GOTESTCMD }} -gcflags=all=-d=checkptr -tags admin ./...
run: ${{ env.GOTESTSUM_CMD }} -gcflags=all=-d=checkptr -tags admin -timeout=20m ./...

- name: Run non-functional tests
run: ${{ env.GOTESTCMD }} -mod=mod -gcflags=all=-d=checkptr ./internal/... ./pkg/...
run: ${{ env.GOTESTSUM_CMD }} -mod=mod -gcflags=all=-d=checkptr ./internal/... ./pkg/...
working-directory: test

- name: Run containerd-shim-runhcs-v1 tests
- name: Build and run containerd-shim-runhcs-v1 tests
shell: powershell
run: |
powershell {
cd '../..'
go build -trimpath -o './test/containerd-shim-runhcs-v1' ./cmd/containerd-shim-runhcs-v1
pwsh {
cd '..'
${{ env.GO_BUILD_CMD }} -o ./test ./cmd/containerd-shim-runhcs-v1 2>&1
}
if ( $LASTEXITCODE ) {
Write-Output '::error::Could not build containerd-shim-runhcs-v1.exe'
exit $LASTEXITCODE
}
${{ env.GOTESTCMD }} -mod=mod -tags functional -gcflags=all=-d=checkptr ./...
working-directory: test/containerd-shim-runhcs-v1
${{ env.GO_BUILD_TEST_CMD }} ./containerd-shim-runhcs-v1
if ( $LASTEXITCODE ) {
Write-Output '::error::Could not build containerd-shim-runhcs-v1.test.exe'
exit $LASTEXITCODE
}
${{ env.GOTESTSUM_CMD_RAW }} ./containerd-shim-runhcs-v1.test.exe '-test.v'
working-directory: test

# build testing binaries
- name: Build cri-containerd Testing Binary
run: go test -mod=mod -gcflags=all=-d=checkptr -c -tags functional ./cri-containerd
run: ${{ env.GO_BUILD_TEST_CMD }} ./cri-containerd
working-directory: test
- name: Build functional Testing Binary
run: go test -mod=mod -gcflags=all=-d=checkptr -c -tags functional ./functional
run: ${{ env.GO_BUILD_TEST_CMD }} ./functional
working-directory: test
- name: Build runhcs Testing Binary
run: go test -mod=mod -gcflags=all=-d=checkptr -c -tags functional ./runhcs
run: ${{ env.GO_BUILD_TEST_CMD }} ./runhcs
working-directory: test
- name: Build logging-driver Binary
run: go build -mod=mod -o sample-logging-driver.exe ./cri-containerd/helpers/log.go
run: ${{ env.GO_BUILD_CMD }} -mod=mod -o sample-logging-driver.exe ./cri-containerd/helpers/log.go
working-directory: test

- uses: actions/upload-artifact@v3
Expand Down Expand Up @@ -474,7 +491,7 @@ jobs:
working-directory: src/github.com/Microsoft/hcsshim
shell: powershell
run: |
go build -mod vendor -o "${{ github.workspace }}/src/github.com/containerd/containerd/bin/containerd-shim-runhcs-v1.exe" .\cmd\containerd-shim-runhcs-v1
${{ env.GO_BUILD_CMD }} -mod vendor -o "${{ github.workspace }}/src/github.com/containerd/containerd/bin/containerd-shim-runhcs-v1.exe" .\cmd\containerd-shim-runhcs-v1
- name: Install gotestsum
run: go install gotest.tools/gotestsum@${{ env.GOTESTSUM_VERSION }}
Expand Down Expand Up @@ -593,22 +610,35 @@ jobs:
$LASTEXITCODE = 0
}
- run: go build ./cmd/containerd-shim-runhcs-v1
- run: go build ./cmd/runhcs
- run: go build ./cmd/tar2ext4
- run: go build ./cmd/wclayer
- run: go build ./cmd/device-util
- run: go build ./cmd/ncproxy
- run: go build ./cmd/dmverity-vhd
- run: go build ./cmd/dmverity-vhd
- run: ${{ env.GO_BUILD_CMD }} ./cmd/containerd-shim-runhcs-v1
name: Build containerd-shim-runhcs-v1.exe
- run: ${{ env.GO_BUILD_CMD }} ./cmd/runhcs
name: Build runhcs.exe
- run: ${{ env.GO_BUILD_CMD }} ./cmd/tar2ext4
name: Build tar2ext4.exe
- run: ${{ env.GO_BUILD_CMD }} ./cmd/wclayer
name: Build wclayer.exe
- run: ${{ env.GO_BUILD_CMD }} ./cmd/device-util
name: Build device-util.exe
- run: ${{ env.GO_BUILD_CMD }} ./cmd/ncproxy
name: Build ncproxy.exe
- run: ${{ env.GO_BUILD_CMD }} ./cmd/dmverity-vhd
name: Build dmverity-vhd.exe
- run: ${{ env.GO_BUILD_CMD }} ./cmd/dmverity-vhd
name: Build dmverity-vhd
env:
GOOS: linux
GOARCH: amd64
- run: go build ./internal/tools/grantvmgroupaccess
- run: go build ./internal/tools/networkagent
- run: go build ./internal/tools/securitypolicy
- run: go build ./internal/tools/uvmboot
- run: go build ./internal/tools/zapdir
- run: ${{ env.GO_BUILD_CMD }} ./internal/tools/grantvmgroupaccess
name: Build grantvmgroupaccess.exe
- run: ${{ env.GO_BUILD_CMD }} ./internal/tools/networkagent
name: Build networkagent.exe
- run: ${{ env.GO_BUILD_CMD }} ./internal/tools/securitypolicy
name: Build securitypolicy.exe
- run: ${{ env.GO_BUILD_CMD }} ./internal/tools/uvmboot
name: Build uvmboot.exe
- run: ${{ env.GO_BUILD_CMD }} ./internal/tools/zapdir
name: Build zapdir.exe

- uses: actions/upload-artifact@v3
if: ${{ github.event_name == 'pull_request' }}
Expand Down
1 change: 1 addition & 0 deletions internal/log/context.go
Expand Up @@ -101,6 +101,7 @@ func WithContext(ctx context.Context, entry *logrus.Entry) (context.Context, *lo
// operations triggered by the cancellation require a non-cancelled context to
// execute.
func Copy(dst context.Context, src context.Context) context.Context {
// TODO (go1.21): https://pkg.go.dev/context#WithoutCancel
if s := trace.FromContext(src); s != nil {
dst = trace.NewContext(dst, s)
}
Expand Down
41 changes: 41 additions & 0 deletions internal/sync/once.go
@@ -0,0 +1,41 @@
package sync

import (
"context"
"sync"
)

// TODO (go1.21): use pkg.go.dev/sync#OnceValues

// OnceValue is a wrapper around [sync.Once] that runs f only once and
// returns both a value (of type T) and an error.
func OnceValue[T any](f func() (T, error)) func() (T, error) {
var (
once sync.Once
v T
err error
)

return func() (T, error) {
once.Do(func() {
v, err = f()
})
return v, err
}
}

// NewOnce is similar to [OnceValue], but allows passing a context to f.
func OnceValueCtx[T any](f func(ctx context.Context) (T, error)) func(context.Context) (T, error) {
var (
once sync.Once
v T
err error
)

return func(ctx context.Context) (T, error) {
once.Do(func() {
v, err = f(ctx)
})
return v, err
}
}
1 change: 0 additions & 1 deletion pkg/cimfs/cim_test.go
Expand Up @@ -138,5 +138,4 @@ func TestCimReadWrite(t *testing.T) {
}
}
}

}
12 changes: 6 additions & 6 deletions test/functional/lcow_bench_test.go
Expand Up @@ -15,7 +15,7 @@ import (
)

func BenchmarkLCOW_UVM(b *testing.B) {
requireFeatures(b, featureLCOW)
requireFeatures(b, featureLCOW, featureUVM)
require.Build(b, osversion.RS5)

pCtx := context.Background()
Expand All @@ -26,7 +26,7 @@ func BenchmarkLCOW_UVM(b *testing.B) {
for i := 0; i < b.N; i++ {
ctx, cancel := context.WithTimeout(pCtx, benchmarkIterationTimeout)

opts := defaultLCOWOptions(b)
opts := defaultLCOWOptions(ctx, b)
opts.ID += util.RandNameSuffix(i)

b.StartTimer()
Expand All @@ -44,7 +44,7 @@ func BenchmarkLCOW_UVM(b *testing.B) {
for i := 0; i < b.N; i++ {
ctx, cancel := context.WithTimeout(pCtx, benchmarkIterationTimeout)

opts := defaultLCOWOptions(b)
opts := defaultLCOWOptions(ctx, b)
opts.ID += util.RandNameSuffix(i)
vm, cleanup := uvm.CreateLCOW(ctx, b, opts)

Expand All @@ -65,7 +65,7 @@ func BenchmarkLCOW_UVM(b *testing.B) {
for i := 0; i < b.N; i++ {
ctx, cancel := context.WithTimeout(pCtx, benchmarkIterationTimeout)

opts := defaultLCOWOptions(b)
opts := defaultLCOWOptions(ctx, b)
opts.ID += util.RandNameSuffix(i)
vm, cleanup := uvm.CreateLCOW(ctx, b, opts)
uvm.Start(ctx, b, vm)
Expand All @@ -88,13 +88,13 @@ func BenchmarkLCOW_UVM(b *testing.B) {
for i := 0; i < b.N; i++ {
ctx, cancel := context.WithTimeout(pCtx, benchmarkIterationTimeout)

opts := defaultLCOWOptions(b)
opts := defaultLCOWOptions(ctx, b)
opts.ID += util.RandNameSuffix(i)
vm, cleanup := uvm.CreateLCOW(ctx, b, opts)
uvm.Start(ctx, b, vm)

b.StartTimer()
if err := vm.Close(); err != nil {
if err := vm.CloseCtx(ctx); err != nil {
b.Fatalf("could not kill uvm %q: %v", vm.ID(), err)
}
b.StopTimer()
Expand Down
18 changes: 9 additions & 9 deletions test/functional/lcow_container_bench_test.go
Expand Up @@ -30,10 +30,10 @@ import (
)

func BenchmarkLCOW_Container(b *testing.B) {
requireFeatures(b, featureLCOW, featureContainer)
requireFeatures(b, featureLCOW, featureUVM, featureContainer)
require.Build(b, osversion.RS5)

pCtx := namespacedContext()
pCtx := namespacedContext(context.Background())
ls := linuxImageLayers(pCtx, b)

// Create a new uVM per benchmark in case any left over state lingers
Expand Down Expand Up @@ -65,7 +65,7 @@ func BenchmarkLCOW_Container(b *testing.B) {
vmCleanup(ctx)
}
// recreate the uVM
opts := defaultLCOWOptions(b)
opts := defaultLCOWOptions(ctx, b)
opts.ID += util.RandNameSuffix(i)
vm, vmCleanup = testuvm.CreateLCOW(ctx, b, opts)
testuvm.Start(ctx, b, vm)
Expand Down Expand Up @@ -145,7 +145,7 @@ func BenchmarkLCOW_Container(b *testing.B) {
vmCleanup(ctx)
}
// recreate the uVM
opts := defaultLCOWOptions(b)
opts := defaultLCOWOptions(ctx, b)
opts.ID += util.RandNameSuffix(i)
vm, vmCleanup = testuvm.CreateLCOW(ctx, b, opts)
testuvm.Start(ctx, b, vm)
Expand Down Expand Up @@ -200,7 +200,7 @@ func BenchmarkLCOW_Container(b *testing.B) {
vmCleanup(ctx)
}
// recreate the uVM
opts := defaultLCOWOptions(b)
opts := defaultLCOWOptions(ctx, b)
opts.ID += util.RandNameSuffix(i)
vm, vmCleanup = testuvm.CreateLCOW(ctx, b, opts)
testuvm.Start(ctx, b, vm)
Expand Down Expand Up @@ -258,7 +258,7 @@ func BenchmarkLCOW_Container(b *testing.B) {
vmCleanup(ctx)
}
// recreate the uVM
opts := defaultLCOWOptions(b)
opts := defaultLCOWOptions(ctx, b)
opts.ID += util.RandNameSuffix(i)
vm, vmCleanup = testuvm.CreateLCOW(ctx, b, opts)
testuvm.Start(ctx, b, vm)
Expand Down Expand Up @@ -322,7 +322,7 @@ func BenchmarkLCOW_Container(b *testing.B) {
vmCleanup(ctx)
}
// recreate the uVM
opts := defaultLCOWOptions(b)
opts := defaultLCOWOptions(ctx, b)
opts.ID += util.RandNameSuffix(i)
vm, vmCleanup = testuvm.CreateLCOW(ctx, b, opts)
testuvm.Start(ctx, b, vm)
Expand Down Expand Up @@ -387,7 +387,7 @@ func BenchmarkLCOW_Container(b *testing.B) {
vmCleanup(ctx)
}
// recreate the uVM
opts := defaultLCOWOptions(b)
opts := defaultLCOWOptions(ctx, b)
opts.ID += util.RandNameSuffix(i)
vm, vmCleanup = testuvm.CreateLCOW(ctx, b, opts)
testuvm.Start(ctx, b, vm)
Expand Down Expand Up @@ -452,7 +452,7 @@ func BenchmarkLCOW_Container(b *testing.B) {
vmCleanup(ctx)
}
// recreate the uVM
opts := defaultLCOWOptions(b)
opts := defaultLCOWOptions(ctx, b)
opts.ID += util.RandNameSuffix(i)
vm, vmCleanup = testuvm.CreateLCOW(ctx, b, opts)
testuvm.Start(ctx, b, vm)
Expand Down
19 changes: 10 additions & 9 deletions test/functional/lcow_container_test.go
Expand Up @@ -4,6 +4,7 @@
package functional

import (
"context"
"strings"
"testing"

Expand All @@ -21,12 +22,12 @@ import (
)

func TestLCOW_ContainerLifecycle(t *testing.T) {
requireFeatures(t, featureLCOW, featureContainer)
requireFeatures(t, featureLCOW, featureUVM, featureContainer)
require.Build(t, osversion.RS5)

ctx := namespacedContext()
ctx := namespacedContext(context.Background())
ls := linuxImageLayers(ctx, t)
opts := defaultLCOWOptions(t)
opts := defaultLCOWOptions(ctx, t)
opts.ID += util.RandNameSuffix()
vm := uvm.CreateAndStartLCOWFromOpts(ctx, t, opts)

Expand Down Expand Up @@ -74,12 +75,12 @@ var ioTests = []struct {
}

func TestLCOW_ContainerIO(t *testing.T) {
requireFeatures(t, featureLCOW, featureContainer)
requireFeatures(t, featureLCOW, featureUVM, featureContainer)
require.Build(t, osversion.RS5)

ctx := namespacedContext()
ctx := namespacedContext(context.Background())
ls := linuxImageLayers(ctx, t)
opts := defaultLCOWOptions(t)
opts := defaultLCOWOptions(ctx, t)
opts.ID += util.RandNameSuffix()
cache := layers.CacheFile(ctx, t, "")
vm := uvm.CreateAndStartLCOWFromOpts(ctx, t, opts)
Expand Down Expand Up @@ -117,12 +118,12 @@ func TestLCOW_ContainerIO(t *testing.T) {
}

func TestLCOW_ContainerExec(t *testing.T) {
requireFeatures(t, featureLCOW, featureContainer)
requireFeatures(t, featureLCOW, featureUVM, featureContainer)
require.Build(t, osversion.RS5)

ctx := namespacedContext()
ctx := namespacedContext(context.Background())
ls := linuxImageLayers(ctx, t)
opts := defaultLCOWOptions(t)
opts := defaultLCOWOptions(ctx, t)
opts.ID += util.RandNameSuffix()
vm := uvm.CreateAndStartLCOWFromOpts(ctx, t, opts)

Expand Down

0 comments on commit 1e84e8c

Please sign in to comment.