github.com/angenalZZZ/gofunc@v0.0.0-20210507121333-48ff1be3917b/f/death_unix_test.go (about)

     1  // +build linux bsd darwin
     2  
     3  package f_test
     4  
     5  import (
     6  	"fmt"
     7  	"os"
     8  	"syscall"
     9  	"testing"
    10  	"time"
    11  
    12  	. "github.com/smartystreets/goconvey/convey"
    13  )
    14  
    15  type Unhashable map[string]interface{}
    16  
    17  func (u Unhashable) Close() error {
    18  	return nil
    19  }
    20  
    21  func TestDeath(t *testing.T) {
    22  	Convey("Validate death handles unhashable types", t, func() {
    23  		u := make(Unhashable)
    24  		death := NewDeath(syscall.SIGTERM)
    25  		syscall.Kill(os.Getpid(), syscall.SIGTERM)
    26  		err := death.WaitForDeath(u)
    27  		So(err, ShouldBeNil)
    28  	})
    29  
    30  	Convey("Validate death happens cleanly", t, func() {
    31  		death := NewDeath(syscall.SIGTERM)
    32  		syscall.Kill(os.Getpid(), syscall.SIGTERM)
    33  		err := death.WaitForDeath()
    34  		So(err, ShouldBeNil)
    35  	})
    36  
    37  	Convey("Validate death happens with other signals", t, func() {
    38  		death := NewDeath(syscall.SIGHUP)
    39  		closeMe := &CloseMe{}
    40  		syscall.Kill(os.Getpid(), syscall.SIGHUP)
    41  		err := death.WaitForDeath(closeMe)
    42  		So(err, ShouldBeNil)
    43  		So(closeMe.Closed, ShouldEqual, 1)
    44  	})
    45  
    46  	Convey("Validate death happens with a manual call", t, func() {
    47  		death := NewDeath(syscall.SIGHUP)
    48  		closeMe := &CloseMe{}
    49  		death.FallOnSword()
    50  		err := death.WaitForDeath(closeMe)
    51  		So(err, ShouldBeNil)
    52  		So(closeMe.Closed, ShouldEqual, 1)
    53  	})
    54  
    55  	Convey("Validate multiple sword falls do not block", t, func() {
    56  		death := NewDeath(syscall.SIGHUP)
    57  		closeMe := &CloseMe{}
    58  		death.FallOnSword()
    59  		death.FallOnSword()
    60  		err := death.WaitForDeath(closeMe)
    61  		So(err, ShouldBeNil)
    62  		So(closeMe.Closed, ShouldEqual, 1)
    63  	})
    64  
    65  	Convey("Validate multiple sword falls do not block even after we have exited waitForDeath", t, func() {
    66  		death := NewDeath(syscall.SIGHUP)
    67  		closeMe := &CloseMe{}
    68  		death.FallOnSword()
    69  		death.FallOnSword()
    70  		err := death.WaitForDeath(closeMe)
    71  		So(err, ShouldBeNil)
    72  		death.FallOnSword()
    73  		death.FallOnSword()
    74  		So(closeMe.Closed, ShouldEqual, 1)
    75  	})
    76  
    77  	Convey("Validate death gives up after timeout", t, func() {
    78  		death := NewDeath(syscall.SIGHUP)
    79  		death.SetTimeout(10 * time.Millisecond)
    80  		neverClose := &neverClose{}
    81  		syscall.Kill(os.Getpid(), syscall.SIGHUP)
    82  		err := death.WaitForDeath(neverClose)
    83  		So(err, ShouldNotBeNil)
    84  	})
    85  
    86  	Convey("Validate death uses new logger", t, func() {
    87  		death := NewDeath(syscall.SIGHUP)
    88  		closeMe := &CloseMe{}
    89  		logger := &MockLogger{}
    90  		death.SetLogger(logger)
    91  
    92  		syscall.Kill(os.Getpid(), syscall.SIGHUP)
    93  		err := death.WaitForDeath(closeMe)
    94  		So(err, ShouldBeNil)
    95  		So(closeMe.Closed, ShouldEqual, 1)
    96  		So(logger.Logs, ShouldNotBeEmpty)
    97  	})
    98  
    99  	Convey("Close multiple things with one that fails the timer", t, func() {
   100  		death := NewDeath(syscall.SIGHUP)
   101  		death.SetTimeout(10 * time.Millisecond)
   102  		neverClose := &neverClose{}
   103  		closeMe := &CloseMe{}
   104  		syscall.Kill(os.Getpid(), syscall.SIGHUP)
   105  		err := death.WaitForDeath(neverClose, closeMe)
   106  		So(err, ShouldNotBeNil)
   107  		So(closeMe.Closed, ShouldEqual, 1)
   108  	})
   109  
   110  	Convey("Close with anonymous function", t, func() {
   111  		death := NewDeath(syscall.SIGHUP)
   112  		death.SetTimeout(5 * time.Millisecond)
   113  		closeMe := &CloseMe{}
   114  		syscall.Kill(os.Getpid(), syscall.SIGHUP)
   115  		death.WaitForDeathWithFunc(func() {
   116  			closeMe.Close()
   117  			So(true, ShouldBeTrue)
   118  		})
   119  		So(closeMe.Closed, ShouldEqual, 1)
   120  	})
   121  
   122  	Convey("Validate death errors when closer returns error", t, func() {
   123  		death := NewDeath(syscall.SIGHUP)
   124  		killMe := &KillMe{}
   125  		death.FallOnSword()
   126  		err := death.WaitForDeath(killMe)
   127  		So(err, ShouldNotBeNil)
   128  	})
   129  
   130  }
   131  
   132  func TestGenerateErrString(t *testing.T) {
   133  	Convey("Generate for multiple errors", t, func() {
   134  		closers := []closer{
   135  			closer{
   136  				Err:     fmt.Errorf("error 1"),
   137  				Name:    "foo",
   138  				PKGPath: "my/pkg",
   139  			},
   140  			closer{
   141  				Err:     fmt.Errorf("error 2"),
   142  				Name:    "bar",
   143  				PKGPath: "my/otherpkg",
   144  			},
   145  		}
   146  
   147  		expected := "my/pkg/foo: error 1, my/otherpkg/bar: error 2"
   148  		actual := generateErrString(closers)
   149  
   150  		So(actual, ShouldEqual, expected)
   151  	})
   152  
   153  	Convey("Generate for single error", t, func() {
   154  		closers := []closer{
   155  			closer{
   156  				Err:     fmt.Errorf("error 1"),
   157  				Name:    "foo",
   158  				PKGPath: "my/pkg",
   159  			},
   160  		}
   161  
   162  		expected := "my/pkg/foo: error 1"
   163  		actual := generateErrString(closers)
   164  
   165  		So(actual, ShouldEqual, expected)
   166  	})
   167  }
   168  
   169  type MockLogger struct {
   170  	Logs []interface{}
   171  }
   172  
   173  func (l *MockLogger) Info(v ...interface{}) {
   174  	for _, log := range v {
   175  		l.Logs = append(l.Logs, log)
   176  	}
   177  }
   178  
   179  func (l *MockLogger) Debug(v ...interface{}) {
   180  	for _, log := range v {
   181  		l.Logs = append(l.Logs, log)
   182  	}
   183  }
   184  
   185  func (l *MockLogger) Error(v ...interface{}) {
   186  	for _, log := range v {
   187  		l.Logs = append(l.Logs, log)
   188  	}
   189  }
   190  
   191  func (l *MockLogger) Warn(v ...interface{}) {
   192  	for _, log := range v {
   193  		l.Logs = append(l.Logs, log)
   194  	}
   195  }
   196  
   197  type neverClose struct {
   198  }
   199  
   200  func (n *neverClose) Close() error {
   201  	time.Sleep(2 * time.Minute)
   202  	return nil
   203  }
   204  
   205  // CloseMe returns nil from close
   206  type CloseMe struct {
   207  	Closed int
   208  }
   209  
   210  func (c *CloseMe) Close() error {
   211  	c.Closed++
   212  	return nil
   213  }
   214  
   215  // KillMe returns an error from close
   216  type KillMe struct{}
   217  
   218  func (c *KillMe) Close() error {
   219  	return fmt.Errorf("error from closer")
   220  }