Skip to content

Commit e1a70bd

Browse files
Add plan preview tests for kubernetes_multicluster plugin
Add plugin_test.go and testdata covering single-target and multi-target scenarios. Signed-off-by: Mohammed Firdous <124298708+mohammedfirdouss@users.noreply.github.com>
1 parent 5c35a9b commit e1a70bd

9 files changed

Lines changed: 381 additions & 0 deletions

File tree

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
// Copyright 2025 The PipeCD Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package planpreview
16+
17+
import (
18+
"context"
19+
"path/filepath"
20+
"testing"
21+
22+
sdk "github.com/pipe-cd/piped-plugin-sdk-go"
23+
"github.com/pipe-cd/piped-plugin-sdk-go/logpersister/logpersistertest"
24+
"github.com/pipe-cd/piped-plugin-sdk-go/toolregistry/toolregistrytest"
25+
"github.com/stretchr/testify/assert"
26+
"github.com/stretchr/testify/require"
27+
"go.uber.org/zap/zaptest"
28+
29+
kubeconfig "github.com/pipe-cd/pipecd/pkg/app/pipedv1/plugin/kubernetes_multicluster/config"
30+
)
31+
32+
const (
33+
pluginName = "kubernetes_multicluster"
34+
runningCommit = "abc000"
35+
targetCommit = "abc123"
36+
)
37+
38+
func makeDeployTargets(names ...string) []*sdk.DeployTarget[kubeconfig.KubernetesDeployTargetConfig] {
39+
dts := make([]*sdk.DeployTarget[kubeconfig.KubernetesDeployTargetConfig], 0, len(names))
40+
for _, name := range names {
41+
dts = append(dts, &sdk.DeployTarget[kubeconfig.KubernetesDeployTargetConfig]{Name: name})
42+
}
43+
return dts
44+
}
45+
46+
func makeInput(
47+
t *testing.T,
48+
appConfigFile string,
49+
targetAppDir string,
50+
runningAppDir string,
51+
) *sdk.GetPlanPreviewInput[kubeconfig.KubernetesApplicationSpec] {
52+
t.Helper()
53+
54+
appCfg := sdk.LoadApplicationConfigForTest[kubeconfig.KubernetesApplicationSpec](t, appConfigFile, pluginName)
55+
testRegistry := toolregistrytest.NewTestToolRegistry(t)
56+
57+
targetDS := sdk.DeploymentSource[kubeconfig.KubernetesApplicationSpec]{
58+
ApplicationDirectory: targetAppDir,
59+
CommitHash: targetCommit,
60+
ApplicationConfig: appCfg,
61+
ApplicationConfigFilename: "app.pipecd.yaml",
62+
}
63+
64+
input := &sdk.GetPlanPreviewInput[kubeconfig.KubernetesApplicationSpec]{
65+
Request: sdk.GetPlanPreviewRequest[kubeconfig.KubernetesApplicationSpec]{
66+
ApplicationID: "app-id",
67+
ApplicationName: "simple",
68+
TargetDeploymentSource: targetDS,
69+
},
70+
Client: sdk.NewClient(nil, pluginName, "app-id", "", logpersistertest.NewTestLogPersister(t), testRegistry),
71+
Logger: zaptest.NewLogger(t),
72+
}
73+
74+
if runningAppDir != "" {
75+
input.Request.RunningDeploymentSource = sdk.DeploymentSource[kubeconfig.KubernetesApplicationSpec]{
76+
ApplicationDirectory: runningAppDir,
77+
CommitHash: runningCommit,
78+
ApplicationConfig: appCfg,
79+
ApplicationConfigFilename: "app.pipecd.yaml",
80+
}
81+
}
82+
83+
return input
84+
}
85+
86+
func TestPlugin_GetPlanPreview_SingleTarget(t *testing.T) {
87+
t.Parallel()
88+
89+
appCfgFile := filepath.Join("testdata", "single", "app.pipecd.yaml")
90+
runningDir := filepath.Join("testdata", "single", "running")
91+
targetDir := filepath.Join("testdata", "single", "target")
92+
p := &Plugin{}
93+
94+
tests := []struct {
95+
name string
96+
targetDir string
97+
runningDir string
98+
wantNoChange bool
99+
wantSummary string
100+
wantInDetails []string
101+
}{
102+
{
103+
name: "first deployment (no running source)",
104+
targetDir: targetDir,
105+
runningDir: "",
106+
wantNoChange: false,
107+
wantSummary: "1 added manifests, 0 changed manifests, 0 deleted manifests",
108+
wantInDetails: []string{
109+
"simple",
110+
"Deployment",
111+
},
112+
},
113+
{
114+
name: "no change (same files)",
115+
targetDir: runningDir,
116+
runningDir: runningDir,
117+
wantNoChange: true,
118+
wantSummary: "No changes were detected",
119+
},
120+
{
121+
name: "image tag changed",
122+
targetDir: targetDir,
123+
runningDir: runningDir,
124+
wantNoChange: false,
125+
wantSummary: "0 added manifests, 1 changed manifests, 0 deleted manifests",
126+
wantInDetails: []string{
127+
"v0.1.0",
128+
"v0.2.0",
129+
},
130+
},
131+
}
132+
133+
for _, tc := range tests {
134+
t.Run(tc.name, func(t *testing.T) {
135+
t.Parallel()
136+
input := makeInput(t, appCfgFile, tc.targetDir, tc.runningDir)
137+
138+
resp, err := p.GetPlanPreview(context.Background(), nil, makeDeployTargets("default"), input)
139+
require.NoError(t, err)
140+
require.Len(t, resp.Results, 1)
141+
142+
result := resp.Results[0]
143+
assert.Equal(t, tc.wantNoChange, result.NoChange)
144+
assert.Equal(t, tc.wantSummary, result.Summary)
145+
assert.Equal(t, "diff", result.DiffLanguage)
146+
147+
for _, s := range tc.wantInDetails {
148+
assert.Contains(t, string(result.Details), s)
149+
}
150+
if tc.wantNoChange {
151+
assert.Nil(t, result.Details)
152+
}
153+
})
154+
}
155+
}
156+
157+
func TestPlugin_GetPlanPreview_MultiTarget(t *testing.T) {
158+
t.Parallel()
159+
160+
appCfgFile := filepath.Join("testdata", "multi", "app.pipecd.yaml")
161+
runningDir := filepath.Join("testdata", "multi", "running")
162+
targetDir := filepath.Join("testdata", "multi", "target")
163+
p := &Plugin{}
164+
dts := makeDeployTargets("cluster1", "cluster2")
165+
166+
tests := []struct {
167+
name string
168+
checks []struct {
169+
deployTarget string
170+
wantNoChange bool
171+
wantSummary string
172+
wantInDetails []string
173+
}
174+
}{
175+
{
176+
name: "cluster1 changed, cluster2 unchanged",
177+
checks: []struct {
178+
deployTarget string
179+
wantNoChange bool
180+
wantSummary string
181+
wantInDetails []string
182+
}{
183+
{
184+
deployTarget: "cluster1",
185+
wantNoChange: false,
186+
wantSummary: "0 added manifests, 1 changed manifests, 0 deleted manifests",
187+
wantInDetails: []string{"v0.1.0", "v0.2.0"},
188+
},
189+
{
190+
deployTarget: "cluster2",
191+
wantNoChange: true,
192+
wantSummary: "No changes were detected",
193+
},
194+
},
195+
},
196+
}
197+
198+
for _, tc := range tests {
199+
t.Run(tc.name, func(t *testing.T) {
200+
t.Parallel()
201+
input := makeInput(t, appCfgFile, targetDir, runningDir)
202+
203+
resp, err := p.GetPlanPreview(context.Background(), nil, dts, input)
204+
require.NoError(t, err)
205+
require.Len(t, resp.Results, 2)
206+
207+
for _, check := range tc.checks {
208+
var result *sdk.PlanPreviewResult
209+
for i := range resp.Results {
210+
if resp.Results[i].DeployTarget == check.deployTarget {
211+
result = &resp.Results[i]
212+
break
213+
}
214+
}
215+
require.NotNil(t, result, "result for deploy target %q not found", check.deployTarget)
216+
217+
assert.Equal(t, check.wantNoChange, result.NoChange)
218+
assert.Equal(t, check.wantSummary, result.Summary)
219+
assert.Equal(t, "diff", result.DiffLanguage)
220+
221+
for _, s := range check.wantInDetails {
222+
assert.Contains(t, string(result.Details), s)
223+
}
224+
if check.wantNoChange {
225+
assert.Nil(t, result.Details)
226+
}
227+
}
228+
})
229+
}
230+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
apiVersion: pipecd.dev/v1beta1
2+
kind: KubernetesApp
3+
spec:
4+
name: simple
5+
plugins:
6+
kubernetes_multicluster:
7+
input:
8+
multiTargets:
9+
- target:
10+
name: cluster1
11+
manifests:
12+
- cluster1/deployment.yaml
13+
- target:
14+
name: cluster2
15+
manifests:
16+
- cluster2/deployment.yaml
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: simple-cluster1
5+
labels:
6+
app: simple-cluster1
7+
spec:
8+
replicas: 2
9+
selector:
10+
matchLabels:
11+
app: simple-cluster1
12+
template:
13+
metadata:
14+
labels:
15+
app: simple-cluster1
16+
spec:
17+
containers:
18+
- name: helloworld
19+
image: ghcr.io/pipe-cd/helloworld:v0.1.0
20+
ports:
21+
- containerPort: 9085
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: simple-cluster2
5+
labels:
6+
app: simple-cluster2
7+
spec:
8+
replicas: 2
9+
selector:
10+
matchLabels:
11+
app: simple-cluster2
12+
template:
13+
metadata:
14+
labels:
15+
app: simple-cluster2
16+
spec:
17+
containers:
18+
- name: helloworld
19+
image: ghcr.io/pipe-cd/helloworld:v0.1.0
20+
ports:
21+
- containerPort: 9085
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: simple-cluster1
5+
labels:
6+
app: simple-cluster1
7+
spec:
8+
replicas: 2
9+
selector:
10+
matchLabels:
11+
app: simple-cluster1
12+
template:
13+
metadata:
14+
labels:
15+
app: simple-cluster1
16+
spec:
17+
containers:
18+
- name: helloworld
19+
image: ghcr.io/pipe-cd/helloworld:v0.2.0
20+
ports:
21+
- containerPort: 9085
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: simple-cluster2
5+
labels:
6+
app: simple-cluster2
7+
spec:
8+
replicas: 2
9+
selector:
10+
matchLabels:
11+
app: simple-cluster2
12+
template:
13+
metadata:
14+
labels:
15+
app: simple-cluster2
16+
spec:
17+
containers:
18+
- name: helloworld
19+
image: ghcr.io/pipe-cd/helloworld:v0.1.0
20+
ports:
21+
- containerPort: 9085
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
apiVersion: pipecd.dev/v1beta1
2+
kind: KubernetesApp
3+
spec:
4+
name: simple
5+
plugins:
6+
kubernetes_multicluster:
7+
input:
8+
manifests:
9+
- deployment.yaml
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: simple
5+
labels:
6+
app: simple
7+
spec:
8+
replicas: 2
9+
selector:
10+
matchLabels:
11+
app: simple
12+
template:
13+
metadata:
14+
labels:
15+
app: simple
16+
spec:
17+
containers:
18+
- name: helloworld
19+
image: ghcr.io/pipe-cd/helloworld:v0.1.0
20+
ports:
21+
- containerPort: 9085
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: simple
5+
labels:
6+
app: simple
7+
spec:
8+
replicas: 2
9+
selector:
10+
matchLabels:
11+
app: simple
12+
template:
13+
metadata:
14+
labels:
15+
app: simple
16+
spec:
17+
containers:
18+
- name: helloworld
19+
image: ghcr.io/pipe-cd/helloworld:v0.2.0
20+
ports:
21+
- containerPort: 9085

0 commit comments

Comments
 (0)