posix_test.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. // Copyright 2015 Google Inc. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // Tests for the behavior of os.File objects on plain old posix file systems,
  15. // for use in verifying the intended behavior of memfs.
  16. package memfs_test
  17. import (
  18. "io"
  19. "io/ioutil"
  20. "os"
  21. "path"
  22. "runtime"
  23. "testing"
  24. "golang.org/x/net/context"
  25. "github.com/jacobsa/fuse/fusetesting"
  26. . "github.com/jacobsa/oglematchers"
  27. . "github.com/jacobsa/ogletest"
  28. )
  29. func TestPosix(t *testing.T) { RunTests(t) }
  30. ////////////////////////////////////////////////////////////////////////
  31. // Helpers
  32. ////////////////////////////////////////////////////////////////////////
  33. func getFileOffset(f *os.File) (offset int64, err error) {
  34. const relativeToCurrent = 1
  35. offset, err = f.Seek(0, relativeToCurrent)
  36. return
  37. }
  38. ////////////////////////////////////////////////////////////////////////
  39. // Boilerplate
  40. ////////////////////////////////////////////////////////////////////////
  41. type PosixTest struct {
  42. ctx context.Context
  43. // A temporary directory.
  44. dir string
  45. // Files to close when tearing down. Nil entries are skipped.
  46. toClose []io.Closer
  47. }
  48. var _ SetUpInterface = &PosixTest{}
  49. var _ TearDownInterface = &PosixTest{}
  50. func init() { RegisterTestSuite(&PosixTest{}) }
  51. func (t *PosixTest) SetUp(ti *TestInfo) {
  52. var err error
  53. t.ctx = ti.Ctx
  54. // Create a temporary directory.
  55. t.dir, err = ioutil.TempDir("", "posix_test")
  56. if err != nil {
  57. panic(err)
  58. }
  59. }
  60. func (t *PosixTest) TearDown() {
  61. // Close any files we opened.
  62. for _, c := range t.toClose {
  63. if c == nil {
  64. continue
  65. }
  66. err := c.Close()
  67. if err != nil {
  68. panic(err)
  69. }
  70. }
  71. // Remove the temporary directory.
  72. err := os.RemoveAll(t.dir)
  73. if err != nil {
  74. panic(err)
  75. }
  76. }
  77. ////////////////////////////////////////////////////////////////////////
  78. // Test functions
  79. ////////////////////////////////////////////////////////////////////////
  80. func (t *PosixTest) WriteOverlapsEndOfFile() {
  81. var err error
  82. var n int
  83. // Create a file.
  84. f, err := os.Create(path.Join(t.dir, "foo"))
  85. t.toClose = append(t.toClose, f)
  86. AssertEq(nil, err)
  87. // Make it 4 bytes long.
  88. err = f.Truncate(4)
  89. AssertEq(nil, err)
  90. // Write the range [2, 6).
  91. n, err = f.WriteAt([]byte("taco"), 2)
  92. AssertEq(nil, err)
  93. AssertEq(4, n)
  94. // Read the full contents of the file.
  95. contents, err := ioutil.ReadAll(f)
  96. AssertEq(nil, err)
  97. ExpectEq("\x00\x00taco", string(contents))
  98. }
  99. func (t *PosixTest) WriteStartsAtEndOfFile() {
  100. var err error
  101. var n int
  102. // Create a file.
  103. f, err := os.Create(path.Join(t.dir, "foo"))
  104. t.toClose = append(t.toClose, f)
  105. AssertEq(nil, err)
  106. // Make it 2 bytes long.
  107. err = f.Truncate(2)
  108. AssertEq(nil, err)
  109. // Write the range [2, 6).
  110. n, err = f.WriteAt([]byte("taco"), 2)
  111. AssertEq(nil, err)
  112. AssertEq(4, n)
  113. // Read the full contents of the file.
  114. contents, err := ioutil.ReadAll(f)
  115. AssertEq(nil, err)
  116. ExpectEq("\x00\x00taco", string(contents))
  117. }
  118. func (t *PosixTest) WriteStartsPastEndOfFile() {
  119. var err error
  120. var n int
  121. // Create a file.
  122. f, err := os.Create(path.Join(t.dir, "foo"))
  123. t.toClose = append(t.toClose, f)
  124. AssertEq(nil, err)
  125. // Write the range [2, 6).
  126. n, err = f.WriteAt([]byte("taco"), 2)
  127. AssertEq(nil, err)
  128. AssertEq(4, n)
  129. // Read the full contents of the file.
  130. contents, err := ioutil.ReadAll(f)
  131. AssertEq(nil, err)
  132. ExpectEq("\x00\x00taco", string(contents))
  133. }
  134. func (t *PosixTest) WriteStartsPastEndOfFile_AppendMode() {
  135. var err error
  136. var n int
  137. // Create a file.
  138. f, err := os.OpenFile(
  139. path.Join(t.dir, "foo"),
  140. os.O_RDWR|os.O_APPEND|os.O_CREATE,
  141. 0600)
  142. t.toClose = append(t.toClose, f)
  143. AssertEq(nil, err)
  144. // Write three bytes.
  145. n, err = f.Write([]byte("111"))
  146. AssertEq(nil, err)
  147. AssertEq(3, n)
  148. // Write at offset six.
  149. n, err = f.WriteAt([]byte("222"), 6)
  150. AssertEq(nil, err)
  151. AssertEq(3, n)
  152. // Read the full contents of the file.
  153. //
  154. // Linux's support for pwrite is buggy; the pwrite(2) man page says this:
  155. //
  156. // POSIX requires that opening a file with the O_APPEND flag should have
  157. // no affect on the location at which pwrite() writes data. However, on
  158. // Linux, if a file is opened with O_APPEND, pwrite() appends data to
  159. // the end of the file, regardless of the value of offset.
  160. //
  161. contents, err := ioutil.ReadFile(f.Name())
  162. AssertEq(nil, err)
  163. if runtime.GOOS == "linux" {
  164. ExpectEq("111222", string(contents))
  165. } else {
  166. ExpectEq("111\x00\x00\x00222", string(contents))
  167. }
  168. }
  169. func (t *PosixTest) WriteAtDoesntChangeOffset_NotAppendMode() {
  170. var err error
  171. var n int
  172. // Create a file.
  173. f, err := os.Create(path.Join(t.dir, "foo"))
  174. t.toClose = append(t.toClose, f)
  175. AssertEq(nil, err)
  176. // Make it 16 bytes long.
  177. err = f.Truncate(16)
  178. AssertEq(nil, err)
  179. // Seek to offset 4.
  180. _, err = f.Seek(4, 0)
  181. AssertEq(nil, err)
  182. // Write the range [10, 14).
  183. n, err = f.WriteAt([]byte("taco"), 2)
  184. AssertEq(nil, err)
  185. AssertEq(4, n)
  186. // We should still be at offset 4.
  187. offset, err := getFileOffset(f)
  188. AssertEq(nil, err)
  189. ExpectEq(4, offset)
  190. }
  191. func (t *PosixTest) WriteAtDoesntChangeOffset_AppendMode() {
  192. var err error
  193. var n int
  194. // Create a file in append mode.
  195. f, err := os.OpenFile(
  196. path.Join(t.dir, "foo"),
  197. os.O_RDWR|os.O_APPEND|os.O_CREATE,
  198. 0600)
  199. t.toClose = append(t.toClose, f)
  200. AssertEq(nil, err)
  201. // Make it 16 bytes long.
  202. err = f.Truncate(16)
  203. AssertEq(nil, err)
  204. // Seek to offset 4.
  205. _, err = f.Seek(4, 0)
  206. AssertEq(nil, err)
  207. // Write the range [10, 14).
  208. n, err = f.WriteAt([]byte("taco"), 2)
  209. AssertEq(nil, err)
  210. AssertEq(4, n)
  211. // We should still be at offset 4.
  212. offset, err := getFileOffset(f)
  213. AssertEq(nil, err)
  214. ExpectEq(4, offset)
  215. }
  216. func (t *PosixTest) AppendMode() {
  217. var err error
  218. var n int
  219. var off int64
  220. buf := make([]byte, 1024)
  221. // Create a file with some contents.
  222. fileName := path.Join(t.dir, "foo")
  223. err = ioutil.WriteFile(fileName, []byte("Jello, "), 0600)
  224. AssertEq(nil, err)
  225. // Open the file in append mode.
  226. f, err := os.OpenFile(fileName, os.O_RDWR|os.O_APPEND, 0600)
  227. t.toClose = append(t.toClose, f)
  228. AssertEq(nil, err)
  229. // Seek to somewhere silly and then write.
  230. off, err = f.Seek(2, 0)
  231. AssertEq(nil, err)
  232. AssertEq(2, off)
  233. n, err = f.Write([]byte("world!"))
  234. AssertEq(nil, err)
  235. AssertEq(6, n)
  236. // The offset should have been updated to point at the end of the file.
  237. off, err = getFileOffset(f)
  238. AssertEq(nil, err)
  239. ExpectEq(13, off)
  240. // A random write should still work, without updating the offset.
  241. n, err = f.WriteAt([]byte("H"), 0)
  242. AssertEq(nil, err)
  243. AssertEq(1, n)
  244. off, err = getFileOffset(f)
  245. AssertEq(nil, err)
  246. ExpectEq(13, off)
  247. // Read back the contents of the file, which should be correct even though we
  248. // seeked to a silly place before writing the world part.
  249. //
  250. // Linux's support for pwrite is buggy; the pwrite(2) man page says this:
  251. //
  252. // POSIX requires that opening a file with the O_APPEND flag should have
  253. // no affect on the location at which pwrite() writes data. However, on
  254. // Linux, if a file is opened with O_APPEND, pwrite() appends data to
  255. // the end of the file, regardless of the value of offset.
  256. //
  257. // So we allow either the POSIX result or the Linux result.
  258. n, err = f.ReadAt(buf, 0)
  259. AssertEq(io.EOF, err)
  260. if runtime.GOOS == "linux" {
  261. ExpectEq("Jello, world!H", string(buf[:n]))
  262. } else {
  263. ExpectEq("Hello, world!", string(buf[:n]))
  264. }
  265. }
  266. func (t *PosixTest) ReadsPastEndOfFile() {
  267. var err error
  268. var n int
  269. buf := make([]byte, 1024)
  270. // Create a file.
  271. f, err := os.Create(path.Join(t.dir, "foo"))
  272. t.toClose = append(t.toClose, f)
  273. AssertEq(nil, err)
  274. // Give it some contents.
  275. n, err = f.Write([]byte("taco"))
  276. AssertEq(nil, err)
  277. AssertEq(4, n)
  278. // Read a range overlapping EOF.
  279. n, err = f.ReadAt(buf[:4], 2)
  280. AssertEq(io.EOF, err)
  281. ExpectEq(2, n)
  282. ExpectEq("co", string(buf[:n]))
  283. // Read a range starting at EOF.
  284. n, err = f.ReadAt(buf[:4], 4)
  285. AssertEq(io.EOF, err)
  286. ExpectEq(0, n)
  287. ExpectEq("", string(buf[:n]))
  288. // Read a range starting past EOF.
  289. n, err = f.ReadAt(buf[:4], 100)
  290. AssertEq(io.EOF, err)
  291. ExpectEq(0, n)
  292. ExpectEq("", string(buf[:n]))
  293. }
  294. func (t *PosixTest) HardLinkDirectory() {
  295. dirName := path.Join(t.dir, "dir")
  296. // Create a directory.
  297. err := os.Mkdir(dirName, 0700)
  298. AssertEq(nil, err)
  299. // Attempt to hard-link it to a new name.
  300. err = os.Link(dirName, path.Join(t.dir, "other"))
  301. AssertNe(nil, err)
  302. ExpectThat(err, Error(HasSubstr("link")))
  303. ExpectThat(err, Error(HasSubstr("not permitted")))
  304. }
  305. func (t *PosixTest) RmdirWhileOpenedForReading() {
  306. var err error
  307. // Create a directory.
  308. err = os.Mkdir(path.Join(t.dir, "dir"), 0700)
  309. AssertEq(nil, err)
  310. // Open the directory for reading.
  311. f, err := os.Open(path.Join(t.dir, "dir"))
  312. defer func() {
  313. if f != nil {
  314. ExpectEq(nil, f.Close())
  315. }
  316. }()
  317. AssertEq(nil, err)
  318. // Remove the directory.
  319. err = os.Remove(path.Join(t.dir, "dir"))
  320. AssertEq(nil, err)
  321. // Create a new directory, with the same name even, and add some contents
  322. // within it.
  323. err = os.MkdirAll(path.Join(t.dir, "dir/foo"), 0700)
  324. AssertEq(nil, err)
  325. err = os.MkdirAll(path.Join(t.dir, "dir/bar"), 0700)
  326. AssertEq(nil, err)
  327. err = os.MkdirAll(path.Join(t.dir, "dir/baz"), 0700)
  328. AssertEq(nil, err)
  329. // We should still be able to stat the open file handle.
  330. fi, err := f.Stat()
  331. ExpectEq("dir", fi.Name())
  332. // Attempt to read from the directory. This shouldn't see any junk from the
  333. // new directory. It should either succeed with an empty result or should
  334. // return ENOENT.
  335. names, err := f.Readdirnames(0)
  336. if err != nil {
  337. ExpectThat(err, Error(HasSubstr("no such file")))
  338. } else {
  339. ExpectThat(names, ElementsAre())
  340. }
  341. }
  342. func (t *PosixTest) CreateInParallel_NoTruncate() {
  343. fusetesting.RunCreateInParallelTest_NoTruncate(t.ctx, t.dir)
  344. }
  345. func (t *PosixTest) CreateInParallel_Truncate() {
  346. fusetesting.RunCreateInParallelTest_Truncate(t.ctx, t.dir)
  347. }
  348. func (t *PosixTest) CreateInParallel_Exclusive() {
  349. fusetesting.RunCreateInParallelTest_Exclusive(t.ctx, t.dir)
  350. }
  351. func (t *PosixTest) MkdirInParallel() {
  352. fusetesting.RunMkdirInParallelTest(t.ctx, t.dir)
  353. }
  354. func (t *PosixTest) SymlinkInParallel() {
  355. fusetesting.RunSymlinkInParallelTest(t.ctx, t.dir)
  356. }