...

Source file src/go.uber.org/zap/zapcore/entry_test.go

Documentation: go.uber.org/zap/zapcore

     1  // Copyright (c) 2016 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package zapcore
    22  
    23  import (
    24  	"sync"
    25  	"testing"
    26  
    27  	"go.uber.org/zap/internal/exit"
    28  
    29  	"github.com/stretchr/testify/assert"
    30  )
    31  
    32  func assertGoexit(t *testing.T, f func()) {
    33  	var finished bool
    34  	recovered := make(chan interface{})
    35  	go func() {
    36  		defer func() {
    37  			recovered <- recover()
    38  		}()
    39  
    40  		f()
    41  		finished = true
    42  	}()
    43  
    44  	assert.Nil(t, <-recovered, "Goexit should cause recover to return nil")
    45  	assert.False(t, finished, "Goroutine should not finish after Goexit")
    46  }
    47  
    48  func TestPutNilEntry(t *testing.T) {
    49  	// Pooling nil entries defeats the purpose.
    50  	var wg sync.WaitGroup
    51  	wg.Add(2)
    52  
    53  	go func() {
    54  		defer wg.Done()
    55  		for i := 0; i < 1000; i++ {
    56  			putCheckedEntry(nil)
    57  		}
    58  	}()
    59  
    60  	go func() {
    61  		defer wg.Done()
    62  		for i := 0; i < 1000; i++ {
    63  			ce := getCheckedEntry()
    64  			assert.NotNil(t, ce, "Expected only non-nil CheckedEntries in pool.")
    65  			assert.False(t, ce.dirty, "Unexpected dirty bit set.")
    66  			assert.Nil(t, ce.ErrorOutput, "Non-nil ErrorOutput.")
    67  			assert.Nil(t, ce.after, "Unexpected terminal behavior.")
    68  			assert.Equal(t, 0, len(ce.cores), "Expected empty slice of cores.")
    69  			assert.True(t, cap(ce.cores) > 0, "Expected pooled CheckedEntries to pre-allocate slice of Cores.")
    70  		}
    71  	}()
    72  
    73  	wg.Wait()
    74  }
    75  
    76  func TestEntryCaller(t *testing.T) {
    77  	tests := []struct {
    78  		caller EntryCaller
    79  		full   string
    80  		short  string
    81  	}{
    82  		{
    83  			caller: NewEntryCaller(100, "/path/to/foo.go", 42, false),
    84  			full:   "undefined",
    85  			short:  "undefined",
    86  		},
    87  		{
    88  			caller: NewEntryCaller(100, "/path/to/foo.go", 42, true),
    89  			full:   "/path/to/foo.go:42",
    90  			short:  "to/foo.go:42",
    91  		},
    92  		{
    93  			caller: NewEntryCaller(100, "to/foo.go", 42, true),
    94  			full:   "to/foo.go:42",
    95  			short:  "to/foo.go:42",
    96  		},
    97  	}
    98  
    99  	for _, tt := range tests {
   100  		assert.Equal(t, tt.full, tt.caller.String(), "Unexpected string from EntryCaller.")
   101  		assert.Equal(t, tt.full, tt.caller.FullPath(), "Unexpected FullPath from EntryCaller.")
   102  		assert.Equal(t, tt.short, tt.caller.TrimmedPath(), "Unexpected TrimmedPath from EntryCaller.")
   103  	}
   104  }
   105  
   106  func TestCheckedEntryWrite(t *testing.T) {
   107  	t.Run("nil is safe", func(t *testing.T) {
   108  		var ce *CheckedEntry
   109  		assert.NotPanics(t, func() { ce.Write() }, "Unexpected panic writing nil CheckedEntry.")
   110  	})
   111  
   112  	t.Run("WriteThenPanic", func(t *testing.T) {
   113  		var ce *CheckedEntry
   114  		ce = ce.After(Entry{}, WriteThenPanic)
   115  		assert.Panics(t, func() { ce.Write() }, "Expected to panic when WriteThenPanic is set.")
   116  	})
   117  
   118  	t.Run("WriteThenGoexit", func(t *testing.T) {
   119  		var ce *CheckedEntry
   120  		ce = ce.After(Entry{}, WriteThenGoexit)
   121  		assertGoexit(t, func() { ce.Write() })
   122  	})
   123  
   124  	t.Run("WriteThenFatal", func(t *testing.T) {
   125  		var ce *CheckedEntry
   126  		ce = ce.After(Entry{}, WriteThenFatal)
   127  		stub := exit.WithStub(func() {
   128  			ce.Write()
   129  		})
   130  		assert.True(t, stub.Exited, "Expected to exit when WriteThenFatal is set.")
   131  		assert.Equal(t, 1, stub.Code, "Expected to exit when WriteThenFatal is set.")
   132  	})
   133  
   134  	t.Run("After", func(t *testing.T) {
   135  		var ce *CheckedEntry
   136  		hook := &customHook{}
   137  		ce = ce.After(Entry{}, hook)
   138  		ce.Write()
   139  		assert.True(t, hook.called, "Expected to call custom action after Write.")
   140  	})
   141  }
   142  
   143  type customHook struct {
   144  	called bool
   145  }
   146  
   147  func (c *customHook) OnWrite(_ *CheckedEntry, _ []Field) {
   148  	c.called = true
   149  }
   150  

View as plain text