github.com/david-imola/snapd@v0.0.0-20210611180407-2de8ddeece6d/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 s.expectRootAccess() 44 45 soon := 0 46 var origEnsureStateSoon func(*state.State) 47 origEnsureStateSoon, restore := daemon.MockEnsureStateSoon(func(st *state.State) { 48 soon++ 49 origEnsureStateSoon(st) 50 }) 51 defer restore() 52 53 buf := bytes.NewBufferString(`{"action": "ensure-state-soon"}`) 54 req, err := http.NewRequest("POST", "/v2/debug", buf) 55 c.Assert(err, check.IsNil) 56 57 rsp := s.syncReq(c, req, nil) 58 c.Check(rsp.Result, check.Equals, true) 59 c.Check(soon, check.Equals, 1) 60 } 61 62 func (s *postDebugSuite) TestDebugConnectivityHappy(c *check.C) { 63 _ = s.daemon(c) 64 65 s.connectivityResult = map[string]bool{ 66 "good.host.com": true, 67 "another.good.host.com": true, 68 } 69 70 req, err := http.NewRequest("GET", "/v2/debug?aspect=connectivity", nil) 71 c.Assert(err, check.IsNil) 72 73 rsp := s.syncReq(c, req, nil) 74 c.Check(rsp.Result, check.DeepEquals, daemon.ConnectivityStatus{ 75 Connectivity: true, 76 Unreachable: []string(nil), 77 }) 78 } 79 80 func (s *postDebugSuite) TestDebugConnectivityUnhappy(c *check.C) { 81 _ = s.daemon(c) 82 83 s.connectivityResult = map[string]bool{ 84 "good.host.com": true, 85 "bad.host.com": false, 86 } 87 88 req, err := http.NewRequest("GET", "/v2/debug?aspect=connectivity", nil) 89 c.Assert(err, check.IsNil) 90 91 rsp := s.syncReq(c, req, nil) 92 c.Check(rsp.Result, check.DeepEquals, daemon.ConnectivityStatus{ 93 Connectivity: false, 94 Unreachable: []string{"bad.host.com"}, 95 }) 96 } 97 98 func (s *postDebugSuite) TestGetDebugBaseDeclaration(c *check.C) { 99 _ = s.daemon(c) 100 101 req, err := http.NewRequest("GET", "/v2/debug?aspect=base-declaration", nil) 102 c.Assert(err, check.IsNil) 103 104 rsp := s.syncReq(c, req, nil) 105 106 c.Check(rsp.Result.(map[string]interface{})["base-declaration"], 107 testutil.Contains, "type: base-declaration") 108 } 109 110 func mockDurationThreshold() func() { 111 oldDurationThreshold := timings.DurationThreshold 112 restore := func() { 113 timings.DurationThreshold = oldDurationThreshold 114 } 115 timings.DurationThreshold = 0 116 return restore 117 } 118 119 func (s *postDebugSuite) getDebugTimings(c *check.C, request string) []interface{} { 120 defer mockDurationThreshold()() 121 122 s.daemonWithOverlordMock(c) 123 124 req, err := http.NewRequest("GET", request, nil) 125 c.Assert(err, check.IsNil) 126 127 st := s.d.Overlord().State() 128 st.Lock() 129 130 chg1 := st.NewChange("foo", "...") 131 task1 := st.NewTask("bar", "...") 132 chg1.AddTask(task1) 133 task1.SetStatus(state.DoingStatus) 134 135 chg2 := st.NewChange("foo", "...") 136 task2 := st.NewTask("bar", "...") 137 chg2.AddTask(task2) 138 139 chg3 := st.NewChange("foo", "...") 140 task3 := st.NewTask("bar", "...") 141 chg3.AddTask(task3) 142 143 tm1 := state.TimingsForTask(task3) 144 sp1 := tm1.StartSpan("span", "span...") 145 sp1.Stop() 146 tm1.Save(st) 147 148 tm2 := timings.New(map[string]string{"ensure": "foo", "change-id": chg1.ID()}) 149 sp2 := tm2.StartSpan("span", "span...") 150 sp2.Stop() 151 tm2.Save(st) 152 153 tm3 := timings.New(map[string]string{"ensure": "foo", "change-id": chg2.ID()}) 154 sp3 := tm3.StartSpan("span", "span...") 155 sp3.Stop() 156 tm3.Save(st) 157 158 tm4 := timings.New(map[string]string{"ensure": "bar", "change-id": chg3.ID()}) 159 sp4 := tm3.StartSpan("span", "span...") 160 sp4.Stop() 161 tm4.Save(st) 162 163 st.Unlock() 164 165 rsp := s.syncReq(c, req, nil) 166 data, err := json.Marshal(rsp.Result) 167 c.Assert(err, check.IsNil) 168 var dataJSON []interface{} 169 json.Unmarshal(data, &dataJSON) 170 171 return dataJSON 172 } 173 174 func (s *postDebugSuite) TestGetDebugTimingsSingleChange(c *check.C) { 175 dataJSON := s.getDebugTimings(c, "/v2/debug?aspect=change-timings&change-id=1") 176 177 c.Check(dataJSON, check.HasLen, 1) 178 tmData := dataJSON[0].(map[string]interface{}) 179 c.Check(tmData["change-id"], check.DeepEquals, "1") 180 c.Check(tmData["change-timings"], check.NotNil) 181 } 182 183 func (s *postDebugSuite) TestGetDebugTimingsEnsureLatest(c *check.C) { 184 dataJSON := s.getDebugTimings(c, "/v2/debug?aspect=change-timings&ensure=foo&all=false") 185 c.Assert(dataJSON, check.HasLen, 1) 186 187 tmData := dataJSON[0].(map[string]interface{}) 188 c.Check(tmData["change-id"], check.DeepEquals, "2") 189 c.Check(tmData["change-timings"], check.NotNil) 190 c.Check(tmData["total-duration"], check.NotNil) 191 } 192 193 func (s *postDebugSuite) TestGetDebugTimingsEnsureAll(c *check.C) { 194 dataJSON := s.getDebugTimings(c, "/v2/debug?aspect=change-timings&ensure=foo&all=true") 195 196 c.Assert(dataJSON, check.HasLen, 2) 197 tmData := dataJSON[0].(map[string]interface{}) 198 c.Check(tmData["change-id"], check.DeepEquals, "1") 199 c.Check(tmData["change-timings"], check.NotNil) 200 c.Check(tmData["total-duration"], check.NotNil) 201 202 tmData = dataJSON[1].(map[string]interface{}) 203 c.Check(tmData["change-id"], check.DeepEquals, "2") 204 c.Check(tmData["change-timings"], check.NotNil) 205 c.Check(tmData["total-duration"], check.NotNil) 206 } 207 208 func (s *postDebugSuite) TestGetDebugTimingsError(c *check.C) { 209 s.daemonWithOverlordMock(c) 210 211 req, err := http.NewRequest("GET", "/v2/debug?aspect=change-timings&ensure=unknown", nil) 212 c.Assert(err, check.IsNil) 213 rsp := s.errorReq(c, req, nil) 214 c.Check(rsp.Status, check.Equals, 400) 215 216 req, err = http.NewRequest("GET", "/v2/debug?aspect=change-timings&change-id=9999", nil) 217 c.Assert(err, check.IsNil) 218 rsp = s.errorReq(c, req, nil) 219 c.Check(rsp.Status, check.Equals, 400) 220 } 221 222 func (s *postDebugSuite) TestMinLane(c *check.C) { 223 st := state.New(nil) 224 st.Lock() 225 defer st.Unlock() 226 227 t := st.NewTask("bar", "") 228 c.Check(daemon.MinLane(t), check.Equals, 0) 229 230 lane1 := st.NewLane() 231 t.JoinLane(lane1) 232 c.Check(daemon.MinLane(t), check.Equals, lane1) 233 234 lane2 := st.NewLane() 235 t.JoinLane(lane2) 236 c.Check(daemon.MinLane(t), check.Equals, lane1) 237 238 // sanity 239 c.Check(t.Lanes(), check.DeepEquals, []int{lane1, lane2}) 240 }