Skip to content

Commit 8ceded6

Browse files
committed
add tests for docker stats versioning
testing for moby#17549 Signed-off-by: Donald Huang <don.hcd@gmail.com>
1 parent d2c04f8 commit 8ceded6

File tree

1 file changed

+86
-0
lines changed

1 file changed

+86
-0
lines changed

integration-cli/docker_api_stats_test.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@ import (
1212

1313
"github.com/docker/docker/api/types"
1414
"github.com/docker/docker/pkg/integration/checker"
15+
"github.com/docker/docker/pkg/version"
1516
"github.com/go-check/check"
1617
)
1718

19+
var expectedNetworkInterfaceStats = strings.Split("rx_bytes rx_dropped rx_errors rx_packets tx_bytes tx_dropped tx_errors tx_packets", " ")
20+
1821
func (s *DockerSuite) TestApiStatsNoStreamGetCpu(c *check.C) {
1922
testRequires(c, DaemonIsLinux)
2023
out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "while true;do echo 'Hello'; usleep 100000; done")
@@ -122,6 +125,28 @@ func (s *DockerSuite) TestApiStatsNetworkStats(c *check.C) {
122125
check.Commentf("Reported less Txbytes than expected. Expected >= %d. Found %d. %s", expRxPkts, postRxPackets, pingouts))
123126
}
124127

128+
func (s *DockerSuite) TestApiStatsNetworkStatsVersioning(c *check.C) {
129+
testRequires(c, SameHostDaemon)
130+
testRequires(c, DaemonIsLinux)
131+
// Run container for 30 secs
132+
out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
133+
id := strings.TrimSpace(out)
134+
c.Assert(waitRun(id), checker.IsNil)
135+
136+
for i := 17; i <= 21; i++ {
137+
apiVersion := fmt.Sprintf("v1.%d", i)
138+
for _, statsJSONBlob := range getVersionedStats(c, id, 3, apiVersion) {
139+
if version.Version(apiVersion).LessThan("v1.21") {
140+
c.Assert(jsonBlobHasLTv121NetworkStats(statsJSONBlob), checker.Equals, true,
141+
check.Commentf("Stats JSON blob from API %s %#v does not look like a <v1.21 API stats structure", apiVersion, statsJSONBlob))
142+
} else {
143+
c.Assert(jsonBlobHasGTE121NetworkStats(statsJSONBlob), checker.Equals, true,
144+
check.Commentf("Stats JSON blob from API %s %#v does not look like a >=v1.21 API stats structure", apiVersion, statsJSONBlob))
145+
}
146+
}
147+
}
148+
}
149+
125150
func getNetworkStats(c *check.C, id string) map[string]types.NetworkStats {
126151
var st *types.StatsJSON
127152

@@ -135,6 +160,67 @@ func getNetworkStats(c *check.C, id string) map[string]types.NetworkStats {
135160
return st.Networks
136161
}
137162

163+
// getVersionedNetworkStats returns a slice of numStats stats results for the
164+
// container with id id using an API call with version apiVersion. Since the
165+
// stats result type differs between API versions, we simply return
166+
// []map[string]interface{}.
167+
func getVersionedStats(c *check.C, id string, numStats int, apiVersion string) []map[string]interface{} {
168+
stats := make([]map[string]interface{}, numStats)
169+
170+
requestPath := fmt.Sprintf("/%s/containers/%s/stats?stream=true", apiVersion, id)
171+
_, body, err := sockRequestRaw("GET", requestPath, nil, "")
172+
c.Assert(err, checker.IsNil)
173+
defer body.Close()
174+
175+
statsDecoder := json.NewDecoder(body)
176+
for i := range stats {
177+
err = statsDecoder.Decode(&stats[i])
178+
c.Assert(err, checker.IsNil, check.Commentf("failed to decode %dth stat: %s", i, err))
179+
}
180+
181+
return stats
182+
}
183+
184+
func jsonBlobHasLTv121NetworkStats(blob map[string]interface{}) bool {
185+
networkStatsIntfc, ok := blob["network"]
186+
if !ok {
187+
return false
188+
}
189+
networkStats, ok := networkStatsIntfc.(map[string]interface{})
190+
if !ok {
191+
return false
192+
}
193+
for _, expectedKey := range expectedNetworkInterfaceStats {
194+
if _, ok := networkStats[expectedKey]; !ok {
195+
return false
196+
}
197+
}
198+
return true
199+
}
200+
201+
func jsonBlobHasGTE121NetworkStats(blob map[string]interface{}) bool {
202+
networksStatsIntfc, ok := blob["networks"]
203+
if !ok {
204+
return false
205+
}
206+
networksStats, ok := networksStatsIntfc.(map[string]interface{})
207+
if !ok {
208+
return false
209+
}
210+
for _, networkInterfaceStatsIntfc := range networksStats {
211+
networkInterfaceStats, ok := networkInterfaceStatsIntfc.(map[string]interface{})
212+
if !ok {
213+
return false
214+
}
215+
for _, expectedKey := range expectedNetworkInterfaceStats {
216+
if _, ok := networkInterfaceStats[expectedKey]; !ok {
217+
return false
218+
}
219+
}
220+
}
221+
return true
222+
}
223+
138224
func (s *DockerSuite) TestApiStatsContainerNotFound(c *check.C) {
139225
testRequires(c, DaemonIsLinux)
140226

0 commit comments

Comments
 (0)