github.com/ethanhsieh/snapd@v0.0.0-20210615102523-3db9b8e4edc5/osutil/export_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 osutil
    21  
    22  import (
    23  	"fmt"
    24  	"io"
    25  	"io/ioutil"
    26  	"os"
    27  	"os/exec"
    28  	"os/user"
    29  	"syscall"
    30  	"time"
    31  
    32  	"github.com/snapcore/snapd/osutil/sys"
    33  	"github.com/snapcore/snapd/strutil"
    34  )
    35  
    36  var (
    37  	StreamsEqualChunked  = streamsEqualChunked
    38  	FilesAreEqualChunked = filesAreEqualChunked
    39  	SudoersFile          = sudoersFile
    40  	DoCopyFile           = doCopyFile
    41  )
    42  
    43  type Fileish = fileish
    44  
    45  func MockMaxCp(new int64) (restore func()) {
    46  	old := maxcp
    47  	maxcp = new
    48  	return func() {
    49  		maxcp = old
    50  	}
    51  }
    52  
    53  func MockCopyFile(new func(fileish, fileish, os.FileInfo) error) (restore func()) {
    54  	old := copyfile
    55  	copyfile = new
    56  	return func() {
    57  		copyfile = old
    58  	}
    59  }
    60  
    61  func MockOpenFile(new func(string, int, os.FileMode) (fileish, error)) (restore func()) {
    62  	old := openfile
    63  	openfile = new
    64  	return func() {
    65  		openfile = old
    66  	}
    67  }
    68  
    69  func MockSyscallSettimeofday(f func(*syscall.Timeval) error) (restore func()) {
    70  	old := syscallSettimeofday
    71  	syscallSettimeofday = f
    72  	return func() {
    73  		syscallSettimeofday = old
    74  	}
    75  }
    76  
    77  func MockUserLookup(mock func(name string) (*user.User, error)) func() {
    78  	realUserLookup := userLookup
    79  	userLookup = mock
    80  
    81  	return func() { userLookup = realUserLookup }
    82  }
    83  
    84  func MockUserCurrent(mock func() (*user.User, error)) func() {
    85  	realUserCurrent := userCurrent
    86  	userCurrent = mock
    87  
    88  	return func() { userCurrent = realUserCurrent }
    89  }
    90  
    91  func MockSudoersDotD(mockDir string) func() {
    92  	realSudoersD := sudoersDotD
    93  	sudoersDotD = mockDir
    94  
    95  	return func() { sudoersDotD = realSudoersD }
    96  }
    97  
    98  func MockSyscallKill(f func(int, syscall.Signal) error) func() {
    99  	oldSyscallKill := syscallKill
   100  	syscallKill = f
   101  	return func() {
   102  		syscallKill = oldSyscallKill
   103  	}
   104  }
   105  
   106  func MockSyscallStatfs(f func(string, *syscall.Statfs_t) error) func() {
   107  	oldSyscallStatfs := syscallStatfs
   108  	syscallStatfs = f
   109  	return func() {
   110  		syscallStatfs = oldSyscallStatfs
   111  	}
   112  }
   113  
   114  func MockSyscallGetpgid(f func(int) (int, error)) func() {
   115  	oldSyscallGetpgid := syscallGetpgid
   116  	syscallGetpgid = f
   117  	return func() {
   118  		syscallGetpgid = oldSyscallGetpgid
   119  	}
   120  }
   121  
   122  func MockCmdWaitTimeout(timeout time.Duration) func() {
   123  	oldCmdWaitTimeout := cmdWaitTimeout
   124  	cmdWaitTimeout = timeout
   125  	return func() {
   126  		cmdWaitTimeout = oldCmdWaitTimeout
   127  	}
   128  }
   129  
   130  func WaitingReaderGuts(r io.Reader) (io.Reader, *exec.Cmd) {
   131  	wr := r.(*waitingReader)
   132  	return wr.reader, wr.cmd
   133  }
   134  
   135  func MockChown(f func(*os.File, sys.UserID, sys.GroupID) error) func() {
   136  	oldChown := chown
   137  	chown = f
   138  	return func() {
   139  		chown = oldChown
   140  	}
   141  }
   142  
   143  func MockLookPath(new func(string) (string, error)) (restore func()) {
   144  	old := lookPath
   145  	lookPath = new
   146  	return func() {
   147  		lookPath = old
   148  	}
   149  }
   150  
   151  func SetAtomicFileRenamed(aw *AtomicFile, renamed bool) {
   152  	aw.renamed = renamed
   153  }
   154  
   155  func SetUnsafeIO(b bool) func() {
   156  	oldSnapdUnsafeIO := snapdUnsafeIO
   157  	snapdUnsafeIO = b
   158  	return func() {
   159  		snapdUnsafeIO = oldSnapdUnsafeIO
   160  	}
   161  }
   162  
   163  func GetUnsafeIO() bool {
   164  	// a getter so that tests do not attempt to modify that directly
   165  	return snapdUnsafeIO
   166  }
   167  
   168  func MockOsReadlink(f func(string) (string, error)) func() {
   169  	realOsReadlink := osReadlink
   170  	osReadlink = f
   171  
   172  	return func() { osReadlink = realOsReadlink }
   173  }
   174  
   175  // MockEtcFstab mocks content of /etc/fstab read by IsHomeUsingNFS
   176  func MockEtcFstab(text string) (restore func()) {
   177  	old := etcFstab
   178  	f, err := ioutil.TempFile("", "fstab")
   179  	if err != nil {
   180  		panic(fmt.Errorf("cannot open temporary file: %s", err))
   181  	}
   182  	if err := ioutil.WriteFile(f.Name(), []byte(text), 0644); err != nil {
   183  		panic(fmt.Errorf("cannot write mock fstab file: %s", err))
   184  	}
   185  	etcFstab = f.Name()
   186  	return func() {
   187  		if etcFstab == "/etc/fstab" {
   188  			panic("respectfully refusing to remove /etc/fstab")
   189  		}
   190  		os.Remove(etcFstab)
   191  		etcFstab = old
   192  	}
   193  }
   194  
   195  // MockUname mocks syscall.Uname as used by MachineName and KernelVersion
   196  func MockUname(f func(*syscall.Utsname) error) (restore func()) {
   197  	old := syscallUname
   198  	syscallUname = f
   199  
   200  	return func() {
   201  		syscallUname = old
   202  	}
   203  }
   204  
   205  var (
   206  	FindUidNoGetentFallback = findUidNoGetentFallback
   207  	FindGidNoGetentFallback = findGidNoGetentFallback
   208  
   209  	FindUidWithGetentFallback = findUidWithGetentFallback
   210  	FindGidWithGetentFallback = findGidWithGetentFallback
   211  )
   212  
   213  func MockFindUidNoFallback(mock func(name string) (uint64, error)) (restore func()) {
   214  	old := findUidNoGetentFallback
   215  	findUidNoGetentFallback = mock
   216  	return func() { findUidNoGetentFallback = old }
   217  }
   218  
   219  func MockFindGidNoFallback(mock func(name string) (uint64, error)) (restore func()) {
   220  	old := findGidNoGetentFallback
   221  	findGidNoGetentFallback = mock
   222  	return func() { findGidNoGetentFallback = old }
   223  }
   224  
   225  const MaxSymlinkTries = maxSymlinkTries
   226  
   227  var ParseRawEnvironment = parseRawEnvironment
   228  
   229  // ParseRawExpandableEnv returns a new expandable environment parsed from key=value strings.
   230  func ParseRawExpandableEnv(entries []string) (ExpandableEnv, error) {
   231  	om := strutil.NewOrderedMap()
   232  	for _, entry := range entries {
   233  		key, value, err := parseEnvEntry(entry)
   234  		if err != nil {
   235  			return ExpandableEnv{}, err
   236  		}
   237  		if om.Get(key) != "" {
   238  			return ExpandableEnv{}, fmt.Errorf("cannot overwrite earlier value of %q", key)
   239  		}
   240  		om.Set(key, value)
   241  	}
   242  	return ExpandableEnv{OrderedMap: om}, nil
   243  }
   244  
   245  // this is weird to use in a test, but it is so that we can test the actual
   246  // implementation of LoadMountInfo, which normally panics during tests if not
   247  // properly mocked
   248  func MountInfoMustMock(new bool) (restore func()) {
   249  	old := mountInfoMustMockInTests
   250  	mountInfoMustMockInTests = new
   251  	return func() {
   252  		mountInfoMustMockInTests = old
   253  	}
   254  }
   255  
   256  // this should not be used except to test the actual implementation logic of
   257  // LoadMountInfo, if you are trying to mock /proc/self/mountinfo in a test,
   258  // use MockMountInfo(), which is exported and the right way to do that.
   259  func MockProcSelfMountInfoLocation(new string) (restore func()) {
   260  	old := procSelfMountInfo
   261  	procSelfMountInfo = new
   262  	return func() {
   263  		procSelfMountInfo = old
   264  	}
   265  }