Skip to content

Add Python Kafka sidecar delivery E2E test - #4111

Merged
knative-prow[bot] merged 6 commits into
knative:mainfrom
aliok:test-kafka-python-delivery
Oct 30, 2026
Merged

knative-prow[bot] merged 6 commits into
knative:mainfrom
aliok:test-kafka-python-delivery

Conversation

@aliok

@aliok aliok commented Oct 27, 2026

Copy link
Copy Markdown
Member

Changes

  • 🎁 Add an integration test proving the Kafka runtime sidecar delivers to Python end to end: a plain cloudevents Python function, built and deployed through func on the keda deployer, receives Kafka records via the injected sidecar as CloudEvents over HTTP — the function itself contains no Kafka code.
  • 🎁 Assert real delivery, not just object creation: the test produces a record to the broker, waits for the Python function to log receipt, and confirms the consumer group drains to lag 0 (the sidecar commits the offset only on a 2xx).

The sidecar is language-agnostic by design, but so far only Go was validated end to end. Unlike the existing TestInt_KafkaScaling — which pins a prebuilt image and only checks the created KEDA objects — this exercises the real build + deploy pipeline for Python and asserts delivery. No template or runtime changes are needed; the stock python/cloudevents template is already a plain CloudEvents-over-HTTP receiver.

It runs against the same Strimzi broker the Kafka integration job already provisions and is picked up by the existing test-integration-kafka target, so no CI changes are needed.

/kind enhancement

Release Note


Docs


The Kafka runtime sidecar is language-agnostic by design, but only Go
was validated end to end. Add an integration test that proves Python: a
plain cloudevents Python function, built and deployed through func on
the keda deployer, receives Kafka records via the injected sidecar as
CloudEvents over HTTP -- the function itself contains no Kafka code.

Unlike the existing TestInt_KafkaScaling, which pins a prebuilt image
and only checks the created KEDA objects, this exercises the real
build+deploy pipeline and asserts delivery: it produces a record to the
broker, waits for the function to log receipt, and confirms the consumer
group drains to lag 0 (the sidecar commits the offset only on a 2xx).

The test runs against the same Strimzi broker the Kafka integration job
already provisions and is picked up by the existing
test-integration-kafka target, so no CI changes are needed.
@knative-prow knative-prow Bot added the kind/enhancement Feature additions or improvements to existing label Oct 27, 2026
@knative-prow

knative-prow Bot commented Oct 27, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: aliok

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@knative-prow knative-prow Bot added approved 🤖 PR has been approved by an approver from all required OWNERS files. size/L 🤖 PR changes 100-499 lines, ignoring generated files. labels Oct 27, 2026
aliok added 2 commits October 27, 2026 12:58
The delivery check only asserted the function logged "Request Received",
which proves a request reached the function but not that it was our
record with the payload intact. Produce a record carrying a unique
per-run token and instrument the scaffolded handler to echo the received
data, then assert that token appears in the function logs.

Delivery of the specific record (delivered and decoded intact) is now
verified, alongside the existing lag-0 check that independently confirms
the function acked it.
The Python Kafka delivery test instrumented the scaffolded handler in
place with a strings.Replace on func.py, anchored to a template line.
That coupled the test to the template's exact source and hid the only
part that matters -- the echo handler -- inside Go string surgery.

Replace it with a committed handler fixture under testdata that is
copied over the scaffold after func create. func create still provides
func.yaml and the dependencies; only the handler is swapped. The
fixture is a reviewable Python file and the test no longer breaks when
the template's wording changes.
aliok added 2 commits October 27, 2026 14:34
func create derives the function name from the target directory's
basename. t.TempDir() returns a path whose leaf segment is numeric
(e.g. ".../002"), which fails function-name validation (a name must
start with an alphabetic character). Nest the function in a validly
named subdirectory so create succeeds.
The Kafka integration job runs a slim cluster with serving (and thus
the Contour ingress) disabled to save CPU. Pushing a built function
image to registry.localtest.me only works through that ingress, so the
Python delivery test's build+push failed with a connection reset -- the
first Kafka test to actually build and push, since the scaling test
pins a prebuilt image.

Expose the registry pod's hostPort (5000) to the host and push to
localhost:5000 instead. containerd treats localhost as insecure, and
the node already pulls it through the same hostPort the containerd
mirror uses, so no ingress is needed. This is the canonical
kind-local-registry pattern.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Failed Kafka tool pods are treated as successful, masking producer and consumer-group command failures instead of immediately reporting errors and pod logs.

1 open issue
What changed in this PR

Adds end-to-end coverage for Kafka sidecar delivery to Python functions through the real func build and KEDA deployment pipeline.

Changes:

  • Adds a Python CloudEvents handler fixture that logs received payloads.
  • Adds an integration test that produces a unique Kafka record, checks function logs, and verifies consumer-group lag reaches zero.
  • Exposes the cluster registry on localhost port 5000 for builds on clusters without ingress.
File Description
pkg/​keda/​testdata/​kafka_python_delivery/​func.py Logs received payloads and returns a response CloudEvent.
pkg/​keda/​kafka_delivery_int_test.go Tests Python delivery and offset commits using the Strimzi broker.
hack/​cluster.sh Maps registry port 5000 to IPv4 and IPv6 loopback addresses.

Review effort: Balanced

Comment thread pkg/keda/kafka_delivery_int_test.go Resolved
runKafkaToolPod waited for the pod to reach either Succeeded or Failed
and then returned its logs regardless of which. A failed producer pod
was therefore treated as success and only surfaced minutes later as a
misleading "function did not log" delivery timeout; a failed
consumer-group command was parsed as a lag observation and reported as
a false "did not drain to lag 0".

Capture the terminal phase and fail the test immediately with the pod
logs when it is not Succeeded, so the real failure is reported at its
source.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

The cleanup command passes --namespace without the required function name and discards the resulting error, so func delete removes nothing and cleanup relies entirely on namespace deletion.

No open issues 🎉

1 previously missed issue

In code that hasn't changed since last review

Low severity Fix cleanup deletion to pass the required function name

pkg/​keda/​kafka_delivery_int_test.go:166

This cleanup command is always rejected: newDeleteConfig in cmd/delete.go requires a positional function name whenever --namespace is supplied. Because the error is discarded, func delete never removes anything, leaving cleanup entirely to namespace deletion. Omit --namespace so deletion uses the namespace and deployer recorded in the local func.yaml.

1 resolved since last review

Review effort: Balanced

@lkingland

Copy link
Copy Markdown
Member

Looks good, thanks @aliok. A genuine end-to-end delivery check (per-run token in the function logs, plus consumer-group lag draining to 0).

One small question, non-blocking: the new host port 5000 mapping in hack/cluster.sh is unconditional, and macOS binds TCP 5000 for AirPlay Receiver by default, so local hack/cluster.sh runs on a Mac may now hit a port-in-use error from kind. Would it make sense to gate it (e.g. behind FUNC_CLUSTER_SERVING=false, or a flag the Kafka job sets), either here or as a follow-up?

/lgtm

@knative-prow knative-prow Bot added the lgtm 🤖 PR is ready to be merged. label Oct 30, 2026
@knative-prow
knative-prow Bot merged commit f96dd09 into knative:main Oct 30, 2026
45 checks passed
@aliok
aliok deleted the test-kafka-python-delivery branch October 30, 2026 12:25
knative-prow Bot pushed a commit that referenced this pull request Oct 30, 2026
The slim Kafka integration cluster skips serving, so it has no Contour
ingress and a host-side `func deploy` build+push cannot reach the
in-cluster registry through registry.localtest.me. #4111 exposed the
registry by mapping host port 5000 to the node unconditionally, for
every cluster hack/cluster.sh creates.

On macOS the AirPlay Receiver listens on *:5000, so that unconditional
mapping makes `kind create cluster` fail to bind -- breaking cluster
creation for every developer on a Mac, not just the Kafka job. CI runs
on Linux, so it never caught this.

Map the registry to the host only on serving-less clusters (full
clusters push through the ingress and need no host mapping), and use
host port 5001 to dodge AirPlay. The node still serves the registry on
container port 5000; a containerd mirror resolves localhost:5001 to it
so pushed images -- now tagged localhost:5001 -- can be pulled. Update
the Python delivery test to push to localhost:5001.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved 🤖 PR has been approved by an approver from all required OWNERS files. kind/enhancement Feature additions or improvements to existing lgtm 🤖 PR is ready to be merged. size/L 🤖 PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants