e2e-framework: end-to-end Kubernetes testing that stays inside go test
A Go framework for end-to-end testing of components running in Kubernetes clusters.
At a glance
- What is it?
- kubernetes-sigs/e2e-framework is a Go library for testing components running in Kubernetes clusters, built on the native testing API so suites are ordinary go test functions with features, assessments and label based filtering. It suits component maintainers who need a real cluster in CI, and it is the wrong tool for anything that does not need one.
- Who is it for?
- Adopt e2e-framework if you maintain a Kubernetes component and want its end-to-end suite to run as plain go test functions, with cluster creation and teardown expressed as environment functions and suites filtered by label in CI. Do not adopt it for unit tests, for testing something that does not need a cluster, or for a team that wants a declarative, non-Go test authoring model, because the framework is a Go API, not a spec format.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
End-to-end tests as ordinary go test functions
Kubernetes component testing has a reputation for enormous, bespoke suites that need their own runner. The stated primary goal of this project is the opposite: provide a go test able framework that uses the native Go testing API to define end-to-end test suites for Kubernetes components.
The additional goals spell out what that means in practice. A sensible programmatic API to compose tests, use of Go's testing API to compose suites, packages that are easy to consume programmatically, a collection of helper functions that abstract Client-Go functionality, and reliance on built-in Go test features to select and filter which tests run during execution.
That last point is the practical payoff. If your suite is a normal Go test binary, then everything the Go toolchain already does applies: `go test -run`, parallel packages, JSON output, IDE integration, coverage tooling. You do not need a separate concept of an end-to-end test binary.
The module path is sigs.k8s.io/e2e-framework, so it lives under the Kubernetes SIG namespace and inherits the community conventions that come with it, including a code of conduct, security contacts and a release process document. The additional goals are documented in more detail in the design document at docs/design/README.md.
env.Environment wraps the cluster lifecycle around TestMain
The integration point is TestMain, the standard Go entry point for a package's tests. The framework exposes an env.Environment value that you set up once per package, and the environment functions do the cluster work before and after the tests run.
Here is the shape of it, trimmed to the setup half:
func TestMain(m *testing.M) {
testenv = env.New()
kindClusterName := envconf.RandomName("my-cluster", 16)
namespace := envconf.RandomName("myns", 16)
testenv.Setup(
envfuncs.CreateCluster(kind.NewProvider(), kindClusterName),
envfuncs.CreateNamespace(namespace),
)
os.Exit(testenv.Run(m))
}Two things are worth reading closely. The provider is passed in, kind.NewProvider() in this case, so the cluster backend is a parameter rather than a global setting. And the teardown half mirrors it: the same environment object takes a Finish call with envfuncs.DeleteNamespace and envfuncs.DestroyCluster, and the package tests are launched with os.Exit(testenv.Run(m)).
The names are randomised with envconf.RandomName, a suffix length of 16, for the cluster and for the namespace. In CI where several jobs share a machine, predictable resource names are how suites collide with each other and fail in ways that look like product bugs.
Adding the two Go modules is the whole installation story, and it takes two lines.
Two modules, no plugin, no code generation
The Go package is designed to be integrated directly in your test. You update your project to pull the desired modules:
go get sigs.k8s.io/e2e-framework/pkg/env
go get sigs.k8s.io/e2e-framework/klientTwo modules, env for the environment and lifecycle handling and klient for the client side. That is a deliberately small surface compared with frameworks that generate test scaffolding or require a config file describing environments.
The reason for two separate modules is that you often need only one of them. A team that already owns its cluster lifecycle and only wants the client helpers takes klient alone. A team that wants the whole flow takes both. The environment functions themselves come from the envfuncs package, which supplies the predefined operations such as creating a cluster and creating a namespace, and the same package supports custom environment functions when the predefined set is not enough, as the examples directory demonstrates with a custom_env_funcs example.
The dependencies are ordinary Kubernetes ones: k8s.io/api, k8s.io/apimachinery, k8s.io/client-go and k8s.io/component-base at v0.35.3, controller-runtime at v0.23.3, klog for logging, sigs.k8s.io/yaml, and gexe, which is the command execution helper the project uses to drive external tools such as cluster tooling.
Features and assessments are the unit of composition
Inside a test function, the framework offers a feature builder. A feature has a name, optional labels, and assessments, which are functions that receive a context, the testing handle and the environment config, and return a context.
The documented example builds two features, one counting pods in kube-system and one asserting that namespaces exist, then hands both to the environment:
testenv.Test(t, f1, f2)The assessments do the actual work with the client, listing pods or namespaces through cfg.Client().Resources(...).List and failing the test when the expectation is not met. The returned context is what allows a later assessment to see what an earlier one put there.
Why go through features instead of calling the client directly in a test body? Because features are individually named and labelled. Labels are the mechanism that lets CI select a subset of a large suite without rewriting it, and the project lists parallel features and fail fast behaviour among its examples, so both are first class concerns rather than afterthoughts.
The environment config, passed to each assessment, is where the client lives. It is also the seam where a different environment, a dry run, or a cluster in another context can be substituted without touching the assessment bodies.
Filtering runs through native go test flags
Because the framework leans on the Go testing API rather than replacing it, selection and filtering are expressed as test arguments rather than as a separate configuration language. The documented example runs every test in a package except those carrying a particular label:
go test ./package -args --skip-labels="type=ns-count"The flag syntax goes through the -args mechanism, which passes everything after it to the test binary itself. That means the label filter is registered by the framework as a flag on the test binary, so it composes with the standard Go flags instead of competing with them.
The labels are attached with a WithLabel call on the feature builder, as in the type=pod-count and type=ns-count examples in the README, so a label is a property of the feature rather than a separate declaration.
The practical effect is that a CI job can run a fast subset on every push and the whole suite on a schedule, without a second test tree and without a runner that has to be taught about labels. The cost is that you inherit Go's conventions, including the fact that flags after -args are not understood by go test itself and that the label vocabulary is maintained by convention in your code rather than in a central file.
Where the framework stops: it drives a cluster, it does not own your pipeline
The boundary of this project is easy to state and easy to get wrong. It is a framework for end-to-end testing of components running in Kubernetes clusters. It is not a deployment tool, not a CI system and not a cluster provisioner for production.
Several limits follow. The framework assumes a cluster is reachable and that the code under test has been built and loaded into it. Deciding which image tag to test, building it and pushing it to a registry remains your pipeline's job, and nothing in the framework makes that decision for you.
The environment functions do create and destroy clusters, using a provider such as kind, and the examples directory lists a range of choices: k3d, kwok, real_cluster, multi_cluster, kubeconfig_env and dry_run. The kwok example is worth a look for anyone whose component does not need real nodes, since kwok provides a simulated Kubernetes API rather than a real cluster. That is a different testing model, not just a cheaper one, and it will not catch node level behaviour.
A second limit is the version coupling. go.mod pins k8s.io/api, apimachinery, client-go and component-base to v0.35.3, and controller-runtime to v0.23.3, and the module itself requires go 1.25.7. If your product pins a different client-go line, adopting this framework means aligning those versions, which is where most of the friction in a Kubernetes dependency upgrade happens anyway.
Apache-2.0, SIG governance and a pre-1.0 version line
The licence is Apache-2.0 with the LICENSE file at the root, the same licence used across the Kubernetes project, so there is no commercial condition to negotiate beyond the standard terms. Because the code lives under a Kubernetes SIG namespace, the usual community machinery applies: CONTRIBUTING.md, an OWNERS file, SECURITY.md and SECURITY_CONTACTS, and the Kubernetes Code of Conduct. Maintainers are reachable through the sig-testing channel on the Kubernetes Slack workspace and a mailing list, and the repository has ADOPTERS.md for the providers and integrations it supports.
On versions, the module is still below 1.0. The releases listed are v0.5.0 on 2024-10-22, v0.6.0 on 2025-01-17 and v0.7.0 on 2026-04-21, and the repository is not archived with the last push on 2026-10-19. So the project is alive and shipping, but the version line has not yet settled, which is normal for a module in the SIG space and means you should pin an exact version in go.mod rather than tracking main.
The release process itself is documented in RELEASE.md and the Makefile carries the verification targets the project runs on itself, including a boilerplate header check, a go module linter and golangci-lint, plus an update-deps target that updates the main module and the separate module used by the examples directory. That last detail is a real operational cost: the examples live in their own go.mod, so a dependency bump touches two modules and has to be verified twice.
Editorial conclusion
Adopt e2e-framework if you maintain a Kubernetes component and want its end-to-end suite to run as plain go test functions, with cluster creation and teardown expressed as environment functions and suites filtered by label in CI. Do not adopt it for unit tests, for testing something that does not need a cluster, or for a team that wants a declarative, non-Go test authoring model, because the framework is a Go API, not a spec format. Before you commit, check that your toolchain meets the go 1.25.7 requirement in go.mod, confirm the client-go version you already depend on matches the v0.35.3 line the module expects, and read docs/design/README.md, since the architecture decisions are documented there rather than in the README.
Frequently asked questions
What is sigs.k8s.io/e2e-framework used for?
It is a Go framework for end-to-end testing of components running in Kubernetes clusters, using the native Go testing API so suites are ordinary go test functions. It provides a programmatic API to compose tests, helper functions that abstract Client-Go functionality, and support for selecting tests by label.
How do I install the e2e-framework Go modules?
Pull the two modules into your project with go get sigs.k8s.io/e2e-framework/pkg/env and go get sigs.k8s.io/e2e-framework/klient. The env module handles environment setup and teardown, while klient provides the client side helpers, and you can depend on either one separately.
How do I create a Kubernetes cluster for the e2e-framework tests?
In TestMain you build an env.Environment, then call testenv.Setup with environment functions such as envfuncs.CreateCluster(kind.NewProvider(), kindClusterName) and envfuncs.CreateNamespace, and tear it down with testenv.Finish before launching the tests with os.Exit(testenv.Run(m)).
Can I run only some e2e-framework tests?
Yes. Features are given labels with WithLabel, and the label filter is a flag on the test binary, so a run such as go test ./package -args --skip-labels="type=ns-count" executes everything except the features carrying that label.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/kubernetes-sigs-e2e-framework)Was this useful?