test(cluster): cover weighted node pool selection

NewNodePool/Get had no tests. Covers capability-slot miss, preferred-
node override, and weight-based selection.

Authored By: TDvorak <info@tdvorak.dev>

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
pull/3582/head
Tomas Dvorak 2 weeks ago
parent 57d21b8f4e
commit 3a5f01a63f

@ -0,0 +1,88 @@
package cluster
import (
"context"
"errors"
"path/filepath"
"testing"
"github.com/cloudreve/Cloudreve/v4/ent"
"github.com/cloudreve/Cloudreve/v4/ent/enttest"
"github.com/cloudreve/Cloudreve/v4/ent/node"
"github.com/cloudreve/Cloudreve/v4/inventory"
"github.com/cloudreve/Cloudreve/v4/inventory/types"
"github.com/cloudreve/Cloudreve/v4/pkg/boolset"
"github.com/cloudreve/Cloudreve/v4/pkg/conf"
"github.com/cloudreve/Cloudreve/v4/pkg/logging"
"github.com/cloudreve/Cloudreve/v4/pkg/setting"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type stubSettings struct {
setting.Provider
}
func capsOf(bits ...types.NodeCapability) *boolset.BooleanSet {
b := &boolset.BooleanSet{}
for _, c := range bits {
boolset.Set(int(c), true, b)
}
return b
}
func newPoolFixture(t *testing.T) (*ent.Client, NodePool, context.Context) {
t.Helper()
ctx := context.Background()
client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&_fk=1")
t.Cleanup(func() { client.Close() })
logger := logging.NewConsoleLogger(logging.LevelError)
cfg, err := conf.NewIniConfigProvider(filepath.Join(t.TempDir(), "conf.ini"), logger)
require.NoError(t, err)
pool, err := NewNodePool(ctx, logger, cfg, &stubSettings{}, inventory.NewNodeClient(client))
require.NoError(t, err)
return client, pool, ctx
}
func TestWeightedNodePoolGet(t *testing.T) {
a := assert.New(t)
client, pool, ctx := newPoolFixture(t)
n1 := client.Node.Create().
SetName("n1").SetType(node.TypeMaster).SetStatus(node.StatusActive).
SetServer("http://n1").SetCapabilities(capsOf(types.NodeCapabilityRemoteDownload)).
SetWeight(10).SaveX(ctx)
client.Node.Create().
SetName("n2").SetType(node.TypeMaster).SetStatus(node.StatusActive).
SetServer("http://n2").SetCapabilities(capsOf(types.NodeCapabilityRemoteDownload)).
SetWeight(1).SaveX(ctx)
pool.(*weightedNodePool).Upsert(ctx, n1)
// Upsert requires a full refresh — rebuild pool from the seeded DB instead.
pool, err := NewNodePool(ctx, logging.NewConsoleLogger(logging.LevelError), pool.(*weightedNodePool).conf, &stubSettings{}, inventory.NewNodeClient(client))
require.NoError(t, err)
// Capability with no matching nodes errors.
_, err = pool.Get(ctx, types.NodeCapabilityCreateArchive, 0)
a.True(errors.Is(err, ErrNoAvailableNode))
// Preferred node wins regardless of weight.
selected, err := pool.Get(ctx, types.NodeCapabilityRemoteDownload, n1.ID)
require.NoError(t, err)
a.Equal(n1.ID, selected.ID())
// Without preference, the heavier node wins the first pick.
selected, err = pool.Get(ctx, types.NodeCapabilityRemoteDownload, 0)
require.NoError(t, err)
a.Equal(n1.ID, selected.ID())
}
func TestWeightedNodePoolGetUnknownCapability(t *testing.T) {
a := assert.New(t)
_, pool, ctx := newPoolFixture(t)
_, err := pool.Get(ctx, types.NodeCapabilityRemoteDownload, 0)
a.True(errors.Is(err, ErrNoAvailableNode))
}
Loading…
Cancel
Save