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  }