github.com/iqoqo/nomad@v0.11.3-0.20200911112621-d7021c74d101/client/logmon/logmon_test.go (about) 1 package logmon 2 3 import ( 4 "crypto/rand" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 "runtime" 10 "testing" 11 12 "github.com/hashicorp/nomad/client/lib/fifo" 13 "github.com/hashicorp/nomad/helper/testlog" 14 "github.com/hashicorp/nomad/helper/uuid" 15 "github.com/hashicorp/nomad/testutil" 16 "github.com/stretchr/testify/require" 17 ) 18 19 func TestLogmon_Start_rotate(t *testing.T) { 20 require := require.New(t) 21 var stdoutFifoPath, stderrFifoPath string 22 23 dir, err := ioutil.TempDir("", "nomadtest") 24 require.NoError(err) 25 defer os.RemoveAll(dir) 26 27 if runtime.GOOS == "windows" { 28 stdoutFifoPath = "//./pipe/test-rotate.stdout" 29 stderrFifoPath = "//./pipe/test-rotate.stderr" 30 } else { 31 stdoutFifoPath = filepath.Join(dir, "stdout.fifo") 32 stderrFifoPath = filepath.Join(dir, "stderr.fifo") 33 } 34 35 cfg := &LogConfig{ 36 LogDir: dir, 37 StdoutLogFile: "stdout", 38 StdoutFifo: stdoutFifoPath, 39 StderrLogFile: "stderr", 40 StderrFifo: stderrFifoPath, 41 MaxFiles: 2, 42 MaxFileSizeMB: 1, 43 } 44 45 lm := NewLogMon(testlog.HCLogger(t)) 46 require.NoError(lm.Start(cfg)) 47 48 stdout, err := fifo.OpenWriter(stdoutFifoPath) 49 require.NoError(err) 50 51 // Write enough bytes such that the log is rotated 52 bytes1MB := make([]byte, 1024*1024) 53 _, err = rand.Read(bytes1MB) 54 require.NoError(err) 55 56 _, err = stdout.Write(bytes1MB) 57 require.NoError(err) 58 59 testutil.WaitForResult(func() (bool, error) { 60 _, err = os.Stat(filepath.Join(dir, "stdout.0")) 61 return err == nil, err 62 }, func(err error) { 63 require.NoError(err) 64 }) 65 testutil.WaitForResult(func() (bool, error) { 66 _, err = os.Stat(filepath.Join(dir, "stdout.1")) 67 return err == nil, err 68 }, func(err error) { 69 require.NoError(err) 70 }) 71 _, err = os.Stat(filepath.Join(dir, "stdout.2")) 72 require.Error(err) 73 require.NoError(lm.Stop()) 74 require.NoError(lm.Stop()) 75 } 76 77 // asserts that calling Start twice restarts the log rotator and that any logs 78 // published while the listener was unavailable are received. 79 func TestLogmon_Start_restart_flusheslogs(t *testing.T) { 80 if runtime.GOOS == "windows" { 81 t.Skip("windows does not support pushing data to a pipe with no servers") 82 } 83 84 require := require.New(t) 85 var stdoutFifoPath, stderrFifoPath string 86 87 dir, err := ioutil.TempDir("", "nomadtest") 88 require.NoError(err) 89 defer os.RemoveAll(dir) 90 91 if runtime.GOOS == "windows" { 92 stdoutFifoPath = "//./pipe/test-restart.stdout" 93 stderrFifoPath = "//./pipe/test-restart.stderr" 94 } else { 95 stdoutFifoPath = filepath.Join(dir, "stdout.fifo") 96 stderrFifoPath = filepath.Join(dir, "stderr.fifo") 97 } 98 99 cfg := &LogConfig{ 100 LogDir: dir, 101 StdoutLogFile: "stdout", 102 StdoutFifo: stdoutFifoPath, 103 StderrLogFile: "stderr", 104 StderrFifo: stderrFifoPath, 105 MaxFiles: 2, 106 MaxFileSizeMB: 1, 107 } 108 109 lm := NewLogMon(testlog.HCLogger(t)) 110 impl, ok := lm.(*logmonImpl) 111 require.True(ok) 112 require.NoError(lm.Start(cfg)) 113 114 stdout, err := fifo.OpenWriter(stdoutFifoPath) 115 require.NoError(err) 116 stderr, err := fifo.OpenWriter(stderrFifoPath) 117 require.NoError(err) 118 119 // Write a string and assert it was written to the file 120 _, err = stdout.Write([]byte("test\n")) 121 require.NoError(err) 122 123 testutil.WaitForResult(func() (bool, error) { 124 raw, err := ioutil.ReadFile(filepath.Join(dir, "stdout.0")) 125 if err != nil { 126 return false, err 127 } 128 return "test\n" == string(raw), fmt.Errorf("unexpected stdout %q", string(raw)) 129 }, func(err error) { 130 require.NoError(err) 131 }) 132 require.True(impl.tl.IsRunning()) 133 134 // Close stdout and assert that logmon no longer writes to the file 135 require.NoError(stdout.Close()) 136 require.NoError(stderr.Close()) 137 138 testutil.WaitForResult(func() (bool, error) { 139 return !impl.tl.IsRunning(), fmt.Errorf("logmon is still running") 140 }, func(err error) { 141 require.NoError(err) 142 }) 143 144 stdout, err = fifo.OpenWriter(stdoutFifoPath) 145 require.NoError(err) 146 stderr, err = fifo.OpenWriter(stderrFifoPath) 147 require.NoError(err) 148 149 _, err = stdout.Write([]byte("te")) 150 require.NoError(err) 151 152 testutil.WaitForResult(func() (bool, error) { 153 raw, err := ioutil.ReadFile(filepath.Join(dir, "stdout.0")) 154 if err != nil { 155 return false, err 156 } 157 return "test\n" == string(raw), fmt.Errorf("unexpected stdout %q", string(raw)) 158 }, func(err error) { 159 require.NoError(err) 160 }) 161 162 // Start logmon again and assert that it appended to the file 163 require.NoError(lm.Start(cfg)) 164 165 stdout, err = fifo.OpenWriter(stdoutFifoPath) 166 require.NoError(err) 167 stderr, err = fifo.OpenWriter(stderrFifoPath) 168 require.NoError(err) 169 170 _, err = stdout.Write([]byte("st\n")) 171 require.NoError(err) 172 testutil.WaitForResult(func() (bool, error) { 173 raw, err := ioutil.ReadFile(filepath.Join(dir, "stdout.0")) 174 if err != nil { 175 return false, err 176 } 177 178 expected := "test\ntest\n" == string(raw) 179 return expected, fmt.Errorf("unexpected stdout %q", string(raw)) 180 }, func(err error) { 181 require.NoError(err) 182 }) 183 } 184 185 // asserts that calling Start twice restarts the log rotator 186 func TestLogmon_Start_restart(t *testing.T) { 187 require := require.New(t) 188 var stdoutFifoPath, stderrFifoPath string 189 190 dir, err := ioutil.TempDir("", "nomadtest") 191 require.NoError(err) 192 defer os.RemoveAll(dir) 193 194 if runtime.GOOS == "windows" { 195 stdoutFifoPath = "//./pipe/test-restart.stdout" 196 stderrFifoPath = "//./pipe/test-restart.stderr" 197 } else { 198 stdoutFifoPath = filepath.Join(dir, "stdout.fifo") 199 stderrFifoPath = filepath.Join(dir, "stderr.fifo") 200 } 201 202 cfg := &LogConfig{ 203 LogDir: dir, 204 StdoutLogFile: "stdout", 205 StdoutFifo: stdoutFifoPath, 206 StderrLogFile: "stderr", 207 StderrFifo: stderrFifoPath, 208 MaxFiles: 2, 209 MaxFileSizeMB: 1, 210 } 211 212 lm := NewLogMon(testlog.HCLogger(t)) 213 impl, ok := lm.(*logmonImpl) 214 require.True(ok) 215 require.NoError(lm.Start(cfg)) 216 217 stdout, err := fifo.OpenWriter(stdoutFifoPath) 218 require.NoError(err) 219 stderr, err := fifo.OpenWriter(stderrFifoPath) 220 require.NoError(err) 221 222 // Write a string and assert it was written to the file 223 _, err = stdout.Write([]byte("test\n")) 224 require.NoError(err) 225 226 testutil.WaitForResult(func() (bool, error) { 227 raw, err := ioutil.ReadFile(filepath.Join(dir, "stdout.0")) 228 if err != nil { 229 return false, err 230 } 231 return "test\n" == string(raw), fmt.Errorf("unexpected stdout %q", string(raw)) 232 }, func(err error) { 233 require.NoError(err) 234 }) 235 require.True(impl.tl.IsRunning()) 236 237 // Close stdout and assert that logmon no longer writes to the file 238 require.NoError(stdout.Close()) 239 require.NoError(stderr.Close()) 240 241 testutil.WaitForResult(func() (bool, error) { 242 return !impl.tl.IsRunning(), fmt.Errorf("logmon is still running") 243 }, func(err error) { 244 require.NoError(err) 245 }) 246 247 // Start logmon again and assert that it can receive logs again 248 require.NoError(lm.Start(cfg)) 249 250 stdout, err = fifo.OpenWriter(stdoutFifoPath) 251 require.NoError(err) 252 stderr, err = fifo.OpenWriter(stderrFifoPath) 253 require.NoError(err) 254 255 _, err = stdout.Write([]byte("test\n")) 256 require.NoError(err) 257 testutil.WaitForResult(func() (bool, error) { 258 raw, err := ioutil.ReadFile(filepath.Join(dir, "stdout.0")) 259 if err != nil { 260 return false, err 261 } 262 263 expected := "test\ntest\n" == string(raw) 264 return expected, fmt.Errorf("unexpected stdout %q", string(raw)) 265 }, func(err error) { 266 require.NoError(err) 267 }) 268 } 269 270 // panicWriter panics on use 271 type panicWriter struct{} 272 273 func (panicWriter) Write([]byte) (int, error) { 274 panic("should not be called") 275 } 276 func (panicWriter) Close() error { 277 panic("should not be called") 278 } 279 280 // TestLogmon_NewError asserts that newLogRotatorWrapper will return an error 281 // if its unable to create the necessray files. 282 func TestLogmon_NewError(t *testing.T) { 283 t.Parallel() 284 285 // Pick a path that does not exist 286 path := filepath.Join(uuid.Generate(), uuid.Generate(), uuid.Generate()) 287 288 logger := testlog.HCLogger(t) 289 290 // No code that uses the writer should get hit 291 rotator := panicWriter{} 292 293 w, err := newLogRotatorWrapper(path, logger, rotator) 294 require.Error(t, err) 295 require.Nil(t, w) 296 }