Skip to content

Commit 38fc2c3

Browse files
committed
add node deletion test
1 parent 78ec509 commit 38fc2c3

File tree

5 files changed

+191
-4
lines changed

5 files changed

+191
-4
lines changed

api/v1alpha4/zz_generated.conversion.go

-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/v1alpha4/zz_generated.deepcopy.go

-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

exp/api/v1alpha4/zz_generated.conversion.go

-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

exp/api/v1alpha4/zz_generated.deepcopy.go

-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/controllers/machine/machine_controller_test.go

+191
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ limitations under the License.
1717
package machine
1818

1919
import (
20+
"context"
21+
"fmt"
2022
"testing"
2123
"time"
2224

@@ -27,9 +29,11 @@ import (
2729
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2830
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2931
"k8s.io/client-go/kubernetes/scheme"
32+
"k8s.io/client-go/tools/record"
3033
"k8s.io/utils/pointer"
3134
ctrl "sigs.k8s.io/controller-runtime"
3235
"sigs.k8s.io/controller-runtime/pkg/client"
36+
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
3337
"sigs.k8s.io/controller-runtime/pkg/client/fake"
3438
"sigs.k8s.io/controller-runtime/pkg/log"
3539
"sigs.k8s.io/controller-runtime/pkg/reconcile"
@@ -1856,6 +1860,193 @@ func TestNodeToMachine(t *testing.T) {
18561860
}
18571861
}
18581862

1863+
type fakeClientWithNodeDeletionErr struct {
1864+
client.Client
1865+
}
1866+
1867+
func (fc fakeClientWithNodeDeletionErr) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error {
1868+
gvk, err := apiutil.GVKForObject(obj, fakeScheme)
1869+
if err == nil && gvk.Kind == "Node" {
1870+
return fmt.Errorf("fake error")
1871+
}
1872+
return fc.Client.Delete(ctx, obj, opts...)
1873+
}
1874+
1875+
func TestNodeDeletion(t *testing.T) {
1876+
g := NewWithT(t)
1877+
1878+
deletionTime := metav1.Now().Add(-1 * time.Second)
1879+
1880+
testCluster := clusterv1.Cluster{
1881+
ObjectMeta: metav1.ObjectMeta{
1882+
Name: "test-cluster",
1883+
Namespace: metav1.NamespaceDefault,
1884+
},
1885+
}
1886+
1887+
node := &corev1.Node{
1888+
ObjectMeta: metav1.ObjectMeta{
1889+
Name: "test",
1890+
},
1891+
Spec: corev1.NodeSpec{ProviderID: "test://id-1"},
1892+
}
1893+
1894+
testMachine := clusterv1.Machine{
1895+
ObjectMeta: metav1.ObjectMeta{
1896+
Name: "test",
1897+
Namespace: metav1.NamespaceDefault,
1898+
Labels: map[string]string{
1899+
clusterv1.MachineControlPlaneLabelName: "",
1900+
},
1901+
Annotations: map[string]string{
1902+
"machine.cluster.x-k8s.io/exclude-node-draining": "",
1903+
},
1904+
Finalizers: []string{clusterv1.MachineFinalizer},
1905+
DeletionTimestamp: &metav1.Time{Time: deletionTime},
1906+
},
1907+
Spec: clusterv1.MachineSpec{
1908+
ClusterName: "test-cluster",
1909+
InfrastructureRef: corev1.ObjectReference{
1910+
APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1",
1911+
Kind: "GenericInfrastructureMachine",
1912+
Name: "infra-config1",
1913+
},
1914+
Bootstrap: clusterv1.Bootstrap{DataSecretName: pointer.StringPtr("data")},
1915+
},
1916+
Status: clusterv1.MachineStatus{
1917+
NodeRef: &corev1.ObjectReference{
1918+
Name: "test",
1919+
},
1920+
},
1921+
}
1922+
1923+
cpmachine1 := &clusterv1.Machine{
1924+
ObjectMeta: metav1.ObjectMeta{
1925+
Name: "cp1",
1926+
Namespace: metav1.NamespaceDefault,
1927+
Labels: map[string]string{
1928+
clusterv1.ClusterLabelName: "test-cluster",
1929+
clusterv1.MachineControlPlaneLabelName: "",
1930+
},
1931+
Finalizers: []string{clusterv1.MachineFinalizer},
1932+
},
1933+
Spec: clusterv1.MachineSpec{
1934+
ClusterName: "test-cluster",
1935+
InfrastructureRef: corev1.ObjectReference{},
1936+
Bootstrap: clusterv1.Bootstrap{DataSecretName: pointer.StringPtr("data")},
1937+
},
1938+
Status: clusterv1.MachineStatus{
1939+
NodeRef: &corev1.ObjectReference{
1940+
Name: "cp1",
1941+
},
1942+
},
1943+
}
1944+
1945+
testCases := []struct {
1946+
name string
1947+
deletionTimeout *metav1.Duration
1948+
resultErr bool
1949+
clusterDeleted bool
1950+
expectNodeDeletion bool
1951+
createFakeClient func(...client.Object) client.Client
1952+
}{
1953+
{
1954+
name: "should return no error when deletion is successful",
1955+
deletionTimeout: &metav1.Duration{Duration: time.Second},
1956+
resultErr: false,
1957+
expectNodeDeletion: true,
1958+
createFakeClient: func(initObjs ...client.Object) client.Client {
1959+
return fake.NewClientBuilder().
1960+
WithObjects(initObjs...).
1961+
Build()
1962+
},
1963+
},
1964+
{
1965+
name: "should return an error when timeout is not expired and node deletion fails",
1966+
deletionTimeout: &metav1.Duration{Duration: time.Hour},
1967+
resultErr: true,
1968+
expectNodeDeletion: false,
1969+
createFakeClient: func(initObjs ...client.Object) client.Client {
1970+
fc := fake.NewClientBuilder().
1971+
WithObjects(initObjs...).
1972+
Build()
1973+
return fakeClientWithNodeDeletionErr{fc}
1974+
},
1975+
},
1976+
{
1977+
name: "should return an error when timeout is infinite and node deletion fails",
1978+
deletionTimeout: &metav1.Duration{Duration: 0}, // should lead to infinite timeout
1979+
resultErr: true,
1980+
expectNodeDeletion: false,
1981+
createFakeClient: func(initObjs ...client.Object) client.Client {
1982+
fc := fake.NewClientBuilder().
1983+
WithObjects(initObjs...).
1984+
Build()
1985+
return fakeClientWithNodeDeletionErr{fc}
1986+
},
1987+
},
1988+
{
1989+
name: "should not return an error when timeout is expired and node deletion fails",
1990+
deletionTimeout: &metav1.Duration{Duration: time.Millisecond},
1991+
resultErr: false,
1992+
expectNodeDeletion: false,
1993+
createFakeClient: func(initObjs ...client.Object) client.Client {
1994+
fc := fake.NewClientBuilder().
1995+
WithObjects(initObjs...).
1996+
Build()
1997+
return fakeClientWithNodeDeletionErr{fc}
1998+
},
1999+
},
2000+
{
2001+
name: "should not delete the node or return an error when the cluster is marked for deletion",
2002+
deletionTimeout: nil, // should lead to infinite timeout
2003+
resultErr: false,
2004+
clusterDeleted: true,
2005+
expectNodeDeletion: false,
2006+
createFakeClient: func(initObjs ...client.Object) client.Client {
2007+
fc := fake.NewClientBuilder().
2008+
WithObjects(initObjs...).
2009+
Build()
2010+
return fakeClientWithNodeDeletionErr{fc}
2011+
},
2012+
},
2013+
}
2014+
2015+
for _, tc := range testCases {
2016+
t.Run(tc.name, func(t *testing.T) {
2017+
m := testMachine.DeepCopy()
2018+
m.Spec.NodeDeletionTimeout = tc.deletionTimeout
2019+
2020+
fakeClient := tc.createFakeClient(node, m, cpmachine1)
2021+
tracker := remote.NewTestClusterCacheTracker(ctrl.Log, fakeClient, fakeScheme, client.ObjectKeyFromObject(&testCluster))
2022+
2023+
r := &Reconciler{
2024+
Client: fakeClient,
2025+
Tracker: tracker,
2026+
recorder: record.NewFakeRecorder(10),
2027+
nodeDeletionRetryTimeout: 10 * time.Millisecond,
2028+
}
2029+
2030+
cluster := testCluster.DeepCopy()
2031+
if tc.clusterDeleted {
2032+
cluster.DeletionTimestamp = &metav1.Time{Time: deletionTime.Add(time.Hour)}
2033+
}
2034+
2035+
_, err := r.reconcileDelete(context.Background(), cluster, m)
2036+
2037+
if tc.resultErr {
2038+
g.Expect(err).To(HaveOccurred())
2039+
} else {
2040+
g.Expect(err).NotTo(HaveOccurred())
2041+
if tc.expectNodeDeletion {
2042+
n := &corev1.Node{}
2043+
g.Expect(fakeClient.Get(context.Background(), client.ObjectKeyFromObject(node), n)).NotTo(Succeed())
2044+
}
2045+
}
2046+
})
2047+
}
2048+
}
2049+
18592050
// adds a condition list to an external object.
18602051
func addConditionsToExternal(u *unstructured.Unstructured, newConditions clusterv1.Conditions) {
18612052
existingConditions := clusterv1.Conditions{}

0 commit comments

Comments
 (0)