Repository: gardener/machine-controller-manager

Issue:
Cleanup after IT is not working properly

**What happened**

/area testing
/kind bug
/priority 2

When we run the IT for mcm-providers in the pipeline, the machine resources are not cleaned up if the MC process fails to run. The logs show that the resources are cleaned up :- 
```
STEP: Running Cleanup
STEP: Restarting Machine Controller 
2023/02/20 13:50:56 deleting test-machine-deployment
2023/02/20 14:05:56 machines.machine.sapcloud.io "test-machine" not found
2023/02/20 14:05:56 deleting test-mc-v1 machineclass
2023/02/20 14:20:56 deleting test-mc-v2 machineclass
2023/02/20 14:20:56 machineclass deleted
2023/02/20 14:20:56 Deleting crds
2023/02/20 14:20:56 ../../../dev/mcm/kubernetes/crds is a directory.
2023/02/20 14:20:56 resource ../../../dev/mcm/kubernetes/crds/machine.sapcloud.io_machineclasses.yaml has been successfully removed from the cluster
2023/02/20 14:20:56 resource ../../../dev/mcm/kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml has been successfully removed from the cluster
2023/02/20 14:20:56 resource ../../../dev/mcm/kubernetes/crds/machine.sapcloud.io_machines.yaml has been successfully removed from the cluster
2023/02/20 14:20:56 resource ../../../dev/mcm/kubernetes/crds/machine.sapcloud.io_machinesets.yaml has been successfully removed from the cluster
2023/02/20 14:20:56 resource ../../../dev/mcm/kubernetes/crds/machine.sapcloud.io_scales.yaml has been successfully removed from the cluster
```

There is deletion timestamp on the machine resources, but we are not waiting for them to be deleted. 
```
k get mc                                                           
NAME                                  STATUS        AGE    NODE
test-machine-deployment-76d4d-787g2   Terminating   2d1h   izgw86khdplvsoa10rik6qz
test-machine-deployment-76d4d-jcc6k   Terminating   2d1h   izgw88ckciy38niobf9u6yz
test-machine-deployment-76d4d-mzbcz   Terminating   2d1h   izgw88ckciy38niobf9u6zz
```

The above issue was encountered in the mcm-provider-alicloud pipeline, where the MC process stopped between the tests. The error code returned by the process was `2` . The error comes at https://github.com/gardener/machine-controller-manager/blob/d98eddffa3ef7a00ff6aaa753366c59bae881608/pkg/test/integration/common/framework.go#L814 
I am not sure why the process stopped in between the tests. There were no logs captured for MC.

**What you expected to happen**:
The machine resources should be cleaned up.

**How to reproduce it (as minimally and precisely as possible)**:

**Anything else we need to know?**:

**Environment**:

- Kubernetes version (use `kubectl version`):
- Cloud provider or hardware configuration:
- Others:

Hints from issue comments:

Solution patch:
diff --git a/.ci/test b/.ci/test
index d13330b9d..a496c4fec 100755
--- a/.ci/test
+++ b/.ci/test
@@ -36,7 +36,7 @@ function test_with_coverage() {
   local output_dir=test/output
   local coverprofile_file=coverprofile.out
   mkdir -p test/output
-  ginkgo $GINKGO_COMMON_FLAGS --coverprofile ${coverprofile_file} -covermode=set -outputdir ${output_dir} ${TEST_PACKAGES}
+  ginkgo $GINKGO_COMMON_FLAGS --coverprofile ${coverprofile_file} -covermode=set -output-dir ${output_dir} ${TEST_PACKAGES}
 
   sed -i -e '/mode: set/d' ${output_dir}/${coverprofile_file}
   {( echo "mode: set"; cat ${output_dir}/${coverprofile_file} )} > ${output_dir}/${coverprofile_file}.temp
@@ -51,7 +51,7 @@ if [[ "${SKIP_UNIT_TESTS}" != "" ]]; then
 else
   echo ">>>>> Invoking unit tests"
   TEST_PACKAGES="cmd pkg"
-  GINKGO_COMMON_FLAGS="-r -timeout=1h0m0s --randomizeAllSpecs --randomizeSuites --failOnPending  --progress"
+  GINKGO_COMMON_FLAGS="-r -timeout=1h0m0s --randomize-all --randomize-suites --fail-on-pending  --show-node-events"
   test_with_coverage
   echo ">>>>> Finished executing unit tests"
 fi
diff --git a/docs/FAQ.md b/docs/FAQ.md
index b492b5069..b4bbd6de7 100644
--- a/docs/FAQ.md
+++ b/docs/FAQ.md
@@ -1,6 +1,8 @@
 ---
-title: Machine Controller Manager FAQ
+title: FAQ
 description: Commonly asked questions about MCM
+weight: 5
+persona: Operators
 ---
 
 # Frequently Asked Questions
diff --git a/docs/documents/_index.md b/docs/documents/_index.md
new file mode 100644
index 000000000..bdfec1968
--- /dev/null
+++ b/docs/documents/_index.md
@@ -0,0 +1,5 @@
+---
+title: Documents
+weight: 2
+persona: Developers
+---
\ No newline at end of file
diff --git a/docs/proposals/_index.md b/docs/proposals/_index.md
new file mode 100644
index 000000000..970c379bb
--- /dev/null
+++ b/docs/proposals/_index.md
@@ -0,0 +1,5 @@
+---
+title: Proposals
+weight: 3
+persona: Developers
+---
\ No newline at end of file
diff --git a/docs/todo/_index.md b/docs/todo/_index.md
new file mode 100644
index 000000000..930e852f8
--- /dev/null
+++ b/docs/todo/_index.md
@@ -0,0 +1,5 @@
+---
+title: To-Do
+weight: 4
+persona: Developers
+---
\ No newline at end of file
diff --git a/go.mod b/go.mod
index a6969079b..e9a5ce81e 100644
--- a/go.mod
+++ b/go.mod
@@ -7,8 +7,8 @@ require (
 	github.com/cenkalti/backoff/v4 v4.3.0
 	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
 	github.com/google/uuid v1.6.0
-	github.com/onsi/ginkgo/v2 v2.19.0
-	github.com/onsi/gomega v1.33.1
+	github.com/onsi/ginkgo/v2 v2.23.0
+	github.com/onsi/gomega v1.36.2
 	github.com/prometheus/client_golang v1.19.1
 	github.com/spf13/pflag v1.0.5
 	golang.org/x/lint v0.0.0-20210508222113-6edffad5e616
@@ -43,7 +43,7 @@ require (
 	github.com/google/gnostic-models v0.6.8 // indirect
 	github.com/google/go-cmp v0.6.0 // indirect
 	github.com/google/gofuzz v1.2.0 // indirect
-	github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af // indirect
+	github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect
 	github.com/imdario/mergo v0.3.12 // indirect
 	github.com/inconshreveable/mousetrap v1.1.0 // indirect
 	github.com/josharian/intern v1.0.0 // indirect
@@ -58,16 +58,16 @@ require (
 	github.com/prometheus/procfs v0.15.1 // indirect
 	github.com/spf13/cobra v1.8.1 // indirect
 	github.com/x448/float16 v0.8.4 // indirect
-	golang.org/x/mod v0.17.0 // indirect
-	golang.org/x/net v0.26.0 // indirect
+	golang.org/x/mod v0.23.0 // indirect
+	golang.org/x/net v0.35.0 // indirect
 	golang.org/x/oauth2 v0.21.0 // indirect
-	golang.org/x/sync v0.7.0 // indirect
-	golang.org/x/sys v0.21.0 // indirect
-	golang.org/x/term v0.21.0 // indirect
-	golang.org/x/text v0.16.0 // indirect
+	golang.org/x/sync v0.11.0 // indirect
+	golang.org/x/sys v0.30.0 // indirect
+	golang.org/x/term v0.29.0 // indirect
+	golang.org/x/text v0.22.0 // indirect
 	golang.org/x/time v0.3.0 // indirect
-	golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
-	google.golang.org/protobuf v1.34.2 // indirect
+	golang.org/x/tools v0.30.0 // indirect
+	google.golang.org/protobuf v1.36.1 // indirect
 	gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
diff --git a/go.sum b/go.sum
index 4ca168c08..4eee5a452 100644
--- a/go.sum
+++ b/go.sum
@@ -45,8 +45,8 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
 github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM=
-github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
+github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
+github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
 github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
@@ -75,10 +75,10 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
-github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
-github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
-github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
-github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
+github.com/onsi/ginkgo/v2 v2.23.0 h1:FA1xjp8ieYDzlgS5ABTpdUDB7wtngggONc8a7ku2NqQ=
+github.com/onsi/ginkgo/v2 v2.23.0/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM=
+github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
+github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -126,32 +126,32 @@ golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPI
 golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
-golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
+golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
-golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
+golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
+golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
 golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
 golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
-golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
+golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
-golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
-golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
+golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
+golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
+golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
-golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
+golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
+golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
 golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
 golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -159,14 +159,14 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
 golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
-golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
+golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
+golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
-google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
+google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
+google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
diff --git a/pkg/controller/machine_safety.go b/pkg/controller/machine_safety.go
index ffe330001..0f17f367f 100644
--- a/pkg/controller/machine_safety.go
+++ b/pkg/controller/machine_safety.go
@@ -9,6 +9,7 @@ import (
 	"context"
 	"fmt"
 
+	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/labels"
 	intstrutil "k8s.io/apimachinery/pkg/util/intstr"
@@ -26,6 +27,10 @@ const (
 	MachineDeploymentStateSync = "MachineDeploymentStateSync"
 	// UnfreezeAnnotation indicates the controllers to unfreeze this object
 	UnfreezeAnnotation = "safety.machine.sapcloud.io/unfreeze"
+	// MachineSetFreezeEvent is recorded when a machineset is frozen
+	MachineSetFreezeEvent = "FrozeMachineSet"
+	// MachineSetUnfreezeEvent is recorded when a machineset is unfrozen
+	MachineSetUnfreezeEvent = "UnfrozeMachineSet"
 )
 
 // reconcileClusterMachineSafetyOvershooting checks all machineSet/machineDeployment
@@ -330,6 +335,7 @@ func (c *controller) freezeMachineSetAndDeployment(ctx context.Context, machineS
 		}
 	}
 
+	c.recorder.Eventf(machineSet, corev1.EventTypeNormal, MachineSetFreezeEvent, "SafetyController: Froze MachineSet %s due to replica overshooting", machineSet.Name)
 	klog.V(2).Infof("SafetyController: Froze MachineSet %q due to overshooting of replicas", machineSet.Name)
 	return nil
 }
@@ -398,6 +404,7 @@ func (c *controller) unfreezeMachineSet(ctx context.Context, machineSet *v1alpha
 		return err
 	}
 
+	c.recorder.Eventf(machineSet, corev1.EventTypeNormal, MachineSetUnfreezeEvent, "SafetyController: Unfroze MachineSet %s", machineSet.Name)
 	klog.V(2).Infof("SafetyController: Unfroze MachineSet %q", machineSet.Name)
 	return nil
 }



Test patch:
diff --git a/pkg/test/integration/common/framework.go b/pkg/test/integration/common/framework.go
index f71d0a615..ae6bcb6d3 100644
--- a/pkg/test/integration/common/framework.go
+++ b/pkg/test/integration/common/framework.go
@@ -5,26 +5,27 @@
 package common
 
 import (
+	"bufio"
+	"bytes"
 	"context"
 	"encoding/json"
 	"fmt"
-	"github.com/gardener/machine-controller-manager/pkg/controller"
-	"io"
 	"log"
 	"os"
 	"os/exec"
+	"path"
 	"path/filepath"
-	"regexp"
 	"strconv"
 	"strings"
 	"time"
 
+	"github.com/gardener/machine-controller-manager/pkg/controller"
+
 	"github.com/onsi/ginkgo/v2"
 
 	"github.com/onsi/gomega"
 	"github.com/onsi/gomega/gexec"
 	appsV1 "k8s.io/api/apps/v1"
-	coreV1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/apimachinery/pkg/watch"
@@ -37,6 +38,8 @@ import (
 
 const (
 	dwdIgnoreScalingAnnotation = "dependency-watchdog.gardener.cloud/ignore-scaling"
+	testMachineDeploymentName  = "test-machine-deployment"
+	testMachineName            = "test-machine"
 )
 
 var (
@@ -98,6 +101,12 @@ var (
 
 	//values for gardener-node-agent-secret-name
 	gnaSecretNameLabelValue = os.Getenv("GNA_SECRET_NAME")
+
+	// Specifies whether the CRDs should be preserved during cleanup at the end
+	preserveCRDDuringCleanup = os.Getenv("PRESERVE_CRD_AT_END")
+
+	// Are the tests running for the virtual provider
+	isVirtualProvider = os.Getenv("IS_VIRTUAL_PROVIDER")
 )
 
 // ProviderSpecPatch struct holds tags for provider, which we want to patch the  machineclass with
@@ -227,226 +236,6 @@ func (c *IntegrationTestFramework) initalizeClusters() error {
 	return nil
 }
 
-func (c *IntegrationTestFramework) prepareMcmDeployment(
-
-	mcContainerImage string,
-	mcmContainerImage string,
-	byCreating bool) error {
-
-	ctx := context.Background()
-
-	if len(machineControllerManagerDeploymentName) == 0 {
-		machineControllerManagerDeploymentName = "machine-controller-manager"
-	}
-
-	if byCreating {
-		// Create clusterroles and clusterrolebindings for control and target cluster
-		// Create secret containing target kubeconfig file
-		// Create machine-deployment using the yaml file
-		controlClusterRegexp, _ := regexp.Compile("control-cluster-role")
-		targetClusterRegexp, _ := regexp.Compile("target-cluster-role")
-		log.Printf("Creating required roles and rolebinginds")
-
-		err := filepath.Walk(
-			filepath.Join(
-				mcmRepoPath,
-				"kubernetes/deployment/out-of-tree/",
-			),
-			func(
-				path string,
-				info os.FileInfo,
-				err error,
-			) error {
-
-				if err != nil {
-					return err
-				}
-
-				if !info.IsDir() {
-					if controlClusterRegexp.MatchString(info.Name()) {
-						err = c.
-							ControlCluster.
-							ApplyFiles(
-								path,
-								controlClusterNamespace,
-							)
-					} else if targetClusterRegexp.MatchString(info.Name()) {
-						err = c.
-							TargetCluster.
-							ApplyFiles(
-								path,
-								"default",
-							)
-					}
-				}
-				return err
-			})
-
-		if err != nil {
-			return err
-		}
-
-		configFile, _ := os.ReadFile(c.TargetCluster.KubeConfigFilePath)
-		if _, err := c.ControlCluster.Clientset.
-			CoreV1().
-			Secrets(controlClusterNamespace).
-			Create(ctx,
-				&coreV1.Secret{
-					ObjectMeta: metav1.ObjectMeta{
-						Name: "machine-controller-manager",
-					},
-					Data: map[string][]byte{
-						"kubeconfig": configFile,
-					},
-					Type: coreV1.SecretTypeOpaque,
-				},
-				metav1.CreateOptions{},
-			); err != nil {
-			return err
-		}
-
-		if err := c.ControlCluster.
-			ApplyFiles(
-				"../../../kubernetes/deployment.yaml",
-				controlClusterNamespace,
-			); err != nil {
-			return err
-		}
-	}
-
-	// mcmDeploymentOrigObj holds a copy of original mcm deployment
-	result, getErr := c.ControlCluster.Clientset.
-		AppsV1().
-		Deployments(controlClusterNamespace).
-		Get(ctx, machineControllerManagerDeploymentName, metav1.GetOptions{})
-
-	if getErr != nil {
-		log.Printf("failed to get latest version of Deployment: %v", getErr)
-		return getErr
-	}
-
-	mcmDeploymentOrigObj = result
-
-	// update containers spec
-	providerSpecificRegexp, _ := regexp.Compile(mcContainerPrefix)
-
-	containers := mcmDeploymentOrigObj.Spec.Template.Spec.Containers
-
-	for i := range containers {
-		if providerSpecificRegexp.MatchString(containers[i].Image) {
-			// set container image to mcContainerImageTag as the name of the container contains provider
-			if len(mcContainerImage) != 0 {
-				containers[i].Image = mcContainerImage
-				var isOptionAvailable bool
-				for option := range containers[i].Command {
-					if strings.Contains(containers[i].Command[option], "machine-drain-timeout=") {
-						isOptionAvailable = true
-						containers[i].Command[option] = "--machine-drain-timeout=5m"
-					}
-				}
-				if !isOptionAvailable {
-					containers[i].Command = append(containers[i].Command, "--machine-drain-timeout=5m")
-				}
-			}
-		} else {
-			// set container image to mcmContainerImageTag as the name of container contains provider
-			if len(mcmContainerImage) != 0 {
-				containers[i].Image = mcmContainerImage
-			}
-
-			// set machine-safety-overshooting-period to 300ms for freeze check to succeed
-			var isOptionAvailable bool
-			for option := range containers[i].Command {
-				if strings.Contains(containers[i].Command[option], "machine-safety-overshooting-period=") {
-					isOptionAvailable = true
-					containers[i].Command[option] = "--machine-safety-overshooting-period=300ms"
-				}
-			}
-			if !isOptionAvailable {
-				containers[i].Command = append(containers[i].Command, "--machine-safety-overshooting-period=300ms")
-			}
-		}
-	}
-
-	// apply updated containers spec to mcmDeploymentObj in kubernetes cluster
-	retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error {
-		// Retrieve the latest version of Deployment before attempting to update
-		// RetryOnConflict uses exponential backoff to avoid exhausting the apiserver
-
-		mcmDeployment, getErr := c.ControlCluster.Clientset.
-			AppsV1().
-			Deployments(controlClusterNamespace).
-			Get(ctx,
-				machineControllerManagerDeploymentName,
-				metav1.GetOptions{},
-			)
-
-		if getErr != nil {
-			log.Printf("failed to get latest version of Deployment: %v", getErr)
-			return getErr
-		}
-
-		mcmDeployment.Spec.Template.Spec.Containers = containers
-		_, updateErr := c.ControlCluster.Clientset.
-			AppsV1().
-			Deployments(controlClusterNamespace).
-			Update(ctx, mcmDeployment, metav1.UpdateOptions{})
-		return updateErr
-	})
-
-	ginkgo.By("Checking controllers are ready in kubernetes cluster")
-	gomega.Eventually(
-		func() error {
-			deployment, err := c.ControlCluster.Clientset.
-				AppsV1().
-				Deployments(controlClusterNamespace).
-				Get(ctx,
-					machineControllerManagerDeploymentName,
-					metav1.GetOptions{},
-				)
-			if err != nil {
-				return err
-			}
-			if deployment.Status.ReadyReplicas == 1 {
-				pods, err := c.ControlCluster.Clientset.
-					CoreV1().
-					Pods(controlClusterNamespace).
-					List(
-						ctx,
-						metav1.ListOptions{
-							LabelSelector: "role=machine-controller-manager",
-						},
-					)
-				if err != nil {
-					return err
-				}
-				podsCount := len(pods.Items)
-				readyPods := 0
-				for _, pod := range pods.Items {
-					if len(pod.Status.ContainerStatuses) < 2 {
-						return fmt.Errorf("containers(s) not ready")
-					}
-					if !pod.Status.ContainerStatuses[0].Ready {
-						return fmt.Errorf("containers(s) not ready.\n%s", pod.Status.ContainerStatuses[0].State.String())
-					}
-					if !pod.Status.ContainerStatuses[1].Ready {
-						return fmt.Errorf("container(s) not ready.\n%s", pod.Status.ContainerStatuses[1].State.String())
-					}
-					readyPods++
-				}
-				if podsCount == readyPods {
-					return nil
-				}
-			}
-			return fmt.Errorf("deployment replicas are not ready.\n%s", deployment.Status.String())
-		},
-		c.timeout,
-		c.pollingInterval).
-		Should(gomega.BeNil())
-
-	return retryErr
-}
-
 func (c *IntegrationTestFramework) scaleMcmDeployment(replicas int32) error {
 
 	ctx := context.Background()
@@ -601,6 +390,7 @@ func (c *IntegrationTestFramework) setupMachineClass() error {
 							Labels:      machineClasses.Items[0].ObjectMeta.Labels,
 							Annotations: machineClasses.Items[0].ObjectMeta.Annotations,
 						},
+						NodeTemplate:         machineClasses.Items[0].NodeTemplate, // virtual
 						ProviderSpec:         machineClasses.Items[0].ProviderSpec,
 						SecretRef:            machineClasses.Items[0].SecretRef,
 						CredentialsSecretRef: machineClasses.Items[0].CredentialsSecretRef,
@@ -765,31 +555,26 @@ func (c *IntegrationTestFramework) runControllersLocally() {
 func (c *IntegrationTestFramework) SetupBeforeSuite() {
 	ctx := context.Background()
 	log.SetOutput(ginkgo.GinkgoWriter)
-	mcContainerImage := os.Getenv("MC_CONTAINER_IMAGE")
-	mcmContainerImage := os.Getenv("MCM_CONTAINER_IMAGE")
 
 	ginkgo.By("Checking for the clusters if provided are available")
 	gomega.Expect(c.initalizeClusters()).To(gomega.BeNil())
 
+	ginkgo.By("Killing any existing processes")
+	stopMCM(ctx)
 	//setting up MCM either locally or by deploying after checking conditions
-	if isControlSeed == "true" {
-
-		if len(mcContainerImage) != 0 || len(mcmContainerImage) != 0 {
-			ginkgo.By("Updating MCM Deployemnt")
-			gomega.Expect(c.prepareMcmDeployment(mcContainerImage, mcmContainerImage, false)).To(gomega.BeNil())
-		} else {
-			checkMcmRepoAvailable()
 
-			ginkgo.By("Scaledown existing machine controllers")
-			gomega.Expect(c.scaleMcmDeployment(0)).To(gomega.BeNil())
+	checkMcmRepoAvailable()
 
-			c.runControllersLocally()
-		}
-	} else {
+	// When running the IT with virtual provider, there's no need to
+	// scale-down MC processes since none are running in the virtual cluster.
+	// Additionally, currently whenever running IT with the virtual provider,
+	// ControlCluster is assumed to be a seed since that simplifies the setup.
+	if isControlSeed == "true" && isVirtualProvider != "true" {
+		ginkgo.By("Scaledown existing machine controllers")
+		gomega.Expect(c.scaleMcmDeployment(0)).To(gomega.BeNil())
+	} else if isControlSeed != "true" {
 		//TODO : Scaledown the MCM deployment of the actual seed of the target cluster
 
-		checkMcmRepoAvailable()
-
 		//create the custom resources in the control cluster using yaml files
 		//available in kubernetes/crds directory of machine-controller-manager repo
 		//resources to be applied are machineclass, machines, machinesets and machinedeployment
@@ -797,13 +582,14 @@ func (c *IntegrationTestFramework) SetupBeforeSuite() {
 		gomega.Expect(c.ControlCluster.
 			ApplyFiles(
 				filepath.Join(mcmRepoPath, "kubernetes/crds"), controlClusterNamespace)).To(gomega.BeNil())
+	}
 
-		if len(mcContainerImage) != 0 || len(mcmContainerImage) != 0 {
-			ginkgo.By("Creating MCM Deployemnt")
-			gomega.Expect(c.prepareMcmDeployment(mcContainerImage, mcmContainerImage, true)).To(gomega.BeNil())
-		} else {
-			c.runControllersLocally()
-		}
+	c.runControllersLocally()
+
+	ginkgo.By("Cleaning any old resources")
+	if c.ControlCluster.McmClient != nil {
+		timeout := int64(900)
+		c.cleanTestResources(ctx, timeout)
 	}
 
 	ginkgo.By("Setup MachineClass")
@@ -826,30 +612,21 @@ func (c *IntegrationTestFramework) SetupBeforeSuite() {
 			machineClass.SecretRef,
 			machineClass.CredentialsSecretRef,
 		)
-	gomega.Expect(err).
-		NotTo(
-			gomega.HaveOccurred(),
-		)
+	gomega.Expect(err).NotTo(gomega.HaveOccurred())
 
-	ginkgo.By(
-		"Initializing orphan resource tracker",
-	)
+	ginkgo.By("Initializing orphan resource tracker")
 	err = c.resourcesTracker.InitializeResourcesTracker(machineClass, secretData, clusterName)
-
 	gomega.Expect(err).NotTo(gomega.HaveOccurred())
 	log.Println("orphan resource tracker initialized")
-
 }
 
 // BeforeEachCheck checks if all the nodes are ready and the controllers are runnings
 func (c *IntegrationTestFramework) BeforeEachCheck() {
 	ginkgo.BeforeEach(func() {
-		if len(os.Getenv("MC_CONTAINER_IMAGE")) == 0 && len(os.Getenv("MCM_CONTAINER_IMAGE")) == 0 {
-			ginkgo.By("Checking machineController process is running")
-			gomega.Expect(mcsession.ExitCode()).Should(gomega.Equal(-1))
-			ginkgo.By("Checking machineControllerManager process is running")
-			gomega.Expect(mcmsession.ExitCode()).Should(gomega.Equal(-1))
-		}
+		ginkgo.By("Checking machineController process is running")
+		gomega.Expect(mcsession.ExitCode()).Should(gomega.Equal(-1))
+		ginkgo.By("Checking machineControllerManager process is running")
+		gomega.Expect(mcmsession.ExitCode()).Should(gomega.Equal(-1))
 		ginkgo.By("Checking nodes in target cluster are healthy")
 		gomega.Eventually(
 			c.TargetCluster.GetNumberOfReadyNodes,
@@ -870,6 +647,12 @@ func (c *IntegrationTestFramework) ControllerTests() {
 		var initialNodes int16
 		ginkgo.Context("creation", func() {
 			ginkgo.It("should not lead to any errors and add 1 more node in target cluster", func() {
+				// In case of existing deployments creating nodes when starting virtual
+				// provider, the change in node count can be >1, this delay prevents
+				// checking node count immediately to allow for a correct initial count
+				if isVirtualProvider == "true" {
+					time.Sleep(2 * time.Second)
+				}
 				// Probe nodes currently available in target cluster
 				initialNodes = c.TargetCluster.GetNumberOfNodes()
 				ginkgo.By("Checking for errors")
@@ -903,7 +686,7 @@ func (c *IntegrationTestFramework) ControllerTests() {
 							c.ControlCluster.McmClient.
 								MachineV1alpha1().
 								Machines(controlClusterNamespace).
-								Delete(ctx, "test-machine", metav1.DeleteOptions{})).
+								Delete(ctx, testMachineName, metav1.DeleteOptions{})).
 							Should(gomega.BeNil(), "No Errors while deleting machine")
 
 						ginkgo.By("Waiting until test-machine machine object is deleted")
@@ -913,7 +696,7 @@ func (c *IntegrationTestFramework) ControllerTests() {
 							c.pollingInterval).
 							Should(gomega.BeTrue())
 
-						ginkgo.By("Waiting until number of ready nodes is equal to number of initial  nodes")
+						ginkgo.By("Waiting until number of ready nodes is equal to number of initial nodes")
 						gomega.Eventually(
 							c.TargetCluster.GetNumberOfNodes,
 							c.timeout,
@@ -957,6 +740,7 @@ func (c *IntegrationTestFramework) ControllerTests() {
 	// Testcase #02 | machine deployment
 	ginkgo.Describe("machine deployment resource", func() {
 		var initialNodes int16 // initialization should be part of creation test logic
+		initialEventCount := 0
 		ginkgo.Context("creation with replicas=0, scale up with replicas=1", func() {
 			ginkgo.It("should not lead to errors and add 1 more node to target cluster", func() {
 				var machineDeployment *v1alpha1.MachineDeployment
@@ -967,14 +751,14 @@ func (c *IntegrationTestFramework) ControllerTests() {
 				gomega.Expect(c.ControlCluster.CreateMachineDeployment(controlClusterNamespace, gnaSecretNameLabelValue, 0)).To(gomega.BeNil())
 
 				ginkgo.By("Waiting for Machine Set to be created")
-				gomega.Eventually(func() int { return c.getNumberOfMachineSets(ctx, controlClusterNamespace) }, c.timeout, c.pollingInterval).Should(gomega.BeNumerically("==", 1))
+				gomega.Eventually(func() int { return len(c.getTestMachineSets(ctx, controlClusterNamespace)) }, c.timeout, c.pollingInterval).Should(gomega.BeNumerically("==", 1))
 
 				ginkgo.By("Updating machineDeployment replicas to 1")
 				retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error {
 					machineDeployment, _ = c.ControlCluster.McmClient.
 						MachineV1alpha1().
 						MachineDeployments(controlClusterNamespace).
-						Get(ctx, "test-machine-deployment", metav1.GetOptions{})
+						Get(ctx, testMachineDeploymentName, metav1.GetOptions{})
 					machineDeployment.Spec.Replicas = 1
 					_, updateErr := c.ControlCluster.McmClient.
 						MachineV1alpha1().
@@ -991,7 +775,7 @@ func (c *IntegrationTestFramework) ControllerTests() {
 					machineDeployment, err = c.ControlCluster.McmClient.
 						MachineV1alpha1().
 						MachineDeployments(controlClusterNamespace).
-						Get(ctx, "test-machine-deployment", metav1.GetOptions{})
+						Get(ctx, testMachineDeploymentName, metav1.GetOptions{})
 					gomega.Expect(err).NotTo(gomega.HaveOccurred())
 					if len(machineDeployment.Status.Conditions) != 2 {
 						return false
@@ -1021,6 +805,8 @@ func (c *IntegrationTestFramework) ControllerTests() {
 					c.timeout,
 					c.pollingInterval).
 					Should(gomega.BeNumerically("==", initialNodes+1))
+				ginkgo.By("Fetching initial number of machineset freeze events")
+				initialEventCount = c.machineSetFreezeEventCount(ctx, controlClusterNamespace)
 			})
 		})
 		ginkgo.Context("scale-up with replicas=6", func() {
@@ -1029,7 +815,7 @@ func (c *IntegrationTestFramework) ControllerTests() {
 					machineDployment, _ := c.ControlCluster.McmClient.
 						MachineV1alpha1().
 						MachineDeployments(controlClusterNamespace).
-						Get(ctx, "test-machine-deployment", metav1.GetOptions{})
+						Get(ctx, testMachineDeploymentName, metav1.GetOptions{})
 					machineDployment.Spec.Replicas = 6
 					_, updateErr := c.ControlCluster.McmClient.
 						MachineV1alpha1().
@@ -1059,7 +845,7 @@ func (c *IntegrationTestFramework) ControllerTests() {
 					machineDployment, _ := c.ControlCluster.McmClient.
 						MachineV1alpha1().
 						MachineDeployments(controlClusterNamespace).
-						Get(ctx, "test-machine-deployment", metav1.GetOptions{})
+						Get(ctx, testMachineDeploymentName, metav1.GetOptions{})
 					machineDployment.Spec.Replicas = 2
 					_, updateErr := c.ControlCluster.McmClient.
 						MachineV1alpha1().
@@ -1084,68 +870,9 @@ func (c *IntegrationTestFramework) ControllerTests() {
 			})
 			// rapid scaling back to 2, should lead to freezing and unfreezing
 			ginkgo.It("should freeze and unfreeze machineset temporarily", func() {
-				if mcsession == nil {
-					// controllers running in pod
-					// Create log file from container log
-					mcmOutputFile, err := rotateOrAppendLogFile(mcmLogFile, true)
-					gomega.Expect(err).NotTo(gomega.HaveOccurred())
-					mcOutputFile, err := rotateOrAppendLogFile(mcLogFile, true)
-					gomega.Expect(err).NotTo(gomega.HaveOccurred())
-					ginkgo.By("Reading container log is leading to no errors")
-					podList, err := c.ControlCluster.Clientset.
-						CoreV1().
-						Pods(controlClusterNamespace).
-						List(
-							ctx,
-							metav1.ListOptions{
-								LabelSelector: "role=machine-controller-manager",
-							},
-						)
-					gomega.Expect(err).NotTo(gomega.HaveOccurred())
-
-					mcmPod := podList.Items[0]
-					providerSpecificRegexp, _ := regexp.Compile(mcContainerPrefix)
-					containers := mcmPod.Spec.Containers
-
-					for i := range containers {
-						if providerSpecificRegexp.Match([]byte(containers[i].Image)) {
-							readCloser, err := c.ControlCluster.Clientset.CoreV1().
-								Pods(controlClusterNamespace).
-								GetLogs(
-									mcmPod.Name,
-									&coreV1.PodLogOptions{
-										Container: containers[i].Name,
-									},
-								).Stream(ctx)
-							gomega.Expect(err).NotTo(gomega.HaveOccurred())
-							_, err = io.Copy(mcOutputFile, readCloser)
-							gomega.Expect(err).NotTo(gomega.HaveOccurred())
-						} else {
-							readCloser, err := c.ControlCluster.Clientset.CoreV1().
-								Pods(controlClusterNamespace).
-								GetLogs(mcmPod.Name, &coreV1.PodLogOptions{
-									Container: containers[i].Name,
-								}).Stream(ctx)
-							gomega.Expect(err).NotTo(gomega.HaveOccurred())
-							_, err = io.Copy(mcmOutputFile, readCloser)
-							gomega.Expect(err).NotTo(gomega.HaveOccurred())
-						}
-					}
-				}
-
-				ginkgo.By("Searching for Froze in mcm log file")
-				frozeRegexp, _ := regexp.Compile(` Froze MachineSet`)
-				gomega.Eventually(func() bool {
-					data, _ := os.ReadFile(mcmLogFile) // #nosec G304 -- Test only
-					return frozeRegexp.Match(data)
-				}, c.timeout, c.pollingInterval).Should(gomega.BeTrue())
-
-				ginkgo.By("Searching Unfroze in mcm log file")
-				unfrozeRegexp, _ := regexp.Compile(` Unfroze MachineSet`)
-				gomega.Eventually(func() bool {
-					data, _ := os.ReadFile(mcmLogFile) // #nosec G304 -- Test only
-					return unfrozeRegexp.Match(data)
-				}, c.timeout, c.pollingInterval).Should(gomega.BeTrue())
+				gomega.Eventually(func() int {
+					return c.machineSetFreezeEventCount(ctx, controlClusterNamespace)
+				}, c.timeout, c.pollingInterval).Should(gomega.Equal(initialEventCount + 2))
 			})
 		})
 		ginkgo.Context("updation to v2 machine-class and replicas=4", func() {
@@ -1156,7 +883,7 @@ func (c *IntegrationTestFramework) ControllerTests() {
 					machineDployment, _ := c.ControlCluster.McmClient.
 						MachineV1alpha1().
 						MachineDeployments(controlClusterNamespace).
-						Get(ctx, "test-machine-deployment", metav1.GetOptions{})
+						Get(ctx, testMachineDeploymentName, metav1.GetOptions{})
 					machineDployment.Spec.Template.Spec.Class.Name = testMachineClassResources[1]
 					machineDployment.Spec.Replicas = 4
 					_, updateErr := c.ControlCluster.McmClient.
@@ -1172,7 +899,7 @@ func (c *IntegrationTestFramework) ControllerTests() {
 					machineDeployment, err := c.ControlCluster.McmClient.
 						MachineV1alpha1().
 						MachineDeployments(controlClusterNamespace).
-						Get(ctx, "test-machine-deployment", metav1.GetOptions{})
+						Get(ctx, testMachineDeploymentName, metav1.GetOptions{})
 					if err != nil {
 						log.Println("Failed to get machinedeployment object")
 					}
@@ -1183,7 +910,7 @@ func (c *IntegrationTestFramework) ControllerTests() {
 					machineDeployment, err := c.ControlCluster.McmClient.
 						MachineV1alpha1().
 						MachineDeployments(controlClusterNamespace).
-						Get(ctx, "test-machine-deployment", metav1.GetOptions{})
+						Get(ctx, testMachineDeploymentName, metav1.GetOptions{})
 					if err != nil {
 						log.Println("Failed to get machinedeployment object")
 					}
@@ -1209,7 +936,7 @@ func (c *IntegrationTestFramework) ControllerTests() {
 					_, err := c.ControlCluster.McmClient.
 						MachineV1alpha1().
 						MachineDeployments(controlClusterNamespace).
-						Get(ctx, "test-machine-deployment", metav1.GetOptions{})
+						Get(ctx, testMachineDeploymentName, metav1.GetOptions{})
 					if err == nil {
 						ginkgo.By("Checking for errors")
 						gomega.Expect(
@@ -1218,7 +945,7 @@ func (c *IntegrationTestFramework) ControllerTests() {
 								MachineDeployments(controlClusterNamespace).
 								Delete(
 									ctx,
-									"test-machine-deployment",
+									testMachineDeploymentName,
 									metav1.DeleteOptions{},
 								)).
 							Should(gomega.BeNil())
@@ -1263,134 +990,62 @@ func (c *IntegrationTestFramework) Cleanup() {
 
 	ginkgo.By("Running Cleanup")
 	//running locally, means none of the image is specified
-	if len(os.Getenv("MC_CONTAINER_IMAGE")) == 0 && len(os.Getenv("MCM_CONTAINER_IMAGE")) == 0 {
-		for i := 0; i < 5; i++ {
-			if mcsession.ExitCode() != -1 {
-				ginkgo.By("Restarting Machine Controller ")
-				outputFile, err := rotateOrAppendLogFile(mcLogFile, false)
-				gomega.Expect(err).NotTo(gomega.HaveOccurred())
-				_, err = outputFile.WriteString("\n------------RESTARTED MC------------\n")
-				gomega.Expect(err).NotTo(gomega.HaveOccurred())
-				args := strings.Fields(
-					fmt.Sprintf(
-						"make --directory=%s start CONTROL_KUBECONFIG=%s TARGET_KUBECONFIG=%s CONTROL_NAMESPACE=%s LEADER_ELECT=false ",
-						"../../..",
-						c.ControlCluster.KubeConfigFilePath,
-						c.TargetCluster.KubeConfigFilePath,
-						controlClusterNamespace),
-				)
-				mcsession, err = gexec.Start(exec.Command(args[0], args[1:]...), outputFile, outputFile) // #nosec G204 -- Test only
-				gomega.Expect(err).NotTo(gomega.HaveOccurred())
-				break
-			}
-			time.Sleep(2 * time.Second)
+	for range 5 {
+		if mcsession.ExitCode() != -1 {
+			ginkgo.By("Restarting Machine Controller ")
+			outputFile, err := rotateOrAppendLogFile(mcLogFile, false)
+			gomega.Expect(err).NotTo(gomega.HaveOccurred())
+			_, err = outputFile.WriteString("\n------------RESTARTED MC------------\n")
+			gomega.Expect(err).NotTo(gomega.HaveOccurred())
+			args := strings.Fields(
+				fmt.Sprintf(
+					"make --directory=%s start CONTROL_KUBECONFIG=%s TARGET_KUBECONFIG=%s CONTROL_NAMESPACE=%s LEADER_ELECT=false ",
+					"../../..",
+					c.ControlCluster.KubeConfigFilePath,
+					c.TargetCluster.KubeConfigFilePath,
+					controlClusterNamespace),
+			)
+			mcsession, err = gexec.Start(exec.Command(args[0], args[1:]...), outputFile, outputFile) // #nosec G204 -- Test only
+			gomega.Expect(err).NotTo(gomega.HaveOccurred())
+			break
 		}
-		for i := 0; i < 5; i++ {
-			if mcmsession.ExitCode() != -1 {
-				ginkgo.By("Restarting Machine Controller Manager")
-				outputFile, err := rotateOrAppendLogFile(mcmLogFile, false)
-				gomega.Expect(err).NotTo(gomega.HaveOccurred())
-				_, err = outputFile.WriteString("\n------------RESTARTED MCM------------\n")
-				gomega.Expect(err).NotTo(gomega.HaveOccurred())
-				args := strings.Fields(
-					fmt.Sprintf(
-						"make --directory=%s start CONTROL_KUBECONFIG=%s TARGET_KUBECONFIG=%s CONTROL_NAMESPACE=%s LEADER_ELECT=false MACHINE_SAFETY_OVERSHOOTING_PERIOD=300ms",
-						mcmRepoPath,
-						c.ControlCluster.KubeConfigFilePath,
-						c.TargetCluster.KubeConfigFilePath,
-						controlClusterNamespace),
-				)
-				mcmsession, err = gexec.Start(exec.Command(args[0], args[1:]...), outputFile, outputFile) // #nosec G204 -- Test only
-				gomega.Expect(err).NotTo(gomega.HaveOccurred())
-				break
-			}
-			time.Sleep(2 * time.Second)
+		time.Sleep(2 * time.Second)
+	}
+	for range 5 {
+		if mcmsession.ExitCode() != -1 {
+			ginkgo.By("Restarting Machine Controller Manager")
+			outputFile, err := rotateOrAppendLogFile(mcmLogFile, false)
+			gomega.Expect(err).NotTo(gomega.HaveOccurred())
+			_, err = outputFile.WriteString("\n------------RESTARTED MCM------------\n")
+			gomega.Expect(err).NotTo(gomega.HaveOccurred())
+			args := strings.Fields(
+				fmt.Sprintf(
+					"make --directory=%s start CONTROL_KUBECONFIG=%s TARGET_KUBECONFIG=%s CONTROL_NAMESPACE=%s LEADER_ELECT=false MACHINE_SAFETY_OVERSHOOTING_PERIOD=300ms",
+					mcmRepoPath,
+					c.ControlCluster.KubeConfigFilePath,
+					c.TargetCluster.KubeConfigFilePath,
+					controlClusterNamespace),
+			)
+			mcmsession, err = gexec.Start(exec.Command(args[0], args[1:]...), outputFile, outputFile) // #nosec G204 -- Test only
+			gomega.Expect(err).NotTo(gomega.HaveOccurred())
+			break
 		}
+		time.Sleep(2 * time.Second)
 	}
 
-	if c.ControlCluster.McmClient != nil {
+	if preserveCRDDuringCleanup == "true" {
+		log.Printf("Preserve CRD: %s\n", preserveCRDDuringCleanup)
+	} else if c.ControlCluster.McmClient != nil {
 		timeout := int64(900)
-		// Check and delete machinedeployment resource
-		_, err := c.ControlCluster.McmClient.
-			MachineV1alpha1().
-			MachineDeployments(controlClusterNamespace).
-			Get(ctx, "test-machine-deployment", metav1.GetOptions{})
-		if err == nil {
-			log.Println("deleting test-machine-deployment")
-			watchMachinesDepl, _ := c.ControlCluster.McmClient.
-				MachineV1alpha1().
-				MachineDeployments(controlClusterNamespace).
-				Watch(ctx, metav1.ListOptions{TimeoutSeconds: &timeout}) //ResourceVersion: machineDeploymentObj.ResourceVersion
-			for event := range watchMachinesDepl.ResultChan() {
-				gomega.Expect(c.ControlCluster.McmClient.
-					MachineV1alpha1().
-					MachineDeployments(controlClusterNamespace).
-					Delete(ctx, "test-machine-deployment", metav1.DeleteOptions{})).To(gomega.Or(gomega.Succeed(), matchers.BeNotFoundError()))
-				if event.Type == watch.Deleted {
-					watchMachinesDepl.Stop()
-					log.Println("machinedeployment deleted")
-				}
-			}
-		} else {
-			log.Println(err.Error())
-		}
-		// Check and delete machine resource
-		_, err = c.ControlCluster.McmClient.
-			MachineV1alpha1().
-			Machines(controlClusterNamespace).
-			Get(ctx, "test-machine", metav1.GetOptions{})
-		if err == nil {
-			log.Println("deleting test-machine")
-			watchMachines, _ := c.ControlCluster.McmClient.
-				MachineV1alpha1().
-				Machines(controlClusterNamespace).
-				Watch(ctx, metav1.ListOptions{TimeoutSeconds: &timeout}) //ResourceVersion: machineObj.ResourceVersion
-			for event := range watchMachines.ResultChan() {
-				gomega.Expect(c.ControlCluster.McmClient.
-					MachineV1alpha1().
-					Machines(controlClusterNamespace).
-					Delete(ctx, "test-machine", metav1.DeleteOptions{})).To(gomega.Or(gomega.Succeed(), matchers.BeNotFoundError()))
-				if event.Type == watch.Deleted {
-					watchMachines.Stop()
-					log.Println("machine deleted")
-				}
-			}
-		} else {
-			log.Println(err.Error())
-		}
+		c.cleanTestResources(ctx, timeout)
+	}
 
-		for _, machineClassName := range testMachineClassResources {
-			// Check and delete machine class resource
-			_, err = c.ControlCluster.McmClient.
-				MachineV1alpha1().
-				MachineClasses(controlClusterNamespace).
-				Get(ctx, machineClassName, metav1.GetOptions{})
-			if err == nil {
-				log.Printf("deleting %s machineclass", machineClassName)
-				watchMachineClass, _ := c.ControlCluster.McmClient.
-					MachineV1alpha1().
-					MachineClasses(controlClusterNamespace).
-					Watch(ctx, metav1.ListOptions{TimeoutSeconds: &timeout})
-				for event := range watchMachineClass.ResultChan() {
-					gomega.Expect(c.ControlCluster.McmClient.
-						MachineV1alpha1().
-						MachineClasses(controlClusterNamespace).
-						Delete(ctx, machineClassName, metav1.DeleteOptions{})).To(gomega.Or(gomega.Succeed(), matchers.BeNotFoundError()))
-					if event.Type == watch.Deleted {
-						watchMachineClass.Stop()
-						log.Println("machineclass deleted")
-					}
-				}
-			} else {
-				log.Println(err.Error())
-			}
-		}
+	ginkgo.By("Killing any existing processes")
+	stopMCM(ctx)
 
-	}
 	if isControlSeed == "true" {
-		// scale back up the MCM deployment to 1 in the Control Cluster
 		// This is needed when IT suite runs locally against a Control & Target cluster
-
+		ginkgo.By("Scale back the existing machine controllers")
 		if err := c.scaleMcmDeployment(1); err != nil {
 			log.Println(err.Error())
 		}
@@ -1403,71 +1058,227 @@ func (c *IntegrationTestFramework) Cleanup() {
 		); err != nil {
 			log.Printf("Error occured while deleting crds. %s", err.Error())
 		}
+	}
 
-		if len(os.Getenv("MC_CONTAINER_IMAGE")) != 0 || len(os.Getenv("MCM_CONTAINER_IMAGE")) != 0 {
-			log.Println("Deleting Clusterroles")
+}
 
-			if err := c.ControlCluster.RbacClient.ClusterRoles().Delete(
-				ctx,
-				"machine-controller-manager-control",
-				metav1.DeleteOptions{},
-			); err != nil {
-				log.Printf("Error occured while deleting clusterrole. %s", err.Error())
-			}
+func (c *IntegrationTestFramework) cleanTestResources(ctx context.Context, timeout int64) {
+	// Check and delete machinedeployment resource
+	if err := c.cleanMachineDeployment(ctx, testMachineDeploymentName, timeout); err != nil {
+		log.Println(err.Error())
+	}
+	// Check and delete machine resource
+	if err := c.cleanMachine(ctx, testMachineName, timeout); err != nil {
+		log.Println(err.Error())
+	}
 
-			if err := c.ControlCluster.RbacClient.ClusterRoleBindings().Delete(
-				ctx,
-				"machine-controller-manager-control",
-				metav1.DeleteOptions{},
-			); err != nil {
-				log.Printf("Error occured while deleting clusterrolebinding . %s", err.Error())
-			}
+	for _, machineClassName := range testMachineClassResources {
+		// Check and delete machine class resource
+		if err := c.cleanMachineClass(ctx, machineClassName, timeout); err != nil {
+			log.Println(err.Error())
+		}
+	}
+}
 
-			if err := c.TargetCluster.RbacClient.ClusterRoles().Delete(
-				ctx,
-				"machine-controller-manager-target",
-				metav1.DeleteOptions{},
-			); err != nil {
-				log.Printf("Error occured while deleting clusterrole . %s", err.Error())
-			}
+func (c *IntegrationTestFramework) cleanMachineDeployment(ctx context.Context, name string, timeout int64) error {
+	_, err := c.ControlCluster.McmClient.
+		MachineV1alpha1().
+		MachineDeployments(controlClusterNamespace).
+		Get(ctx, name, metav1.GetOptions{})
+	if err != nil {
+		return err
+	}
+	log.Printf("deleting %s\n", name)
+	selector := fmt.Sprintf("metadata.name=%s", name)
+	watchMachinesDepl, _ := c.ControlCluster.McmClient.
+		MachineV1alpha1().
+		MachineDeployments(controlClusterNamespace).
+		Watch(ctx, metav1.ListOptions{
+			TimeoutSeconds: &timeout,
+			FieldSelector:  selector,
+		})
+	for event := range watchMachinesDepl.ResultChan() {
+		gomega.Expect(c.ControlCluster.McmClient.
+			MachineV1alpha1().
+			MachineDeployments(controlClusterNamespace).
+			Delete(ctx, name, metav1.DeleteOptions{})).To(gomega.Or(gomega.Succeed(), matchers.BeNotFoundError()))
+		if event.Type == watch.Deleted {
+			watchMachinesDepl.Stop()
+			log.Println("machinedeployment deleted")
+		}
+	}
+	return nil
+}
 
-			if err := c.TargetCluster.RbacClient.ClusterRoleBindings().Delete(
-				ctx,
-				"machine-controller-manager-target",
-				metav1.DeleteOptions{},
-			); err != nil {
-				log.Printf("Error occured while deleting clusterrolebinding . %s", err.Error())
-			}
+func (c *IntegrationTestFramework) cleanMachine(ctx context.Context, name string, timeout int64) error {
+	_, err := c.ControlCluster.McmClient.
+		MachineV1alpha1().
+		Machines(controlClusterNamespace).
+		Get(ctx, name, metav1.GetOptions{})
+	if err != nil {
+		return err
+	}
+	log.Printf("deleting %s\n", name)
+	selector := fmt.Sprintf("metadata.name=%s", name)
+	watchMachines, _ := c.ControlCluster.McmClient.
+		MachineV1alpha1().
+		Machines(controlClusterNamespace).
+		Watch(ctx, metav1.ListOptions{
+			TimeoutSeconds: &timeout,
+			FieldSelector:  selector,
+		}) //ResourceVersion: machineObj.ResourceVersion
+	for event := range watchMachines.ResultChan() {
+		gomega.Expect(c.ControlCluster.McmClient.
+			MachineV1alpha1().
+			Machines(controlClusterNamespace).
+			Delete(ctx, name, metav1.DeleteOptions{})).To(gomega.Or(gomega.Succeed(), matchers.BeNotFoundError()))
+		if event.Type == watch.Deleted {
+			watchMachines.Stop()
+			log.Println("machine deleted")
+		}
+	}
+	return nil
+}
 
-			log.Println("Deleting MCM deployment")
+func (c *IntegrationTestFramework) cleanMachineClass(ctx context.Context, machineClassName string, timeout int64) error {
+	_, err := c.ControlCluster.McmClient.
+		MachineV1alpha1().
+		MachineClasses(controlClusterNamespace).
+		Get(ctx, machineClassName, metav1.GetOptions{})
+	if err != nil {
+		return err
+	}
 
-			gomega.Expect(c.ControlCluster.Clientset.
-				CoreV1().
-				Secrets(controlClusterNamespace).
-				Delete(ctx,
-					"machine-controller-manager",
-					metav1.DeleteOptions{})).To(gomega.Or(gomega.Succeed(), matchers.BeNotFoundError()))
-			gomega.Expect(c.ControlCluster.Clientset.
-				AppsV1().
-				Deployments(controlClusterNamespace).
-				Delete(ctx,
-					machineControllerManagerDeploymentName,
-					metav1.DeleteOptions{})).To(gomega.Or(gomega.Succeed(), matchers.BeNotFoundError()))
+	log.Printf("deleting %s machineclass", machineClassName)
+	selector := fmt.Sprintf("metadata.name=%s", machineClassName)
+	watchMachineClass, _ := c.ControlCluster.McmClient.
+		MachineV1alpha1().
+		MachineClasses(controlClusterNamespace).
+		Watch(ctx, metav1.ListOptions{
+			TimeoutSeconds: &timeout,
+			FieldSelector:  selector,
+		})
+	for event := range watchMachineClass.ResultChan() {
+		gomega.Expect(c.ControlCluster.McmClient.
+			MachineV1alpha1().
+			MachineClasses(controlClusterNamespace).
+			Delete(ctx, machineClassName, metav1.DeleteOptions{})).To(gomega.Or(gomega.Succeed(), matchers.BeNotFoundError()))
+		if event.Type == watch.Deleted {
+			watchMachineClass.Stop()
+			log.Println("machineclass deleted")
+		}
+	}
+	return nil
+}
+
+func stopMCM(ctx context.Context) {
+	processesToKill := []string{
+		"machine-controller-manager --control-kubeconfig", // virtual
+		"machine-controller --control-kubeconfig",         // virtual
+		"controller_manager --control-kubeconfig",
+		"main --control-kubeconfig",
+		"go run cmd/machine-controller/main.go",
+		"go run cmd/machine-controller-manager/controller_manager.go",
+		"make --directory=../../..",
+	}
+	for _, proc := range processesToKill {
+		pids, err := findAndKillProcess(ctx, proc)
+		if err != nil {
+			log.Println(err.Error())
+		}
+		if len(pids) > 0 {
+			log.Printf("stopMCM killed MCM process(es) with pid(s): %v\n", pids)
 		}
 	}
+}
 
+func findAndKillProcess(ctx context.Context, prefix string) (pids []int, err error) {
+	pids, err = findPidsByPrefix(ctx, prefix)
+	if len(pids) != 0 {
+		var proc *os.Process
+		for _, pid := range pids {
+			proc, err = os.FindProcess(pid)
+			if err != nil {
+				err = fmt.Errorf("failed to find process with PID %d: %v", pid, err)
+				return
+			}
+			err = proc.Kill()
+			if err != nil {
+				err = fmt.Errorf("failed to kill process with PID %d: %v", pid, err)
+				return
+			}
+		}
+	}
+	return
 }
 
-func (c *IntegrationTestFramework) getNumberOfMachineSets(ctx context.Context, namespace string) int {
+func findPidsByPrefix(ctx context.Context, prefix string) (pids []int, err error) {
+	cmd := exec.CommandContext(ctx, "ps", "-e", "-o", "pid,args")
+	psOutput, err := cmd.Output()
+	if err != nil {
+		log.Printf("FindProcess could not run ps command: %v", err)
+		return
+	}
+	scanner := bufio.NewScanner(bytes.NewReader(psOutput))
+	var pid int
+	for scanner.Scan() {
+		line := scanner.Text()
+		fields := strings.Fields(line)
+		if len(fields) < 2 {
+			continue
+		}
+		// Process the PID and command columns
+		pidStr := fields[0]
+		commandPath := fields[1]
+		commandName := path.Base(commandPath)
+		if len(fields) > 2 {
+			commandName = commandName + " " + strings.Join(fields[2:], " ")
+		}
+
+		if strings.HasPrefix(commandName, prefix) {
+			log.Println(commandName)
+			pid, err = strconv.Atoi(pidStr)
+			if err != nil {
+				err = fmt.Errorf("invalid pid: %s", pidStr)
+				return
+			}
+			pids = append(pids, pid)
+		}
+	}
+	return
+}
+
+func (c *IntegrationTestFramework) getTestMachineSets(ctx context.Context, namespace string) []string {
 	machineSets, err := c.ControlCluster.McmClient.MachineV1alpha1().MachineSets(namespace).List(ctx, metav1.ListOptions{})
+	testMachineSets := []string{}
 	gomega.Expect(err).NotTo(gomega.HaveOccurred())
-	count := 0
 	for _, machineSet := range machineSets.Items {
-		if machineSet.OwnerReferences[0].Name == "test-machine-deployment" {
-			count++
+		if machineSet.OwnerReferences[0].Name == testMachineDeploymentName {
+			testMachineSets = append(testMachineSets, machineSet.Name)
+		}
+	}
+	return testMachineSets
+}
+
+func (c *IntegrationTestFramework) machineSetFreezeEventCount(ctx context.Context, namespace string) int {
+	eventCount := 0
+	testMachineSets := c.getTestMachineSets(ctx, namespace)
+	machineSetFreezeReason := fmt.Sprintf("reason=%s", controller.MachineSetFreezeEvent)
+	machineSetUnfreezeReason := fmt.Sprintf("reason=%s", controller.MachineSetUnfreezeEvent)
+	for _, machineSet := range testMachineSets {
+		for _, reason := range []string{machineSetFreezeReason, machineSetUnfreezeReason} {
+			event := fmt.Sprintf("%s,involvedObject.name=%s", reason, machineSet)
+			frozenEvents, err := c.ControlCluster.Clientset.
+				CoreV1().
+				Events(namespace).
+				List(ctx, metav1.ListOptions{
+					FieldSelector: event,
+				})
+			gomega.Expect(err).NotTo(gomega.HaveOccurred())
+			eventCount += len(frozenEvents.Items)
 		}
 	}
-	return count
+	return eventCount
 }
 
 func checkMcmRepoAvailable() {
diff --git a/pkg/util/provider/machinecontroller/machine_test.go b/pkg/util/provider/machinecontroller/machine_test.go
index a658641f4..493988e87 100644
--- a/pkg/util/provider/machinecontroller/machine_test.go
+++ b/pkg/util/provider/machinecontroller/machine_test.go
@@ -226,7 +226,7 @@ var _ = Describe("machine", func() {
 				action: machineapi.Machine{
 					Spec: machineapi.MachineSpec{
 						Class: machineapi.ClassSpec{
-							Kind: "AWSMachineClass",
+							Kind: "MachineClass",
 							Name: "aws",
 						},
 					},
@@ -234,6 +234,30 @@ var _ = Describe("machine", func() {
 				expect: field.ErrorList{},
 			}),
 		)
+		DescribeTable("#machine validation fails with no class name",
+			func(data *data) {
+				errList := validation.ValidateMachine(&data.action)
+				Expect(errList).To(Equal(data.expect))
+			},
+			Entry("aws", &data{
+				action: machineapi.Machine{
+					Spec: machineapi.MachineSpec{
+						Class: machineapi.ClassSpec{
+							Kind: "MachineClass",
+							Name: "",
+						},
+					},
+				},
+				expect: field.ErrorList{
+					{
+						Type:     "FieldValueRequired",
+						Field:    "spec.class.name",
+						BadValue: "",
+						Detail:   "Name is required",
+					},
+				},
+			}),
+		)
 	})
 
 	Describe("#ValidateMachineClass", func() {