#
tokens: 16183/50000 1/115 files (page 5/5)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 5 of 5. Use http://codebase.md/portainer/portainer-mcp?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .cursor
│   └── rules
│       └── integration-test.mdc
├── .github
│   └── workflows
│       ├── ci.yml
│       └── release.yml
├── .gitignore
├── CLAUDE.md
├── cloc.sh
├── cmd
│   ├── portainer-mcp
│   │   └── mcp.go
│   └── token-count
│       └── token.go
├── docs
│   ├── clients_and_models.md
│   ├── design
│   │   ├── 202503-1-external-tools-file.md
│   │   ├── 202503-2-tools-vs-mcp-resources.md
│   │   ├── 202503-3-specific-update-tools.md
│   │   ├── 202504-1-embedded-tools-yaml.md
│   │   ├── 202504-2-tools-yaml-versioning.md
│   │   ├── 202504-3-portainer-version-compatibility.md
│   │   └── 202504-4-read-only-mode.md
│   └── design_summary.md
├── go.mod
├── go.sum
├── internal
│   ├── k8sutil
│   │   ├── stripper_test.go
│   │   └── stripper.go
│   ├── mcp
│   │   ├── access_group_test.go
│   │   ├── access_group.go
│   │   ├── docker_test.go
│   │   ├── docker.go
│   │   ├── environment_test.go
│   │   ├── environment.go
│   │   ├── group_test.go
│   │   ├── group.go
│   │   ├── kubernetes_test.go
│   │   ├── kubernetes.go
│   │   ├── mocks_test.go
│   │   ├── schema_test.go
│   │   ├── schema.go
│   │   ├── server_test.go
│   │   ├── server.go
│   │   ├── settings_test.go
│   │   ├── settings.go
│   │   ├── stack_test.go
│   │   ├── stack.go
│   │   ├── tag_test.go
│   │   ├── tag.go
│   │   ├── team_test.go
│   │   ├── team.go
│   │   ├── testdata
│   │   │   ├── invalid_tools.yaml
│   │   │   └── valid_tools.yaml
│   │   ├── user_test.go
│   │   ├── user.go
│   │   ├── utils_test.go
│   │   └── utils.go
│   └── tooldef
│       ├── tooldef_test.go
│       ├── tooldef.go
│       └── tools.yaml
├── LICENSE
├── Makefile
├── pkg
│   ├── portainer
│   │   ├── client
│   │   │   ├── access_group_test.go
│   │   │   ├── access_group.go
│   │   │   ├── client_test.go
│   │   │   ├── client.go
│   │   │   ├── docker_test.go
│   │   │   ├── docker.go
│   │   │   ├── environment_test.go
│   │   │   ├── environment.go
│   │   │   ├── group_test.go
│   │   │   ├── group.go
│   │   │   ├── kubernetes_test.go
│   │   │   ├── kubernetes.go
│   │   │   ├── mocks_test.go
│   │   │   ├── settings_test.go
│   │   │   ├── settings.go
│   │   │   ├── stack_test.go
│   │   │   ├── stack.go
│   │   │   ├── tag_test.go
│   │   │   ├── tag.go
│   │   │   ├── team_test.go
│   │   │   ├── team.go
│   │   │   ├── user_test.go
│   │   │   ├── user.go
│   │   │   ├── version_test.go
│   │   │   └── version.go
│   │   ├── models
│   │   │   ├── access_group_test.go
│   │   │   ├── access_group.go
│   │   │   ├── access_policy_test.go
│   │   │   ├── access_policy.go
│   │   │   ├── docker.go
│   │   │   ├── environment_test.go
│   │   │   ├── environment.go
│   │   │   ├── group_test.go
│   │   │   ├── group.go
│   │   │   ├── kubernetes.go
│   │   │   ├── settings_test.go
│   │   │   ├── settings.go
│   │   │   ├── stack_test.go
│   │   │   ├── stack.go
│   │   │   ├── tag_test.go
│   │   │   ├── tag.go
│   │   │   ├── team_test.go
│   │   │   ├── team.go
│   │   │   ├── user_test.go
│   │   │   └── user.go
│   │   └── utils
│   │       ├── utils_test.go
│   │       └── utils.go
│   └── toolgen
│       ├── param_test.go
│       ├── param.go
│       ├── yaml_test.go
│       └── yaml.go
├── README.md
├── tests
│   └── integration
│       ├── access_group_test.go
│       ├── containers
│       │   └── portainer.go
│       ├── docker_test.go
│       ├── environment_test.go
│       ├── group_test.go
│       ├── helpers
│       │   └── test_env.go
│       ├── server_test.go
│       ├── settings_test.go
│       ├── stack_test.go
│       ├── tag_test.go
│       ├── team_test.go
│       └── user_test.go
└── token.sh
```

# Files

--------------------------------------------------------------------------------
/internal/k8sutil/stripper_test.go:
--------------------------------------------------------------------------------

```go
   1 | package k8sutil
   2 | 
   3 | import (
   4 | 	"bytes"
   5 | 	"fmt"
   6 | 	"io"
   7 | 	"net/http"
   8 | 	"testing"
   9 | 
  10 | 	"github.com/stretchr/testify/assert"
  11 | 	"github.com/stretchr/testify/require"
  12 | 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
  13 | )
  14 | 
  15 | func TestProcessRawKubernetesAPIResponse(t *testing.T) {
  16 | 	tests := []struct {
  17 | 		name           string
  18 | 		httpResp       *http.Response
  19 | 		expectedResult string
  20 | 		expectedError  bool
  21 | 		description    string
  22 | 	}{
  23 | 		{
  24 | 			name:          "nil response",
  25 | 			httpResp:      nil,
  26 | 			expectedError: true,
  27 | 			description:   "should return error when http response is nil",
  28 | 		},
  29 | 		{
  30 | 			name: "nil body with 204 status",
  31 | 			httpResp: &http.Response{
  32 | 				StatusCode:    http.StatusNoContent,
  33 | 				Body:          nil,
  34 | 				ContentLength: 0,
  35 | 			},
  36 | 			expectedResult: "",
  37 | 			expectedError:  false,
  38 | 			description:    "should handle nil body gracefully for 204 status",
  39 | 		},
  40 | 		{
  41 | 			name: "nil body with 200 status",
  42 | 			httpResp: &http.Response{
  43 | 				StatusCode:    http.StatusOK,
  44 | 				Body:          nil,
  45 | 				ContentLength: 1,
  46 | 			},
  47 | 			expectedError: true,
  48 | 			description:   "should return error when body is nil but content expected",
  49 | 		},
  50 | 		{
  51 | 			name: "empty body",
  52 | 			httpResp: &http.Response{
  53 | 				StatusCode: http.StatusOK,
  54 | 				Body:       io.NopCloser(bytes.NewReader([]byte{})),
  55 | 			},
  56 | 			expectedResult: "",
  57 | 			expectedError:  false,
  58 | 			description:    "should handle empty body gracefully",
  59 | 		},
  60 | 		{
  61 | 			name: "empty JSON object",
  62 | 			httpResp: &http.Response{
  63 | 				StatusCode: http.StatusOK,
  64 | 				Body:       io.NopCloser(bytes.NewReader([]byte("{}"))),
  65 | 			},
  66 | 			expectedResult: "{}",
  67 | 			expectedError:  false,
  68 | 			description:    "should handle empty JSON object",
  69 | 		},
  70 | 		{
  71 | 			name: "empty JSON array",
  72 | 			httpResp: &http.Response{
  73 | 				StatusCode: http.StatusOK,
  74 | 				Body:       io.NopCloser(bytes.NewReader([]byte("[]"))),
  75 | 			},
  76 | 			expectedResult: "[]",
  77 | 			expectedError:  false,
  78 | 			description:    "should handle empty JSON array",
  79 | 		},
  80 | 		{
  81 | 			name: "invalid JSON",
  82 | 			httpResp: &http.Response{
  83 | 				StatusCode: http.StatusOK,
  84 | 				Body:       io.NopCloser(bytes.NewReader([]byte("invalid json"))),
  85 | 			},
  86 | 			expectedError: true,
  87 | 			description:   "should return error for invalid JSON",
  88 | 		},
  89 | 		{
  90 | 			name: "single object with managedFields",
  91 | 			httpResp: &http.Response{
  92 | 				StatusCode: http.StatusOK,
  93 | 				Body: io.NopCloser(bytes.NewReader([]byte(`{
  94 | 					"apiVersion": "v1",
  95 | 					"kind": "Pod",
  96 | 					"metadata": {
  97 | 						"name": "test-pod",
  98 | 						"namespace": "default",
  99 | 						"managedFields": [
 100 | 							{
 101 | 								"manager": "kubectl-client-side-apply",
 102 | 								"operation": "Update",
 103 | 								"apiVersion": "v1",
 104 | 								"time": "2023-01-01T00:00:00Z"
 105 | 							}
 106 | 						]
 107 | 					},
 108 | 					"spec": {
 109 | 						"containers": [
 110 | 							{
 111 | 								"name": "test-container",
 112 | 								"image": "nginx"
 113 | 							}
 114 | 						]
 115 | 					}
 116 | 				}`))),
 117 | 			},
 118 | 			expectedResult: `{"apiVersion":"v1","kind":"Pod","metadata":{"name":"test-pod","namespace":"default"},"spec":{"containers":[{"image":"nginx","name":"test-container"}]}}`,
 119 | 			expectedError:  false,
 120 | 			description:    "should remove managedFields from single object",
 121 | 		},
 122 | 		{
 123 | 			name: "single object without managedFields",
 124 | 			httpResp: &http.Response{
 125 | 				StatusCode: http.StatusOK,
 126 | 				Body: io.NopCloser(bytes.NewReader([]byte(`{
 127 | 					"apiVersion": "v1",
 128 | 					"kind": "Pod",
 129 | 					"metadata": {
 130 | 						"name": "test-pod",
 131 | 						"namespace": "default"
 132 | 					},
 133 | 					"spec": {
 134 | 						"containers": [
 135 | 							{
 136 | 								"name": "test-container",
 137 | 								"image": "nginx"
 138 | 							}
 139 | 						]
 140 | 					}
 141 | 				}`))),
 142 | 			},
 143 | 			expectedResult: `{"apiVersion":"v1","kind":"Pod","metadata":{"name":"test-pod","namespace":"default"},"spec":{"containers":[{"image":"nginx","name":"test-container"}]}}`,
 144 | 			expectedError:  false,
 145 | 			description:    "should handle single object without managedFields",
 146 | 		},
 147 | 		{
 148 | 			name: "list with managedFields",
 149 | 			httpResp: &http.Response{
 150 | 				StatusCode: http.StatusOK,
 151 | 				Body: io.NopCloser(bytes.NewReader([]byte(`{
 152 | 					"apiVersion": "v1",
 153 | 					"kind": "PodList",
 154 | 					"items": [
 155 | 						{
 156 | 							"apiVersion": "v1",
 157 | 							"kind": "Pod",
 158 | 							"metadata": {
 159 | 								"name": "test-pod-1",
 160 | 								"namespace": "default",
 161 | 								"managedFields": [
 162 | 									{
 163 | 										"manager": "kubectl-client-side-apply",
 164 | 										"operation": "Update",
 165 | 										"apiVersion": "v1",
 166 | 										"time": "2023-01-01T00:00:00Z"
 167 | 									}
 168 | 								]
 169 | 							},
 170 | 							"spec": {
 171 | 								"containers": [
 172 | 									{
 173 | 										"name": "test-container",
 174 | 										"image": "nginx"
 175 | 									}
 176 | 								]
 177 | 							}
 178 | 						},
 179 | 						{
 180 | 							"apiVersion": "v1",
 181 | 							"kind": "Pod",
 182 | 							"metadata": {
 183 | 								"name": "test-pod-2",
 184 | 								"namespace": "default",
 185 | 								"managedFields": [
 186 | 									{
 187 | 										"manager": "kubectl-client-side-apply",
 188 | 										"operation": "Update",
 189 | 										"apiVersion": "v1",
 190 | 										"time": "2023-01-01T00:00:00Z"
 191 | 									}
 192 | 								]
 193 | 							},
 194 | 							"spec": {
 195 | 								"containers": [
 196 | 									{
 197 | 										"name": "test-container",
 198 | 										"image": "redis"
 199 | 									}
 200 | 								]
 201 | 							}
 202 | 						}
 203 | 					]
 204 | 				}`))),
 205 | 			},
 206 | 			expectedResult: `{"apiVersion":"v1","items":[{"apiVersion":"v1","kind":"Pod","metadata":{"name":"test-pod-1","namespace":"default"},"spec":{"containers":[{"image":"nginx","name":"test-container"}]}},{"apiVersion":"v1","kind":"Pod","metadata":{"name":"test-pod-2","namespace":"default"},"spec":{"containers":[{"image":"redis","name":"test-container"}]}}],"kind":"PodList"}`,
 207 | 			expectedError:  false,
 208 | 			description:    "should remove managedFields from all items in list",
 209 | 		},
 210 | 		{
 211 | 			name: "object without metadata",
 212 | 			httpResp: &http.Response{
 213 | 				StatusCode: http.StatusOK,
 214 | 				Body: io.NopCloser(bytes.NewReader([]byte(`{
 215 | 					"apiVersion": "v1",
 216 | 					"kind": "Pod",
 217 | 					"spec": {
 218 | 						"containers": [
 219 | 							{
 220 | 								"name": "test-container",
 221 | 								"image": "nginx"
 222 | 							}
 223 | 						]
 224 | 					}
 225 | 				}`))),
 226 | 			},
 227 | 			expectedResult: `{"apiVersion":"v1","kind":"Pod","spec":{"containers":[{"image":"nginx","name":"test-container"}]}}`,
 228 | 			expectedError:  false,
 229 | 			description:    "should handle object without metadata",
 230 | 		},
 231 | 		{
 232 | 			name: "empty object with no fields",
 233 | 			httpResp: &http.Response{
 234 | 				StatusCode: http.StatusOK,
 235 | 				Body:       io.NopCloser(bytes.NewReader([]byte(`{"apiVersion":"v1","kind":"Pod"}`))),
 236 | 			},
 237 | 			expectedResult: `{"apiVersion":"v1","kind":"Pod"}`,
 238 | 			expectedError:  false,
 239 | 			description:    "should handle empty object with no fields",
 240 | 		},
 241 | 		{
 242 | 			name: "object with other metadata fields",
 243 | 			httpResp: &http.Response{
 244 | 				StatusCode: http.StatusOK,
 245 | 				Body: io.NopCloser(bytes.NewReader([]byte(`{
 246 | 					"apiVersion": "v1",
 247 | 					"kind": "Service",
 248 | 					"metadata": {
 249 | 						"name": "test-service",
 250 | 						"namespace": "default",
 251 | 						"labels": {"app": "test"},
 252 | 						"annotations": {"key": "value"},
 253 | 						"managedFields": [
 254 | 							{
 255 | 								"manager": "kubectl-client-side-apply",
 256 | 								"operation": "Update",
 257 | 								"apiVersion": "v1",
 258 | 								"time": "2023-01-01T00:00:00Z"
 259 | 							}
 260 | 						]
 261 | 					},
 262 | 					"spec": {
 263 | 						"ports": [{"port": 80}]
 264 | 					}
 265 | 				}`))),
 266 | 			},
 267 | 			expectedResult: `{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{"key":"value"},"labels":{"app":"test"},"name":"test-service","namespace":"default"},"spec":{"ports":[{"port":80}]}}`,
 268 | 			expectedError:  false,
 269 | 			description:    "should preserve other metadata fields while removing managedFields",
 270 | 		},
 271 | 		{
 272 | 			name: "list with mixed items",
 273 | 			httpResp: &http.Response{
 274 | 				StatusCode: http.StatusOK,
 275 | 				Body: io.NopCloser(bytes.NewReader([]byte(`{
 276 | 					"apiVersion": "v1",
 277 | 					"kind": "PodList",
 278 | 					"items": [
 279 | 						{
 280 | 							"apiVersion": "v1",
 281 | 							"kind": "Pod",
 282 | 							"metadata": {
 283 | 								"name": "test-pod-1",
 284 | 								"managedFields": [{"manager": "kubectl"}]
 285 | 							}
 286 | 						},
 287 | 						{
 288 | 							"apiVersion": "v1",
 289 | 							"kind": "Pod",
 290 | 							"metadata": {
 291 | 								"name": "test-pod-2"
 292 | 							}
 293 | 						}
 294 | 					]
 295 | 				}`))),
 296 | 			},
 297 | 			expectedResult: `{"apiVersion":"v1","items":[{"apiVersion":"v1","kind":"Pod","metadata":{"name":"test-pod-1"}},{"apiVersion":"v1","kind":"Pod","metadata":{"name":"test-pod-2"}}],"kind":"PodList"}`,
 298 | 			expectedError:  false,
 299 | 			description:    "should handle list with items that have and don't have managedFields",
 300 | 		},
 301 | 		{
 302 | 			name: "nil body with 404 status",
 303 | 			httpResp: &http.Response{
 304 | 				StatusCode:    http.StatusNotFound,
 305 | 				Body:          nil,
 306 | 				ContentLength: 0,
 307 | 			},
 308 | 			expectedResult: "",
 309 | 			expectedError:  false,
 310 | 			description:    "should handle nil body for non-204 status with zero content length",
 311 | 		},
 312 | 		{
 313 | 			name: "nil body with 500 status",
 314 | 			httpResp: &http.Response{
 315 | 				StatusCode:    http.StatusInternalServerError,
 316 | 				Body:          nil,
 317 | 				ContentLength: 0,
 318 | 			},
 319 | 			expectedResult: "",
 320 | 			expectedError:  false,
 321 | 			description:    "should handle nil body for error status with zero content length",
 322 | 		},
 323 | 		{
 324 | 			name: "malformed list JSON",
 325 | 			httpResp: &http.Response{
 326 | 				StatusCode: http.StatusOK,
 327 | 				Body: io.NopCloser(bytes.NewReader([]byte(`{
 328 | 					"apiVersion": "v1",
 329 | 					"kind": "PodList",
 330 | 					"items": "not-an-array"
 331 | 				}`))),
 332 | 			},
 333 | 			expectedResult: `{"apiVersion":"v1","kind":"PodList","items":"not-an-array"}`,
 334 | 			expectedError:  false,
 335 | 			description:    "should handle malformed list JSON gracefully",
 336 | 		},
 337 | 		{
 338 | 			name: "object with circular reference",
 339 | 			httpResp: &http.Response{
 340 | 				StatusCode: http.StatusOK,
 341 | 				Body: io.NopCloser(bytes.NewReader([]byte(`{
 342 | 					"apiVersion": "v1",
 343 | 					"kind": "Pod",
 344 | 					"metadata": {
 345 | 						"name": "test-pod",
 346 | 						"managedFields": [
 347 | 							{
 348 | 								"manager": "kubectl-client-side-apply",
 349 | 								"operation": "Update",
 350 | 								"apiVersion": "v1",
 351 | 								"time": "2023-01-01T00:00:00Z"
 352 | 							}
 353 | 						]
 354 | 					},
 355 | 					"spec": {
 356 | 						"containers": [
 357 | 							{
 358 | 								"name": "test-container",
 359 | 								"image": "nginx"
 360 | 							}
 361 | 						]
 362 | 					}
 363 | 				}`))),
 364 | 			},
 365 | 			expectedResult: `{"apiVersion":"v1","kind":"Pod","metadata":{"name":"test-pod"},"spec":{"containers":[{"image":"nginx","name":"test-container"}]}}`,
 366 | 			expectedError:  false,
 367 | 			description:    "should handle object with managedFields and preserve other fields",
 368 | 		},
 369 | 		{
 370 | 			name: "list with empty items",
 371 | 			httpResp: &http.Response{
 372 | 				StatusCode: http.StatusOK,
 373 | 				Body: io.NopCloser(bytes.NewReader([]byte(`{
 374 | 					"apiVersion": "v1",
 375 | 					"kind": "PodList",
 376 | 					"items": []
 377 | 				}`))),
 378 | 			},
 379 | 			expectedResult: `{"apiVersion":"v1","items":[],"kind":"PodList"}`,
 380 | 			expectedError:  false,
 381 | 			description:    "should handle list with empty items array",
 382 | 		},
 383 | 		{
 384 | 			name: "object with deeply nested managedFields",
 385 | 			httpResp: &http.Response{
 386 | 				StatusCode: http.StatusOK,
 387 | 				Body: io.NopCloser(bytes.NewReader([]byte(`{
 388 | 					"apiVersion": "v1",
 389 | 					"kind": "Pod",
 390 | 					"metadata": {
 391 | 						"name": "test-pod",
 392 | 						"managedFields": [
 393 | 							{
 394 | 								"manager": "kubectl-client-side-apply",
 395 | 								"operation": "Update",
 396 | 								"apiVersion": "v1",
 397 | 								"time": "2023-01-01T00:00:00Z",
 398 | 								"fields": {
 399 | 									"f:spec": {
 400 | 										"f:containers": {
 401 | 											"k:{\"name\":\"test-container\"}": {
 402 | 												"f:image": {}
 403 | 											}
 404 | 										}
 405 | 									}
 406 | 								}
 407 | 							}
 408 | 						]
 409 | 					},
 410 | 					"spec": {
 411 | 						"containers": [
 412 | 							{
 413 | 								"name": "test-container",
 414 | 								"image": "nginx"
 415 | 							}
 416 | 						]
 417 | 					}
 418 | 				}`))),
 419 | 			},
 420 | 			expectedResult: `{"apiVersion":"v1","kind":"Pod","metadata":{"name":"test-pod"},"spec":{"containers":[{"image":"nginx","name":"test-container"}]}}`,
 421 | 			expectedError:  false,
 422 | 			description:    "should remove complex managedFields with nested structures",
 423 | 		},
 424 | 		{
 425 | 			name: "different Kubernetes resource type",
 426 | 			httpResp: &http.Response{
 427 | 				StatusCode: http.StatusOK,
 428 | 				Body: io.NopCloser(bytes.NewReader([]byte(`{
 429 | 					"apiVersion": "apps/v1",
 430 | 					"kind": "Deployment",
 431 | 					"metadata": {
 432 | 						"name": "test-deployment",
 433 | 						"namespace": "default",
 434 | 						"managedFields": [
 435 | 							{
 436 | 								"manager": "kubectl-client-side-apply",
 437 | 								"operation": "Update",
 438 | 								"apiVersion": "apps/v1",
 439 | 								"time": "2023-01-01T00:00:00Z"
 440 | 							}
 441 | 						]
 442 | 					},
 443 | 					"spec": {
 444 | 						"replicas": 3,
 445 | 						"selector": {
 446 | 							"matchLabels": {
 447 | 								"app": "test"
 448 | 							}
 449 | 						}
 450 | 					}
 451 | 				}`))),
 452 | 			},
 453 | 			expectedResult: `{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"name":"test-deployment","namespace":"default"},"spec":{"replicas":3,"selector":{"matchLabels":{"app":"test"}}}}`,
 454 | 			expectedError:  false,
 455 | 			description:    "should handle different Kubernetes resource types",
 456 | 		},
 457 | 		{
 458 | 			name: "custom resource with managedFields",
 459 | 			httpResp: &http.Response{
 460 | 				StatusCode: http.StatusOK,
 461 | 				Body: io.NopCloser(bytes.NewReader([]byte(`{
 462 | 					"apiVersion": "custom.example.com/v1",
 463 | 					"kind": "CustomResource",
 464 | 					"metadata": {
 465 | 						"name": "test-custom",
 466 | 						"managedFields": [
 467 | 							{
 468 | 								"manager": "custom-controller",
 469 | 								"operation": "Apply",
 470 | 								"apiVersion": "custom.example.com/v1",
 471 | 								"time": "2023-01-01T00:00:00Z"
 472 | 							}
 473 | 						]
 474 | 					},
 475 | 					"spec": {
 476 | 						"customField": "customValue"
 477 | 					}
 478 | 				}`))),
 479 | 			},
 480 | 			expectedResult: `{"apiVersion":"custom.example.com/v1","kind":"CustomResource","metadata":{"name":"test-custom"},"spec":{"customField":"customValue"}}`,
 481 | 			expectedError:  false,
 482 | 			description:    "should handle custom resources with managedFields",
 483 | 		},
 484 | 	}
 485 | 
 486 | 	for _, tt := range tests {
 487 | 		t.Run(tt.name, func(t *testing.T) {
 488 | 			result, err := ProcessRawKubernetesAPIResponse(tt.httpResp)
 489 | 
 490 | 			if tt.expectedError {
 491 | 				assert.Error(t, err, tt.description)
 492 | 				return
 493 | 			}
 494 | 
 495 | 			require.NoError(t, err, tt.description)
 496 | 			if tt.expectedResult == "" {
 497 | 				assert.Equal(t, tt.expectedResult, string(result), tt.description)
 498 | 			} else {
 499 | 				assert.JSONEq(t, tt.expectedResult, string(result), tt.description)
 500 | 			}
 501 | 		})
 502 | 	}
 503 | }
 504 | 
 505 | func TestRemoveManagedFieldsFromUnstructuredObject(t *testing.T) {
 506 | 	tests := []struct {
 507 | 		name           string
 508 | 		obj            *unstructured.Unstructured
 509 | 		expectedResult *unstructured.Unstructured
 510 | 		expectedError  bool
 511 | 		description    string
 512 | 	}{
 513 | 		{
 514 | 			name:           "nil object",
 515 | 			obj:            nil,
 516 | 			expectedResult: nil,
 517 | 			expectedError:  false,
 518 | 			description:    "should handle nil object gracefully",
 519 | 		},
 520 | 		{
 521 | 			name: "object with nil Object field",
 522 | 			obj: &unstructured.Unstructured{
 523 | 				Object: nil,
 524 | 			},
 525 | 			expectedResult: &unstructured.Unstructured{
 526 | 				Object: nil,
 527 | 			},
 528 | 			expectedError: false,
 529 | 			description:   "should handle object with nil Object field",
 530 | 		},
 531 | 		{
 532 | 			name: "object with managedFields",
 533 | 			obj: &unstructured.Unstructured{
 534 | 				Object: map[string]interface{}{
 535 | 					"apiVersion": "v1",
 536 | 					"kind":       "Pod",
 537 | 					"metadata": map[string]interface{}{
 538 | 						"name":      "test-pod",
 539 | 						"namespace": "default",
 540 | 						"managedFields": []interface{}{
 541 | 							map[string]interface{}{
 542 | 								"manager":    "kubectl-client-side-apply",
 543 | 								"operation":  "Update",
 544 | 								"apiVersion": "v1",
 545 | 								"time":       "2023-01-01T00:00:00Z",
 546 | 							},
 547 | 						},
 548 | 					},
 549 | 					"spec": map[string]interface{}{
 550 | 						"containers": []interface{}{
 551 | 							map[string]interface{}{
 552 | 								"name":  "test-container",
 553 | 								"image": "nginx",
 554 | 							},
 555 | 						},
 556 | 					},
 557 | 				},
 558 | 			},
 559 | 			expectedResult: &unstructured.Unstructured{
 560 | 				Object: map[string]interface{}{
 561 | 					"apiVersion": "v1",
 562 | 					"kind":       "Pod",
 563 | 					"metadata": map[string]interface{}{
 564 | 						"name":      "test-pod",
 565 | 						"namespace": "default",
 566 | 					},
 567 | 					"spec": map[string]interface{}{
 568 | 						"containers": []interface{}{
 569 | 							map[string]interface{}{
 570 | 								"name":  "test-container",
 571 | 								"image": "nginx",
 572 | 							},
 573 | 						},
 574 | 					},
 575 | 				},
 576 | 			},
 577 | 			expectedError: false,
 578 | 			description:   "should remove managedFields from object metadata",
 579 | 		},
 580 | 		{
 581 | 			name: "object without managedFields",
 582 | 			obj: &unstructured.Unstructured{
 583 | 				Object: map[string]interface{}{
 584 | 					"apiVersion": "v1",
 585 | 					"kind":       "Pod",
 586 | 					"metadata": map[string]interface{}{
 587 | 						"name":      "test-pod",
 588 | 						"namespace": "default",
 589 | 					},
 590 | 					"spec": map[string]interface{}{
 591 | 						"containers": []interface{}{
 592 | 							map[string]interface{}{
 593 | 								"name":  "test-container",
 594 | 								"image": "nginx",
 595 | 							},
 596 | 						},
 597 | 					},
 598 | 				},
 599 | 			},
 600 | 			expectedResult: &unstructured.Unstructured{
 601 | 				Object: map[string]interface{}{
 602 | 					"apiVersion": "v1",
 603 | 					"kind":       "Pod",
 604 | 					"metadata": map[string]interface{}{
 605 | 						"name":      "test-pod",
 606 | 						"namespace": "default",
 607 | 					},
 608 | 					"spec": map[string]interface{}{
 609 | 						"containers": []interface{}{
 610 | 							map[string]interface{}{
 611 | 								"name":  "test-container",
 612 | 								"image": "nginx",
 613 | 							},
 614 | 						},
 615 | 					},
 616 | 				},
 617 | 			},
 618 | 			expectedError: false,
 619 | 			description:   "should handle object without managedFields",
 620 | 		},
 621 | 		{
 622 | 			name: "object without metadata",
 623 | 			obj: &unstructured.Unstructured{
 624 | 				Object: map[string]interface{}{
 625 | 					"apiVersion": "v1",
 626 | 					"kind":       "Pod",
 627 | 					"spec": map[string]interface{}{
 628 | 						"containers": []interface{}{
 629 | 							map[string]interface{}{
 630 | 								"name":  "test-container",
 631 | 								"image": "nginx",
 632 | 							},
 633 | 						},
 634 | 					},
 635 | 				},
 636 | 			},
 637 | 			expectedResult: &unstructured.Unstructured{
 638 | 				Object: map[string]interface{}{
 639 | 					"apiVersion": "v1",
 640 | 					"kind":       "Pod",
 641 | 					"spec": map[string]interface{}{
 642 | 						"containers": []interface{}{
 643 | 							map[string]interface{}{
 644 | 								"name":  "test-container",
 645 | 								"image": "nginx",
 646 | 							},
 647 | 						},
 648 | 					},
 649 | 				},
 650 | 			},
 651 | 			expectedError: false,
 652 | 			description:   "should handle object without metadata",
 653 | 		},
 654 | 		{
 655 | 			name: "object with non-map metadata",
 656 | 			obj: &unstructured.Unstructured{
 657 | 				Object: map[string]interface{}{
 658 | 					"apiVersion": "v1",
 659 | 					"kind":       "Pod",
 660 | 					"metadata":   "not-a-map",
 661 | 					"spec": map[string]interface{}{
 662 | 						"containers": []interface{}{
 663 | 							map[string]interface{}{
 664 | 								"name":  "test-container",
 665 | 								"image": "nginx",
 666 | 							},
 667 | 						},
 668 | 					},
 669 | 				},
 670 | 			},
 671 | 			expectedResult: &unstructured.Unstructured{
 672 | 				Object: map[string]interface{}{
 673 | 					"apiVersion": "v1",
 674 | 					"kind":       "Pod",
 675 | 					"metadata":   "not-a-map",
 676 | 					"spec": map[string]interface{}{
 677 | 						"containers": []interface{}{
 678 | 							map[string]interface{}{
 679 | 								"name":  "test-container",
 680 | 								"image": "nginx",
 681 | 							},
 682 | 						},
 683 | 					},
 684 | 				},
 685 | 			},
 686 | 			expectedError: true,
 687 | 			description:   "should return error when metadata is not a map",
 688 | 		},
 689 | 		{
 690 | 			name: "object with complex metadata",
 691 | 			obj: &unstructured.Unstructured{
 692 | 				Object: map[string]interface{}{
 693 | 					"apiVersion": "v1",
 694 | 					"kind":       "Service",
 695 | 					"metadata": map[string]interface{}{
 696 | 						"name":      "test-service",
 697 | 						"namespace": "default",
 698 | 						"labels": map[string]interface{}{
 699 | 							"app":     "test",
 700 | 							"version": "v1",
 701 | 						},
 702 | 						"annotations": map[string]interface{}{
 703 | 							"key1": "value1",
 704 | 							"key2": "value2",
 705 | 						},
 706 | 						"managedFields": []interface{}{
 707 | 							map[string]interface{}{
 708 | 								"manager":    "kubectl-client-side-apply",
 709 | 								"operation":  "Update",
 710 | 								"apiVersion": "v1",
 711 | 								"time":       "2023-01-01T00:00:00Z",
 712 | 							},
 713 | 							map[string]interface{}{
 714 | 								"manager":    "controller-manager",
 715 | 								"operation":  "Apply",
 716 | 								"apiVersion": "v1",
 717 | 								"time":       "2023-01-02T00:00:00Z",
 718 | 							},
 719 | 						},
 720 | 						"ownerReferences": []interface{}{
 721 | 							map[string]interface{}{
 722 | 								"apiVersion": "apps/v1",
 723 | 								"kind":       "Deployment",
 724 | 								"name":       "test-deployment",
 725 | 							},
 726 | 						},
 727 | 					},
 728 | 					"spec": map[string]interface{}{
 729 | 						"ports": []interface{}{
 730 | 							map[string]interface{}{
 731 | 								"port": 80,
 732 | 							},
 733 | 						},
 734 | 					},
 735 | 				},
 736 | 			},
 737 | 			expectedResult: &unstructured.Unstructured{
 738 | 				Object: map[string]interface{}{
 739 | 					"apiVersion": "v1",
 740 | 					"kind":       "Service",
 741 | 					"metadata": map[string]interface{}{
 742 | 						"name":      "test-service",
 743 | 						"namespace": "default",
 744 | 						"labels": map[string]interface{}{
 745 | 							"app":     "test",
 746 | 							"version": "v1",
 747 | 						},
 748 | 						"annotations": map[string]interface{}{
 749 | 							"key1": "value1",
 750 | 							"key2": "value2",
 751 | 						},
 752 | 						"ownerReferences": []interface{}{
 753 | 							map[string]interface{}{
 754 | 								"apiVersion": "apps/v1",
 755 | 								"kind":       "Deployment",
 756 | 								"name":       "test-deployment",
 757 | 							},
 758 | 						},
 759 | 					},
 760 | 					"spec": map[string]interface{}{
 761 | 						"ports": []interface{}{
 762 | 							map[string]interface{}{
 763 | 								"port": 80,
 764 | 							},
 765 | 						},
 766 | 					},
 767 | 				},
 768 | 			},
 769 | 			expectedError: false,
 770 | 			description:   "should remove managedFields while preserving other metadata fields",
 771 | 		},
 772 | 		{
 773 | 			name: "object with empty managedFields",
 774 | 			obj: &unstructured.Unstructured{
 775 | 				Object: map[string]interface{}{
 776 | 					"apiVersion": "v1",
 777 | 					"kind":       "Pod",
 778 | 					"metadata": map[string]interface{}{
 779 | 						"name":          "test-pod",
 780 | 						"namespace":     "default",
 781 | 						"managedFields": []interface{}{},
 782 | 					},
 783 | 					"spec": map[string]interface{}{
 784 | 						"containers": []interface{}{
 785 | 							map[string]interface{}{
 786 | 								"name":  "test-container",
 787 | 								"image": "nginx",
 788 | 							},
 789 | 						},
 790 | 					},
 791 | 				},
 792 | 			},
 793 | 			expectedResult: &unstructured.Unstructured{
 794 | 				Object: map[string]interface{}{
 795 | 					"apiVersion": "v1",
 796 | 					"kind":       "Pod",
 797 | 					"metadata": map[string]interface{}{
 798 | 						"name":      "test-pod",
 799 | 						"namespace": "default",
 800 | 					},
 801 | 					"spec": map[string]interface{}{
 802 | 						"containers": []interface{}{
 803 | 							map[string]interface{}{
 804 | 								"name":  "test-container",
 805 | 								"image": "nginx",
 806 | 							},
 807 | 						},
 808 | 					},
 809 | 				},
 810 | 			},
 811 | 			expectedError: false,
 812 | 			description:   "should remove empty managedFields array",
 813 | 		},
 814 | 		{
 815 | 			name: "object with nil managedFields",
 816 | 			obj: &unstructured.Unstructured{
 817 | 				Object: map[string]interface{}{
 818 | 					"apiVersion": "v1",
 819 | 					"kind":       "Pod",
 820 | 					"metadata": map[string]interface{}{
 821 | 						"name":          "test-pod",
 822 | 						"namespace":     "default",
 823 | 						"managedFields": nil,
 824 | 					},
 825 | 					"spec": map[string]interface{}{
 826 | 						"containers": []interface{}{
 827 | 							map[string]interface{}{
 828 | 								"name":  "test-container",
 829 | 								"image": "nginx",
 830 | 							},
 831 | 						},
 832 | 					},
 833 | 				},
 834 | 			},
 835 | 			expectedResult: &unstructured.Unstructured{
 836 | 				Object: map[string]interface{}{
 837 | 					"apiVersion": "v1",
 838 | 					"kind":       "Pod",
 839 | 					"metadata": map[string]interface{}{
 840 | 						"name":      "test-pod",
 841 | 						"namespace": "default",
 842 | 					},
 843 | 					"spec": map[string]interface{}{
 844 | 						"containers": []interface{}{
 845 | 							map[string]interface{}{
 846 | 								"name":  "test-container",
 847 | 								"image": "nginx",
 848 | 							},
 849 | 						},
 850 | 					},
 851 | 				},
 852 | 			},
 853 | 			expectedError: false,
 854 | 			description:   "should remove nil managedFields",
 855 | 		},
 856 | 		{
 857 | 			name: "object with minimal fields",
 858 | 			obj: &unstructured.Unstructured{
 859 | 				Object: map[string]interface{}{
 860 | 					"apiVersion": "v1",
 861 | 					"kind":       "Pod",
 862 | 					"metadata": map[string]interface{}{
 863 | 						"name": "test-pod",
 864 | 					},
 865 | 				},
 866 | 			},
 867 | 			expectedResult: &unstructured.Unstructured{
 868 | 				Object: map[string]interface{}{
 869 | 					"apiVersion": "v1",
 870 | 					"kind":       "Pod",
 871 | 					"metadata": map[string]interface{}{
 872 | 						"name": "test-pod",
 873 | 					},
 874 | 				},
 875 | 			},
 876 | 			expectedError: false,
 877 | 			description:   "should handle object with minimal metadata",
 878 | 		},
 879 | 	}
 880 | 
 881 | 	for _, tt := range tests {
 882 | 		t.Run(tt.name, func(t *testing.T) {
 883 | 			err := removeManagedFieldsFromUnstructuredObject(tt.obj)
 884 | 
 885 | 			if tt.expectedError {
 886 | 				assert.Error(t, err, tt.description)
 887 | 				return
 888 | 			}
 889 | 
 890 | 			require.NoError(t, err, tt.description)
 891 | 			assert.Equal(t, tt.expectedResult, tt.obj, tt.description)
 892 | 		})
 893 | 	}
 894 | }
 895 | 
 896 | // Helper function to create a JSON response for testing
 897 | func createJSONResponse(statusCode int, body string) *http.Response {
 898 | 	return &http.Response{
 899 | 		StatusCode: statusCode,
 900 | 		Body:       io.NopCloser(bytes.NewReader([]byte(body))),
 901 | 		Header:     make(http.Header),
 902 | 	}
 903 | }
 904 | 
 905 | // Benchmark tests for performance
 906 | func BenchmarkProcessRawKubernetesAPIResponse_SingleObject(b *testing.B) {
 907 | 	jsonBody := `{
 908 | 		"apiVersion": "v1",
 909 | 		"kind": "Pod",
 910 | 		"metadata": {
 911 | 			"name": "test-pod",
 912 | 			"namespace": "default",
 913 | 			"managedFields": [
 914 | 				{
 915 | 					"manager": "kubectl-client-side-apply",
 916 | 					"operation": "Update",
 917 | 					"apiVersion": "v1",
 918 | 					"time": "2023-01-01T00:00:00Z"
 919 | 				}
 920 | 			]
 921 | 		},
 922 | 		"spec": {
 923 | 			"containers": [
 924 | 				{
 925 | 					"name": "test-container",
 926 | 					"image": "nginx"
 927 | 				}
 928 | 			]
 929 | 		}
 930 | 	}`
 931 | 
 932 | 	for i := 0; i < b.N; i++ {
 933 | 		resp := createJSONResponse(http.StatusOK, jsonBody)
 934 | 		_, err := ProcessRawKubernetesAPIResponse(resp)
 935 | 		if err != nil {
 936 | 			b.Fatal(err)
 937 | 		}
 938 | 	}
 939 | }
 940 | 
 941 | func BenchmarkProcessRawKubernetesAPIResponse_List(b *testing.B) {
 942 | 	jsonBody := `{
 943 | 		"apiVersion": "v1",
 944 | 		"kind": "PodList",
 945 | 		"items": [
 946 | 			{
 947 | 				"apiVersion": "v1",
 948 | 				"kind": "Pod",
 949 | 				"metadata": {
 950 | 					"name": "test-pod-1",
 951 | 					"namespace": "default",
 952 | 					"managedFields": [
 953 | 						{
 954 | 							"manager": "kubectl-client-side-apply",
 955 | 							"operation": "Update",
 956 | 							"apiVersion": "v1",
 957 | 							"time": "2023-01-01T00:00:00Z"
 958 | 						}
 959 | 					]
 960 | 				},
 961 | 				"spec": {
 962 | 					"containers": [
 963 | 						{
 964 | 							"name": "test-container",
 965 | 							"image": "nginx"
 966 | 						}
 967 | 					]
 968 | 				}
 969 | 			}
 970 | 		]
 971 | 	}`
 972 | 
 973 | 	for i := 0; i < b.N; i++ {
 974 | 		resp := createJSONResponse(http.StatusOK, jsonBody)
 975 | 		_, err := ProcessRawKubernetesAPIResponse(resp)
 976 | 		if err != nil {
 977 | 			b.Fatal(err)
 978 | 		}
 979 | 	}
 980 | }
 981 | 
 982 | // TestErrorConditions tests various error conditions that might occur
 983 | func TestErrorConditions(t *testing.T) {
 984 | 	t.Run("body read error", func(t *testing.T) {
 985 | 		// Create a response with a body that will fail to read
 986 | 		resp := &http.Response{
 987 | 			StatusCode: http.StatusOK,
 988 | 			Body:       &errorReader{},
 989 | 		}
 990 | 
 991 | 		_, err := ProcessRawKubernetesAPIResponse(resp)
 992 | 		assert.Error(t, err)
 993 | 		assert.Contains(t, err.Error(), "failed to read response body")
 994 | 	})
 995 | 
 996 | 	t.Run("json marshal error", func(t *testing.T) {
 997 | 		// This test is difficult to trigger in practice since the unstructured
 998 | 		// library handles most cases, but we can test the structure
 999 | 		resp := createJSONResponse(http.StatusOK, `{
1000 | 			"apiVersion": "v1",
1001 | 			"kind": "Pod",
1002 | 			"metadata": {
1003 | 				"name": "test-pod",
1004 | 				"managedFields": [{"manager": "kubectl"}]
1005 | 			}
1006 | 		}`)
1007 | 
1008 | 		result, err := ProcessRawKubernetesAPIResponse(resp)
1009 | 		require.NoError(t, err)
1010 | 		assert.NotEmpty(t, result)
1011 | 	})
1012 | }
1013 | 
1014 | // errorReader is a reader that always returns an error
1015 | type errorReader struct{}
1016 | 
1017 | func (e *errorReader) Read(p []byte) (n int, err error) {
1018 | 	return 0, fmt.Errorf("simulated read error")
1019 | }
1020 | 
1021 | func (e *errorReader) Close() error {
1022 | 	return nil
1023 | }
1024 | 
1025 | // TestEdgeCases tests various edge cases and boundary conditions
1026 | func TestEdgeCases(t *testing.T) {
1027 | 	t.Run("very large managedFields", func(t *testing.T) {
1028 | 		// Create a large managedFields array
1029 | 		largeManagedFields := make([]interface{}, 1000)
1030 | 		for i := 0; i < 1000; i++ {
1031 | 			largeManagedFields[i] = map[string]interface{}{
1032 | 				"manager":    fmt.Sprintf("manager-%d", i),
1033 | 				"operation":  "Update",
1034 | 				"apiVersion": "v1",
1035 | 				"time":       "2023-01-01T00:00:00Z",
1036 | 			}
1037 | 		}
1038 | 
1039 | 		obj := &unstructured.Unstructured{
1040 | 			Object: map[string]interface{}{
1041 | 				"apiVersion": "v1",
1042 | 				"kind":       "Pod",
1043 | 				"metadata": map[string]interface{}{
1044 | 					"name":          "test-pod",
1045 | 					"managedFields": largeManagedFields,
1046 | 				},
1047 | 			},
1048 | 		}
1049 | 
1050 | 		err := removeManagedFieldsFromUnstructuredObject(obj)
1051 | 		require.NoError(t, err)
1052 | 
1053 | 		// Verify managedFields was removed
1054 | 		metadata, found, err := unstructured.NestedFieldCopy(obj.Object, "metadata")
1055 | 		require.NoError(t, err)
1056 | 		require.True(t, found)
1057 | 
1058 | 		metadataMap, ok := metadata.(map[string]interface{})
1059 | 		require.True(t, ok)
1060 | 		_, hasManagedFields := metadataMap["managedFields"]
1061 | 		assert.False(t, hasManagedFields)
1062 | 	})
1063 | 
1064 | 	t.Run("metadata with special characters", func(t *testing.T) {
1065 | 		obj := &unstructured.Unstructured{
1066 | 			Object: map[string]interface{}{
1067 | 				"apiVersion": "v1",
1068 | 				"kind":       "Pod",
1069 | 				"metadata": map[string]interface{}{
1070 | 					"name":          "test-pod-with-special-chars-!@#$%^&*()",
1071 | 					"namespace":     "default-namespace",
1072 | 					"managedFields": []interface{}{map[string]interface{}{"manager": "kubectl"}},
1073 | 				},
1074 | 			},
1075 | 		}
1076 | 
1077 | 		err := removeManagedFieldsFromUnstructuredObject(obj)
1078 | 		require.NoError(t, err)
1079 | 
1080 | 		// Verify the object still has the special characters in name
1081 | 		name, found, err := unstructured.NestedString(obj.Object, "metadata", "name")
1082 | 		require.NoError(t, err)
1083 | 		require.True(t, found)
1084 | 		assert.Equal(t, "test-pod-with-special-chars-!@#$%^&*()", name)
1085 | 	})
1086 | 
1087 | 	t.Run("empty object after processing", func(t *testing.T) {
1088 | 		obj := &unstructured.Unstructured{
1089 | 			Object: map[string]interface{}{
1090 | 				"apiVersion": "v1",
1091 | 				"kind":       "Pod",
1092 | 				"metadata": map[string]interface{}{
1093 | 					"managedFields": []interface{}{map[string]interface{}{"manager": "kubectl"}},
1094 | 				},
1095 | 			},
1096 | 		}
1097 | 
1098 | 		err := removeManagedFieldsFromUnstructuredObject(obj)
1099 | 		require.NoError(t, err)
1100 | 
1101 | 		// Verify the object still has the basic structure
1102 | 		assert.Equal(t, "v1", obj.GetAPIVersion())
1103 | 		assert.Equal(t, "Pod", obj.GetKind())
1104 | 	})
1105 | 
1106 | 	t.Run("object with only managedFields in metadata", func(t *testing.T) {
1107 | 		obj := &unstructured.Unstructured{
1108 | 			Object: map[string]interface{}{
1109 | 				"apiVersion": "v1",
1110 | 				"kind":       "Pod",
1111 | 				"metadata": map[string]interface{}{
1112 | 					"managedFields": []interface{}{
1113 | 						map[string]interface{}{"manager": "kubectl"},
1114 | 						map[string]interface{}{"manager": "controller"},
1115 | 					},
1116 | 				},
1117 | 			},
1118 | 		}
1119 | 
1120 | 		err := removeManagedFieldsFromUnstructuredObject(obj)
1121 | 		require.NoError(t, err)
1122 | 
1123 | 		// Verify managedFields was removed and metadata is now empty
1124 | 		metadata, found, err := unstructured.NestedFieldCopy(obj.Object, "metadata")
1125 | 		require.NoError(t, err)
1126 | 		require.True(t, found)
1127 | 
1128 | 		metadataMap, ok := metadata.(map[string]interface{})
1129 | 		require.True(t, ok)
1130 | 		assert.Empty(t, metadataMap)
1131 | 	})
1132 | 
1133 | 	t.Run("object with empty Object map", func(t *testing.T) {
1134 | 		obj := &unstructured.Unstructured{
1135 | 			Object: map[string]interface{}{},
1136 | 		}
1137 | 
1138 | 		err := removeManagedFieldsFromUnstructuredObject(obj)
1139 | 		require.NoError(t, err)
1140 | 		assert.Empty(t, obj.Object)
1141 | 	})
1142 | 
1143 | 	t.Run("object with non-map metadata that causes error", func(t *testing.T) {
1144 | 		obj := &unstructured.Unstructured{
1145 | 			Object: map[string]interface{}{
1146 | 				"apiVersion": "v1",
1147 | 				"kind":       "Pod",
1148 | 				"metadata":   "not-a-map",
1149 | 			},
1150 | 		}
1151 | 
1152 | 		err := removeManagedFieldsFromUnstructuredObject(obj)
1153 | 		assert.Error(t, err)
1154 | 		assert.Contains(t, err.Error(), "metadata for object")
1155 | 		assert.Contains(t, err.Error(), "is not in the expected map format")
1156 | 	})
1157 | 
1158 | 	t.Run("object with metadata that causes NestedFieldCopy error", func(t *testing.T) {
1159 | 		// Create an object with a metadata field that will cause an error
1160 | 		// This is difficult to trigger in practice, but we can test the error path
1161 | 		obj := &unstructured.Unstructured{
1162 | 			Object: map[string]interface{}{
1163 | 				"apiVersion": "v1",
1164 | 				"kind":       "Pod",
1165 | 				"metadata": map[string]interface{}{
1166 | 					"name": "test-pod",
1167 | 				},
1168 | 			},
1169 | 		}
1170 | 
1171 | 		err := removeManagedFieldsFromUnstructuredObject(obj)
1172 | 		require.NoError(t, err)
1173 | 	})
1174 | 
1175 | 	t.Run("object with metadata that causes SetNestedField error", func(t *testing.T) {
1176 | 		// This is difficult to trigger in practice since SetNestedField is quite robust
1177 | 		// But we can test the structure
1178 | 		obj := &unstructured.Unstructured{
1179 | 			Object: map[string]interface{}{
1180 | 				"apiVersion": "v1",
1181 | 				"kind":       "Pod",
1182 | 				"metadata": map[string]interface{}{
1183 | 					"name":          "test-pod",
1184 | 					"managedFields": []interface{}{map[string]interface{}{"manager": "kubectl"}},
1185 | 				},
1186 | 			},
1187 | 		}
1188 | 
1189 | 		err := removeManagedFieldsFromUnstructuredObject(obj)
1190 | 		require.NoError(t, err)
1191 | 	})
1192 | }
1193 | 
1194 | // TestAdditionalErrorCases tests additional error scenarios that might not be covered
1195 | func TestAdditionalErrorCases(t *testing.T) {
1196 | 	t.Run("list with ToList error", func(t *testing.T) {
1197 | 		// Create a malformed list that will cause ToList to fail
1198 | 		// This is difficult to trigger in practice, but we can test the structure
1199 | 		resp := &http.Response{
1200 | 			StatusCode: http.StatusOK,
1201 | 			Body: io.NopCloser(bytes.NewReader([]byte(`{
1202 | 				"apiVersion": "v1",
1203 | 				"kind": "PodList",
1204 | 				"items": "not-an-array"
1205 | 			}`))),
1206 | 		}
1207 | 
1208 | 		result, err := ProcessRawKubernetesAPIResponse(resp)
1209 | 		// This should not error because the unstructured library handles this gracefully
1210 | 		require.NoError(t, err)
1211 | 		assert.NotEmpty(t, result)
1212 | 	})
1213 | 
1214 | 	t.Run("single object with empty Object map", func(t *testing.T) {
1215 | 		resp := &http.Response{
1216 | 			StatusCode: http.StatusOK,
1217 | 			Body:       io.NopCloser(bytes.NewReader([]byte(`{"apiVersion":"v1","kind":"Pod"}`))),
1218 | 		}
1219 | 
1220 | 		result, err := ProcessRawKubernetesAPIResponse(resp)
1221 | 		require.NoError(t, err)
1222 | 		assert.NotEmpty(t, result)
1223 | 	})
1224 | 
1225 | 	t.Run("list with error during item processing", func(t *testing.T) {
1226 | 		// Create a list where one item has invalid metadata
1227 | 		resp := &http.Response{
1228 | 			StatusCode: http.StatusOK,
1229 | 			Body: io.NopCloser(bytes.NewReader([]byte(`{
1230 | 				"apiVersion": "v1",
1231 | 				"kind": "PodList",
1232 | 				"items": [
1233 | 					{
1234 | 						"apiVersion": "v1",
1235 | 						"kind": "Pod",
1236 | 						"metadata": "not-a-map"
1237 | 					}
1238 | 				]
1239 | 			}`))),
1240 | 		}
1241 | 
1242 | 		_, err := ProcessRawKubernetesAPIResponse(resp)
1243 | 		assert.Error(t, err)
1244 | 		assert.Contains(t, err.Error(), "failed to remove managedFields from item")
1245 | 	})
1246 | 
1247 | 	t.Run("single object with error during processing", func(t *testing.T) {
1248 | 		// Create a single object with invalid metadata
1249 | 		resp := &http.Response{
1250 | 			StatusCode: http.StatusOK,
1251 | 			Body: io.NopCloser(bytes.NewReader([]byte(`{
1252 | 				"apiVersion": "v1",
1253 | 				"kind": "Pod",
1254 | 				"metadata": "not-a-map"
1255 | 			}`))),
1256 | 		}
1257 | 
1258 | 		_, err := ProcessRawKubernetesAPIResponse(resp)
1259 | 		assert.Error(t, err)
1260 | 		assert.Contains(t, err.Error(), "failed to remove managedFields from single object")
1261 | 	})
1262 | 
1263 | 	t.Run("json marshal error for list", func(t *testing.T) {
1264 | 		// This is difficult to trigger in practice since json.Marshal is quite robust
1265 | 		// But we can test the structure
1266 | 		resp := &http.Response{
1267 | 			StatusCode: http.StatusOK,
1268 | 			Body: io.NopCloser(bytes.NewReader([]byte(`{
1269 | 				"apiVersion": "v1",
1270 | 				"kind": "PodList",
1271 | 				"items": [
1272 | 					{
1273 | 						"apiVersion": "v1",
1274 | 						"kind": "Pod",
1275 | 						"metadata": {
1276 | 							"name": "test-pod",
1277 | 							"managedFields": [{"manager": "kubectl"}]
1278 | 						}
1279 | 					}
1280 | 				]
1281 | 			}`))),
1282 | 		}
1283 | 
1284 | 		result, err := ProcessRawKubernetesAPIResponse(resp)
1285 | 		require.NoError(t, err)
1286 | 		assert.NotEmpty(t, result)
1287 | 	})
1288 | 
1289 | 	t.Run("json marshal error for single object", func(t *testing.T) {
1290 | 		// This is difficult to trigger in practice since json.Marshal is quite robust
1291 | 		// But we can test the structure
1292 | 		resp := &http.Response{
1293 | 			StatusCode: http.StatusOK,
1294 | 			Body: io.NopCloser(bytes.NewReader([]byte(`{
1295 | 				"apiVersion": "v1",
1296 | 				"kind": "Pod",
1297 | 				"metadata": {
1298 | 					"name": "test-pod",
1299 | 					"managedFields": [{"manager": "kubectl"}]
1300 | 				}
1301 | 			}`))),
1302 | 		}
1303 | 
1304 | 		result, err := ProcessRawKubernetesAPIResponse(resp)
1305 | 		require.NoError(t, err)
1306 | 		assert.NotEmpty(t, result)
1307 | 	})
1308 | }
1309 | 
1310 | // TestNilBodyWithContentLength tests the specific case where body is nil but content length is not zero
1311 | func TestNilBodyWithContentLength(t *testing.T) {
1312 | 	t.Run("nil body with positive content length", func(t *testing.T) {
1313 | 		resp := &http.Response{
1314 | 			StatusCode:    http.StatusOK,
1315 | 			Body:          nil,
1316 | 			ContentLength: 100,
1317 | 		}
1318 | 
1319 | 		_, err := ProcessRawKubernetesAPIResponse(resp)
1320 | 		assert.Error(t, err)
1321 | 		assert.Contains(t, err.Error(), "http response body is nil but content was expected")
1322 | 	})
1323 | 
1324 | 	t.Run("nil body with negative content length", func(t *testing.T) {
1325 | 		resp := &http.Response{
1326 | 			StatusCode:    http.StatusOK,
1327 | 			Body:          nil,
1328 | 			ContentLength: -1,
1329 | 		}
1330 | 
1331 | 		_, err := ProcessRawKubernetesAPIResponse(resp)
1332 | 		assert.Error(t, err)
1333 | 		assert.Contains(t, err.Error(), "http response body is nil but content was expected")
1334 | 	})
1335 | }
1336 | 
1337 | // TestUnmarshalErrorHandling tests the specific error handling for JSON unmarshaling
1338 | func TestUnmarshalErrorHandling(t *testing.T) {
1339 | 	t.Run("invalid JSON that is not empty object or array", func(t *testing.T) {
1340 | 		resp := &http.Response{
1341 | 			StatusCode: http.StatusOK,
1342 | 			Body:       io.NopCloser(bytes.NewReader([]byte("invalid json content"))),
1343 | 		}
1344 | 
1345 | 		_, err := ProcessRawKubernetesAPIResponse(resp)
1346 | 		assert.Error(t, err)
1347 | 		assert.Contains(t, err.Error(), "failed to unmarshal JSON into Unstructured")
1348 | 		assert.Contains(t, err.Error(), "Body: invalid json content")
1349 | 	})
1350 | 
1351 | 	t.Run("empty JSON object string", func(t *testing.T) {
1352 | 		resp := &http.Response{
1353 | 			StatusCode: http.StatusOK,
1354 | 			Body:       io.NopCloser(bytes.NewReader([]byte("{}"))),
1355 | 		}
1356 | 
1357 | 		result, err := ProcessRawKubernetesAPIResponse(resp)
1358 | 		require.NoError(t, err)
1359 | 		assert.Equal(t, "{}", string(result))
1360 | 	})
1361 | 
1362 | 	t.Run("empty JSON array string", func(t *testing.T) {
1363 | 		resp := &http.Response{
1364 | 			StatusCode: http.StatusOK,
1365 | 			Body:       io.NopCloser(bytes.NewReader([]byte("[]"))),
1366 | 		}
1367 | 
1368 | 		result, err := ProcessRawKubernetesAPIResponse(resp)
1369 | 		require.NoError(t, err)
1370 | 		assert.Equal(t, "[]", string(result))
1371 | 	})
1372 | }
1373 | 
```
Page 5/5FirstPrevNextLast