Contributing to Kzmlabs Flink StateFun
May 11, 2026 · View on GitHub
Thanks for your interest in contributing! This project is an actively maintained continuation of the Stateful Functions framework, updated for Flink 2.2.0 and Java 21.
Ways to Contribute
- Report bugs — Open an issue with a minimal reproducer, Flink/Java versions, and stack trace
- Request features — Open an issue describing the use case and desired behavior
- Submit pull requests — Bug fixes, new ingress/egress connectors, documentation, tests
- Improve documentation — README, inline Javadoc, examples
- Answer questions — Help others in issues and discussions
Development Setup
Prerequisites
- Java 21 (
JAVA_HOMEset) - Maven 3.5+
- Docker (for K8s E2E tests)
Build
# Full build with all tests (including K8s E2E)
mvn install -B
# Skip K8s E2E for faster iteration
mvn install -Dskip.k8s.e2e -B
# Skip all tests
mvn install -DskipTests -B
Code Style
Google Java Format (2-space indent) is enforced by spotless-maven-plugin. Before committing:
mvn spotless:apply
CI will fail builds that do not conform.
Testing Conventions
The project uses JUnit 5 Jupiter with AssertJ for fluent assertions. Hamcrest is also available for legacy tests. Match the style of the surrounding tests in the module you are touching.
Test method naming
Use plain camelCase, no underscores. Make the name a short statement of the property under test. The class name (SomethingTest) already provides the subject; the method name describes the behavior:
// Good — matches the project's existing 300+ tests
@Test
void routesArnKeyedRecordsToConfiguredTargets() { ... }
@Test
void throwsWhenStreamKeyIsNotInRoutingMap() { ... }
// Avoid — snake_case is inconsistent with the rest of the codebase
@Test
void deserialize_withArnAsStream_routesToConfiguredTargets() { ... }
Do not use @DisplayName. The test method name is the documentation; relying on annotations splits the description from the code that defines it.
Test structure
- Arrange / Act / Assert separation visible in each test.
- One concept per test (
@ParameterizedTestfor the same property across multiple inputs). - Use
@BeforeEachto set up shared state; tests that need a different setup shadow with a local variable instead of mutating the shared field. - Real types over mocks where practical. Reach for mocks only when the dependency is genuinely external (network, filesystem) or has a complex lifecycle.
- Helpers (record builders, config builders) as
private staticmethods at the bottom of the test class.
Documentation
Use Javadoc on tests only when the why is non-obvious — e.g. "regression guard for the Flink 2.x ARN-vs-short-name contract", not "tests deserialization". The reader can see what the test does from the assertions; the comment should add context the assertions can't.
Coverage guidance
The project tracks coverage via JaCoCo + Codecov (flags unittests and e2e). New behavior should be covered. Don't chase coverage percentages on glue/getter/builder code; prioritize critical-runtime paths (binders, state access, message dispatch) and error paths (boundary conditions, malformed input, transient failures). See issue #149 for the rolling investment plan.
Pull Request Process
- Fork the repository and create a feature branch from
release - Make focused, well-scoped commits with clear messages
- Add or update tests for behavior changes (JUnit Jupiter 5.11)
- Run
mvn spotless:applybefore committing - Ensure
mvn install -Dskip.k8s.e2e -Bpasses locally - Open a PR against the
releasebranch - A maintainer will review; CI must pass before merge
Commit Messages
- Use imperative mood ("Add Kafka headers support", not "Added")
- First line ≤ 72 characters
- Reference issue numbers where relevant (
Fixes #123)
Reporting Bugs
Include:
- Kzmlabs StateFun version
- Flink version (should be 2.2.x)
- Java version (should be 21)
- OS and architecture
- Minimal reproducer (code + config)
- Full stack trace and relevant logs
License
By contributing, you agree your contributions will be licensed under the Apache License 2.0.