Skip to content

Commit 5f83ccd

Browse files
authored
Introduce integration tests (#929)
* Add test harness * Add sorting tests * Add filtering tests * Add columns tests * Update README * Add GHA action for integration tests * Check HTTP response code for sorting tests * Check HTTP response code for columns tests * Remove unnecessary comment * Move integration tests to tests/integration * Fix waitForSchema for group-less resources
1 parent 26d62fd commit 5f83ccd

26 files changed

+4949
-15
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: Integration tests
2+
3+
on:
4+
pull_request: {}
5+
push:
6+
branches:
7+
- master
8+
- release/*
9+
10+
jobs:
11+
ci:
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name : Checkout repository
15+
# https://github.com/actions/checkout/releases/tag/v4.1.1
16+
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
17+
18+
- name: Install Go
19+
# https://github.com/actions/setup-go/releases/tag/v5.0.0
20+
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
21+
with:
22+
go-version-file: 'go.mod'
23+
24+
- name: Set up Docker Buildx
25+
uses: docker/setup-buildx-action@v3
26+
27+
- name: Install k3d
28+
run: |
29+
curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | TAG=v5.8.3 bash
30+
31+
- name: Download dependencies
32+
run: go mod download
33+
34+
- name: Run integration tests
35+
run: make integration-tests
36+
env:
37+
INTEGRATION_TEST_ARGS: "-v -count=1"

Makefile

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
INTEGRATION_TEST_ARGS ?=
2+
INTEGRATION_TEST_DEBUG ?=
3+
4+
TEST_ARGS := $(INTEGRATION_TEST_ARGS)
5+
6+
ifeq ($(INTEGRATION_TEST_DEBUG),true)
7+
# we likely want longer timeout
8+
TEST_ARGS += -timeout=60m
9+
# verbose to see KUBECONFIG path and steve URL
10+
TEST_ARGS += -v
11+
endif
12+
113
build:
214
docker build -t steve .
315

@@ -13,5 +25,8 @@ run-host: build
1325
test:
1426
bash scripts/test.sh
1527

28+
integration-tests:
29+
@TEST_ARGS="$(TEST_ARGS)" ./scripts/integration-tests.sh
30+
1631
validate:
17-
bash scripts/validate.sh
32+
bash scripts/validate.sh

README.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -925,10 +925,8 @@ all requests in the table test.
925925
926926
#### Integration tests
927927
928-
Integration tests for the steve API are located among the [rancher integration
929-
tests](ihttps://github.com/rancher/rancher/tree/release/v2.8/tests/v2/integration/steveapi).
930-
See the documentation included there for running the tests and using them to
931-
generate API documentation.
928+
New integration tests for the steve API are located in the `tests/` directory.
929+
Refer to [tests/integration/README.md](./tests/integration/README.md) for documentation on running and adding these tests.
932930
933931
## Running Tests
934932

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ require (
4444
go.yaml.in/yaml/v3 v3.0.4
4545
golang.org/x/sync v0.17.0
4646
google.golang.org/protobuf v1.36.9
47+
gopkg.in/yaml.v3 v3.0.1
4748
k8s.io/api v0.34.1
4849
k8s.io/apiextensions-apiserver v0.34.1
4950
k8s.io/apimachinery v0.34.1
@@ -144,7 +145,6 @@ require (
144145
gopkg.in/inf.v0 v0.9.1 // indirect
145146
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
146147
gopkg.in/yaml.v2 v2.4.0 // indirect
147-
gopkg.in/yaml.v3 v3.0.1 // indirect
148148
k8s.io/kms v0.34.1 // indirect
149149
modernc.org/libc v1.66.10 // indirect
150150
modernc.org/mathutil v1.7.1 // indirect

pkg/stores/sqlproxy/proxy_store.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ var (
6565
paramScheme = runtime.NewScheme()
6666
paramCodec = runtime.NewParameterCodec(paramScheme)
6767
// Please keep the gvkKey entries in alphabetical order, on a field-by-field basis
68-
typeSpecificIndexedFields = map[string][][]string{
68+
TypeSpecificIndexedFields = map[string][][]string{
6969
gvkKey("", "v1", "Event"): {
7070
{"_type"},
7171
{"involvedObject", "kind"},
@@ -498,7 +498,7 @@ func (s *Store) initializeNamespaceCache() error {
498498
func getFieldForGVK(gvk schema.GroupVersionKind) [][]string {
499499
fields := [][]string{}
500500
fields = append(fields, commonIndexFields...)
501-
typeFields := typeSpecificIndexedFields[gvkKey(gvk.Group, gvk.Version, gvk.Kind)]
501+
typeFields := TypeSpecificIndexedFields[gvkKey(gvk.Group, gvk.Version, gvk.Kind)]
502502
if typeFields != nil {
503503
fields = append(fields, typeFields...)
504504
}
@@ -884,7 +884,7 @@ func (s *Store) Delete(apiOp *types.APIRequest, schema *types.APISchema, id stri
884884
return obj, buffer, nil
885885
}
886886

887-
var typeGuidanceTable = map[schema.GroupVersionKind]map[string]string{
887+
var TypeGuidanceTable = map[schema.GroupVersionKind]map[string]string{
888888
schema.GroupVersionKind{Group: "management.cattle.io", Version: "v3", Kind: "Cluster"}: {
889889
"status.allocatable.cpuRaw": "REAL",
890890
"status.allocatable.memoryRaw": "REAL",
@@ -933,7 +933,7 @@ func getTypeGuidance(cols []common.ColumnDefinition, gvk schema.GroupVersionKind
933933
guidance[trimmedField] = colType
934934
}
935935
}
936-
tg, ok := typeGuidanceTable[gvk]
936+
tg, ok := TypeGuidanceTable[gvk]
937937
if ok {
938938
for k, v := range tg {
939939
guidance[k] = v

pkg/stores/sqlproxy/proxy_store_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ func TestListByPartitions(t *testing.T) {
284284
Version: "test",
285285
Kind: "gvk",
286286
}
287-
typeSpecificIndexedFields["some_test_gvk"] = [][]string{{"gvk", "specific", "fields"}}
287+
TypeSpecificIndexedFields["some_test_gvk"] = [][]string{{"gvk", "specific", "fields"}}
288288

289289
setupContext(req)
290290
attributes.SetGVK(schema, gvk)
@@ -370,7 +370,7 @@ func TestListByPartitions(t *testing.T) {
370370
Version: "test",
371371
Kind: "gvk",
372372
}
373-
typeSpecificIndexedFields["some_test_gvk"] = [][]string{{"gvk", "specific", "fields"}}
373+
TypeSpecificIndexedFields["some_test_gvk"] = [][]string{{"gvk", "specific", "fields"}}
374374

375375
setupContext(req)
376376
attributes.SetGVK(schema, gvk)
@@ -448,7 +448,7 @@ func TestListByPartitions(t *testing.T) {
448448
Version: "test",
449449
Kind: "gvk",
450450
}
451-
typeSpecificIndexedFields["some_test_gvk"] = [][]string{{"gvk", "specific", "fields"}}
451+
TypeSpecificIndexedFields["some_test_gvk"] = [][]string{{"gvk", "specific", "fields"}}
452452

453453
attributes.SetGVK(schema, gvk)
454454
// ListByPartitions copies point so we need some original record of items to ensure as asserting listToReturn's
@@ -536,7 +536,7 @@ func TestListByPartitions(t *testing.T) {
536536
Version: "test",
537537
Kind: "gvk",
538538
}
539-
typeSpecificIndexedFields["some_test_gvk"] = [][]string{{"gvk", "specific", "fields"}}
539+
TypeSpecificIndexedFields["some_test_gvk"] = [][]string{{"gvk", "specific", "fields"}}
540540

541541
setupContext(req)
542542
attributes.SetGVK(schema, gvk)
@@ -625,7 +625,7 @@ func TestListByPartitions(t *testing.T) {
625625
Version: "test",
626626
Kind: "gvk",
627627
}
628-
typeSpecificIndexedFields["some_test_gvk"] = [][]string{{"gvk", "specific", "fields"}}
628+
TypeSpecificIndexedFields["some_test_gvk"] = [][]string{{"gvk", "specific", "fields"}}
629629

630630
setupContext(req)
631631
attributes.SetGVK(schema, gvk)

scripts/integration-tests.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/bin/sh
2+
3+
CLUSTER_NAME=steve-integration-test
4+
5+
if [ -z "$KUBECONFIG" ] || [ -z "$(kubectl config get-contexts --no-headers)" ]; then
6+
if ! docker version >/dev/null 2>&1; then
7+
echo "docker not running"
8+
exit 1
9+
fi
10+
11+
KUBECONFIG=$(mktemp)
12+
export KUBECONFIG
13+
if ! k3d kubeconfig get "$CLUSTER_NAME" > "$KUBECONFIG"; then
14+
k3d cluster create "$CLUSTER_NAME"
15+
fi
16+
fi
17+
18+
set -x
19+
RUN_INTEGRATION_TESTS=true go test $TEST_ARGS ./tests/integration/...

tests/integration/README.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Integration Tests
2+
3+
This document outlines how to run, debug and add new integration tests for steve.
4+
5+
## Dependencies
6+
7+
To run the integration tests, you will need a running Kubernetes cluster. The tests will automatically target the cluster configured in your `KUBECONFIG` environment variable.
8+
9+
If you do not have a cluster configured, the tests will attempt to create a local one for you using [k3d](https://k3d.io/v5.6.0/#installation). This requires the following tools to be installed:
10+
11+
- [docker](https://docs.docker.com/get-docker/)
12+
- [k3d](https://k3d.io/v5.6.0/#installation)
13+
14+
You will also need [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) to be installed and available in your `PATH`.
15+
16+
## Running the tests
17+
18+
The integration tests can be run by executing the following command:
19+
20+
```sh
21+
make integration-tests
22+
```
23+
24+
This will:
25+
1. Connect to the Kubernetes cluster defined by your `KUBECONFIG` environment variable. If no cluster is configured, it will try to create a `k3d` cluster named `steve-integration-test`.
26+
2. Run the Go tests located in the `tests/` directory.
27+
28+
## Debugging
29+
30+
It is possible to pause the execution of a test to manually inspect the state of the cluster, the steve API and the SQLite database. This can be achieved by setting `INTEGRATION_TEST_DEBUG=true`:
31+
32+
```sh
33+
INTEGRATION_TEST_DEBUG=true make integration-tests
34+
```
35+
36+
When a test is finished, it will print the following information and block until the test is cancelled (e.g. with `Ctrl+C`):
37+
38+
```
39+
###########################
40+
#
41+
# Integration tests stopped as requested
42+
#
43+
# You can now access the Kubernetes cluster and steve
44+
#
45+
# Kubernetes: KUBECONFIG=<path to kubeconfig>
46+
# Steve URL: <steve API endpoint>
47+
# SQL cache database: <path to sqlite database>
48+
#
49+
###########################
50+
```
51+
52+
You can then use this information to interact with the Kubernetes cluster and the steve API.
53+
54+
## Adding new tests
55+
56+
The integration tests are written using the `testify/suite` package. The main suite is `IntegrationSuite` in `integration_test.go`.
57+
58+
Tests are data-driven and rely on `.test.yaml` files located in the `testdata` directory. These YAML files contain both the Kubernetes resources to apply and the configuration for the test assertions.
59+
60+
To add a new test scenario, you can follow the example of `column_test.go` and `testdata/columns/`:
61+
62+
1. Create a new `my_feature_test.go` file in the `tests/` directory.
63+
2. Create a new directory `testdata/my_feature/`.
64+
3. Add a new test function to the `IntegrationSuite`, for example `TestMyFeature`, in your new Go file.
65+
4. In this function, you will typically:
66+
- Set up a `httptest.NewServer` with the steve API handler.
67+
- Find your test scenarios by looking for `.test.yaml` files in `testdata/my_feature/`.
68+
- For each scenario, run a subtest.
69+
5. Each subtest should:
70+
- Parse the `.test.yaml` file. The file can contain a header with test configuration and Kubernetes objects separated by `---`.
71+
- Apply the Kubernetes objects to the cluster.
72+
- Make requests to the steve API.
73+
- Assert that the responses are correct based on the test configuration.
74+
- Ensure that `defer i.maybeStopAndDebug(baseURL)` is called to allow for debugging.

0 commit comments

Comments
 (0)