Repository: yonahd/kor
Pull request #58 (2023-09-06 18:34:18)

Add tests for unused kubernetes resources finders


Patch:
diff --git a/.github/workflows/merge-request.yml b/.github/workflows/merge-request.yml
index 923757c..0192cdf 100644
--- a/.github/workflows/merge-request.yml
+++ b/.github/workflows/merge-request.yml
@@ -28,9 +28,15 @@ jobs:
         uses: golangci/golangci-lint-action@v3
         with:
           version: latest
+          skip-pkg-cache: true
 
       - name: Build
         run: go build -v ./...
 
       - name: Test
-        run: go test -v ./...
\ No newline at end of file
+        run: go test -v ./... -coverprofile=coverage.txt
+
+      - name: Upload coverage reports to Codecov
+        uses: codecov/codecov-action@v3
+        env:
+          CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
\ No newline at end of file
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 06d14de..c83fd27 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -33,10 +33,18 @@ jobs:
         with:
           username: ${{ secrets.DOCKERHUB_USERNAME }}
           password: ${{ secrets.DOCKERHUB_TOKEN }}
-
-      - name: Build and push
-        uses: docker/build-push-action@v4
+          
+      - name: Extract metadata for the Docker image
+        id: meta
+        uses: docker/metadata-action@v5
+        with:
+          images: ${{ secrets.DOCKERHUB_USERNAME }}/kor
+  
+      - name: Build and push the Docker image
+        uses: docker/build-push-action@v5
         with:
           context: .
           push: true
-          tags: yonahdissen/kor:${{ github.ref }}
+          tags: ${{ steps.meta.outputs.tags }}
+          labels: ${{ steps.meta.outputs.labels }}
+          
diff --git a/README.md b/README.md
index 61a4758..f5d3768 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,6 @@
 ![GitHub go.mod Go version (subdirectory of monorepo)](https://img.shields.io/github/go-mod/go-version/yonahd/kor)
 ![GitHub release (with filter)](https://img.shields.io/github/v/release/yonahd/kor?color=green&link=https://github.com/yonahd/kor/releases)
+[![codecov](https://codecov.io/gh/yonahd/kor/branch/main/graph/badge.svg?token=tNKcOjlxLo)](https://codecov.io/gh/yonahd/kor)
 
 # Kor - Kubernetes Orphaned Resources Finder
 
diff --git a/cmd/kor/statefulsets.go b/cmd/kor/statefulsets.go
index 5a100f1..130da02 100644
--- a/cmd/kor/statefulsets.go
+++ b/cmd/kor/statefulsets.go
@@ -10,18 +10,18 @@ import (
 var stsCmd = &cobra.Command{
 	Use:     "statefulset",
 	Aliases: []string{"sts", "statefulsets"},
-	Short:   "Gets unused statefulsets",
+	Short:   "Gets unused statefulSets",
 	Args:    cobra.ExactArgs(0),
 	Run: func(cmd *cobra.Command, args []string) {
 		clientset := kor.GetKubeClient(kubeconfig)
 		if outputFormat == "json" || outputFormat == "yaml" {
-			if response, err := kor.GetUnusedStatefulsetsStructured(includeExcludeLists, clientset, outputFormat); err != nil {
+			if response, err := kor.GetUnusedStatefulSetsStructured(includeExcludeLists, clientset, outputFormat); err != nil {
 				fmt.Println(err)
 			} else {
 				fmt.Println(response)
 			}
 		} else {
-			kor.GetUnusedStatefulsets(includeExcludeLists, clientset)
+			kor.GetUnusedStatefulSets(includeExcludeLists, clientset)
 		}
 
 	},
diff --git a/go.mod b/go.mod
index de40bb6..3a4d873 100644
--- a/go.mod
+++ b/go.mod
@@ -15,6 +15,7 @@ require (
 require (
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/emicklei/go-restful/v3 v3.10.1 // indirect
+	github.com/evanphx/json-patch v5.6.0+incompatible // indirect
 	github.com/go-logr/logr v1.2.4 // indirect
 	github.com/go-openapi/jsonpointer v0.20.0 // indirect
 	github.com/go-openapi/jsonreference v0.20.2 // indirect
@@ -34,11 +35,14 @@ require (
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
+	github.com/onsi/ginkgo/v2 v2.11.0 // indirect
+	github.com/onsi/gomega v1.27.10 // indirect
+	github.com/pkg/errors v0.9.1 // indirect
 	github.com/rivo/uniseg v0.4.4 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
 	golang.org/x/net v0.13.0 // indirect
 	golang.org/x/oauth2 v0.10.0 // indirect
-	golang.org/x/sys v0.10.0 // indirect
+	golang.org/x/sys v0.11.0 // indirect
 	golang.org/x/term v0.10.0 // indirect
 	golang.org/x/text v0.11.0 // indirect
 	golang.org/x/time v0.3.0 // indirect
diff --git a/go.sum b/go.sum
index a168485..423cae2 100644
--- a/go.sum
+++ b/go.sum
@@ -5,6 +5,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ=
 github.com/emicklei/go-restful/v3 v3.10.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U=
+github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
 github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
 github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
 github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@@ -64,8 +66,12 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
 github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
 github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
-github.com/onsi/ginkgo/v2 v2.9.4 h1:xR7vG4IXt5RWx6FfIjyAtsoMAtnc3C/rFXBBd2AjZwE=
-github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
+github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
+github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
+github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
+github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
+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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
@@ -107,8 +113,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
 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.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
-golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
+golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
 golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/pkg/kor/all.go b/pkg/kor/all.go
index 6f6778d..5952b20 100644
--- a/pkg/kor/all.go
+++ b/pkg/kor/all.go
@@ -19,8 +19,8 @@ type ResourceDiff struct {
 	diff         []string
 }
 
-func getUnusedCMs(kubeClient *kubernetes.Clientset, namespace string) ResourceDiff {
-	cmDiff, err := processNamespaceCM(kubeClient, namespace)
+func getUnusedCMs(clientset kubernetes.Interface, namespace string) ResourceDiff {
+	cmDiff, err := processNamespaceCM(clientset, namespace)
 	if err != nil {
 		fmt.Fprintf(os.Stderr, "Failed to get %s namespace %s: %v\n", "configmaps", namespace, err)
 	}
@@ -28,8 +28,8 @@ func getUnusedCMs(kubeClient *kubernetes.Clientset, namespace string) ResourceDi
 	return namespaceCMDiff
 }
 
-func getUnusedSVCs(kubeClient *kubernetes.Clientset, namespace string) ResourceDiff {
-	svcDiff, err := ProcessNamespaceServices(kubeClient, namespace)
+func getUnusedSVCs(clientset kubernetes.Interface, namespace string) ResourceDiff {
+	svcDiff, err := ProcessNamespaceServices(clientset, namespace)
 	if err != nil {
 		fmt.Fprintf(os.Stderr, "Failed to get %s namespace %s: %v\n", "services", namespace, err)
 	}
@@ -37,8 +37,8 @@ func getUnusedSVCs(kubeClient *kubernetes.Clientset, namespace string) ResourceD
 	return namespaceSVCDiff
 }
 
-func getUnusedSecrets(kubeClient *kubernetes.Clientset, namespace string) ResourceDiff {
-	secretDiff, err := processNamespaceSecret(kubeClient, namespace)
+func getUnusedSecrets(clientset kubernetes.Interface, namespace string) ResourceDiff {
+	secretDiff, err := processNamespaceSecret(clientset, namespace)
 	if err != nil {
 		fmt.Fprintf(os.Stderr, "Failed to get %s namespace %s: %v\n", "secrets", namespace, err)
 	}
@@ -46,8 +46,8 @@ func getUnusedSecrets(kubeClient *kubernetes.Clientset, namespace string) Resour
 	return namespaceSecretDiff
 }
 
-func getUnusedServiceAccounts(kubeClient *kubernetes.Clientset, namespace string) ResourceDiff {
-	saDiff, err := processNamespaceSA(kubeClient, namespace)
+func getUnusedServiceAccounts(clientset kubernetes.Interface, namespace string) ResourceDiff {
+	saDiff, err := processNamespaceSA(clientset, namespace)
 	if err != nil {
 		fmt.Fprintf(os.Stderr, "Failed to get %s namespace %s: %v\n", "serviceaccounts", namespace, err)
 	}
@@ -55,8 +55,8 @@ func getUnusedServiceAccounts(kubeClient *kubernetes.Clientset, namespace string
 	return namespaceSADiff
 }
 
-func getUnusedDeployments(kubeClient *kubernetes.Clientset, namespace string) ResourceDiff {
-	deployDiff, err := ProcessNamespaceDeployments(kubeClient, namespace)
+func getUnusedDeployments(clientset kubernetes.Interface, namespace string) ResourceDiff {
+	deployDiff, err := ProcessNamespaceDeployments(clientset, namespace)
 	if err != nil {
 		fmt.Fprintf(os.Stderr, "Failed to get %s namespace %s: %v\n", "deployments", namespace, err)
 	}
@@ -64,17 +64,17 @@ func getUnusedDeployments(kubeClient *kubernetes.Clientset, namespace string) Re
 	return namespaceSADiff
 }
 
-func getUnusedStatefulsets(kubeClient *kubernetes.Clientset, namespace string) ResourceDiff {
-	stsDiff, err := ProcessNamespaceStatefulsets(kubeClient, namespace)
+func getUnusedStatefulSets(clientset kubernetes.Interface, namespace string) ResourceDiff {
+	stsDiff, err := ProcessNamespaceStatefulSets(clientset, namespace)
 	if err != nil {
-		fmt.Fprintf(os.Stderr, "Failed to get %s namespace %s: %v\n", "statefulsets", namespace, err)
+		fmt.Fprintf(os.Stderr, "Failed to get %s namespace %s: %v\n", "statefulSets", namespace, err)
 	}
-	namespaceSADiff := ResourceDiff{"Statefulset", stsDiff}
+	namespaceSADiff := ResourceDiff{"StatefulSet", stsDiff}
 	return namespaceSADiff
 }
 
-func getUnusedRoles(kubeClient *kubernetes.Clientset, namespace string) ResourceDiff {
-	roleDiff, err := processNamespaceRoles(kubeClient, namespace)
+func getUnusedRoles(clientset kubernetes.Interface, namespace string) ResourceDiff {
+	roleDiff, err := processNamespaceRoles(clientset, namespace)
 	if err != nil {
 		fmt.Fprintf(os.Stderr, "Failed to get %s namespace %s: %v\n", "roles", namespace, err)
 	}
@@ -82,8 +82,8 @@ func getUnusedRoles(kubeClient *kubernetes.Clientset, namespace string) Resource
 	return namespaceSADiff
 }
 
-func getUnusedHpas(kubeClient *kubernetes.Clientset, namespace string) ResourceDiff {
-	hpaDiff, err := processNamespaceHpas(kubeClient, namespace)
+func getUnusedHpas(clientset kubernetes.Interface, namespace string) ResourceDiff {
+	hpaDiff, err := processNamespaceHpas(clientset, namespace)
 	if err != nil {
 		fmt.Fprintf(os.Stderr, "Failed to get %s namespace %s: %v\n", "hpas", namespace, err)
 	}
@@ -91,8 +91,8 @@ func getUnusedHpas(kubeClient *kubernetes.Clientset, namespace string) ResourceD
 	return namespaceHpaDiff
 }
 
-func getUnusedPvcs(kubeClient *kubernetes.Clientset, namespace string) ResourceDiff {
-	pvcDiff, err := processNamespacePvcs(kubeClient, namespace)
+func getUnusedPvcs(clientset kubernetes.Interface, namespace string) ResourceDiff {
+	pvcDiff, err := processNamespacePvcs(clientset, namespace)
 	if err != nil {
 		fmt.Fprintf(os.Stderr, "Failed to get %s namespace %s: %v\n", "pvcs", namespace, err)
 	}
@@ -100,8 +100,8 @@ func getUnusedPvcs(kubeClient *kubernetes.Clientset, namespace string) ResourceD
 	return namespacePvcDiff
 }
 
-func getUnusedIngresses(kubeClient *kubernetes.Clientset, namespace string) ResourceDiff {
-	ingressDiff, err := processNamespaceIngresses(kubeClient, namespace)
+func getUnusedIngresses(clientset kubernetes.Interface, namespace string) ResourceDiff {
+	ingressDiff, err := processNamespaceIngresses(clientset, namespace)
 	if err != nil {
 		fmt.Fprintf(os.Stderr, "Failed to get %s namespace %s: %v\n", "ingresses", namespace, err)
 	}
@@ -109,8 +109,8 @@ func getUnusedIngresses(kubeClient *kubernetes.Clientset, namespace string) Reso
 	return namespaceIngressDiff
 }
 
-func getUnusedPdbs(kubeClient *kubernetes.Clientset, namespace string) ResourceDiff {
-	pdbDiff, err := processNamespacePdbs(kubeClient, namespace)
+func getUnusedPdbs(clientset kubernetes.Interface, namespace string) ResourceDiff {
+	pdbDiff, err := processNamespacePdbs(clientset, namespace)
 	if err != nil {
 		fmt.Fprintf(os.Stderr, "Failed to get %s namespace %s: %v\n", "pdbs", namespace, err)
 	}
@@ -118,7 +118,7 @@ func getUnusedPdbs(kubeClient *kubernetes.Clientset, namespace string) ResourceD
 	return namespacePdbDiff
 }
 
-func GetUnusedAll(includeExcludeLists IncludeExcludeLists, clientset *kubernetes.Clientset) {
+func GetUnusedAll(includeExcludeLists IncludeExcludeLists, clientset kubernetes.Interface) {
 	namespaces := SetNamespaceList(includeExcludeLists, clientset)
 	for _, namespace := range namespaces {
 		var allDiffs []ResourceDiff
@@ -132,7 +132,7 @@ func GetUnusedAll(includeExcludeLists IncludeExcludeLists, clientset *kubernetes
 		allDiffs = append(allDiffs, namespaceSADiff)
 		namespaceDeploymentDiff := getUnusedDeployments(clientset, namespace)
 		allDiffs = append(allDiffs, namespaceDeploymentDiff)
-		namespaceStatefulsetDiff := getUnusedStatefulsets(clientset, namespace)
+		namespaceStatefulsetDiff := getUnusedStatefulSets(clientset, namespace)
 		allDiffs = append(allDiffs, namespaceStatefulsetDiff)
 		namespaceRoleDiff := getUnusedRoles(clientset, namespace)
 		allDiffs = append(allDiffs, namespaceRoleDiff)
@@ -150,7 +150,7 @@ func GetUnusedAll(includeExcludeLists IncludeExcludeLists, clientset *kubernetes
 	}
 }
 
-func GetUnusedAllStructured(includeExcludeLists IncludeExcludeLists, clientset *kubernetes.Clientset, outputFormat string) (string, error) {
+func GetUnusedAllStructured(includeExcludeLists IncludeExcludeLists, clientset kubernetes.Interface, outputFormat string) (string, error) {
 	namespaces := SetNamespaceList(includeExcludeLists, clientset)
 
 	// Create the JSON response object
@@ -174,7 +174,7 @@ func GetUnusedAllStructured(includeExcludeLists IncludeExcludeLists, clientset *
 		namespaceDeploymentDiff := getUnusedDeployments(clientset, namespace)
 		allDiffs = append(allDiffs, namespaceDeploymentDiff)
 
-		namespaceStatefulsetDiff := getUnusedStatefulsets(clientset, namespace)
+		namespaceStatefulsetDiff := getUnusedStatefulSets(clientset, namespace)
 		allDiffs = append(allDiffs, namespaceStatefulsetDiff)
 
 		namespaceRoleDiff := getUnusedRoles(clientset, namespace)
diff --git a/pkg/kor/confimgmaps.go b/pkg/kor/confimgmaps.go
index e5438f7..64ca796 100644
--- a/pkg/kor/confimgmaps.go
+++ b/pkg/kor/confimgmaps.go
@@ -17,7 +17,7 @@ var exceptionconfigmaps = []ExceptionResource{
 	{ResourceName: "kube-root-ca.crt", Namespace: "*"},
 }
 
-func retrieveUsedCM(kubeClient *kubernetes.Clientset, namespace string) ([]string, []string, []string, []string, []string, []string, error) {
+func retrieveUsedCM(clientset kubernetes.Interface, namespace string) ([]string, []string, []string, []string, []string, []string, error) {
 	var volumesCM []string
 	var volumesProjectedCM []string
 	var envCM []string
@@ -25,13 +25,11 @@ func retrieveUsedCM(kubeClient *kubernetes.Clientset, namespace string) ([]strin
 	var envFromContainerCM []string
 	var envFromInitContainerCM []string
 
-	// Retrieve pods in the specified namespace
-	pods, err := kubeClient.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{})
+	pods, err := clientset.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{})
 	if err != nil {
 		return nil, nil, nil, nil, nil, nil, err
 	}
 
-	// Extract volume and environment information from pods
 	for _, pod := range pods.Items {
 		for _, volume := range pod.Spec.Volumes {
 			if volume.ConfigMap != nil {
@@ -85,8 +83,8 @@ func retrieveUsedCM(kubeClient *kubernetes.Clientset, namespace string) ([]strin
 	return volumesCM, volumesProjectedCM, envCM, envFromCM, envFromContainerCM, envFromInitContainerCM, nil
 }
 
-func retrieveConfigMapNames(kubeClient *kubernetes.Clientset, namespace string) ([]string, error) {
-	configmaps, err := kubeClient.CoreV1().ConfigMaps(namespace).List(context.TODO(), metav1.ListOptions{})
+func retrieveConfigMapNames(clientset kubernetes.Interface, namespace string) ([]string, error) {
+	configmaps, err := clientset.CoreV1().ConfigMaps(namespace).List(context.TODO(), metav1.ListOptions{})
 	if err != nil {
 		return nil, err
 	}
@@ -101,8 +99,8 @@ func retrieveConfigMapNames(kubeClient *kubernetes.Clientset, namespace string)
 	return names, nil
 }
 
-func processNamespaceCM(kubeClient *kubernetes.Clientset, namespace string) ([]string, error) {
-	volumesCM, volumesProjectedCM, envCM, envFromCM, envFromContainerCM, envFromInitContainerCM, err := retrieveUsedCM(kubeClient, namespace)
+func processNamespaceCM(clientset kubernetes.Interface, namespace string) ([]string, error) {
+	volumesCM, volumesProjectedCM, envCM, envFromCM, envFromContainerCM, envFromInitContainerCM, err := retrieveUsedCM(clientset, namespace)
 	if err != nil {
 		return nil, err
 	}
@@ -114,7 +112,7 @@ func processNamespaceCM(kubeClient *kubernetes.Clientset, namespace string) ([]s
 	envFromContainerCM = RemoveDuplicatesAndSort(envFromContainerCM)
 	envFromInitContainerCM = RemoveDuplicatesAndSort(envFromInitContainerCM)
 
-	configMapNames, err := retrieveConfigMapNames(kubeClient, namespace)
+	configMapNames, err := retrieveConfigMapNames(clientset, namespace)
 	if err != nil {
 		return nil, err
 	}
@@ -130,7 +128,7 @@ func processNamespaceCM(kubeClient *kubernetes.Clientset, namespace string) ([]s
 
 }
 
-func GetUnusedConfigmaps(includeExcludeLists IncludeExcludeLists, clientset *kubernetes.Clientset) {
+func GetUnusedConfigmaps(includeExcludeLists IncludeExcludeLists, clientset kubernetes.Interface) {
 	namespaces := SetNamespaceList(includeExcludeLists, clientset)
 
 	for _, namespace := range namespaces {
@@ -145,7 +143,7 @@ func GetUnusedConfigmaps(includeExcludeLists IncludeExcludeLists, clientset *kub
 	}
 }
 
-func GetUnusedConfigmapsStructured(includeExcludeLists IncludeExcludeLists, clientset *kubernetes.Clientset, outputFormat string) (string, error) {
+func GetUnusedConfigmapsStructured(includeExcludeLists IncludeExcludeLists, clientset kubernetes.Interface, outputFormat string) (string, error) {
 	namespaces := SetNamespaceList(includeExcludeLists, clientset)
 	response := make(map[string]map[string][]string)
 
diff --git a/pkg/kor/deployments.go b/pkg/kor/deployments.go
index 8601eaa..3285ea7 100644
--- a/pkg/kor/deployments.go
+++ b/pkg/kor/deployments.go
@@ -11,8 +11,8 @@ import (
 	"sigs.k8s.io/yaml"
 )
 
-func getDeploymentsWithoutReplicas(kubeClient *kubernetes.Clientset, namespace string) ([]string, error) {
-	deploymentsList, err := kubeClient.AppsV1().Deployments(namespace).List(context.TODO(), metav1.ListOptions{})
+func ProcessNamespaceDeployments(clientset kubernetes.Interface, namespace string) ([]string, error) {
+	deploymentsList, err := clientset.AppsV1().Deployments(namespace).List(context.TODO(), metav1.ListOptions{})
 	if err != nil {
 		return nil, err
 	}
@@ -32,16 +32,7 @@ func getDeploymentsWithoutReplicas(kubeClient *kubernetes.Clientset, namespace s
 	return deploymentsWithoutReplicas, nil
 }
 
-func ProcessNamespaceDeployments(clientset *kubernetes.Clientset, namespace string) ([]string, error) {
-	usedServices, err := getDeploymentsWithoutReplicas(clientset, namespace)
-	if err != nil {
-		return nil, err
-	}
-
-	return usedServices, nil
-}
-
-func GetUnusedDeployments(includeExcludeLists IncludeExcludeLists, clientset *kubernetes.Clientset) {
+func GetUnusedDeployments(includeExcludeLists IncludeExcludeLists, clientset kubernetes.Interface) {
 	namespaces := SetNamespaceList(includeExcludeLists, clientset)
 
 	for _, namespace := range namespaces {
@@ -56,7 +47,7 @@ func GetUnusedDeployments(includeExcludeLists IncludeExcludeLists, clientset *ku
 	}
 }
 
-func GetUnusedDeploymentsStructured(includeExcludeLists IncludeExcludeLists, clientset *kubernetes.Clientset, outputFormat string) (string, error) {
+func GetUnusedDeploymentsStructured(includeExcludeLists IncludeExcludeLists, clientset kubernetes.Interface, outputFormat string) (string, error) {
 	namespaces := SetNamespaceList(includeExcludeLists, clientset)
 	response := make(map[string]map[string][]string)
 
diff --git a/pkg/kor/hpas.go b/pkg/kor/hpas.go
index e47903d..635fb7e 100644
--- a/pkg/kor/hpas.go
+++ b/pkg/kor/hpas.go
@@ -13,7 +13,7 @@ import (
 	"sigs.k8s.io/yaml"
 )
 
-func getDeploymentNames(clientset *kubernetes.Clientset, namespace string) ([]string, error) {
+func getDeploymentNames(clientset kubernetes.Interface, namespace string) ([]string, error) {
 	deployments, err := clientset.AppsV1().Deployments(namespace).List(context.TODO(), metav1.ListOptions{})
 	if err != nil {
 		return nil, err
@@ -25,19 +25,19 @@ func getDeploymentNames(clientset *kubernetes.Clientset, namespace string) ([]st
 	return names, nil
 }
 
-func getStatefulSetNames(clientset *kubernetes.Clientset, namespace string) ([]string, error) {
-	statefulsets, err := clientset.AppsV1().StatefulSets(namespace).List(context.TODO(), metav1.ListOptions{})
+func getStatefulSetNames(clientset kubernetes.Interface, namespace string) ([]string, error) {
+	statefulSets, err := clientset.AppsV1().StatefulSets(namespace).List(context.TODO(), metav1.ListOptions{})
 	if err != nil {
 		return nil, err
 	}
-	names := make([]string, 0, len(statefulsets.Items))
-	for _, statefulset := range statefulsets.Items {
-		names = append(names, statefulset.Name)
+	names := make([]string, 0, len(statefulSets.Items))
+	for _, statefulSet := range statefulSets.Items {
+		names = append(names, statefulSet.Name)
 	}
 	return names, nil
 }
 
-func extractUnusedHpas(clientset *kubernetes.Clientset, namespace string) ([]string, error) {
+func extractUnusedHpas(clientset kubernetes.Interface, namespace string) ([]string, error) {
 	deploymentNames, err := getDeploymentNames(clientset, namespace)
 	if err != nil {
 		return nil, err
@@ -46,7 +46,7 @@ func extractUnusedHpas(clientset *kubernetes.Clientset, namespace string) ([]str
 	if err != nil {
 		return nil, err
 	}
-	hpas, err := clientset.AutoscalingV1().HorizontalPodAutoscalers(namespace).List(context.TODO(), metav1.ListOptions{})
+	hpas, err := clientset.AutoscalingV2().HorizontalPodAutoscalers(namespace).List(context.TODO(), metav1.ListOptions{})
 	if err != nil {
 		return nil, err
 	}
@@ -71,7 +71,7 @@ func extractUnusedHpas(clientset *kubernetes.Clientset, namespace string) ([]str
 	return diff, nil
 }
 
-func processNamespaceHpas(clientset *kubernetes.Clientset, namespace string) ([]string, error) {
+func processNamespaceHpas(clientset kubernetes.Interface, namespace string) ([]string, error) {
 	unusedHpas, err := extractUnusedHpas(clientset, namespace)
 	if err != nil {
 		return nil, err
@@ -79,7 +79,7 @@ func processNamespaceHpas(clientset *kubernetes.Clientset, namespace string) ([]
 	return unusedHpas, nil
 }
 
-func GetUnusedHpas(includeExcludeLists IncludeExcludeLists, clientset *kubernetes.Clientset) {
+func GetUnusedHpas(includeExcludeLists IncludeExcludeLists, clientset kubernetes.Interface) {
 	namespaces := SetNamespaceList(includeExcludeLists, clientset)
 
 	for _, namespace := range namespaces {
@@ -95,7 +95,7 @@ func GetUnusedHpas(includeExcludeLists IncludeExcludeLists, clientset *kubernete
 
 }
 
-func GetUnusedHpasStructured(includeExcludeLists IncludeExcludeLists, clientset *kubernetes.Clientset, outputFormat string) (string, error) {
+func GetUnusedHpasStructured(includeExcludeLists IncludeExcludeLists, clientset kubernetes.Interface, outputFormat string) (string, error) {
 	namespaces := SetNamespaceList(includeExcludeLists, clientset)
 	response := make(map[string]map[string][]string)
 
diff --git a/pkg/kor/ingresses.go b/pkg/kor/ingresses.go
index f6a4eae..b657dc4 100644
--- a/pkg/kor/ingresses.go
+++ b/pkg/kor/ingresses.go
@@ -13,11 +13,11 @@ import (
 	"sigs.k8s.io/yaml"
 )
 
-func validateServiceBackend(kubeClient *kubernetes.Clientset, namespace string, backend *v1.IngressBackend) bool {
+func validateServiceBackend(clientset kubernetes.Interface, namespace string, backend *v1.IngressBackend) bool {
 	if backend.Service != nil {
 		serviceName := backend.Service.Name
 
-		_, err := kubeClient.CoreV1().Services(namespace).Get(context.TODO(), serviceName, metav1.GetOptions{})
+		_, err := clientset.CoreV1().Services(namespace).Get(context.TODO(), serviceName, metav1.GetOptions{})
 		if err != nil {
 			return false
 		}
@@ -25,8 +25,8 @@ func validateServiceBackend(kubeClient *kubernetes.Clientset, namespace string,
 	return true
 }
 
-func retrieveUsedIngress(kubeClient *kubernetes.Clientset, namespace string) ([]string, error) {
-	ingresses, err := kubeClient.NetworkingV1().Ingresses(namespace).List(context.TODO(), metav1.ListOptions{})
+func retrieveUsedIngress(clientset kubernetes.Interface, namespace string) ([]string, error) {
+	ingresses, err := clientset.NetworkingV1().Ingresses(namespace).List(context.TODO(), metav1.ListOptions{})
 	if err != nil {
 		return nil, err
 	}
@@ -41,11 +41,11 @@ func retrieveUsedIngress(kubeClient *kubernetes.Clientset, namespace string) ([]
 		used := true
 
 		if ingress.Spec.DefaultBackend != nil {
-			used = validateServiceBackend(kubeClient, namespace, ingress.Spec.DefaultBackend)
+			used = validateServiceBackend(clientset, namespace, ingress.Spec.DefaultBackend)
 		}
 		for _, rule := range ingress.Spec.Rules {
 			for _, path := range rule.HTTP.Paths {
-				used = validateServiceBackend(kubeClient, namespace, &path.Backend)
+				used = validateServiceBackend(clientset, namespace, &path.Backend)
 				if used {
 					break
 				}
@@ -61,8 +61,8 @@ func retrieveUsedIngress(kubeClient *kubernetes.Clientset, namespace string) ([]
 	return usedIngresses, nil
 }
 
-func retrieveIngressNames(kubeClient *kubernetes.Clientset, namespace string) ([]string, error) {
-	ingresses, err := kubeClient.NetworkingV1().Ingresses(namespace).List(context.TODO(), metav1.ListOptions{})
+func retrieveIngressNames(clientset kubernetes.Interface, namespace string) ([]string, error) {
+	ingresses, err := clientset.NetworkingV1().Ingresses(namespace).List(context.TODO(), metav1.ListOptions{})
 	if err != nil {
 		return nil, err
 	}
@@ -73,12 +73,12 @@ func retrieveIngressNames(kubeClient *kubernetes.Clientset, namespace string) ([
 	return names, nil
 }
 
-func processNamespaceIngresses(kubeClient *kubernetes.Clientset, namespace string) ([]string, error) {
-	usedIngresses, err := retrieveUsedIngress(kubeClient, namespace)
+func processNamespaceIngresses(clientset kubernetes.Interface, namespace string) ([]string, error) {
+	usedIngresses, err := retrieveUsedIngress(clientset, namespace)
 	if err != nil {
 		return nil, err
 	}
-	ingressNames, err := retrieveIngressNames(kubeClient, namespace)
+	ingressNames, err := retrieveIngressNames(clientset, namespace)
 	if err != nil {
 		return nil, err
 	}
@@ -88,7 +88,7 @@ func processNamespaceIngresses(kubeClient *kubernetes.Clientset, namespace strin
 
 }
 
-func GetUnusedIngresses(includeExcludeLists IncludeExcludeLists, clientset *kubernetes.Clientset) {
+func GetUnusedIngresses(includeExcludeLists IncludeExcludeLists, clientset kubernetes.Interface) {
 	namespaces := SetNamespaceList(includeExcludeLists, clientset)
 
 	for _, namespace := range namespaces {
@@ -103,7 +103,7 @@ func GetUnusedIngresses(includeExcludeLists IncludeExcludeLists, clientset *kube
 	}
 }
 
-func GetUnusedIngressesStructured(includeExcludeLists IncludeExcludeLists, clientset *kubernetes.Clientset, outputFormat string) (string, error) {
+func GetUnusedIngressesStructured(includeExcludeLists IncludeExcludeLists, clientset kubernetes.Interface, outputFormat string) (string, error) {
 	namespaces := SetNamespaceList(includeExcludeLists, clientset)
 	response := make(map[string]map[string][]string)
 
diff --git a/pkg/kor/kor.go b/pkg/kor/kor.go
index f7c0f9b..d2ebe91 100644
--- a/pkg/kor/kor.go
+++ b/pkg/kor/kor.go
@@ -80,7 +80,7 @@ func GetKubeClient(kubeconfig string) *kubernetes.Clientset {
 	return clientset
 }
 
-func SetNamespaceList(namespaceLists IncludeExcludeLists, kubeClient *kubernetes.Clientset) []string {
+func SetNamespaceList(namespaceLists IncludeExcludeLists, clientset kubernetes.Interface) []string {
 	namespaces := make([]string, 0)
 	namespacesMap := make(map[string]bool)
 	if namespaceLists.IncludeListStr != "" && namespaceLists.ExcludeListStr != "" {
@@ -89,7 +89,7 @@ func SetNamespaceList(namespaceLists IncludeExcludeLists, kubeClient *kubernetes
 	}
 	includeNamespaces := strings.Split(namespaceLists.IncludeListStr, ",")
 	excludeNamespaces := strings.Split(namespaceLists.ExcludeListStr, ",")
-	namespaceList, err := kubeClient.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{})
+	namespaceList, err := clientset.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{})
 	if err != nil {
 		fmt.Fprintf(os.Stderr, "Failed to retrieve namespaces: %v\n", err)
 		os.Exit(1)
diff --git a/pkg/kor/multi.go b/pkg/kor/multi.go
index a45d144..9caee0e 100644
--- a/pkg/kor/multi.go
+++ b/pkg/kor/multi.go
@@ -9,42 +9,42 @@ import (
 	"sigs.k8s.io/yaml"
 )
 
-func retrieveNamespaceDiffs(kubeClient *kubernetes.Clientset, namespace string, resourceList []string) []ResourceDiff {
+func retrieveNamespaceDiffs(clientset kubernetes.Interface, namespace string, resourceList []string) []ResourceDiff {
 	var allDiffs []ResourceDiff
 	for _, resource := range resourceList {
 		switch resource {
 		case "cm", "configmap", "configmaps":
-			namespaceCMDiff := getUnusedCMs(kubeClient, namespace)
+			namespaceCMDiff := getUnusedCMs(clientset, namespace)
 			allDiffs = append(allDiffs, namespaceCMDiff)
 		case "svc", "service", "services":
-			namespaceSVCDiff := getUnusedSVCs(kubeClient, namespace)
+			namespaceSVCDiff := getUnusedSVCs(clientset, namespace)
 			allDiffs = append(allDiffs, namespaceSVCDiff)
 		case "scrt", "secret", "secrets":
-			namespaceSecretDiff := getUnusedSecrets(kubeClient, namespace)
+			namespaceSecretDiff := getUnusedSecrets(clientset, namespace)
 			allDiffs = append(allDiffs, namespaceSecretDiff)
 		case "sa", "serviceaccount", "serviceaccounts":
-			namespaceSADiff := getUnusedServiceAccounts(kubeClient, namespace)
+			namespaceSADiff := getUnusedServiceAccounts(clientset, namespace)
 			allDiffs = append(allDiffs, namespaceSADiff)
 		case "deploy", "deployment", "deployments":
-			namespaceDeploymentDiff := getUnusedDeployments(kubeClient, namespace)
+			namespaceDeploymentDiff := getUnusedDeployments(clientset, namespace)
 			allDiffs = append(allDiffs, namespaceDeploymentDiff)
 		case "sts", "statefulset", "statefulsets":
-			namespaceStatefulsetDiff := getUnusedStatefulsets(kubeClient, namespace)
+			namespaceStatefulsetDiff := getUnusedStatefulSets(clientset, namespace)
 			allDiffs = append(allDiffs, namespaceStatefulsetDiff)
 		case "role", "roles":
-			namespaceRoleDiff := getUnusedRoles(kubeClient, namespace)
+			namespaceRoleDiff := getUnusedRoles(clientset, namespace)
 			allDiffs = append(allDiffs, namespaceRoleDiff)
 		case "hpa", "horizontalpodautoscaler", "horizontalpodautoscalers":
-			namespaceHpaDiff := getUnusedHpas(kubeClient, namespace)
+			namespaceHpaDiff := getUnusedHpas(clientset, namespace)
 			allDiffs = append(allDiffs, namespaceHpaDiff)
 		case "pvc", "persistentvolumeclaim", "persistentvolumeclaims":
-			namespacePvcDiff := getUnusedPvcs(kubeClient, namespace)
+			namespacePvcDiff := getUnusedPvcs(clientset, namespace)
 			allDiffs = append(allDiffs, namespacePvcDiff)
 		case "ing", "ingress", "ingresses":
-			namespaceIngressDiff := getUnusedIngresses(kubeClient, namespace)
+			namespaceIngressDiff := getUnusedIngresses(clientset, namespace)
 			allDiffs = append(allDiffs, namespaceIngressDiff)
 		case "pdb", "poddisruptionbudget", "poddisruptionbudgets":
-			namespacePdbDiff := getUnusedPdbs(kubeClient, namespace)
+			namespacePdbDiff := getUnusedPdbs(clientset, namespace)
 			allDiffs = append(allDiffs, namespacePdbDiff)
 		default:
 			fmt.Printf("resource type %q is not supported\n", resource)
@@ -54,16 +54,16 @@ func retrieveNamespaceDiffs(kubeClient *kubernetes.Clientset, namespace string,
 }
 
 func GetUnusedMulti(includeExcludeLists IncludeExcludeLists, kubeconfig, resourceNames string) {
-	var kubeClient *kubernetes.Clientset
+	var clientset kubernetes.Interface
 	var namespaces []string
 
-	kubeClient = GetKubeClient(kubeconfig)
+	clientset = GetKubeClient(kubeconfig)
 
 	resourceList := strings.Split(resourceNames, ",")
-	namespaces = SetNamespaceList(includeExcludeLists, kubeClient)
+	namespaces = SetNamespaceList(includeExcludeLists, clientset)
 
 	for _, namespace := range namespaces {
-		allDiffs := retrieveNamespaceDiffs(kubeClient, namespace, resourceList)
+		allDiffs := retrieveNamespaceDiffs(clientset, namespace, resourceList)
 		output := FormatOutputAll(namespace, allDiffs)
 		fmt.Println(output)
 		fmt.Println()
@@ -71,19 +71,19 @@ func GetUnusedMulti(includeExcludeLists IncludeExcludeLists, kubeconfig, resourc
 }
 
 func GetUnusedMultiStructured(includeExcludeLists IncludeExcludeLists, kubeconfig, outputFormat, resourceNames string) (string, error) {
-	var kubeClient *kubernetes.Clientset
+	var clientset kubernetes.Interface
 	var namespaces []string
 
-	kubeClient = GetKubeClient(kubeconfig)
+	clientset = GetKubeClient(kubeconfig)
 
 	resourceList := strings.Split(resourceNames, ",")
-	namespaces = SetNamespaceList(includeExcludeLists, kubeClient)
+	namespaces = SetNamespaceList(includeExcludeLists, clientset)
 
 	// Create the JSON response object
 	response := make(map[string]map[string][]string)
 
 	for _, namespace := range namespaces {
-		allDiffs := retrieveNamespaceDiffs(kubeClient, namespace, resourceList)
+		allDiffs := retrieveNamespaceDiffs(clientset, namespace, resourceList)
 		// Store the unused resources for each resource type in the JSON response
 		resourceMap := make(map[string][]string)
 		for _, diff := range allDiffs {
diff --git a/pkg/kor/pdbs.go b/pkg/kor/pdbs.go
index 893dae8..b0458a0 100644
--- a/pkg/kor/pdbs.go
+++ b/pkg/kor/pdbs.go
@@ -12,7 +12,7 @@ import (
 	"sigs.k8s.io/yaml"
 )
 
-func processNamespacePdbs(clientset *kubernetes.Clientset, namespace string) ([]string, error) {
+func processNamespacePdbs(clientset kubernetes.Interface, namespace string) ([]string, error) {
 	var unusedPdbs []string
 	pdbs, err := clientset.PolicyV1().PodDisruptionBudgets(namespace).List(context.TODO(), metav1.ListOptions{})
 	if err != nil {
@@ -25,26 +25,30 @@ func processNamespacePdbs(clientset *kubernetes.Clientset, namespace string) ([]
 		}
 
 		selector := pdb.Spec.Selector
+		if len(selector.MatchLabels) == 0 {
+			unusedPdbs = append(unusedPdbs, pdb.Name)
+			continue
+		}
 		deployments, err := clientset.AppsV1().Deployments(namespace).List(context.TODO(), metav1.ListOptions{
 			LabelSelector: metav1.FormatLabelSelector(selector),
 		})
 		if err != nil {
 			return nil, err
 		}
-		statefulsets, err := clientset.AppsV1().StatefulSets(namespace).List(context.TODO(), metav1.ListOptions{
+		statefulSets, err := clientset.AppsV1().StatefulSets(namespace).List(context.TODO(), metav1.ListOptions{
 			LabelSelector: metav1.FormatLabelSelector(selector),
 		})
 		if err != nil {
 			return nil, err
 		}
-		if len(deployments.Items) == 0 && len(statefulsets.Items) == 0 {
+		if len(deployments.Items) == 0 && len(statefulSets.Items) == 0 {
 			unusedPdbs = append(unusedPdbs, pdb.Name)
 		}
 	}
 	return unusedPdbs, nil
 }
 
-func GetUnusedPdbs(includeExcludeLists IncludeExcludeLists, clientset *kubernetes.Clientset) {
+func GetUnusedPdbs(includeExcludeLists IncludeExcludeLists, clientset kubernetes.Interface) {
 	namespaces := SetNamespaceList(includeExcludeLists, clientset)
 
 	for _, namespace := range namespaces {
@@ -59,7 +63,7 @@ func GetUnusedPdbs(includeExcludeLists IncludeExcludeLists, clientset *kubernete
 	}
 }
 
-func GetUnusedPdbsStructured(includeExcludeLists IncludeExcludeLists, clientset *kubernetes.Clientset, outputFormat string) (string, error) {
+func GetUnusedPdbsStructured(includeExcludeLists IncludeExcludeLists, clientset kubernetes.Interface, outputFormat string) (string, error) {
 	namespaces := SetNamespaceList(includeExcludeLists, clientset)
 	response := make(map[string]map[string][]string)
 
diff --git a/pkg/kor/pvc.go b/pkg/kor/pvc.go
index 8ac4cbc..4303566 100644
--- a/pkg/kor/pvc.go
+++ b/pkg/kor/pvc.go
@@ -12,8 +12,8 @@ import (
 	"sigs.k8s.io/yaml"
 )
 
-func retreiveUsedPvcs(kubeClient *kubernetes.Clientset, namespace string) ([]string, error) {
-	pods, err := kubeClient.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{})
+func retreiveUsedPvcs(clientset kubernetes.Interface, namespace string) ([]string, error) {
+	pods, err := clientset.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{})
 	if err != nil {
 		fmt.Printf("Failed to list Pods: %v\n", err)
 		os.Exit(1)
@@ -30,8 +30,8 @@ func retreiveUsedPvcs(kubeClient *kubernetes.Clientset, namespace string) ([]str
 	return usedPvcs, err
 }
 
-func processNamespacePvcs(kubeClient *kubernetes.Clientset, namespace string) ([]string, error) {
-	pvcs, err := kubeClient.CoreV1().PersistentVolumeClaims(namespace).List(context.TODO(), metav1.ListOptions{})
+func processNamespacePvcs(clientset kubernetes.Interface, namespace string) ([]string, error) {
+	pvcs, err := clientset.CoreV1().PersistentVolumeClaims(namespace).List(context.TODO(), metav1.ListOptions{})
 	if err != nil {
 		return nil, err
 	}
@@ -44,7 +44,7 @@ func processNamespacePvcs(kubeClient *kubernetes.Clientset, namespace string) ([
 		pvcNames = append(pvcNames, pvc.Name)
 	}
 
-	usedPvcs, err := retreiveUsedPvcs(kubeClient, namespace)
+	usedPvcs, err := retreiveUsedPvcs(clientset, namespace)
 	if err != nil {
 		return nil, err
 	}
@@ -53,7 +53,7 @@ func processNamespacePvcs(kubeClient *kubernetes.Clientset, namespace string) ([
 	return diff, nil
 }
 
-func GetUnusedPvcs(includeExcludeLists IncludeExcludeLists, clientset *kubernetes.Clientset) {
+func GetUnusedPvcs(includeExcludeLists IncludeExcludeLists, clientset kubernetes.Interface) {
 	namespaces := SetNamespaceList(includeExcludeLists, clientset)
 
 	for _, namespace := range namespaces {
@@ -69,7 +69,7 @@ func GetUnusedPvcs(includeExcludeLists IncludeExcludeLists, clientset *kubernete
 
 }
 
-func GetUnusedPvcsStructured(includeExcludeLists IncludeExcludeLists, clientset *kubernetes.Clientset, outputFormat string) (string, error) {
+func GetUnusedPvcsStructured(includeExcludeLists IncludeExcludeLists, clientset kubernetes.Interface, outputFormat string) (string, error) {
 	namespaces := SetNamespaceList(includeExcludeLists, clientset)
 	response := make(map[string]map[string][]string)
 
diff --git a/pkg/kor/roles.go b/pkg/kor/roles.go
index a417fff..93ddc55 100644
--- a/pkg/kor/roles.go
+++ b/pkg/kor/roles.go
@@ -12,25 +12,19 @@ import (
 	"sigs.k8s.io/yaml"
 )
 
-func retrieveUsedRoles(clientset *kubernetes.Clientset, namespace string) ([]string, error) {
+func retrieveUsedRoles(clientset kubernetes.Interface, namespace string) ([]string, error) {
 	// Get a list of all role bindings in the specified namespace
 	roleBindings, err := clientset.RbacV1().RoleBindings(namespace).List(context.TODO(), metav1.ListOptions{})
 	if err != nil {
 		return nil, fmt.Errorf("failed to list role bindings in namespace %s: %v", namespace, err)
 	}
 
-	// Create a map to store role binding names
 	usedRoles := make(map[string]bool)
-
-	// Populate the map with role binding names
 	for _, rb := range roleBindings.Items {
 		usedRoles[rb.RoleRef.Name] = true
 	}
 
-	// Create a slice to store used role names
 	var usedRoleNames []string
-
-	// Extract used role names from the map
 	for role := range usedRoles {
 		usedRoleNames = append(usedRoleNames, role)
 	}
@@ -38,8 +32,8 @@ func retrieveUsedRoles(clientset *kubernetes.Clientset, namespace string) ([]str
 	return usedRoleNames, nil
 }
 
-func retrieveRoleNames(kubeClient *kubernetes.Clientset, namespace string) ([]string, error) {
-	roles, err := kubeClient.RbacV1().Roles(namespace).List(context.TODO(), metav1.ListOptions{})
+func retrieveRoleNames(clientset kubernetes.Interface, namespace string) ([]string, error) {
+	roles, err := clientset.RbacV1().Roles(namespace).List(context.TODO(), metav1.ListOptions{})
 	if err != nil {
 		return nil, err
 	}
@@ -54,15 +48,15 @@ func retrieveRoleNames(kubeClient *kubernetes.Clientset, namespace string) ([]st
 	return names, nil
 }
 
-func processNamespaceRoles(kubeClient *kubernetes.Clientset, namespace string) ([]string, error) {
-	usedRoles, err := retrieveUsedRoles(kubeClient, namespace)
+func processNamespaceRoles(clientset kubernetes.Interface, namespace string) ([]string, error) {
+	usedRoles, err := retrieveUsedRoles(clientset, namespace)
 	if err != nil {
 		return nil, err
 	}
 
 	usedRoles = RemoveDuplicatesAndSort(usedRoles)
 
-	roleNames, err := retrieveRoleNames(kubeClient, namespace)
+	roleNames, err := retrieveRoleNames(clientset, namespace)
 	if err != nil {
 		return nil, err
 	}
@@ -72,7 +66,7 @@ func processNamespaceRoles(kubeClient *kubernetes.Clientset, namespace string) (
 
 }
 
-func GetUnusedRoles(includeExcludeLists IncludeExcludeLists, clientset *kubernetes.Clientset) {
+func GetUnusedRoles(includeExcludeLists IncludeExcludeLists, clientset kubernetes.Interface) {
 	namespaces := SetNamespaceList(includeExcludeLists, clientset)
 
 	for _, namespace := range namespaces {
@@ -87,7 +81,7 @@ func GetUnusedRoles(includeExcludeLists IncludeExcludeLists, clientset *kubernet
 	}
 }
 
-func GetUnusedRolesStructured(includeExcludeLists IncludeExcludeLists, clientset *kubernetes.Clientset, outputFormat string) (string, error) {
+func GetUnusedRolesStructured(includeExcludeLists IncludeExcludeLists, clientset kubernetes.Interface, outputFormat string) (string, error) {
 	namespaces := SetNamespaceList(includeExcludeLists, clientset)
 	response := make(map[string]map[string][]string)
 
diff --git a/pkg/kor/secrets.go b/pkg/kor/secrets.go
index 9c1b3e4..9a42133 100644
--- a/pkg/kor/secrets.go
+++ b/pkg/kor/secrets.go
@@ -19,7 +19,7 @@ var exceptionSecretTypes = []string{
 	`kubernetes.io/service-account-token`,
 }
 
-func retrieveIngressTLS(clientset *kubernetes.Clientset, namespace string) ([]string, error) {
+func retrieveIngressTLS(clientset kubernetes.Interface, namespace string) ([]string, error) {
 	secretNames := make([]string, 0)
 	ingressList, err := clientset.NetworkingV1().Ingresses(namespace).List(context.TODO(), metav1.ListOptions{})
 	if err != nil {
@@ -37,7 +37,7 @@ func retrieveIngressTLS(clientset *kubernetes.Clientset, namespace string) ([]st
 
 }
 
-func retrieveUsedSecret(kubeClient *kubernetes.Clientset, namespace string) ([]string, []string, []string, []string, []string, []string, error) {
+func retrieveUsedSecret(clientset kubernetes.Interface, namespace string) ([]string, []string, []string, []string, []string, []string, error) {
 	var envSecrets []string
 	var envSecrets2 []string
 	var volumeSecrets []string
@@ -45,7 +45,7 @@ func retrieveUsedSecret(kubeClient *kubernetes.Clientset, namespace string) ([]s
 	var initContainerEnvSecrets []string
 
 	// Retrieve pods in the specified namespace
-	pods, err := kubeClient.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{})
+	pods, err := clientset.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{})
 	if err != nil {
 		return nil, nil, nil, nil, nil, nil, err
 	}
@@ -85,7 +85,7 @@ func retrieveUsedSecret(kubeClient *kubernetes.Clientset, namespace string) ([]s
 		}
 	}
 
-	tlsSecrets, err := retrieveIngressTLS(kubeClient, namespace)
+	tlsSecrets, err := retrieveIngressTLS(clientset, namespace)
 	if err != nil {
 		return nil, nil, nil, nil, nil, nil, err
 	}
@@ -93,8 +93,8 @@ func retrieveUsedSecret(kubeClient *kubernetes.Clientset, namespace string) ([]s
 	return envSecrets, envSecrets2, volumeSecrets, initContainerEnvSecrets, pullSecrets, tlsSecrets, nil
 }
 
-func retrieveSecretNames(kubeClient *kubernetes.Clientset, namespace string) ([]string, error) {
-	secrets, err := kubeClient.CoreV1().Secrets(namespace).List(context.TODO(), metav1.ListOptions{})
+func retrieveSecretNames(clientset kubernetes.Interface, namespace string) ([]string, error) {
+	secrets, err := clientset.CoreV1().Secrets(namespace).List(context.TODO(), metav1.ListOptions{})
 	if err != nil {
 		return nil, err
 	}
@@ -111,8 +111,8 @@ func retrieveSecretNames(kubeClient *kubernetes.Clientset, namespace string) ([]
 	return names, nil
 }
 
-func processNamespaceSecret(kubeClient *kubernetes.Clientset, namespace string) ([]string, error) {
-	envSecrets, envSecrets2, volumeSecrets, initContainerEnvSecrets, pullSecrets, tlsSecrets, err := retrieveUsedSecret(kubeClient, namespace)
+func processNamespaceSecret(clientset kubernetes.Interface, namespace string) ([]string, error) {
+	envSecrets, envSecrets2, volumeSecrets, initContainerEnvSecrets, pullSecrets, tlsSecrets, err := retrieveUsedSecret(clientset, namespace)
 	if err != nil {
 		return nil, err
 	}
@@ -124,7 +124,7 @@ func processNamespaceSecret(kubeClient *kubernetes.Clientset, namespace string)
 	pullSecrets = RemoveDuplicatesAndSort(pullSecrets)
 	tlsSecrets = RemoveDuplicatesAndSort(tlsSecrets)
 
-	secretNames, err := retrieveSecretNames(kubeClient, namespace)
+	secretNames, err := retrieveSecretNames(clientset, namespace)
 	if err != nil {
 		return nil, err
 	}
@@ -140,7 +140,7 @@ func processNamespaceSecret(kubeClient *kubernetes.Clientset, namespace string)
 
 }
 
-func GetUnusedSecrets(includeExcludeLists IncludeExcludeLists, clientset *kubernetes.Clientset) {
+func GetUnusedSecrets(includeExcludeLists IncludeExcludeLists, clientset kubernetes.Interface) {
 	namespaces := SetNamespaceList(includeExcludeLists, clientset)
 
 	for _, namespace := range namespaces {
@@ -155,7 +155,7 @@ func GetUnusedSecrets(includeExcludeLists IncludeExcludeLists, clientset *kubern
 	}
 }
 
-func GetUnusedSecretsStructured(includeExcludeLists IncludeExcludeLists, clientset *kubernetes.Clientset, outputFormat string) (string, error) {
+func GetUnusedSecretsStructured(includeExcludeLists IncludeExcludeLists, clientset kubernetes.Interface, outputFormat string) (string, error) {
 	namespaces := SetNamespaceList(includeExcludeLists, clientset)
 	response := make(map[string]map[string][]string)
 
diff --git a/pkg/kor/serviceaccounts.go b/pkg/kor/serviceaccounts.go
index f835dc0..b7e90a6 100644
--- a/pkg/kor/serviceaccounts.go
+++ b/pkg/kor/serviceaccounts.go
@@ -15,7 +15,7 @@ var exceptionServiceAccounts = []ExceptionResource{
 	{ResourceName: "default", Namespace: "*"},
 }
 
-func getServiceAccountsFromClusterRoleBindings(clientset *kubernetes.Clientset, namespace string) ([]string, error) {
+func getServiceAccountsFromClusterRoleBindings(clientset kubernetes.Interface, namespace string) ([]string, error) {
 	// Get a list of all role bindings in the specified namespace
 	roleBindings, err := clientset.RbacV1().ClusterRoleBindings().List(context.TODO(), metav1.ListOptions{})
 	if err != nil {
@@ -42,7 +42,7 @@ func getServiceAccountsFromClusterRoleBindings(clientset *kubernetes.Clientset,
 	return serviceAccounts, nil
 }
 
-func getServiceAccountsFromRoleBindings(clientset *kubernetes.Clientset, namespace string) ([]string, error) {
+func getServiceAccountsFromRoleBindings(clientset kubernetes.Interface, namespace string) ([]string, error) {
 	// Get a list of all role bindings in the specified namespace
 	roleBindings, err := clientset.RbacV1().RoleBindings(namespace).List(context.TODO(), metav1.ListOptions{})
 	if err != nil {
@@ -68,11 +68,11 @@ func getServiceAccountsFromRoleBindings(clientset *kubernetes.Clientset, namespa
 	return serviceAccounts, nil
 }
 
-func retrieveUsedSA(kubeClient *kubernetes.Clientset, namespace string) ([]string, []string, []string, error) {
+func retrieveUsedSA(clientset kubernetes.Interface, namespace string) ([]string, []string, []string, error) {
+
 	var podServiceAccounts []string
 
-	// Retrieve pods in the specified namespace
-	pods, err := kubeClient.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{})
+	pods, err := clientset.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{})
 	if err != nil {
 		return nil, nil, nil, err
 	}
@@ -90,19 +90,19 @@ func retrieveUsedSA(kubeClient *kubernetes.Clientset, namespace string) ([]strin
 		}
 	}
 
-	roleServiceAccounts, err := getServiceAccountsFromRoleBindings(kubeClient, namespace)
+	roleServiceAccounts, err := getServiceAccountsFromRoleBindings(clientset, namespace)
 	if err != nil {
 		return nil, nil, nil, err
 	}
-	clusterRoleServiceAccounts, err := getServiceAccountsFromClusterRoleBindings(kubeClient, namespace)
+	clusterRoleServiceAccounts, err := getServiceAccountsFromClusterRoleBindings(clientset, namespace)
 	if err != nil {
 		return nil, nil, nil, err
 	}
 	return podServiceAccounts, roleServiceAccounts, clusterRoleServiceAccounts, nil
 }
 
-func retrieveServiceAccountNames(kubeClient *kubernetes.Clientset, namespace string) ([]string, error) {
-	serviceaccounts, err := kubeClient.CoreV1().ServiceAccounts(namespace).List(context.TODO(), metav1.ListOptions{})
+func retrieveServiceAccountNames(clientset kubernetes.Interface, namespace string) ([]string, error) {
+	serviceaccounts, err := clientset.CoreV1().ServiceAccounts(namespace).List(context.TODO(), metav1.ListOptions{})
 	if err != nil {
 		return nil, err
 	}
@@ -117,8 +117,8 @@ func retrieveServiceAccountNames(kubeClient *kubernetes.Clientset, namespace str
 	return names, nil
 }
 
-func processNamespaceSA(kubeClient *kubernetes.Clientset, namespace string) ([]string, error) {
-	usedServiceAccounts, roleServiceAccounts, clusterRoleServiceAccounts, err := retrieveUsedSA(kubeClient, namespace)
+func processNamespaceSA(clientset kubernetes.Interface, namespace string) ([]string, error) {
+	usedServiceAccounts, roleServiceAccounts, clusterRoleServiceAccounts, err := retrieveUsedSA(clientset, namespace)
 	if err != nil {
 		return nil, err
 	}
@@ -129,7 +129,7 @@ func processNamespaceSA(kubeClient *kubernetes.Clientset, namespace string) ([]s
 
 	usedServiceAccounts = append(append(usedServiceAccounts, roleServiceAccounts...), clusterRoleServiceAccounts...)
 
-	serviceAccountNames, err := retrieveServiceAccountNames(kubeClient, namespace)
+	serviceAccountNames, err := retrieveServiceAccountNames(clientset, namespace)
 	if err != nil {
 		return nil, err
 	}
@@ -139,7 +139,7 @@ func processNamespaceSA(kubeClient *kubernetes.Clientset, namespace string) ([]s
 
 }
 
-func GetUnusedServiceAccounts(includeExcludeLists IncludeExcludeLists, clientset *kubernetes.Clientset) {
+func GetUnusedServiceAccounts(includeExcludeLists IncludeExcludeLists, clientset kubernetes.Interface) {
 	namespaces := SetNamespaceList(includeExcludeLists, clientset)
 
 	for _, namespace := range namespaces {
@@ -154,7 +154,7 @@ func GetUnusedServiceAccounts(includeExcludeLists IncludeExcludeLists, clientset
 	}
 }
 
-func GetUnusedServiceAccountsStructured(includeExcludeLists IncludeExcludeLists, clientset *kubernetes.Clientset, outputFormat string) (string, error) {
+func GetUnusedServiceAccountsStructured(includeExcludeLists IncludeExcludeLists, clientset kubernetes.Interface, outputFormat string) (string, error) {
 	namespaces := SetNamespaceList(includeExcludeLists, clientset)
 	response := make(map[string]map[string][]string)
 
diff --git a/pkg/kor/services.go b/pkg/kor/services.go
index 1f5008b..14a2cb8 100644
--- a/pkg/kor/services.go
+++ b/pkg/kor/services.go
@@ -11,8 +11,8 @@ import (
 	"sigs.k8s.io/yaml"
 )
 
-func getEndpointsWithoutSubsets(kubeClient *kubernetes.Clientset, namespace string) ([]string, error) {
-	endpointsList, err := kubeClient.CoreV1().Endpoints(namespace).List(context.TODO(), metav1.ListOptions{})
+func ProcessNamespaceServices(clientset kubernetes.Interface, namespace string) ([]string, error) {
+	endpointsList, err := clientset.CoreV1().Endpoints(namespace).List(context.TODO(), metav1.ListOptions{})
 	if err != nil {
 		return nil, err
 	}
@@ -32,16 +32,7 @@ func getEndpointsWithoutSubsets(kubeClient *kubernetes.Clientset, namespace stri
 	return endpointsWithoutSubsets, nil
 }
 
-func ProcessNamespaceServices(clientset *kubernetes.Clientset, namespace string) ([]string, error) {
-	usedServices, err := getEndpointsWithoutSubsets(clientset, namespace)
-	if err != nil {
-		return nil, err
-	}
-
-	return usedServices, nil
-}
-
-func GetUnusedServices(includeExcludeLists IncludeExcludeLists, clientset *kubernetes.Clientset) {
+func GetUnusedServices(includeExcludeLists IncludeExcludeLists, clientset kubernetes.Interface) {
 	namespaces := SetNamespaceList(includeExcludeLists, clientset)
 
 	for _, namespace := range namespaces {
@@ -56,7 +47,7 @@ func GetUnusedServices(includeExcludeLists IncludeExcludeLists, clientset *kuber
 	}
 }
 
-func GetUnusedServicesStructured(includeExcludeLists IncludeExcludeLists, clientset *kubernetes.Clientset, outputFormat string) (string, error) {
+func GetUnusedServicesStructured(includeExcludeLists IncludeExcludeLists, clientset kubernetes.Interface, outputFormat string) (string, error) {
 	namespaces := SetNamespaceList(includeExcludeLists, clientset)
 	response := make(map[string]map[string][]string)
 
diff --git a/pkg/kor/statefulsets.go b/pkg/kor/statefulsets.go
index 5713f6f..6c7102e 100644
--- a/pkg/kor/statefulsets.go
+++ b/pkg/kor/statefulsets.go
@@ -11,57 +11,44 @@ import (
 	"sigs.k8s.io/yaml"
 )
 
-func getStatefulsetsWithoutReplicas(kubeClient *kubernetes.Clientset, namespace string) ([]string, error) {
-	statefulsetsList, err := kubeClient.AppsV1().StatefulSets(namespace).List(context.TODO(), metav1.ListOptions{})
+func ProcessNamespaceStatefulSets(clientset kubernetes.Interface, namespace string) ([]string, error) {
+	statefulSetsList, err := clientset.AppsV1().StatefulSets(namespace).List(context.TODO(), metav1.ListOptions{})
 	if err != nil {
 		return nil, err
 	}
 
-	var statefulsetsWithoutReplicas []string
+	var statefulSetsWithoutReplicas []string
 
-	for _, statefulset := range statefulsetsList.Items {
-		if statefulset.Labels["kor/used"] == "true" {
-			continue
-		}
-
-		if *statefulset.Spec.Replicas == 0 {
-			statefulsetsWithoutReplicas = append(statefulsetsWithoutReplicas, statefulset.Name)
+	for _, statefulSet := range statefulSetsList.Items {
+		if *statefulSet.Spec.Replicas == 0 {
+			statefulSetsWithoutReplicas = append(statefulSetsWithoutReplicas, statefulSet.Name)
 		}
 	}
 
-	return statefulsetsWithoutReplicas, nil
-}
-
-func ProcessNamespaceStatefulsets(clientset *kubernetes.Clientset, namespace string) ([]string, error) {
-	usedServices, err := getStatefulsetsWithoutReplicas(clientset, namespace)
-	if err != nil {
-		return nil, err
-	}
-
-	return usedServices, nil
+	return statefulSetsWithoutReplicas, nil
 }
 
-func GetUnusedStatefulsets(includeExcludeLists IncludeExcludeLists, clientset *kubernetes.Clientset) {
+func GetUnusedStatefulSets(includeExcludeLists IncludeExcludeLists, clientset kubernetes.Interface) {
 	namespaces := SetNamespaceList(includeExcludeLists, clientset)
 
 	for _, namespace := range namespaces {
-		diff, err := ProcessNamespaceStatefulsets(clientset, namespace)
+		diff, err := ProcessNamespaceStatefulSets(clientset, namespace)
 		if err != nil {
 			fmt.Fprintf(os.Stderr, "Failed to process namespace %s: %v\n", namespace, err)
 			continue
 		}
-		output := FormatOutput(namespace, diff, "Statefulsets")
+		output := FormatOutput(namespace, diff, "StatefulSets")
 		fmt.Println(output)
 		fmt.Println()
 	}
 }
 
-func GetUnusedStatefulsetsStructured(includeExcludeLists IncludeExcludeLists, clientset *kubernetes.Clientset, outputFormat string) (string, error) {
+func GetUnusedStatefulSetsStructured(includeExcludeLists IncludeExcludeLists, clientset kubernetes.Interface, outputFormat string) (string, error) {
 	namespaces := SetNamespaceList(includeExcludeLists, clientset)
 	response := make(map[string]map[string][]string)
 
 	for _, namespace := range namespaces {
-		diff, err := ProcessNamespaceStatefulsets(clientset, namespace)
+		diff, err := ProcessNamespaceStatefulSets(clientset, namespace)
 		if err != nil {
 			fmt.Fprintf(os.Stderr, "Failed to process namespace %s: %v\n", namespace, err)
 			continue


Test patch:
diff --git a/pkg/kor/configmaps_test.go b/pkg/kor/configmaps_test.go
new file mode 100644
index 0000000..3141c42
--- /dev/null
+++ b/pkg/kor/configmaps_test.go
@@ -0,0 +1,203 @@
+package kor
+
+import (
+	"context"
+	"encoding/json"
+	"reflect"
+	"testing"
+
+	appsv1 "k8s.io/api/apps/v1"
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/client-go/kubernetes/fake"
+	"k8s.io/client-go/kubernetes/scheme"
+)
+
+func createTestConfigmaps(t *testing.T) *fake.Clientset {
+	clientset := fake.NewSimpleClientset()
+
+	_, err := clientset.CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{
+		ObjectMeta: metav1.ObjectMeta{Name: testNamespace},
+	}, metav1.CreateOptions{})
+
+	if err != nil {
+		t.Fatalf("Error creating namespace %s: %v", testNamespace, err)
+	}
+
+	configmap1 := CreateTestConfigmap(testNamespace, "configmap-1")
+	configmap2 := CreateTestConfigmap(testNamespace, "configmap-2")
+	configmap3 := CreateTestConfigmap(testNamespace, "configmap-3")
+
+	pod1 := CreateTestPod(testNamespace, "pod-1", "", []corev1.Volume{
+		{Name: "vol-1", VolumeSource: corev1.VolumeSource{ConfigMap: &corev1.ConfigMapVolumeSource{LocalObjectReference: corev1.LocalObjectReference{Name: configmap1.ObjectMeta.Name}}}},
+	})
+
+	pod2 := CreateTestPod(testNamespace, "pod-2", "", nil)
+	pod2.Spec.Containers = []corev1.Container{
+		{
+			Env: []corev1.EnvVar{
+				{Name: "ENV_VAR_1", ValueFrom: &corev1.EnvVarSource{ConfigMapKeyRef: &corev1.ConfigMapKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: configmap1.ObjectMeta.Name}}}},
+			},
+		},
+	}
+
+	pod3 := CreateTestPod(testNamespace, "pod-3", "", nil)
+	pod3.Spec.Containers = []corev1.Container{
+		{
+			EnvFrom: []corev1.EnvFromSource{
+				{ConfigMapRef: &corev1.ConfigMapEnvSource{LocalObjectReference: corev1.LocalObjectReference{Name: configmap2.ObjectMeta.Name}}},
+			},
+		},
+	}
+
+	pod4 := CreateTestPod(testNamespace, "pod-4", "", nil)
+	pod4.Spec.InitContainers = []corev1.Container{
+		{
+			Env: []corev1.EnvVar{
+				{Name: "INIT_ENV_VAR_1", ValueFrom: &corev1.EnvVarSource{ConfigMapKeyRef: &corev1.ConfigMapKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: configmap2.ObjectMeta.Name}}}},
+			},
+		},
+	}
+
+	_, err = clientset.CoreV1().ConfigMaps(testNamespace).Create(context.TODO(), configmap1, metav1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake configmap: %v", err)
+	}
+
+	_, err = clientset.CoreV1().ConfigMaps(testNamespace).Create(context.TODO(), configmap2, metav1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake configmap: %v", err)
+	}
+
+	_, err = clientset.CoreV1().ConfigMaps(testNamespace).Create(context.TODO(), configmap3, metav1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake configmap: %v", err)
+	}
+
+	_, err = clientset.CoreV1().Pods(testNamespace).Create(context.TODO(), pod1, metav1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake pod: %v", err)
+	}
+
+	_, err = clientset.CoreV1().Pods(testNamespace).Create(context.TODO(), pod2, metav1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake pod: %v", err)
+	}
+
+	_, err = clientset.CoreV1().Pods(testNamespace).Create(context.TODO(), pod3, metav1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake pod: %v", err)
+	}
+
+	_, err = clientset.CoreV1().Pods(testNamespace).Create(context.TODO(), pod4, metav1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake pod: %v", err)
+	}
+
+	return clientset
+}
+
+func TestRetrieveConfigMapNames(t *testing.T) {
+	clientset := createTestConfigmaps(t)
+
+	configMapNames, err := retrieveConfigMapNames(clientset, testNamespace)
+
+	if err != nil {
+		t.Fatalf("Error retrieving configmap names: %v", err)
+	}
+
+	expectedConfigMapNames := []string{"configmap-1", "configmap-2", "configmap-3"}
+	if !equalSlices(configMapNames, expectedConfigMapNames) {
+		t.Errorf("Expected configmap names %v, got %v", expectedConfigMapNames, configMapNames)
+	}
+}
+
+func TestProcessNamespaceCM(t *testing.T) {
+	clientset := createTestConfigmaps(t)
+
+	diff, err := processNamespaceCM(clientset, testNamespace)
+	if err != nil {
+		t.Fatalf("Error processing namespace CM: %v", err)
+	}
+
+	unusedConfigmaps := []string{"configmap-3"}
+	if !equalSlices(diff, unusedConfigmaps) {
+		t.Errorf("Expected diff %v, got %v", unusedConfigmaps, diff)
+	}
+}
+
+func TestRetrieveUsedCM(t *testing.T) {
+	clientset := createTestConfigmaps(t)
+
+	volumesCM, volumesProjectedCM, envCM, envFromCM, envFromContainerCM, envFromInitContainerCM, err := retrieveUsedCM(clientset, testNamespace)
+
+	if err != nil {
+		t.Fatalf("Error retrieving used ConfigMaps: %v", err)
+	}
+
+	expectedVolumesCM := []string{"configmap-1", "kube-root-ca.crt"}
+	if !equalSlices(volumesCM, expectedVolumesCM) {
+		t.Errorf("Expected volume configmaps %v, got %v", expectedVolumesCM, volumesCM)
+	}
+
+	var expectedVolumesProjectedCM []string
+	if !equalSlices(volumesProjectedCM, expectedVolumesProjectedCM) {
+		t.Errorf("Expected volume configmaps %v, got %v", expectedVolumesProjectedCM, volumesProjectedCM)
+	}
+
+	expectedEnvCM := []string{"configmap-1"}
+	if !equalSlices(envCM, expectedEnvCM) {
+		t.Errorf("Expected env configmaps %v, got %v", expectedEnvCM, envCM)
+	}
+
+	expectedEnvFromCM := []string{"configmap-2"}
+	if !equalSlices(envFromCM, expectedEnvFromCM) {
+		t.Errorf("Expected envFrom configmaps %v, got %v", expectedEnvFromCM, envFromCM)
+	}
+
+	expectedEnvFromContainerCM := []string{"configmap-2"}
+	if !equalSlices(envFromContainerCM, expectedEnvFromContainerCM) {
+		t.Errorf("Expected envFrom configmaps %v, got %v", expectedEnvFromContainerCM, envFromContainerCM)
+	}
+
+	expectedEnvFromInitContainerCM := []string{"configmap-2"}
+	if !equalSlices(envFromInitContainerCM, expectedEnvFromInitContainerCM) {
+		t.Errorf("Expected initContainer env configmaps %v, got %v", expectedEnvFromInitContainerCM, envFromInitContainerCM)
+	}
+
+}
+
+func TestGetUnusedConfigmapsStructured(t *testing.T) {
+	clientset := createTestConfigmaps(t)
+
+	includeExcludeLists := IncludeExcludeLists{
+		IncludeListStr: "",
+		ExcludeListStr: "",
+	}
+
+	output, err := GetUnusedConfigmapsStructured(includeExcludeLists, clientset, "json")
+	if err != nil {
+		t.Fatalf("Error calling GetUnusedConfigmapsStructured: %v", err)
+	}
+
+	expectedOutput := map[string]map[string][]string{
+		testNamespace: {
+			"ConfigMap": {"configmap-3"},
+		},
+	}
+
+	var actualOutput map[string]map[string][]string
+	if err := json.Unmarshal([]byte(output), &actualOutput); err != nil {
+		t.Fatalf("Error unmarshaling actual output: %v", err)
+	}
+
+	if !reflect.DeepEqual(expectedOutput, actualOutput) {
+		t.Errorf("Expected output does not match actual output")
+	}
+}
+
+func init() {
+	scheme.Scheme = runtime.NewScheme()
+	_ = appsv1.AddToScheme(scheme.Scheme)
+}
diff --git a/pkg/kor/create_test_resources.go b/pkg/kor/create_test_resources.go
new file mode 100644
index 0000000..2f2e5ad
--- /dev/null
+++ b/pkg/kor/create_test_resources.go
@@ -0,0 +1,250 @@
+package kor
+
+import (
+	appsv1 "k8s.io/api/apps/v1"
+	autoscalingv2 "k8s.io/api/autoscaling/v2"
+	corev1 "k8s.io/api/core/v1"
+	networkingv1 "k8s.io/api/networking/v1"
+	policyv1 "k8s.io/api/policy/v1"
+	rbacv1 "k8s.io/api/rbac/v1"
+	"k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+var testNamespace = "test-namespace"
+
+func CreateTestDeployment(namespace, name string, replicas int32, labels map[string]string) *appsv1.Deployment {
+	return &appsv1.Deployment{
+		ObjectMeta: v1.ObjectMeta{
+			Namespace: namespace,
+			Name:      name,
+			Labels:    labels,
+		},
+		Spec: appsv1.DeploymentSpec{
+			Replicas: &replicas,
+		},
+	}
+}
+
+func CreateTestStatefulSet(namespace, name string, replicas int32, labels map[string]string) *appsv1.StatefulSet {
+	return &appsv1.StatefulSet{
+		ObjectMeta: v1.ObjectMeta{
+			Namespace: namespace,
+			Name:      name,
+			Labels:    labels,
+		},
+		Spec: appsv1.StatefulSetSpec{
+			Replicas: &replicas,
+		},
+	}
+}
+
+func CreateTestService(namespace, name string) *corev1.Service {
+	return &corev1.Service{
+		ObjectMeta: v1.ObjectMeta{
+			Namespace: namespace,
+			Name:      name,
+		},
+	}
+}
+
+func CreateTestPod(namespace, name, serviceAccountName string, volumes []corev1.Volume) *corev1.Pod {
+	return &corev1.Pod{
+		ObjectMeta: v1.ObjectMeta{
+			Namespace: namespace,
+			Name:      name,
+		},
+		Spec: corev1.PodSpec{
+			Volumes:            volumes,
+			InitContainers:     nil,
+			Containers:         nil,
+			ServiceAccountName: serviceAccountName,
+		},
+	}
+}
+
+func CreatePersistentVolumeClaimVolumeSource(name string) *corev1.PersistentVolumeClaimVolumeSource {
+	return &corev1.PersistentVolumeClaimVolumeSource{
+		ClaimName: name,
+	}
+}
+
+func CreateTestVolume(name, pvcName string) *corev1.Volume {
+	pvc := CreatePersistentVolumeClaimVolumeSource(pvcName)
+	return &corev1.Volume{
+		Name: name,
+		VolumeSource: corev1.VolumeSource{
+			PersistentVolumeClaim: pvc,
+		},
+	}
+
+}
+
+func CreateTestServiceAccount(namespace, name string) *corev1.ServiceAccount {
+	return &corev1.ServiceAccount{
+		ObjectMeta: v1.ObjectMeta{
+			Namespace: namespace,
+			Name:      name,
+		},
+	}
+}
+
+func CreateTestRbacSubject(namespace, serviceAccountName string) *rbacv1.Subject {
+	return &rbacv1.Subject{
+		Kind:      "ServiceAccount",
+		Name:      serviceAccountName,
+		Namespace: namespace,
+	}
+}
+
+func CreateTestRoleRef(roleName string) *rbacv1.RoleRef {
+	return &rbacv1.RoleRef{
+		Kind: "Role",
+		Name: roleName,
+	}
+}
+
+func CreateTestRoleBinding(namespace, name, serviceAccountName string, roleRefName *rbacv1.RoleRef) *rbacv1.RoleBinding {
+	rbacSubject := CreateTestRbacSubject(namespace, serviceAccountName)
+	return &rbacv1.RoleBinding{
+		ObjectMeta: v1.ObjectMeta{
+			Namespace: namespace,
+			Name:      name,
+		},
+		Subjects: []rbacv1.Subject{
+			*rbacSubject,
+		},
+		RoleRef: *roleRefName,
+	}
+}
+
+func CreateTestClusterRoleBinding(namespace, name, serviceAccountName string) *rbacv1.ClusterRoleBinding {
+	rbacSubject := CreateTestRbacSubject(namespace, serviceAccountName)
+	return &rbacv1.ClusterRoleBinding{
+		ObjectMeta: v1.ObjectMeta{
+			Name: name,
+		},
+		Subjects: []rbacv1.Subject{
+			*rbacSubject,
+		},
+	}
+}
+
+func createPolicyRule() *rbacv1.PolicyRule {
+	return &rbacv1.PolicyRule{
+		Verbs:     []string{"get"},
+		Resources: []string{"pods"},
+	}
+}
+
+func CreateTestRole(namespace, name string) *rbacv1.Role {
+	policyRule := createPolicyRule()
+	return &rbacv1.Role{
+		ObjectMeta: v1.ObjectMeta{
+			Name:      name,
+			Namespace: namespace,
+		},
+		Rules: []rbacv1.PolicyRule{*policyRule},
+	}
+}
+
+func CreateTestEndpoint(namespace, name string, endpointSubsetCount int) *corev1.Endpoints {
+	return &corev1.Endpoints{
+		ObjectMeta: v1.ObjectMeta{
+			Namespace: namespace,
+			Name:      name,
+		},
+		Subsets: make([]corev1.EndpointSubset, endpointSubsetCount),
+	}
+}
+func CreateTestHpa(namespace, name, deploymentName string, minReplicas, maxReplicas int32) *autoscalingv2.HorizontalPodAutoscaler {
+	return &autoscalingv2.HorizontalPodAutoscaler{
+		ObjectMeta: v1.ObjectMeta{
+			Namespace: namespace,
+			Name:      name,
+		},
+		Spec: autoscalingv2.HorizontalPodAutoscalerSpec{
+			MinReplicas: &minReplicas,
+			MaxReplicas: maxReplicas,
+			ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{
+				Kind: "Deployment",
+				Name: deploymentName,
+			},
+		},
+	}
+}
+
+func CreateTestIngress(namespace, name, ServiceName, secretName string) *networkingv1.Ingress {
+	ingressRule := networkingv1.IngressRule{
+		Host: "test.com",
+		IngressRuleValue: networkingv1.IngressRuleValue{
+			HTTP: &networkingv1.HTTPIngressRuleValue{
+				Paths: []networkingv1.HTTPIngressPath{
+					{
+						Path: "/path",
+						Backend: networkingv1.IngressBackend{
+							Service: &networkingv1.IngressServiceBackend{
+								Name: ServiceName,
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+	ingressTls := networkingv1.IngressTLS{
+		SecretName: secretName,
+	}
+
+	return &networkingv1.Ingress{
+		ObjectMeta: v1.ObjectMeta{
+			Namespace: namespace,
+			Name:      name,
+		},
+		Spec: networkingv1.IngressSpec{
+			Rules: []networkingv1.IngressRule{ingressRule},
+			TLS:   []networkingv1.IngressTLS{ingressTls},
+		},
+	}
+}
+
+func CreateTestPvc(namespace, name string) *corev1.PersistentVolumeClaim {
+	return &corev1.PersistentVolumeClaim{
+		ObjectMeta: v1.ObjectMeta{
+			Namespace: namespace,
+			Name:      name,
+		},
+	}
+}
+
+func CreateTestPdb(namespace, name string, matchLabels map[string]string) *policyv1.PodDisruptionBudget {
+	return &policyv1.PodDisruptionBudget{
+		ObjectMeta: v1.ObjectMeta{
+			Namespace: namespace,
+			Name:      name,
+		},
+		Spec: policyv1.PodDisruptionBudgetSpec{
+			MinAvailable: nil,
+			Selector: &v1.LabelSelector{
+				MatchLabels: matchLabels,
+			},
+		},
+	}
+}
+
+func CreateTestSecret(namespace, name string) *corev1.Secret {
+	return &corev1.Secret{
+		ObjectMeta: v1.ObjectMeta{
+			Namespace: namespace,
+			Name:      name,
+		},
+	}
+}
+
+func CreateTestConfigmap(namespace, name string) *corev1.ConfigMap {
+	return &corev1.ConfigMap{
+		ObjectMeta: v1.ObjectMeta{
+			Namespace: namespace,
+			Name:      name,
+		},
+	}
+}
diff --git a/pkg/kor/deployments_test.go b/pkg/kor/deployments_test.go
new file mode 100644
index 0000000..bed7ec9
--- /dev/null
+++ b/pkg/kor/deployments_test.go
@@ -0,0 +1,94 @@
+package kor
+
+import (
+	"context"
+	"encoding/json"
+	"reflect"
+	"testing"
+
+	appsv1 "k8s.io/api/apps/v1"
+	corev1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/client-go/kubernetes/fake"
+	"k8s.io/client-go/kubernetes/scheme"
+)
+
+func createTestDeployments(t *testing.T) *fake.Clientset {
+	clientset := fake.NewSimpleClientset()
+
+	_, err := clientset.CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{
+		ObjectMeta: v1.ObjectMeta{Name: testNamespace},
+	}, v1.CreateOptions{})
+
+	if err != nil {
+		t.Fatalf("Error creating namespace %s: %v", testNamespace, err)
+	}
+
+	appLabels := map[string]string{}
+
+	deployment1 := CreateTestDeployment(testNamespace, "test-deployment1", 0, appLabels)
+	deployment2 := CreateTestDeployment(testNamespace, "test-deployment2", 1, appLabels)
+	_, err = clientset.AppsV1().Deployments(testNamespace).Create(context.TODO(), deployment1, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake deployment: %v", err)
+	}
+
+	_, err = clientset.AppsV1().Deployments(testNamespace).Create(context.TODO(), deployment2, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake deployment: %v", err)
+	}
+
+	return clientset
+}
+
+func TestProcessNamespaceDeployments(t *testing.T) {
+	clientset := createTestDeployments(t)
+
+	deploymentsWithoutReplicas, err := ProcessNamespaceDeployments(clientset, testNamespace)
+	if err != nil {
+		t.Errorf("Expected no error, got %v", err)
+	}
+
+	if len(deploymentsWithoutReplicas) != 1 {
+		t.Errorf("Expected 1 deployment without replicas, got %d", len(deploymentsWithoutReplicas))
+	}
+
+	if deploymentsWithoutReplicas[0] != "test-deployment1" {
+		t.Errorf("Expected 'test-deployment1', got %s", deploymentsWithoutReplicas[0])
+	}
+}
+
+func TestGetUnusedDeploymentsStructured(t *testing.T) {
+	clientset := createTestDeployments(t)
+
+	includeExcludeLists := IncludeExcludeLists{
+		IncludeListStr: "",
+		ExcludeListStr: "",
+	}
+
+	output, err := GetUnusedDeploymentsStructured(includeExcludeLists, clientset, "json")
+	if err != nil {
+		t.Fatalf("Error calling GetUnusedDeploymentsStructured: %v", err)
+	}
+
+	expectedOutput := map[string]map[string][]string{
+		testNamespace: {
+			"Deployments": {"test-deployment1"},
+		},
+	}
+
+	var actualOutput map[string]map[string][]string
+	if err := json.Unmarshal([]byte(output), &actualOutput); err != nil {
+		t.Fatalf("Error unmarshaling actual output: %v", err)
+	}
+
+	if !reflect.DeepEqual(expectedOutput, actualOutput) {
+		t.Errorf("Expected output does not match actual output")
+	}
+}
+
+func init() {
+	scheme.Scheme = runtime.NewScheme()
+	_ = appsv1.AddToScheme(scheme.Scheme)
+}
diff --git a/pkg/kor/hpas_test.go b/pkg/kor/hpas_test.go
new file mode 100644
index 0000000..ab8a8bc
--- /dev/null
+++ b/pkg/kor/hpas_test.go
@@ -0,0 +1,101 @@
+package kor
+
+import (
+	"context"
+	"encoding/json"
+	"reflect"
+	"testing"
+
+	appsv1 "k8s.io/api/apps/v1"
+	corev1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/client-go/kubernetes/fake"
+	"k8s.io/client-go/kubernetes/scheme"
+)
+
+func createTestHpas(t *testing.T) *fake.Clientset {
+	clientset := fake.NewSimpleClientset()
+
+	_, err := clientset.CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{
+		ObjectMeta: v1.ObjectMeta{Name: testNamespace},
+	}, v1.CreateOptions{})
+
+	if err != nil {
+		t.Fatalf("Error creating namespace %s: %v", testNamespace, err)
+	}
+
+	deploymentName := "test-deployment"
+	appLabels := map[string]string{}
+
+	deployment1 := CreateTestDeployment(testNamespace, deploymentName, 1, appLabels)
+	hpa1 := CreateTestHpa(testNamespace, "test-hpa1", deploymentName, 1, 1)
+
+	hpa2 := CreateTestHpa(testNamespace, "test-hpa2", "non-existing-deployment", 1, 1)
+	_, err = clientset.AppsV1().Deployments(testNamespace).Create(context.TODO(), deployment1, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake deployment: %v", err)
+	}
+
+	_, err = clientset.AutoscalingV2().HorizontalPodAutoscalers(testNamespace).Create(context.TODO(), hpa1, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake Hpa: %v", err)
+	}
+
+	_, err = clientset.AutoscalingV2().HorizontalPodAutoscalers(testNamespace).Create(context.TODO(), hpa2, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake Hpa: %v", err)
+	}
+
+	return clientset
+}
+
+func TestExtractUnusedHpas(t *testing.T) {
+	clientset := createTestHpas(t)
+
+	unusedHpas, err := extractUnusedHpas(clientset, testNamespace)
+	if err != nil {
+		t.Errorf("Expected no error, got %v", err)
+	}
+
+	if len(unusedHpas) != 1 {
+		t.Errorf("Expected 1 unused HPA, got %d", len(unusedHpas))
+	}
+
+	if unusedHpas[0] != "test-hpa2" {
+		t.Errorf("Expected 'test-hpa2', got %s", unusedHpas[0])
+	}
+}
+
+func TestGetUnusedHpasStructured(t *testing.T) {
+	clientset := createTestHpas(t)
+
+	includeExcludeLists := IncludeExcludeLists{
+		IncludeListStr: "",
+		ExcludeListStr: "",
+	}
+
+	output, err := GetUnusedHpasStructured(includeExcludeLists, clientset, "json")
+	if err != nil {
+		t.Fatalf("Error calling GetUnusedHpasStructured: %v", err)
+	}
+
+	expectedOutput := map[string]map[string][]string{
+		testNamespace: {
+			"Hpa": {"test-hpa2"},
+		},
+	}
+
+	var actualOutput map[string]map[string][]string
+	if err := json.Unmarshal([]byte(output), &actualOutput); err != nil {
+		t.Fatalf("Error unmarshaling actual output: %v", err)
+	}
+
+	if !reflect.DeepEqual(expectedOutput, actualOutput) {
+		t.Errorf("Expected output does not match actual output")
+	}
+}
+func init() {
+	scheme.Scheme = runtime.NewScheme()
+	_ = appsv1.AddToScheme(scheme.Scheme)
+}
diff --git a/pkg/kor/ingresses_test.go b/pkg/kor/ingresses_test.go
new file mode 100644
index 0000000..7812098
--- /dev/null
+++ b/pkg/kor/ingresses_test.go
@@ -0,0 +1,106 @@
+package kor
+
+import (
+	"context"
+	"encoding/json"
+	"reflect"
+	"testing"
+
+	appsv1 "k8s.io/api/apps/v1"
+	corev1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/client-go/kubernetes/fake"
+	"k8s.io/client-go/kubernetes/scheme"
+)
+
+func createTestIngresses(t *testing.T) *fake.Clientset {
+	clientset := fake.NewSimpleClientset()
+
+	_, err := clientset.CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{
+		ObjectMeta: v1.ObjectMeta{Name: testNamespace},
+	}, v1.CreateOptions{})
+
+	if err != nil {
+		t.Fatalf("Error creating namespace %s: %v", testNamespace, err)
+	}
+
+	service1 := CreateTestService(testNamespace, "my-service-1")
+	ingress1 := CreateTestIngress(testNamespace, "test-ingress-1", "my-service-1", "test-secret")
+	ingress2 := CreateTestIngress(testNamespace, "test-ingress-2", "my-service-2", "test-secret")
+
+	_, err = clientset.CoreV1().Services(testNamespace).Create(context.TODO(), service1, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "Service", err)
+	}
+	_, err = clientset.NetworkingV1().Ingresses(testNamespace).Create(context.TODO(), ingress1, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "Ingress", err)
+	}
+	_, err = clientset.NetworkingV1().Ingresses(testNamespace).Create(context.TODO(), ingress2, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "Ingress", err)
+	}
+
+	return clientset
+}
+
+func TestRetrieveUsedIngress(t *testing.T) {
+	clientset := createTestIngresses(t)
+
+	usedIngresses, err := retrieveUsedIngress(clientset, testNamespace)
+	if err != nil {
+		t.Errorf("Expected no error, got %v", err)
+	}
+
+	if len(usedIngresses) != 1 {
+		t.Errorf("Expected 1 used Ingress objects, got %d", len(usedIngresses))
+	}
+
+	if !contains(usedIngresses, "test-ingress-1") {
+		t.Error("Expected specific Ingress objects in the list")
+	}
+}
+
+func contains(slice []string, item string) bool {
+	for _, s := range slice {
+		if s == item {
+			return true
+		}
+	}
+	return false
+}
+
+func TestGetUnusedIngressesStructured(t *testing.T) {
+	clientset := createTestIngresses(t)
+
+	includeExcludeLists := IncludeExcludeLists{
+		IncludeListStr: "",
+		ExcludeListStr: "",
+	}
+
+	output, err := GetUnusedIngressesStructured(includeExcludeLists, clientset, "json")
+	if err != nil {
+		t.Fatalf("Error calling GetUnusedIngressesStructured: %v", err)
+	}
+
+	expectedOutput := map[string]map[string][]string{
+		testNamespace: {
+			"Ingresses": {"test-ingress-2"},
+		},
+	}
+
+	var actualOutput map[string]map[string][]string
+	if err := json.Unmarshal([]byte(output), &actualOutput); err != nil {
+		t.Fatalf("Error unmarshaling actual output: %v", err)
+	}
+
+	if !reflect.DeepEqual(expectedOutput, actualOutput) {
+		t.Errorf("Expected output does not match actual output")
+	}
+}
+
+func init() {
+	scheme.Scheme = runtime.NewScheme()
+	_ = appsv1.AddToScheme(scheme.Scheme)
+}
diff --git a/pkg/kor/pdbs_test.go b/pkg/kor/pdbs_test.go
new file mode 100644
index 0000000..cad29c2
--- /dev/null
+++ b/pkg/kor/pdbs_test.go
@@ -0,0 +1,107 @@
+package kor
+
+import (
+	"context"
+	"encoding/json"
+	"reflect"
+	"testing"
+
+	corev1 "k8s.io/api/core/v1"
+	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/client-go/kubernetes/fake"
+)
+
+func createTestPdbs(t *testing.T) *fake.Clientset {
+	clientset := fake.NewSimpleClientset()
+
+	_, err := clientset.CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{
+		ObjectMeta: v1.ObjectMeta{Name: testNamespace},
+	}, v1.CreateOptions{})
+
+	if err != nil {
+		t.Fatalf("Error creating namespace %s: %v", testNamespace, err)
+	}
+
+	appLabels1 := map[string]string{
+		"app": "my-app",
+	}
+	appLabels2 := map[string]string{}
+
+	pdb1 := CreateTestPdb(testNamespace, "test-pdb1", appLabels1)
+	pdb2 := CreateTestPdb(testNamespace, "test-pdb2", appLabels1)
+	pdb3 := CreateTestPdb(testNamespace, "test-pdb3", appLabels2)
+	_, err = clientset.PolicyV1().PodDisruptionBudgets(testNamespace).Create(context.TODO(), pdb1, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "Pdb", err)
+	}
+
+	_, err = clientset.PolicyV1().PodDisruptionBudgets(testNamespace).Create(context.TODO(), pdb2, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "Pdb", err)
+	}
+
+	_, err = clientset.PolicyV1().PodDisruptionBudgets(testNamespace).Create(context.TODO(), pdb3, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "Pdb", err)
+	}
+
+	deployment1 := CreateTestDeployment(testNamespace, "test-deployment2", 1, appLabels1)
+	_, err = clientset.AppsV1().Deployments(testNamespace).Create(context.TODO(), deployment1, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake deployment: %v", err)
+	}
+
+	sts1 := CreateTestStatefulSet(testNamespace, "test-sts2", 1, appLabels1)
+	_, err = clientset.AppsV1().StatefulSets(testNamespace).Create(context.TODO(), sts1, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "StatefulSet", err)
+	}
+
+	return clientset
+}
+
+func TestProcessNamespacePdbs(t *testing.T) {
+	clientset := createTestPdbs(t)
+
+	unusedPdbs, err := processNamespacePdbs(clientset, testNamespace)
+	if err != nil {
+		t.Errorf("Expected no error, got %v", err)
+	}
+
+	if len(unusedPdbs) != 1 {
+		t.Errorf("Expected 1 unused pdb, got %d", len(unusedPdbs))
+	}
+
+	if unusedPdbs[0] != "test-pdb3" {
+		t.Errorf("Expected 'test-pdb3', got %s", unusedPdbs[0])
+	}
+}
+
+func TestGetUnusedPdbsStructured(t *testing.T) {
+	clientset := createTestPdbs(t)
+
+	includeExcludeLists := IncludeExcludeLists{
+		IncludeListStr: "",
+		ExcludeListStr: "",
+	}
+
+	output, err := GetUnusedPdbsStructured(includeExcludeLists, clientset, "json")
+	if err != nil {
+		t.Fatalf("Error calling GetUnusedPdbsStructured: %v", err)
+	}
+
+	expectedOutput := map[string]map[string][]string{
+		testNamespace: {
+			"Pdb": {"test-pdb3"},
+		},
+	}
+
+	var actualOutput map[string]map[string][]string
+	if err := json.Unmarshal([]byte(output), &actualOutput); err != nil {
+		t.Fatalf("Error unmarshaling actual output: %v", err)
+	}
+
+	if !reflect.DeepEqual(expectedOutput, actualOutput) {
+		t.Errorf("Expected output does not match actual output")
+	}
+}
diff --git a/pkg/kor/pvc_test.go b/pkg/kor/pvc_test.go
new file mode 100644
index 0000000..a0fd5cb
--- /dev/null
+++ b/pkg/kor/pvc_test.go
@@ -0,0 +1,117 @@
+package kor
+
+import (
+	"context"
+	"encoding/json"
+	"reflect"
+	"testing"
+
+	appsv1 "k8s.io/api/apps/v1"
+	corev1 "k8s.io/api/core/v1"
+	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/client-go/kubernetes/fake"
+	"k8s.io/client-go/kubernetes/scheme"
+)
+
+func createTestPvcs(t *testing.T) *fake.Clientset {
+	clientset := fake.NewSimpleClientset()
+	var volumeList []corev1.Volume
+
+	_, err := clientset.CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{
+		ObjectMeta: v1.ObjectMeta{Name: testNamespace},
+	}, v1.CreateOptions{})
+
+	if err != nil {
+		t.Fatalf("Error creating namespace %s: %v", testNamespace, err)
+	}
+
+	pvc1 := CreateTestPvc(testNamespace, "test-pvc1")
+	pvc2 := CreateTestPvc(testNamespace, "test-pvc2")
+	_, err = clientset.CoreV1().PersistentVolumeClaims(testNamespace).Create(context.TODO(), pvc1, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "Pvc", err)
+	}
+
+	_, err = clientset.CoreV1().PersistentVolumeClaims(testNamespace).Create(context.TODO(), pvc2, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "Pvc", err)
+	}
+
+	testVolume := CreateTestVolume("test-volume", "test-pvc1")
+	volumeList = append(volumeList, *testVolume)
+	testPod := CreateTestPod(testNamespace, "test-pod", "test-sa", volumeList)
+
+	_, err = clientset.CoreV1().Pods(testNamespace).Create(context.TODO(), testPod, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "Pvc", err)
+	}
+
+	return clientset
+}
+
+func TestRetreiveUsedPvcs(t *testing.T) {
+	clientset := createTestPvcs(t)
+	usedPvcs, err := retreiveUsedPvcs(clientset, testNamespace)
+	if err != nil {
+		t.Errorf("Expected no error, got %v", err)
+	}
+
+	if len(usedPvcs) != 1 {
+		t.Errorf("Expected 1 used pvc, got %d", len(usedPvcs))
+	}
+
+	if usedPvcs[0] != "test-pvc1" {
+		t.Errorf("Expected 'test-pvc1', got %s", usedPvcs[0])
+	}
+}
+
+func TestProcessNamespacePvcs(t *testing.T) {
+	clientset := createTestPvcs(t)
+	usedPvcs, err := processNamespacePvcs(clientset, testNamespace)
+	if err != nil {
+		t.Errorf("Expected no error, got %v", err)
+	}
+
+	if len(usedPvcs) != 1 {
+		t.Errorf("Expected 1 unused pvc, got %d", len(usedPvcs))
+	}
+
+	if usedPvcs[0] != "test-pvc2" {
+		t.Errorf("Expected 'test-pvc2', got %s", usedPvcs[0])
+	}
+}
+
+func TestGetUnusedPvcsStructured(t *testing.T) {
+	clientset := createTestPvcs(t)
+
+	includeExcludeLists := IncludeExcludeLists{
+		IncludeListStr: "",
+		ExcludeListStr: "",
+	}
+
+	output, err := GetUnusedPvcsStructured(includeExcludeLists, clientset, "json")
+	if err != nil {
+		t.Fatalf("Error calling GetUnusedPvcsStructured: %v", err)
+	}
+
+	expectedOutput := map[string]map[string][]string{
+		testNamespace: {
+			"Pvc": {"test-pvc2"},
+		},
+	}
+
+	var actualOutput map[string]map[string][]string
+	if err := json.Unmarshal([]byte(output), &actualOutput); err != nil {
+		t.Fatalf("Error unmarshaling actual output: %v", err)
+	}
+
+	if !reflect.DeepEqual(expectedOutput, actualOutput) {
+		t.Errorf("Expected output does not match actual output")
+	}
+}
+
+func init() {
+	scheme.Scheme = runtime.NewScheme()
+	_ = appsv1.AddToScheme(scheme.Scheme)
+}
diff --git a/pkg/kor/roles_test.go b/pkg/kor/roles_test.go
new file mode 100644
index 0000000..e4e61ae
--- /dev/null
+++ b/pkg/kor/roles_test.go
@@ -0,0 +1,127 @@
+package kor
+
+import (
+	"context"
+	"encoding/json"
+	"reflect"
+	"testing"
+
+	appsv1 "k8s.io/api/apps/v1"
+	corev1 "k8s.io/api/core/v1"
+	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/client-go/kubernetes/fake"
+	"k8s.io/client-go/kubernetes/scheme"
+)
+
+func createTestRoles(t *testing.T) *fake.Clientset {
+	clientset := fake.NewSimpleClientset()
+
+	_, err := clientset.CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{
+		ObjectMeta: v1.ObjectMeta{Name: testNamespace},
+	}, v1.CreateOptions{})
+
+	if err != nil {
+		t.Fatalf("Error creating namespace %s: %v", testNamespace, err)
+	}
+
+	role1 := CreateTestRole(testNamespace, "test-role1")
+	role2 := CreateTestRole(testNamespace, "test-role2")
+	_, err = clientset.RbacV1().Roles(testNamespace).Create(context.TODO(), role1, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "Role", err)
+	}
+
+	_, err = clientset.RbacV1().Roles(testNamespace).Create(context.TODO(), role2, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "Role", err)
+	}
+
+	testRoleRef := CreateTestRoleRef("test-role1")
+	testRoleBinding := CreateTestRoleBinding(testNamespace, "test-rb", "test-sa", testRoleRef)
+	_, err = clientset.RbacV1().RoleBindings(testNamespace).Create(context.TODO(), testRoleBinding, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "Role", err)
+	}
+
+	return clientset
+}
+func TestRetrieveUsedRoles(t *testing.T) {
+	clientset := createTestRoles(t)
+
+	usedRoles, err := retrieveUsedRoles(clientset, testNamespace)
+	if err != nil {
+		t.Errorf("Expected no error, got %v", err)
+	}
+
+	if len(usedRoles) != 1 {
+		t.Errorf("Expected 1 used role, got %d", len(usedRoles))
+	}
+
+	if usedRoles[0] != "test-role1" {
+		t.Errorf("Expected 'test-role1', got %s", usedRoles[0])
+	}
+}
+
+func TestRetrieveRoleNames(t *testing.T) {
+	clientset := createTestRoles(t)
+	allRoles, err := retrieveRoleNames(clientset, testNamespace)
+	if err != nil {
+		t.Errorf("Expected no error, got %v", err)
+	}
+
+	if len(allRoles) != 2 {
+		t.Errorf("Expected 2 roles, got %d", len(allRoles))
+	}
+}
+
+func TestProcessNamespaceRoles(t *testing.T) {
+	clientset := createTestRoles(t)
+
+	unusedRoles, err := processNamespaceRoles(clientset, testNamespace)
+	if err != nil {
+		t.Errorf("Expected no error, got %v", err)
+	}
+
+	if len(unusedRoles) != 1 {
+		t.Errorf("Expected 1 unused role, got %d", len(unusedRoles))
+	}
+
+	if unusedRoles[0] != "test-role2" {
+		t.Errorf("Expected 'test-role2', got %s", unusedRoles[0])
+	}
+}
+
+func TestGetUnusedRolesStructured(t *testing.T) {
+	clientset := createTestRoles(t)
+
+	includeExcludeLists := IncludeExcludeLists{
+		IncludeListStr: "",
+		ExcludeListStr: "",
+	}
+
+	output, err := GetUnusedRolesStructured(includeExcludeLists, clientset, "json")
+	if err != nil {
+		t.Fatalf("Error calling GetUnusedRolesStructured: %v", err)
+	}
+
+	expectedOutput := map[string]map[string][]string{
+		testNamespace: {
+			"Roles": {"test-role2"},
+		},
+	}
+
+	var actualOutput map[string]map[string][]string
+	if err := json.Unmarshal([]byte(output), &actualOutput); err != nil {
+		t.Fatalf("Error unmarshaling actual output: %v", err)
+	}
+
+	if !reflect.DeepEqual(expectedOutput, actualOutput) {
+		t.Errorf("Expected output does not match actual output")
+	}
+}
+
+func init() {
+	scheme.Scheme = runtime.NewScheme()
+	_ = appsv1.AddToScheme(scheme.Scheme)
+}
diff --git a/pkg/kor/secrets_test.go b/pkg/kor/secrets_test.go
new file mode 100644
index 0000000..689218e
--- /dev/null
+++ b/pkg/kor/secrets_test.go
@@ -0,0 +1,283 @@
+package kor
+
+import (
+	"context"
+	"encoding/json"
+	"reflect"
+	"testing"
+
+	appsv1 "k8s.io/api/apps/v1"
+	corev1 "k8s.io/api/core/v1"
+	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/client-go/kubernetes/fake"
+	"k8s.io/client-go/kubernetes/scheme"
+)
+
+func createTestSecrets(t *testing.T) *fake.Clientset {
+	clientset := fake.NewSimpleClientset()
+
+	_, err := clientset.CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{
+		ObjectMeta: v1.ObjectMeta{Name: testNamespace},
+	}, v1.CreateOptions{})
+
+	if err != nil {
+		t.Fatalf("Error creating namespace %s: %v", testNamespace, err)
+	}
+
+	secret1 := CreateTestSecret(testNamespace, "test-secret1")
+	secret2 := CreateTestSecret(testNamespace, "test-secret2")
+	secret3 := CreateTestSecret(testNamespace, "test-secret3")
+
+	pod1 := CreateTestPod(testNamespace, "pod-1", "", []corev1.Volume{
+		{Name: "vol-1", VolumeSource: corev1.VolumeSource{Secret: &corev1.SecretVolumeSource{SecretName: "test-secret1"}}},
+	})
+
+	pod2 := CreateTestPod(testNamespace, "pod-2", "", []corev1.Volume{
+		{Name: "vol-2", VolumeSource: corev1.VolumeSource{Secret: &corev1.SecretVolumeSource{SecretName: "test-secret2"}}},
+	})
+
+	pod3 := CreateTestPod(testNamespace, "pod-3", "", nil)
+	pod3.Spec.Containers = []corev1.Container{
+		{
+			Env: []corev1.EnvVar{
+				{Name: "ENV_VAR_1", ValueFrom: &corev1.EnvVarSource{SecretKeyRef: &corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: secret1.ObjectMeta.Name}}}},
+			},
+		},
+	}
+
+	pod4 := CreateTestPod(testNamespace, "pod-4", "", nil)
+	pod4.Spec.Containers = []corev1.Container{
+		{
+			EnvFrom: []corev1.EnvFromSource{
+				{SecretRef: &corev1.SecretEnvSource{LocalObjectReference: corev1.LocalObjectReference{Name: secret1.ObjectMeta.Name}}},
+			},
+		},
+	}
+
+	pod5 := CreateTestPod(testNamespace, "pod-5", "", nil)
+	pod5.Spec.InitContainers = []corev1.Container{
+		{
+			Env: []corev1.EnvVar{
+				{Name: "INIT_ENV_VAR_1", ValueFrom: &corev1.EnvVarSource{SecretKeyRef: &corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: secret1.ObjectMeta.Name}}}},
+			},
+		},
+	}
+
+	pod6 := CreateTestPod(testNamespace, "pod-6", "", nil)
+	pod6.Spec.ImagePullSecrets = []corev1.LocalObjectReference{
+		{Name: secret1.ObjectMeta.Name},
+		{Name: secret2.ObjectMeta.Name},
+	}
+
+	_, err = clientset.CoreV1().Pods(testNamespace).Create(context.TODO(), pod1, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake pod: %v", err)
+	}
+
+	_, err = clientset.CoreV1().Pods(testNamespace).Create(context.TODO(), pod2, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake pod: %v", err)
+	}
+
+	_, err = clientset.CoreV1().Pods(testNamespace).Create(context.TODO(), pod3, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake pod: %v", err)
+	}
+
+	_, err = clientset.CoreV1().Pods(testNamespace).Create(context.TODO(), pod4, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake pod: %v", err)
+	}
+
+	_, err = clientset.CoreV1().Pods(testNamespace).Create(context.TODO(), pod5, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake pod: %v", err)
+	}
+
+	_, err = clientset.CoreV1().Pods(testNamespace).Create(context.TODO(), pod6, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake pod: %v", err)
+	}
+
+	_, err = clientset.CoreV1().Secrets(testNamespace).Create(context.TODO(), secret1, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "Secret", err)
+	}
+
+	_, err = clientset.CoreV1().Secrets(testNamespace).Create(context.TODO(), secret2, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "Secret", err)
+	}
+
+	_, err = clientset.CoreV1().Secrets(testNamespace).Create(context.TODO(), secret3, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "Secret", err)
+	}
+
+	return clientset
+}
+
+func TestRetrieveIngressTLS(t *testing.T) {
+	clientset := fake.NewSimpleClientset()
+
+	ingress1 := CreateTestIngress(testNamespace, "test-ingress-1", "my-service-1", "test-secret1")
+	secret1 := CreateTestSecret(testNamespace, "test-secret1")
+	secret2 := CreateTestSecret(testNamespace, "test-secret2")
+
+	_, err := clientset.NetworkingV1().Ingresses(testNamespace).Create(context.TODO(), ingress1, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "Ingress", err)
+	}
+
+	_, err = clientset.CoreV1().Secrets(testNamespace).Create(context.TODO(), secret1, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "Secret", err)
+	}
+
+	_, err = clientset.CoreV1().Secrets(testNamespace).Create(context.TODO(), secret2, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "Secret", err)
+	}
+
+	tlsSecrets, err := retrieveIngressTLS(clientset, testNamespace)
+	if err != nil {
+		t.Errorf("Expected no error, got %v", err)
+	}
+
+	if len(tlsSecrets) != 1 {
+		t.Errorf("Expected 1 used Secret object, got %d", len(tlsSecrets))
+	}
+
+	if tlsSecrets[0] != "test-secret1" {
+		t.Errorf("Expected 'test-secret1', got %s", tlsSecrets[0])
+	}
+
+}
+
+func TestRetrieveUsedSecret(t *testing.T) {
+	clientset := createTestSecrets(t)
+
+	envSecrets, envSecrets2, volumeSecrets, initContainerEnvSecrets, pullSecrets, _, err := retrieveUsedSecret(clientset, testNamespace)
+	if err != nil {
+		t.Fatalf("Error retrieving used secrets: %v", err)
+	}
+
+	expectedVolumeSecrets := []string{"test-secret1", "test-secret2"}
+	if !equalSlices(volumeSecrets, expectedVolumeSecrets) {
+		t.Errorf("Expected volume secrets %v, got %v", expectedVolumeSecrets, volumeSecrets)
+	}
+
+	expectedEnvSecrets := []string{"test-secret1"}
+	if !equalSlices(envSecrets, expectedEnvSecrets) {
+		t.Errorf("Expected env secrets %v, got %v", expectedEnvSecrets, envSecrets)
+	}
+
+	expectedEnvSecrets2 := []string{"test-secret1"}
+	if !equalSlices(envSecrets2, expectedEnvSecrets2) {
+		t.Errorf("Expected envFrom secrets %v, got %v", expectedEnvSecrets2, envSecrets2)
+	}
+
+	expectedInitContainerEnvSecrets := []string{"test-secret1"}
+	if !equalSlices(initContainerEnvSecrets, expectedInitContainerEnvSecrets) {
+		t.Errorf("Expected initContainer env secrets %v, got %v", expectedInitContainerEnvSecrets, initContainerEnvSecrets)
+	}
+
+	expectedPullSecrets := []string{"test-secret1", "test-secret2"}
+	if !equalSlices(pullSecrets, expectedPullSecrets) {
+		t.Errorf("Expected pull secrets %v, got %v", expectedPullSecrets, pullSecrets)
+	}
+
+}
+
+func TestRetrieveSecretNames(t *testing.T) {
+	clientset := fake.NewSimpleClientset()
+
+	secret1 := CreateTestSecret(testNamespace, "secret-1")
+	secret2 := CreateTestSecret(testNamespace, "secret-2")
+
+	_, err := clientset.CoreV1().Secrets(testNamespace).Create(context.TODO(), secret1, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake secret: %v", err)
+	}
+
+	_, err = clientset.CoreV1().Secrets(testNamespace).Create(context.TODO(), secret2, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake secret: %v", err)
+	}
+
+	secretNames, err := retrieveSecretNames(clientset, testNamespace)
+
+	if err != nil {
+		t.Fatalf("Error retrieving secret names: %v", err)
+	}
+
+	expectedSecretNames := []string{"secret-1", "secret-2"}
+	if !equalSlices(secretNames, expectedSecretNames) {
+		t.Errorf("Expected secret names %v, got %v", expectedSecretNames, secretNames)
+	}
+}
+
+func TestProcessNamespaceSecret(t *testing.T) {
+	clientset := createTestSecrets(t)
+
+	unusedSecrets, err := processNamespaceSecret(clientset, testNamespace)
+	if err != nil {
+		t.Fatalf("Error retrieving unused secrets: %v", err)
+	}
+
+	if len(unusedSecrets) != 1 {
+		t.Errorf("Expected 1 used Secret objects, got %d", len(unusedSecrets))
+	}
+
+	if !contains(unusedSecrets, "test-secret3") {
+		t.Error("Expected specific Secret  in the list")
+	}
+
+}
+
+func TestGetUnusedSecretsStructured(t *testing.T) {
+	clientset := createTestSecrets(t)
+
+	includeExcludeLists := IncludeExcludeLists{
+		IncludeListStr: "",
+		ExcludeListStr: "",
+	}
+
+	output, err := GetUnusedSecretsStructured(includeExcludeLists, clientset, "json")
+	if err != nil {
+		t.Fatalf("Error calling GetUnusedSecretsStructured: %v", err)
+	}
+
+	expectedOutput := map[string]map[string][]string{
+		testNamespace: {
+			"Secrets": {"test-secret3"},
+		},
+	}
+
+	var actualOutput map[string]map[string][]string
+	if err := json.Unmarshal([]byte(output), &actualOutput); err != nil {
+		t.Fatalf("Error unmarshaling actual output: %v", err)
+	}
+
+	if !reflect.DeepEqual(expectedOutput, actualOutput) {
+		t.Errorf("Expected output does not match actual output")
+	}
+}
+
+func equalSlices(a, b []string) bool {
+	if len(a) != len(b) {
+		return false
+	}
+	for i, v := range a {
+		if v != b[i] {
+			return false
+		}
+	}
+	return true
+}
+
+func init() {
+	scheme.Scheme = runtime.NewScheme()
+	_ = appsv1.AddToScheme(scheme.Scheme)
+}
diff --git a/pkg/kor/serviceaccounts_test.go b/pkg/kor/serviceaccounts_test.go
new file mode 100644
index 0000000..a7e0088
--- /dev/null
+++ b/pkg/kor/serviceaccounts_test.go
@@ -0,0 +1,202 @@
+package kor
+
+import (
+	"context"
+	"encoding/json"
+	"reflect"
+	"testing"
+
+	appsv1 "k8s.io/api/apps/v1"
+	corev1 "k8s.io/api/core/v1"
+	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/client-go/kubernetes/fake"
+	"k8s.io/client-go/kubernetes/scheme"
+)
+
+func createTestServiceAccounts(t *testing.T) *fake.Clientset {
+
+	clientset := fake.NewSimpleClientset()
+
+	_, err := clientset.CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{
+		ObjectMeta: v1.ObjectMeta{Name: testNamespace},
+	}, v1.CreateOptions{})
+
+	if err != nil {
+		t.Fatalf("Error creating namespace %s: %v", testNamespace, err)
+	}
+
+	sa1 := CreateTestServiceAccount(testNamespace, "test-sa1")
+	sa2 := CreateTestServiceAccount(testNamespace, "test-sa2")
+	_, err = clientset.CoreV1().ServiceAccounts(testNamespace).Create(context.TODO(), sa1, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "ServiceAccount", err)
+	}
+
+	_, err = clientset.CoreV1().ServiceAccounts(testNamespace).Create(context.TODO(), sa2, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "ServiceAccount", err)
+	}
+
+	return clientset
+}
+func TestGetServiceAccountsFromClusterRoleBindings(t *testing.T) {
+	clientset := createTestServiceAccounts(t)
+
+	clusterRoleBinding1 := CreateTestClusterRoleBinding(testNamespace, "test-crb1", "test-sa1")
+	_, err := clientset.RbacV1().ClusterRoleBindings().Create(context.TODO(), clusterRoleBinding1, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "clusterRoleBinding", err)
+	}
+
+	serviceAccountWithCRB, err := getServiceAccountsFromClusterRoleBindings(clientset, testNamespace)
+	if err != nil {
+		t.Errorf("Expected no error, got %v", err)
+	}
+
+	if len(serviceAccountWithCRB) != 1 {
+		t.Errorf("Expected 1 serviceAccount without CRB, got %d", len(serviceAccountWithCRB))
+	}
+
+	if serviceAccountWithCRB[0] != "test-sa1" {
+		t.Errorf("Expected 'test-sa1', got %s", serviceAccountWithCRB[0])
+	}
+
+}
+
+func TestGetServiceAccountsFromRoleBindings(t *testing.T) {
+	clientset := createTestServiceAccounts(t)
+
+	testRoleRef := CreateTestRoleRef("test-role")
+	roleBinding1 := CreateTestRoleBinding(testNamespace, "test-crb1", "test-sa1", testRoleRef)
+	_, err := clientset.RbacV1().RoleBindings(testNamespace).Create(context.TODO(), roleBinding1, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "roleBinding", err)
+	}
+
+	serviceAccountWithRB, err := getServiceAccountsFromRoleBindings(clientset, testNamespace)
+	if err != nil {
+		t.Errorf("Expected no error, got %v", err)
+	}
+
+	if len(serviceAccountWithRB) != 1 {
+		t.Errorf("Expected 1 serviceAccount without CRB, got %d", len(serviceAccountWithRB))
+	}
+
+	if serviceAccountWithRB[0] != "test-sa1" {
+		t.Errorf("Expected 'test-sa1', got %s", serviceAccountWithRB[0])
+	}
+}
+
+func TestRetrieveUsedSA(t *testing.T) {
+	var volumeList []corev1.Volume
+	clientset := createTestServiceAccounts(t)
+
+	testVolume := CreateTestVolume("test-volume1", "test-pvc")
+	volumeList = append(volumeList, *testVolume)
+
+	podWithSA := CreateTestPod(testNamespace, "test-pod1", "test-sa1", volumeList)
+	_, err := clientset.CoreV1().Pods(testNamespace).Create(context.TODO(), podWithSA, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "Pod", err)
+	}
+	serviceAccountUsedByPod, _, _, err := retrieveUsedSA(clientset, testNamespace)
+	if err != nil {
+		t.Errorf("Expected no error, got %v", err)
+	}
+
+	if len(serviceAccountUsedByPod) != 2 {
+		t.Errorf("Expected 2 serviceAccount Used by pod, got %d", len(serviceAccountUsedByPod))
+	}
+
+	if serviceAccountUsedByPod[0] != "test-sa1" || serviceAccountUsedByPod[1] != "default" {
+		t.Errorf("Expected 'test-sa1' and 'default', got %s", serviceAccountUsedByPod[0])
+	}
+
+}
+
+func TestRetrieveServiceAccountNames(t *testing.T) {
+	clientset := createTestServiceAccounts(t)
+	serviceAccountNames, err := retrieveServiceAccountNames(clientset, testNamespace)
+	if err != nil {
+		t.Fatalf("Expected no error, got %v", err)
+	}
+	if len(serviceAccountNames) != 2 {
+		t.Errorf("Expected 2 serviceAccounts , got %d", len(serviceAccountNames))
+	}
+}
+
+func TestProcessNamespaceSA(t *testing.T) {
+	clientset := createTestServiceAccounts(t)
+	var volumeList []corev1.Volume
+
+	testVolume := CreateTestVolume("test-volume1", "test-pvc")
+	volumeList = append(volumeList, *testVolume)
+
+	testRoleRef := CreateTestRoleRef("test-role")
+
+	roleBinding1 := CreateTestRoleBinding(testNamespace, "test-crb1", "test-sa1", testRoleRef)
+	_, err := clientset.RbacV1().RoleBindings(testNamespace).Create(context.TODO(), roleBinding1, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "roleBinding", err)
+	}
+
+	podWithSA := CreateTestPod(testNamespace, "test-pod1", "test-sa1", volumeList)
+	_, err = clientset.CoreV1().Pods(testNamespace).Create(context.TODO(), podWithSA, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "Pod", err)
+	}
+
+	unusedServiceAccounts, err := processNamespaceSA(clientset, testNamespace)
+	if err != nil {
+		t.Fatalf("Expected no error, got %v", err)
+	}
+
+	if len(unusedServiceAccounts) != 1 {
+		t.Errorf("Expected 2 serviceAccount Used by pod, got %d", len(unusedServiceAccounts))
+	}
+
+	if unusedServiceAccounts[0] != "test-sa2" {
+		t.Errorf("Expected 'test-sa2', got %s", unusedServiceAccounts[0])
+	}
+}
+
+func TestGetUnusedServiceAccountsStructured(t *testing.T) {
+	clientset := createTestServiceAccounts(t)
+
+	clusterRoleBinding1 := CreateTestClusterRoleBinding(testNamespace, "test-crb1", "test-sa1")
+	_, err := clientset.RbacV1().ClusterRoleBindings().Create(context.TODO(), clusterRoleBinding1, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "clusterRoleBinding", err)
+	}
+
+	includeExcludeLists := IncludeExcludeLists{
+		IncludeListStr: "",
+		ExcludeListStr: "",
+	}
+
+	output, err := GetUnusedServiceAccountsStructured(includeExcludeLists, clientset, "json")
+	if err != nil {
+		t.Fatalf("Error calling GetUnusedServiceAccountsStructured: %v", err)
+	}
+
+	expectedOutput := map[string]map[string][]string{
+		testNamespace: {
+			"ServiceAccounts": {"test-sa2"},
+		},
+	}
+
+	var actualOutput map[string]map[string][]string
+	if err := json.Unmarshal([]byte(output), &actualOutput); err != nil {
+		t.Fatalf("Error unmarshaling actual output: %v", err)
+	}
+
+	if !reflect.DeepEqual(expectedOutput, actualOutput) {
+		t.Errorf("Expected output does not match actual output")
+	}
+}
+
+func init() {
+	scheme.Scheme = runtime.NewScheme()
+	_ = appsv1.AddToScheme(scheme.Scheme)
+}
diff --git a/pkg/kor/services_test.go b/pkg/kor/services_test.go
new file mode 100644
index 0000000..4db5901
--- /dev/null
+++ b/pkg/kor/services_test.go
@@ -0,0 +1,92 @@
+package kor
+
+import (
+	"context"
+	"encoding/json"
+	"reflect"
+	"testing"
+
+	appsv1 "k8s.io/api/apps/v1"
+	corev1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/client-go/kubernetes/fake"
+	"k8s.io/client-go/kubernetes/scheme"
+)
+
+func createTestServices(t *testing.T) *fake.Clientset {
+	clientset := fake.NewSimpleClientset()
+
+	_, err := clientset.CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{
+		ObjectMeta: v1.ObjectMeta{Name: testNamespace},
+	}, v1.CreateOptions{})
+
+	if err != nil {
+		t.Fatalf("Error creating namespace %s: %v", testNamespace, err)
+	}
+
+	endpoint1 := CreateTestEndpoint(testNamespace, "test-endpoint1", 0)
+	endpoint2 := CreateTestEndpoint(testNamespace, "test-endpoint2", 1)
+	_, err = clientset.CoreV1().Endpoints(testNamespace).Create(context.TODO(), endpoint1, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake endpoint: %v", err)
+	}
+
+	_, err = clientset.CoreV1().Endpoints(testNamespace).Create(context.TODO(), endpoint2, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake endpoint: %v", err)
+	}
+
+	return clientset
+}
+
+func TestGetEndpointsWithoutSubsets(t *testing.T) {
+	clientset := createTestServices(t)
+
+	servicesWithoutEndpoints, err := ProcessNamespaceServices(clientset, testNamespace)
+	if err != nil {
+		t.Errorf("Expected no error, got %v", err)
+	}
+
+	if len(servicesWithoutEndpoints) != 1 {
+		t.Errorf("Expected 1 service without endpoint, got %d", len(servicesWithoutEndpoints))
+	}
+
+	if servicesWithoutEndpoints[0] != "test-endpoint1" {
+		t.Errorf("Expected 'test-endpoint1', got %s", servicesWithoutEndpoints[0])
+	}
+}
+
+func TestGetUnusedServicesStructured(t *testing.T) {
+	clientset := createTestServices(t)
+
+	includeExcludeLists := IncludeExcludeLists{
+		IncludeListStr: testNamespace,
+		ExcludeListStr: "",
+	}
+
+	output, err := GetUnusedServicesStructured(includeExcludeLists, clientset, "json")
+	if err != nil {
+		t.Fatalf("Error calling GetUnusedServicesStructured: %v", err)
+	}
+
+	expectedOutput := map[string]map[string][]string{
+		testNamespace: {
+			"Services": {"test-endpoint1"},
+		},
+	}
+
+	var actualOutput map[string]map[string][]string
+	if err := json.Unmarshal([]byte(output), &actualOutput); err != nil {
+		t.Fatalf("Error unmarshaling actual output: %v", err)
+	}
+
+	if !reflect.DeepEqual(expectedOutput, actualOutput) {
+		t.Errorf("Expected output does not match actual output")
+	}
+}
+
+func init() {
+	scheme.Scheme = runtime.NewScheme()
+	_ = appsv1.AddToScheme(scheme.Scheme)
+}
diff --git a/pkg/kor/statefulsets_test.go b/pkg/kor/statefulsets_test.go
new file mode 100644
index 0000000..5fc3c91
--- /dev/null
+++ b/pkg/kor/statefulsets_test.go
@@ -0,0 +1,94 @@
+package kor
+
+import (
+	"context"
+	"encoding/json"
+	"reflect"
+	"testing"
+
+	appsv1 "k8s.io/api/apps/v1"
+	corev1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/client-go/kubernetes/fake"
+	"k8s.io/client-go/kubernetes/scheme"
+)
+
+func createTestStatefulSets(t *testing.T) *fake.Clientset {
+	clientset := fake.NewSimpleClientset()
+
+	_, err := clientset.CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{
+		ObjectMeta: v1.ObjectMeta{Name: testNamespace},
+	}, v1.CreateOptions{})
+
+	if err != nil {
+		t.Fatalf("Error creating namespace %s: %v", testNamespace, err)
+	}
+
+	appLabels := map[string]string{}
+
+	sts1 := CreateTestStatefulSet(testNamespace, "test-sts1", 0, appLabels)
+	sts2 := CreateTestStatefulSet(testNamespace, "test-sts2", 1, appLabels)
+	_, err = clientset.AppsV1().StatefulSets(testNamespace).Create(context.TODO(), sts1, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "statefulSet", err)
+	}
+
+	_, err = clientset.AppsV1().StatefulSets(testNamespace).Create(context.TODO(), sts2, v1.CreateOptions{})
+	if err != nil {
+		t.Fatalf("Error creating fake %s: %v", "statefulSet", err)
+	}
+
+	return clientset
+}
+
+func TestProcessNamespaceStatefulSets(t *testing.T) {
+	clientset := createTestStatefulSets(t)
+
+	statefulSetsWithoutReplicas, err := ProcessNamespaceStatefulSets(clientset, testNamespace)
+	if err != nil {
+		t.Errorf("Expected no error, got %v", err)
+	}
+
+	if len(statefulSetsWithoutReplicas) != 1 {
+		t.Errorf("Expected 1 deployment without replicas, got %d", len(statefulSetsWithoutReplicas))
+	}
+
+	if statefulSetsWithoutReplicas[0] != "test-sts1" {
+		t.Errorf("Expected 'test-sts1', got %s", statefulSetsWithoutReplicas[0])
+	}
+}
+
+func TestGetUnusedStatefulSetsStructured(t *testing.T) {
+	clientset := createTestStatefulSets(t)
+
+	includeExcludeLists := IncludeExcludeLists{
+		IncludeListStr: "",
+		ExcludeListStr: "",
+	}
+
+	output, err := GetUnusedStatefulSetsStructured(includeExcludeLists, clientset, "json")
+	if err != nil {
+		t.Fatalf("Error calling GetUnusedStatefulSetsStructured: %v", err)
+	}
+
+	expectedOutput := map[string]map[string][]string{
+		testNamespace: {
+			"Statefulsets": {"test-sts1"},
+		},
+	}
+
+	var actualOutput map[string]map[string][]string
+	if err := json.Unmarshal([]byte(output), &actualOutput); err != nil {
+		t.Fatalf("Error unmarshaling actual output: %v", err)
+	}
+
+	if !reflect.DeepEqual(expectedOutput, actualOutput) {
+		t.Errorf("Expected output does not match actual output")
+	}
+}
+
+func init() {
+	scheme.Scheme = runtime.NewScheme()
+	_ = appsv1.AddToScheme(scheme.Scheme)
+}