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 }