github.com/chipaca/snappy@v0.0.0-20210104084008-1f06296fe8ad/daemon/api_debug_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2014-2019 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package daemon 21 22 import ( 23 "bytes" 24 "encoding/json" 25 "net/http" 26 27 "gopkg.in/check.v1" 28 29 "github.com/snapcore/snapd/overlord/state" 30 "github.com/snapcore/snapd/testutil" 31 "github.com/snapcore/snapd/timings" 32 ) 33 34 var _ = check.Suite(&postDebugSuite{}) 35 36 type postDebugSuite struct { 37 APIBaseSuite 38 } 39 40 func (s *postDebugSuite) TestPostDebugEnsureStateSoon(c *check.C) { 41 s.daemonWithOverlordMock(c) 42 43 soon := 0 44 ensureStateSoon = func(st *state.State) { 45 soon++ 46 ensureStateSoonImpl(st) 47 } 48 49 buf := bytes.NewBufferString(`{"action": "ensure-state-soon"}`) 50 req, err := http.NewRequest("POST", "/v2/debug", buf) 51 c.Assert(err, check.IsNil) 52 53 rsp := postDebug(debugCmd, req, nil).(*resp) 54 55 c.Check(rsp.Type, check.Equals, ResponseTypeSync) 56 c.Check(rsp.Result, check.Equals, true) 57 c.Check(soon, check.Equals, 1) 58 } 59 60 func (s *postDebugSuite) TestPostDebugGetBaseDeclaration(c *check.C) { 61 _ = s.daemon(c) 62 63 buf := bytes.NewBufferString(`{"action": "get-base-declaration"}`) 64 req, err := http.NewRequest("POST", "/v2/debug", buf) 65 c.Assert(err, check.IsNil) 66 67 rsp := postDebug(debugCmd, req, nil).(*resp) 68 69 c.Check(rsp.Type, check.Equals, ResponseTypeSync) 70 c.Check(rsp.Result.(map[string]interface{})["base-declaration"], 71 testutil.Contains, "type: base-declaration") 72 } 73 74 func (s *postDebugSuite) testDebugConnectivityHappy(c *check.C, post bool) { 75 _ = s.daemon(c) 76 77 s.connectivityResult = map[string]bool{ 78 "good.host.com": true, 79 "another.good.host.com": true, 80 } 81 82 var rsp *resp 83 if post { 84 buf := bytes.NewBufferString(`{"action": "connectivity"}`) 85 req, err := http.NewRequest("POST", "/v2/debug", buf) 86 c.Assert(err, check.IsNil) 87 88 rsp = postDebug(debugCmd, req, nil).(*resp) 89 } else { 90 req, err := http.NewRequest("POST", "/v2/debug?aspect=connectivity", nil) 91 c.Assert(err, check.IsNil) 92 rsp = getDebug(debugCmd, req, nil).(*resp) 93 94 } 95 96 c.Check(rsp.Type, check.Equals, ResponseTypeSync) 97 c.Check(rsp.Result, check.DeepEquals, ConnectivityStatus{ 98 Connectivity: true, 99 Unreachable: []string(nil), 100 }) 101 } 102 103 func (s *postDebugSuite) TestPostDebugConnectivityHappy(c *check.C) { 104 s.testDebugConnectivityHappy(c, true) 105 } 106 107 func (s *postDebugSuite) TestGetDebugConnectivityHappy(c *check.C) { 108 s.testDebugConnectivityHappy(c, false) 109 } 110 111 func (s *postDebugSuite) testDebugConnectivityUnhappy(c *check.C, post bool) { 112 _ = s.daemon(c) 113 114 s.connectivityResult = map[string]bool{ 115 "good.host.com": true, 116 "bad.host.com": false, 117 } 118 119 var rsp *resp 120 if post { 121 buf := bytes.NewBufferString(`{"action": "connectivity"}`) 122 req, err := http.NewRequest("POST", "/v2/debug", buf) 123 c.Assert(err, check.IsNil) 124 125 rsp = postDebug(debugCmd, req, nil).(*resp) 126 } else { 127 req, err := http.NewRequest("GET", "/v2/debug?aspect=connectivity", nil) 128 c.Assert(err, check.IsNil) 129 rsp = getDebug(debugCmd, req, nil).(*resp) 130 } 131 132 c.Check(rsp.Type, check.Equals, ResponseTypeSync) 133 c.Check(rsp.Result, check.DeepEquals, ConnectivityStatus{ 134 Connectivity: false, 135 Unreachable: []string{"bad.host.com"}, 136 }) 137 } 138 139 func (s *postDebugSuite) TestPostDebugConnectivityUnhappy(c *check.C) { 140 s.testDebugConnectivityUnhappy(c, true) 141 } 142 143 func (s *postDebugSuite) TestGetDebugConnectivityUnhappy(c *check.C) { 144 s.testDebugConnectivityUnhappy(c, false) 145 } 146 147 func (s *postDebugSuite) TestGetDebugBaseDeclaration(c *check.C) { 148 _ = s.daemon(c) 149 150 req, err := http.NewRequest("GET", "/v2/debug?aspect=base-declaration", nil) 151 c.Assert(err, check.IsNil) 152 153 rsp := getDebug(debugCmd, req, nil).(*resp) 154 155 c.Check(rsp.Type, check.Equals, ResponseTypeSync) 156 c.Check(rsp.Result.(map[string]interface{})["base-declaration"], 157 testutil.Contains, "type: base-declaration") 158 } 159 160 func mockDurationThreshold() func() { 161 oldDurationThreshold := timings.DurationThreshold 162 restore := func() { 163 timings.DurationThreshold = oldDurationThreshold 164 } 165 timings.DurationThreshold = 0 166 return restore 167 } 168 169 func (s *postDebugSuite) getDebugTimings(c *check.C, request string) []interface{} { 170 defer mockDurationThreshold()() 171 172 s.daemonWithOverlordMock(c) 173 174 req, err := http.NewRequest("GET", request, nil) 175 c.Assert(err, check.IsNil) 176 177 st := s.d.overlord.State() 178 st.Lock() 179 180 chg1 := st.NewChange("foo", "...") 181 task1 := st.NewTask("bar", "...") 182 chg1.AddTask(task1) 183 task1.SetStatus(state.DoingStatus) 184 185 chg2 := st.NewChange("foo", "...") 186 task2 := st.NewTask("bar", "...") 187 chg2.AddTask(task2) 188 189 chg3 := st.NewChange("foo", "...") 190 task3 := st.NewTask("bar", "...") 191 chg3.AddTask(task3) 192 193 tm1 := state.TimingsForTask(task3) 194 sp1 := tm1.StartSpan("span", "span...") 195 sp1.Stop() 196 tm1.Save(st) 197 198 tm2 := timings.New(map[string]string{"ensure": "foo", "change-id": chg1.ID()}) 199 sp2 := tm2.StartSpan("span", "span...") 200 sp2.Stop() 201 tm2.Save(st) 202 203 tm3 := timings.New(map[string]string{"ensure": "foo", "change-id": chg2.ID()}) 204 sp3 := tm3.StartSpan("span", "span...") 205 sp3.Stop() 206 tm3.Save(st) 207 208 tm4 := timings.New(map[string]string{"ensure": "bar", "change-id": chg3.ID()}) 209 sp4 := tm3.StartSpan("span", "span...") 210 sp4.Stop() 211 tm4.Save(st) 212 213 st.Unlock() 214 215 rsp := getDebug(debugCmd, req, nil).(*resp) 216 data, err := json.Marshal(rsp.Result) 217 c.Assert(err, check.IsNil) 218 var dataJSON []interface{} 219 json.Unmarshal(data, &dataJSON) 220 221 c.Assert(rsp.Type, check.Equals, ResponseTypeSync) 222 return dataJSON 223 } 224 225 func (s *postDebugSuite) TestGetDebugTimingsSingleChange(c *check.C) { 226 dataJSON := s.getDebugTimings(c, "/v2/debug?aspect=change-timings&change-id=1") 227 228 c.Check(dataJSON, check.HasLen, 1) 229 tmData := dataJSON[0].(map[string]interface{}) 230 c.Check(tmData["change-id"], check.DeepEquals, "1") 231 c.Check(tmData["change-timings"], check.NotNil) 232 } 233 234 func (s *postDebugSuite) TestGetDebugTimingsEnsureLatest(c *check.C) { 235 dataJSON := s.getDebugTimings(c, "/v2/debug?aspect=change-timings&ensure=foo&all=false") 236 c.Assert(dataJSON, check.HasLen, 1) 237 238 tmData := dataJSON[0].(map[string]interface{}) 239 c.Check(tmData["change-id"], check.DeepEquals, "2") 240 c.Check(tmData["change-timings"], check.NotNil) 241 c.Check(tmData["total-duration"], check.NotNil) 242 } 243 244 func (s *postDebugSuite) TestGetDebugTimingsEnsureAll(c *check.C) { 245 dataJSON := s.getDebugTimings(c, "/v2/debug?aspect=change-timings&ensure=foo&all=true") 246 247 c.Assert(dataJSON, check.HasLen, 2) 248 tmData := dataJSON[0].(map[string]interface{}) 249 c.Check(tmData["change-id"], check.DeepEquals, "1") 250 c.Check(tmData["change-timings"], check.NotNil) 251 c.Check(tmData["total-duration"], check.NotNil) 252 253 tmData = dataJSON[1].(map[string]interface{}) 254 c.Check(tmData["change-id"], check.DeepEquals, "2") 255 c.Check(tmData["change-timings"], check.NotNil) 256 c.Check(tmData["total-duration"], check.NotNil) 257 } 258 259 func (s *postDebugSuite) TestGetDebugTimingsError(c *check.C) { 260 s.daemonWithOverlordMock(c) 261 262 req, err := http.NewRequest("GET", "/v2/debug?aspect=change-timings&ensure=unknown", nil) 263 c.Assert(err, check.IsNil) 264 rsp := getDebug(debugCmd, req, nil).(*resp) 265 c.Check(rsp.Status, check.Equals, 400) 266 267 req, err = http.NewRequest("GET", "/v2/debug?aspect=change-timings&change-id=9999", nil) 268 c.Assert(err, check.IsNil) 269 rsp = getDebug(debugCmd, req, nil).(*resp) 270 c.Check(rsp.Status, check.Equals, 400) 271 } 272 273 func (s *postDebugSuite) TestMinLane(c *check.C) { 274 st := state.New(nil) 275 st.Lock() 276 defer st.Unlock() 277 278 t := st.NewTask("bar", "") 279 c.Check(MinLane(t), check.Equals, 0) 280 281 lane1 := st.NewLane() 282 t.JoinLane(lane1) 283 c.Check(MinLane(t), check.Equals, lane1) 284 285 lane2 := st.NewLane() 286 t.JoinLane(lane2) 287 c.Check(MinLane(t), check.Equals, lane1) 288 289 // sanity 290 c.Check(t.Lanes(), check.DeepEquals, []int{lane1, lane2}) 291 }