src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/daemon/activate_test.go (about)

     1  package daemon
     2  
     3  import (
     4  	"io"
     5  	"net"
     6  	"os"
     7  	"runtime"
     8  	"testing"
     9  	"time"
    10  
    11  	"src.elv.sh/pkg/daemon/daemondefs"
    12  	"src.elv.sh/pkg/must"
    13  	"src.elv.sh/pkg/testutil"
    14  )
    15  
    16  func TestActivate_ConnectsToExistingServer(t *testing.T) {
    17  	setup(t)
    18  	startServer(t, cli("sock", "db"))
    19  	_, err := Activate(io.Discard,
    20  		&daemondefs.SpawnConfig{DbPath: "db", SockPath: "sock", RunDir: "."})
    21  	if err != nil {
    22  		t.Errorf("got error %v, want nil", err)
    23  	}
    24  }
    25  
    26  func TestActivate_SpawnsNewServer(t *testing.T) {
    27  	activated := 0
    28  	setupForActivate(t, func(name string, argv []string, attr *os.ProcAttr) error {
    29  		startServer(t, argv)
    30  		activated++
    31  		return nil
    32  	})
    33  
    34  	_, err := Activate(io.Discard,
    35  		&daemondefs.SpawnConfig{DbPath: "db", SockPath: "sock", RunDir: "."})
    36  	if err != nil {
    37  		t.Errorf("got error %v, want nil", err)
    38  	}
    39  	if activated != 1 {
    40  		t.Errorf("got activated %v times, want 1", activated)
    41  	}
    42  }
    43  
    44  func TestActivate_RemovesHangingSocketAndSpawnsNewServer(t *testing.T) {
    45  	activated := 0
    46  	setupForActivate(t, func(name string, argv []string, attr *os.ProcAttr) error {
    47  		startServer(t, argv)
    48  		activated++
    49  		return nil
    50  	})
    51  	makeHangingUnixSocket(t, "sock")
    52  
    53  	_, err := Activate(io.Discard,
    54  		&daemondefs.SpawnConfig{DbPath: "db", SockPath: "sock", RunDir: "."})
    55  	if err != nil {
    56  		t.Errorf("got error %v, want nil", err)
    57  	}
    58  	if activated != 1 {
    59  		t.Errorf("got activated %v times, want 1", activated)
    60  	}
    61  }
    62  
    63  func TestActivate_FailsIfCannotStatSock(t *testing.T) {
    64  	setup(t)
    65  	// Build a path for which Lstat will return a non-nil err such that
    66  	// os.IsNotExist(err) is false.
    67  	badSockPath := ""
    68  	if runtime.GOOS != "windows" {
    69  		// POSIX lstat(2) returns ENOTDIR instead of ENOENT if a path prefix is
    70  		// not a directory.
    71  		must.CreateEmpty("not-dir")
    72  		badSockPath = "not-dir/sock"
    73  	} else {
    74  		// Use a syntactically invalid drive letter on Windows.
    75  		badSockPath = `CD:\sock`
    76  	}
    77  	_, err := Activate(io.Discard,
    78  		&daemondefs.SpawnConfig{DbPath: "db", SockPath: badSockPath, RunDir: "."})
    79  	if err == nil {
    80  		t.Errorf("got error nil, want non-nil")
    81  	}
    82  }
    83  
    84  func TestActivate_FailsIfCannotDialSock(t *testing.T) {
    85  	setup(t)
    86  	must.CreateEmpty("sock")
    87  	_, err := Activate(io.Discard,
    88  		&daemondefs.SpawnConfig{DbPath: "db", SockPath: "sock", RunDir: "."})
    89  	if err == nil {
    90  		t.Errorf("got error nil, want non-nil")
    91  	}
    92  }
    93  
    94  func setupForActivate(t *testing.T, f func(string, []string, *os.ProcAttr) error) {
    95  	setup(t)
    96  
    97  	testutil.Set(t, &startProcess, f)
    98  	scaleDuration(t, &daemonSpawnTimeout)
    99  	scaleDuration(t, &daemonKillTimeout)
   100  }
   101  
   102  func scaleDuration(t *testing.T, d *time.Duration) {
   103  	testutil.Set(t, d, testutil.Scaled(*d))
   104  }
   105  
   106  func makeHangingUnixSocket(t *testing.T, path string) {
   107  	t.Helper()
   108  
   109  	l, err := net.Listen("unix", path)
   110  	if err != nil {
   111  		t.Fatal(err)
   112  	}
   113  	// We need to call l.Close() to make the socket hang, but that will
   114  	// helpfully remove the socket file. Work around this by renaming the socket
   115  	// file.
   116  	err = os.Rename(path, path+".save")
   117  	if err != nil {
   118  		t.Fatal(err)
   119  	}
   120  	l.Close()
   121  	err = os.Rename(path+".save", path)
   122  	if err != nil {
   123  		t.Fatal(err)
   124  	}
   125  }