Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixed test #145

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
7 changes: 3 additions & 4 deletions .github/workflows/compile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
build:
needs: formatting-check
runs-on: ${{ matrix.os }}
timeout-minutes: 6
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
Expand All @@ -38,17 +38,16 @@ jobs:
- name: Check out repository code
uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3
uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go }}
cache: true
- name: vet
run: go vet ./...
- name: Download Linux kernel
run: make download_kernel
- name: Unit Test
run: make test
timeout-minutes: 3
timeout-minutes: 5
- name: Build Linux
run: make -C example/linux
- name: Build GUI Linux
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ fmt:

.PHONY: test
test:
go test -p 1 -exec "go run $(PWD)/cmd/codesign" ./... -timeout 60s -v
go test -p 1 -exec "go run $(PWD)/cmd/codesign" ./... -timeout 5m -v

.PHONY: test/run
test/run:
Expand Down
12 changes: 6 additions & 6 deletions virtualization_11.m
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ void setStorageDevicesVZVirtualMachineConfiguration(void *config,
void VZVirtioSocketDevice_setSocketListenerForPort(void *socketDevice, void *vmQueue, void *listener, uint32_t port)
{
if (@available(macOS 11, *)) {
dispatch_sync((dispatch_queue_t)vmQueue, ^{
dispatch_async((dispatch_queue_t)vmQueue, ^{
[(VZVirtioSocketDevice *)socketDevice setSocketListener:(VZVirtioSocketListener *)listener forPort:port];
});
return;
Expand All @@ -622,7 +622,7 @@ void VZVirtioSocketDevice_setSocketListenerForPort(void *socketDevice, void *vmQ
void VZVirtioSocketDevice_removeSocketListenerForPort(void *socketDevice, void *vmQueue, uint32_t port)
{
if (@available(macOS 11, *)) {
dispatch_sync((dispatch_queue_t)vmQueue, ^{
dispatch_async((dispatch_queue_t)vmQueue, ^{
[(VZVirtioSocketDevice *)socketDevice removeSocketListenerForPort:port];
});
return;
Expand Down Expand Up @@ -773,7 +773,7 @@ bool requestStopVirtualMachine(void *machine, void *queue, void **error)
{
if (@available(macOS 11, *)) {
__block BOOL ret;
dispatch_sync((dispatch_queue_t)queue, ^{
dispatch_async((dispatch_queue_t)queue, ^{
ret = [(VZVirtualMachine *)machine requestStopWithError:(NSError *_Nullable *_Nullable)error];
});
return (bool)ret;
Expand All @@ -794,7 +794,7 @@ void startWithCompletionHandler(void *machine, void *queue, uintptr_t cgoHandle)
{
if (@available(macOS 11, *)) {
vm_completion_handler_t handler = makeVMCompletionHandler(cgoHandle);
dispatch_sync((dispatch_queue_t)queue, ^{
dispatch_async((dispatch_queue_t)queue, ^{
[(VZVirtualMachine *)machine startWithCompletionHandler:handler];
});
Block_release(handler);
Expand All @@ -808,7 +808,7 @@ void pauseWithCompletionHandler(void *machine, void *queue, uintptr_t cgoHandle)
{
if (@available(macOS 11, *)) {
vm_completion_handler_t handler = makeVMCompletionHandler(cgoHandle);
dispatch_sync((dispatch_queue_t)queue, ^{
dispatch_async((dispatch_queue_t)queue, ^{
[(VZVirtualMachine *)machine pauseWithCompletionHandler:handler];
});
Block_release(handler);
Expand All @@ -822,7 +822,7 @@ void resumeWithCompletionHandler(void *machine, void *queue, uintptr_t cgoHandle
{
if (@available(macOS 11, *)) {
vm_completion_handler_t handler = makeVMCompletionHandler(cgoHandle);
dispatch_sync((dispatch_queue_t)queue, ^{
dispatch_async((dispatch_queue_t)queue, ^{
[(VZVirtualMachine *)machine resumeWithCompletionHandler:handler];
});
Block_release(handler);
Expand Down
2 changes: 1 addition & 1 deletion virtualization_12.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ void stopWithCompletionHandler(void *machine, void *queue, uintptr_t cgoHandle)
{
if (@available(macOS 12, *)) {
vm_completion_handler_t handler = makeVMCompletionHandler(cgoHandle);
dispatch_sync((dispatch_queue_t)queue, ^{
dispatch_async((dispatch_queue_t)queue, ^{
[(VZVirtualMachine *)machine stopWithCompletionHandler:handler];
});
Block_release(handler);
Expand Down
4 changes: 2 additions & 2 deletions virtualization_12_arm64.m
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ VZMacHardwareModelStruct convertVZMacHardwareModel2Struct(void *hardwareModelPtr
__block VZMacOSInstaller *ret;
NSString *restoreImageFilePathNSString = [NSString stringWithUTF8String:restoreImageFilePath];
NSURL *restoreImageFileURL = [NSURL fileURLWithPath:restoreImageFilePathNSString];
dispatch_sync((dispatch_queue_t)vmQueue, ^{
dispatch_async((dispatch_queue_t)vmQueue, ^{
ret = [[VZMacOSInstaller alloc] initWithVirtualMachine:(VZVirtualMachine *)virtualMachine restoreImageURL:restoreImageFileURL];
});
return ret;
Expand All @@ -427,7 +427,7 @@ void installByVZMacOSInstaller(void *installerPtr, void *vmQueue, void *progress
{
if (@available(macOS 12, *)) {
VZMacOSInstaller *installer = (VZMacOSInstaller *)installerPtr;
dispatch_sync((dispatch_queue_t)vmQueue, ^{
dispatch_async((dispatch_queue_t)vmQueue, ^{
[installer installWithCompletionHandler:^(NSError *error) {
macOSInstallCompletionHandler(completionHandler, error);
}];
Expand Down
2 changes: 1 addition & 1 deletion virtualization_13.m
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ void startWithOptionsCompletionHandler(void *machine, void *queue, void *options
#ifdef INCLUDE_TARGET_OSX_13
if (@available(macOS 13, *)) {
vm_completion_handler_t handler = makeVMCompletionHandler(cgoHandle);
dispatch_sync((dispatch_queue_t)queue, ^{
dispatch_async((dispatch_queue_t)queue, ^{
[(VZVirtualMachine *)machine startWithOptions:options completionHandler:handler];
});
Block_release(handler);
Expand Down
4 changes: 2 additions & 2 deletions virtualization_14_arm64.m
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ void restoreMachineStateFromURLWithCompletionHandler(void *machine, void *queue,
NSString *saveFilePathNSString = [NSString stringWithUTF8String:saveFilePath];
NSURL *saveFileURL = [NSURL fileURLWithPath:saveFilePathNSString];
vm_completion_handler_t handler = makeVMCompletionHandler(cgoHandle);
dispatch_sync((dispatch_queue_t)queue, ^{
dispatch_async((dispatch_queue_t)queue, ^{
[(VZVirtualMachine *)machine restoreMachineStateFromURL:saveFileURL completionHandler:handler];
});
Block_release(handler);
Expand Down Expand Up @@ -74,7 +74,7 @@ void saveMachineStateToURLWithCompletionHandler(void *machine, void *queue, uint
NSString *saveFilePathNSString = [NSString stringWithUTF8String:saveFilePath];
NSURL *saveFileURL = [NSURL fileURLWithPath:saveFilePathNSString];
vm_completion_handler_t handler = makeVMCompletionHandler(cgoHandle);
dispatch_sync((dispatch_queue_t)queue, ^{
dispatch_async((dispatch_queue_t)queue, ^{
[(VZVirtualMachine *)machine saveMachineStateToURL:saveFileURL completionHandler:handler];
});
Block_release(handler);
Expand Down
131 changes: 95 additions & 36 deletions virtualization_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,25 @@ func newVirtualizationMachine(
t *testing.T,
configs ...func(*vz.VirtualMachineConfiguration) error,
) *Container {
t.Helper()
RETRY:
for i := 1; ; i++ {
container, err := newVirtualizationMachineErr(configs...)
if err != nil {
if isECONNRESET(err) {
time.Sleep(time.Second)
t.Logf("retry: %d", i)
continue RETRY
}
t.Fatal(err)
}
return container
}
}

func newVirtualizationMachineErr(
configs ...func(*vz.VirtualMachineConfiguration) error,
) (*Container, error) {
vmlinuz := "./testdata/Image"
initramfs := "./testdata/initramfs.cpio.gz"
bootLoader, err := vz.NewLinuxBootLoader(
Expand All @@ -123,44 +142,49 @@ func newVirtualizationMachine(
vz.WithInitrd(initramfs),
)
if err != nil {
t.Fatal(err)
return nil, err
}

config, err := setupConfiguration(bootLoader)
if err != nil {
t.Fatal(err)
return nil, err
}
for _, setConfig := range configs {
if err := setConfig(config); err != nil {
t.Fatal(err)
return nil, err
}
}

validated, err := config.Validate()
if !validated || err != nil {
t.Fatal(validated, err)
return nil, fmt.Errorf("validated=%v: %w", validated, err)
}

vm, err := vz.NewVirtualMachine(config)
if err != nil {
t.Fatal(err)
return nil, err
}
socketDevices := vm.SocketDevices()
if len(socketDevices) != 1 {
t.Fatalf("want the number of socket devices is 1 but got %d", len(socketDevices))
return nil, fmt.Errorf("want the number of socket devices is 1 but got %d", len(socketDevices))
}
socketDevice := socketDevices[0]

if canStart := vm.CanStart(); !canStart {
t.Fatal("want CanStart is true")
return nil, fmt.Errorf("want CanStart is true")
}

if err := vm.Start(); err != nil {
t.Fatal(err)
return nil, err
}

waitState(t, 3*time.Second, vm, vz.VirtualMachineStateStarting)
waitState(t, 3*time.Second, vm, vz.VirtualMachineStateRunning)
timeout := 3 * time.Second
if err := waitStateErr(timeout, vm, vz.VirtualMachineStateStarting); err != nil {
return nil, err
}
if err := waitStateErr(timeout, vm, vz.VirtualMachineStateRunning); err != nil {
return nil, err
}

sshConfig := testhelper.NewSshConfig("root", "passwd")

Expand All @@ -170,47 +194,77 @@ func newVirtualizationMachine(
// does not seem to have a connection timeout set.
if vz.Available(12) {
time.Sleep(5 * time.Second)
} else {
time.Sleep(time.Second)
}

RETRY:
for i := 1; ; i++ {
conn, err := socketDevice.Connect(2222)
if err != nil {
var nserr *vz.NSError
if !errors.As(err, &nserr) || i > 5 {
t.Fatal(err)
}
if nserr.Code == int(syscall.ECONNRESET) {
t.Logf("retry vsock connect: %d", i)
time.Sleep(time.Second)
continue RETRY
}
t.Fatalf("failed to connect vsock: %v", err)
stop := func() {
if vz.Available(12) {
vm.RequestStop()
} else {
vm.Stop()
}

sshClient, err := testhelper.NewSshClient(conn, ":22", sshConfig)
if err != nil {
conn.Close()
t.Fatalf("failed to create a new ssh client: %v", err)
LOOP:
for {
select {
case got := <-vm.StateChangedNotify():
if got == vz.VirtualMachineStateStopping {
continue LOOP
}
if got == vz.VirtualMachineStateStopped {
return
}
case <-time.After(timeout):
return
}
}
}

return &Container{
VirtualMachine: vm,
Client: sshClient,
}
conn, err := socketDevice.Connect(2222)
if err != nil {
stop()
return nil, fmt.Errorf("failed to connect vsock: %w", err)
}

sshClient, err := testhelper.NewSshClient(conn, ":22", sshConfig)
if err != nil {
conn.Close()
stop()
return nil, fmt.Errorf("failed to create a new ssh client: %w", err)
}

return &Container{
VirtualMachine: vm,
Client: sshClient,
}, nil
}

func isECONNRESET(err error) bool {
var nserr *vz.NSError
if !errors.As(err, &nserr) {
return false
}
return nserr.Code == int(syscall.ECONNRESET)
}

func waitState(t *testing.T, wait time.Duration, vm *vz.VirtualMachine, want vz.VirtualMachineState) {
t.Helper()
if err := waitStateErr(wait, vm, want); err != nil {
t.Fatal(err)
}
}

func waitStateErr(wait time.Duration, vm *vz.VirtualMachine, want vz.VirtualMachineState) error {
select {
case got := <-vm.StateChangedNotify():
if want != got {
t.Fatalf("unexpected state want %d but got %d", want, got)
return fmt.Errorf("unexpected state want %d but got %d", want, got)
}
case <-time.After(wait):
t.Fatal("failed to wait state changed notification")
return fmt.Errorf("failed to wait state changed notification")
}
return nil
}

func TestRun(t *testing.T) {
Expand Down Expand Up @@ -267,7 +321,12 @@ func TestRun(t *testing.T) {
// waitState(t, 5*time.Second, vm, vz.VirtualMachineStateStopping)
// waitState(t, 5*time.Second, vm, vz.VirtualMachineStateStopped)

sshSession.Run("poweroff")
if vz.Available(12) {
sshSession.Run("poweroff")
} else {
vm.Stop()
waitState(t, timeout, vm, vz.VirtualMachineStateStopping)
}

waitState(t, timeout, vm, vz.VirtualMachineStateStopped)

Expand All @@ -287,7 +346,7 @@ func TestStop(t *testing.T) {
vm := container.VirtualMachine

if got := vm.CanStop(); !got {
t.Fatal("want CanRequestStop is true")
t.Fatal("want CanStop is true")
}
if err := vm.Stop(); err != nil {
t.Fatal(err)
Expand Down