Skip to content

Commit

Permalink
Use abs path to testing binary
Browse files Browse the repository at this point in the history
Use the full path to the `functional.test.exe` binary when sharing into
the uVM or container for the `TestHVSock_*` test cases in
`test\functional\hvsock_test.go` to prevent vSMB share issues.

Otherwise, `os.Args[0]` will return the path that the tests were run
with (e.g., `.\functional.test.exe`), which can cause vSMB to fail with
`The parameter is incorrect.` (likely because it cannot find the current
file).

Signed-off-by: Hamza El-Saawy <[email protected]>
  • Loading branch information
helsaawy committed Dec 17, 2024
1 parent 1a8c2e3 commit a5874d7
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 20 deletions.
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 binary will be run directly on a uVM, and not from within a container.
// For the later 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 = `C:\`
}

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
}

0 comments on commit a5874d7

Please sign in to comment.