Browse code

add tests for docker stats versioning

testing for #17549

Signed-off-by: Donald Huang <don.hcd@gmail.com>

Donald Huang authored on 2015/10/31 08:32:09
Showing 1 changed files
... ...
@@ -12,9 +12,12 @@ import (
12 12
 
13 13
 	"github.com/docker/docker/api/types"
14 14
 	"github.com/docker/docker/pkg/integration/checker"
15
+	"github.com/docker/docker/pkg/version"
15 16
 	"github.com/go-check/check"
16 17
 )
17 18
 
19
+var expectedNetworkInterfaceStats = strings.Split("rx_bytes rx_dropped rx_errors rx_packets tx_bytes tx_dropped tx_errors tx_packets", " ")
20
+
18 21
 func (s *DockerSuite) TestApiStatsNoStreamGetCpu(c *check.C) {
19 22
 	testRequires(c, DaemonIsLinux)
20 23
 	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) {
122 122
 		check.Commentf("Reported less Txbytes than expected. Expected >= %d. Found %d. %s", expRxPkts, postRxPackets, pingouts))
123 123
 }
124 124
 
125
+func (s *DockerSuite) TestApiStatsNetworkStatsVersioning(c *check.C) {
126
+	testRequires(c, SameHostDaemon)
127
+	testRequires(c, DaemonIsLinux)
128
+	// Run container for 30 secs
129
+	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
130
+	id := strings.TrimSpace(out)
131
+	c.Assert(waitRun(id), checker.IsNil)
132
+
133
+	for i := 17; i <= 21; i++ {
134
+		apiVersion := fmt.Sprintf("v1.%d", i)
135
+		for _, statsJSONBlob := range getVersionedStats(c, id, 3, apiVersion) {
136
+			if version.Version(apiVersion).LessThan("v1.21") {
137
+				c.Assert(jsonBlobHasLTv121NetworkStats(statsJSONBlob), checker.Equals, true,
138
+					check.Commentf("Stats JSON blob from API %s %#v does not look like a <v1.21 API stats structure", apiVersion, statsJSONBlob))
139
+			} else {
140
+				c.Assert(jsonBlobHasGTE121NetworkStats(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
+			}
143
+		}
144
+	}
145
+}
146
+
125 147
 func getNetworkStats(c *check.C, id string) map[string]types.NetworkStats {
126 148
 	var st *types.StatsJSON
127 149
 
... ...
@@ -135,6 +160,67 @@ func getNetworkStats(c *check.C, id string) map[string]types.NetworkStats {
135 135
 	return st.Networks
136 136
 }
137 137
 
138
+// getVersionedNetworkStats returns a slice of numStats stats results for the
139
+// container with id id using an API call with version apiVersion. Since the
140
+// stats result type differs between API versions, we simply return
141
+// []map[string]interface{}.
142
+func getVersionedStats(c *check.C, id string, numStats int, apiVersion string) []map[string]interface{} {
143
+	stats := make([]map[string]interface{}, numStats)
144
+
145
+	requestPath := fmt.Sprintf("/%s/containers/%s/stats?stream=true", apiVersion, id)
146
+	_, body, err := sockRequestRaw("GET", requestPath, nil, "")
147
+	c.Assert(err, checker.IsNil)
148
+	defer body.Close()
149
+
150
+	statsDecoder := json.NewDecoder(body)
151
+	for i := range stats {
152
+		err = statsDecoder.Decode(&stats[i])
153
+		c.Assert(err, checker.IsNil, check.Commentf("failed to decode %dth stat: %s", i, err))
154
+	}
155
+
156
+	return stats
157
+}
158
+
159
+func jsonBlobHasLTv121NetworkStats(blob map[string]interface{}) bool {
160
+	networkStatsIntfc, ok := blob["network"]
161
+	if !ok {
162
+		return false
163
+	}
164
+	networkStats, ok := networkStatsIntfc.(map[string]interface{})
165
+	if !ok {
166
+		return false
167
+	}
168
+	for _, expectedKey := range expectedNetworkInterfaceStats {
169
+		if _, ok := networkStats[expectedKey]; !ok {
170
+			return false
171
+		}
172
+	}
173
+	return true
174
+}
175
+
176
+func jsonBlobHasGTE121NetworkStats(blob map[string]interface{}) bool {
177
+	networksStatsIntfc, ok := blob["networks"]
178
+	if !ok {
179
+		return false
180
+	}
181
+	networksStats, ok := networksStatsIntfc.(map[string]interface{})
182
+	if !ok {
183
+		return false
184
+	}
185
+	for _, networkInterfaceStatsIntfc := range networksStats {
186
+		networkInterfaceStats, ok := networkInterfaceStatsIntfc.(map[string]interface{})
187
+		if !ok {
188
+			return false
189
+		}
190
+		for _, expectedKey := range expectedNetworkInterfaceStats {
191
+			if _, ok := networkInterfaceStats[expectedKey]; !ok {
192
+				return false
193
+			}
194
+		}
195
+	}
196
+	return true
197
+}
198
+
138 199
 func (s *DockerSuite) TestApiStatsContainerNotFound(c *check.C) {
139 200
 	testRequires(c, DaemonIsLinux)
140 201