github.com/ruishantech/selfupdate@v1.0.3/internal/osext/osext_test.go (about)

     1  // Copyright 2012 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build darwin linux freebsd netbsd windows
     6  
     7  package osext
     8  
     9  import (
    10  	"bytes"
    11  	"fmt"
    12  	"io"
    13  	"os"
    14  	"os/exec"
    15  	"path/filepath"
    16  	"runtime"
    17  	"testing"
    18  )
    19  
    20  const (
    21  	executableEnvVar = "OSTEST_OUTPUT_EXECUTABLE"
    22  
    23  	executableEnvValueMatch  = "match"
    24  	executableEnvValueDelete = "delete"
    25  )
    26  
    27  func TestPrintExecutable(t *testing.T) {
    28  	ef, err := Executable()
    29  	if err != nil {
    30  		t.Fatalf("Executable failed: %v", err)
    31  	}
    32  	t.Log("Executable:", ef)
    33  }
    34  func TestPrintExecutableFolder(t *testing.T) {
    35  	ef, err := ExecutableFolder()
    36  	if err != nil {
    37  		t.Fatalf("ExecutableFolder failed: %v", err)
    38  	}
    39  	t.Log("Executable Folder:", ef)
    40  }
    41  func TestExecutableFolder(t *testing.T) {
    42  	ef, err := ExecutableFolder()
    43  	if err != nil {
    44  		t.Fatalf("ExecutableFolder failed: %v", err)
    45  	}
    46  	if ef[len(ef)-1] == filepath.Separator {
    47  		t.Fatal("ExecutableFolder ends with a trailing slash.")
    48  	}
    49  }
    50  func TestExecutableMatch(t *testing.T) {
    51  	ep, err := Executable()
    52  	if err != nil {
    53  		t.Fatalf("Executable failed: %v", err)
    54  	}
    55  
    56  	// fullpath to be of the form "dir/prog".
    57  	dir := filepath.Dir(filepath.Dir(ep))
    58  	fullpath, err := filepath.Rel(dir, ep)
    59  	if err != nil {
    60  		t.Fatalf("filepath.Rel: %v", err)
    61  	}
    62  	// Make child start with a relative program path.
    63  	// Alter argv[0] for child to verify getting real path without argv[0].
    64  	cmd := &exec.Cmd{
    65  		Dir:  dir,
    66  		Path: fullpath,
    67  		Env:  []string{fmt.Sprintf("%s=%s", executableEnvVar, executableEnvValueMatch)},
    68  	}
    69  	out, err := cmd.CombinedOutput()
    70  	if err != nil {
    71  		t.Fatalf("exec(self) failed: %v", err)
    72  	}
    73  	outs := string(out)
    74  	if !filepath.IsAbs(outs) {
    75  		t.Fatalf("Child returned %q, want an absolute path", out)
    76  	}
    77  	if !sameFile(outs, ep) {
    78  		t.Fatalf("Child returned %q, not the same file as %q", out, ep)
    79  	}
    80  }
    81  
    82  func TestExecutableDelete(t *testing.T) {
    83  	if runtime.GOOS != "linux" {
    84  		t.Skip()
    85  	}
    86  	fpath, err := Executable()
    87  	if err != nil {
    88  		t.Fatalf("Executable failed: %v", err)
    89  	}
    90  
    91  	r, w := io.Pipe()
    92  	stderrBuff := &bytes.Buffer{}
    93  	stdoutBuff := &bytes.Buffer{}
    94  	cmd := &exec.Cmd{
    95  		Path:   fpath,
    96  		Env:    []string{fmt.Sprintf("%s=%s", executableEnvVar, executableEnvValueDelete)},
    97  		Stdin:  r,
    98  		Stderr: stderrBuff,
    99  		Stdout: stdoutBuff,
   100  	}
   101  	err = cmd.Start()
   102  	if err != nil {
   103  		t.Fatalf("exec(self) start failed: %v", err)
   104  	}
   105  
   106  	tempPath := fpath + "_copy"
   107  	_ = os.Remove(tempPath)
   108  
   109  	err = copyFile(tempPath, fpath)
   110  	if err != nil {
   111  		t.Fatalf("copy file failed: %v", err)
   112  	}
   113  	err = os.Remove(fpath)
   114  	if err != nil {
   115  		t.Fatalf("remove running test file failed: %v", err)
   116  	}
   117  	err = os.Rename(tempPath, fpath)
   118  	if err != nil {
   119  		t.Fatalf("rename copy to previous name failed: %v", err)
   120  	}
   121  
   122  	w.Write([]byte{0})
   123  	w.Close()
   124  
   125  	err = cmd.Wait()
   126  	if err != nil {
   127  		t.Fatalf("exec wait failed: %v", err)
   128  	}
   129  
   130  	childPath := stderrBuff.String()
   131  	if !filepath.IsAbs(childPath) {
   132  		t.Fatalf("Child returned %q, want an absolute path", childPath)
   133  	}
   134  	if !sameFile(childPath, fpath) {
   135  		t.Fatalf("Child returned %q, not the same file as %q", childPath, fpath)
   136  	}
   137  }
   138  
   139  func sameFile(fn1, fn2 string) bool {
   140  	fi1, err := os.Stat(fn1)
   141  	if err != nil {
   142  		return false
   143  	}
   144  	fi2, err := os.Stat(fn2)
   145  	if err != nil {
   146  		return false
   147  	}
   148  	return os.SameFile(fi1, fi2)
   149  }
   150  func copyFile(dest, src string) error {
   151  	df, err := os.Create(dest)
   152  	if err != nil {
   153  		return err
   154  	}
   155  	defer df.Close()
   156  
   157  	sf, err := os.Open(src)
   158  	if err != nil {
   159  		return err
   160  	}
   161  	defer sf.Close()
   162  
   163  	_, err = io.Copy(df, sf)
   164  	return err
   165  }
   166  
   167  func TestMain(m *testing.M) {
   168  	env := os.Getenv(executableEnvVar)
   169  	switch env {
   170  	case "":
   171  		os.Exit(m.Run())
   172  	case executableEnvValueMatch:
   173  		// First chdir to another path.
   174  		dir := "/"
   175  		if runtime.GOOS == "windows" {
   176  			dir = filepath.VolumeName(".")
   177  		}
   178  		os.Chdir(dir)
   179  		if ep, err := Executable(); err != nil {
   180  			fmt.Fprint(os.Stderr, "ERROR: ", err)
   181  		} else {
   182  			fmt.Fprint(os.Stderr, ep)
   183  		}
   184  	case executableEnvValueDelete:
   185  		bb := make([]byte, 1)
   186  		var err error
   187  		n, err := os.Stdin.Read(bb)
   188  		if err != nil {
   189  			fmt.Fprint(os.Stderr, "ERROR: ", err)
   190  			os.Exit(2)
   191  		}
   192  		if n != 1 {
   193  			fmt.Fprint(os.Stderr, "ERROR: n != 1, n == ", n)
   194  			os.Exit(2)
   195  		}
   196  		if ep, err := Executable(); err != nil {
   197  			fmt.Fprint(os.Stderr, "ERROR: ", err)
   198  		} else {
   199  			fmt.Fprint(os.Stderr, ep)
   200  		}
   201  	}
   202  	os.Exit(0)
   203  }