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  }