Add tests for network.Loader
This commit is contained in:
parent
ab8dac0789
commit
53a1dc0cc2
63
go/daemon/network/constructors.go
Normal file
63
go/daemon/network/constructors.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
//go:generate mockery --name constructors --inpackage --filename constructors_mock.go
|
||||||
|
|
||||||
|
package network
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"isle/bootstrap"
|
||||||
|
"isle/daemon/children"
|
||||||
|
"isle/nebula"
|
||||||
|
"isle/toolkit"
|
||||||
|
|
||||||
|
"dev.mediocregopher.com/mediocre-go-lib.git/mlog"
|
||||||
|
)
|
||||||
|
|
||||||
|
// constructors wraps the various Network constructor functions in an interface,
|
||||||
|
// so that they can be mocked.
|
||||||
|
//
|
||||||
|
// This is needed primarily for testing the Loader. We can't test the Loader
|
||||||
|
// during Network integration tests because the Loader doesn't allow multiple
|
||||||
|
// Networks with the same ID to be loaded, but we need to do so in integration
|
||||||
|
// tests. Working around that requirement in the integration tests would add
|
||||||
|
// extra complexity there, and it's better to do unit testing anyway.
|
||||||
|
type constructors interface {
|
||||||
|
load(
|
||||||
|
ctx context.Context,
|
||||||
|
logger *mlog.Logger,
|
||||||
|
envBinDirPath string,
|
||||||
|
nebulaDeviceNamer *children.NebulaDeviceNamer,
|
||||||
|
stateDir toolkit.Dir,
|
||||||
|
runtimeDir toolkit.Dir,
|
||||||
|
opts *Opts,
|
||||||
|
) (
|
||||||
|
Network, error,
|
||||||
|
)
|
||||||
|
|
||||||
|
join(
|
||||||
|
ctx context.Context,
|
||||||
|
logger *mlog.Logger,
|
||||||
|
envBinDirPath string,
|
||||||
|
nebulaDeviceNamer *children.NebulaDeviceNamer,
|
||||||
|
joiningBootstrap JoiningBootstrap,
|
||||||
|
stateDir toolkit.Dir,
|
||||||
|
runtimeDir toolkit.Dir,
|
||||||
|
opts *Opts,
|
||||||
|
) (
|
||||||
|
Network, error,
|
||||||
|
)
|
||||||
|
|
||||||
|
create(
|
||||||
|
ctx context.Context,
|
||||||
|
logger *mlog.Logger,
|
||||||
|
envBinDirPath string,
|
||||||
|
nebulaDeviceNamer *children.NebulaDeviceNamer,
|
||||||
|
stateDir toolkit.Dir,
|
||||||
|
runtimeDir toolkit.Dir,
|
||||||
|
creationParams bootstrap.CreationParams,
|
||||||
|
ipNet nebula.IPNet,
|
||||||
|
hostName nebula.HostName,
|
||||||
|
opts *Opts,
|
||||||
|
) (
|
||||||
|
Network, error,
|
||||||
|
)
|
||||||
|
}
|
127
go/daemon/network/constructors_mock.go
Normal file
127
go/daemon/network/constructors_mock.go
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
// Code generated by mockery v2.43.1. DO NOT EDIT.
|
||||||
|
|
||||||
|
package network
|
||||||
|
|
||||||
|
import (
|
||||||
|
bootstrap "isle/bootstrap"
|
||||||
|
children "isle/daemon/children"
|
||||||
|
|
||||||
|
context "context"
|
||||||
|
|
||||||
|
mlog "dev.mediocregopher.com/mediocre-go-lib.git/mlog"
|
||||||
|
|
||||||
|
mock "github.com/stretchr/testify/mock"
|
||||||
|
|
||||||
|
nebula "isle/nebula"
|
||||||
|
|
||||||
|
toolkit "isle/toolkit"
|
||||||
|
)
|
||||||
|
|
||||||
|
// mockConstructors is an autogenerated mock type for the constructors type
|
||||||
|
type mockConstructors struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// create provides a mock function with given fields: ctx, logger, envBinDirPath, nebulaDeviceNamer, stateDir, runtimeDir, creationParams, ipNet, hostName, opts
|
||||||
|
func (_m *mockConstructors) create(ctx context.Context, logger *mlog.Logger, envBinDirPath string, nebulaDeviceNamer *children.NebulaDeviceNamer, stateDir toolkit.Dir, runtimeDir toolkit.Dir, creationParams bootstrap.CreationParams, ipNet nebula.IPNet, hostName nebula.HostName, opts *Opts) (Network, error) {
|
||||||
|
ret := _m.Called(ctx, logger, envBinDirPath, nebulaDeviceNamer, stateDir, runtimeDir, creationParams, ipNet, hostName, opts)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for create")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 Network
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func(context.Context, *mlog.Logger, string, *children.NebulaDeviceNamer, toolkit.Dir, toolkit.Dir, bootstrap.CreationParams, nebula.IPNet, nebula.HostName, *Opts) (Network, error)); ok {
|
||||||
|
return rf(ctx, logger, envBinDirPath, nebulaDeviceNamer, stateDir, runtimeDir, creationParams, ipNet, hostName, opts)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(context.Context, *mlog.Logger, string, *children.NebulaDeviceNamer, toolkit.Dir, toolkit.Dir, bootstrap.CreationParams, nebula.IPNet, nebula.HostName, *Opts) Network); ok {
|
||||||
|
r0 = rf(ctx, logger, envBinDirPath, nebulaDeviceNamer, stateDir, runtimeDir, creationParams, ipNet, hostName, opts)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(Network)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(context.Context, *mlog.Logger, string, *children.NebulaDeviceNamer, toolkit.Dir, toolkit.Dir, bootstrap.CreationParams, nebula.IPNet, nebula.HostName, *Opts) error); ok {
|
||||||
|
r1 = rf(ctx, logger, envBinDirPath, nebulaDeviceNamer, stateDir, runtimeDir, creationParams, ipNet, hostName, opts)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// join provides a mock function with given fields: ctx, logger, envBinDirPath, nebulaDeviceNamer, joiningBootstrap, stateDir, runtimeDir, opts
|
||||||
|
func (_m *mockConstructors) join(ctx context.Context, logger *mlog.Logger, envBinDirPath string, nebulaDeviceNamer *children.NebulaDeviceNamer, joiningBootstrap JoiningBootstrap, stateDir toolkit.Dir, runtimeDir toolkit.Dir, opts *Opts) (Network, error) {
|
||||||
|
ret := _m.Called(ctx, logger, envBinDirPath, nebulaDeviceNamer, joiningBootstrap, stateDir, runtimeDir, opts)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for join")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 Network
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func(context.Context, *mlog.Logger, string, *children.NebulaDeviceNamer, JoiningBootstrap, toolkit.Dir, toolkit.Dir, *Opts) (Network, error)); ok {
|
||||||
|
return rf(ctx, logger, envBinDirPath, nebulaDeviceNamer, joiningBootstrap, stateDir, runtimeDir, opts)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(context.Context, *mlog.Logger, string, *children.NebulaDeviceNamer, JoiningBootstrap, toolkit.Dir, toolkit.Dir, *Opts) Network); ok {
|
||||||
|
r0 = rf(ctx, logger, envBinDirPath, nebulaDeviceNamer, joiningBootstrap, stateDir, runtimeDir, opts)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(Network)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(context.Context, *mlog.Logger, string, *children.NebulaDeviceNamer, JoiningBootstrap, toolkit.Dir, toolkit.Dir, *Opts) error); ok {
|
||||||
|
r1 = rf(ctx, logger, envBinDirPath, nebulaDeviceNamer, joiningBootstrap, stateDir, runtimeDir, opts)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// load provides a mock function with given fields: ctx, logger, envBinDirPath, nebulaDeviceNamer, stateDir, runtimeDir, opts
|
||||||
|
func (_m *mockConstructors) load(ctx context.Context, logger *mlog.Logger, envBinDirPath string, nebulaDeviceNamer *children.NebulaDeviceNamer, stateDir toolkit.Dir, runtimeDir toolkit.Dir, opts *Opts) (Network, error) {
|
||||||
|
ret := _m.Called(ctx, logger, envBinDirPath, nebulaDeviceNamer, stateDir, runtimeDir, opts)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for load")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 Network
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func(context.Context, *mlog.Logger, string, *children.NebulaDeviceNamer, toolkit.Dir, toolkit.Dir, *Opts) (Network, error)); ok {
|
||||||
|
return rf(ctx, logger, envBinDirPath, nebulaDeviceNamer, stateDir, runtimeDir, opts)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(context.Context, *mlog.Logger, string, *children.NebulaDeviceNamer, toolkit.Dir, toolkit.Dir, *Opts) Network); ok {
|
||||||
|
r0 = rf(ctx, logger, envBinDirPath, nebulaDeviceNamer, stateDir, runtimeDir, opts)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(Network)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(context.Context, *mlog.Logger, string, *children.NebulaDeviceNamer, toolkit.Dir, toolkit.Dir, *Opts) error); ok {
|
||||||
|
r1 = rf(ctx, logger, envBinDirPath, nebulaDeviceNamer, stateDir, runtimeDir, opts)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// newMockConstructors creates a new instance of mockConstructors. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||||
|
// The first argument is typically a *testing.T value.
|
||||||
|
func newMockConstructors(t interface {
|
||||||
|
mock.TestingT
|
||||||
|
Cleanup(func())
|
||||||
|
}) *mockConstructors {
|
||||||
|
mock := &mockConstructors{}
|
||||||
|
mock.Mock.Test(t)
|
||||||
|
|
||||||
|
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||||
|
|
||||||
|
return mock
|
||||||
|
}
|
@ -139,6 +139,8 @@ type Loader interface {
|
|||||||
type LoaderOpts struct {
|
type LoaderOpts struct {
|
||||||
// Defaults to that returned by daecommon.GetEnvVars.
|
// Defaults to that returned by daecommon.GetEnvVars.
|
||||||
EnvVars daecommon.EnvVars
|
EnvVars daecommon.EnvVars
|
||||||
|
|
||||||
|
constructors constructors // defaults to newConstructors()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *LoaderOpts) withDefaults() *LoaderOpts {
|
func (o *LoaderOpts) withDefaults() *LoaderOpts {
|
||||||
@ -150,10 +152,15 @@ func (o *LoaderOpts) withDefaults() *LoaderOpts {
|
|||||||
o.EnvVars = daecommon.GetEnvVars()
|
o.EnvVars = daecommon.GetEnvVars()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if o.constructors == nil {
|
||||||
|
o.constructors = newConstructors()
|
||||||
|
}
|
||||||
|
|
||||||
return o
|
return o
|
||||||
}
|
}
|
||||||
|
|
||||||
type loader struct {
|
type loader struct {
|
||||||
|
opts *LoaderOpts
|
||||||
envBinDirPath string
|
envBinDirPath string
|
||||||
networksStateDir toolkit.Dir
|
networksStateDir toolkit.Dir
|
||||||
networksRuntimeDir toolkit.Dir
|
networksRuntimeDir toolkit.Dir
|
||||||
@ -196,6 +203,7 @@ func NewLoader(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &loader{
|
return &loader{
|
||||||
|
opts,
|
||||||
envBinDirPath,
|
envBinDirPath,
|
||||||
networksStateDir,
|
networksStateDir,
|
||||||
networksRuntimeDir,
|
networksRuntimeDir,
|
||||||
@ -247,6 +255,21 @@ func (l *loader) StoredConfig(
|
|||||||
return loadConfig(networkStateDir)
|
return loadConfig(networkStateDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *loader) isJoined(ctx context.Context, networkID string) (bool, error) {
|
||||||
|
allJoinedCreationParams, err := l.Loadable(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("getting already joined networks: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, joinedCreationParams := range allJoinedCreationParams {
|
||||||
|
if joinedCreationParams.ID == networkID {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (l *loader) Load(
|
func (l *loader) Load(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
logger *mlog.Logger,
|
logger *mlog.Logger,
|
||||||
@ -257,6 +280,12 @@ func (l *loader) Load(
|
|||||||
) {
|
) {
|
||||||
networkID := creationParams.ID
|
networkID := creationParams.ID
|
||||||
|
|
||||||
|
if isJoined, err := l.isJoined(ctx, networkID); err != nil {
|
||||||
|
return nil, fmt.Errorf("checking if network is already joined: %w", err)
|
||||||
|
} else if !isJoined {
|
||||||
|
return nil, errors.New("network is not yet joined")
|
||||||
|
}
|
||||||
|
|
||||||
networkStateDir, networkRuntimeDir, err := networkDirs(
|
networkStateDir, networkRuntimeDir, err := networkDirs(
|
||||||
l.networksStateDir, l.networksRuntimeDir, networkID, true,
|
l.networksStateDir, l.networksRuntimeDir, networkID, true,
|
||||||
)
|
)
|
||||||
@ -266,7 +295,7 @@ func (l *loader) Load(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return load(
|
return l.opts.constructors.load(
|
||||||
ctx,
|
ctx,
|
||||||
logger,
|
logger,
|
||||||
l.envBinDirPath,
|
l.envBinDirPath,
|
||||||
@ -290,22 +319,6 @@ func (l *loader) Join(
|
|||||||
networkID = creationParams.ID
|
networkID = creationParams.ID
|
||||||
)
|
)
|
||||||
|
|
||||||
// Start by checking that the new network isn't already joined. This
|
|
||||||
// shouldn't _technically_ be necessary, as the caller of Join should
|
|
||||||
// already be handling this, but it's worth doing to make sure we don't
|
|
||||||
// accidentally delete the state directory of an already joined network.
|
|
||||||
|
|
||||||
allJoinedCreationParams, err := l.Loadable(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("getting already joined networks: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, joinedCreationParams := range allJoinedCreationParams {
|
|
||||||
if joinedCreationParams.ID == networkID {
|
|
||||||
return nil, fmt.Errorf("network %q already joined", networkID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
networkStateDir, networkRuntimeDir, err := networkDirs(
|
networkStateDir, networkRuntimeDir, err := networkDirs(
|
||||||
l.networksStateDir, l.networksRuntimeDir, networkID, false,
|
l.networksStateDir, l.networksRuntimeDir, networkID, false,
|
||||||
)
|
)
|
||||||
@ -315,7 +328,7 @@ func (l *loader) Join(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
n, err := join(
|
n, err := l.opts.constructors.join(
|
||||||
ctx,
|
ctx,
|
||||||
logger,
|
logger,
|
||||||
l.envBinDirPath,
|
l.envBinDirPath,
|
||||||
@ -356,7 +369,7 @@ func (l *loader) Create(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
n, err := create(
|
n, err := l.opts.constructors.create(
|
||||||
ctx,
|
ctx,
|
||||||
logger,
|
logger,
|
||||||
l.envBinDirPath,
|
l.envBinDirPath,
|
||||||
|
389
go/daemon/network/loader_test.go
Normal file
389
go/daemon/network/loader_test.go
Normal file
@ -0,0 +1,389 @@
|
|||||||
|
package network
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"io/fs"
|
||||||
|
"isle/bootstrap"
|
||||||
|
"isle/daemon/children"
|
||||||
|
"isle/daemon/daecommon"
|
||||||
|
"isle/nebula"
|
||||||
|
"isle/toolkit"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"dev.mediocregopher.com/mediocre-go-lib.git/mlog"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
type loaderHarness struct {
|
||||||
|
ctx context.Context
|
||||||
|
logger *mlog.Logger
|
||||||
|
envBinDirPath string
|
||||||
|
stateDirPath string
|
||||||
|
runtimeDirPath string
|
||||||
|
constructors *mockConstructors
|
||||||
|
|
||||||
|
loader Loader
|
||||||
|
}
|
||||||
|
|
||||||
|
func newLoaderHarness(t *testing.T) *loaderHarness {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
var (
|
||||||
|
ctx = context.Background()
|
||||||
|
logger = toolkit.NewTestLogger(t)
|
||||||
|
rootDir = toolkit.TempDir(t)
|
||||||
|
envBinDir, _ = rootDir.MkChildDir("bin", false)
|
||||||
|
stateDir, _ = rootDir.MkChildDir("state", false)
|
||||||
|
runtimeDir, _ = rootDir.MkChildDir("runtime", false)
|
||||||
|
constructors = newMockConstructors(t)
|
||||||
|
)
|
||||||
|
|
||||||
|
loader, err := NewLoader(
|
||||||
|
ctx, logger, envBinDir.Path, &LoaderOpts{
|
||||||
|
EnvVars: daecommon.EnvVars{
|
||||||
|
StateDir: stateDir,
|
||||||
|
RuntimeDir: runtimeDir,
|
||||||
|
},
|
||||||
|
constructors: constructors,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
return &loaderHarness{
|
||||||
|
ctx,
|
||||||
|
logger,
|
||||||
|
envBinDir.Path,
|
||||||
|
stateDir.Path,
|
||||||
|
runtimeDir.Path,
|
||||||
|
constructors,
|
||||||
|
loader,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *loaderHarness) networkStateDirPath(networkID string) string {
|
||||||
|
return filepath.Join(h.stateDirPath, "networks", networkID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *loaderHarness) networkRuntimeDirPath(networkID string) string {
|
||||||
|
return filepath.Join(h.runtimeDirPath, "networks", networkID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *loaderHarness) join(
|
||||||
|
t *testing.T, creationParams bootstrap.CreationParams,
|
||||||
|
) *MockNetwork {
|
||||||
|
var (
|
||||||
|
joiningBootstrap = JoiningBootstrap{
|
||||||
|
Bootstrap: bootstrap.Bootstrap{
|
||||||
|
NetworkCreationParams: creationParams,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
networkStateDirPath = h.networkStateDirPath(creationParams.ID)
|
||||||
|
networkRuntimeDirPath = h.networkRuntimeDirPath(creationParams.ID)
|
||||||
|
network = NewMockNetwork(t)
|
||||||
|
)
|
||||||
|
|
||||||
|
h.constructors.
|
||||||
|
On(
|
||||||
|
"join",
|
||||||
|
toolkit.MockArg[context.Context](),
|
||||||
|
toolkit.MockArg[*mlog.Logger](),
|
||||||
|
h.envBinDirPath,
|
||||||
|
toolkit.MockArg[*children.NebulaDeviceNamer](),
|
||||||
|
joiningBootstrap,
|
||||||
|
toolkit.Dir{Path: networkStateDirPath},
|
||||||
|
toolkit.Dir{Path: networkRuntimeDirPath},
|
||||||
|
(*Opts)(nil),
|
||||||
|
).
|
||||||
|
Return(network, nil).
|
||||||
|
Once()
|
||||||
|
|
||||||
|
got, err := h.loader.Join(
|
||||||
|
h.ctx,
|
||||||
|
h.logger,
|
||||||
|
joiningBootstrap,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, got, network)
|
||||||
|
|
||||||
|
require.NoError(t, writeBootstrapToStateDir(
|
||||||
|
networkStateDirPath, joiningBootstrap.Bootstrap,
|
||||||
|
))
|
||||||
|
|
||||||
|
return network
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *loaderHarness) assertDirExists(
|
||||||
|
t *testing.T, exists bool, path string,
|
||||||
|
) {
|
||||||
|
stat, err := os.Stat(path)
|
||||||
|
if exists {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, os.ModeDir, stat.Mode().Type())
|
||||||
|
} else {
|
||||||
|
assert.ErrorIs(t, err, fs.ErrNotExist)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoader_Loadable(t *testing.T) {
|
||||||
|
allCreationParams := []bootstrap.CreationParams{
|
||||||
|
bootstrap.NewCreationParams("AAA", "a.com"),
|
||||||
|
bootstrap.NewCreationParams("BBB", "b.com"),
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("empty", func(t *testing.T) {
|
||||||
|
h := newLoaderHarness(t)
|
||||||
|
got, err := h.loader.Loadable(h.ctx)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Empty(t, got)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("single", func(t *testing.T) {
|
||||||
|
h := newLoaderHarness(t)
|
||||||
|
h.join(t, allCreationParams[0])
|
||||||
|
got, err := h.loader.Loadable(h.ctx)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, allCreationParams[:1], got)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("multiple", func(t *testing.T) {
|
||||||
|
h := newLoaderHarness(t)
|
||||||
|
h.join(t, allCreationParams[0])
|
||||||
|
h.join(t, allCreationParams[1])
|
||||||
|
got, err := h.loader.Loadable(h.ctx)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.ElementsMatch(t, allCreationParams, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoader_Load(t *testing.T) {
|
||||||
|
var (
|
||||||
|
creationParams = bootstrap.NewCreationParams("AAA", "a.com")
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Run("success", func(t *testing.T) {
|
||||||
|
var (
|
||||||
|
h = newLoaderHarness(t)
|
||||||
|
networkStateDirPath = h.networkStateDirPath(creationParams.ID)
|
||||||
|
networkRuntimeDirPath = h.networkRuntimeDirPath(creationParams.ID)
|
||||||
|
network = h.join(t, creationParams)
|
||||||
|
)
|
||||||
|
|
||||||
|
h.constructors.
|
||||||
|
On(
|
||||||
|
"load",
|
||||||
|
toolkit.MockArg[context.Context](),
|
||||||
|
toolkit.MockArg[*mlog.Logger](),
|
||||||
|
h.envBinDirPath,
|
||||||
|
toolkit.MockArg[*children.NebulaDeviceNamer](),
|
||||||
|
toolkit.Dir{Path: networkStateDirPath},
|
||||||
|
toolkit.Dir{Path: networkRuntimeDirPath},
|
||||||
|
(*Opts)(nil),
|
||||||
|
).
|
||||||
|
Return(network, nil).
|
||||||
|
Once()
|
||||||
|
|
||||||
|
got, err := h.loader.Load(
|
||||||
|
h.ctx,
|
||||||
|
h.logger,
|
||||||
|
creationParams,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, network, got)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("error/not yet joined", func(t *testing.T) {
|
||||||
|
var (
|
||||||
|
h = newLoaderHarness(t)
|
||||||
|
networkStateDirPath = h.networkStateDirPath(creationParams.ID)
|
||||||
|
networkRuntimeDirPath = h.networkRuntimeDirPath(creationParams.ID)
|
||||||
|
)
|
||||||
|
|
||||||
|
_, err := h.loader.Load(
|
||||||
|
h.ctx,
|
||||||
|
h.logger,
|
||||||
|
creationParams,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.ErrorContains(t, err, "not yet joined")
|
||||||
|
h.assertDirExists(t, false, networkStateDirPath)
|
||||||
|
h.assertDirExists(t, false, networkRuntimeDirPath)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoader_Join(t *testing.T) {
|
||||||
|
var (
|
||||||
|
creationParams = bootstrap.NewCreationParams("AAA", "a.com")
|
||||||
|
joiningBootstrap = JoiningBootstrap{
|
||||||
|
Bootstrap: bootstrap.Bootstrap{
|
||||||
|
NetworkCreationParams: creationParams,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
network = NewMockNetwork(t)
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Run("success", func(t *testing.T) {
|
||||||
|
var (
|
||||||
|
h = newLoaderHarness(t)
|
||||||
|
networkStateDirPath = h.networkStateDirPath(creationParams.ID)
|
||||||
|
networkRuntimeDirPath = h.networkRuntimeDirPath(creationParams.ID)
|
||||||
|
)
|
||||||
|
|
||||||
|
h.constructors.
|
||||||
|
On(
|
||||||
|
"join",
|
||||||
|
toolkit.MockArg[context.Context](),
|
||||||
|
toolkit.MockArg[*mlog.Logger](),
|
||||||
|
h.envBinDirPath,
|
||||||
|
toolkit.MockArg[*children.NebulaDeviceNamer](),
|
||||||
|
joiningBootstrap,
|
||||||
|
toolkit.Dir{Path: networkStateDirPath},
|
||||||
|
toolkit.Dir{Path: networkRuntimeDirPath},
|
||||||
|
(*Opts)(nil),
|
||||||
|
).
|
||||||
|
Return(network, nil).
|
||||||
|
Once()
|
||||||
|
|
||||||
|
got, err := h.loader.Join(
|
||||||
|
h.ctx,
|
||||||
|
h.logger,
|
||||||
|
joiningBootstrap,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, network, got)
|
||||||
|
h.assertDirExists(t, true, networkStateDirPath)
|
||||||
|
h.assertDirExists(t, true, networkRuntimeDirPath)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("error/constructor", func(t *testing.T) {
|
||||||
|
var (
|
||||||
|
h = newLoaderHarness(t)
|
||||||
|
networkStateDirPath = h.networkStateDirPath(creationParams.ID)
|
||||||
|
networkRuntimeDirPath = h.networkRuntimeDirPath(creationParams.ID)
|
||||||
|
wantErr = errors.New("some error")
|
||||||
|
)
|
||||||
|
|
||||||
|
h.constructors.
|
||||||
|
On(
|
||||||
|
"join",
|
||||||
|
toolkit.MockArg[context.Context](),
|
||||||
|
toolkit.MockArg[*mlog.Logger](),
|
||||||
|
h.envBinDirPath,
|
||||||
|
toolkit.MockArg[*children.NebulaDeviceNamer](),
|
||||||
|
joiningBootstrap,
|
||||||
|
toolkit.Dir{Path: networkStateDirPath},
|
||||||
|
toolkit.Dir{Path: networkRuntimeDirPath},
|
||||||
|
(*Opts)(nil),
|
||||||
|
).
|
||||||
|
Return(nil, wantErr).
|
||||||
|
Once()
|
||||||
|
|
||||||
|
_, err := h.loader.Join(
|
||||||
|
h.ctx,
|
||||||
|
h.logger,
|
||||||
|
joiningBootstrap,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.ErrorIs(t, err, wantErr)
|
||||||
|
h.assertDirExists(t, false, networkStateDirPath)
|
||||||
|
h.assertDirExists(t, false, networkRuntimeDirPath)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoader_Create(t *testing.T) {
|
||||||
|
var (
|
||||||
|
creationParams = bootstrap.NewCreationParams("AAA", "a.com")
|
||||||
|
ipNet = nebula.MustParseIPNet(t, "172.16.0.0/24")
|
||||||
|
hostName = nebula.HostName("foo")
|
||||||
|
network = NewMockNetwork(t)
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Run("success", func(t *testing.T) {
|
||||||
|
var (
|
||||||
|
h = newLoaderHarness(t)
|
||||||
|
networkStateDirPath = h.networkStateDirPath(creationParams.ID)
|
||||||
|
networkRuntimeDirPath = h.networkRuntimeDirPath(creationParams.ID)
|
||||||
|
)
|
||||||
|
|
||||||
|
h.constructors.
|
||||||
|
On(
|
||||||
|
"create",
|
||||||
|
toolkit.MockArg[context.Context](),
|
||||||
|
toolkit.MockArg[*mlog.Logger](),
|
||||||
|
h.envBinDirPath,
|
||||||
|
toolkit.MockArg[*children.NebulaDeviceNamer](),
|
||||||
|
toolkit.Dir{Path: networkStateDirPath},
|
||||||
|
toolkit.Dir{Path: networkRuntimeDirPath},
|
||||||
|
creationParams,
|
||||||
|
ipNet,
|
||||||
|
hostName,
|
||||||
|
(*Opts)(nil),
|
||||||
|
).
|
||||||
|
Return(network, nil).
|
||||||
|
Once()
|
||||||
|
|
||||||
|
got, err := h.loader.Create(
|
||||||
|
h.ctx,
|
||||||
|
h.logger,
|
||||||
|
creationParams,
|
||||||
|
ipNet,
|
||||||
|
hostName,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, network, got)
|
||||||
|
h.assertDirExists(t, true, networkStateDirPath)
|
||||||
|
h.assertDirExists(t, true, networkRuntimeDirPath)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("error", func(t *testing.T) {
|
||||||
|
var (
|
||||||
|
h = newLoaderHarness(t)
|
||||||
|
networkStateDirPath = h.networkStateDirPath(creationParams.ID)
|
||||||
|
networkRuntimeDirPath = h.networkRuntimeDirPath(creationParams.ID)
|
||||||
|
wantErr = errors.New("some error")
|
||||||
|
)
|
||||||
|
|
||||||
|
h.constructors.
|
||||||
|
On(
|
||||||
|
"create",
|
||||||
|
toolkit.MockArg[context.Context](),
|
||||||
|
toolkit.MockArg[*mlog.Logger](),
|
||||||
|
h.envBinDirPath,
|
||||||
|
toolkit.MockArg[*children.NebulaDeviceNamer](),
|
||||||
|
toolkit.Dir{Path: networkStateDirPath},
|
||||||
|
toolkit.Dir{Path: networkRuntimeDirPath},
|
||||||
|
creationParams,
|
||||||
|
ipNet,
|
||||||
|
hostName,
|
||||||
|
(*Opts)(nil),
|
||||||
|
).
|
||||||
|
Return(nil, wantErr).
|
||||||
|
Once()
|
||||||
|
|
||||||
|
_, err := h.loader.Create(
|
||||||
|
h.ctx,
|
||||||
|
h.logger,
|
||||||
|
creationParams,
|
||||||
|
ipNet,
|
||||||
|
hostName,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.ErrorIs(t, err, wantErr)
|
||||||
|
h.assertDirExists(t, false, networkStateDirPath)
|
||||||
|
h.assertDirExists(t, false, networkRuntimeDirPath)
|
||||||
|
})
|
||||||
|
}
|
@ -139,6 +139,12 @@ type Network interface {
|
|||||||
Shutdown() error
|
Shutdown() error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Implements constructors interface, methods defined alongside the rest of the
|
||||||
|
// Network implementation.
|
||||||
|
type constructorsImpl struct{}
|
||||||
|
|
||||||
|
func newConstructors() constructors { return constructorsImpl{} }
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Network implementation
|
// Network implementation
|
||||||
|
|
||||||
@ -257,7 +263,7 @@ func loadCreationParams(
|
|||||||
return bs.NetworkCreationParams, nil
|
return bs.NetworkCreationParams, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func load(
|
func (constructorsImpl) load(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
logger *mlog.Logger,
|
logger *mlog.Logger,
|
||||||
envBinDirPath string,
|
envBinDirPath string,
|
||||||
@ -298,7 +304,7 @@ func load(
|
|||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func join(
|
func (constructorsImpl) join(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
logger *mlog.Logger,
|
logger *mlog.Logger,
|
||||||
envBinDirPath string,
|
envBinDirPath string,
|
||||||
@ -337,7 +343,7 @@ func join(
|
|||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func create(
|
func (constructorsImpl) create(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
logger *mlog.Logger,
|
logger *mlog.Logger,
|
||||||
envBinDirPath string,
|
envBinDirPath string,
|
||||||
|
@ -63,6 +63,7 @@ func newPublicAddr() string {
|
|||||||
type integrationHarness struct {
|
type integrationHarness struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
logger *mlog.Logger
|
logger *mlog.Logger
|
||||||
|
constructors constructors
|
||||||
rootDir toolkit.Dir
|
rootDir toolkit.Dir
|
||||||
dirCounter atomic.Uint64
|
dirCounter atomic.Uint64
|
||||||
nebulaDeviceNamer *children.NebulaDeviceNamer
|
nebulaDeviceNamer *children.NebulaDeviceNamer
|
||||||
@ -90,6 +91,7 @@ func newIntegrationHarness(t *testing.T) *integrationHarness {
|
|||||||
return &integrationHarness{
|
return &integrationHarness{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
logger: toolkit.NewTestLogger(t),
|
logger: toolkit.NewTestLogger(t),
|
||||||
|
constructors: newConstructors(),
|
||||||
rootDir: toolkit.Dir{Path: rootDir},
|
rootDir: toolkit.Dir{Path: rootDir},
|
||||||
nebulaDeviceNamer: children.NewNebulaDeviceNamer(),
|
nebulaDeviceNamer: children.NewNebulaDeviceNamer(),
|
||||||
}
|
}
|
||||||
@ -171,6 +173,7 @@ type integrationHarnessNetwork struct {
|
|||||||
|
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
logger *mlog.Logger
|
logger *mlog.Logger
|
||||||
|
constructors constructors
|
||||||
hostName nebula.HostName
|
hostName nebula.HostName
|
||||||
stateDir, runtimeDir toolkit.Dir
|
stateDir, runtimeDir toolkit.Dir
|
||||||
nebulaDeviceNamer *children.NebulaDeviceNamer
|
nebulaDeviceNamer *children.NebulaDeviceNamer
|
||||||
@ -204,7 +207,7 @@ func (h *integrationHarness) createNetwork(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
network, err := create(
|
network, err := h.constructors.create(
|
||||||
h.ctx,
|
h.ctx,
|
||||||
logger,
|
logger,
|
||||||
getEnvBinDirPath(),
|
getEnvBinDirPath(),
|
||||||
@ -224,6 +227,7 @@ func (h *integrationHarness) createNetwork(
|
|||||||
network,
|
network,
|
||||||
h.ctx,
|
h.ctx,
|
||||||
logger,
|
logger,
|
||||||
|
h.constructors,
|
||||||
hostName,
|
hostName,
|
||||||
stateDir,
|
stateDir,
|
||||||
runtimeDir,
|
runtimeDir,
|
||||||
@ -288,7 +292,7 @@ func (h *integrationHarness) joinNetwork(
|
|||||||
)
|
)
|
||||||
|
|
||||||
t.Logf("Joining as %q", hostNameStr)
|
t.Logf("Joining as %q", hostNameStr)
|
||||||
joinedNetwork, err := join(
|
joinedNetwork, err := h.constructors.join(
|
||||||
h.ctx,
|
h.ctx,
|
||||||
logger,
|
logger,
|
||||||
getEnvBinDirPath(),
|
getEnvBinDirPath(),
|
||||||
@ -306,6 +310,7 @@ func (h *integrationHarness) joinNetwork(
|
|||||||
joinedNetwork,
|
joinedNetwork,
|
||||||
h.ctx,
|
h.ctx,
|
||||||
logger,
|
logger,
|
||||||
|
h.constructors,
|
||||||
hostName,
|
hostName,
|
||||||
stateDir,
|
stateDir,
|
||||||
runtimeDir,
|
runtimeDir,
|
||||||
@ -331,7 +336,7 @@ func (nh *integrationHarnessNetwork) restart(t *testing.T) {
|
|||||||
|
|
||||||
t.Log("Loading network (restart)")
|
t.Log("Loading network (restart)")
|
||||||
var err error
|
var err error
|
||||||
nh.Network, err = load(
|
nh.Network, err = nh.constructors.load(
|
||||||
nh.ctx,
|
nh.ctx,
|
||||||
nh.logger,
|
nh.logger,
|
||||||
getEnvBinDirPath(),
|
getEnvBinDirPath(),
|
||||||
|
Loading…
Reference in New Issue
Block a user