github.com/fairyhunter13/air@v1.40.5/runner/util_test.go (about)

     1  package runner
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"os/exec"
     8  	"path/filepath"
     9  	"reflect"
    10  	"runtime"
    11  	"strconv"
    12  	"strings"
    13  	"syscall"
    14  	"testing"
    15  	"time"
    16  
    17  	"github.com/stretchr/testify/assert"
    18  )
    19  
    20  func TestIsDirRootPath(t *testing.T) {
    21  	result := isDir(".")
    22  	if result != true {
    23  		t.Errorf("expected '%t' but got '%t'", true, result)
    24  	}
    25  }
    26  
    27  func TestIsDirMainFile(t *testing.T) {
    28  	result := isDir("main.go")
    29  	if result != false {
    30  		t.Errorf("expected '%t' but got '%t'", true, result)
    31  	}
    32  }
    33  
    34  func TestIsDirFileNot(t *testing.T) {
    35  	result := isDir("main.go")
    36  	if result != false {
    37  		t.Errorf("expected '%t' but got '%t'", true, result)
    38  	}
    39  }
    40  
    41  func TestExpandPathWithDot(t *testing.T) {
    42  	path, _ := expandPath(".")
    43  	wd, _ := os.Getwd()
    44  	if path != wd {
    45  		t.Errorf("expected '%s' but got '%s'", wd, path)
    46  	}
    47  }
    48  
    49  func TestExpandPathWithHomePath(t *testing.T) {
    50  	path := "~/.conf"
    51  	result, _ := expandPath(path)
    52  	home := os.Getenv("HOME")
    53  	want := home + path[1:]
    54  	if result != want {
    55  		t.Errorf("expected '%s' but got '%s'", want, result)
    56  	}
    57  }
    58  
    59  func TestFileChecksum(t *testing.T) {
    60  	tests := []struct {
    61  		name                  string
    62  		fileContents          []byte
    63  		expectedChecksum      string
    64  		expectedChecksumError string
    65  	}{
    66  		{
    67  			name:                  "empty",
    68  			fileContents:          []byte(``),
    69  			expectedChecksum:      "",
    70  			expectedChecksumError: "empty file, forcing rebuild without updating checksum",
    71  		},
    72  		{
    73  			name:                  "simple",
    74  			fileContents:          []byte(`foo`),
    75  			expectedChecksum:      "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae",
    76  			expectedChecksumError: "",
    77  		},
    78  		{
    79  			name:                  "binary",
    80  			fileContents:          []byte{0xF}, // invalid UTF-8 codepoint
    81  			expectedChecksum:      "dc0e9c3658a1a3ed1ec94274d8b19925c93e1abb7ddba294923ad9bde30f8cb8",
    82  			expectedChecksumError: "",
    83  		},
    84  	}
    85  
    86  	for _, test := range tests {
    87  		t.Run(test.name, func(t *testing.T) {
    88  			f, err := os.CreateTemp("", "")
    89  			if err != nil {
    90  				t.Fatalf("couldn't create temp file for test: %v", err)
    91  			}
    92  
    93  			defer func() {
    94  				if err := f.Close(); err != nil {
    95  					t.Errorf("error closing temp file: %v", err)
    96  				}
    97  				if err := os.Remove(f.Name()); err != nil {
    98  					t.Errorf("error removing temp file: %v", err)
    99  				}
   100  			}()
   101  
   102  			_, err = f.Write(test.fileContents)
   103  			if err != nil {
   104  				t.Fatalf("couldn't write to temp file for test: %v", err)
   105  			}
   106  
   107  			checksum, err := fileChecksum(f.Name())
   108  			if err != nil && err.Error() != test.expectedChecksumError {
   109  				t.Errorf("expected '%s' but got '%s'", test.expectedChecksumError, err.Error())
   110  			}
   111  
   112  			if checksum != test.expectedChecksum {
   113  				t.Errorf("expected '%s' but got '%s'", test.expectedChecksum, checksum)
   114  			}
   115  		})
   116  	}
   117  }
   118  
   119  func TestChecksumMap(t *testing.T) {
   120  	m := &checksumMap{m: make(map[string]string, 3)}
   121  
   122  	if !m.updateFileChecksum("foo.txt", "abcxyz") {
   123  		t.Errorf("expected no entry for foo.txt, but had one")
   124  	}
   125  
   126  	if m.updateFileChecksum("foo.txt", "abcxyz") {
   127  		t.Errorf("expected matching entry for foo.txt")
   128  	}
   129  
   130  	if !m.updateFileChecksum("foo.txt", "123456") {
   131  		t.Errorf("expected matching entry for foo.txt")
   132  	}
   133  
   134  	if !m.updateFileChecksum("bar.txt", "123456") {
   135  		t.Errorf("expected no entry for bar.txt, but had one")
   136  	}
   137  }
   138  
   139  func TestAdaptToVariousPlatforms(t *testing.T) {
   140  	config := &Config{
   141  		Build: cfgBuild{
   142  			Bin: "tmp\\main.exe  -dev",
   143  		},
   144  	}
   145  	adaptToVariousPlatforms(config)
   146  	if config.Build.Bin != "tmp\\main.exe  -dev" {
   147  		t.Errorf("expected '%s' but got '%s'", "tmp\\main.exe  -dev", config.Build.Bin)
   148  	}
   149  }
   150  
   151  func Test_killCmd_no_process(t *testing.T) {
   152  	e := Engine{
   153  		config: &Config{
   154  			Build: cfgBuild{
   155  				SendInterrupt: false,
   156  			},
   157  		},
   158  	}
   159  	_, err := e.killCmd(&exec.Cmd{
   160  		Process: &os.Process{
   161  			Pid: 9999,
   162  		},
   163  	})
   164  	if err == nil {
   165  		t.Errorf("expected error but got none")
   166  	}
   167  	if !errors.Is(err, syscall.ESRCH) {
   168  		t.Errorf("expected '%s' but got '%s'", syscall.ESRCH, errors.Unwrap(err))
   169  	}
   170  }
   171  
   172  func Test_killCmd_SendInterrupt_false(t *testing.T) {
   173  	_, b, _, _ := runtime.Caller(0)
   174  
   175  	// Root folder of this project
   176  	dir := filepath.Dir(b)
   177  	err := os.Chdir(dir)
   178  	if err != nil {
   179  		t.Fatalf("couldn't change directory: %v", err)
   180  	}
   181  
   182  	// clean file before test
   183  	os.Remove("pid")
   184  	defer os.Remove("pid")
   185  	e := Engine{
   186  		config: &Config{
   187  			Build: cfgBuild{
   188  				SendInterrupt: false,
   189  			},
   190  		},
   191  	}
   192  	startChan := make(chan struct {
   193  		pid int
   194  		cmd *exec.Cmd
   195  	})
   196  	go func() {
   197  		cmd, _, _, err := e.startCmd("sh _testdata/run-many-processes.sh")
   198  		if err != nil {
   199  			t.Errorf("failed to start command: %v", err)
   200  			return
   201  		}
   202  		pid := cmd.Process.Pid
   203  		t.Logf("process pid is %v", pid)
   204  		startChan <- struct {
   205  			pid int
   206  			cmd *exec.Cmd
   207  		}{pid: pid, cmd: cmd}
   208  		cmd.Wait()
   209  		t.Logf("wait finished")
   210  	}()
   211  	resp := <-startChan
   212  	t.Logf("process started. checking pid %v", resp.pid)
   213  	time.Sleep(2 * time.Second)
   214  	t.Logf("%v", resp.cmd.Process.Pid)
   215  	pid, err := e.killCmd(resp.cmd)
   216  	if err != nil {
   217  		t.Fatalf("failed to kill command: %v", err)
   218  	}
   219  	t.Logf("%v was been killed", pid)
   220  	// check processes were being killed
   221  	// read pids from file
   222  	bytesRead, _ := os.ReadFile("pid")
   223  	lines := strings.Split(string(bytesRead), "\n")
   224  	for _, line := range lines {
   225  		_, err := strconv.Atoi(line)
   226  		if err != nil {
   227  			t.Logf("failed to covert str to int %v", err)
   228  			continue
   229  		}
   230  		_, err = exec.Command("ps", "-p", line, "-o", "comm= ").Output()
   231  		if err == nil {
   232  			t.Fatalf("process should be killed %v", line)
   233  		}
   234  	}
   235  }
   236  
   237  func TestGetStructureFieldTagMap(t *testing.T) {
   238  	c := Config{}
   239  	tagMap := flatConfig(c)
   240  	for _, i2 := range tagMap {
   241  		fmt.Printf("%v\n", i2.fieldPath)
   242  	}
   243  }
   244  
   245  func TestSetStructValue(t *testing.T) {
   246  	c := Config{}
   247  	v := reflect.ValueOf(&c)
   248  	setValue2Struct(v, "TmpDir", "asdasd")
   249  	assert.Equal(t, "asdasd", c.TmpDir)
   250  }
   251  
   252  func TestNestStructValue(t *testing.T) {
   253  	c := Config{}
   254  	v := reflect.ValueOf(&c)
   255  	setValue2Struct(v, "Build.Cmd", "asdasd")
   256  	assert.Equal(t, "asdasd", c.Build.Cmd)
   257  }
   258  
   259  func TestNestStructArrayValue(t *testing.T) {
   260  	c := Config{}
   261  	v := reflect.ValueOf(&c)
   262  	setValue2Struct(v, "Build.ExcludeDir", "dir1,dir2")
   263  	assert.Equal(t, []string{"dir1", "dir2"}, c.Build.ExcludeDir)
   264  }
   265  
   266  func TestNestStructArrayValueOverride(t *testing.T) {
   267  	c := Config{
   268  		Build: cfgBuild{
   269  			ExcludeDir: []string{"default1", "default2"},
   270  		},
   271  	}
   272  	v := reflect.ValueOf(&c)
   273  	setValue2Struct(v, "Build.ExcludeDir", "dir1,dir2")
   274  	assert.Equal(t, []string{"dir1", "dir2"}, c.Build.ExcludeDir)
   275  }