[Jens Neuse](/content/people/jens-neuse/index.html)  
CEO & Co-Founder at WunderGraph  
January 24, 2024·19min read  
Last updated on October 22, 2025

[Cosmo Router](/content/cosmo/router/index.html) is a GraphQL Gateway that allows you to combine multiple GraphQL APIs into a unified Graph using [GraphQL Federation](/content/cosmo/federation/index.html). But that's really just the tip of the iceberg when it comes to the complexity of the system.

## State of GraphQL Federation 2026
How are teams governing schema changes, handling production traffic, and measuring Federation success? Share your experience and get early access to the full report. For every valid survey completed, we'll donate $30 to [UNICEF](https://www.unicef.org/).

When we say "Federation", we mean that [Cosmo Router](/content/cosmo/router/index.html) integrates Subgraphs, which are GraphQL APIs that are managed by a separate team. Subgraphs can be written in any language, they can support Requests over HTTP and Subscriptions over WebSockets via SSE. Clients can make HTTP requests to the Cosmo Router or initiate Subscriptions over WebSockets or SSE, with multiple protocols and transports supported. In addition, we've recently added support for [Event-Driven Federated Subscriptions](/content/blog/announcing_edfs_event_driven_federated_subscriptions/index.html), which allows you to drive Subscriptions from events in your system.

As you can imagine, this is a lot of moving parts, and we need to make sure that everything works together seamlessly. But how do we efficiently test such a complex system?

In this article, we'll show you how we test the Cosmo Router using advanced techniques in GraphQL Federation, including the utilization of subgraphs and subscriptions, to ensure seamless end-to-end functionality, correctness and superior system performance.

## What is GraphQL & GraphQL Federation?
GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. It provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.

GraphQL Federation is a set of specifications that allow you to build a single GraphQL API from multiple GraphQL APIs ([Subgraphs](https://cosmo-docs.wundergraph.com/cli/subgraph)). It allows you to build a single unified Graph that can be queried by clients using a single GraphQL endpoint, while each Subgraph can be managed by a separate team and written in any language.

## What is Cosmo Router?
Cosmo Router is an Open Source GraphQL API Gateway that implements the GraphQL Federation specification. It handles client requests, plans the execution of those requests across multiple Subgraphs, and then executes those requests in parallel, combining the results into a single response.

## What is Cosmo?
Cosmo is a complete GraphQL Platform that includes Cosmo Router, [Cosmo CLI](https://cosmo-docs.wundergraph.com/cli/intro), and [Cosmo Studio](https://cosmo-docs.wundergraph.com/studio/intro). Together, these tools allow you to build, deploy, and manage your Federated GraphQL APIs and Subgraphs. Cosmo is Open Source and available on [GitHub](https://github.com/wundergraph). You can self-host Cosmo, e.g. if you have to comply with strict data privacy regulations, or you can use our Soc2 compliant SaaS offering, [Cosmo Cloud](https://cosmo.wundergraph.com/).

## Integration Testing challenges for GraphQL Federation
Integration testing is a type of testing that tests the integration between different components of a system. In our case, we want to test the integration between the Cosmo Router, the Subgraphs, Event-Driven Federated Subscriptions, and the various client protocols and transports.

Let's start by lising some of the criteria that is important to us when we set out to build our integration testing framework:

- Tests should be fast
- Tests should be easy to write
- Tests should be able to run in parallel
- Tests must run in isolation
- Tests should be able to run in a CI/CD environment (e.g. GitHub Actions)
- Tests should be able to run in a local development environment
- Tests should be deterministic and reproducible
- Tests should be easy to debug
- Tests must not be flaky at all

### We need to be able to...
- Mock authentication and authorization
- Test for race conditions
- Configure authentication and authorization per test
- Test custom modules (Router extensions, e.g. custom middleware)
- Test Subscriptions (both over WebSockets and SSE) reliably
- Test Header propagation
- Test the execution plan cache
- Test input validation
- Test advanced request tracing (ART)
- Test when Subgraphs return valid GraphQL responses, but with errors
- Test when Subgraphs return HTTP errors
- Test when Subgraphs return nothing / timeout
- Test Persisted Operation / Persisted Queries
- Test Singleflight / Origin Request Deduplication
- Test different WebSocket protocols and transports
- Test different SSE protocols and transports
- Test WebSockets with Epoll/Kqueue (Linux/MacOS) and with regular polling
- Test for memory leaks and other resource leaks when using Subscriptions
- Test for abnormal behavior when using Subscriptions
- And much more...

As you can see, there are a lot of things to consider when testing a complex system like Cosmo Router. Let's break down how we've built our integration testing framework to meet these requirements.

## Integration Testing Cosmo Router, the Open Source GraphQL Federation Gateway

### How to achieve fast and parallel end-to-end tests for Distributed Systems
Let's tackle the first few requirement to set the foundation for all other requirements. We want our tests to be fast, deterministic, reproducible, and not flaky. This might seem trivial, but it was quite challenging to achieve for a distributed system like Cosmo Router.

In addition, we want our tests to be easy to debug, which means that we would need to run all services in a single process.

We also learned that it's important to run our tests in isolation. We're using [GraphQL Subscriptions](https://cosmo-docs.wundergraph.com/router/subscriptions), a mechanism that allows clients to subscribe to events in the system. If you're looking to test Subscriptions in a deterministic way, you will realize that you need to run these tests in isolation or they might interfere with each other.

As we wanted to make tests as easy to write as possible, we decided to create a test framework that abstracts away all the complexity of setting up an isolated environment, including Subgraphs, Event-Driven Federated Subscriptions using [NATS](https://cosmo-docs.wundergraph.com/federation/event-driven-federated-subscriptions/nats), and the Cosmo Router itself.

Luckily, we can use [gqlgen](https://gqlgen.com/) to implement our Subgraphs and run them in the same process as our tests. This means that we can debug into our Subgraphs if necessary. NATS is also written in Go, so we can use the test server provided by NATS, as well as the NATS client, to define Event-Driven Federated Subscriptions tests. Lastly, Cosmo Router is also written in Go, so we can run everything together in a single process and debug all components if necessary.

### Achieving parallelism with complex tests in Go
First, when you want to run tests in parallel in Go, you need to call `t.Parallel()` at the beginning of your test function. The Go testing framework runs all tests in parallel that call `t.Parallel()`. All other tests are run sequentially.

But to achieve parallelism without flakiness, we need to ensure that we're not accidentally trying to use the same port twice. We need to get two free ports per test, one for the Router and one for NATS. All Subgraphs are running using the `httptest` package, which automatically assigns a free port.

Initially, getting two free ports in parallel tests was sometimes flaky, so we had to implement a simple solution to prevent multiple tests running in parallel from using the same port.

### Key takeaways for testing distributed systems
1. You should be able to start and clean up all components of the system in a short amount of time
2. We need to be able to modify / mock / override the behavior of all components
3. Our system needs to be event driven and easy to debug
4. Our tests need to be deterministic and reproducible

## Conclusion
This article gave you an overview of how we're testing a distributed system like the Cosmo Router. I hope that this article gave you some ideas on how to test your own distributed systems, how to improve the developer experience of your own tests, and how to make your tests more deterministic and reproducible.
