e0e362d700
SDK Tests / changes (push) Successful in 2m29s
Real E2E Tests / changes (push) Successful in 2m29s
Deploy Docs Pages / build (push) Has been cancelled
Deploy Docs Pages / deploy (push) Has been cancelled
Real E2E Tests / JavaScript E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / Python E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / Java E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / C# E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / Go E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / Real E2E CI (push) Has been cancelled
SDK Tests / SDK CI (push) Has been cancelled
SDK Tests / CLI Tests (push) Has been cancelled
SDK Tests / Python SDK Quality (code-interpreter) (push) Has been cancelled
SDK Tests / Python SDK Quality (sandbox) (push) Has been cancelled
SDK Tests / Python SDK Tests (code-interpreter) (push) Has been cancelled
SDK Tests / JavaScript SDK Quality And Tests (code-interpreter) (push) Has been cancelled
SDK Tests / JavaScript SDK Quality And Tests (sandbox) (push) Has been cancelled
SDK Tests / Python SDK Tests (sandbox) (push) Has been cancelled
SDK Tests / CLI Quality (push) Has been cancelled
SDK Tests / Kotlin SDK Quality And Tests (sandbox) (push) Has been cancelled
SDK Tests / Kotlin SDK Quality And Tests (code-interpreter) (push) Has been cancelled
SDK Tests / C# SDK Quality And Tests (code-interpreter) (push) Has been cancelled
SDK Tests / C# SDK Quality And Tests (sandbox) (push) Has been cancelled
SDK Tests / Go SDK Quality And Tests (push) Has been cancelled
582 lines
18 KiB
Go
582 lines
18 KiB
Go
// Copyright 2025 Alibaba Group Holding Ltd.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package controller
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
|
|
|
sandboxv1alpha1 "github.com/alibaba/OpenSandbox/sandbox-k8s/apis/sandbox/v1alpha1"
|
|
)
|
|
|
|
func TestInMemoryAllocationStore_GetAllocation_Empty(t *testing.T) {
|
|
store := NewInMemoryAllocationStore()
|
|
ctx := context.Background()
|
|
|
|
pool := &sandboxv1alpha1.Pool{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-pool"},
|
|
}
|
|
|
|
alloc, err := store.GetAllocation(ctx, pool)
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, alloc)
|
|
assert.Empty(t, alloc.PodAllocation)
|
|
}
|
|
|
|
func TestInMemoryAllocationStore_SetAndGetAllocation(t *testing.T) {
|
|
store := NewInMemoryAllocationStore()
|
|
ctx := context.Background()
|
|
|
|
pool := &sandboxv1alpha1.Pool{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-pool"},
|
|
}
|
|
|
|
alloc := &PoolAllocation{
|
|
PodAllocation: map[string]string{
|
|
"pod1": "sandbox1",
|
|
"pod2": "sandbox2",
|
|
},
|
|
}
|
|
|
|
err := store.SetAllocation(ctx, pool, alloc)
|
|
assert.NoError(t, err)
|
|
|
|
alloc2, err := store.GetAllocation(ctx, pool)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, alloc.PodAllocation, alloc2.PodAllocation)
|
|
}
|
|
|
|
func TestInMemoryAllocationStore_UpdateAllocation_AddPods(t *testing.T) {
|
|
store := NewInMemoryAllocationStore().(*InMemoryAllocationStore)
|
|
ctx := context.Background()
|
|
|
|
store.UpdateAllocation(ctx, "default", "pool1", "sandbox1", []string{"pod1", "pod2"})
|
|
|
|
assert.Equal(t, "sandbox1", store.pools["default/pool1"].data["pod1"])
|
|
assert.Equal(t, "sandbox1", store.pools["default/pool1"].data["pod2"])
|
|
}
|
|
|
|
func TestInMemoryAllocationStore_UpdateAllocation_ReplacePods(t *testing.T) {
|
|
store := NewInMemoryAllocationStore().(*InMemoryAllocationStore)
|
|
ctx := context.Background()
|
|
|
|
store.UpdateAllocation(ctx, "default", "pool1", "sandbox1", []string{"pod1", "pod2"})
|
|
store.UpdateAllocation(ctx, "default", "pool1", "sandbox1", []string{"pod3", "pod4"})
|
|
|
|
_, exists1 := store.pools["default/pool1"].data["pod1"]
|
|
_, exists2 := store.pools["default/pool1"].data["pod2"]
|
|
assert.False(t, exists1, "old pod1 should be removed")
|
|
assert.False(t, exists2, "old pod2 should be removed")
|
|
|
|
assert.Equal(t, "sandbox1", store.pools["default/pool1"].data["pod3"])
|
|
assert.Equal(t, "sandbox1", store.pools["default/pool1"].data["pod4"])
|
|
}
|
|
|
|
func TestInMemoryAllocationStore_UpdateAllocation_MultipleSandboxes(t *testing.T) {
|
|
store := NewInMemoryAllocationStore().(*InMemoryAllocationStore)
|
|
ctx := context.Background()
|
|
|
|
store.UpdateAllocation(ctx, "default", "pool1", "sandbox1", []string{"pod1", "pod2"})
|
|
store.UpdateAllocation(ctx, "default", "pool1", "sandbox2", []string{"pod3", "pod4"})
|
|
|
|
assert.Equal(t, "sandbox1", store.pools["default/pool1"].data["pod1"])
|
|
assert.Equal(t, "sandbox1", store.pools["default/pool1"].data["pod2"])
|
|
assert.Equal(t, "sandbox2", store.pools["default/pool1"].data["pod3"])
|
|
assert.Equal(t, "sandbox2", store.pools["default/pool1"].data["pod4"])
|
|
}
|
|
|
|
func TestInMemoryAllocationStore_UpdateAllocation_MultiplePools(t *testing.T) {
|
|
store := NewInMemoryAllocationStore().(*InMemoryAllocationStore)
|
|
ctx := context.Background()
|
|
|
|
store.UpdateAllocation(ctx, "default", "pool1", "sandbox1", []string{"pod1", "pod2"})
|
|
store.UpdateAllocation(ctx, "default", "pool2", "sandbox2", []string{"pod3", "pod4"})
|
|
|
|
assert.Equal(t, "sandbox1", store.pools["default/pool1"].data["pod1"])
|
|
assert.Equal(t, "sandbox2", store.pools["default/pool2"].data["pod3"])
|
|
|
|
_, exists := store.pools["default/pool1"].data["pod3"]
|
|
assert.False(t, exists, "pool1 should not see pool2's pods")
|
|
}
|
|
|
|
func TestInMemoryAllocationStore_GetAllocation_IsolatedByPool(t *testing.T) {
|
|
store := NewInMemoryAllocationStore()
|
|
ctx := context.Background()
|
|
|
|
pool1 := &sandboxv1alpha1.Pool{ObjectMeta: metav1.ObjectMeta{Name: "pool1"}}
|
|
pool2 := &sandboxv1alpha1.Pool{ObjectMeta: metav1.ObjectMeta{Name: "pool2"}}
|
|
|
|
_ = store.SetAllocation(ctx, pool1, &PoolAllocation{
|
|
PodAllocation: map[string]string{"pod1": "sandbox1"},
|
|
})
|
|
_ = store.SetAllocation(ctx, pool2, &PoolAllocation{
|
|
PodAllocation: map[string]string{"pod2": "sandbox2"},
|
|
})
|
|
|
|
alloc1, _ := store.GetAllocation(ctx, pool1)
|
|
alloc2, _ := store.GetAllocation(ctx, pool2)
|
|
|
|
assert.Equal(t, "sandbox1", alloc1.PodAllocation["pod1"])
|
|
assert.Empty(t, alloc1.PodAllocation["pod2"])
|
|
|
|
assert.Equal(t, "sandbox2", alloc2.PodAllocation["pod2"])
|
|
assert.Empty(t, alloc2.PodAllocation["pod1"])
|
|
}
|
|
|
|
func TestInMemoryAllocationStore_Recover(t *testing.T) {
|
|
scheme := runtime.NewScheme()
|
|
_ = sandboxv1alpha1.AddToScheme(scheme)
|
|
|
|
allocation1 := &SandboxAllocation{Pods: []string{"pod1", "pod2"}}
|
|
allocation2 := &SandboxAllocation{Pods: []string{"pod3", "pod4"}}
|
|
// released (alloc-released) means recycle is complete; Recover should exclude these pods.
|
|
released2 := &AllocationReleased{Pods: []string{"pod4"}}
|
|
|
|
alloc1JSON, _ := json.Marshal(allocation1)
|
|
alloc2JSON, _ := json.Marshal(allocation2)
|
|
released2JSON, _ := json.Marshal(released2)
|
|
|
|
sandbox1 := &sandboxv1alpha1.BatchSandbox{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "sandbox1",
|
|
Namespace: "default",
|
|
Annotations: map[string]string{
|
|
AnnoAllocStatusKey: string(alloc1JSON),
|
|
},
|
|
},
|
|
Spec: sandboxv1alpha1.BatchSandboxSpec{
|
|
PoolRef: "pool1",
|
|
},
|
|
}
|
|
|
|
sandbox2 := &sandboxv1alpha1.BatchSandbox{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "sandbox2",
|
|
Namespace: "default",
|
|
Annotations: map[string]string{
|
|
AnnoAllocStatusKey: string(alloc2JSON),
|
|
AnnoAllocReleasedKey: string(released2JSON),
|
|
},
|
|
},
|
|
Spec: sandboxv1alpha1.BatchSandboxSpec{
|
|
PoolRef: "pool1",
|
|
},
|
|
}
|
|
|
|
sandbox3 := &sandboxv1alpha1.BatchSandbox{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "sandbox3",
|
|
Namespace: "default",
|
|
},
|
|
Spec: sandboxv1alpha1.BatchSandboxSpec{
|
|
PoolRef: "pool2",
|
|
},
|
|
}
|
|
|
|
client := fake.NewClientBuilder().
|
|
WithScheme(scheme).
|
|
WithObjects(sandbox1, sandbox2, sandbox3).
|
|
Build()
|
|
|
|
store := NewInMemoryAllocationStore().(*InMemoryAllocationStore)
|
|
ctx := context.Background()
|
|
|
|
err := store.Recover(ctx, client)
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "sandbox1", store.pools["default/pool1"].data["pod1"])
|
|
assert.Equal(t, "sandbox1", store.pools["default/pool1"].data["pod2"])
|
|
assert.Equal(t, "sandbox2", store.pools["default/pool1"].data["pod3"])
|
|
// pod4 is in alloc-released (completed recycle), so it should be excluded from the pool.
|
|
assert.Equal(t, "", store.pools["default/pool1"].data["pod4"])
|
|
|
|
assert.Equal(t, 0, len(store.pools["default/pool2"].data), "pool2 should have no allocations")
|
|
}
|
|
|
|
func TestInMemoryAllocationStore_Recover_ReleaseOnlyOwnPods(t *testing.T) {
|
|
scheme := runtime.NewScheme()
|
|
_ = sandboxv1alpha1.AddToScheme(scheme)
|
|
|
|
allocation1 := &SandboxAllocation{Pods: []string{"pod1"}}
|
|
// sandbox1 has completed recycling pod1 (alloc-released), so pod1 should be freed.
|
|
released1 := &AllocationReleased{Pods: []string{"pod1"}}
|
|
allocation2 := &SandboxAllocation{Pods: []string{"pod1"}}
|
|
|
|
alloc1JSON, _ := json.Marshal(allocation1)
|
|
released1JSON, _ := json.Marshal(released1)
|
|
alloc2JSON, _ := json.Marshal(allocation2)
|
|
|
|
sandbox1 := &sandboxv1alpha1.BatchSandbox{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "sandbox1",
|
|
Namespace: "default",
|
|
Annotations: map[string]string{
|
|
AnnoAllocStatusKey: string(alloc1JSON),
|
|
AnnoAllocReleasedKey: string(released1JSON),
|
|
},
|
|
},
|
|
Spec: sandboxv1alpha1.BatchSandboxSpec{
|
|
PoolRef: "pool1",
|
|
},
|
|
}
|
|
|
|
sandbox2 := &sandboxv1alpha1.BatchSandbox{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "sandbox2",
|
|
Namespace: "default",
|
|
Annotations: map[string]string{
|
|
AnnoAllocStatusKey: string(alloc2JSON),
|
|
},
|
|
},
|
|
Spec: sandboxv1alpha1.BatchSandboxSpec{
|
|
PoolRef: "pool1",
|
|
},
|
|
}
|
|
|
|
client := fake.NewClientBuilder().
|
|
WithScheme(scheme).
|
|
WithObjects(sandbox2, sandbox1).
|
|
Build()
|
|
|
|
store := NewInMemoryAllocationStore().(*InMemoryAllocationStore)
|
|
ctx := context.Background()
|
|
|
|
err := store.Recover(ctx, client)
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "sandbox2", store.pools["default/pool1"].data["pod1"])
|
|
}
|
|
|
|
func TestInMemoryAllocationStore_Recover_ReleasePodReassignedMultipleTimes(t *testing.T) {
|
|
scheme := runtime.NewScheme()
|
|
_ = sandboxv1alpha1.AddToScheme(scheme)
|
|
|
|
allocation1 := &SandboxAllocation{Pods: []string{"pod1"}}
|
|
released1 := &AllocationReleased{Pods: []string{"pod1"}}
|
|
allocation2 := &SandboxAllocation{Pods: []string{"pod1"}}
|
|
released2 := &AllocationReleased{Pods: []string{"pod1"}}
|
|
allocation3 := &SandboxAllocation{Pods: []string{"pod1"}}
|
|
|
|
alloc1JSON, _ := json.Marshal(allocation1)
|
|
released1JSON, _ := json.Marshal(released1)
|
|
alloc2JSON, _ := json.Marshal(allocation2)
|
|
released2JSON, _ := json.Marshal(released2)
|
|
alloc3JSON, _ := json.Marshal(allocation3)
|
|
|
|
sandbox1 := &sandboxv1alpha1.BatchSandbox{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "sandbox1",
|
|
Namespace: "default",
|
|
Annotations: map[string]string{
|
|
AnnoAllocStatusKey: string(alloc1JSON),
|
|
AnnoAllocReleasedKey: string(released1JSON),
|
|
},
|
|
},
|
|
Spec: sandboxv1alpha1.BatchSandboxSpec{PoolRef: "pool1"},
|
|
}
|
|
|
|
sandbox2 := &sandboxv1alpha1.BatchSandbox{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "sandbox2",
|
|
Namespace: "default",
|
|
Annotations: map[string]string{
|
|
AnnoAllocStatusKey: string(alloc2JSON),
|
|
AnnoAllocReleasedKey: string(released2JSON),
|
|
},
|
|
},
|
|
Spec: sandboxv1alpha1.BatchSandboxSpec{PoolRef: "pool1"},
|
|
}
|
|
|
|
sandbox3 := &sandboxv1alpha1.BatchSandbox{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "sandbox3",
|
|
Namespace: "default",
|
|
Annotations: map[string]string{
|
|
AnnoAllocStatusKey: string(alloc3JSON),
|
|
},
|
|
},
|
|
Spec: sandboxv1alpha1.BatchSandboxSpec{PoolRef: "pool1"},
|
|
}
|
|
|
|
client := fake.NewClientBuilder().
|
|
WithScheme(scheme).
|
|
WithObjects(sandbox3, sandbox2, sandbox1).
|
|
Build()
|
|
|
|
store := NewInMemoryAllocationStore().(*InMemoryAllocationStore)
|
|
ctx := context.Background()
|
|
|
|
err := store.Recover(ctx, client)
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "sandbox3", store.pools["default/pool1"].data["pod1"])
|
|
}
|
|
|
|
func TestInMemoryAllocationStore_Recover_ClearsExisting(t *testing.T) {
|
|
scheme := runtime.NewScheme()
|
|
_ = sandboxv1alpha1.AddToScheme(scheme)
|
|
|
|
client := fake.NewClientBuilder().WithScheme(scheme).Build()
|
|
store := NewInMemoryAllocationStore().(*InMemoryAllocationStore)
|
|
ctx := context.Background()
|
|
|
|
store.pools["default/pool1"] = &poolEntry{data: map[string]string{"old-pod": "old-sandbox"}}
|
|
|
|
allocation := &SandboxAllocation{Pods: []string{"new-pod"}}
|
|
allocJSON, _ := json.Marshal(allocation)
|
|
|
|
sandbox := &sandboxv1alpha1.BatchSandbox{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "sandbox1",
|
|
Namespace: "default",
|
|
Annotations: map[string]string{
|
|
AnnoAllocStatusKey: string(allocJSON),
|
|
},
|
|
},
|
|
Spec: sandboxv1alpha1.BatchSandboxSpec{
|
|
PoolRef: "pool1",
|
|
},
|
|
}
|
|
|
|
client = fake.NewClientBuilder().
|
|
WithScheme(scheme).
|
|
WithObjects(sandbox).
|
|
Build()
|
|
|
|
err := store.Recover(ctx, client)
|
|
assert.NoError(t, err)
|
|
|
|
_, exists := store.pools["default/pool1"].data["old-pod"]
|
|
assert.False(t, exists, "old allocation should be cleared")
|
|
assert.Equal(t, "sandbox1", store.pools["default/pool1"].data["new-pod"])
|
|
}
|
|
|
|
func TestInMemoryAllocationStore_ThreadSafety(t *testing.T) {
|
|
store := NewInMemoryAllocationStore()
|
|
ctx := context.Background()
|
|
|
|
var wg sync.WaitGroup
|
|
numGoroutines := 100
|
|
numOperations := 100
|
|
|
|
pool := &sandboxv1alpha1.Pool{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-pool"},
|
|
}
|
|
|
|
for i := 0; i < numGoroutines; i++ {
|
|
wg.Add(1)
|
|
go func(id int) {
|
|
defer wg.Done()
|
|
for j := 0; j < numOperations; j++ {
|
|
alloc := &PoolAllocation{
|
|
PodAllocation: map[string]string{
|
|
"pod": "sandbox",
|
|
},
|
|
}
|
|
_ = store.SetAllocation(ctx, pool, alloc)
|
|
_, _ = store.GetAllocation(ctx, pool)
|
|
}
|
|
}(i)
|
|
}
|
|
|
|
wg.Wait()
|
|
}
|
|
|
|
func TestInMemoryAllocationStore_GetAllocation_ReturnsCopy(t *testing.T) {
|
|
store := NewInMemoryAllocationStore()
|
|
ctx := context.Background()
|
|
|
|
pool := &sandboxv1alpha1.Pool{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-pool"},
|
|
}
|
|
|
|
alloc := &PoolAllocation{
|
|
PodAllocation: map[string]string{
|
|
"pod1": "sandbox1",
|
|
},
|
|
}
|
|
|
|
_ = store.SetAllocation(ctx, pool, alloc)
|
|
|
|
alloc1, _ := store.GetAllocation(ctx, pool)
|
|
alloc2, _ := store.GetAllocation(ctx, pool)
|
|
|
|
alloc1.PodAllocation["pod1"] = "modified"
|
|
|
|
assert.Equal(t, "sandbox1", alloc2.PodAllocation["pod1"], "GetAllocation should return a copy")
|
|
}
|
|
|
|
func TestInMemoryAllocationStore_SandboxDeleted_PodsReturnedToPool(t *testing.T) {
|
|
store := NewInMemoryAllocationStore()
|
|
ctx := context.Background()
|
|
|
|
pool := &sandboxv1alpha1.Pool{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-pool"},
|
|
}
|
|
|
|
// Initial state: sandbox1 has pod1 and pod2 allocated
|
|
initialAlloc := &PoolAllocation{
|
|
PodAllocation: map[string]string{
|
|
"pod1": "sandbox1",
|
|
"pod2": "sandbox1",
|
|
"pod3": "sandbox2",
|
|
},
|
|
}
|
|
err := store.SetAllocation(ctx, pool, initialAlloc)
|
|
assert.NoError(t, err)
|
|
|
|
// Simulate sandbox1 deletion by updating allocation without sandbox1's pods
|
|
// This is what Schedule does when GC detects deleted sandbox
|
|
updatedAlloc := &PoolAllocation{
|
|
PodAllocation: map[string]string{
|
|
"pod3": "sandbox2",
|
|
},
|
|
}
|
|
err = store.SetAllocation(ctx, pool, updatedAlloc)
|
|
assert.NoError(t, err)
|
|
|
|
// Verify pods are returned to pool (no longer allocated)
|
|
result, err := store.GetAllocation(ctx, pool)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, result.PodAllocation, 1)
|
|
assert.Equal(t, "sandbox2", result.PodAllocation["pod3"])
|
|
_, exists1 := result.PodAllocation["pod1"]
|
|
_, exists2 := result.PodAllocation["pod2"]
|
|
assert.False(t, exists1, "pod1 should be returned to pool")
|
|
assert.False(t, exists2, "pod2 should be returned to pool")
|
|
}
|
|
|
|
func TestInMemoryAllocationStore_UpdateAllocation_EmptyPods_ReleaseAll(t *testing.T) {
|
|
store := NewInMemoryAllocationStore().(*InMemoryAllocationStore)
|
|
ctx := context.Background()
|
|
|
|
// Setup initial allocation
|
|
store.UpdateAllocation(ctx, "default", "pool1", "sandbox1", []string{"pod1", "pod2"})
|
|
assert.Equal(t, 2, len(store.pools["default/pool1"].data))
|
|
|
|
// Update with empty pods (simulates release)
|
|
store.UpdateAllocation(ctx, "default", "pool1", "sandbox1", []string{})
|
|
|
|
// Verify all pods are released
|
|
assert.Empty(t, store.pools["default/pool1"].data, "all pods should be released when empty slice provided")
|
|
}
|
|
|
|
func TestInMemoryAllocationStore_SetAllocation_ReplaceAll(t *testing.T) {
|
|
store := NewInMemoryAllocationStore()
|
|
ctx := context.Background()
|
|
|
|
pool := &sandboxv1alpha1.Pool{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-pool"},
|
|
}
|
|
|
|
// Set initial allocation with multiple sandboxes
|
|
_ = store.SetAllocation(ctx, pool, &PoolAllocation{
|
|
PodAllocation: map[string]string{
|
|
"pod1": "sandbox1",
|
|
"pod2": "sandbox1",
|
|
"pod3": "sandbox2",
|
|
"pod4": "sandbox2",
|
|
},
|
|
})
|
|
|
|
// Simulate GC: replace with allocation excluding deleted sandbox
|
|
_ = store.SetAllocation(ctx, pool, &PoolAllocation{
|
|
PodAllocation: map[string]string{
|
|
"pod3": "sandbox2",
|
|
"pod4": "sandbox2",
|
|
},
|
|
})
|
|
|
|
result, _ := store.GetAllocation(ctx, pool)
|
|
assert.Len(t, result.PodAllocation, 2)
|
|
assert.NotContains(t, result.PodAllocation, "pod1")
|
|
assert.NotContains(t, result.PodAllocation, "pod2")
|
|
assert.Equal(t, "sandbox2", result.PodAllocation["pod3"])
|
|
assert.Equal(t, "sandbox2", result.PodAllocation["pod4"])
|
|
}
|
|
|
|
// TestInMemoryAllocationStore_MultiNamespaceSamePoolName tests that pools with the same name
|
|
// in different namespaces are properly isolated from each other.
|
|
func TestInMemoryAllocationStore_MultiNamespaceSamePoolName(t *testing.T) {
|
|
store := NewInMemoryAllocationStore()
|
|
ctx := context.Background()
|
|
|
|
// Create two pools with the same name but in different namespaces
|
|
poolNs1 := &sandboxv1alpha1.Pool{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "shared-pool",
|
|
Namespace: "namespace1",
|
|
},
|
|
}
|
|
poolNs2 := &sandboxv1alpha1.Pool{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "shared-pool",
|
|
Namespace: "namespace2",
|
|
},
|
|
}
|
|
|
|
// Set different allocations for each namespace
|
|
_ = store.SetAllocation(ctx, poolNs1, &PoolAllocation{
|
|
PodAllocation: map[string]string{
|
|
"pod1": "sandbox1-ns1",
|
|
"pod2": "sandbox1-ns1",
|
|
},
|
|
})
|
|
_ = store.SetAllocation(ctx, poolNs2, &PoolAllocation{
|
|
PodAllocation: map[string]string{
|
|
"pod3": "sandbox1-ns2",
|
|
"pod4": "sandbox1-ns2",
|
|
},
|
|
})
|
|
|
|
// Verify each namespace only sees its own allocations
|
|
allocNs1, _ := store.GetAllocation(ctx, poolNs1)
|
|
allocNs2, _ := store.GetAllocation(ctx, poolNs2)
|
|
|
|
// Namespace1 should have pod1 and pod2
|
|
assert.Len(t, allocNs1.PodAllocation, 2)
|
|
assert.Equal(t, "sandbox1-ns1", allocNs1.PodAllocation["pod1"])
|
|
assert.Equal(t, "sandbox1-ns1", allocNs1.PodAllocation["pod2"])
|
|
assert.Empty(t, allocNs1.PodAllocation["pod3"], "namespace1 should not see namespace2's pods")
|
|
assert.Empty(t, allocNs1.PodAllocation["pod4"], "namespace1 should not see namespace2's pods")
|
|
|
|
// Namespace2 should have pod3 and pod4
|
|
assert.Len(t, allocNs2.PodAllocation, 2)
|
|
assert.Equal(t, "sandbox1-ns2", allocNs2.PodAllocation["pod3"])
|
|
assert.Equal(t, "sandbox1-ns2", allocNs2.PodAllocation["pod4"])
|
|
assert.Empty(t, allocNs2.PodAllocation["pod1"], "namespace2 should not see namespace1's pods")
|
|
assert.Empty(t, allocNs2.PodAllocation["pod2"], "namespace2 should not see namespace1's pods")
|
|
|
|
// Update allocation in namespace1 should not affect namespace2
|
|
_ = store.SetAllocation(ctx, poolNs1, &PoolAllocation{
|
|
PodAllocation: map[string]string{
|
|
"pod5": "sandbox2-ns1",
|
|
},
|
|
})
|
|
|
|
// Verify namespace2 is unchanged
|
|
allocNs2AfterUpdate, _ := store.GetAllocation(ctx, poolNs2)
|
|
assert.Len(t, allocNs2AfterUpdate.PodAllocation, 2, "namespace2 should still have 2 pods")
|
|
assert.Equal(t, "sandbox1-ns2", allocNs2AfterUpdate.PodAllocation["pod3"])
|
|
assert.Equal(t, "sandbox1-ns2", allocNs2AfterUpdate.PodAllocation["pod4"])
|
|
}
|