Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 89 additions & 5 deletions test/e2e/servicesync/servicesync.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,67 @@ import (
corev1 "k8s.io/api/core/v1"
kerrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
)

var _ = ginkgo.Describe("map services from host to virtual cluster and vice versa", func() {
var f *framework.Framework

ginkgo.JustBeforeEach(func() {
// use default framework
var _ = ginkgo.Describe("Verify mapping and syncing of services and endpoints", ginkgo.Ordered, func() {
var (
f *framework.Framework
testService *corev1.Service
//nolint:staticcheck // SA1019: corev1.Endpoints is deprecated, but still required for compatibility
testEndpoint *corev1.Endpoints
serviceName = "test-service-sync"
serviceNamespace = "default"
endpointName = "test-service-sync"
)
ginkgo.BeforeAll(func() {
f = framework.DefaultFramework
testService = &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: serviceName,
Namespace: serviceNamespace,
},
Spec: corev1.ServiceSpec{
ClusterIP: "None",
Ports: []corev1.ServicePort{
{
Name: "custom-port",
Port: 8080,
Protocol: corev1.ProtocolTCP,
TargetPort: intstr.FromInt(5000),
},
},
},
}
//nolint:staticcheck // SA1019: corev1.Endpoints is deprecated, but still required for compatibility
testEndpoint = &corev1.Endpoints{
ObjectMeta: metav1.ObjectMeta{
Name: endpointName,
Namespace: serviceNamespace,
},
//nolint:staticcheck // SA1019: corev1.Endpoints is deprecated, but still required for compatibility
Subsets: []corev1.EndpointSubset{
{
Addresses: []corev1.EndpointAddress{
{
IP: "1.1.1.1",
},
},
Ports: []corev1.EndpointPort{
{
Port: 5000,
},
},
},
},
}
})

ginkgo.AfterAll(func() {
framework.ExpectNoError(f.VClusterClient.CoreV1().Endpoints(serviceNamespace).Delete(f.Context, endpointName, metav1.DeleteOptions{}))
framework.ExpectNoError(f.VClusterClient.CoreV1().Services(serviceNamespace).Delete(f.Context, serviceName, metav1.DeleteOptions{}))
})

ginkgo.It("Test service mapping", func() {
Expand Down Expand Up @@ -54,6 +105,39 @@ var _ = ginkgo.Describe("map services from host to virtual cluster and vice vers
checkEndpointsSync(f.Context, f.VClusterClient, "test", "nginx", f.HostClient, f.VClusterNamespace, "nginx")
})
})

ginkgo.Context("Verify endpoint sync when endpoint is deployed before service", func() {
ginkgo.It("Should sync Service, Endpoints, and EndpointSlice from vCluster to host cluster", func() {
ctx := f.Context
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: usage of ctx vs. f.Context is not consistent. The object creations use .Create(f.Context, ... and all other use .Get(ctx, ...


ginkgo.By("Create Service Endpoint in vCluster")
_, err := f.VClusterClient.CoreV1().Endpoints(serviceNamespace).Create(f.Context, testEndpoint, metav1.CreateOptions{})
framework.ExpectNoError(err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd always prefer gomega.Expect(err).To(gomega.Succeed()) over framework.ExpectNoError(err)` because:

  1. it delivers way more context in case of failure. E.g. the whole nested error chain instead of only the aggregated error message.
  2. it is universal, can be used in any test, not only the once using framework.

But this is personal preference, feel free to just close this comment in case of disagreement.


ginkgo.By("Create Service in vCluster")
_, err = f.VClusterClient.CoreV1().Services(serviceNamespace).Create(f.Context, testService, metav1.CreateOptions{})
framework.ExpectNoError(err)

ginkgo.By("Verify Endpoint exists in vCluster")
_, err = f.VClusterClient.CoreV1().Endpoints(serviceNamespace).Get(ctx, endpointName, metav1.GetOptions{})
framework.ExpectNoError(err)

ginkgo.By("Verify Service exists in vCluster")
_, err = f.VClusterClient.CoreV1().Services(serviceNamespace).Get(ctx, serviceName, metav1.GetOptions{})
framework.ExpectNoError(err)

translatedServiceName := translate.SingleNamespaceHostName(serviceName, serviceNamespace, translate.VClusterName)

ginkgo.By("Verify Service exists in Host Cluster")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed this is only a check about existence. But is this sufficient? I'd test also the content of the objects. E.g. the presence of the input values from above:

				Ports: []corev1.ServicePort{
				{
					Name:       "custom-port",
					Port:       8080,
					Protocol:   corev1.ProtocolTCP,
					TargetPort: intstr.FromInt(5000),
				},
			},

This also applies to the endpoint object.

_, err = f.HostClient.CoreV1().Services(f.VClusterNamespace).Get(ctx, translatedServiceName, metav1.GetOptions{})
framework.ExpectNoError(err)

ginkgo.By("Verify Endpoint exists in Host Cluster")
_, err = f.HostClient.CoreV1().Endpoints(f.VClusterNamespace).Get(ctx, translatedServiceName, metav1.GetOptions{})
framework.ExpectNoError(err)

})
})
})

func testMapping(ctx context.Context, fromClient kubernetes.Interface, fromNamespace, fromName string, toClient kubernetes.Interface, toNamespace, toName string, checkEndpoints bool) {
Expand Down
Loading