mirror of
https://github.com/cirruslabs/orchard.git
synced 2026-09-30 12:01:15 +02:00
* Regenerate .pb with protoc-gen-go v1.36.11 * Support running host processes alongside VMs * Replace existing host processes when starting a set
171 lines
4.3 KiB
Go
171 lines
4.3 KiB
Go
//nolint:goconst,noctx,testpackage // Preserve the original helper-process fixtures.
|
|
package hostprocess
|
|
|
|
import (
|
|
"net"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/cirruslabs/orchard/internal/worker/ondiskname"
|
|
v1 "github.com/cirruslabs/orchard/pkg/resource/v1"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
const (
|
|
testHelperArg = "--orchard-host-process-test-helper"
|
|
testHelperEnv = "ORCHARD_HOST_PROCESS_TEST_ENV"
|
|
testHelperInheritedEnv = "ORCHARD_HOST_PROCESS_TEST_INHERITED_ENV"
|
|
)
|
|
|
|
func TestMain(m *testing.M) {
|
|
if len(os.Args) == 2 && os.Args[1] == testHelperArg {
|
|
os.Exit(runTestHelper())
|
|
}
|
|
|
|
os.Exit(m.Run())
|
|
}
|
|
|
|
func TestSetStartAndStop(t *testing.T) {
|
|
t.Setenv(testHelperInheritedEnv, "must-not-be-inherited")
|
|
|
|
// Use this test binary as a host process
|
|
executable, err := os.Executable()
|
|
require.NoError(t, err)
|
|
|
|
// Create an empty host process set
|
|
set := NewSet("", "", ondiskname.OnDiskName{})
|
|
t.Cleanup(set.Stop)
|
|
|
|
// Ensure that a new set is not ready until started
|
|
require.False(t, set.Ready())
|
|
|
|
// Start the first host process
|
|
require.NoError(t, set.Start(t.Context(), []v1.HostProcess{{
|
|
Name: "first",
|
|
Program: executable,
|
|
Args: []string{testHelperArg},
|
|
Env: map[string]string{
|
|
testHelperEnv: "set",
|
|
"PATH": "must-not-win",
|
|
"ORCHARD_PROCESS_SOCKET": "/must-not-win",
|
|
},
|
|
}}))
|
|
require.True(t, set.Ready())
|
|
|
|
// Ensure that the first host process is reachable
|
|
connection, err := set.Dial(t.Context(), "first")
|
|
require.NoError(t, err)
|
|
require.NoError(t, connection.Close())
|
|
|
|
// A failed replacement leaves the set not ready
|
|
require.Error(t, set.Replace(t.Context(), []v1.HostProcess{{
|
|
Name: "invalid",
|
|
Program: "/does/not/exist",
|
|
}}))
|
|
require.False(t, set.Ready())
|
|
_, err = set.Dial(t.Context(), "first")
|
|
require.Error(t, err)
|
|
|
|
// Replace the first host process
|
|
require.NoError(t, set.Replace(t.Context(), []v1.HostProcess{{
|
|
Name: "replacement",
|
|
Program: executable,
|
|
Args: []string{testHelperArg},
|
|
Env: map[string]string{
|
|
testHelperEnv: "set",
|
|
"PATH": "must-not-win",
|
|
"ORCHARD_PROCESS_SOCKET": "/must-not-win",
|
|
},
|
|
}}))
|
|
require.True(t, set.Ready())
|
|
|
|
// Ensure that only the replacement host process is reachable
|
|
_, err = set.Dial(t.Context(), "first")
|
|
require.Error(t, err)
|
|
|
|
connection, err = set.Dial(t.Context(), "replacement")
|
|
require.NoError(t, err)
|
|
require.NoError(t, connection.Close())
|
|
|
|
// Stop all host processes
|
|
set.Stop()
|
|
require.False(t, set.Ready())
|
|
|
|
// Ensure that the stopped host process is no longer reachable
|
|
_, err = set.Dial(t.Context(), "replacement")
|
|
require.Error(t, err)
|
|
|
|
// Ensure that an explicitly started empty set is ready
|
|
require.NoError(t, set.Start(t.Context(), nil))
|
|
require.True(t, set.Ready())
|
|
}
|
|
|
|
func TestSetStartReplacesExistingProcesses(t *testing.T) {
|
|
// Use this test binary as a host process
|
|
executable, err := os.Executable()
|
|
require.NoError(t, err)
|
|
|
|
// Create a host process set and start a new host process
|
|
set := NewSet("", "", ondiskname.OnDiskName{})
|
|
defer set.Stop()
|
|
|
|
hostProcesses := []v1.HostProcess{{
|
|
Name: "process",
|
|
Program: executable,
|
|
Args: []string{testHelperArg},
|
|
Env: map[string]string{
|
|
testHelperEnv: "set",
|
|
},
|
|
}}
|
|
|
|
require.NoError(t, set.Start(t.Context(), hostProcesses))
|
|
|
|
// Keep track of the original process to verify it is stopped
|
|
original := set.Lookup("process")
|
|
require.NotNil(t, original)
|
|
defer original.Close()
|
|
|
|
// Start a new host process
|
|
require.NoError(t, set.Start(t.Context(), hostProcesses))
|
|
|
|
// Ensure that the original process was stopped
|
|
select {
|
|
case <-original.done:
|
|
// It was stopped, nice
|
|
default:
|
|
require.FailNow(t, "the original process is still running")
|
|
}
|
|
|
|
// Ensure that a new ready process replaced the original
|
|
replacement := set.Lookup("process")
|
|
require.NotNil(t, replacement)
|
|
require.NotSame(t, original, replacement)
|
|
require.True(t, set.Ready())
|
|
}
|
|
|
|
func runTestHelper() int {
|
|
if os.Getenv(testHelperEnv) != "set" {
|
|
return 3
|
|
}
|
|
if os.Getenv(testHelperInheritedEnv) != "" {
|
|
return 4
|
|
}
|
|
if os.Getenv("PATH") == "must-not-win" {
|
|
return 5
|
|
}
|
|
|
|
listener, err := net.Listen("unix", os.Getenv("ORCHARD_PROCESS_SOCKET"))
|
|
if err != nil {
|
|
return 2
|
|
}
|
|
defer listener.Close()
|
|
|
|
for {
|
|
connection, err := listener.Accept()
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
_ = connection.Close()
|
|
}
|
|
}
|