Skip to content

Commit e420024

Browse files
committed
** Added tests for compute -> firewalls, subnets, network
1 parent 2b06e8c commit e420024

File tree

3 files changed

+805
-0
lines changed

3 files changed

+805
-0
lines changed
Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
/*
2+
Copyright 2022 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package firewalls
18+
19+
import (
20+
"context"
21+
"fmt"
22+
"google.golang.org/api/googleapi"
23+
"net/http"
24+
"testing"
25+
26+
"github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud"
27+
"github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud/meta"
28+
"google.golang.org/api/compute/v1"
29+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30+
"k8s.io/client-go/kubernetes/scheme"
31+
"k8s.io/utils/ptr"
32+
infrav1 "sigs.k8s.io/cluster-api-provider-gcp/api/v1beta1"
33+
"sigs.k8s.io/cluster-api-provider-gcp/cloud/scope"
34+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
35+
"sigs.k8s.io/controller-runtime/pkg/client/fake"
36+
)
37+
38+
func init() {
39+
_ = clusterv1.AddToScheme(scheme.Scheme)
40+
_ = infrav1.AddToScheme(scheme.Scheme)
41+
}
42+
43+
var fakeCluster = &clusterv1.Cluster{
44+
ObjectMeta: metav1.ObjectMeta{
45+
Name: "my-cluster",
46+
Namespace: "default",
47+
},
48+
Spec: clusterv1.ClusterSpec{},
49+
}
50+
51+
var fakeGCPCluster = &infrav1.GCPCluster{
52+
ObjectMeta: metav1.ObjectMeta{
53+
Name: "my-cluster",
54+
Namespace: "default",
55+
},
56+
Spec: infrav1.GCPClusterSpec{
57+
Project: "my-proj",
58+
Region: "us-central1",
59+
Network: infrav1.NetworkSpec{
60+
Name: ptr.To("my-network"),
61+
Subnets: infrav1.Subnets{
62+
infrav1.SubnetSpec{
63+
Name: "workers",
64+
CidrBlock: "10.0.0.1/28",
65+
Region: "us-central1",
66+
Purpose: ptr.To[string]("INTERNAL_HTTPS_LOAD_BALANCER"),
67+
},
68+
},
69+
},
70+
},
71+
Status: infrav1.GCPClusterStatus{
72+
Network: infrav1.Network{
73+
FirewallRules: map[string]string{
74+
"my-cluster-apiserver": "test",
75+
"my-cluster-apiintserver": "test",
76+
},
77+
},
78+
},
79+
}
80+
81+
var fakeGCPClusterSharedVPC = &infrav1.GCPCluster{
82+
ObjectMeta: metav1.ObjectMeta{
83+
Name: "my-cluster",
84+
Namespace: "default",
85+
},
86+
Spec: infrav1.GCPClusterSpec{
87+
Project: "my-proj",
88+
Region: "us-central1",
89+
Network: infrav1.NetworkSpec{
90+
HostProject: ptr.To("my-shared-vpc-project"),
91+
Name: ptr.To("my-network"),
92+
Subnets: infrav1.Subnets{
93+
infrav1.SubnetSpec{
94+
Name: "workers",
95+
CidrBlock: "10.0.0.1/28",
96+
Region: "us-central1",
97+
Purpose: ptr.To[string]("INTERNAL_HTTPS_LOAD_BALANCER"),
98+
},
99+
},
100+
},
101+
},
102+
Status: infrav1.GCPClusterStatus{
103+
Network: infrav1.Network{
104+
FirewallRules: map[string]string{
105+
"my-cluster-apiserver": "test",
106+
"my-cluster-apiintserver": "test",
107+
},
108+
},
109+
},
110+
}
111+
112+
//func getSharedVPCCluster() *infrav1.GCPCluster {
113+
// fakeGCPClusterSharedVPC := fakeGCPCluster
114+
// fakeGCPClusterSharedVPC.Spec.Network.HostProject = ptr.To("my-shared-vpc-project")
115+
// return fakeGCPClusterSharedVPC
116+
//}
117+
118+
type testCase struct {
119+
name string
120+
scope func() Scope
121+
mockFirewalls *cloud.MockFirewalls
122+
wantErr bool
123+
assert func(ctx context.Context, t testCase) error
124+
}
125+
126+
func TestService_Reconcile(t *testing.T) {
127+
fakec := fake.NewClientBuilder().
128+
WithScheme(scheme.Scheme).
129+
Build()
130+
131+
clusterScope, err := scope.NewClusterScope(context.TODO(), scope.ClusterScopeParams{
132+
Client: fakec,
133+
Cluster: fakeCluster,
134+
GCPCluster: fakeGCPCluster,
135+
GCPServices: scope.GCPServices{
136+
Compute: &compute.Service{},
137+
},
138+
})
139+
if err != nil {
140+
t.Fatal(err)
141+
}
142+
143+
//fakeGCPClusterSharedVPC := getSharedVPCCluster()
144+
clusterScopeSharedVpc, err := scope.NewClusterScope(context.TODO(), scope.ClusterScopeParams{
145+
Client: fakec,
146+
Cluster: fakeCluster,
147+
GCPCluster: fakeGCPClusterSharedVPC,
148+
GCPServices: scope.GCPServices{
149+
Compute: &compute.Service{},
150+
},
151+
})
152+
if err != nil {
153+
t.Fatal(err)
154+
}
155+
156+
tests := []testCase{
157+
{
158+
name: "firewall rule already exist (should return existing firewall rule)",
159+
scope: func() Scope { return clusterScope },
160+
mockFirewalls: &cloud.MockFirewalls{
161+
ProjectRouter: &cloud.SingleProjectRouter{ID: "my-proj"},
162+
Objects: map[meta.Key]*cloud.MockFirewallsObj{
163+
*meta.GlobalKey(fmt.Sprintf("allow-%s-healthchecks", *fakeGCPCluster.Spec.Network.Name)): {},
164+
},
165+
},
166+
},
167+
{
168+
name: "error getting instance with non 404 error code (should return an error)",
169+
scope: func() Scope { return clusterScope },
170+
mockFirewalls: &cloud.MockFirewalls{
171+
ProjectRouter: &cloud.SingleProjectRouter{ID: "my-proj"},
172+
Objects: map[meta.Key]*cloud.MockFirewallsObj{},
173+
GetHook: func(ctx context.Context, key *meta.Key, m *cloud.MockFirewalls) (bool, *compute.Firewall, error) {
174+
return true, &compute.Firewall{}, &googleapi.Error{Code: http.StatusBadRequest}
175+
},
176+
},
177+
wantErr: true,
178+
},
179+
//{
180+
// name: "subnet does not exist (should create subnet)",
181+
// scope: func() Scope { return clusterScope },
182+
// mockSubnetworks: &cloud.MockSubnetworks{
183+
// ProjectRouter: &cloud.SingleProjectRouter{ID: "my-proj"},
184+
// Objects: map[meta.Key]*cloud.MockSubnetworksObj{},
185+
// },
186+
// assert: func(ctx context.Context, t testCase) error {
187+
// key := meta.RegionalKey(fakeGCPCluster.Spec.Network.Subnets[0].Name, fakeGCPCluster.Spec.Region)
188+
// subnet, err := t.mockSubnetworks.Get(ctx, key)
189+
// if err != nil {
190+
// return err
191+
// }
192+
//
193+
// if subnet.Name != fakeGCPCluster.Spec.Network.Subnets[0].Name ||
194+
// subnet.IpCidrRange != fakeGCPCluster.Spec.Network.Subnets[0].CidrBlock ||
195+
// subnet.Purpose != *fakeGCPCluster.Spec.Network.Subnets[0].Purpose {
196+
// return errors.New("subnet was created but with wrong values")
197+
// }
198+
//
199+
// return nil
200+
// },
201+
//},
202+
{
203+
name: "firewall rule creation fails (should return an error)",
204+
scope: func() Scope { return clusterScope },
205+
mockFirewalls: &cloud.MockFirewalls{
206+
ProjectRouter: &cloud.SingleProjectRouter{ID: "my-proj"},
207+
Objects: map[meta.Key]*cloud.MockFirewallsObj{},
208+
GetHook: func(ctx context.Context, key *meta.Key, m *cloud.MockFirewalls) (bool, *compute.Firewall, error) {
209+
return true, &compute.Firewall{}, &googleapi.Error{Code: http.StatusNotFound}
210+
},
211+
InsertError: map[meta.Key]error{
212+
*meta.GlobalKey(fmt.Sprintf("allow-%s-healthchecks", *fakeGCPCluster.Spec.Network.Name)): &googleapi.Error{Code: http.StatusNotFound},
213+
},
214+
},
215+
wantErr: false,
216+
},
217+
{
218+
name: "firewall return no error using shared vpc",
219+
scope: func() Scope { return clusterScopeSharedVpc },
220+
mockFirewalls: &cloud.MockFirewalls{
221+
ProjectRouter: &cloud.SingleProjectRouter{ID: "my-proj"},
222+
Objects: map[meta.Key]*cloud.MockFirewallsObj{
223+
*meta.GlobalKey(fmt.Sprintf("allow-%s-healthchecks", *fakeGCPCluster.Spec.Network.Name)): {},
224+
},
225+
},
226+
},
227+
}
228+
for _, tt := range tests {
229+
t.Run(tt.name, func(t *testing.T) {
230+
ctx := context.TODO()
231+
s := New(tt.scope())
232+
s.firewalls = tt.mockFirewalls
233+
err := s.Reconcile(ctx)
234+
if (err != nil) != tt.wantErr {
235+
t.Errorf("Service.Reconcile() error = %v, wantErr %v", err, tt.wantErr)
236+
return
237+
}
238+
if tt.assert != nil {
239+
err = tt.assert(ctx, tt)
240+
if err != nil {
241+
t.Errorf("firewall rule was not created as expected: %v", err)
242+
return
243+
}
244+
}
245+
})
246+
}
247+
}
248+
249+
//func TestService_Delete(t *testing.T) {
250+
// fakec := fake.NewClientBuilder().
251+
// WithScheme(scheme.Scheme).
252+
// Build()
253+
//
254+
// clusterScope, err := scope.NewClusterScope(context.TODO(), scope.ClusterScopeParams{
255+
// Client: fakec,
256+
// Cluster: fakeCluster,
257+
// GCPCluster: fakeGCPCluster,
258+
// GCPServices: scope.GCPServices{
259+
// Compute: &compute.Service{},
260+
// },
261+
// })
262+
// if err != nil {
263+
// t.Fatal(err)
264+
// }
265+
//
266+
// fakeGCPClusterSharedVPC := getSharedVPCCluster()
267+
// clusterScopeSharedVpc, err := scope.NewClusterScope(context.TODO(), scope.ClusterScopeParams{
268+
// Client: fakec,
269+
// Cluster: fakeCluster,
270+
// GCPCluster: fakeGCPClusterSharedVPC,
271+
// GCPServices: scope.GCPServices{
272+
// Compute: &compute.Service{},
273+
// },
274+
// })
275+
// if err != nil {
276+
// t.Fatal(err)
277+
// }
278+
//
279+
// tests := []testCase{
280+
// {
281+
// name: "subnet does not exist, should do nothing",
282+
// scope: func() Scope { return clusterScope },
283+
// mockSubnetworks: &cloud.MockSubnetworks{
284+
// ProjectRouter: &cloud.SingleProjectRouter{ID: "my-proj"},
285+
// DeleteError: map[meta.Key]error{
286+
// *meta.RegionalKey(fakeGCPCluster.Spec.Network.Subnets[0].Name, fakeGCPCluster.Spec.Region): &googleapi.Error{Code: http.StatusNotFound},
287+
// },
288+
// },
289+
// },
290+
// {
291+
// name: "error deleting subnet, should return error",
292+
// scope: func() Scope { return clusterScope },
293+
// mockSubnetworks: &cloud.MockSubnetworks{
294+
// ProjectRouter: &cloud.SingleProjectRouter{ID: "my-proj"},
295+
// DeleteError: map[meta.Key]error{
296+
// *meta.RegionalKey(fakeGCPCluster.Spec.Network.Subnets[0].Name, fakeGCPCluster.Spec.Region): &googleapi.Error{Code: http.StatusBadRequest},
297+
// },
298+
// },
299+
// wantErr: true,
300+
// },
301+
// {
302+
// name: "subnet deletion with shared vpc",
303+
// scope: func() Scope { return clusterScopeSharedVpc },
304+
// mockSubnetworks: &cloud.MockSubnetworks{
305+
// ProjectRouter: &cloud.SingleProjectRouter{ID: "my-proj"},
306+
// DeleteError: map[meta.Key]error{
307+
// *meta.RegionalKey(fakeGCPCluster.Spec.Network.Subnets[0].Name, fakeGCPCluster.Spec.Region): &googleapi.Error{Code: http.StatusNotFound},
308+
// },
309+
// },
310+
// },
311+
// }
312+
// for _, tt := range tests {
313+
// t.Run(tt.name, func(t *testing.T) {
314+
// ctx := context.TODO()
315+
// s := New(tt.scope())
316+
// s.subnets = tt.mockSubnetworks
317+
// err := s.Delete(ctx)
318+
// if (err != nil) != tt.wantErr {
319+
// t.Errorf("Service.Delete() error = %v, wantErr %v", err, tt.wantErr)
320+
// return
321+
// }
322+
// })
323+
// }
324+
//}

0 commit comments

Comments
 (0)