Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 41 additions & 20 deletions test/functional/hvsock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import (
"fmt"
"io"
"net"
"os"
"path/filepath"
"sync"
"testing"
"time"
Expand All @@ -22,6 +20,7 @@ import (
"golang.org/x/sys/windows"

hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
"github.com/Microsoft/hcsshim/internal/uvm"
"github.com/Microsoft/hcsshim/osversion"

testcmd "github.com/Microsoft/hcsshim/test/internal/cmd"
Expand Down Expand Up @@ -134,8 +133,7 @@ func TestHVSock_UVM_HostBind(t *testing.T) {
return err
})

guestPath := filepath.Join(`C:\`, filepath.Base(os.Args[0]))
testuvm.Share(ctx, t, vm, os.Args[0], guestPath, true)
guestPath := reExecSelfShareUVM(ctx, t, vm, "")

reexecCmd := fmt.Sprintf(`%s -test.run=%s`, guestPath, util.TestNameRegex(t))
if testing.Verbose() {
Expand Down Expand Up @@ -231,8 +229,7 @@ func TestHVSock_UVM_GuestBind(t *testing.T) {
ctx, cancel := context.WithTimeout(ctx, hvsockTestTimeout) //nolint:govet // ctx is shadowed
t.Cleanup(cancel)

guestPath := filepath.Join(`C:\`, filepath.Base(os.Args[0]))
testuvm.Share(ctx, t, vm, os.Args[0], guestPath, true)
guestPath := reExecSelfShareUVM(ctx, t, vm, "")

reexecCmd := fmt.Sprintf(`%s -test.run=%s`, guestPath, util.TestNameRegex(t))
if testing.Verbose() {
Expand Down Expand Up @@ -353,11 +350,7 @@ func TestHVSock_Container_HostBind(t *testing.T) {

vm := testuvm.CreateAndStart(ctx, t, opts)

guestPath := filepath.Join(`C:\`, filepath.Base(os.Args[0]))
reexecCmd := fmt.Sprintf(`%s -test.run=%s`, guestPath, util.TestNameRegex(t))
if testing.Verbose() {
reexecCmd += " -test.v"
}
hostPath, guestPath, reExecCmd := reExecSelfCmd(ctx, t, "")

cID := vm.ID() + "-container"
scratch := layers.WCOWScratchDir(ctx, t, "")
Expand All @@ -366,9 +359,9 @@ func TestHVSock_Container_HostBind(t *testing.T) {
testoci.WithWindowsLayerFolders(append(windowsImageLayers(ctx, t), scratch)),
ctrdoci.WithUsername(`NT AUTHORITY\SYSTEM`),
ctrdoci.WithEnv([]string{util.ReExecEnv + "=1"}),
ctrdoci.WithProcessCommandLine(reexecCmd),
ctrdoci.WithProcessCommandLine(reExecCmd),
ctrdoci.WithMounts([]specs.Mount{{
Source: os.Args[0],
Source: hostPath,
Destination: guestPath,
Options: []string{"ro"},
}}),
Expand Down Expand Up @@ -501,11 +494,7 @@ func TestHVSock_Container_GuestBind(t *testing.T) {

vm := testuvm.CreateAndStart(ctx, t, opts)

guestPath := filepath.Join(`C:\`, filepath.Base(os.Args[0]))
reexecCmd := fmt.Sprintf(`%s -test.run=%s`, guestPath, util.TestNameRegex(t))
if testing.Verbose() {
reexecCmd += " -test.v"
}
hostPath, guestPath, reExecCmd := reExecSelfCmd(ctx, t, "")

cID := vm.ID() + "-container"
scratch := layers.WCOWScratchDir(ctx, t, "")
Expand All @@ -514,9 +503,9 @@ func TestHVSock_Container_GuestBind(t *testing.T) {
testoci.WithWindowsLayerFolders(append(windowsImageLayers(ctx, t), scratch)),
ctrdoci.WithUsername(`NT AUTHORITY\SYSTEM`),
ctrdoci.WithEnv([]string{util.ReExecEnv + "=1"}),
ctrdoci.WithProcessCommandLine(reexecCmd),
ctrdoci.WithProcessCommandLine(reExecCmd),
ctrdoci.WithMounts([]specs.Mount{{
Source: os.Args[0],
Source: hostPath,
Destination: guestPath,
Options: []string{"ro"},
}}),
Expand Down Expand Up @@ -1148,3 +1137,35 @@ func goBlockT[T any](f func() T) <-chan T {

return ch
}

// reExecSelfShareUVM shares the current testing binary directly into the specified uVM,
//
// This assumes that the binary will be run directly on a uVM, and not from within a container.
// For the latter case, see [reExecSelfCmd].
//
// See [util.ReExecSelfGuestPath] for information on generating the guest path.
func reExecSelfShareUVM(ctx context.Context, tb testing.TB, vm *uvm.UtilityVM, base string) string {
tb.Helper()

self, guestPath := util.ReExecSelfGuestPath(ctx, tb, base)
testuvm.Share(ctx, tb, vm, self, guestPath, true)

return guestPath
}

// reExecSelfCmd returns the host and guest path for the current test binary, as well as
// the appropriate re-exec command to configure the container spec with.
//
// See [reExecSelfShareUVM] for more details.
func reExecSelfCmd(ctx context.Context, tb testing.TB, base string) (string, string, string) {
tb.Helper()

self, guestPath := util.ReExecSelfGuestPath(ctx, tb, base)
c := fmt.Sprintf(`%s -test.run=%s`, guestPath, util.TestNameRegex(tb))

if testing.Verbose() {
c += " -test.v"
}

return self, guestPath, c
}
29 changes: 29 additions & 0 deletions test/internal/util/reexec_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//go:build windows

package util

import (
"context"
"path/filepath"
"testing"
)

// windows only because TestingBinaryPath is Windows only as well, and the default path is `C:\`

// Default path to share the current testing binary under.
const ReExecDefaultGuestPathBase = `C:\`

// ReExecSelfGuestPath returns the path to the current testing binary, as well as the
// path should be shared (under the path specified by base).
//
// If base is empty, [ReExecDefaultGuestPathBase] will be used.
func ReExecSelfGuestPath(ctx context.Context, tb testing.TB, base string) (string, string) {
tb.Helper()

if base == "" {
base = ReExecDefaultGuestPathBase
}

self := TestingBinaryPath(ctx, tb)
return self, filepath.Join(base, filepath.Base(self))
}
27 changes: 27 additions & 0 deletions test/internal/util/util_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ package util

import (
"context"
"fmt"
"os"
"sync"
"testing"

"github.com/Microsoft/go-winio/pkg/fs"

"github.com/Microsoft/hcsshim/internal/wclayer"
)
Expand All @@ -17,3 +22,25 @@ func DestroyLayer(ctx context.Context, p string) (err error) {
}
return repeat(func() error { return wclayer.DestroyLayer(ctx, p) }, RemoveAttempts, RemoveWait)
}

// executablePathOnce returns the current testing binary image
var executablePathOnce = sync.OnceValues(func() (string, error) {
// use [os.Executable] over `os.Args[0]` to make sure path is absolute
// as always, this shouldn't really fail, but just to be safe...
p, err := os.Executable()
if err != nil {
return "", fmt.Errorf("retrieve executable path: %w", err)
}
// just to be safe (and address the comments on [os.Executable]), resolve the path
return fs.ResolvePath(p)
})

func TestingBinaryPath(_ context.Context, tb testing.TB) string {
tb.Helper()

p, err := executablePathOnce()
if err != nil {
tb.Fatalf("could not get testing binary path: %v", err)
}
return p
}
Loading