github.com/ethanhsieh/snapd@v0.0.0-20210615102523-3db9b8e4edc5/usersession/autostart/autostart_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2018 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 autostart_test
    21  
    22  import (
    23  	"io/ioutil"
    24  	"os"
    25  	"os/user"
    26  	"path"
    27  	"path/filepath"
    28  	"strings"
    29  	"testing"
    30  
    31  	. "gopkg.in/check.v1"
    32  
    33  	"github.com/snapcore/snapd/dirs"
    34  	"github.com/snapcore/snapd/snap"
    35  	"github.com/snapcore/snapd/snap/snaptest"
    36  	"github.com/snapcore/snapd/testutil"
    37  	"github.com/snapcore/snapd/usersession/autostart"
    38  )
    39  
    40  func Test(t *testing.T) { TestingT(t) }
    41  
    42  type autostartSuite struct {
    43  	dir                string
    44  	autostartDir       string
    45  	userDir            string
    46  	userCurrentRestore func()
    47  }
    48  
    49  var _ = Suite(&autostartSuite{})
    50  
    51  func (s *autostartSuite) SetUpTest(c *C) {
    52  	s.dir = c.MkDir()
    53  	dirs.SetRootDir(s.dir)
    54  	snap.MockSanitizePlugsSlots(func(snapInfo *snap.Info) {})
    55  
    56  	s.userDir = path.Join(s.dir, "home")
    57  	s.autostartDir = path.Join(s.userDir, ".config", "autostart")
    58  	s.userCurrentRestore = autostart.MockUserCurrent(func() (*user.User, error) {
    59  		return &user.User{HomeDir: s.userDir}, nil
    60  	})
    61  
    62  	err := os.MkdirAll(s.autostartDir, 0755)
    63  	c.Assert(err, IsNil)
    64  }
    65  
    66  func (s *autostartSuite) TearDownTest(c *C) {
    67  	s.dir = c.MkDir()
    68  	dirs.SetRootDir("/")
    69  	if s.userCurrentRestore != nil {
    70  		s.userCurrentRestore()
    71  	}
    72  }
    73  
    74  func (s *autostartSuite) TestLoadAutostartDesktopFile(c *C) {
    75  	allGood := `[Desktop Entry]
    76  Exec=foo --bar
    77  `
    78  	allGoodWithFlags := `[Desktop Entry]
    79  Exec=foo --bar "%%p" %U %D +%s %%
    80  `
    81  	noExec := `[Desktop Entry]
    82  Type=Application
    83  `
    84  	emptyExec := `[Desktop Entry]
    85  Exec=
    86  `
    87  	onlySpacesExec := `[Desktop Entry]
    88  Exec=
    89  `
    90  	hidden := `[Desktop Entry]
    91  Exec=foo --bar
    92  Hidden=true
    93  `
    94  	hiddenFalse := `[Desktop Entry]
    95  Exec=foo --bar
    96  Hidden=false
    97  `
    98  	justGNOME := `[Desktop Entry]
    99  Exec=foo --bar
   100  OnlyShowIn=GNOME;
   101  `
   102  	notInGNOME := `[Desktop Entry]
   103  Exec=foo --bar
   104  NotShownIn=GNOME;
   105  `
   106  	notInGNOMEAndKDE := `[Desktop Entry]
   107  Exec=foo --bar
   108  NotShownIn=GNOME;KDE;
   109  `
   110  	hiddenGNOMEextension := `[Desktop Entry]
   111  Exec=foo --bar
   112  X-GNOME-Autostart-enabled=false
   113  `
   114  	GNOMEextension := `[Desktop Entry]
   115  Exec=foo --bar
   116  X-GNOME-Autostart-enabled=true
   117  `
   118  
   119  	for i, tc := range []struct {
   120  		in      string
   121  		out     string
   122  		err     string
   123  		current string
   124  	}{{
   125  		in:  allGood,
   126  		out: "foo --bar",
   127  	}, {
   128  		in:  noExec,
   129  		err: "Exec not found or invalid",
   130  	}, {
   131  		in:  emptyExec,
   132  		err: "Exec not found or invalid",
   133  	}, {
   134  		in:  onlySpacesExec,
   135  		err: "Exec not found or invalid",
   136  	}, {
   137  		in:  allGoodWithFlags,
   138  		out: `foo --bar "%p"   + %`,
   139  	}, {
   140  		in:  hidden,
   141  		err: `desktop file is hidden`,
   142  	}, {
   143  		in:  hiddenFalse,
   144  		out: `foo --bar`,
   145  	}, {
   146  		in:      justGNOME,
   147  		out:     "foo --bar",
   148  		current: "GNOME",
   149  	}, {
   150  		in:      justGNOME,
   151  		current: "KDE",
   152  		err:     `current desktop \["KDE"\] not included in \["GNOME"\]`,
   153  	}, {
   154  		in:      notInGNOME,
   155  		current: "GNOME",
   156  		err:     `current desktop \["GNOME"\] excluded by \["GNOME"\]`,
   157  	}, {
   158  		in:      notInGNOME,
   159  		current: "KDE",
   160  		out:     "foo --bar",
   161  	}, {
   162  		in:      notInGNOMEAndKDE,
   163  		current: "XFCE",
   164  		out:     "foo --bar",
   165  	}, {
   166  		in:      hiddenGNOMEextension,
   167  		current: "KDE",
   168  		out:     "foo --bar",
   169  	}, {
   170  		in:      hiddenGNOMEextension,
   171  		current: "GNOME",
   172  		err:     `desktop file is hidden by X-GNOME-Autostart-enabled extension`,
   173  	}, {
   174  		in:      GNOMEextension,
   175  		current: "GNOME",
   176  		out:     "foo --bar",
   177  	}, {
   178  		in:      GNOMEextension,
   179  		current: "KDE",
   180  		out:     "foo --bar",
   181  	}} {
   182  		c.Logf("tc %d", i)
   183  
   184  		path := filepath.Join(c.MkDir(), "foo.desktop")
   185  		err := ioutil.WriteFile(path, []byte(tc.in), 0644)
   186  		c.Assert(err, IsNil)
   187  
   188  		run := func() {
   189  			defer autostart.MockCurrentDesktop(tc.current)()
   190  
   191  			cmd, err := autostart.LoadAutostartDesktopFile(path)
   192  			if tc.err != "" {
   193  				c.Check(cmd, Equals, "")
   194  				c.Check(err, ErrorMatches, tc.err)
   195  			} else {
   196  				c.Check(err, IsNil)
   197  				c.Check(cmd, Equals, tc.out)
   198  			}
   199  		}
   200  		run()
   201  	}
   202  }
   203  
   204  var mockYaml = `name: snapname
   205  version: 1.0
   206  apps:
   207   foo:
   208    command: run-app
   209    autostart: foo-stable.desktop
   210  `
   211  
   212  func (s *autostartSuite) TestTryAutostartAppValid(c *C) {
   213  	si := snaptest.MockSnapCurrent(c, mockYaml, &snap.SideInfo{Revision: snap.R("x2")})
   214  
   215  	appWrapperPath := si.Apps["foo"].WrapperPath()
   216  
   217  	appCmd := testutil.MockCommand(c, appWrapperPath, "")
   218  	defer appCmd.Restore()
   219  
   220  	fooDesktopFile := filepath.Join(s.autostartDir, "foo-stable.desktop")
   221  	writeFile(c, fooDesktopFile,
   222  		[]byte(`[Desktop Entry]
   223  Exec=this-is-ignored -a -b --foo="a b c" -z "dev"
   224  `))
   225  
   226  	cmd, err := autostart.AutostartCmd("snapname", fooDesktopFile)
   227  	c.Assert(err, IsNil)
   228  	c.Assert(cmd.Path, Equals, appWrapperPath)
   229  
   230  	err = cmd.Start()
   231  	c.Assert(err, IsNil)
   232  	cmd.Wait()
   233  
   234  	c.Assert(appCmd.Calls(), DeepEquals,
   235  		[][]string{
   236  			{
   237  				filepath.Base(appWrapperPath),
   238  				"-a",
   239  				"-b",
   240  				"--foo=a b c",
   241  				"-z",
   242  				"dev",
   243  			},
   244  		})
   245  }
   246  
   247  func (s *autostartSuite) TestTryAutostartAppNoMatchingApp(c *C) {
   248  	snaptest.MockSnapCurrent(c, mockYaml, &snap.SideInfo{Revision: snap.R("x2")})
   249  
   250  	fooDesktopFile := filepath.Join(s.autostartDir, "foo-no-match.desktop")
   251  	writeFile(c, fooDesktopFile,
   252  		[]byte(`[Desktop Entry]
   253  Exec=this-is-ignored -a -b --foo="a b c" -z "dev"
   254  `))
   255  
   256  	cmd, err := autostart.AutostartCmd("snapname", fooDesktopFile)
   257  	c.Assert(cmd, IsNil)
   258  	c.Assert(err, ErrorMatches, `cannot match desktop file with snap snapname applications`)
   259  }
   260  
   261  func (s *autostartSuite) TestTryAutostartAppNoSnap(c *C) {
   262  	fooDesktopFile := filepath.Join(s.autostartDir, "foo-stable.desktop")
   263  	writeFile(c, fooDesktopFile,
   264  		[]byte(`[Desktop Entry]
   265  Exec=this-is-ignored -a -b --foo="a b c" -z "dev"
   266  `))
   267  
   268  	cmd, err := autostart.AutostartCmd("snapname", fooDesktopFile)
   269  	c.Assert(cmd, IsNil)
   270  	c.Assert(err, ErrorMatches, `cannot find current revision for snap snapname.*`)
   271  }
   272  
   273  func (s *autostartSuite) TestTryAutostartAppBadExec(c *C) {
   274  	snaptest.MockSnapCurrent(c, mockYaml, &snap.SideInfo{Revision: snap.R("x2")})
   275  
   276  	fooDesktopFile := filepath.Join(s.autostartDir, "foo-stable.desktop")
   277  	writeFile(c, fooDesktopFile,
   278  		[]byte(`[Desktop Entry]
   279  Foo=bar
   280  `))
   281  
   282  	cmd, err := autostart.AutostartCmd("snapname", fooDesktopFile)
   283  	c.Assert(cmd, IsNil)
   284  	c.Assert(err, ErrorMatches, `cannot determine startup command for application foo in snap snapname: Exec not found or invalid`)
   285  }
   286  
   287  func writeFile(c *C, path string, content []byte) {
   288  	err := os.MkdirAll(filepath.Dir(path), 0755)
   289  	c.Assert(err, IsNil)
   290  	err = ioutil.WriteFile(path, content, 0644)
   291  	c.Assert(err, IsNil)
   292  }
   293  
   294  func (s *autostartSuite) TestTryAutostartMany(c *C) {
   295  	var mockYamlTemplate = `name: {snap}
   296  version: 1.0
   297  apps:
   298   foo:
   299    command: run-app
   300    autostart: foo-stable.desktop
   301  `
   302  
   303  	snaptest.MockSnapCurrent(c, strings.Replace(mockYamlTemplate, "{snap}", "a-foo", -1),
   304  		&snap.SideInfo{Revision: snap.R("x2")})
   305  	snaptest.MockSnapCurrent(c, strings.Replace(mockYamlTemplate, "{snap}", "b-foo", -1),
   306  		&snap.SideInfo{Revision: snap.R("x2")})
   307  	writeFile(c, filepath.Join(s.userDir, "snap/a-foo/current/.config/autostart/foo-stable.desktop"),
   308  		[]byte(`[Desktop Entry]
   309  Foo=bar
   310  `))
   311  	writeFile(c, filepath.Join(s.userDir, "snap/b-foo/current/.config/autostart/no-match.desktop"),
   312  		[]byte(`[Desktop Entry]
   313  Exec=no-snap
   314  `))
   315  	writeFile(c, filepath.Join(s.userDir, "snap/c-foo/current/.config/autostart/no-snap.desktop"),
   316  		[]byte(`[Desktop Entry]
   317  Exec=no-snap
   318  `))
   319  
   320  	err := autostart.AutostartSessionApps()
   321  	c.Assert(err, NotNil)
   322  	c.Check(err, ErrorMatches, `- "foo-stable.desktop": cannot determine startup command for application foo in snap a-foo: Exec not found or invalid
   323  - "no-match.desktop": cannot match desktop file with snap b-foo applications
   324  - "no-snap.desktop": cannot find current revision for snap c-foo: readlink.*no such file or directory
   325  `)
   326  }