github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/usersession/userd/settings_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2017-2020 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 userd_test
    21  
    22  import (
    23  	"io/ioutil"
    24  	"os"
    25  	"path/filepath"
    26  
    27  	"github.com/godbus/dbus"
    28  	. "gopkg.in/check.v1"
    29  
    30  	"github.com/snapcore/snapd/dirs"
    31  	"github.com/snapcore/snapd/testutil"
    32  	"github.com/snapcore/snapd/usersession/userd"
    33  	"github.com/snapcore/snapd/usersession/userd/ui"
    34  )
    35  
    36  type settingsSuite struct {
    37  	settings *userd.Settings
    38  
    39  	mockXdgSettings       *testutil.MockCmd
    40  	restoreSnapFromSender func()
    41  }
    42  
    43  var _ = Suite(&settingsSuite{})
    44  
    45  func (s *settingsSuite) SetUpTest(c *C) {
    46  	dirs.SetRootDir(c.MkDir())
    47  	s.restoreSnapFromSender = userd.MockSnapFromSender(func(*dbus.Conn, dbus.Sender) (string, error) {
    48  		return "some-snap", nil
    49  	})
    50  
    51  	s.settings = &userd.Settings{}
    52  	s.mockXdgSettings = testutil.MockCommand(c, "xdg-settings", `
    53  case "$1" in
    54      get)
    55          case "$2" in
    56              default-web-browser)
    57                  echo "some-snap_foo.desktop"
    58                  ;;
    59              default-url-scheme-handler)
    60                  echo "some-snap_ircclient.desktop"
    61                  ;;
    62              *)
    63                  echo "mock called with unsupported arguments: $*"
    64                  exit 1
    65                  ;;
    66          esac
    67          ;;
    68      set)
    69          case "$2" in
    70              default-web-browser)
    71                  # nothing to do
    72                  ;;
    73              default-url-scheme-handler)
    74                  if [ "$3" = "irc2" ]; then
    75                      echo "fail"
    76                      exit 1
    77                  fi
    78                  # nothing to do
    79                  ;;
    80              *)
    81                  echo "mock called with unsupported arguments: $*"
    82                  exit 1
    83                  ;;
    84          esac
    85          ;;
    86      check)
    87          case "$2" in
    88              default-web-browser)
    89                  if [ "$3" = "some-snap_foo.desktop" ]; then
    90                      echo "yes"
    91                  else
    92                      echo "no"
    93                  fi
    94                  ;;
    95              default-url-scheme-handler)
    96                  if [ "$3" = "irc" ] && [ "$4" = "some-snap_ircclient.desktop" ]; then
    97                      echo "yes"
    98                  else
    99                      echo "no"
   100                  fi
   101                  ;;
   102          esac
   103          ;;
   104      *)
   105          echo "mock called with unsupported argument: $1"
   106          exit 1
   107          ;;
   108  esac
   109  `)
   110  }
   111  
   112  func (s *settingsSuite) TearDownTest(c *C) {
   113  	s.mockXdgSettings.Restore()
   114  	s.restoreSnapFromSender()
   115  	dirs.SetRootDir("/")
   116  }
   117  
   118  func mockUIcommands(c *C, script string) func() {
   119  	mockZenity := testutil.MockCommand(c, "zenity", script)
   120  	mockKDialog := testutil.MockCommand(c, "kdialog", script)
   121  	return func() {
   122  		mockZenity.Restore()
   123  		mockKDialog.Restore()
   124  	}
   125  }
   126  
   127  func (s *settingsSuite) TestGetUnhappy(c *C) {
   128  	for _, t := range []struct {
   129  		setting    string
   130  		errMatcher string
   131  	}{
   132  		{"random-setting", `invalid setting "random-setting"`},
   133  		{"invälid", `invalid setting "invälid"`},
   134  		{"", `invalid setting ""`},
   135  	} {
   136  		_, err := s.settings.Get(t.setting, ":some-dbus-sender")
   137  		c.Assert(err, ErrorMatches, t.errMatcher)
   138  		c.Assert(s.mockXdgSettings.Calls(), IsNil)
   139  	}
   140  }
   141  
   142  func (s *settingsSuite) TestGetHappy(c *C) {
   143  	defaultBrowser, err := s.settings.Get("default-web-browser", ":some-dbus-sender")
   144  	c.Assert(err, IsNil)
   145  	c.Check(defaultBrowser, Equals, "foo.desktop")
   146  	c.Check(s.mockXdgSettings.Calls(), DeepEquals, [][]string{
   147  		{"xdg-settings", "get", "default-web-browser"},
   148  	})
   149  }
   150  
   151  func (s *settingsSuite) TestCheckInvalidSetting(c *C) {
   152  	_, err := s.settings.Check("random-setting", "foo.desktop", ":some-dbus-sender")
   153  	c.Assert(err, ErrorMatches, `invalid setting "random-setting"`)
   154  	c.Assert(s.mockXdgSettings.Calls(), IsNil)
   155  }
   156  
   157  func (s *settingsSuite) TestCheckIsDefault(c *C) {
   158  	isDefault, err := s.settings.Check("default-web-browser", "foo.desktop", ":some-dbus-sender")
   159  	c.Assert(err, IsNil)
   160  	c.Check(isDefault, Equals, "yes")
   161  	c.Check(s.mockXdgSettings.Calls(), DeepEquals, [][]string{
   162  		{"xdg-settings", "check", "default-web-browser", "some-snap_foo.desktop"},
   163  	})
   164  }
   165  
   166  func (s *settingsSuite) TestCheckIsDefaultUrlScheme(c *C) {
   167  	isDefault, err := s.settings.CheckSub("default-url-scheme-handler", "irc", "ircclient.desktop", ":some-dbus-sender")
   168  	c.Assert(err, IsNil)
   169  	c.Check(isDefault, Equals, "yes")
   170  	c.Check(s.mockXdgSettings.Calls(), DeepEquals, [][]string{
   171  		{"xdg-settings", "check", "default-url-scheme-handler", "irc", "some-snap_ircclient.desktop"},
   172  	})
   173  }
   174  
   175  func (s *settingsSuite) TestCheckNoDefault(c *C) {
   176  	isDefault, err := s.settings.Check("default-web-browser", "bar.desktop", ":some-dbus-sender")
   177  	c.Assert(err, IsNil)
   178  	c.Check(isDefault, Equals, "no")
   179  	c.Check(s.mockXdgSettings.Calls(), DeepEquals, [][]string{
   180  		{"xdg-settings", "check", "default-web-browser", "some-snap_bar.desktop"},
   181  	})
   182  }
   183  
   184  func (s *settingsSuite) TestCheckNoDefaultUrlScheme(c *C) {
   185  	isDefault, err := s.settings.CheckSub("default-url-scheme-handler", "irc", "bar.desktop", ":some-dbus-sender")
   186  	c.Assert(err, IsNil)
   187  	c.Check(isDefault, Equals, "no")
   188  	c.Check(s.mockXdgSettings.Calls(), DeepEquals, [][]string{
   189  		{"xdg-settings", "check", "default-url-scheme-handler", "irc", "some-snap_bar.desktop"},
   190  	})
   191  }
   192  
   193  func (s *settingsSuite) TestNotThisSnap(c *C) {
   194  	mockXdgSettings := testutil.MockCommand(c, "xdg-settings", `
   195  if [ "$1" = "get" ] && [ "$2" = "default-web-browser" ]; then
   196      echo "other-snap_foo.desktop"
   197      exit 0
   198  fi
   199  if [ "$1" = "get" ] && [ "$2" = "default-url-scheme-handler" ] && [ "$3" = "irc" ]; then
   200      echo "other-snap_foo-irc.desktop"
   201      exit 0
   202  fi
   203  
   204  echo "mock called with unsupported argument: $1"
   205  exit 1
   206  `)
   207  	defer mockXdgSettings.Restore()
   208  
   209  	defaultBrowser, err := s.settings.Get("default-web-browser", ":some-dbus-sender")
   210  	c.Assert(err, IsNil)
   211  	c.Check(defaultBrowser, Equals, "NOT-THIS-SNAP.desktop")
   212  	c.Check(mockXdgSettings.Calls(), DeepEquals, [][]string{
   213  		{"xdg-settings", "get", "default-web-browser"},
   214  	})
   215  
   216  	mockXdgSettings.ForgetCalls()
   217  
   218  	defaultSchemeHandler, err := s.settings.GetSub("default-url-scheme-handler", "irc", ":some-dbus-sender")
   219  	c.Assert(err, IsNil)
   220  	c.Check(defaultSchemeHandler, Equals, "NOT-THIS-SNAP.desktop")
   221  	c.Check(mockXdgSettings.Calls(), DeepEquals, [][]string{
   222  		{"xdg-settings", "get", "default-url-scheme-handler", "irc"},
   223  	})
   224  }
   225  
   226  func (s *settingsSuite) TestSetInvalidSetting(c *C) {
   227  	err := s.settings.Set("random-setting", "foo.desktop", ":some-dbus-sender")
   228  	c.Assert(err, ErrorMatches, `invalid setting "random-setting"`)
   229  	c.Assert(s.mockXdgSettings.Calls(), IsNil)
   230  }
   231  
   232  func (s *settingsSuite) TestSetInvalidValue(c *C) {
   233  	err := s.settings.Set("default-web-browser", "foo", ":some-dbus-sender")
   234  	c.Assert(err, ErrorMatches, `cannot set "default-web-browser" setting to invalid value "foo"`)
   235  	c.Assert(s.mockXdgSettings.Calls(), IsNil)
   236  }
   237  
   238  func (s *settingsSuite) TestSetSubInvalidSetting(c *C) {
   239  	err := s.settings.SetSub("random-setting", "subprop", "foo.desktop", ":some-dbus-sender")
   240  	c.Assert(err, ErrorMatches, `invalid setting "random-setting"`)
   241  	c.Assert(s.mockXdgSettings.Calls(), IsNil)
   242  }
   243  
   244  func (s *settingsSuite) TestSetSubInvalidValue(c *C) {
   245  	err := s.settings.SetSub("default-url-scheme-handler", "irc", "foo", ":some-dbus-sender")
   246  	c.Assert(err, ErrorMatches, `cannot set "default-url-scheme-handler" subproperty "irc" setting to invalid value "foo"`)
   247  	c.Assert(s.mockXdgSettings.Calls(), IsNil)
   248  }
   249  
   250  func (s *settingsSuite) testSetUserDeclined(c *C) {
   251  	df := filepath.Join(dirs.SnapDesktopFilesDir, "some-snap_bar.desktop")
   252  	err := os.MkdirAll(filepath.Dir(df), 0755)
   253  	c.Assert(err, IsNil)
   254  	err = ioutil.WriteFile(df, nil, 0644)
   255  	c.Assert(err, IsNil)
   256  
   257  	err = s.settings.Set("default-web-browser", "bar.desktop", ":some-dbus-sender")
   258  	c.Assert(err, ErrorMatches, `cannot change configuration: user declined change`)
   259  	c.Check(s.mockXdgSettings.Calls(), IsNil)
   260  	// FIXME: this needs PR#4342
   261  	/*
   262  		c.Check(mockZenity.Calls(), DeepEquals, [][]string{
   263  			{"zenity", "--question", "--text=Allow changing setting \"default-web-browser\" to \"bar.desktop\" ?"},
   264  		})
   265  	*/
   266  }
   267  
   268  func (s *settingsSuite) TestSetUserDeclinedKDialog(c *C) {
   269  	// force zenity exec missing
   270  	restoreZenity := ui.MockHasZenityExecutable(func() bool { return false })
   271  	restoreCmds := mockUIcommands(c, "false")
   272  	defer func() {
   273  		restoreZenity()
   274  		restoreCmds()
   275  	}()
   276  
   277  	s.testSetUserDeclined(c)
   278  }
   279  
   280  func (s *settingsSuite) TestSetUserDeclinedZenity(c *C) {
   281  	// force kdialog exec missing
   282  	restoreKDialog := ui.MockHasKDialogExecutable(func() bool { return false })
   283  	restoreCmds := mockUIcommands(c, "false")
   284  	defer func() {
   285  		restoreKDialog()
   286  		restoreCmds()
   287  	}()
   288  
   289  	s.testSetUserDeclined(c)
   290  }
   291  
   292  func (s *settingsSuite) testSetUserAccepts(c *C) {
   293  	df := filepath.Join(dirs.SnapDesktopFilesDir, "some-snap_foo.desktop")
   294  	err := os.MkdirAll(filepath.Dir(df), 0755)
   295  	c.Assert(err, IsNil)
   296  	err = ioutil.WriteFile(df, nil, 0644)
   297  	c.Assert(err, IsNil)
   298  
   299  	err = s.settings.Set("default-web-browser", "foo.desktop", ":some-dbus-sender")
   300  	c.Assert(err, IsNil)
   301  	c.Check(s.mockXdgSettings.Calls(), DeepEquals, [][]string{
   302  		{"xdg-settings", "set", "default-web-browser", "some-snap_foo.desktop"},
   303  	})
   304  	// FIXME: this needs PR#4342
   305  	/*
   306  			c.Check(mockZenity.Calls(), DeepEquals, [][]string{
   307  				{"zenity", "--question", "--text=Allow changing setting \"default-web-browser\" to \"foo.desktop\" ?"},
   308  		})
   309  	*/
   310  }
   311  
   312  func (s *settingsSuite) testSetUserAcceptsURLScheme(c *C) {
   313  	df := filepath.Join(dirs.SnapDesktopFilesDir, "some-snap_ircclient.desktop")
   314  	err := os.MkdirAll(filepath.Dir(df), 0755)
   315  	c.Assert(err, IsNil)
   316  	err = ioutil.WriteFile(df, nil, 0644)
   317  	c.Assert(err, IsNil)
   318  
   319  	err = s.settings.SetSub("default-url-scheme-handler", "irc", "ircclient.desktop", ":some-dbus-sender")
   320  	c.Assert(err, IsNil)
   321  	c.Check(s.mockXdgSettings.Calls(), DeepEquals, [][]string{
   322  		{"xdg-settings", "set", "default-url-scheme-handler", "irc", "some-snap_ircclient.desktop"},
   323  	})
   324  }
   325  
   326  func (s *settingsSuite) TestSetUserAcceptsZenity(c *C) {
   327  	// force kdialog exec missing
   328  	restoreKDialog := ui.MockHasKDialogExecutable(func() bool { return false })
   329  	restoreCmds := mockUIcommands(c, "true")
   330  	defer func() {
   331  		restoreKDialog()
   332  		restoreCmds()
   333  	}()
   334  
   335  	s.testSetUserAccepts(c)
   336  }
   337  
   338  func (s *settingsSuite) TestSetUserAcceptsZenityUrlScheme(c *C) {
   339  	// force kdialog exec missing
   340  	restoreKDialog := ui.MockHasKDialogExecutable(func() bool { return false })
   341  	restoreCmds := mockUIcommands(c, "true")
   342  	defer func() {
   343  		restoreKDialog()
   344  		restoreCmds()
   345  	}()
   346  
   347  	s.testSetUserAcceptsURLScheme(c)
   348  }
   349  
   350  func (s *settingsSuite) TestSetUserAcceptsKDialog(c *C) {
   351  	// force zenity exec missing
   352  	restoreZenity := ui.MockHasZenityExecutable(func() bool { return false })
   353  	restoreCmds := mockUIcommands(c, "true")
   354  	defer func() {
   355  		restoreZenity()
   356  		restoreCmds()
   357  	}()
   358  
   359  	s.testSetUserAccepts(c)
   360  }
   361  
   362  func (s *settingsSuite) TestSetUserAcceptsKDialogUrlScheme(c *C) {
   363  	// force zenity exec missing
   364  	restoreZenity := ui.MockHasZenityExecutable(func() bool { return false })
   365  	restoreCmds := mockUIcommands(c, "true")
   366  	defer func() {
   367  		restoreZenity()
   368  		restoreCmds()
   369  	}()
   370  
   371  	s.testSetUserAcceptsURLScheme(c)
   372  }
   373  
   374  func (s *settingsSuite) TestSetUserAcceptsZenityUrlSchemeXdgSettingsError(c *C) {
   375  	// force kdialog exec missing
   376  	restoreKDialog := ui.MockHasKDialogExecutable(func() bool { return false })
   377  	restoreCmds := mockUIcommands(c, "true")
   378  	defer func() {
   379  		restoreKDialog()
   380  		restoreCmds()
   381  	}()
   382  
   383  	df := filepath.Join(dirs.SnapDesktopFilesDir, "some-snap_ircclient.desktop")
   384  	err := os.MkdirAll(filepath.Dir(df), 0755)
   385  	c.Assert(err, IsNil)
   386  	err = ioutil.WriteFile(df, nil, 0644)
   387  	c.Assert(err, IsNil)
   388  
   389  	err = s.settings.SetSub("default-url-scheme-handler", "irc2", "ircclient.desktop", ":some-dbus-sender")
   390  	c.Assert(err, ErrorMatches, `cannot set "default-url-scheme-handler" subproperty "irc2" setting: fail`)
   391  	c.Check(s.mockXdgSettings.Calls(), DeepEquals, [][]string{
   392  		{"xdg-settings", "set", "default-url-scheme-handler", "irc2", "some-snap_ircclient.desktop"},
   393  	})
   394  }