writer_test.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  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. package zap
  21. import (
  22. "encoding/hex"
  23. "errors"
  24. "io/ioutil"
  25. "math/rand"
  26. "net/url"
  27. "os"
  28. "path/filepath"
  29. "strings"
  30. "testing"
  31. "github.com/stretchr/testify/assert"
  32. "github.com/stretchr/testify/require"
  33. "go.uber.org/zap/zapcore"
  34. )
  35. func TestOpenNoPaths(t *testing.T) {
  36. ws, cleanup, err := Open()
  37. defer cleanup()
  38. assert.NoError(t, err, "Expected opening no paths to succeed.")
  39. assert.Equal(
  40. t,
  41. zapcore.AddSync(ioutil.Discard),
  42. ws,
  43. "Expected opening no paths to return a no-op WriteSyncer.",
  44. )
  45. }
  46. func TestOpen(t *testing.T) {
  47. tempName := tempFileName("", "zap-open-test")
  48. assert.False(t, fileExists(tempName))
  49. require.True(t, strings.HasPrefix(tempName, "/"), "Expected absolute temp file path.")
  50. tests := []struct {
  51. paths []string
  52. errs []string
  53. }{
  54. {[]string{"stdout"}, nil},
  55. {[]string{"stderr"}, nil},
  56. {[]string{tempName}, nil},
  57. {[]string{"file://" + tempName}, nil},
  58. {[]string{"file://localhost" + tempName}, nil},
  59. {[]string{"/foo/bar/baz"}, []string{"open /foo/bar/baz: no such file or directory"}},
  60. {[]string{"file://localhost/foo/bar/baz"}, []string{"open /foo/bar/baz: no such file or directory"}},
  61. {
  62. paths: []string{"stdout", "/foo/bar/baz", tempName, "file:///baz/quux"},
  63. errs: []string{
  64. "open /foo/bar/baz: no such file or directory",
  65. "open /baz/quux: no such file or directory",
  66. },
  67. },
  68. {[]string{"file:///stderr"}, []string{"open /stderr: permission denied"}},
  69. {[]string{"file:///stdout"}, []string{"open /stdout: permission denied"}},
  70. {[]string{"file://host01.test.com" + tempName}, []string{"empty or use localhost"}},
  71. {[]string{"file://rms@localhost" + tempName}, []string{"user and password not allowed"}},
  72. {[]string{"file://localhost" + tempName + "#foo"}, []string{"fragments not allowed"}},
  73. {[]string{"file://localhost" + tempName + "?foo=bar"}, []string{"query parameters not allowed"}},
  74. {[]string{"file://localhost:8080" + tempName}, []string{"ports not allowed"}},
  75. }
  76. for _, tt := range tests {
  77. _, cleanup, err := Open(tt.paths...)
  78. if err == nil {
  79. defer cleanup()
  80. }
  81. if len(tt.errs) == 0 {
  82. assert.NoError(t, err, "Unexpected error opening paths %v.", tt.paths)
  83. } else {
  84. msg := err.Error()
  85. for _, expect := range tt.errs {
  86. assert.Contains(t, msg, expect, "Unexpected error opening paths %v.", tt.paths)
  87. }
  88. }
  89. }
  90. assert.True(t, fileExists(tempName))
  91. os.Remove(tempName)
  92. }
  93. func TestOpenRelativePath(t *testing.T) {
  94. const name = "test-relative-path.txt"
  95. require.False(t, fileExists(name), "Test file already exists.")
  96. s, cleanup, err := Open(name)
  97. require.NoError(t, err, "Open failed.")
  98. defer func() {
  99. err := os.Remove(name)
  100. if !t.Failed() {
  101. // If the test has already failed, we probably didn't create this file.
  102. require.NoError(t, err, "Deleting test file failed.")
  103. }
  104. }()
  105. defer cleanup()
  106. _, err = s.Write([]byte("test"))
  107. assert.NoError(t, err, "Write failed.")
  108. assert.True(t, fileExists(name), "Didn't create file for relative path.")
  109. }
  110. func TestOpenFails(t *testing.T) {
  111. tests := []struct {
  112. paths []string
  113. }{
  114. {paths: []string{"./non-existent-dir/file"}}, // directory doesn't exist
  115. {paths: []string{"stdout", "./non-existent-dir/file"}}, // directory doesn't exist
  116. {paths: []string{"://foo.log"}}, // invalid URL, scheme can't begin with colon
  117. {paths: []string{"mem://somewhere"}}, // scheme not registered
  118. }
  119. for _, tt := range tests {
  120. _, cleanup, err := Open(tt.paths...)
  121. require.Nil(t, cleanup, "Cleanup function should never be nil")
  122. assert.Error(t, err, "Open with invalid URL should fail.")
  123. }
  124. }
  125. type testWriter struct {
  126. expected string
  127. t testing.TB
  128. }
  129. func (w *testWriter) Write(actual []byte) (int, error) {
  130. assert.Equal(w.t, []byte(w.expected), actual, "Unexpected write error.")
  131. return len(actual), nil
  132. }
  133. func (w *testWriter) Sync() error {
  134. return nil
  135. }
  136. func TestOpenWithErroringSinkFactory(t *testing.T) {
  137. defer resetSinkRegistry()
  138. msg := "expected factory error"
  139. factory := func(_ *url.URL) (Sink, error) {
  140. return nil, errors.New(msg)
  141. }
  142. assert.NoError(t, RegisterSink("test", factory), "Failed to register sink factory.")
  143. _, _, err := Open("test://some/path")
  144. assert.Contains(t, err.Error(), msg, "Unexpected error.")
  145. }
  146. func TestCombineWriteSyncers(t *testing.T) {
  147. tw := &testWriter{"test", t}
  148. w := CombineWriteSyncers(tw)
  149. w.Write([]byte("test"))
  150. }
  151. func tempFileName(prefix, suffix string) string {
  152. randBytes := make([]byte, 16)
  153. rand.Read(randBytes)
  154. return filepath.Join(os.TempDir(), prefix+hex.EncodeToString(randBytes)+suffix)
  155. }
  156. func fileExists(name string) bool {
  157. if _, err := os.Stat(name); os.IsNotExist(err) {
  158. return false
  159. }
  160. return true
  161. }