github.com/mongodb/grip@v0.0.0-20240213223901-f906268d82b9/logging/send_test.go (about)

     1  package logging
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"os/exec"
     8  	"testing"
     9  
    10  	"github.com/mongodb/grip/level"
    11  	"github.com/mongodb/grip/message"
    12  	"github.com/mongodb/grip/send"
    13  	"github.com/stretchr/testify/suite"
    14  )
    15  
    16  type GripInternalSuite struct {
    17  	grip *Grip
    18  	name string
    19  	suite.Suite
    20  }
    21  
    22  func TestGripSuite(t *testing.T) {
    23  	suite.Run(t, new(GripInternalSuite))
    24  }
    25  
    26  func (s *GripInternalSuite) SetupSuite() {
    27  	s.name = "test"
    28  	s.grip = NewGrip(s.name)
    29  	s.Equal(s.grip.Name(), s.name)
    30  }
    31  
    32  func (s *GripInternalSuite) SetupTest() {
    33  	s.grip.SetName(s.name)
    34  	sender, err := send.NewNativeLogger(s.grip.Name(), send.LevelInfo{Default: level.Info, Threshold: level.Trace})
    35  	s.NoError(err)
    36  	s.NoError(s.grip.SetSender(sender))
    37  }
    38  
    39  func (s *GripInternalSuite) TestPanicSenderActuallyPanics() {
    40  	// both of these are in anonymous functions so that the defers
    41  	// cover the correct area.
    42  
    43  	func() {
    44  		// first make sure that the default send method doesn't panic
    45  		defer func() {
    46  			s.Nil(recover())
    47  		}()
    48  
    49  		s.grip.GetSender().Send(message.NewLineMessage(level.Critical, "foo"))
    50  	}()
    51  
    52  	func() {
    53  		// call a panic function with a recoverer set.
    54  		defer func() {
    55  			s.NotNil(recover())
    56  		}()
    57  
    58  		s.grip.sendPanic(message.NewLineMessage(level.Info, "foo"))
    59  	}()
    60  }
    61  
    62  func (s *GripInternalSuite) TestSetSenderErrorsForNil() {
    63  	s.Error(s.grip.SetSender(nil))
    64  }
    65  
    66  func (s *GripInternalSuite) TestPanicSenderRespectsTThreshold() {
    67  	s.True(level.Debug > s.grip.GetSender().Level().Threshold)
    68  	s.NoError(s.grip.GetSender().SetLevel(send.LevelInfo{Default: level.Info, Threshold: level.Notice}))
    69  	s.True(level.Debug < s.grip.GetSender().Level().Threshold)
    70  
    71  	// test that there is a no panic if the message isn't "logabble"
    72  	defer func() {
    73  		s.Nil(recover())
    74  	}()
    75  
    76  	s.grip.sendPanic(message.NewLineMessage(level.Debug, "foo"))
    77  }
    78  
    79  func (s *GripInternalSuite) TestConditionalSend() {
    80  	// because sink is an internal type (implementation of
    81  	// sender,) and "GetMessage" isn't in the interface, though it
    82  	// is exported, we can't pass the sink between functions.
    83  	sink, err := send.NewInternalLogger("sink", s.grip.GetSender().Level())
    84  	s.NoError(err)
    85  	s.NoError(s.grip.SetSender(sink))
    86  
    87  	msg := message.NewLineMessage(level.Info, "foo")
    88  	msgTwo := message.NewLineMessage(level.Notice, "bar")
    89  
    90  	// when the conditional argument is true, it should work
    91  	s.grip.Log(msg.Priority(), message.When(true, msg))
    92  	s.Equal(msg.Raw(), sink.GetMessage().Message.Raw())
    93  
    94  	// when the conditional argument is true, it should work, and the channel is fifo
    95  	s.grip.Log(msgTwo.Priority(), message.When(false, msgTwo))
    96  	s.grip.Log(msg.Priority(), message.When(true, msg))
    97  	result := sink.GetMessage().Message
    98  	if result.Loggable() {
    99  		s.Equal(msg.Raw(), result.Raw())
   100  	} else {
   101  		s.Equal(msgTwo.Raw(), result.Raw())
   102  	}
   103  
   104  	// change the order
   105  	s.grip.Log(msg.Priority(), message.When(true, msg))
   106  	s.grip.Log(msgTwo.Priority(), message.When(false, msgTwo))
   107  	result = sink.GetMessage().Message
   108  
   109  	if result.Loggable() {
   110  		s.Equal(msg.Raw(), result.Raw())
   111  	} else {
   112  		s.Equal(msgTwo.Raw(), result.Raw())
   113  	}
   114  }
   115  
   116  func (s *GripInternalSuite) TestCatchMethods() {
   117  	sink, err := send.NewInternalLogger("sink", send.LevelInfo{Default: level.Trace, Threshold: level.Trace})
   118  	s.NoError(err)
   119  	s.NoError(s.grip.SetSender(sink))
   120  
   121  	cases := []interface{}{
   122  		s.grip.Alert,
   123  		s.grip.Critical,
   124  		s.grip.Debug,
   125  		s.grip.Emergency,
   126  		s.grip.Error,
   127  		s.grip.Info,
   128  		s.grip.Notice,
   129  		s.grip.Warning,
   130  
   131  		s.grip.Alertln,
   132  		s.grip.Criticalln,
   133  		s.grip.Debugln,
   134  		s.grip.Emergencyln,
   135  		s.grip.Errorln,
   136  		s.grip.Infoln,
   137  		s.grip.Noticeln,
   138  		s.grip.Warningln,
   139  
   140  		s.grip.Alertf,
   141  		s.grip.Criticalf,
   142  		s.grip.Debugf,
   143  		s.grip.Emergencyf,
   144  		s.grip.Errorf,
   145  		s.grip.Infof,
   146  		s.grip.Noticef,
   147  		s.grip.Warningf,
   148  
   149  		s.grip.AlertWhen,
   150  		s.grip.CriticalWhen,
   151  		s.grip.DebugWhen,
   152  		s.grip.EmergencyWhen,
   153  		s.grip.ErrorWhen,
   154  		s.grip.InfoWhen,
   155  		s.grip.NoticeWhen,
   156  		s.grip.WarningWhen,
   157  
   158  		s.grip.AlertWhenln,
   159  		s.grip.CriticalWhenln,
   160  		s.grip.DebugWhenln,
   161  		s.grip.EmergencyWhenln,
   162  		s.grip.ErrorWhenln,
   163  		s.grip.InfoWhenln,
   164  		s.grip.NoticeWhenln,
   165  		s.grip.WarningWhenln,
   166  
   167  		s.grip.AlertWhenf,
   168  		s.grip.CriticalWhenf,
   169  		s.grip.DebugWhenf,
   170  		s.grip.EmergencyWhenf,
   171  		s.grip.ErrorWhenf,
   172  		s.grip.InfoWhenf,
   173  		s.grip.NoticeWhenf,
   174  		s.grip.WarningWhenf,
   175  
   176  		func(w bool, m interface{}) { s.grip.LogWhen(w, level.Info, m) },
   177  		func(w bool, m ...interface{}) { s.grip.LogWhenln(w, level.Info, m...) },
   178  		func(w bool, m string, a ...interface{}) { s.grip.LogWhenf(w, level.Info, m, a...) },
   179  		func(m interface{}) { s.grip.Log(level.Info, m) },
   180  		func(m string, a ...interface{}) { s.grip.Logf(level.Info, m, a...) },
   181  		func(m ...interface{}) { s.grip.Logln(level.Info, m...) },
   182  		func(m ...message.Composer) { s.grip.Log(level.Info, m) },
   183  		func(m []message.Composer) { s.grip.Log(level.Info, m) },
   184  		func(w bool, m ...message.Composer) { s.grip.LogWhen(w, level.Info, m) },
   185  		func(w bool, m []message.Composer) { s.grip.LogWhen(w, level.Info, m) },
   186  	}
   187  
   188  	const msg = "hello world!"
   189  	multiMessage := []message.Composer{
   190  		message.ConvertToComposer(0, nil),
   191  		message.ConvertToComposer(0, msg),
   192  	}
   193  
   194  	for _, logger := range cases {
   195  		s.Equal(0, sink.Len())
   196  		s.False(sink.HasMessage())
   197  
   198  		switch log := logger.(type) {
   199  		case func(error):
   200  			log(errors.New(msg))
   201  		case func(interface{}):
   202  			log(msg)
   203  		case func(...interface{}):
   204  			log(msg, "", nil)
   205  		case func(string, ...interface{}):
   206  			log("%s", msg)
   207  		case func(bool, interface{}):
   208  			log(false, msg)
   209  			log(true, msg)
   210  		case func(bool, ...interface{}):
   211  			log(false, msg, "", nil)
   212  			log(true, msg, "", nil)
   213  		case func(bool, string, ...interface{}):
   214  			log(false, "%s", msg)
   215  			log(true, "%s", msg)
   216  		case func(...message.Composer):
   217  			log(multiMessage...)
   218  		case func(bool, ...message.Composer):
   219  			log(false, multiMessage...)
   220  			log(true, multiMessage...)
   221  		case func([]message.Composer):
   222  			log(multiMessage)
   223  		case func(bool, []message.Composer):
   224  			log(false, multiMessage)
   225  			log(true, multiMessage)
   226  		default:
   227  			panic(fmt.Sprintf("%T is not supported\n", log))
   228  		}
   229  
   230  		if sink.Len() > 1 {
   231  			// this is the many case
   232  			var numLogged int
   233  			out := sink.GetMessage()
   234  			for i := 0; i < sink.Len(); i++ {
   235  				out = sink.GetMessage()
   236  				if out.Logged {
   237  					numLogged++
   238  					s.Equal(out.Rendered, msg)
   239  				}
   240  			}
   241  
   242  			s.True(numLogged == 1, fmt.Sprintf("%T: %d %s", logger, numLogged, out.Priority))
   243  
   244  			continue
   245  		}
   246  
   247  		s.True(sink.Len() == 1)
   248  		s.True(sink.HasMessage())
   249  		out := sink.GetMessage()
   250  		s.Equal(out.Rendered, msg)
   251  		s.True(out.Logged, fmt.Sprintf("%T %s", logger, out.Priority))
   252  	}
   253  }
   254  
   255  // This testing method uses the technique outlined in:
   256  // http://stackoverflow.com/a/33404435 to test a function that exits
   257  // since it's impossible to "catch" an os.Exit
   258  func TestSendFatalExits(t *testing.T) {
   259  	grip := NewGrip("test")
   260  	if os.Getenv("SHOULD_CRASH") == "1" {
   261  		grip.sendFatal(message.NewLineMessage(level.Error, "foo"))
   262  		return
   263  	}
   264  
   265  	cmd := exec.Command(os.Args[0], "-test.run=TestSendFatalExits")
   266  	cmd.Env = append(os.Environ(), "SHOULD_CRASH=1")
   267  	err := cmd.Run()
   268  	if err == nil {
   269  		t.Errorf("sendFatal should have exited 0, instead: %+v", err)
   270  	}
   271  }