Skip to content

Commit 72268b7

Browse files
yroblataskbot
andauthored
validate that group membership changes trigger reconciliation (#2866)
* add test to validate that group membership changes trigger reconciliation * fixes from review --------- Co-authored-by: taskbot <[email protected]>
1 parent 90a7b31 commit 72268b7

File tree

1 file changed

+134
-0
lines changed

1 file changed

+134
-0
lines changed

test/e2e/thv-operator/virtualmcp/virtualmcp_yardstick_base_test.go

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package virtualmcp
33
import (
44
"fmt"
55
"net/http"
6+
"slices"
67
"strings"
78
"time"
89

@@ -243,4 +244,137 @@ var _ = Describe("VirtualMCPServer Yardstick Base", Ordered, func() {
243244
Expect(vmcpServer.Status.Phase).To(Equal(mcpv1alpha1.VirtualMCPServerPhaseReady))
244245
})
245246
})
247+
248+
Context("when testing group membership changes trigger reconciliation", func() {
249+
backend3Name := "yardstick-c"
250+
backend4Name := "yardstick-d"
251+
252+
It("should have two discovered backends initially", func() {
253+
status, err := GetVirtualMCPServerStatus(ctx, k8sClient, vmcpServerName, testNamespace)
254+
Expect(err).ToNot(HaveOccurred())
255+
Expect(status.BackendCount).To(Equal(2), "Should have 2 initial backends")
256+
Expect(status.DiscoveredBackends).To(HaveLen(2), "Should have 2 discovered backends")
257+
258+
backendNames := make([]string, len(status.DiscoveredBackends))
259+
for i, backend := range status.DiscoveredBackends {
260+
backendNames[i] = backend.Name
261+
}
262+
Expect(backendNames).To(ContainElements(backend1Name, backend2Name))
263+
264+
By(fmt.Sprintf("Initial backends: %v", backendNames))
265+
})
266+
267+
It("should discover a new backend when added to the group", func() {
268+
By("Creating a new yardstick backend MCPServer and adding to the group")
269+
CreateMCPServerAndWait(ctx, k8sClient, backend3Name, testNamespace,
270+
mcpGroupName, images.YardstickServerImage, timeout, pollingInterval)
271+
272+
By("Waiting for VirtualMCPServer to reconcile and discover the new backend")
273+
Eventually(func() error {
274+
status, err := GetVirtualMCPServerStatus(ctx, k8sClient, vmcpServerName, testNamespace)
275+
if err != nil {
276+
return err
277+
}
278+
279+
if status.BackendCount != 3 {
280+
return fmt.Errorf("expected 3 backends, got %d", status.BackendCount)
281+
}
282+
283+
if len(status.DiscoveredBackends) != 3 {
284+
return fmt.Errorf("expected 3 discovered backends, got %d", len(status.DiscoveredBackends))
285+
}
286+
287+
backendNames := make([]string, len(status.DiscoveredBackends))
288+
for i, backend := range status.DiscoveredBackends {
289+
backendNames[i] = backend.Name
290+
}
291+
292+
if !slices.Contains(backendNames, backend3Name) {
293+
return fmt.Errorf("new backend %s not found in discovered backends: %v", backend3Name, backendNames)
294+
}
295+
296+
return nil
297+
}, timeout, pollingInterval).Should(Succeed(), "VirtualMCPServer should discover the new backend")
298+
299+
})
300+
301+
It("should remove a backend when deleted from the group", func() {
302+
By("Creating a dedicated backend MCPServer for deletion test")
303+
CreateMCPServerAndWait(ctx, k8sClient, backend4Name, testNamespace,
304+
mcpGroupName, images.YardstickServerImage, timeout, pollingInterval)
305+
306+
By("Waiting for VirtualMCPServer to discover the new backend (should have 4 backends)")
307+
Eventually(func() error {
308+
status, err := GetVirtualMCPServerStatus(ctx, k8sClient, vmcpServerName, testNamespace)
309+
if err != nil {
310+
return err
311+
}
312+
if status.BackendCount != 4 {
313+
return fmt.Errorf("expected 4 backends before deletion, got %d", status.BackendCount)
314+
}
315+
return nil
316+
}, timeout, pollingInterval).Should(Succeed())
317+
318+
By("Deleting the dedicated backend MCPServer from the group")
319+
backend4 := &mcpv1alpha1.MCPServer{
320+
ObjectMeta: metav1.ObjectMeta{
321+
Name: backend4Name,
322+
Namespace: testNamespace,
323+
},
324+
}
325+
Expect(k8sClient.Delete(ctx, backend4)).To(Succeed())
326+
327+
By("Waiting for VirtualMCPServer to reconcile and remove the deleted backend")
328+
Eventually(func() error {
329+
status, err := GetVirtualMCPServerStatus(ctx, k8sClient, vmcpServerName, testNamespace)
330+
if err != nil {
331+
return err
332+
}
333+
334+
if status.BackendCount != 3 {
335+
return fmt.Errorf("expected 3 backends after removal, got %d", status.BackendCount)
336+
}
337+
338+
if len(status.DiscoveredBackends) != 3 {
339+
return fmt.Errorf("expected 3 discovered backends after removal, got %d", len(status.DiscoveredBackends))
340+
}
341+
342+
backendNames := make([]string, len(status.DiscoveredBackends))
343+
for i, backend := range status.DiscoveredBackends {
344+
backendNames[i] = backend.Name
345+
}
346+
347+
if slices.Contains(backendNames, backend4Name) {
348+
return fmt.Errorf("deleted backend %s still found in discovered backends: %v", backend4Name, backendNames)
349+
}
350+
351+
return nil
352+
}, timeout, pollingInterval).Should(Succeed(), "VirtualMCPServer should remove the deleted backend")
353+
354+
})
355+
356+
It("should remain ready throughout membership changes", func() {
357+
vmcpServer := &mcpv1alpha1.VirtualMCPServer{}
358+
err := k8sClient.Get(ctx, types.NamespacedName{
359+
Name: vmcpServerName,
360+
Namespace: testNamespace,
361+
}, vmcpServer)
362+
Expect(err).ToNot(HaveOccurred())
363+
Expect(HasCondition(vmcpServer, "Ready", "True")).To(BeTrue(),
364+
"VirtualMCPServer should remain ready after membership changes")
365+
})
366+
367+
AfterAll(func() {
368+
By("Cleaning up additional backends from membership test")
369+
for _, backendName := range []string{backend3Name, backend4Name} {
370+
backend := &mcpv1alpha1.MCPServer{
371+
ObjectMeta: metav1.ObjectMeta{
372+
Name: backendName,
373+
Namespace: testNamespace,
374+
},
375+
}
376+
_ = k8sClient.Delete(ctx, backend)
377+
}
378+
})
379+
})
246380
})

0 commit comments

Comments
 (0)