github.com/bugraaydogar/snapd@v0.0.0-20210315170335-8c70bb858939/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_test 21 22 import ( 23 "bytes" 24 "encoding/json" 25 "net/http" 26 27 "gopkg.in/check.v1" 28 29 "github.com/snapcore/snapd/daemon" 30 "github.com/snapcore/snapd/overlord/state" 31 "github.com/snapcore/snapd/testutil" 32 "github.com/snapcore/snapd/timings" 33 ) 34 35 var _ = check.Suite(&postDebugSuite{}) 36 37 type postDebugSuite struct { 38 apiBaseSuite 39 } 40 41 func (s *postDebugSuite) TestPostDebugEnsureStateSoon(c *check.C) { 42 s.daemonWithOverlordMock(c) 43 44 soon := 0 45 var origEnsureStateSoon func(*state.State) 46 origEnsureStateSoon, restore := daemon.MockEnsureStateSoon(func(st *state.State) { 47 soon++ 48 origEnsureStateSoon(st) 49 }) 50 defer restore() 51 52 buf := bytes.NewBufferString(`{"action": "ensure-state-soon"}`) 53 req, err := http.NewRequest("POST", "/v2/debug", buf) 54 c.Assert(err, check.IsNil) 55 56 rsp := s.req(c, req, nil).(*daemon.Resp) 57 58 c.Check(rsp.Type, check.Equals, daemon.ResponseTypeSync) 59 c.Check(rsp.Result, check.Equals, true) 60 c.Check(soon, check.Equals, 1) 61 } 62 63 func (s *postDebugSuite) TestPostDebugGetBaseDeclaration(c *check.C) { 64 _ = s.daemon(c) 65 66 buf := bytes.NewBufferString(`{"action": "get-base-declaration"}`) 67 req, err := http.NewRequest("POST", "/v2/debug", buf) 68 c.Assert(err, check.IsNil) 69 70 rsp := s.req(c, req, nil).(*daemon.Resp) 71 72 c.Check(rsp.Type, check.Equals, daemon.ResponseTypeSync) 73 c.Check(rsp.Result.(map[string]interface{})["base-declaration"], 74 testutil.Contains, "type: base-declaration") 75 } 76 77 func (s *postDebugSuite) testDebugConnectivityHappy(c *check.C, post bool) { 78 _ = s.daemon(c) 79 80 s.connectivityResult = map[string]bool{ 81 "good.host.com": true, 82 "another.good.host.com": true, 83 } 84 85 var rsp *daemon.Resp 86 if post { 87 buf := bytes.NewBufferString(`{"action": "connectivity"}`) 88 req, err := http.NewRequest("POST", "/v2/debug", buf) 89 c.Assert(err, check.IsNil) 90 91 rsp = s.req(c, req, nil).(*daemon.Resp) 92 } else { 93 req, err := http.NewRequest("GET", "/v2/debug?aspect=connectivity", nil) 94 c.Assert(err, check.IsNil) 95 rsp = s.req(c, req, nil).(*daemon.Resp) 96 97 } 98 99 c.Check(rsp.Type, check.Equals, daemon.ResponseTypeSync) 100 c.Check(rsp.Result, check.DeepEquals, daemon.ConnectivityStatus{ 101 Connectivity: true, 102 Unreachable: []string(nil), 103 }) 104 } 105 106 func (s *postDebugSuite) TestPostDebugConnectivityHappy(c *check.C) { 107 s.testDebugConnectivityHappy(c, true) 108 } 109 110 func (s *postDebugSuite) TestGetDebugConnectivityHappy(c *check.C) { 111 s.testDebugConnectivityHappy(c, false) 112 } 113 114 func (s *postDebugSuite) testDebugConnectivityUnhappy(c *check.C, post bool) { 115 _ = s.daemon(c) 116 117 s.connectivityResult = map[string]bool{ 118 "good.host.com": true, 119 "bad.host.com": false, 120 } 121 122 var rsp *daemon.Resp 123 if post { 124 buf := bytes.NewBufferString(`{"action": "connectivity"}`) 125 req, err := http.NewRequest("POST", "/v2/debug", buf) 126 c.Assert(err, check.IsNil) 127 128 rsp = s.req(c, req, nil).(*daemon.Resp) 129 } else { 130 req, err := http.NewRequest("GET", "/v2/debug?aspect=connectivity", nil) 131 c.Assert(err, check.IsNil) 132 rsp = s.req(c, req, nil).(*daemon.Resp) 133 } 134 135 c.Check(rsp.Type, check.Equals, daemon.ResponseTypeSync) 136 c.Check(rsp.Result, check.DeepEquals, daemon.ConnectivityStatus{ 137 Connectivity: false, 138 Unreachable: []string{"bad.host.com"}, 139 }) 140 } 141 142 func (s *postDebugSuite) TestPostDebugConnectivityUnhappy(c *check.C) { 143 s.testDebugConnectivityUnhappy(c, true) 144 } 145 146 func (s *postDebugSuite) TestGetDebugConnectivityUnhappy(c *check.C) { 147 s.testDebugConnectivityUnhappy(c, false) 148 } 149 150 func (s *postDebugSuite) TestGetDebugBaseDeclaration(c *check.C) { 151 _ = s.daemon(c) 152 153 req, err := http.NewRequest("GET", "/v2/debug?aspect=base-declaration", nil) 154 c.Assert(err, check.IsNil) 155 156 rsp := s.req(c, req, nil).(*daemon.Resp) 157 158 c.Check(rsp.Type, check.Equals, daemon.ResponseTypeSync) 159 c.Check(rsp.Result.(map[string]interface{})["base-declaration"], 160 testutil.Contains, "type: base-declaration") 161 } 162 163 func mockDurationThreshold() func() { 164 oldDurationThreshold := timings.DurationThreshold 165 restore := func() { 166 timings.DurationThreshold = oldDurationThreshold 167 } 168 timings.DurationThreshold = 0 169 return restore 170 } 171 172 func (s *postDebugSuite) getDebugTimings(c *check.C, request string) []interface{} { 173 defer mockDurationThreshold()() 174 175 s.daemonWithOverlordMock(c) 176 177 req, err := http.NewRequest("GET", request, nil) 178 c.Assert(err, check.IsNil) 179 180 st := s.d.Overlord().State() 181 st.Lock() 182 183 chg1 := st.NewChange("foo", "...") 184 task1 := st.NewTask("bar", "...") 185 chg1.AddTask(task1) 186 task1.SetStatus(state.DoingStatus) 187 188 chg2 := st.NewChange("foo", "...") 189 task2 := st.NewTask("bar", "...") 190 chg2.AddTask(task2) 191 192 chg3 := st.NewChange("foo", "...") 193 task3 := st.NewTask("bar", "...") 194 chg3.AddTask(task3) 195 196 tm1 := state.TimingsForTask(task3) 197 sp1 := tm1.StartSpan("span", "span...") 198 sp1.Stop() 199 tm1.Save(st) 200 201 tm2 := timings.New(map[string]string{"ensure": "foo", "change-id": chg1.ID()}) 202 sp2 := tm2.StartSpan("span", "span...") 203 sp2.Stop() 204 tm2.Save(st) 205 206 tm3 := timings.New(map[string]string{"ensure": "foo", "change-id": chg2.ID()}) 207 sp3 := tm3.StartSpan("span", "span...") 208 sp3.Stop() 209 tm3.Save(st) 210 211 tm4 := timings.New(map[string]string{"ensure": "bar", "change-id": chg3.ID()}) 212 sp4 := tm3.StartSpan("span", "span...") 213 sp4.Stop() 214 tm4.Save(st) 215 216 st.Unlock() 217 218 rsp := s.req(c, req, nil).(*daemon.Resp) 219 data, err := json.Marshal(rsp.Result) 220 c.Assert(err, check.IsNil) 221 var dataJSON []interface{} 222 json.Unmarshal(data, &dataJSON) 223 224 c.Assert(rsp.Type, check.Equals, daemon.ResponseTypeSync) 225 return dataJSON 226 } 227 228 func (s *postDebugSuite) TestGetDebugTimingsSingleChange(c *check.C) { 229 dataJSON := s.getDebugTimings(c, "/v2/debug?aspect=change-timings&change-id=1") 230 231 c.Check(dataJSON, check.HasLen, 1) 232 tmData := dataJSON[0].(map[string]interface{}) 233 c.Check(tmData["change-id"], check.DeepEquals, "1") 234 c.Check(tmData["change-timings"], check.NotNil) 235 } 236 237 func (s *postDebugSuite) TestGetDebugTimingsEnsureLatest(c *check.C) { 238 dataJSON := s.getDebugTimings(c, "/v2/debug?aspect=change-timings&ensure=foo&all=false") 239 c.Assert(dataJSON, check.HasLen, 1) 240 241 tmData := dataJSON[0].(map[string]interface{}) 242 c.Check(tmData["change-id"], check.DeepEquals, "2") 243 c.Check(tmData["change-timings"], check.NotNil) 244 c.Check(tmData["total-duration"], check.NotNil) 245 } 246 247 func (s *postDebugSuite) TestGetDebugTimingsEnsureAll(c *check.C) { 248 dataJSON := s.getDebugTimings(c, "/v2/debug?aspect=change-timings&ensure=foo&all=true") 249 250 c.Assert(dataJSON, check.HasLen, 2) 251 tmData := dataJSON[0].(map[string]interface{}) 252 c.Check(tmData["change-id"], check.DeepEquals, "1") 253 c.Check(tmData["change-timings"], check.NotNil) 254 c.Check(tmData["total-duration"], check.NotNil) 255 256 tmData = dataJSON[1].(map[string]interface{}) 257 c.Check(tmData["change-id"], check.DeepEquals, "2") 258 c.Check(tmData["change-timings"], check.NotNil) 259 c.Check(tmData["total-duration"], check.NotNil) 260 } 261 262 func (s *postDebugSuite) TestGetDebugTimingsError(c *check.C) { 263 s.daemonWithOverlordMock(c) 264 265 req, err := http.NewRequest("GET", "/v2/debug?aspect=change-timings&ensure=unknown", nil) 266 c.Assert(err, check.IsNil) 267 rsp := s.req(c, req, nil).(*daemon.Resp) 268 c.Check(rsp.Status, check.Equals, 400) 269 270 req, err = http.NewRequest("GET", "/v2/debug?aspect=change-timings&change-id=9999", nil) 271 c.Assert(err, check.IsNil) 272 rsp = s.req(c, req, nil).(*daemon.Resp) 273 c.Check(rsp.Status, check.Equals, 400) 274 } 275 276 func (s *postDebugSuite) TestMinLane(c *check.C) { 277 st := state.New(nil) 278 st.Lock() 279 defer st.Unlock() 280 281 t := st.NewTask("bar", "") 282 c.Check(daemon.MinLane(t), check.Equals, 0) 283 284 lane1 := st.NewLane() 285 t.JoinLane(lane1) 286 c.Check(daemon.MinLane(t), check.Equals, lane1) 287 288 lane2 := st.NewLane() 289 t.JoinLane(lane2) 290 c.Check(daemon.MinLane(t), check.Equals, lane1) 291 292 // sanity 293 c.Check(t.Lanes(), check.DeepEquals, []int{lane1, lane2}) 294 }