Skip to content

Commit 8ea3f21

Browse files
authored
feat: add KinD integration tests (#141)
* feat: add KinD integration tests Add integration tests that run against a real Kubernetes cluster using KinD (Kubernetes in Docker). This addresses #58. Changes: - Add integration_test.go with tests for: - Pod events (create/delete) - ReplicaSet events - Multi-namespace support - Label selector filtering - Add .github/workflows/integration.yaml CI workflow that: - Runs lint and unit tests first - Then runs integration tests with KinD - 10 minute timeout - Add scripts/kind-setup.sh for local development - Update README.md with integration test documentation The integration tests use the existing fakeAgentAPI to mock the Coder server, focusing on validating real Kubernetes informer behavior. * fix: use real clock for integration tests The integration tests were using quartz.NewMock(t) which creates a mock clock that doesn't advance automatically. This caused timeouts when waiting for log source registration because the timers in the log queuer never fired. Changes: - Remove mock clock usage from all integration tests - Use real clock (nil) which is the default - Reduce logDebounce to 5s for faster test execution - Increase informer sync wait to 1s for reliability * fix: remove duplicate unit-test job from integration workflow * fix: make integration tests more robust against event ordering The tests now use waitForLogContaining which continuously collects logs until finding the expected message, rather than expecting specific messages in the first batch of logs received. This fixes flaky tests caused by Kubernetes scheduling events arriving before pod lifecycle events. * fix: address PR review feedback - Add safety check to prevent running integration tests against non-KinD clusters (detects localhost/127.0.0.1/kind in host) - Use SHA pinning for GitHub Actions with version comments - Add INTEGRATION_TEST_UNSAFE=1 escape hatch for special cases * chore: add binary to gitignore * feat: add Makefile with lint/shellcheck and fmt/shfmt targets - Add Makefile with build, test, lint, and fmt targets - Fix shellcheck warnings in scripts/helm.sh and scripts/version.sh - Format shell scripts with shfmt * chore: update GitHub Actions dependencies and clean up .gitignore - Update actions/checkout to v6.0.1 - Update actions/setup-go to v6.1.0 - Update helm/kind-action to v1.13.0 - Remove buildcoder-logstream-kube from .gitignore * fix: address remaining PR review comments - Fix safety check logic: check INTEGRATION_TEST_UNSAFE env var before calling t.Fatalf, not after - Fix .gitignore: add coder-logstream-kube and build/ on separate lines * fix: use Go 1.24 in integration workflow to match go.mod
1 parent db7bcb7 commit 8ea3f21

File tree

9 files changed

+814
-18
lines changed

9 files changed

+814
-18
lines changed

.github/workflows/integration.yaml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: integration
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
9+
permissions:
10+
actions: none
11+
checks: none
12+
contents: read
13+
deployments: none
14+
issues: none
15+
packages: none
16+
pull-requests: none
17+
repository-projects: none
18+
security-events: none
19+
statuses: none
20+
21+
# Cancel in-progress runs for pull requests when developers push
22+
# additional changes
23+
concurrency:
24+
group: ${{ github.workflow }}-${{ github.ref }}
25+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
26+
27+
jobs:
28+
integration-test:
29+
runs-on: ubuntu-latest
30+
timeout-minutes: 10
31+
steps:
32+
- name: Checkout
33+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
34+
35+
- name: Setup Go
36+
uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
37+
with:
38+
go-version: "~1.24"
39+
40+
- name: Create KinD cluster
41+
uses: helm/kind-action@92086f6be054225fa813e0a4b13787fc9088faab # v1.13.0
42+
with:
43+
cluster_name: integration-test
44+
45+
- name: Run integration tests
46+
run: go test -tags=integration -v -timeout=8m ./...

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
coder-logstream-kube
12
coder-logstream-kube-*
2-
build
3+
build/

Makefile

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Colors for output
2+
GREEN := $(shell printf '\033[32m')
3+
RESET := $(shell printf '\033[0m')
4+
BOLD := $(shell printf '\033[1m')
5+
6+
# Shell source files - use shfmt to find them (respects .editorconfig)
7+
SHELL_SRC_FILES := $(shell shfmt -f .)
8+
9+
.PHONY: all
10+
all: build
11+
12+
.PHONY: build
13+
build:
14+
go build ./...
15+
16+
.PHONY: test
17+
test:
18+
go test ./... -race
19+
20+
.PHONY: test/integration
21+
test/integration:
22+
go test -tags=integration -v -timeout=8m ./...
23+
24+
.PHONY: lint
25+
lint: lint/go lint/shellcheck
26+
27+
.PHONY: lint/go
28+
lint/go:
29+
golangci-lint run --timeout=5m
30+
31+
.PHONY: lint/shellcheck
32+
lint/shellcheck: $(SHELL_SRC_FILES)
33+
echo "--- shellcheck"
34+
shellcheck --external-sources $(SHELL_SRC_FILES)
35+
36+
.PHONY: fmt
37+
fmt: fmt/go fmt/shfmt
38+
39+
.PHONY: fmt/go
40+
fmt/go:
41+
go fmt ./...
42+
43+
.PHONY: fmt/shfmt
44+
fmt/shfmt: $(SHELL_SRC_FILES)
45+
ifdef FILE
46+
# Format single shell script
47+
if [[ -f "$(FILE)" ]] && [[ "$(FILE)" == *.sh ]]; then \
48+
echo "$(GREEN)==>$(RESET) $(BOLD)fmt/shfmt$(RESET) $(FILE)"; \
49+
shfmt -w "$(FILE)"; \
50+
fi
51+
else
52+
echo "$(GREEN)==>$(RESET) $(BOLD)fmt/shfmt$(RESET)"
53+
# Only do diff check in CI, errors on diff.
54+
ifdef CI
55+
shfmt -d $(SHELL_SRC_FILES)
56+
else
57+
shfmt -w $(SHELL_SRC_FILES)
58+
endif
59+
endif
60+
61+
.PHONY: clean
62+
clean:
63+
rm -f coder-logstream-kube
64+
65+
.PHONY: kind/create
66+
kind/create:
67+
./scripts/kind-setup.sh create
68+
69+
.PHONY: kind/delete
70+
kind/delete:
71+
./scripts/kind-setup.sh delete
72+
73+
.PHONY: help
74+
help:
75+
@echo "Available targets:"
76+
@echo " build - Build the project"
77+
@echo " test - Run unit tests"
78+
@echo " test/integration - Run integration tests (requires KinD cluster)"
79+
@echo " lint - Run all linters"
80+
@echo " lint/go - Run golangci-lint"
81+
@echo " lint/shellcheck - Run shellcheck on shell scripts"
82+
@echo " fmt - Format all code"
83+
@echo " fmt/go - Format Go code"
84+
@echo " fmt/shfmt - Format shell scripts"
85+
@echo " kind/create - Create KinD cluster for integration tests"
86+
@echo " kind/delete - Delete KinD cluster"
87+
@echo " clean - Remove build artifacts"

README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,42 @@ Kubernetes provides an [informers](https://pkg.go.dev/k8s.io/client-go/informers
6464
6565
- [`SSL_CERT_FILE`](https://go.dev/src/crypto/x509/root_unix.go#L19): Specifies the path to an SSL certificate.
6666
- [`SSL_CERT_DIR`](https://go.dev/src/crypto/x509/root_unix.go#L25): Identifies which directory to check for SSL certificate files.
67+
68+
## Development
69+
70+
### Running Tests
71+
72+
Unit tests can be run with:
73+
74+
```console
75+
go test ./... -race
76+
```
77+
78+
### Integration Tests
79+
80+
Integration tests run against a real Kubernetes cluster using [KinD (Kubernetes in Docker)](https://kind.sigs.k8s.io/).
81+
82+
**Prerequisites:**
83+
- [Docker](https://docs.docker.com/get-docker/)
84+
- [KinD](https://kind.sigs.k8s.io/docs/user/quick-start/#installation)
85+
- [kubectl](https://kubernetes.io/docs/tasks/tools/)
86+
87+
**Setup and run:**
88+
89+
```console
90+
# Create a KinD cluster
91+
./scripts/kind-setup.sh create
92+
93+
# Run integration tests
94+
go test -tags=integration -v ./...
95+
96+
# Clean up when done
97+
./scripts/kind-setup.sh delete
98+
```
99+
100+
The integration tests validate:
101+
- Pod event streaming with real Kubernetes informers
102+
- ReplicaSet event handling
103+
- Multi-namespace support
104+
- Label selector filtering
105+

0 commit comments

Comments
 (0)