@@ -21,6 +21,39 @@ import (
2121 "github.com/runfinch/finch-daemon/e2e/client"
2222)
2323
24+ // waitForContainerRunning waits for a container to reach the running state.
25+ func waitForContainerRunning (uClient * http.Client , version string , containerID string , maxRetries int ) bool {
26+ const retryInterval = 500 * time .Millisecond
27+
28+ for i := 0 ; i < maxRetries ; i ++ {
29+ res , err := uClient .Get (client .ConvertToFinchUrl (version , fmt .Sprintf ("/containers/%s/json" , containerID )))
30+ if err != nil {
31+ time .Sleep (retryInterval )
32+ continue
33+ }
34+
35+ if res .StatusCode != http .StatusOK {
36+ time .Sleep (retryInterval )
37+ continue
38+ }
39+
40+ var container types.Container
41+ err = json .NewDecoder (res .Body ).Decode (& container )
42+ res .Body .Close ()
43+ if err != nil {
44+ time .Sleep (retryInterval )
45+ continue
46+ }
47+
48+ if container .State .Status == "running" {
49+ return true
50+ }
51+
52+ time .Sleep (retryInterval )
53+ }
54+ return false
55+ }
56+
2457// ContainerStats tests the `GET containers/{id}/stats` API.
2558func ContainerStats (opt * option.Option ) {
2659 Describe ("get container stats" , func () {
@@ -30,9 +63,7 @@ func ContainerStats(opt *option.Option) {
3063 wantContainerName string
3164 )
3265 BeforeEach (func () {
33- // create a custom client to use http over unix sockets
3466 uClient = client .NewClient (GetDockerHostUrl ())
35- // get the docker api version that will be tested
3667 version = GetDockerApiVersion ()
3768 wantContainerName = fmt .Sprintf ("/%s" , testContainerName )
3869 })
@@ -55,13 +86,14 @@ func ContainerStats(opt *option.Option) {
5586 opt , "run" , "-d" , "--name" , testContainerName , defaultImage , "sleep" , "Infinity" ,
5687 )
5788
58- // get container stats
89+ isRunning := waitForContainerRunning (uClient , version , cid , 10 )
90+ Expect (isRunning ).Should (BeTrue (), "Container should be in running state before checking stats" )
91+
5992 relativeUrl := fmt .Sprintf ("/containers/%s/stats?stream=false" , testContainerName )
6093 res , err := uClient .Get (client .ConvertToFinchUrl (version , relativeUrl ))
6194 Expect (err ).Should (BeNil ())
6295 Expect (res .StatusCode ).Should (Equal (http .StatusOK ))
6396
64- // check json contents
6597 var statsJSON types.StatsJSON
6698 err = json .NewDecoder (res .Body ).Decode (& statsJSON )
6799 Expect (err ).Should (BeNil ())
@@ -72,13 +104,14 @@ func ContainerStats(opt *option.Option) {
72104 opt , "run" , "-d" , "--name" , testContainerName , defaultImage , "sleep" , "Infinity" ,
73105 )
74106
75- // get container stats
107+ isRunning := waitForContainerRunning (uClient , version , cid , 10 )
108+ Expect (isRunning ).Should (BeTrue (), "Container should be in running state before checking stats" )
109+
76110 relativeUrl := fmt .Sprintf ("/containers/%s/stats?stream=false" , cid )
77111 res , err := uClient .Get (client .ConvertToFinchUrl (version , relativeUrl ))
78112 Expect (err ).Should (BeNil ())
79113 Expect (res .StatusCode ).Should (Equal (http .StatusOK ))
80114
81- // check json contents
82115 var statsJSON types.StatsJSON
83116 err = json .NewDecoder (res .Body ).Decode (& statsJSON )
84117 Expect (err ).Should (BeNil ())
@@ -89,13 +122,14 @@ func ContainerStats(opt *option.Option) {
89122 opt , "run" , "-d" , "--name" , testContainerName , defaultImage , "sleep" , "Infinity" ,
90123 )
91124
92- // get container stats
125+ isRunning := waitForContainerRunning (uClient , version , cid , 10 )
126+ Expect (isRunning ).Should (BeTrue (), "Container should be in running state before checking stats" )
127+
93128 relativeUrl := fmt .Sprintf ("/containers/%s/stats?stream=false" , cid [:12 ])
94129 res , err := uClient .Get (client .ConvertToFinchUrl (version , relativeUrl ))
95130 Expect (err ).Should (BeNil ())
96131 Expect (res .StatusCode ).Should (Equal (http .StatusOK ))
97132
98- // check json contents
99133 var statsJSON types.StatsJSON
100134 err = json .NewDecoder (res .Body ).Decode (& statsJSON )
101135 Expect (err ).Should (BeNil ())
@@ -106,51 +140,62 @@ func ContainerStats(opt *option.Option) {
106140 opt , "run" , "-d" , "--name" , testContainerName , defaultImage , "sleep" , "Infinity" ,
107141 )
108142
109- // start a routine to remove the container in 3 seconds
143+ isRunning := waitForContainerRunning (uClient , version , cid , 10 )
144+ Expect (isRunning ).Should (BeTrue (), "Container should be in running state before checking stats" )
145+
110146 go func () {
111- time .Sleep (time .Second * 3 )
147+ time .Sleep (time .Second * 5 )
112148 command .Run (opt , "rm" , "-f" , testContainerName )
113149 }()
114150
115- // get container stats
116151 relativeUrl := fmt .Sprintf ("/containers/%s/stats" , testContainerName )
117152 res , err := uClient .Get (client .ConvertToFinchUrl (version , relativeUrl ))
118153 Expect (err ).Should (BeNil ())
119154 Expect (res .StatusCode ).Should (Equal (http .StatusOK ))
120155
121- // check json contents
122156 scanner := bufio .NewScanner (res .Body )
123157 num := 0
124158 for scanner .Scan () {
125159 var statsJSON types.StatsJSON
126160 err = json .Unmarshal (scanner .Bytes (), & statsJSON )
127161 Expect (err ).Should (BeNil ())
162+ isRunning := waitForContainerRunning (uClient , version , cid , 1 )
163+ // confirm need to check the stats were obtained for container running state
164+ if ! isRunning {
165+ break
166+ }
128167 expectValidStats (& statsJSON , wantContainerName , cid , 1 )
129168 num += 1
130169 }
131- // should tick at least twice in 3 seconds
170+
132171 Expect (num ).Should (BeNumerically (">" , 1 ))
133- Expect (num ).Should (BeNumerically ("<" , 5 ))
172+ Expect (num ).Should (BeNumerically ("<" , 10 ))
134173 })
135174 It ("should stream stats for a stopped container" , func () {
136175 cid := command .StdoutStr (
137176 opt , "run" , "-d" , "--name" , testContainerName , defaultImage , "echo" , "hello" ,
138177 )
139178 command .Run (opt , "wait" , testContainerName )
140179
141- // start a routine to remove the container in 3 seconds
180+ res , err := uClient .Get (client .ConvertToFinchUrl (version , fmt .Sprintf ("/containers/%s/json" , cid )))
181+ Expect (err ).Should (BeNil ())
182+ Expect (res .StatusCode ).Should (Equal (http .StatusOK ))
183+ var container types.Container
184+ err = json .NewDecoder (res .Body ).Decode (& container )
185+ res .Body .Close ()
186+ Expect (err ).Should (BeNil ())
187+ Expect (container .State .Status ).ShouldNot (Equal ("running" ))
188+
142189 go func () {
143- time .Sleep (time .Second * 3 )
190+ time .Sleep (time .Second * 5 )
144191 command .Run (opt , "rm" , "-f" , testContainerName )
145192 }()
146193
147- // get container stats
148194 relativeUrl := fmt .Sprintf ("/containers/%s/stats" , testContainerName )
149- res , err : = uClient .Get (client .ConvertToFinchUrl (version , relativeUrl ))
195+ res , err = uClient .Get (client .ConvertToFinchUrl (version , relativeUrl ))
150196 Expect (err ).Should (BeNil ())
151197 Expect (res .StatusCode ).Should (Equal (http .StatusOK ))
152198
153- // check json contents
154199 scanner := bufio .NewScanner (res .Body )
155200 num := 0
156201 for scanner .Scan () {
@@ -160,9 +205,9 @@ func ContainerStats(opt *option.Option) {
160205 expectEmptyStats (& statsJSON , wantContainerName , cid )
161206 num += 1
162207 }
163- // should tick at least twice in 3 seconds
208+
164209 Expect (num ).Should (BeNumerically (">" , 1 ))
165- Expect (num ).Should (BeNumerically ("<" , 5 ))
210+ Expect (num ).Should (BeNumerically ("<" , 10 ))
166211 })
167212 It ("should stream stats when no network interface is created" , func () {
168213 cid := command .StdoutStr (
@@ -175,34 +220,38 @@ func ContainerStats(opt *option.Option) {
175220 "sleep" , "Infinity" ,
176221 )
177222
178- // start a routine to remove the container in 3 seconds
223+ isRunning := waitForContainerRunning (uClient , version , cid , 10 )
224+ Expect (isRunning ).Should (BeTrue (), "Container should be in running state before checking stats" )
225+
179226 go func () {
180- time .Sleep (time .Second * 3 )
227+ time .Sleep (time .Second * 5 )
181228 command .Run (opt , "rm" , "-f" , testContainerName )
182229 }()
183230
184- // get container stats
185231 relativeUrl := fmt .Sprintf ("/containers/%s/stats" , testContainerName )
186232 res , err := uClient .Get (client .ConvertToFinchUrl (version , relativeUrl ))
187233 Expect (err ).Should (BeNil ())
188234 Expect (res .StatusCode ).Should (Equal (http .StatusOK ))
189235
190- // check json contents
191236 scanner := bufio .NewScanner (res .Body )
192237 num := 0
193238 for scanner .Scan () {
194239 var statsJSON types.StatsJSON
195240 err = json .Unmarshal (scanner .Bytes (), & statsJSON )
196241 Expect (err ).Should (BeNil ())
242+ isRunning := waitForContainerRunning (uClient , version , cid , 1 )
243+ // confirm need to check the stats were obtained for container running state
244+ if ! isRunning {
245+ break
246+ }
197247 expectValidStats (& statsJSON , wantContainerName , cid , 0 )
198248 num += 1
199249 }
200- // should tick at least twice in 3 seconds
250+
201251 Expect (num ).Should (BeNumerically (">" , 1 ))
202- Expect (num ).Should (BeNumerically ("<" , 5 ))
252+ Expect (num ).Should (BeNumerically ("<" , 10 ))
203253 })
204254 It ("should stream stats with multiple network interfaces" , func () {
205- // create networks and run a container with multiple networks
206255 command .Run (opt , "network" , "create" , "net1" )
207256 command .Run (opt , "network" , "create" , "net2" )
208257 cid := command .StdoutStr (
@@ -216,31 +265,36 @@ func ContainerStats(opt *option.Option) {
216265 "sleep" , "Infinity" ,
217266 )
218267
219- // start a routine to remove the container in 3 seconds
268+ isRunning := waitForContainerRunning (uClient , version , cid , 10 )
269+ Expect (isRunning ).Should (BeTrue (), "Container should be in running state before checking stats" )
270+
220271 go func () {
221- time .Sleep (time .Second * 3 )
272+ time .Sleep (time .Second * 5 )
222273 command .Run (opt , "rm" , "-f" , testContainerName )
223274 }()
224275
225- // get container stats
226276 relativeUrl := fmt .Sprintf ("/containers/%s/stats" , testContainerName )
227277 res , err := uClient .Get (client .ConvertToFinchUrl (version , relativeUrl ))
228278 Expect (err ).Should (BeNil ())
229279 Expect (res .StatusCode ).Should (Equal (http .StatusOK ))
230280
231- // check json contents
232281 scanner := bufio .NewScanner (res .Body )
233282 num := 0
234283 for scanner .Scan () {
235284 var statsJSON types.StatsJSON
236285 err = json .Unmarshal (scanner .Bytes (), & statsJSON )
237286 Expect (err ).Should (BeNil ())
287+ isRunning := waitForContainerRunning (uClient , version , cid , 1 )
288+ // confirm need to check the stats were obtained for container running state
289+ if ! isRunning {
290+ break
291+ }
238292 expectValidStats (& statsJSON , wantContainerName , cid , 2 )
239293 num += 1
240294 }
241- // should tick at least twice in 3 seconds
295+
242296 Expect (num ).Should (BeNumerically (">" , 1 ))
243- Expect (num ).Should (BeNumerically ("<" , 5 ))
297+ Expect (num ).Should (BeNumerically ("<" , 10 ))
244298 })
245299 })
246300}
@@ -258,14 +312,10 @@ func expectValidStats(st *types.StatsJSON, name, id string, numNetworks int) {
258312 Expect (st .Read ).Should (BeTemporally ("~" , st .PreRead .Add (time .Second ), time .Millisecond * 100 ))
259313 }
260314
261- // check that number of current PIDs is > 0
262315 Expect (st .PidsStats .Current ).ShouldNot (BeZero ())
263-
264- // check that number of CPUs and system usage is > 0
265316 Expect (st .CPUStats .OnlineCPUs ).ShouldNot (BeZero ())
266317 Expect (st .CPUStats .SystemUsage ).ShouldNot (BeZero ())
267318
268- // check that object contains networks data
269319 if numNetworks == 0 {
270320 Expect (st .Networks ).Should (BeNil ())
271321 } else {
@@ -277,10 +327,8 @@ func expectValidStats(st *types.StatsJSON, name, id string, numNetworks int) {
277327// expectEmptyStats ensures that the data contained in the stats object is empty
278328// which is the case with containers that are not running.
279329func expectEmptyStats (st * types.StatsJSON , name , id string ) {
280- // verify container name and ID
281330 Expect (st .Name ).Should (Equal (name ))
282331 Expect (st .ID ).Should (Equal (id ))
283-
284332 Expect (st .Read ).Should (Equal (time.Time {}))
285333 Expect (st .PreRead ).Should (Equal (time.Time {}))
286334 Expect (st .PidsStats ).Should (Equal (dockertypes.PidsStats {}))
0 commit comments