Skip to content

Commit 55ce148

Browse files
committed
Add first csv formatter test
1 parent 94d0063 commit 55ce148

File tree

3 files changed

+189
-2
lines changed

3 files changed

+189
-2
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,4 @@ dmypy.json
133133
.DS_Store
134134
robusta_lib
135135
.idea
136+
.vscode

robusta_krr/core/models/result.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ class Recommendation(pd.BaseModel):
1717

1818

1919
class ResourceRecommendation(pd.BaseModel):
20-
requests: dict[ResourceType, RecommendationValue]
21-
limits: dict[ResourceType, RecommendationValue]
20+
requests: dict[ResourceType, RecommendationValue | Recommendation]
21+
limits: dict[ResourceType, RecommendationValue | Recommendation]
2222
info: dict[ResourceType, Optional[str]]
2323

2424

@@ -40,6 +40,7 @@ def calculate(cls, object: K8sObjectData, recommendation: ResourceAllocations) -
4040

4141
current_severity = Severity.calculate(current, recommended, resource_type)
4242

43+
#TODO: consider... changing field after model created doesn't validate it.
4344
getattr(recommendation_processed, selector)[resource_type] = Recommendation(
4445
value=recommended, severity=current_severity
4546
)
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
import json
2+
from typing import Any
3+
from robusta_krr.core.models.result import Result
4+
from robusta_krr.formatters.csv import csv_exporter
5+
import io
6+
import csv
7+
8+
RESULT = """
9+
{
10+
"scans": [
11+
{
12+
"object": {
13+
"cluster": "mock-cluster",
14+
"name": "mock-object-1",
15+
"container": "mock-container-1",
16+
"pods": [
17+
{
18+
"name": "mock-pod-1",
19+
"deleted": false
20+
},
21+
{
22+
"name": "mock-pod-2",
23+
"deleted": false
24+
},
25+
{
26+
"name": "mock-pod-3",
27+
"deleted": true
28+
}
29+
],
30+
"hpa": null,
31+
"namespace": "default",
32+
"kind": "Deployment",
33+
"allocations": {
34+
"requests": {
35+
"cpu": 1.0,
36+
"memory": 1.0
37+
},
38+
"limits": {
39+
"cpu": 2.0,
40+
"memory": 2.0
41+
},
42+
"info": {}
43+
},
44+
"warnings": []
45+
},
46+
"recommended": {
47+
"requests": {
48+
"cpu": {
49+
"value": "?",
50+
"severity": "UNKNOWN"
51+
},
52+
"memory": {
53+
"value": "?",
54+
"severity": "UNKNOWN"
55+
}
56+
},
57+
"limits": {
58+
"cpu": {
59+
"value": "?",
60+
"severity": "UNKNOWN"
61+
},
62+
"memory": {
63+
"value": "?",
64+
"severity": "UNKNOWN"
65+
}
66+
},
67+
"info": {
68+
"cpu": "Not enough data",
69+
"memory": "Not enough data"
70+
}
71+
},
72+
"severity": "UNKNOWN"
73+
}
74+
],
75+
"score": 100,
76+
"resources": [
77+
"cpu",
78+
"memory"
79+
],
80+
"description": "tests data",
81+
"strategy": {
82+
"name": "simple",
83+
"settings": {
84+
"history_duration": 336.0,
85+
"timeframe_duration": 1.25,
86+
"cpu_percentile": 95.0,
87+
"memory_buffer_percentage": 15.0,
88+
"points_required": 100,
89+
"allow_hpa": false,
90+
"use_oomkill_data": false,
91+
"oom_memory_buffer_percentage": 25.0
92+
}
93+
},
94+
"errors": [],
95+
"clusterSummary": {},
96+
"config": {
97+
"quiet": false,
98+
"verbose": false,
99+
"clusters": [],
100+
"kubeconfig": null,
101+
"impersonate_user": null,
102+
"impersonate_group": null,
103+
"namespaces": "*",
104+
"resources": [],
105+
"selector": null,
106+
"cpu_min_value": 10,
107+
"memory_min_value": 100,
108+
"prometheus_url": null,
109+
"prometheus_auth_header": null,
110+
"prometheus_other_headers": {},
111+
"prometheus_ssl_enabled": false,
112+
"prometheus_cluster_label": null,
113+
"prometheus_label": null,
114+
"eks_managed_prom": false,
115+
"eks_managed_prom_profile_name": null,
116+
"eks_access_key": null,
117+
"eks_secret_key": null,
118+
"eks_service_name": "aps",
119+
"eks_managed_prom_region": null,
120+
"coralogix_token": null,
121+
"openshift": false,
122+
"max_workers": 10,
123+
"format": "csv",
124+
"show_cluster_name": false,
125+
"strategy": "simple",
126+
"log_to_stderr": false,
127+
"width": null,
128+
"file_output": null,
129+
"slack_output": null,
130+
"other_args": {
131+
"history_duration": "336",
132+
"timeframe_duration": "1.25",
133+
"cpu_percentile": "95",
134+
"memory_buffer_percentage": "15",
135+
"points_required": "100",
136+
"allow_hpa": false,
137+
"use_oomkill_data": false,
138+
"oom_memory_buffer_percentage": "25"
139+
},
140+
"inside_cluster": false,
141+
"file_output_dynamic": false,
142+
"bool": false
143+
}
144+
}
145+
"""
146+
147+
148+
def test_csv_headers() -> None:
149+
res_data = json.loads(RESULT)
150+
result = Result(**res_data)
151+
x = csv_exporter(result)
152+
reader = csv.DictReader(io.StringIO(x))
153+
154+
expected_headers: list[str] = [
155+
"Namespace",
156+
"Name",
157+
"Pods",
158+
"Old Pods",
159+
"Type",
160+
"Container",
161+
"CPU Diff",
162+
"CPU Requests",
163+
"CPU Limits",
164+
"Memory Diff",
165+
"Memory Requests",
166+
"Memory Limits",
167+
]
168+
assert reader.fieldnames == expected_headers
169+
170+
expected_first_row: dict[str, str] = {
171+
"Namespace": "default",
172+
"Name": "mock-object-1",
173+
"Pods": "2",
174+
"Old Pods": "1",
175+
"Type": "Deployment",
176+
"Container": "mock-container-1",
177+
"CPU Diff": "",
178+
"CPU Requests": "1.0 -> ?",
179+
"CPU Limits": "2.0 -> ?",
180+
"Memory Diff": "",
181+
"Memory Requests": "1.0 -> ?",
182+
"Memory Limits": "2.0 -> ?",
183+
}
184+
first_row: dict[str, Any] = next(reader)
185+
assert first_row == expected_first_row

0 commit comments

Comments
 (0)