Skip to content

Commit 4a217ac

Browse files
committed
Ensure roundtrip success for Quantities
1 parent b0b6cf8 commit 4a217ac

File tree

2 files changed

+89
-2
lines changed

2 files changed

+89
-2
lines changed

pkg/resources/requests.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,15 +108,27 @@ func ResourceQuantity(name corev1.ResourceName, v int64) resource.Quantity {
108108
case corev1.ResourceCPU:
109109
return *resource.NewMilliQuantity(v, resource.DecimalSI)
110110
case corev1.ResourceMemory, corev1.ResourceEphemeralStorage:
111-
return *resource.NewQuantity(v, resource.BinarySI)
111+
return parseMaybeBinary(v)
112112
default:
113113
if strings.HasPrefix(string(name), corev1.ResourceHugePagesPrefix) {
114-
return *resource.NewQuantity(v, resource.BinarySI)
114+
return parseMaybeBinary(v)
115115
}
116116
return *resource.NewQuantity(v, resource.DecimalSI)
117117
}
118118
}
119119

120+
// Ensures that the resulting Quantity roundtrips.
121+
// For example, 1000000 will be decimal (1M), while 1048576 will be binary (1Mi)
122+
func parseMaybeBinary(v int64) resource.Quantity {
123+
binary := *resource.NewQuantity(v, resource.BinarySI)
124+
final, err := resource.ParseQuantity(binary.String())
125+
if err != nil {
126+
// Should never happen
127+
return binary
128+
}
129+
return final
130+
}
131+
120132
func ResourceQuantityString(name corev1.ResourceName, v int64) string {
121133
rq := ResourceQuantity(name, v)
122134
return rq.String()

pkg/resources/requests_test.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@ limitations under the License.
1717
package resources
1818

1919
import (
20+
"encoding/json"
2021
"math"
2122
"testing"
2223

2324
corev1 "k8s.io/api/core/v1"
25+
"k8s.io/apimachinery/pkg/api/resource"
2426
)
2527

2628
func TestCountIn(t *testing.T) {
@@ -121,3 +123,76 @@ func TestCountIn(t *testing.T) {
121123
})
122124
}
123125
}
126+
127+
func TestResourceQuantityRoundTrips(t *testing.T) {
128+
cases := map[string]struct {
129+
resource corev1.ResourceName
130+
value int64
131+
expected string
132+
}{
133+
"1": {
134+
resource: corev1.ResourceMemory,
135+
value: 1,
136+
expected: "1",
137+
},
138+
"1k": {
139+
resource: corev1.ResourceMemory,
140+
value: 1000,
141+
expected: "1k",
142+
},
143+
"1M": {
144+
resource: corev1.ResourceMemory,
145+
value: 1000000,
146+
expected: "1M",
147+
},
148+
"1.5M": {
149+
resource: corev1.ResourceMemory,
150+
value: 1500000,
151+
expected: "1500k",
152+
},
153+
"1G": {
154+
resource: corev1.ResourceMemory,
155+
value: 1000000000,
156+
expected: "1G",
157+
},
158+
"1Ki": {
159+
resource: corev1.ResourceMemory,
160+
value: 1024,
161+
expected: "1Ki",
162+
},
163+
"1Mi": {
164+
resource: corev1.ResourceMemory,
165+
value: 1024 * 1024,
166+
expected: "1Mi",
167+
},
168+
"1.5Mi": {
169+
resource: corev1.ResourceMemory,
170+
value: 1024 * 1024 * 1.5,
171+
expected: "1536Ki",
172+
},
173+
"1Gi": {
174+
resource: corev1.ResourceMemory,
175+
value: 1024 * 1024 * 1024,
176+
expected: "1Gi",
177+
},
178+
}
179+
for name, tc := range cases {
180+
t.Run(name, func(t *testing.T) {
181+
quantity := ResourceQuantity(tc.resource, tc.value)
182+
initial := quantity.String()
183+
184+
if initial != tc.expected {
185+
t.Errorf("unexpected result, want=%s, got=%s", tc.expected, initial)
186+
}
187+
188+
serialized, _ := json.Marshal(quantity)
189+
var deserialized resource.Quantity
190+
_ = json.Unmarshal(serialized, &deserialized)
191+
roundtrip := deserialized.String()
192+
193+
if roundtrip != tc.expected {
194+
t.Errorf("unexpected result after roundtrip, want=%s, got=%s", tc.expected, roundtrip)
195+
}
196+
})
197+
}
198+
}

0 commit comments

Comments
 (0)