github.com/rigado/snapd@v2.42.5-go-mod+incompatible/cmd/snap/cmd_auto_import_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2016 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 main_test
    21  
    22  import (
    23  	"fmt"
    24  	"io/ioutil"
    25  	"net/http"
    26  	"os"
    27  	"path/filepath"
    28  
    29  	. "gopkg.in/check.v1"
    30  
    31  	snap "github.com/snapcore/snapd/cmd/snap"
    32  	"github.com/snapcore/snapd/dirs"
    33  	"github.com/snapcore/snapd/logger"
    34  	"github.com/snapcore/snapd/osutil"
    35  	"github.com/snapcore/snapd/release"
    36  )
    37  
    38  func makeMockMountInfo(c *C, content string) string {
    39  	fn := filepath.Join(c.MkDir(), "mountinfo")
    40  	err := ioutil.WriteFile(fn, []byte(content), 0644)
    41  	c.Assert(err, IsNil)
    42  	return fn
    43  }
    44  
    45  func (s *SnapSuite) TestAutoImportAssertsHappy(c *C) {
    46  	restore := release.MockOnClassic(false)
    47  	defer restore()
    48  
    49  	fakeAssertData := []byte("my-assertion")
    50  
    51  	n := 0
    52  	total := 2
    53  	s.RedirectClientToTestServer(func(w http.ResponseWriter, r *http.Request) {
    54  		switch n {
    55  		case 0:
    56  			c.Check(r.Method, Equals, "POST")
    57  			c.Check(r.URL.Path, Equals, "/v2/assertions")
    58  			postData, err := ioutil.ReadAll(r.Body)
    59  			c.Assert(err, IsNil)
    60  			c.Check(postData, DeepEquals, fakeAssertData)
    61  			fmt.Fprintln(w, `{"type": "sync", "result": {"ready": true, "status": "Done"}}`)
    62  			n++
    63  		case 1:
    64  			c.Check(r.Method, Equals, "POST")
    65  			c.Check(r.URL.Path, Equals, "/v2/create-user")
    66  			postData, err := ioutil.ReadAll(r.Body)
    67  			c.Assert(err, IsNil)
    68  			c.Check(string(postData), Equals, `{"sudoer":true,"known":true}`)
    69  
    70  			fmt.Fprintln(w, `{"type": "sync", "result": [{"username": "foo"}]}`)
    71  			n++
    72  		default:
    73  			c.Fatalf("unexpected request: %v (expected %d got %d)", r, total, n)
    74  		}
    75  
    76  	})
    77  
    78  	fakeAssertsFn := filepath.Join(c.MkDir(), "auto-import.assert")
    79  	err := ioutil.WriteFile(fakeAssertsFn, fakeAssertData, 0644)
    80  	c.Assert(err, IsNil)
    81  
    82  	mockMountInfoFmt := `
    83  24 0 8:18 / %s rw,relatime shared:1 - ext4 /dev/sdb2 rw,errors=remount-ro,data=ordered`
    84  	content := fmt.Sprintf(mockMountInfoFmt, filepath.Dir(fakeAssertsFn))
    85  	restore = snap.MockMountInfoPath(makeMockMountInfo(c, content))
    86  	defer restore()
    87  
    88  	logbuf, restore := logger.MockLogger()
    89  	defer restore()
    90  
    91  	rest, err := snap.Parser(snap.Client()).ParseArgs([]string{"auto-import"})
    92  	c.Assert(err, IsNil)
    93  	c.Assert(rest, DeepEquals, []string{})
    94  	c.Check(s.Stdout(), Equals, `created user "foo"`+"\n")
    95  	// matches because we may get a:
    96  	//   "WARNING: cannot create syslog logger\n"
    97  	// in the output
    98  	c.Check(logbuf.String(), Matches, fmt.Sprintf("(?ms).*imported %s\n", fakeAssertsFn))
    99  	c.Check(n, Equals, total)
   100  }
   101  
   102  func (s *SnapSuite) TestAutoImportAssertsNotImportedFromLoop(c *C) {
   103  	restore := release.MockOnClassic(false)
   104  	defer restore()
   105  
   106  	fakeAssertData := []byte("bad-assertion")
   107  
   108  	s.RedirectClientToTestServer(func(w http.ResponseWriter, r *http.Request) {
   109  		// assertion is ignored, nothing is posted to this endpoint
   110  		panic("not reached")
   111  	})
   112  
   113  	fakeAssertsFn := filepath.Join(c.MkDir(), "auto-import.assert")
   114  	err := ioutil.WriteFile(fakeAssertsFn, fakeAssertData, 0644)
   115  	c.Assert(err, IsNil)
   116  
   117  	mockMountInfoFmtWithLoop := `
   118  24 0 8:18 / %s rw,relatime shared:1 - squashfs /dev/loop1 rw,errors=remount-ro,data=ordered`
   119  	content := fmt.Sprintf(mockMountInfoFmtWithLoop, filepath.Dir(fakeAssertsFn))
   120  	restore = snap.MockMountInfoPath(makeMockMountInfo(c, content))
   121  	defer restore()
   122  
   123  	rest, err := snap.Parser(snap.Client()).ParseArgs([]string{"auto-import"})
   124  	c.Assert(err, IsNil)
   125  	c.Assert(rest, DeepEquals, []string{})
   126  	c.Check(s.Stdout(), Equals, "")
   127  	c.Check(s.Stderr(), Equals, "")
   128  }
   129  
   130  func (s *SnapSuite) TestAutoImportCandidatesHappy(c *C) {
   131  	dirs := make([]string, 4)
   132  	args := make([]interface{}, len(dirs))
   133  	files := make([]string, len(dirs))
   134  	for i := range dirs {
   135  		dirs[i] = c.MkDir()
   136  		args[i] = dirs[i]
   137  		files[i] = filepath.Join(dirs[i], "auto-import.assert")
   138  		err := ioutil.WriteFile(files[i], nil, 0644)
   139  		c.Assert(err, IsNil)
   140  	}
   141  
   142  	mockMountInfoFmtWithLoop := `
   143  too short
   144  24 0 8:18 / %[1]s rw,relatime foo ext3 /dev/meep2 no,separator
   145  24 0 8:18 / %[2]s rw,relatime - ext3 /dev/meep2 rw,errors=remount-ro,data=ordered
   146  24 0 8:18 / %[3]s rw,relatime opt:1 - ext4 /dev/meep3 rw,errors=remount-ro,data=ordered
   147  24 0 8:18 / %[4]s rw,relatime opt:1 opt:2 - ext2 /dev/meep1 rw,errors=remount-ro,data=ordered
   148  `
   149  
   150  	content := fmt.Sprintf(mockMountInfoFmtWithLoop, args...)
   151  	restore := snap.MockMountInfoPath(makeMockMountInfo(c, content))
   152  	defer restore()
   153  
   154  	l, err := snap.AutoImportCandidates()
   155  	c.Check(err, IsNil)
   156  	c.Check(l, DeepEquals, files[1:])
   157  }
   158  
   159  func (s *SnapSuite) TestAutoImportAssertsHappyNotOnClassic(c *C) {
   160  	restore := release.MockOnClassic(true)
   161  	defer restore()
   162  
   163  	fakeAssertData := []byte("my-assertion")
   164  	s.RedirectClientToTestServer(func(w http.ResponseWriter, r *http.Request) {
   165  		c.Errorf("auto-import on classic is disabled, but something tried to do a %q with %s", r.Method, r.URL.Path)
   166  	})
   167  
   168  	fakeAssertsFn := filepath.Join(c.MkDir(), "auto-import.assert")
   169  	err := ioutil.WriteFile(fakeAssertsFn, fakeAssertData, 0644)
   170  	c.Assert(err, IsNil)
   171  
   172  	mockMountInfoFmt := `
   173  24 0 8:18 / %s rw,relatime shared:1 - ext4 /dev/sdb2 rw,errors=remount-ro,data=ordered`
   174  	content := fmt.Sprintf(mockMountInfoFmt, filepath.Dir(fakeAssertsFn))
   175  	restore = snap.MockMountInfoPath(makeMockMountInfo(c, content))
   176  	defer restore()
   177  
   178  	rest, err := snap.Parser(snap.Client()).ParseArgs([]string{"auto-import"})
   179  	c.Assert(err, IsNil)
   180  	c.Assert(rest, DeepEquals, []string{})
   181  	c.Check(s.Stdout(), Equals, "")
   182  	c.Check(s.Stderr(), Equals, "auto-import is disabled on classic\n")
   183  }
   184  
   185  func (s *SnapSuite) TestAutoImportIntoSpool(c *C) {
   186  	restore := release.MockOnClassic(false)
   187  	defer restore()
   188  
   189  	logbuf, restore := logger.MockLogger()
   190  	defer restore()
   191  
   192  	fakeAssertData := []byte("good-assertion")
   193  
   194  	// ensure we can not connect
   195  	snap.ClientConfig.BaseURL = "can-not-connect-to-this-url"
   196  
   197  	fakeAssertsFn := filepath.Join(c.MkDir(), "auto-import.assert")
   198  	err := ioutil.WriteFile(fakeAssertsFn, fakeAssertData, 0644)
   199  	c.Assert(err, IsNil)
   200  
   201  	mockMountInfoFmt := `
   202  24 0 8:18 / %s rw,relatime shared:1 - squashfs /dev/sc1 rw,errors=remount-ro,data=ordered`
   203  	content := fmt.Sprintf(mockMountInfoFmt, filepath.Dir(fakeAssertsFn))
   204  	restore = snap.MockMountInfoPath(makeMockMountInfo(c, content))
   205  	defer restore()
   206  
   207  	rest, err := snap.Parser(snap.Client()).ParseArgs([]string{"auto-import"})
   208  	c.Assert(err, IsNil)
   209  	c.Assert(rest, DeepEquals, []string{})
   210  	c.Check(s.Stdout(), Equals, "")
   211  	// matches because we may get a:
   212  	//   "WARNING: cannot create syslog logger\n"
   213  	// in the output
   214  	c.Check(logbuf.String(), Matches, "(?ms).*queuing for later.*\n")
   215  
   216  	files, err := ioutil.ReadDir(dirs.SnapAssertsSpoolDir)
   217  	c.Assert(err, IsNil)
   218  	c.Check(files, HasLen, 1)
   219  	c.Check(files[0].Name(), Equals, "iOkaeet50rajLvL-0Qsf2ELrTdn3XIXRIBlDewcK02zwRi3_TJlUOTl9AaiDXmDn.assert")
   220  }
   221  
   222  func (s *SnapSuite) TestAutoImportFromSpoolHappy(c *C) {
   223  	restore := release.MockOnClassic(false)
   224  	defer restore()
   225  
   226  	fakeAssertData := []byte("my-assertion")
   227  
   228  	n := 0
   229  	total := 2
   230  	s.RedirectClientToTestServer(func(w http.ResponseWriter, r *http.Request) {
   231  		switch n {
   232  		case 0:
   233  			c.Check(r.Method, Equals, "POST")
   234  			c.Check(r.URL.Path, Equals, "/v2/assertions")
   235  			postData, err := ioutil.ReadAll(r.Body)
   236  			c.Assert(err, IsNil)
   237  			c.Check(postData, DeepEquals, fakeAssertData)
   238  			fmt.Fprintln(w, `{"type": "sync", "result": {"ready": true, "status": "Done"}}`)
   239  			n++
   240  		case 1:
   241  			c.Check(r.Method, Equals, "POST")
   242  			c.Check(r.URL.Path, Equals, "/v2/create-user")
   243  			postData, err := ioutil.ReadAll(r.Body)
   244  			c.Assert(err, IsNil)
   245  			c.Check(string(postData), Equals, `{"sudoer":true,"known":true}`)
   246  
   247  			fmt.Fprintln(w, `{"type": "sync", "result": [{"username": "foo"}]}`)
   248  			n++
   249  		default:
   250  			c.Fatalf("unexpected request: %v (expected %d got %d)", r, total, n)
   251  		}
   252  
   253  	})
   254  
   255  	fakeAssertsFn := filepath.Join(dirs.SnapAssertsSpoolDir, "1234343")
   256  	err := os.MkdirAll(filepath.Dir(fakeAssertsFn), 0755)
   257  	c.Assert(err, IsNil)
   258  	err = ioutil.WriteFile(fakeAssertsFn, fakeAssertData, 0644)
   259  	c.Assert(err, IsNil)
   260  
   261  	logbuf, restore := logger.MockLogger()
   262  	defer restore()
   263  
   264  	rest, err := snap.Parser(snap.Client()).ParseArgs([]string{"auto-import"})
   265  	c.Assert(err, IsNil)
   266  	c.Assert(rest, DeepEquals, []string{})
   267  	c.Check(s.Stdout(), Equals, `created user "foo"`+"\n")
   268  	// matches because we may get a:
   269  	//   "WARNING: cannot create syslog logger\n"
   270  	// in the output
   271  	c.Check(logbuf.String(), Matches, fmt.Sprintf("(?ms).*imported %s\n", fakeAssertsFn))
   272  	c.Check(n, Equals, total)
   273  
   274  	c.Check(osutil.FileExists(fakeAssertsFn), Equals, false)
   275  }
   276  
   277  func (s *SnapSuite) TestAutoImportIntoSpoolUnhappyTooBig(c *C) {
   278  	restore := release.MockOnClassic(false)
   279  	defer restore()
   280  
   281  	_, restoreLogger := logger.MockLogger()
   282  	defer restoreLogger()
   283  
   284  	// fake data is bigger than the default assertion limit
   285  	fakeAssertData := make([]byte, 641*1024)
   286  
   287  	// ensure we can not connect
   288  	snap.ClientConfig.BaseURL = "can-not-connect-to-this-url"
   289  
   290  	fakeAssertsFn := filepath.Join(c.MkDir(), "auto-import.assert")
   291  	err := ioutil.WriteFile(fakeAssertsFn, fakeAssertData, 0644)
   292  	c.Assert(err, IsNil)
   293  
   294  	mockMountInfoFmt := `
   295  24 0 8:18 / %s rw,relatime shared:1 - squashfs /dev/sc1 rw,errors=remount-ro,data=ordered`
   296  	content := fmt.Sprintf(mockMountInfoFmt, filepath.Dir(fakeAssertsFn))
   297  	restore = snap.MockMountInfoPath(makeMockMountInfo(c, content))
   298  	defer restore()
   299  
   300  	_, err = snap.Parser(snap.Client()).ParseArgs([]string{"auto-import"})
   301  	c.Assert(err, ErrorMatches, "cannot queue .*, file size too big: 656384")
   302  }