Skip to content

Commit

Permalink
chore(tests): add logs in e2e tests
Browse files Browse the repository at this point in the history
  • Loading branch information
pmalek committed Apr 30, 2024
1 parent 9bcdabd commit e06832f
Show file tree
Hide file tree
Showing 4 changed files with 360 additions and 30 deletions.
1 change: 1 addition & 0 deletions config/manager/manager.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ metadata:
namespace: system
labels:
control-plane: controller-manager
app.kubernetes.io/name: gateway-operator
spec:
strategy:
type: Recreate
Expand Down
87 changes: 79 additions & 8 deletions test/e2e/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ var loggerOnce sync.Once
// When running with helm caller is responsible for cleaning up the environment.
func CreateEnvironment(t *testing.T, ctx context.Context, opts ...TestEnvOption) TestEnvironment {
t.Helper()

const (
waitTime = 1 * time.Minute
)

var opt testEnvOptions
for _, o := range opts {
o(&opt)
Expand Down Expand Up @@ -230,7 +235,7 @@ func CreateEnvironment(t *testing.T, ctx context.Context, opts ...TestEnvOption)
require.NoError(t, clusters.KustomizeDeployForCluster(ctx, env.Cluster(), kustomizeDir.Tests(), "--server-side"))

t.Log("waiting for operator deployment to complete")
require.NoError(t, waitForOperatorDeployment(ctx, "kong-system", clients.K8sClient))
require.NoError(t, waitForOperatorDeployment(t, ctx, "kong-system", clients.K8sClient, waitTime))

t.Log("waiting for operator webhook service to be connective")
require.Eventually(t, waitForOperatorWebhookEventually(t, ctx, clients.K8sClient),
Expand Down Expand Up @@ -280,52 +285,118 @@ func cleanupEnvironment(t *testing.T, ctx context.Context, env environments.Envi

type deploymentAssertOptions func(*appsv1.Deployment) bool

func deploymentAssertConditions(conds ...appsv1.DeploymentCondition) deploymentAssertOptions {
func deploymentAssertConditions(t *testing.T, conds ...appsv1.DeploymentCondition) deploymentAssertOptions {
t.Helper()

return func(deployment *appsv1.Deployment) bool {
return lo.EveryBy(conds, func(cond appsv1.DeploymentCondition) bool {
return lo.ContainsBy(deployment.Status.Conditions, func(c appsv1.DeploymentCondition) bool {
if !lo.ContainsBy(deployment.Status.Conditions, func(c appsv1.DeploymentCondition) bool {
return c.Type == cond.Type &&
c.Status == cond.Status &&
c.Reason == cond.Reason
})
}) {
t.Logf("Deployment %s/%s does not have condition %#v", deployment.Namespace, deployment.Name, cond)
t.Logf("Deployment %s/%s current status: %#v", deployment.Namespace, deployment.Name, deployment.Status)
return false
}
return true
})
}
}

func waitForOperatorDeployment(ctx context.Context, ns string, k8sClient *kubernetes.Clientset, opts ...deploymentAssertOptions) error {
outer:
func waitForOperatorDeployment(
t *testing.T,
ctx context.Context,
ns string,
k8sClient *kubernetes.Clientset,
waitTime time.Duration,
opts ...deploymentAssertOptions,
) error {
t.Helper()

timer := time.NewTimer(waitTime)
defer timer.Stop()
pollTimer := time.NewTicker(time.Second)
defer pollTimer.Stop()

for {
select {
case <-timer.C:
logOperatorPodLogs(t, ctx, k8sClient, ns)
return fmt.Errorf("timed out waiting for operator deployment in namespace %s", ns)
case <-ctx.Done():
logOperatorPodLogs(t, context.Background(), k8sClient, ns)
return ctx.Err()
default:
case <-pollTimer.C:
listOpts := metav1.ListOptions{
// NOTE: This is a common label used by:
// - kustomize https://github.com/Kong/gateway-operator/blob/f98ef9358078ac100e143ab677a9ca836d0222a0/config/manager/manager.yaml#L15
// - helm https://github.com/Kong/charts/blob/4968b34ae7c252ab056b37cc137eaeb7a071e101/charts/gateway-operator/templates/deployment.yaml#L5-L6
//
// As long as kustomize is used for tests let's use this label selector.
LabelSelector: "app.kubernetes.io/name=gateway-operator",
}
deploymentList, err := k8sClient.AppsV1().Deployments(ns).List(ctx, listOpts)
if err != nil {
return err
}
if len(deploymentList.Items) == 0 {
t.Logf("No operator deployment found in namespace %s", ns)
continue
}

deployment := &deploymentList.Items[0]

if deployment.Status.AvailableReplicas <= 0 {
t.Logf("Deployment %s/%s has no AvailableReplicas", ns, deployment.Name)
continue
}

for _, opt := range opts {
if !opt(deployment) {
continue outer
continue
}
}
return nil
}
}
}

func logOperatorPodLogs(t *testing.T, ctx context.Context, k8sClient *kubernetes.Clientset, ns string) {
t.Helper()

pods, err := k8sClient.CoreV1().Pods(ns).List(ctx, metav1.ListOptions{
LabelSelector: "app.kubernetes.io/name=gateway-operator",
})
if err != nil {
t.Logf("Failed to list operator pods in namespace %s: %v", ns, err)
return
}

if len(pods.Items) == 0 {
t.Logf("No operator pod found in namespace %s", ns)
return
}

result := k8sClient.CoreV1().Pods(ns).GetLogs(pods.Items[0].Name, &corev1.PodLogOptions{
Container: "manager",
InsecureSkipTLSVerifyBackend: true,
}).Do(ctx)

if result.Error() != nil {
t.Logf("Failed to get logs from operator pod %s/%s: %v", ns, pods.Items[0].Name, result.Error())
return
}

b, err := result.Raw()
if err != nil {
t.Logf("Failed to read logs from operator pod %s/%s: %v", ns, pods.Items[0].Name, err)
return
}

t.Logf("Operator pod logs:\n%s", string(b))
}

func waitForOperatorWebhookEventually(t *testing.T, ctx context.Context, k8sClient *kubernetes.Clientset) func() bool {
return func() bool {
if err := waitForOperatorWebhook(ctx, k8sClient); err != nil {
Expand Down
Loading

0 comments on commit e06832f

Please sign in to comment.