-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Integration Tests #2617
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Integration Tests #2617
Conversation
For end-to-end we could look into https://playwright.dev/. It does not have issues with flakiness since tests are running next to app code, not remote communications and so on as with Selenium. |
Thanks for the pointer :) There also is https://github.com/mxschmitt/playwright-go, which uses Playwright but could be integrated into this framework. That said, I'd hope we won't need those kinds of tests in the foreseeable future, due to their complexity and brittlenes. The more we can cover using other means, the better. |
3b8b428
to
655feae
Compare
This way it's accessible from packages other than supervisor, e.g. future integration tests.
UUIDv4 can start with a number also, not just a letter.
655feae
to
af9e07b
Compare
af9e07b
to
5b24280
Compare
Another way @akosyakov and I explored back when we tried to make the integration tests work: https://github.com/gitpod-com/gitpod/pull/3757/files#diff-844058ea0e3f3ad9600eaa77711088f83e185cc2d9b9b66550198930b759d067 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm really looking forward to writing tests with this! Looks really nice from the outside.
(comment are questions/nits only)
} | ||
client, err := kubernetes.NewForConfig(restConfig) | ||
if err != nil { | ||
t.Fatal("cannot connecto Kubernetes", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
connect to
} | ||
|
||
// CreateBucket reads the daemon's config, and creates a bucket | ||
func (*DaemonAgent) CreateBucket(args *api.CreateBucketRequest, resp *api.CreateBucketResponse) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to clarify: The value of this test lies in the fact that we run the same functionality in the same context.
But why not talk to ws-deamon
directly instead? And: What is the benefit value in using agents for this compared to accessing the service directly? (Injecting agents into workspaces is another story altogether, there it's just awesome to have a functionality like this!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, that's the value of this test.
The trade-off/decision is exactly the one you outline: either embed the testing functionality into the components and make them available their gRPC interface, or we keep this logic out of the components and use agents instead. In this particular case I'm really really on the fence, because arguably trying to create a bucket is a self-test that ws-daemon could certainly run at start-up. Maybe this use of agents just isn't a good one.
My reasoning was that we have agents already, might as well use them rather than extend other components. I reckon there are other cases which are not as close a call, e.g. meddling with the on-disk state of ws-daemon. Certainly this could be done in a TestService
, but it would be super intrusive to the component and spread the test out across several components (test and ws-daemon).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this particular case I'm really really on the fenc
I reckon there are other cases which are not as close a call,
Thank you for elaborating; completely agree!
This PR adds an integration test framework and a first set of actual tests.
The star of the show is an integration framework that integrates with Go unit tests. It provides
Because integration tests are Go unit tests, they can be compiled to a binary and shipped in a Docker image. There is excellent tool support and loads of examples.
Access to Gitpod's internal API
Integration tests may need to interact with any component of Gitpod directly. The test framework can access
For all API access, we create a port-forward using the Kubernetes API and produce a client that access the API. For the Gitpod server, we'll create a fully privileged API token for the first non-builtin user we find. If there is no such user the test fails (see open points).
Examples:
gitpod/test/tests/examples/server_test.go
Lines 16 to 29 in 3b8b428
gitpod/test/tests/examples/wsmanager_test.go
Lines 16 to 27 in 3b8b428
Access to the database
Inspecting or even modifying is yet another common task. The integration test framework provides easy database access. To this end, it inspects the
db
service and port-forwards to the backing pod (the same thatkubectl port-forward service/db
would do). It then grabs the DB password from the corresponding secret and opens asql.DB
connection.Examples:
gitpod/test/tests/examples/db_test.go
Lines 13 to 35 in 3b8b428
Easy start and observation of workspaces
Starting workspaces and interacting with them is a common task. The integration test framework provides a simple API for waiting until a workspace is running.
There are two main ways how a workspace can be started:
When in doubt the ws-manager route is preferable, because it requires fewer external moving parts.
Examples:
gitpod/test/tests/examples/server_test.go
Lines 38 to 45 in 3b8b428
gitpod/test/tests/workspace/tasks_test.go
Lines 62 to 64 in 3b8b428
Instrumentation of existing components
To interact within the context of existing pods, the integration test framework supports "agents". Agents are tiny Go programs which are compiled on-demand (can also be precompiled and added to the path), uploaded to the pod, executed and port-fowarded to the test.
This mechanism allows for the inspection of component configuration (e.g. checking if ws-daemon can create a bucket with its configuration) and workspaces.
Example:
gitpod/test/tests/workspace/tasks_test.go
Lines 91 to 103 in 3b8b428
The example above will look for
gitpod-integration-test-workspace-agent
in the$PATH
or try to compileworkspace_agent/main.go
. Those agents are expected to communicate using net/rpc, and there's a convenience function available for building them.Example:
https://github.com/gitpod-io/gitpod/blob/cw/integration-tests/test/tests/workspace/workspace_agent/main.go#L14-L34
How can I run tests?
The integration tests are built, not run, as part of the
components:all
package, and result in a Docker image. This Docker image can be-kubeconfig in-cluster
docker run --rm -it -v $HOME/.kube/config:/config eu.gcr.io/gitpod-core-dev/build/integration-tests:cw-integration-tests.18 -test.v -kubeconfig /config
Because the integration tests are Go unit tests, you can also run them from the command line, e.g.:
or from within the editor:

Open Points
it.API().DB()
functionality