monitor_test.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. // Copyright (C) 2017 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package main
  7. import (
  8. "io"
  9. "os"
  10. "path/filepath"
  11. "testing"
  12. "time"
  13. )
  14. func TestRotatedFile(t *testing.T) {
  15. // Verify that log rotation happens.
  16. dir := t.TempDir()
  17. open := func(name string) (io.WriteCloser, error) {
  18. f, err := os.Create(name)
  19. t.Cleanup(func() {
  20. if f != nil {
  21. _ = f.Close()
  22. }
  23. })
  24. return f, err
  25. }
  26. logName := filepath.Join(dir, "log.txt")
  27. testData := []byte("12345678\n")
  28. maxSize := int64(len(testData) + len(testData)/2)
  29. // We allow the log file plus two rotated copies.
  30. rf, err := newRotatedFile(logName, open, maxSize, 2)
  31. if err != nil {
  32. t.Fatal(err)
  33. }
  34. // Write some bytes.
  35. if _, err := rf.Write(testData); err != nil {
  36. t.Fatal(err)
  37. }
  38. // They should be in the log.
  39. checkSize(t, logName, len(testData))
  40. checkNotExist(t, logName+".0")
  41. // Write some more bytes. We should rotate and write into a new file as the
  42. // new bytes don't fit.
  43. if _, err := rf.Write(testData); err != nil {
  44. t.Fatal(err)
  45. }
  46. checkSize(t, logName, len(testData))
  47. checkSize(t, numberedFile(logName, 0), len(testData))
  48. checkNotExist(t, logName+".1")
  49. // Write another byte. That should fit without causing an extra rotate.
  50. _, _ = rf.Write([]byte{42})
  51. checkSize(t, logName, len(testData)+1)
  52. checkSize(t, numberedFile(logName, 0), len(testData))
  53. checkNotExist(t, numberedFile(logName, 1))
  54. // Write some more bytes. We should rotate and write into a new file as the
  55. // new bytes don't fit.
  56. if _, err := rf.Write(testData); err != nil {
  57. t.Fatal(err)
  58. }
  59. checkSize(t, logName, len(testData))
  60. checkSize(t, numberedFile(logName, 0), len(testData)+1) // the one we wrote extra to, now rotated
  61. checkSize(t, numberedFile(logName, 1), len(testData))
  62. checkNotExist(t, numberedFile(logName, 2))
  63. // Write some more bytes. We should rotate and write into a new file as the
  64. // new bytes don't fit.
  65. if _, err := rf.Write(testData); err != nil {
  66. t.Fatal(err)
  67. }
  68. checkSize(t, logName, len(testData))
  69. checkSize(t, numberedFile(logName, 0), len(testData))
  70. checkSize(t, numberedFile(logName, 1), len(testData)+1)
  71. checkNotExist(t, numberedFile(logName, 2)) // exceeds maxFiles so deleted
  72. }
  73. func TestNumberedFile(t *testing.T) {
  74. // Mostly just illustrates where the number ends up and makes sure it
  75. // doesn't crash without an extension.
  76. cases := []struct {
  77. in string
  78. num int
  79. out string
  80. }{
  81. {
  82. in: "syncthing.log",
  83. num: 42,
  84. out: "syncthing.42.log",
  85. },
  86. {
  87. in: filepath.Join("asdfasdf", "syncthing.log.txt"),
  88. num: 42,
  89. out: filepath.Join("asdfasdf", "syncthing.log.42.txt"),
  90. },
  91. {
  92. in: "syncthing-log",
  93. num: 42,
  94. out: "syncthing-log.42",
  95. },
  96. }
  97. for _, tc := range cases {
  98. res := numberedFile(tc.in, tc.num)
  99. if res != tc.out {
  100. t.Errorf("numberedFile(%q, %d) => %q, expected %q", tc.in, tc.num, res, tc.out)
  101. }
  102. }
  103. }
  104. func checkSize(t *testing.T, name string, size int) {
  105. t.Helper()
  106. info, err := os.Lstat(name)
  107. if err != nil {
  108. t.Fatal(err)
  109. }
  110. if info.Size() != int64(size) {
  111. t.Errorf("%s wrong size: %d != expected %d", name, info.Size(), size)
  112. }
  113. }
  114. func checkNotExist(t *testing.T, name string) {
  115. t.Helper()
  116. _, err := os.Lstat(name)
  117. if !os.IsNotExist(err) {
  118. t.Errorf("%s should not exist", name)
  119. }
  120. }
  121. func TestAutoClosedFile(t *testing.T) {
  122. os.RemoveAll("_autoclose")
  123. defer os.RemoveAll("_autoclose")
  124. os.Mkdir("_autoclose", 0755)
  125. file := filepath.FromSlash("_autoclose/tmp")
  126. data := []byte("hello, world\n")
  127. // An autoclosed file that closes very quickly
  128. ac, err := newAutoclosedFile(file, time.Millisecond, time.Millisecond)
  129. if err != nil {
  130. t.Fatal(err)
  131. }
  132. // Write some data.
  133. if _, err := ac.Write(data); err != nil {
  134. t.Fatal(err)
  135. }
  136. // Wait for it to close
  137. start := time.Now()
  138. for {
  139. time.Sleep(time.Millisecond)
  140. ac.mut.Lock()
  141. fd := ac.fd
  142. ac.mut.Unlock()
  143. if fd == nil {
  144. break
  145. }
  146. if time.Since(start) > time.Second {
  147. t.Fatal("File should have been closed after first write")
  148. }
  149. }
  150. // Write more data, which should be an append.
  151. if _, err := ac.Write(data); err != nil {
  152. t.Fatal(err)
  153. }
  154. // Close.
  155. if err := ac.Close(); err != nil {
  156. t.Fatal(err)
  157. }
  158. // The file should have both writes in it.
  159. bs, err := os.ReadFile(file)
  160. if err != nil {
  161. t.Fatal(err)
  162. }
  163. if len(bs) != 2*len(data) {
  164. t.Fatalf("Writes failed, expected %d bytes, not %d", 2*len(data), len(bs))
  165. }
  166. // Open the file again.
  167. ac, err = newAutoclosedFile(file, time.Second, time.Second)
  168. if err != nil {
  169. t.Fatal(err)
  170. }
  171. // Write something
  172. if _, err := ac.Write(data); err != nil {
  173. t.Fatal(err)
  174. }
  175. // It should now contain three writes, as the file is always opened for appending
  176. bs, err = os.ReadFile(file)
  177. if err != nil {
  178. t.Fatal(err)
  179. }
  180. if len(bs) != 3*len(data) {
  181. t.Fatalf("Write failed, expected %d bytes, not %d", 3*len(data), len(bs))
  182. }
  183. // Close.
  184. if err := ac.Close(); err != nil {
  185. t.Fatal(err)
  186. }
  187. }