Skip to content

Commit 2eb9937

Browse files
committed
Fix GoReleaser config and switch integration tests to kind for multiplatform support
- Fix GoReleaser configuration: add version field, remove broken blobs section - Replace k3s with kind for integration tests (works on Mac, Linux, Windows) - Add Makefile targets for kind cluster management (kind-create, kind-delete, kind-status) - Update README with integration test instructions and kind installation guide - Integration tests now automatically create/use kind cluster named kubectl-rltop-test
1 parent 66c2ceb commit 2eb9937

File tree

4 files changed

+201
-34
lines changed

4 files changed

+201
-34
lines changed

.goreleaser.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
version: 2
2+
13
project_name: kubectl-rltop
24

35
before:
@@ -28,9 +30,6 @@ builds:
2830

2931
archives:
3032
- id: default
31-
format_overrides:
32-
- goos: windows
33-
format: zip
3433
files:
3534
- README.md
3635
- LICENSE
@@ -40,7 +39,7 @@ checksum:
4039
name_template: "checksums.txt"
4140

4241
snapshot:
43-
name_template: "{{ .Tag }}-next"
42+
# name_template is deprecated, using default
4443

4544
changelog:
4645
sort: asc
@@ -60,6 +59,7 @@ release:
6059

6160
blobs:
6261
- provider: github
62+
bucket: releases
6363
ids:
6464
- kubectl-rltop-linux-amd64
6565
- kubectl-rltop-linux-arm64

Makefile

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,29 @@ test-unit: ## Run unit tests only
4545
@echo "Running unit tests..."
4646
@go test -v ./pkg/... ./cmd/...
4747

48-
test-integration: ## Run integration tests (requires k3s)
48+
test-integration: ## Run integration tests (requires kind and Docker)
4949
@echo "Running integration tests..."
50-
@echo "Note: This requires k3s to be installed and running"
50+
@echo "Note: This requires kind and Docker to be installed and running"
5151
@go test -v -tags=integration ./test/integration/... -timeout 10m
5252

53+
kind-create: ## Create kind cluster for integration tests
54+
@echo "Creating kind cluster for integration tests..."
55+
@kind create cluster --name kubectl-rltop-test || true
56+
@echo "Installing metrics-server..."
57+
@kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml || true
58+
@kubectl patch deployment metrics-server -n kube-system --type json -p '[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--kubelet-insecure-tls"}]' || true
59+
@echo "Waiting for metrics-server to be ready..."
60+
@kubectl wait --for=condition=ready pod -l k8s-app=metrics-server -n kube-system --timeout=120s || true
61+
@echo "Kind cluster is ready!"
62+
63+
kind-delete: ## Delete kind cluster used for integration tests
64+
@echo "Deleting kind cluster..."
65+
@kind delete cluster --name kubectl-rltop-test || true
66+
@echo "Kind cluster deleted"
67+
68+
kind-status: ## Check status of kind cluster
69+
@kind get clusters | grep -q kubectl-rltop-test && echo "Cluster exists" || echo "Cluster does not exist"
70+
5371
test-all: test-unit test-integration ## Run both unit and integration tests
5472

5573
test-coverage: ## Run tests with coverage

README.md

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,16 +242,63 @@ This will create binaries in the `dist/` directory for:
242242

243243
### Testing
244244

245-
Run tests:
245+
Run unit tests:
246246
```bash
247-
make test
247+
make test-unit
248248
```
249249

250250
Run tests with coverage:
251251
```bash
252252
make test-coverage
253253
```
254254

255+
#### Integration Tests
256+
257+
Integration tests require a Kubernetes cluster. The tests use [kind](https://kind.sigs.k8s.io/) (Kubernetes in Docker) which works on Mac, Linux, and Windows.
258+
259+
**Prerequisites:**
260+
- [Docker](https://www.docker.com/) installed and running
261+
- [kind](https://kind.sigs.k8s.io/docs/user/quick-start/#installation) installed
262+
263+
**Install kind:**
264+
```bash
265+
# macOS
266+
brew install kind
267+
268+
# Linux
269+
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64
270+
chmod +x ./kind
271+
sudo mv ./kind /usr/local/bin/kind
272+
273+
# Windows (using Chocolatey)
274+
choco install kind
275+
```
276+
277+
**Run integration tests:**
278+
```bash
279+
# The tests will automatically create a kind cluster if it doesn't exist
280+
make test-integration
281+
```
282+
283+
**Manual cluster management:**
284+
```bash
285+
# Create kind cluster manually (optional)
286+
make kind-create
287+
288+
# Check cluster status
289+
make kind-status
290+
291+
# Delete kind cluster
292+
make kind-delete
293+
```
294+
295+
The integration tests will:
296+
1. Create a kind cluster named `kubectl-rltop-test` (if it doesn't exist)
297+
2. Install metrics-server
298+
3. Create test pods with known resource requests/limits
299+
4. Run all integration tests
300+
5. Clean up test resources (but keep the cluster for reuse)
301+
255302
### Linting
256303

257304
Run linters:

test/integration/main_test.go

Lines changed: 128 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ var (
2323
kubeconfigPath string
2424
clientset kubernetes.Interface
2525
testNamespace = "rltop-test"
26+
clusterName = "kubectl-rltop-test"
2627
)
2728

2829
func TestMain(m *testing.M) {
@@ -42,17 +43,22 @@ func TestMain(m *testing.M) {
4243
}
4344

4445
func setup() error {
45-
// Check if k3s is already running
46-
if isK3sRunning() {
47-
fmt.Println("k3s is already running, using existing cluster")
48-
kubeconfigPath = "/etc/rancher/k3s/k3s.yaml"
46+
// Check if kind cluster already exists
47+
if isKindClusterExists() {
48+
fmt.Printf("kind cluster '%s' already exists, using existing cluster\n", clusterName)
4949
} else {
50-
// Install and start k3s
51-
fmt.Println("Installing k3s...")
52-
if err := installK3s(); err != nil {
53-
return fmt.Errorf("failed to install k3s: %w", err)
50+
// Create kind cluster
51+
fmt.Printf("Creating kind cluster '%s'...\n", clusterName)
52+
if err := createKindCluster(); err != nil {
53+
return fmt.Errorf("failed to create kind cluster: %w", err)
5454
}
55-
kubeconfigPath = "/etc/rancher/k3s/k3s.yaml"
55+
}
56+
57+
// Get kubeconfig path for kind cluster
58+
var err error
59+
kubeconfigPath, err = getKindKubeconfig()
60+
if err != nil {
61+
return fmt.Errorf("failed to get kind kubeconfig: %w", err)
5662
}
5763

5864
// Wait for cluster to be ready
@@ -108,38 +114,130 @@ func teardown() {
108114
// Clean up test namespace
109115
clientset.CoreV1().Namespaces().Delete(ctx, testNamespace, metav1.DeleteOptions{})
110116
}
117+
// Note: We don't delete the kind cluster here to allow reuse
118+
// Users can delete it manually with: kind delete cluster --name kubectl-rltop-test
111119
}
112120

113-
func isK3sRunning() bool {
114-
cmd := exec.Command("systemctl", "is-active", "--quiet", "k3s")
115-
return cmd.Run() == nil
121+
func isKindClusterExists() bool {
122+
cmd := exec.Command("kind", "get", "clusters")
123+
output, err := cmd.Output()
124+
if err != nil {
125+
return false
126+
}
127+
return strings.Contains(string(output), clusterName)
116128
}
117129

118-
func installK3s() error {
119-
// Check if k3s is already installed
120-
if _, err := exec.LookPath("k3s"); err == nil {
121-
// k3s is installed, try to start it
122-
cmd := exec.Command("sudo", "systemctl", "start", "k3s")
123-
if err := cmd.Run(); err != nil {
124-
return fmt.Errorf("failed to start k3s: %w", err)
125-
}
126-
return nil
130+
func createKindCluster() error {
131+
// Check if kind is installed
132+
if _, err := exec.LookPath("kind"); err != nil {
133+
return fmt.Errorf("kind is not installed. Please install it: https://kind.sigs.k8s.io/docs/user/quick-start/#installation")
134+
}
135+
136+
// Check if Docker is running
137+
if err := checkDockerRunning(); err != nil {
138+
return fmt.Errorf("docker is not running: %w. Please start Docker", err)
139+
}
140+
141+
// Create kind cluster with metrics-server enabled
142+
// We use a config that enables metrics-server
143+
config := `kind: Cluster
144+
apiVersion: kind.x-k8s.io/v1alpha4
145+
nodes:
146+
- role: control-plane
147+
kubeadmConfigPatches:
148+
- |
149+
kind: InitConfiguration
150+
nodeRegistration:
151+
kubeletExtraArgs:
152+
node-labels: "ingress-ready=true"
153+
extraPortMappings:
154+
- containerPort: 80
155+
hostPort: 80
156+
protocol: TCP
157+
- containerPort: 443
158+
hostPort: 443
159+
protocol: TCP`
160+
161+
// Write config to temp file
162+
tmpfile, err := os.CreateTemp("", "kind-config-*.yaml")
163+
if err != nil {
164+
return fmt.Errorf("failed to create temp config file: %w", err)
165+
}
166+
defer os.Remove(tmpfile.Name())
167+
168+
if _, err := tmpfile.WriteString(config); err != nil {
169+
return fmt.Errorf("failed to write config: %w", err)
170+
}
171+
if err := tmpfile.Close(); err != nil {
172+
return fmt.Errorf("failed to close config file: %w", err)
173+
}
174+
175+
// Create cluster
176+
cmd := exec.Command("kind", "create", "cluster", "--name", clusterName, "--config", tmpfile.Name())
177+
cmd.Stdout = os.Stdout
178+
cmd.Stderr = os.Stderr
179+
if err := cmd.Run(); err != nil {
180+
return fmt.Errorf("failed to create kind cluster: %w", err)
127181
}
128182

129-
// Install k3s
130-
cmd := exec.Command("sh", "-c", "curl -sfL https://get.k3s.io | sh -")
183+
// Get kubeconfig for the newly created cluster
184+
kubeconfig, err := getKindKubeconfig()
185+
if err != nil {
186+
return fmt.Errorf("failed to get kubeconfig after cluster creation: %w", err)
187+
}
188+
189+
// Install metrics-server
190+
fmt.Println("Installing metrics-server...")
191+
cmd = exec.Command("kubectl", "apply", "-f", "https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml")
192+
cmd.Env = append(os.Environ(), fmt.Sprintf("KUBECONFIG=%s", kubeconfig))
131193
cmd.Stdout = os.Stdout
132194
cmd.Stderr = os.Stderr
133195
if err := cmd.Run(); err != nil {
134-
return fmt.Errorf("failed to install k3s: %w", err)
196+
return fmt.Errorf("failed to install metrics-server: %w", err)
135197
}
136198

137-
// Wait a bit for k3s to start
138-
time.Sleep(5 * time.Second)
199+
// Patch metrics-server to work in kind (disable TLS verification)
200+
cmd = exec.Command("kubectl", "patch", "deployment", "metrics-server", "-n", "kube-system",
201+
"--type", "json", "-p", `[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--kubelet-insecure-tls"}]`)
202+
cmd.Env = append(os.Environ(), fmt.Sprintf("KUBECONFIG=%s", kubeconfig))
203+
cmd.Stdout = os.Stdout
204+
cmd.Stderr = os.Stderr
205+
if err := cmd.Run(); err != nil {
206+
return fmt.Errorf("failed to patch metrics-server: %w", err)
207+
}
139208

140209
return nil
141210
}
142211

212+
func getKindKubeconfig() (string, error) {
213+
// Get kubeconfig from kind
214+
cmd := exec.Command("kind", "get", "kubeconfig", "--name", clusterName)
215+
output, err := cmd.Output()
216+
if err != nil {
217+
return "", fmt.Errorf("failed to get kubeconfig: %w", err)
218+
}
219+
220+
// Write to temp file
221+
tmpfile, err := os.CreateTemp("", "kubeconfig-*.yaml")
222+
if err != nil {
223+
return "", fmt.Errorf("failed to create temp kubeconfig file: %w", err)
224+
}
225+
226+
if _, err := tmpfile.Write(output); err != nil {
227+
return "", fmt.Errorf("failed to write kubeconfig: %w", err)
228+
}
229+
if err := tmpfile.Close(); err != nil {
230+
return "", fmt.Errorf("failed to close kubeconfig file: %w", err)
231+
}
232+
233+
return tmpfile.Name(), nil
234+
}
235+
236+
func checkDockerRunning() error {
237+
cmd := exec.Command("docker", "info")
238+
return cmd.Run()
239+
}
240+
143241
func waitForClusterReady(timeout time.Duration) error {
144242
ctx, cancel := context.WithTimeout(context.Background(), timeout)
145243
defer cancel()
@@ -150,6 +248,7 @@ func waitForClusterReady(timeout time.Duration) error {
150248
return fmt.Errorf("timeout waiting for cluster to be ready")
151249
default:
152250
cmd := exec.Command("kubectl", "--kubeconfig", kubeconfigPath, "get", "nodes", "--no-headers")
251+
cmd.Env = append(os.Environ(), fmt.Sprintf("KUBECONFIG=%s", kubeconfigPath))
153252
if err := cmd.Run(); err == nil {
154253
return nil
155254
}
@@ -169,7 +268,10 @@ func waitForMetricsServer(timeout time.Duration) error {
169268
default:
170269
cmd := exec.Command("kubectl", "--kubeconfig", kubeconfigPath, "wait", "--for=condition=ready",
171270
"pod", "-l", "k8s-app=metrics-server", "-n", "kube-system", "--timeout=30s")
271+
cmd.Env = append(os.Environ(), fmt.Sprintf("KUBECONFIG=%s", kubeconfigPath))
172272
if err := cmd.Run(); err == nil {
273+
// Wait a bit more for metrics to be available
274+
time.Sleep(5 * time.Second)
173275
return nil
174276
}
175277
time.Sleep(5 * time.Second)

0 commit comments

Comments
 (0)