Skip to content

Commit

Permalink
Make zaptest a wrapper around internal/ztest
Browse files Browse the repository at this point in the history
Mitigate the distasteful copy-paste of `zaptest` by providing a path
forward using Go 1.9 aliases. For Go 1.9 users, `zaptest` is now nothing
more than a few type aliases; this cleans up the GoDoc output nicely,
since it removes the documentation for all the methods on the testing
spies while remaining fully backward-compatible. For Go 1.8 and earlier,
we keep the original code but add a test to make sure that it exactly
matches the version in `internal/ztest`.

With this change, we're free to introduce functionality into `zaptest`
that relies on `zapcore` and `zap` itself. In particular, we can return
`*zap.Logger` from constructors.
  • Loading branch information
Akshay Shah committed Oct 31, 2017
1 parent 1abd904 commit a142dae
Show file tree
Hide file tree
Showing 7 changed files with 212 additions and 29 deletions.
18 changes: 13 additions & 5 deletions internal/ztest/timeout.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,21 @@ func Sleep(base time.Duration) {
time.Sleep(Timeout(base))
}

// Initialize checks the environment and alters the timeout scale accordingly.
// It returns a function to undo the scaling.
func Initialize(factor string) func() {
original := _timeoutScale
fv, err := strconv.ParseFloat(factor, 64)
if err != nil {
panic(err)
}
_timeoutScale = fv
return func() { _timeoutScale = original }
}

func init() {
if v := os.Getenv("TEST_TIMEOUT_SCALE"); v != "" {
fv, err := strconv.ParseFloat(v, 64)
if err != nil {
panic(err)
}
_timeoutScale = fv
Initialize(v)
log.Printf("Scaling timeouts by %vx.\n", _timeoutScale)
}
}
7 changes: 1 addition & 6 deletions zaptest/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,5 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// Package zaptest provides low-level helpers for testing log output. These
// utilities are helpful in zap's own unit tests, but any assertions using
// them are strongly coupled to a single encoding.
//
// Most users should use go.uber.org/zap/zaptest/observer instead of this
// package.
// Package zaptest provides a variety of helpers for testing log output.
package zaptest // import "go.uber.org/zap/zaptest"
22 changes: 4 additions & 18 deletions zaptest/timeout.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,17 @@
package zaptest

import (
"log"
"os"
"strconv"
"time"
)

var _timeoutScale = 1.0
"go.uber.org/zap/internal/ztest"
)

// Timeout scales the provided duration by $TEST_TIMEOUT_SCALE.
func Timeout(base time.Duration) time.Duration {
return time.Duration(float64(base) * _timeoutScale)
return ztest.Timeout(base)
}

// Sleep scales the sleep duration by $TEST_TIMEOUT_SCALE.
func Sleep(base time.Duration) {
time.Sleep(Timeout(base))
}

func init() {
if v := os.Getenv("TEST_TIMEOUT_SCALE"); v != "" {
fv, err := strconv.ParseFloat(v, 64)
if err != nil {
panic(err)
}
_timeoutScale = fv
log.Printf("Scaling timeouts by %vx.\n", _timeoutScale)
}
ztest.Sleep(base)
}
43 changes: 43 additions & 0 deletions zaptest/timeout_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package zaptest

import (
"testing"
"time"

"github.com/stretchr/testify/assert"
"go.uber.org/zap/internal/ztest"
)

func TestTimeout(t *testing.T) {
defer ztest.Initialize("2")()
assert.Equal(t, time.Duration(100), Timeout(50), "Expected to scale up timeout.")
}

func TestSleep(t *testing.T) {
defer ztest.Initialize("2")()
const sleepFor = 50 * time.Millisecond
now := time.Now()
Sleep(sleepFor)
elapsed := time.Since(now)
assert.True(t, 2*sleepFor <= elapsed, "Expected to scale up timeout.")
}
2 changes: 2 additions & 0 deletions zaptest/writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// +build !go1.9

package zaptest

import (
Expand Down
45 changes: 45 additions & 0 deletions zaptest/writer_go_19.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// +build go1.9

package zaptest

import "go.uber.org/zap/internal/ztest"

type (
// A Syncer is a spy for the Sync portion of zapcore.WriteSyncer.
Syncer = ztest.Syncer

// A Discarder sends all writes to ioutil.Discard.
Discarder = ztest.Discarder

// FailWriter is a WriteSyncer that always returns an error on writes.
FailWriter = ztest.FailWriter

// ShortWriter is a WriteSyncer whose write method never fails, but
// nevertheless fails to the last byte of the input.
ShortWriter = ztest.ShortWriter

// Buffer is an implementation of zapcore.WriteSyncer that sends all writes to
// a bytes.Buffer. It has convenience methods to split the accumulated buffer
// on newlines.
Buffer = ztest.Buffer
)
104 changes: 104 additions & 0 deletions zaptest/writer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package zaptest

import (
"bufio"
"errors"
"os"
"strings"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func readCode(t testing.TB, fname string) []string {
f, err := os.Open(fname)
require.NoError(t, err, "Failed to read %s.", fname)
var lines []string
s := bufio.NewScanner(f)
for s.Scan() {
l := s.Text()
if len(l) == 0 {
continue
}
if strings.HasPrefix(l, "//") {
continue
}
if strings.HasPrefix(l, "package ") {
continue
}
lines = append(lines, l)
}
return lines
}

func TestCopiedCodeInSync(t *testing.T) {
// Until we drop Go 1.8 support, we need to keep a near-exact copy of the
// ztest package's WriteSyncer test spies in zaptest. This test ensures that
// the two files stay in sync.
assert.Equal(t,
readCode(t, "../internal/ztest/writer.go"),
readCode(t, "writer.go"),
"Writer spy implementations in zaptest and internal/ztest should be identical.",
)
}

func TestSyncer(t *testing.T) {
err := errors.New("sentinel")
s := &Syncer{}
s.SetError(err)
assert.Equal(t, err, s.Sync(), "Expected Sync to fail with provided error.")
assert.True(t, s.Called(), "Expected to record that Sync was called.")
}

func TestDiscarder(t *testing.T) {
d := &Discarder{}
payload := []byte("foo")
n, err := d.Write(payload)
assert.NoError(t, err, "Unexpected error writing to Discarder.")
assert.Equal(t, len(payload), n, "Wrong number of bytes written.")
}

func TestFailWriter(t *testing.T) {
w := &FailWriter{}
payload := []byte("foo")
n, err := w.Write(payload)
assert.Error(t, err, "Expected an error writing to FailWriter.")
assert.Equal(t, len(payload), n, "Wrong number of bytes written.")
}

func TestShortWriter(t *testing.T) {
w := &ShortWriter{}
payload := []byte("foo")
n, err := w.Write(payload)
assert.NoError(t, err, "Unexpected error writing to ShortWriter.")
assert.Equal(t, len(payload)-1, n, "Wrong number of bytes written.")
}

func TestBuffer(t *testing.T) {
buf := &Buffer{}
buf.WriteString("foo\n")
buf.WriteString("bar\n")
assert.Equal(t, []string{"foo", "bar"}, buf.Lines(), "Unexpected output from Lines.")
assert.Equal(t, "foo\nbar", buf.Stripped(), "Unexpected output from Stripped.")
}

0 comments on commit a142dae

Please sign in to comment.