Generalize create network code in network package integration tests
This commit is contained in:
parent
010c53e5c7
commit
f146b77187
@ -113,16 +113,22 @@ func nebulaConfig(
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
_, port, err := net.SplitHostPort(publicAddr)
|
host, port, err := net.SplitHostPort(publicAddr)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
"parsing public address %q: %w", publicAddr, err,
|
"parsing public address %q: %w", publicAddr, err,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This helps with integration testing, so we can set a test to listen
|
||||||
|
// on some local IP without conflicting with something else running on
|
||||||
|
// the host.
|
||||||
|
if hostIP := net.ParseIP(host); hostIP == nil || !hostIP.IsLoopback() {
|
||||||
|
host = "0.0.0.0"
|
||||||
|
}
|
||||||
|
|
||||||
config["listen"] = map[string]string{
|
config["listen"] = map[string]string{
|
||||||
"host": "0.0.0.0",
|
"host": host,
|
||||||
"port": port,
|
"port": port,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,152 +1,29 @@
|
|||||||
package network
|
package network
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"sync"
|
|
||||||
"sync/atomic"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"isle/bootstrap"
|
|
||||||
"isle/daemon/daecommon"
|
|
||||||
"isle/nebula"
|
|
||||||
"isle/toolkit"
|
"isle/toolkit"
|
||||||
|
|
||||||
"dev.mediocregopher.com/mediocre-go-lib.git/mlog"
|
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// TODO seeing more of these logs than I'd expect:
|
||||||
getEnvBinDirPath = sync.OnceValue(func() string {
|
// INFO [network/children] Creating UDP socket from nebula addr "lUDPAddr"="172.16.1.1:0" "rUDPAddr"="172.16.1.1:45535"
|
||||||
appDirPath := os.Getenv("APPDIR")
|
|
||||||
if appDirPath == "" {
|
|
||||||
panic("APPDIR not set")
|
|
||||||
}
|
|
||||||
return filepath.Join(appDirPath, "bin")
|
|
||||||
})
|
|
||||||
|
|
||||||
ipNetCounter uint64
|
|
||||||
)
|
|
||||||
|
|
||||||
func newIPNet(t *testing.T) nebula.IPNet {
|
|
||||||
var (
|
|
||||||
ipNet nebula.IPNet
|
|
||||||
ipNetStr = fmt.Sprintf(
|
|
||||||
"172.16.%d.0/24", atomic.AddUint64(&ipNetCounter, 1),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if err := ipNet.UnmarshalText([]byte(ipNetStr)); err != nil {
|
|
||||||
t.Fatalf("parsing IPNet from %q: %v", ipNetStr, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ipNet
|
|
||||||
}
|
|
||||||
|
|
||||||
func mustParseNetworkConfigf(str string, args ...any) daecommon.NetworkConfig {
|
|
||||||
str = fmt.Sprintf(str, args...)
|
|
||||||
|
|
||||||
var networkConfig daecommon.NetworkConfig
|
|
||||||
if err := yaml.Unmarshal([]byte(str), &networkConfig); err != nil {
|
|
||||||
panic(fmt.Sprintf("parsing network config: %v", err))
|
|
||||||
}
|
|
||||||
return networkConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
type harness struct {
|
|
||||||
ctx context.Context
|
|
||||||
logger *mlog.Logger
|
|
||||||
rootDir toolkit.Dir
|
|
||||||
dirCounter uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
func newHarness(t *testing.T) *harness {
|
|
||||||
return &harness{
|
|
||||||
ctx: context.Background(),
|
|
||||||
logger: mlog.NewLogger(nil),
|
|
||||||
rootDir: toolkit.Dir{Path: t.TempDir()},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *harness) mkDir(t *testing.T, name string) toolkit.Dir {
|
|
||||||
fullName := fmt.Sprintf("%s-%d", name, atomic.AddUint64(&h.dirCounter, 1))
|
|
||||||
|
|
||||||
t.Logf("Creating directory %q", fullName)
|
|
||||||
d, err := h.rootDir.MkChildDir(fullName, false)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("creating %q: %v", fullName, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreate(t *testing.T) {
|
func TestCreate(t *testing.T) {
|
||||||
toolkit.MarkIntegrationTest(t)
|
toolkit.MarkIntegrationTest(t)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
h = newHarness(t)
|
h = newIntegrationHarness(t)
|
||||||
creationParams = bootstrap.NewCreationParams("test", "test.localnet")
|
network = h.createNetwork(t, "primus", nil)
|
||||||
networkConfig = mustParseNetworkConfigf(`
|
|
||||||
vpn:
|
|
||||||
public_addr: "127.0.0.1:10000"
|
|
||||||
tun:
|
|
||||||
device: isle-test
|
|
||||||
storage:
|
|
||||||
allocations:
|
|
||||||
- data_path: %s
|
|
||||||
meta_path: %s
|
|
||||||
capacity: 1
|
|
||||||
- data_path: %s
|
|
||||||
meta_path: %s
|
|
||||||
capacity: 1
|
|
||||||
- data_path: %s
|
|
||||||
meta_path: %s
|
|
||||||
capacity: 1
|
|
||||||
`,
|
|
||||||
h.mkDir(t, "data").Path,
|
|
||||||
h.mkDir(t, "meta").Path,
|
|
||||||
h.mkDir(t, "data").Path,
|
|
||||||
h.mkDir(t, "meta").Path,
|
|
||||||
h.mkDir(t, "data").Path,
|
|
||||||
h.mkDir(t, "meta").Path,
|
|
||||||
)
|
)
|
||||||
stateDir = h.mkDir(t, "state")
|
|
||||||
runtimeDir = h.mkDir(t, "runtime")
|
|
||||||
ipNet = newIPNet(t)
|
|
||||||
hostName = nebula.HostName("primus")
|
|
||||||
)
|
|
||||||
|
|
||||||
network, err := Create(
|
|
||||||
h.ctx,
|
|
||||||
h.logger.WithNamespace("network"),
|
|
||||||
networkConfig,
|
|
||||||
getEnvBinDirPath(),
|
|
||||||
stateDir,
|
|
||||||
runtimeDir,
|
|
||||||
creationParams,
|
|
||||||
ipNet,
|
|
||||||
hostName,
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("creating Network: %v", err)
|
|
||||||
}
|
|
||||||
t.Cleanup(func() {
|
|
||||||
t.Log("Shutting down Network")
|
|
||||||
if err := network.Shutdown(); err != nil {
|
|
||||||
t.Logf("Shutting down Network failed: %v", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
gotCreationParams, err := network.GetNetworkCreationParams(h.ctx)
|
gotCreationParams, err := network.GetNetworkCreationParams(h.ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("calling GetNetworkCreationParams: %v", err)
|
t.Fatalf("calling GetNetworkCreationParams: %v", err)
|
||||||
} else if creationParams != gotCreationParams {
|
} else if network.creationParams != gotCreationParams {
|
||||||
t.Fatalf(
|
t.Fatalf(
|
||||||
"expected CreationParams %+v, got %+v",
|
"expected CreationParams %+v, got %+v",
|
||||||
creationParams,
|
network.creationParams,
|
||||||
gotCreationParams,
|
gotCreationParams,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
227
go/daemon/network/network_it_util_test.go
Normal file
227
go/daemon/network/network_it_util_test.go
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
package network
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"isle/bootstrap"
|
||||||
|
"isle/daemon/children"
|
||||||
|
"isle/daemon/daecommon"
|
||||||
|
"isle/nebula"
|
||||||
|
"isle/toolkit"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"dev.mediocregopher.com/mediocre-go-lib.git/mlog"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Utilities related to running network integration tests
|
||||||
|
|
||||||
|
var (
|
||||||
|
getEnvBinDirPath = sync.OnceValue(func() string {
|
||||||
|
appDirPath := os.Getenv("APPDIR")
|
||||||
|
if appDirPath == "" {
|
||||||
|
panic("APPDIR not set")
|
||||||
|
}
|
||||||
|
return filepath.Join(appDirPath, "bin")
|
||||||
|
})
|
||||||
|
|
||||||
|
ipNetCounter uint64 = 0
|
||||||
|
publicAddrPortCounter uint64 = 1024
|
||||||
|
tunDeviceCounter uint64 = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
func newIPNet() nebula.IPNet {
|
||||||
|
var (
|
||||||
|
ipNet nebula.IPNet
|
||||||
|
ipNetStr = fmt.Sprintf(
|
||||||
|
"172.16.%d.0/24", atomic.AddUint64(&ipNetCounter, 1),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := ipNet.UnmarshalText([]byte(ipNetStr)); err != nil {
|
||||||
|
panic(fmt.Sprintf("parsing IPNet from %q: %v", ipNetStr, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return ipNet
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPublicAddr() string {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"127.0.0.200:%d", atomic.AddUint64(&publicAddrPortCounter, 1),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTunDevice() string {
|
||||||
|
return fmt.Sprintf("isle-test-%d", atomic.AddUint64(&tunDeviceCounter, 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustParseNetworkConfigf(str string, args ...any) daecommon.NetworkConfig {
|
||||||
|
str = fmt.Sprintf(str, args...)
|
||||||
|
|
||||||
|
var networkConfig daecommon.NetworkConfig
|
||||||
|
if err := yaml.Unmarshal([]byte(str), &networkConfig); err != nil {
|
||||||
|
panic(fmt.Sprintf("parsing network config: %v", err))
|
||||||
|
}
|
||||||
|
return networkConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
type integrationHarness struct {
|
||||||
|
ctx context.Context
|
||||||
|
logger *mlog.Logger
|
||||||
|
rootDir toolkit.Dir
|
||||||
|
dirCounter uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func newIntegrationHarness(t *testing.T) *integrationHarness {
|
||||||
|
toolkit.MarkIntegrationTest(t)
|
||||||
|
|
||||||
|
rootDir, err := os.MkdirTemp("", "isle-network-it-test.*")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("creating root temp dir: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Cleanup(func() {
|
||||||
|
if t.Failed() {
|
||||||
|
t.Logf("Temp directory for failed test not deleted: %q", rootDir)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("Deleting temp directory %q", rootDir)
|
||||||
|
if err := os.RemoveAll(rootDir); err != nil {
|
||||||
|
t.Errorf("failed to remove %q: %v", rootDir, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return &integrationHarness{
|
||||||
|
ctx: context.Background(),
|
||||||
|
logger: mlog.NewLogger(nil),
|
||||||
|
rootDir: toolkit.Dir{Path: rootDir},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *integrationHarness) mkDir(t *testing.T, name string) toolkit.Dir {
|
||||||
|
fullName := fmt.Sprintf("%s-%d", name, atomic.AddUint64(&h.dirCounter, 1))
|
||||||
|
|
||||||
|
t.Logf("Creating directory %q", fullName)
|
||||||
|
d, err := h.rootDir.MkChildDir(fullName, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("creating %q: %v", fullName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
type createNetworkOpts struct {
|
||||||
|
creationParams bootstrap.CreationParams
|
||||||
|
noCleanup bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *createNetworkOpts) withDefaults() *createNetworkOpts {
|
||||||
|
if o == nil {
|
||||||
|
o = new(createNetworkOpts)
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.creationParams == (bootstrap.CreationParams{}) {
|
||||||
|
o.creationParams = bootstrap.NewCreationParams("test", "test.localnet")
|
||||||
|
}
|
||||||
|
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
type integrationHarnessNetwork struct {
|
||||||
|
Network
|
||||||
|
creationParams bootstrap.CreationParams
|
||||||
|
stateDir, runtimeDir toolkit.Dir
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *integrationHarness) createNetwork(
|
||||||
|
t *testing.T,
|
||||||
|
hostNameStr string,
|
||||||
|
opts *createNetworkOpts,
|
||||||
|
) integrationHarnessNetwork {
|
||||||
|
opts = opts.withDefaults()
|
||||||
|
|
||||||
|
var (
|
||||||
|
networkConfig = mustParseNetworkConfigf(`
|
||||||
|
vpn:
|
||||||
|
public_addr: %q
|
||||||
|
tun:
|
||||||
|
device: %q
|
||||||
|
storage:
|
||||||
|
allocations:
|
||||||
|
- data_path: %s
|
||||||
|
meta_path: %s
|
||||||
|
capacity: 1
|
||||||
|
- data_path: %s
|
||||||
|
meta_path: %s
|
||||||
|
capacity: 1
|
||||||
|
- data_path: %s
|
||||||
|
meta_path: %s
|
||||||
|
capacity: 1
|
||||||
|
`,
|
||||||
|
newPublicAddr(),
|
||||||
|
newTunDevice(),
|
||||||
|
h.mkDir(t, "data").Path,
|
||||||
|
h.mkDir(t, "meta").Path,
|
||||||
|
h.mkDir(t, "data").Path,
|
||||||
|
h.mkDir(t, "meta").Path,
|
||||||
|
h.mkDir(t, "data").Path,
|
||||||
|
h.mkDir(t, "meta").Path,
|
||||||
|
)
|
||||||
|
|
||||||
|
stateDir = h.mkDir(t, "state")
|
||||||
|
runtimeDir = h.mkDir(t, "runtime")
|
||||||
|
childrenLogFilePath = filepath.Join(runtimeDir.Path, "children.log")
|
||||||
|
|
||||||
|
ipNet = newIPNet()
|
||||||
|
hostName = nebula.HostName(hostNameStr)
|
||||||
|
)
|
||||||
|
|
||||||
|
childrenLogFile, err := os.Create(childrenLogFilePath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("creating %q: %v", childrenLogFilePath, err)
|
||||||
|
}
|
||||||
|
t.Cleanup(func() {
|
||||||
|
if err := childrenLogFile.Close(); err != nil {
|
||||||
|
t.Errorf("closing %q: %v", childrenLogFilePath, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
network, err := Create(
|
||||||
|
h.ctx,
|
||||||
|
h.logger.WithNamespace("network"),
|
||||||
|
networkConfig,
|
||||||
|
getEnvBinDirPath(),
|
||||||
|
stateDir,
|
||||||
|
runtimeDir,
|
||||||
|
opts.creationParams,
|
||||||
|
ipNet,
|
||||||
|
hostName,
|
||||||
|
&Opts{
|
||||||
|
ChildrenOpts: &children.Opts{
|
||||||
|
Stdout: childrenLogFile,
|
||||||
|
Stderr: childrenLogFile,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("creating Network: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !opts.noCleanup {
|
||||||
|
t.Cleanup(func() {
|
||||||
|
t.Log("Shutting down Network")
|
||||||
|
if err := network.Shutdown(); err != nil {
|
||||||
|
t.Logf("Shutting down Network failed: %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return integrationHarnessNetwork{
|
||||||
|
network, opts.creationParams, stateDir, runtimeDir,
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user