Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .github/workflows/integration-tests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Integration tests

on:
pull_request: {}
push:
branches:
- master
- release/*

jobs:
ci:
runs-on: ubuntu-latest
steps:
- name : Checkout repository
# https://github.com/actions/checkout/releases/tag/v4.1.1
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0

- name: Install Go
# https://github.com/actions/setup-go/releases/tag/v5.0.0
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version-file: 'go.mod'

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Install k3d
run: |
curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | TAG=v5.8.3 bash

- name: Download dependencies
run: go mod download

- name: Run integration tests
run: make integration-tests
env:
INTEGRATION_TEST_ARGS: "-v -count=1"
17 changes: 16 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
INTEGRATION_TEST_ARGS ?=
INTEGRATION_TEST_DEBUG ?=

TEST_ARGS := $(INTEGRATION_TEST_ARGS)

ifeq ($(INTEGRATION_TEST_DEBUG),true)
# we likely want longer timeout
TEST_ARGS += -timeout=60m
# verbose to see KUBECONFIG path and steve URL
TEST_ARGS += -v
endif

build:
docker build -t steve .

Expand All @@ -13,5 +25,8 @@ run-host: build
test:
bash scripts/test.sh

integration-tests:
@TEST_ARGS="$(TEST_ARGS)" ./scripts/integration-tests.sh

validate:
bash scripts/validate.sh
bash scripts/validate.sh
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -909,10 +909,8 @@ all requests in the table test.

#### Integration tests

Integration tests for the steve API are located among the [rancher integration
tests](ihttps://github.com/rancher/rancher/tree/release/v2.8/tests/v2/integration/steveapi).
See the documentation included there for running the tests and using them to
generate API documentation.
New integration tests for the steve API are located in the `tests/` directory.
Refer to [tests/README.md](./tests/README.md) for documentation on running and adding these tests.

## Running Tests

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ require (
go.yaml.in/yaml/v3 v3.0.4
golang.org/x/sync v0.17.0
google.golang.org/protobuf v1.36.9
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.34.1
k8s.io/apiextensions-apiserver v0.34.1
k8s.io/apimachinery v0.34.1
Expand Down Expand Up @@ -144,7 +145,6 @@ require (
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/kms v0.34.1 // indirect
modernc.org/libc v1.66.3 // indirect
modernc.org/mathutil v1.7.1 // indirect
Expand Down
8 changes: 4 additions & 4 deletions pkg/stores/sqlproxy/proxy_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ var (
paramScheme = runtime.NewScheme()
paramCodec = runtime.NewParameterCodec(paramScheme)
// Please keep the gvkKey entries in alphabetical order, on a field-by-field basis
typeSpecificIndexedFields = map[string][][]string{
TypeSpecificIndexedFields = map[string][][]string{
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking of moving this to an option in the CachefactoryOption struct so we can modify things per-gvk (fields, type hints, etc). But that would be in another PR. For now, the only other way I figured was making this public for the sake of modifying it in the tests. Not great, but does the job. Open to other suggestions though

gvkKey("", "v1", "Event"): {
{"_type"},
{"involvedObject", "kind"},
Expand Down Expand Up @@ -498,7 +498,7 @@ func (s *Store) initializeNamespaceCache() error {
func getFieldForGVK(gvk schema.GroupVersionKind) [][]string {
fields := [][]string{}
fields = append(fields, commonIndexFields...)
typeFields := typeSpecificIndexedFields[gvkKey(gvk.Group, gvk.Version, gvk.Kind)]
typeFields := TypeSpecificIndexedFields[gvkKey(gvk.Group, gvk.Version, gvk.Kind)]
if typeFields != nil {
fields = append(fields, typeFields...)
}
Expand Down Expand Up @@ -884,7 +884,7 @@ func (s *Store) Delete(apiOp *types.APIRequest, schema *types.APISchema, id stri
return obj, buffer, nil
}

var typeGuidanceTable = map[schema.GroupVersionKind]map[string]string{
var TypeGuidanceTable = map[schema.GroupVersionKind]map[string]string{
schema.GroupVersionKind{Group: "management.cattle.io", Version: "v3", Kind: "Cluster"}: {
"status.allocatable.cpuRaw": "REAL",
"status.allocatable.memoryRaw": "REAL",
Expand Down Expand Up @@ -933,7 +933,7 @@ func getTypeGuidance(cols []common.ColumnDefinition, gvk schema.GroupVersionKind
guidance[trimmedField] = colType
}
}
tg, ok := typeGuidanceTable[gvk]
tg, ok := TypeGuidanceTable[gvk]
if ok {
for k, v := range tg {
guidance[k] = v
Expand Down
10 changes: 5 additions & 5 deletions pkg/stores/sqlproxy/proxy_store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ func TestListByPartitions(t *testing.T) {
Version: "test",
Kind: "gvk",
}
typeSpecificIndexedFields["some_test_gvk"] = [][]string{{"gvk", "specific", "fields"}}
TypeSpecificIndexedFields["some_test_gvk"] = [][]string{{"gvk", "specific", "fields"}}

setupContext(req)
attributes.SetGVK(schema, gvk)
Expand Down Expand Up @@ -370,7 +370,7 @@ func TestListByPartitions(t *testing.T) {
Version: "test",
Kind: "gvk",
}
typeSpecificIndexedFields["some_test_gvk"] = [][]string{{"gvk", "specific", "fields"}}
TypeSpecificIndexedFields["some_test_gvk"] = [][]string{{"gvk", "specific", "fields"}}

setupContext(req)
attributes.SetGVK(schema, gvk)
Expand Down Expand Up @@ -448,7 +448,7 @@ func TestListByPartitions(t *testing.T) {
Version: "test",
Kind: "gvk",
}
typeSpecificIndexedFields["some_test_gvk"] = [][]string{{"gvk", "specific", "fields"}}
TypeSpecificIndexedFields["some_test_gvk"] = [][]string{{"gvk", "specific", "fields"}}

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

setupContext(req)
attributes.SetGVK(schema, gvk)
Expand Down Expand Up @@ -625,7 +625,7 @@ func TestListByPartitions(t *testing.T) {
Version: "test",
Kind: "gvk",
}
typeSpecificIndexedFields["some_test_gvk"] = [][]string{{"gvk", "specific", "fields"}}
TypeSpecificIndexedFields["some_test_gvk"] = [][]string{{"gvk", "specific", "fields"}}

setupContext(req)
attributes.SetGVK(schema, gvk)
Expand Down
19 changes: 19 additions & 0 deletions scripts/integration-tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/sh

CLUSTER_NAME=steve-integration-test

if [ -z "$KUBECONFIG" ] || [ -z "$(kubectl config get-contexts --no-headers)" ]; then
if ! docker version >/dev/null 2>&1; then
echo "docker not running"
exit 1
fi

KUBECONFIG=$(mktemp)
export KUBECONFIG
if ! k3d kubeconfig get "$CLUSTER_NAME" > "$KUBECONFIG"; then
k3d cluster create "$CLUSTER_NAME"
fi
fi

set -x
RUN_INTEGRATION_TESTS=true go test $TEST_ARGS ./tests/...
74 changes: 74 additions & 0 deletions tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Integration Tests

This document outlines how to run, debug and add new integration tests for steve.

## Dependencies

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.

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:

- [docker](https://docs.docker.com/get-docker/)
- [k3d](https://k3d.io/v5.6.0/#installation)

You will also need [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) to be installed and available in your `PATH`.

## Running the tests

The integration tests can be run by executing the following command:

```sh
make integration-tests
```

This will:
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`.
2. Run the Go tests located in the `tests/` directory.

## Debugging

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`:

```sh
INTEGRATION_TEST_DEBUG=true make integration-tests
```

When a test is finished, it will print the following information and block until the test is cancelled (e.g. with `Ctrl+C`):

```
###########################
#
# Integration tests stopped as requested
#
# You can now access the Kubernetes cluster and steve
#
# Kubernetes: KUBECONFIG=<path to kubeconfig>
# Steve URL: <steve API endpoint>
# SQL cache database: <path to sqlite database>
#
###########################
```

You can then use this information to interact with the Kubernetes cluster and the steve API.

## Adding new tests

The integration tests are written using the `testify/suite` package. The main suite is `IntegrationSuite` in `integration_test.go`.

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.

To add a new test scenario, you can follow the example of `column_test.go` and `testdata/columns/`:

1. Create a new `my_feature_test.go` file in the `tests/` directory.
2. Create a new directory `testdata/my_feature/`.
3. Add a new test function to the `IntegrationSuite`, for example `TestMyFeature`, in your new Go file.
4. In this function, you will typically:
- Set up a `httptest.NewServer` with the steve API handler.
- Find your test scenarios by looking for `.test.yaml` files in `testdata/my_feature/`.
- For each scenario, run a subtest.
5. Each subtest should:
- Parse the `.test.yaml` file. The file can contain a header with test configuration and Kubernetes objects separated by `---`.
- Apply the Kubernetes objects to the cluster.
- Make requests to the steve API.
- Assert that the responses are correct based on the test configuration.
- Ensure that `defer i.maybeStopAndDebug(baseURL)` is called to allow for debugging.
Loading
Loading