66 "github.com/infracost/go-proto/pkg/tree/kubernetes"
77 "github.com/infracost/go-proto/pkg/tree/kubernetes/apps"
88 "github.com/infracost/go-proto/pkg/tree/kubernetes/batch"
9+ "github.com/infracost/go-proto/pkg/tree/kubernetes/core"
910 "github.com/infracost/go-proto/pkg/tree/kubernetes/workload"
1011 "github.com/infracost/go-proto/pkg/tree/resource"
1112 "github.com/infracost/go-proto/pkg/tree/value"
@@ -57,6 +58,18 @@ func TestKubernetesRoundTrip(t *testing.T) {
5758 },
5859 },
5960 },
61+ StatefulSets : []apps.StatefulSet {
62+ {
63+ Workload : workload.Workload {Resource : resource.Resource {ID : "db" }},
64+ Replicas : value .New [int64 ](3 , 0 , "" , nil ),
65+ VolumeClaimTemplates : []core.StorageRequest {
66+ {
67+ StorageClassName : value .New ("gp3" , 0 , "" , nil ),
68+ RequestBytes : value .New [int64 ](10737418240 , 0 , "" , nil ),
69+ },
70+ },
71+ },
72+ },
6073 },
6174 Batch : batch.Batch {
6275 CronJobs : []batch.CronJob {
@@ -70,12 +83,52 @@ func TestKubernetesRoundTrip(t *testing.T) {
7083 },
7184 },
7285 },
86+ Core : core.Core {
87+ PersistentVolumeClaims : []core.PersistentVolumeClaim {
88+ {
89+ Resource : resource.Resource {
90+ ID : "data" ,
91+ Tags : resource.Tags {
92+ {Key : value .New ("app" , 0 , "" , nil ), Value : value .New ("api" , 0 , "" , nil )},
93+ },
94+ },
95+ StorageRequest : core.StorageRequest {
96+ StorageClassName : value .New ("io2" , 0 , "" , nil ),
97+ RequestBytes : value .New [int64 ](21474836480 , 0 , "" , nil ),
98+ },
99+ Annotations : []resource.Tag {
100+ {
101+ Key : value .New ("volume.beta.kubernetes.io/storage-provisioner" , 0 , "" , nil ),
102+ Value : value .New ("ebs.csi.aws.com" , 0 , "" , nil ),
103+ },
104+ },
105+ },
106+ },
107+ Services : []core.Service {
108+ {
109+ Resource : resource.Resource {ID : "api-lb" },
110+ Type : value .New ("LoadBalancer" , 0 , "" , nil ),
111+ Annotations : []resource.Tag {
112+ {
113+ Key : value .New ("service.beta.kubernetes.io/aws-load-balancer-type" , 0 , "" , nil ),
114+ Value : value .New ("nlb" , 0 , "" , nil ),
115+ },
116+ },
117+ Ports : []core.ServicePort {
118+ {Port : value .New [int64 ](443 , 0 , "" , nil ), Protocol : value .New ("TCP" , 0 , "" , nil )},
119+ },
120+ },
121+ },
122+ },
73123 },
74124 }
75125
76126 origDep := original .Kubernetes .Apps .Deployments [0 ]
77127 origDaemon := original .Kubernetes .Apps .DaemonSets [0 ]
128+ origSts := original .Kubernetes .Apps .StatefulSets [0 ]
78129 origCron := original .Kubernetes .Batch .CronJobs [0 ]
130+ origPVC := original .Kubernetes .Core .PersistentVolumeClaims [0 ]
131+ origSvc := original .Kubernetes .Core .Services [0 ]
79132
80133 proto , err := original .ToProto ()
81134 require .NoError (t , err )
@@ -87,6 +140,12 @@ func TestKubernetesRoundTrip(t *testing.T) {
87140 require .NotNil (t , depAttrs ["containers" ], "embedded base fields must be flattened" )
88141 require .NotNil (t , depAttrs ["annotations" ], "embedded base fields must be flattened" )
89142
143+ // The PersistentVolumeClaim embeds StorageRequest, so its storage fields are
144+ // flattened to the claim's top level rather than nested under an embed key.
145+ pvcAttrs := proto .Providers ["kubernetes" ].Services ["core" ].Resources [0 ].Attributes .Entries
146+ assert .Equal (t , origPVC .StorageClassName .Value (), pvcAttrs ["storage_class_name" ].GetStringValue ())
147+ assert .Equal (t , origPVC .RequestBytes .Value (), pvcAttrs ["request_bytes" ].GetIntValue ())
148+
90149 result , err := FromProto (proto )
91150 require .NoError (t , err )
92151
@@ -111,6 +170,37 @@ func TestKubernetesRoundTrip(t *testing.T) {
111170 require .Len (t , daemon .Containers , len (origDaemon .Containers ))
112171 assert .Equal (t , origDaemon .Containers [0 ].Name .Value (), daemon .Containers [0 ].Name .Value ())
113172
173+ // StatefulSet volumeClaimTemplates: a slice of nested StorageRequest structs.
174+ require .Len (t , result .Kubernetes .Apps .StatefulSets , 1 )
175+ sts := result .Kubernetes .Apps .StatefulSets [0 ]
176+ assert .Equal (t , origSts .ID , sts .ID )
177+ assert .Equal (t , origSts .Replicas .Value (), sts .Replicas .Value ())
178+ require .Len (t , sts .VolumeClaimTemplates , len (origSts .VolumeClaimTemplates ))
179+ assert .Equal (t , origSts .VolumeClaimTemplates [0 ].StorageClassName .Value (), sts .VolumeClaimTemplates [0 ].StorageClassName .Value ())
180+ assert .Equal (t , origSts .VolumeClaimTemplates [0 ].RequestBytes .Value (), sts .VolumeClaimTemplates [0 ].RequestBytes .Value ())
181+
182+ // core group: PersistentVolumeClaim (embedded StorageRequest) and Service.
183+ require .Len (t , result .Kubernetes .Core .PersistentVolumeClaims , 1 )
184+ pvc := result .Kubernetes .Core .PersistentVolumeClaims [0 ]
185+ assert .Equal (t , origPVC .ID , pvc .ID )
186+ assert .Equal (t , origPVC .StorageClassName .Value (), pvc .StorageClassName .Value ())
187+ assert .Equal (t , origPVC .RequestBytes .Value (), pvc .RequestBytes .Value ())
188+ require .Len (t , pvc .Tags , len (origPVC .Tags ))
189+ assert .Equal (t , origPVC .Tags [0 ].Key .Value (), pvc .Tags [0 ].Key .Value ())
190+ require .Len (t , pvc .Annotations , len (origPVC .Annotations ))
191+ assert .Equal (t , origPVC .Annotations [0 ].Key .Value (), pvc .Annotations [0 ].Key .Value ())
192+ assert .Equal (t , origPVC .Annotations [0 ].Value .Value (), pvc .Annotations [0 ].Value .Value ())
193+
194+ require .Len (t , result .Kubernetes .Core .Services , 1 )
195+ svc := result .Kubernetes .Core .Services [0 ]
196+ assert .Equal (t , origSvc .ID , svc .ID )
197+ assert .Equal (t , origSvc .Type .Value (), svc .Type .Value ())
198+ require .Len (t , svc .Annotations , len (origSvc .Annotations ))
199+ assert .Equal (t , origSvc .Annotations [0 ].Key .Value (), svc .Annotations [0 ].Key .Value ())
200+ require .Len (t , svc .Ports , len (origSvc .Ports ))
201+ assert .Equal (t , origSvc .Ports [0 ].Port .Value (), svc .Ports [0 ].Port .Value ())
202+ assert .Equal (t , origSvc .Ports [0 ].Protocol .Value (), svc .Ports [0 ].Protocol .Value ())
203+
114204 // Multi-level embedding: CronJob -> Job -> Workload all flatten together.
115205 require .Len (t , result .Kubernetes .Batch .CronJobs , 1 )
116206 cj := result .Kubernetes .Batch .CronJobs [0 ]
0 commit comments