A lightweight mechanism to provide an *instant kickstart* to a Go web server instance upon changing any Go source files under the project directory (and its subdirectories).

integration_test.go 32KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237
  1. // Copyright 2010 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // +build !plan9,!solaris
  5. package fsnotify
  6. import (
  7. "io/ioutil"
  8. "os"
  9. "os/exec"
  10. "path"
  11. "path/filepath"
  12. "runtime"
  13. "sync/atomic"
  14. "testing"
  15. "time"
  16. )
  17. // An atomic counter
  18. type counter struct {
  19. val int32
  20. }
  21. func (c *counter) increment() {
  22. atomic.AddInt32(&c.val, 1)
  23. }
  24. func (c *counter) value() int32 {
  25. return atomic.LoadInt32(&c.val)
  26. }
  27. func (c *counter) reset() {
  28. atomic.StoreInt32(&c.val, 0)
  29. }
  30. // tempMkdir makes a temporary directory
  31. func tempMkdir(t *testing.T) string {
  32. dir, err := ioutil.TempDir("", "fsnotify")
  33. if err != nil {
  34. t.Fatalf("failed to create test directory: %s", err)
  35. }
  36. return dir
  37. }
  38. // tempMkFile makes a temporary file.
  39. func tempMkFile(t *testing.T, dir string) string {
  40. f, err := ioutil.TempFile(dir, "fsnotify")
  41. if err != nil {
  42. t.Fatalf("failed to create test file: %v", err)
  43. }
  44. defer f.Close()
  45. return f.Name()
  46. }
  47. // newWatcher initializes an fsnotify Watcher instance.
  48. func newWatcher(t *testing.T) *Watcher {
  49. watcher, err := NewWatcher()
  50. if err != nil {
  51. t.Fatalf("NewWatcher() failed: %s", err)
  52. }
  53. return watcher
  54. }
  55. // addWatch adds a watch for a directory
  56. func addWatch(t *testing.T, watcher *Watcher, dir string) {
  57. if err := watcher.Add(dir); err != nil {
  58. t.Fatalf("watcher.Add(%q) failed: %s", dir, err)
  59. }
  60. }
  61. func TestFsnotifyMultipleOperations(t *testing.T) {
  62. watcher := newWatcher(t)
  63. // Receive errors on the error channel on a separate goroutine
  64. go func() {
  65. for err := range watcher.Errors {
  66. t.Fatalf("error received: %s", err)
  67. }
  68. }()
  69. // Create directory to watch
  70. testDir := tempMkdir(t)
  71. defer os.RemoveAll(testDir)
  72. // Create directory that's not watched
  73. testDirToMoveFiles := tempMkdir(t)
  74. defer os.RemoveAll(testDirToMoveFiles)
  75. testFile := filepath.Join(testDir, "TestFsnotifySeq.testfile")
  76. testFileRenamed := filepath.Join(testDirToMoveFiles, "TestFsnotifySeqRename.testfile")
  77. addWatch(t, watcher, testDir)
  78. // Receive events on the event channel on a separate goroutine
  79. eventstream := watcher.Events
  80. var createReceived, modifyReceived, deleteReceived, renameReceived counter
  81. done := make(chan bool)
  82. go func() {
  83. for event := range eventstream {
  84. // Only count relevant events
  85. if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) {
  86. t.Logf("event received: %s", event)
  87. if event.Op&Remove == Remove {
  88. deleteReceived.increment()
  89. }
  90. if event.Op&Write == Write {
  91. modifyReceived.increment()
  92. }
  93. if event.Op&Create == Create {
  94. createReceived.increment()
  95. }
  96. if event.Op&Rename == Rename {
  97. renameReceived.increment()
  98. }
  99. } else {
  100. t.Logf("unexpected event received: %s", event)
  101. }
  102. }
  103. done <- true
  104. }()
  105. // Create a file
  106. // This should add at least one event to the fsnotify event queue
  107. var f *os.File
  108. f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
  109. if err != nil {
  110. t.Fatalf("creating test file failed: %s", err)
  111. }
  112. f.Sync()
  113. time.Sleep(time.Millisecond)
  114. f.WriteString("data")
  115. f.Sync()
  116. f.Close()
  117. time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
  118. if err := testRename(testFile, testFileRenamed); err != nil {
  119. t.Fatalf("rename failed: %s", err)
  120. }
  121. // Modify the file outside of the watched dir
  122. f, err = os.Open(testFileRenamed)
  123. if err != nil {
  124. t.Fatalf("open test renamed file failed: %s", err)
  125. }
  126. f.WriteString("data")
  127. f.Sync()
  128. f.Close()
  129. time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
  130. // Recreate the file that was moved
  131. f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
  132. if err != nil {
  133. t.Fatalf("creating test file failed: %s", err)
  134. }
  135. f.Close()
  136. time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
  137. // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
  138. time.Sleep(500 * time.Millisecond)
  139. cReceived := createReceived.value()
  140. if cReceived != 2 {
  141. t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 2)
  142. }
  143. mReceived := modifyReceived.value()
  144. if mReceived != 1 {
  145. t.Fatalf("incorrect number of modify events received after 500 ms (%d vs %d)", mReceived, 1)
  146. }
  147. dReceived := deleteReceived.value()
  148. rReceived := renameReceived.value()
  149. if dReceived+rReceived != 1 {
  150. t.Fatalf("incorrect number of rename+delete events received after 500 ms (%d vs %d)", rReceived+dReceived, 1)
  151. }
  152. // Try closing the fsnotify instance
  153. t.Log("calling Close()")
  154. watcher.Close()
  155. t.Log("waiting for the event channel to become closed...")
  156. select {
  157. case <-done:
  158. t.Log("event channel closed")
  159. case <-time.After(2 * time.Second):
  160. t.Fatal("event stream was not closed after 2 seconds")
  161. }
  162. }
  163. func TestFsnotifyMultipleCreates(t *testing.T) {
  164. watcher := newWatcher(t)
  165. // Receive errors on the error channel on a separate goroutine
  166. go func() {
  167. for err := range watcher.Errors {
  168. t.Fatalf("error received: %s", err)
  169. }
  170. }()
  171. // Create directory to watch
  172. testDir := tempMkdir(t)
  173. defer os.RemoveAll(testDir)
  174. testFile := filepath.Join(testDir, "TestFsnotifySeq.testfile")
  175. addWatch(t, watcher, testDir)
  176. // Receive events on the event channel on a separate goroutine
  177. eventstream := watcher.Events
  178. var createReceived, modifyReceived, deleteReceived counter
  179. done := make(chan bool)
  180. go func() {
  181. for event := range eventstream {
  182. // Only count relevant events
  183. if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) {
  184. t.Logf("event received: %s", event)
  185. if event.Op&Remove == Remove {
  186. deleteReceived.increment()
  187. }
  188. if event.Op&Create == Create {
  189. createReceived.increment()
  190. }
  191. if event.Op&Write == Write {
  192. modifyReceived.increment()
  193. }
  194. } else {
  195. t.Logf("unexpected event received: %s", event)
  196. }
  197. }
  198. done <- true
  199. }()
  200. // Create a file
  201. // This should add at least one event to the fsnotify event queue
  202. var f *os.File
  203. f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
  204. if err != nil {
  205. t.Fatalf("creating test file failed: %s", err)
  206. }
  207. f.Sync()
  208. time.Sleep(time.Millisecond)
  209. f.WriteString("data")
  210. f.Sync()
  211. f.Close()
  212. time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
  213. os.Remove(testFile)
  214. time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
  215. // Recreate the file
  216. f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
  217. if err != nil {
  218. t.Fatalf("creating test file failed: %s", err)
  219. }
  220. f.Close()
  221. time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
  222. // Modify
  223. f, err = os.OpenFile(testFile, os.O_WRONLY, 0666)
  224. if err != nil {
  225. t.Fatalf("creating test file failed: %s", err)
  226. }
  227. f.Sync()
  228. time.Sleep(time.Millisecond)
  229. f.WriteString("data")
  230. f.Sync()
  231. f.Close()
  232. time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
  233. // Modify
  234. f, err = os.OpenFile(testFile, os.O_WRONLY, 0666)
  235. if err != nil {
  236. t.Fatalf("creating test file failed: %s", err)
  237. }
  238. f.Sync()
  239. time.Sleep(time.Millisecond)
  240. f.WriteString("data")
  241. f.Sync()
  242. f.Close()
  243. time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
  244. // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
  245. time.Sleep(500 * time.Millisecond)
  246. cReceived := createReceived.value()
  247. if cReceived != 2 {
  248. t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 2)
  249. }
  250. mReceived := modifyReceived.value()
  251. if mReceived < 3 {
  252. t.Fatalf("incorrect number of modify events received after 500 ms (%d vs atleast %d)", mReceived, 3)
  253. }
  254. dReceived := deleteReceived.value()
  255. if dReceived != 1 {
  256. t.Fatalf("incorrect number of rename+delete events received after 500 ms (%d vs %d)", dReceived, 1)
  257. }
  258. // Try closing the fsnotify instance
  259. t.Log("calling Close()")
  260. watcher.Close()
  261. t.Log("waiting for the event channel to become closed...")
  262. select {
  263. case <-done:
  264. t.Log("event channel closed")
  265. case <-time.After(2 * time.Second):
  266. t.Fatal("event stream was not closed after 2 seconds")
  267. }
  268. }
  269. func TestFsnotifyDirOnly(t *testing.T) {
  270. watcher := newWatcher(t)
  271. // Create directory to watch
  272. testDir := tempMkdir(t)
  273. defer os.RemoveAll(testDir)
  274. // Create a file before watching directory
  275. // This should NOT add any events to the fsnotify event queue
  276. testFileAlreadyExists := filepath.Join(testDir, "TestFsnotifyEventsExisting.testfile")
  277. {
  278. var f *os.File
  279. f, err := os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666)
  280. if err != nil {
  281. t.Fatalf("creating test file failed: %s", err)
  282. }
  283. f.Sync()
  284. f.Close()
  285. }
  286. addWatch(t, watcher, testDir)
  287. // Receive errors on the error channel on a separate goroutine
  288. go func() {
  289. for err := range watcher.Errors {
  290. t.Fatalf("error received: %s", err)
  291. }
  292. }()
  293. testFile := filepath.Join(testDir, "TestFsnotifyDirOnly.testfile")
  294. // Receive events on the event channel on a separate goroutine
  295. eventstream := watcher.Events
  296. var createReceived, modifyReceived, deleteReceived counter
  297. done := make(chan bool)
  298. go func() {
  299. for event := range eventstream {
  300. // Only count relevant events
  301. if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) || event.Name == filepath.Clean(testFileAlreadyExists) {
  302. t.Logf("event received: %s", event)
  303. if event.Op&Remove == Remove {
  304. deleteReceived.increment()
  305. }
  306. if event.Op&Write == Write {
  307. modifyReceived.increment()
  308. }
  309. if event.Op&Create == Create {
  310. createReceived.increment()
  311. }
  312. } else {
  313. t.Logf("unexpected event received: %s", event)
  314. }
  315. }
  316. done <- true
  317. }()
  318. // Create a file
  319. // This should add at least one event to the fsnotify event queue
  320. var f *os.File
  321. f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
  322. if err != nil {
  323. t.Fatalf("creating test file failed: %s", err)
  324. }
  325. f.Sync()
  326. time.Sleep(time.Millisecond)
  327. f.WriteString("data")
  328. f.Sync()
  329. f.Close()
  330. time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
  331. os.Remove(testFile)
  332. os.Remove(testFileAlreadyExists)
  333. // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
  334. time.Sleep(500 * time.Millisecond)
  335. cReceived := createReceived.value()
  336. if cReceived != 1 {
  337. t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 1)
  338. }
  339. mReceived := modifyReceived.value()
  340. if mReceived != 1 {
  341. t.Fatalf("incorrect number of modify events received after 500 ms (%d vs %d)", mReceived, 1)
  342. }
  343. dReceived := deleteReceived.value()
  344. if dReceived != 2 {
  345. t.Fatalf("incorrect number of delete events received after 500 ms (%d vs %d)", dReceived, 2)
  346. }
  347. // Try closing the fsnotify instance
  348. t.Log("calling Close()")
  349. watcher.Close()
  350. t.Log("waiting for the event channel to become closed...")
  351. select {
  352. case <-done:
  353. t.Log("event channel closed")
  354. case <-time.After(2 * time.Second):
  355. t.Fatal("event stream was not closed after 2 seconds")
  356. }
  357. }
  358. func TestFsnotifyDeleteWatchedDir(t *testing.T) {
  359. watcher := newWatcher(t)
  360. defer watcher.Close()
  361. // Create directory to watch
  362. testDir := tempMkdir(t)
  363. defer os.RemoveAll(testDir)
  364. // Create a file before watching directory
  365. testFileAlreadyExists := filepath.Join(testDir, "TestFsnotifyEventsExisting.testfile")
  366. {
  367. var f *os.File
  368. f, err := os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666)
  369. if err != nil {
  370. t.Fatalf("creating test file failed: %s", err)
  371. }
  372. f.Sync()
  373. f.Close()
  374. }
  375. addWatch(t, watcher, testDir)
  376. // Add a watch for testFile
  377. addWatch(t, watcher, testFileAlreadyExists)
  378. // Receive errors on the error channel on a separate goroutine
  379. go func() {
  380. for err := range watcher.Errors {
  381. t.Fatalf("error received: %s", err)
  382. }
  383. }()
  384. // Receive events on the event channel on a separate goroutine
  385. eventstream := watcher.Events
  386. var deleteReceived counter
  387. go func() {
  388. for event := range eventstream {
  389. // Only count relevant events
  390. if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFileAlreadyExists) {
  391. t.Logf("event received: %s", event)
  392. if event.Op&Remove == Remove {
  393. deleteReceived.increment()
  394. }
  395. } else {
  396. t.Logf("unexpected event received: %s", event)
  397. }
  398. }
  399. }()
  400. os.RemoveAll(testDir)
  401. // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
  402. time.Sleep(500 * time.Millisecond)
  403. dReceived := deleteReceived.value()
  404. if dReceived < 2 {
  405. t.Fatalf("did not receive at least %d delete events, received %d after 500 ms", 2, dReceived)
  406. }
  407. }
  408. func TestFsnotifySubDir(t *testing.T) {
  409. watcher := newWatcher(t)
  410. // Create directory to watch
  411. testDir := tempMkdir(t)
  412. defer os.RemoveAll(testDir)
  413. testFile1 := filepath.Join(testDir, "TestFsnotifyFile1.testfile")
  414. testSubDir := filepath.Join(testDir, "sub")
  415. testSubDirFile := filepath.Join(testDir, "sub/TestFsnotifyFile1.testfile")
  416. // Receive errors on the error channel on a separate goroutine
  417. go func() {
  418. for err := range watcher.Errors {
  419. t.Fatalf("error received: %s", err)
  420. }
  421. }()
  422. // Receive events on the event channel on a separate goroutine
  423. eventstream := watcher.Events
  424. var createReceived, deleteReceived counter
  425. done := make(chan bool)
  426. go func() {
  427. for event := range eventstream {
  428. // Only count relevant events
  429. if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testSubDir) || event.Name == filepath.Clean(testFile1) {
  430. t.Logf("event received: %s", event)
  431. if event.Op&Create == Create {
  432. createReceived.increment()
  433. }
  434. if event.Op&Remove == Remove {
  435. deleteReceived.increment()
  436. }
  437. } else {
  438. t.Logf("unexpected event received: %s", event)
  439. }
  440. }
  441. done <- true
  442. }()
  443. addWatch(t, watcher, testDir)
  444. // Create sub-directory
  445. if err := os.Mkdir(testSubDir, 0777); err != nil {
  446. t.Fatalf("failed to create test sub-directory: %s", err)
  447. }
  448. // Create a file
  449. var f *os.File
  450. f, err := os.OpenFile(testFile1, os.O_WRONLY|os.O_CREATE, 0666)
  451. if err != nil {
  452. t.Fatalf("creating test file failed: %s", err)
  453. }
  454. f.Sync()
  455. f.Close()
  456. // Create a file (Should not see this! we are not watching subdir)
  457. var fs *os.File
  458. fs, err = os.OpenFile(testSubDirFile, os.O_WRONLY|os.O_CREATE, 0666)
  459. if err != nil {
  460. t.Fatalf("creating test file failed: %s", err)
  461. }
  462. fs.Sync()
  463. fs.Close()
  464. time.Sleep(200 * time.Millisecond)
  465. // Make sure receive deletes for both file and sub-directory
  466. os.RemoveAll(testSubDir)
  467. os.Remove(testFile1)
  468. // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
  469. time.Sleep(500 * time.Millisecond)
  470. cReceived := createReceived.value()
  471. if cReceived != 2 {
  472. t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 2)
  473. }
  474. dReceived := deleteReceived.value()
  475. if dReceived != 2 {
  476. t.Fatalf("incorrect number of delete events received after 500 ms (%d vs %d)", dReceived, 2)
  477. }
  478. // Try closing the fsnotify instance
  479. t.Log("calling Close()")
  480. watcher.Close()
  481. t.Log("waiting for the event channel to become closed...")
  482. select {
  483. case <-done:
  484. t.Log("event channel closed")
  485. case <-time.After(2 * time.Second):
  486. t.Fatal("event stream was not closed after 2 seconds")
  487. }
  488. }
  489. func TestFsnotifyRename(t *testing.T) {
  490. watcher := newWatcher(t)
  491. // Create directory to watch
  492. testDir := tempMkdir(t)
  493. defer os.RemoveAll(testDir)
  494. addWatch(t, watcher, testDir)
  495. // Receive errors on the error channel on a separate goroutine
  496. go func() {
  497. for err := range watcher.Errors {
  498. t.Fatalf("error received: %s", err)
  499. }
  500. }()
  501. testFile := filepath.Join(testDir, "TestFsnotifyEvents.testfile")
  502. testFileRenamed := filepath.Join(testDir, "TestFsnotifyEvents.testfileRenamed")
  503. // Receive events on the event channel on a separate goroutine
  504. eventstream := watcher.Events
  505. var renameReceived counter
  506. done := make(chan bool)
  507. go func() {
  508. for event := range eventstream {
  509. // Only count relevant events
  510. if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) || event.Name == filepath.Clean(testFileRenamed) {
  511. if event.Op&Rename == Rename {
  512. renameReceived.increment()
  513. }
  514. t.Logf("event received: %s", event)
  515. } else {
  516. t.Logf("unexpected event received: %s", event)
  517. }
  518. }
  519. done <- true
  520. }()
  521. // Create a file
  522. // This should add at least one event to the fsnotify event queue
  523. var f *os.File
  524. f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
  525. if err != nil {
  526. t.Fatalf("creating test file failed: %s", err)
  527. }
  528. f.Sync()
  529. f.WriteString("data")
  530. f.Sync()
  531. f.Close()
  532. // Add a watch for testFile
  533. addWatch(t, watcher, testFile)
  534. if err := testRename(testFile, testFileRenamed); err != nil {
  535. t.Fatalf("rename failed: %s", err)
  536. }
  537. // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
  538. time.Sleep(500 * time.Millisecond)
  539. if renameReceived.value() == 0 {
  540. t.Fatal("fsnotify rename events have not been received after 500 ms")
  541. }
  542. // Try closing the fsnotify instance
  543. t.Log("calling Close()")
  544. watcher.Close()
  545. t.Log("waiting for the event channel to become closed...")
  546. select {
  547. case <-done:
  548. t.Log("event channel closed")
  549. case <-time.After(2 * time.Second):
  550. t.Fatal("event stream was not closed after 2 seconds")
  551. }
  552. os.Remove(testFileRenamed)
  553. }
  554. func TestFsnotifyRenameToCreate(t *testing.T) {
  555. watcher := newWatcher(t)
  556. // Create directory to watch
  557. testDir := tempMkdir(t)
  558. defer os.RemoveAll(testDir)
  559. // Create directory to get file
  560. testDirFrom := tempMkdir(t)
  561. defer os.RemoveAll(testDirFrom)
  562. addWatch(t, watcher, testDir)
  563. // Receive errors on the error channel on a separate goroutine
  564. go func() {
  565. for err := range watcher.Errors {
  566. t.Fatalf("error received: %s", err)
  567. }
  568. }()
  569. testFile := filepath.Join(testDirFrom, "TestFsnotifyEvents.testfile")
  570. testFileRenamed := filepath.Join(testDir, "TestFsnotifyEvents.testfileRenamed")
  571. // Receive events on the event channel on a separate goroutine
  572. eventstream := watcher.Events
  573. var createReceived counter
  574. done := make(chan bool)
  575. go func() {
  576. for event := range eventstream {
  577. // Only count relevant events
  578. if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) || event.Name == filepath.Clean(testFileRenamed) {
  579. if event.Op&Create == Create {
  580. createReceived.increment()
  581. }
  582. t.Logf("event received: %s", event)
  583. } else {
  584. t.Logf("unexpected event received: %s", event)
  585. }
  586. }
  587. done <- true
  588. }()
  589. // Create a file
  590. // This should add at least one event to the fsnotify event queue
  591. var f *os.File
  592. f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
  593. if err != nil {
  594. t.Fatalf("creating test file failed: %s", err)
  595. }
  596. f.Sync()
  597. f.Close()
  598. if err := testRename(testFile, testFileRenamed); err != nil {
  599. t.Fatalf("rename failed: %s", err)
  600. }
  601. // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
  602. time.Sleep(500 * time.Millisecond)
  603. if createReceived.value() == 0 {
  604. t.Fatal("fsnotify create events have not been received after 500 ms")
  605. }
  606. // Try closing the fsnotify instance
  607. t.Log("calling Close()")
  608. watcher.Close()
  609. t.Log("waiting for the event channel to become closed...")
  610. select {
  611. case <-done:
  612. t.Log("event channel closed")
  613. case <-time.After(2 * time.Second):
  614. t.Fatal("event stream was not closed after 2 seconds")
  615. }
  616. os.Remove(testFileRenamed)
  617. }
  618. func TestFsnotifyRenameToOverwrite(t *testing.T) {
  619. switch runtime.GOOS {
  620. case "plan9", "windows":
  621. t.Skipf("skipping test on %q (os.Rename over existing file does not create event).", runtime.GOOS)
  622. }
  623. watcher := newWatcher(t)
  624. // Create directory to watch
  625. testDir := tempMkdir(t)
  626. defer os.RemoveAll(testDir)
  627. // Create directory to get file
  628. testDirFrom := tempMkdir(t)
  629. defer os.RemoveAll(testDirFrom)
  630. testFile := filepath.Join(testDirFrom, "TestFsnotifyEvents.testfile")
  631. testFileRenamed := filepath.Join(testDir, "TestFsnotifyEvents.testfileRenamed")
  632. // Create a file
  633. var fr *os.File
  634. fr, err := os.OpenFile(testFileRenamed, os.O_WRONLY|os.O_CREATE, 0666)
  635. if err != nil {
  636. t.Fatalf("creating test file failed: %s", err)
  637. }
  638. fr.Sync()
  639. fr.Close()
  640. addWatch(t, watcher, testDir)
  641. // Receive errors on the error channel on a separate goroutine
  642. go func() {
  643. for err := range watcher.Errors {
  644. t.Fatalf("error received: %s", err)
  645. }
  646. }()
  647. // Receive events on the event channel on a separate goroutine
  648. eventstream := watcher.Events
  649. var eventReceived counter
  650. done := make(chan bool)
  651. go func() {
  652. for event := range eventstream {
  653. // Only count relevant events
  654. if event.Name == filepath.Clean(testFileRenamed) {
  655. eventReceived.increment()
  656. t.Logf("event received: %s", event)
  657. } else {
  658. t.Logf("unexpected event received: %s", event)
  659. }
  660. }
  661. done <- true
  662. }()
  663. // Create a file
  664. // This should add at least one event to the fsnotify event queue
  665. var f *os.File
  666. f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
  667. if err != nil {
  668. t.Fatalf("creating test file failed: %s", err)
  669. }
  670. f.Sync()
  671. f.Close()
  672. if err := testRename(testFile, testFileRenamed); err != nil {
  673. t.Fatalf("rename failed: %s", err)
  674. }
  675. // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
  676. time.Sleep(500 * time.Millisecond)
  677. if eventReceived.value() == 0 {
  678. t.Fatal("fsnotify events have not been received after 500 ms")
  679. }
  680. // Try closing the fsnotify instance
  681. t.Log("calling Close()")
  682. watcher.Close()
  683. t.Log("waiting for the event channel to become closed...")
  684. select {
  685. case <-done:
  686. t.Log("event channel closed")
  687. case <-time.After(2 * time.Second):
  688. t.Fatal("event stream was not closed after 2 seconds")
  689. }
  690. os.Remove(testFileRenamed)
  691. }
  692. func TestRemovalOfWatch(t *testing.T) {
  693. // Create directory to watch
  694. testDir := tempMkdir(t)
  695. defer os.RemoveAll(testDir)
  696. // Create a file before watching directory
  697. testFileAlreadyExists := filepath.Join(testDir, "TestFsnotifyEventsExisting.testfile")
  698. {
  699. var f *os.File
  700. f, err := os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666)
  701. if err != nil {
  702. t.Fatalf("creating test file failed: %s", err)
  703. }
  704. f.Sync()
  705. f.Close()
  706. }
  707. watcher := newWatcher(t)
  708. defer watcher.Close()
  709. addWatch(t, watcher, testDir)
  710. if err := watcher.Remove(testDir); err != nil {
  711. t.Fatalf("Could not remove the watch: %v\n", err)
  712. }
  713. go func() {
  714. select {
  715. case ev := <-watcher.Events:
  716. t.Fatalf("We received event: %v\n", ev)
  717. case <-time.After(500 * time.Millisecond):
  718. t.Log("No event received, as expected.")
  719. }
  720. }()
  721. time.Sleep(200 * time.Millisecond)
  722. // Modify the file outside of the watched dir
  723. f, err := os.Open(testFileAlreadyExists)
  724. if err != nil {
  725. t.Fatalf("Open test file failed: %s", err)
  726. }
  727. f.WriteString("data")
  728. f.Sync()
  729. f.Close()
  730. if err := os.Chmod(testFileAlreadyExists, 0700); err != nil {
  731. t.Fatalf("chmod failed: %s", err)
  732. }
  733. time.Sleep(400 * time.Millisecond)
  734. }
  735. func TestFsnotifyAttrib(t *testing.T) {
  736. if runtime.GOOS == "windows" {
  737. t.Skip("attributes don't work on Windows.")
  738. }
  739. watcher := newWatcher(t)
  740. // Create directory to watch
  741. testDir := tempMkdir(t)
  742. defer os.RemoveAll(testDir)
  743. // Receive errors on the error channel on a separate goroutine
  744. go func() {
  745. for err := range watcher.Errors {
  746. t.Fatalf("error received: %s", err)
  747. }
  748. }()
  749. testFile := filepath.Join(testDir, "TestFsnotifyAttrib.testfile")
  750. // Receive events on the event channel on a separate goroutine
  751. eventstream := watcher.Events
  752. // The modifyReceived counter counts IsModify events that are not IsAttrib,
  753. // and the attribReceived counts IsAttrib events (which are also IsModify as
  754. // a consequence).
  755. var modifyReceived counter
  756. var attribReceived counter
  757. done := make(chan bool)
  758. go func() {
  759. for event := range eventstream {
  760. // Only count relevant events
  761. if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) {
  762. if event.Op&Write == Write {
  763. modifyReceived.increment()
  764. }
  765. if event.Op&Chmod == Chmod {
  766. attribReceived.increment()
  767. }
  768. t.Logf("event received: %s", event)
  769. } else {
  770. t.Logf("unexpected event received: %s", event)
  771. }
  772. }
  773. done <- true
  774. }()
  775. // Create a file
  776. // This should add at least one event to the fsnotify event queue
  777. var f *os.File
  778. f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
  779. if err != nil {
  780. t.Fatalf("creating test file failed: %s", err)
  781. }
  782. f.Sync()
  783. f.WriteString("data")
  784. f.Sync()
  785. f.Close()
  786. // Add a watch for testFile
  787. addWatch(t, watcher, testFile)
  788. if err := os.Chmod(testFile, 0700); err != nil {
  789. t.Fatalf("chmod failed: %s", err)
  790. }
  791. // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
  792. // Creating/writing a file changes also the mtime, so IsAttrib should be set to true here
  793. time.Sleep(500 * time.Millisecond)
  794. if modifyReceived.value() != 0 {
  795. t.Fatal("received an unexpected modify event when creating a test file")
  796. }
  797. if attribReceived.value() == 0 {
  798. t.Fatal("fsnotify attribute events have not received after 500 ms")
  799. }
  800. // Modifying the contents of the file does not set the attrib flag (although eg. the mtime
  801. // might have been modified).
  802. modifyReceived.reset()
  803. attribReceived.reset()
  804. f, err = os.OpenFile(testFile, os.O_WRONLY, 0)
  805. if err != nil {
  806. t.Fatalf("reopening test file failed: %s", err)
  807. }
  808. f.WriteString("more data")
  809. f.Sync()
  810. f.Close()
  811. time.Sleep(500 * time.Millisecond)
  812. if modifyReceived.value() != 1 {
  813. t.Fatal("didn't receive a modify event after changing test file contents")
  814. }
  815. if attribReceived.value() != 0 {
  816. t.Fatal("did receive an unexpected attrib event after changing test file contents")
  817. }
  818. modifyReceived.reset()
  819. attribReceived.reset()
  820. // Doing a chmod on the file should trigger an event with the "attrib" flag set (the contents
  821. // of the file are not changed though)
  822. if err := os.Chmod(testFile, 0600); err != nil {
  823. t.Fatalf("chmod failed: %s", err)
  824. }
  825. time.Sleep(500 * time.Millisecond)
  826. if attribReceived.value() != 1 {
  827. t.Fatal("didn't receive an attribute change after 500ms")
  828. }
  829. // Try closing the fsnotify instance
  830. t.Log("calling Close()")
  831. watcher.Close()
  832. t.Log("waiting for the event channel to become closed...")
  833. select {
  834. case <-done:
  835. t.Log("event channel closed")
  836. case <-time.After(1e9):
  837. t.Fatal("event stream was not closed after 1 second")
  838. }
  839. os.Remove(testFile)
  840. }
  841. func TestFsnotifyClose(t *testing.T) {
  842. watcher := newWatcher(t)
  843. watcher.Close()
  844. var done int32
  845. go func() {
  846. watcher.Close()
  847. atomic.StoreInt32(&done, 1)
  848. }()
  849. time.Sleep(50e6) // 50 ms
  850. if atomic.LoadInt32(&done) == 0 {
  851. t.Fatal("double Close() test failed: second Close() call didn't return")
  852. }
  853. testDir := tempMkdir(t)
  854. defer os.RemoveAll(testDir)
  855. if err := watcher.Add(testDir); err == nil {
  856. t.Fatal("expected error on Watch() after Close(), got nil")
  857. }
  858. }
  859. func TestFsnotifyFakeSymlink(t *testing.T) {
  860. if runtime.GOOS == "windows" {
  861. t.Skip("symlinks don't work on Windows.")
  862. }
  863. watcher := newWatcher(t)
  864. // Create directory to watch
  865. testDir := tempMkdir(t)
  866. defer os.RemoveAll(testDir)
  867. var errorsReceived counter
  868. // Receive errors on the error channel on a separate goroutine
  869. go func() {
  870. for errors := range watcher.Errors {
  871. t.Logf("Received error: %s", errors)
  872. errorsReceived.increment()
  873. }
  874. }()
  875. // Count the CREATE events received
  876. var createEventsReceived, otherEventsReceived counter
  877. go func() {
  878. for ev := range watcher.Events {
  879. t.Logf("event received: %s", ev)
  880. if ev.Op&Create == Create {
  881. createEventsReceived.increment()
  882. } else {
  883. otherEventsReceived.increment()
  884. }
  885. }
  886. }()
  887. addWatch(t, watcher, testDir)
  888. if err := os.Symlink(filepath.Join(testDir, "zzz"), filepath.Join(testDir, "zzznew")); err != nil {
  889. t.Fatalf("Failed to create bogus symlink: %s", err)
  890. }
  891. t.Logf("Created bogus symlink")
  892. // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
  893. time.Sleep(500 * time.Millisecond)
  894. // Should not be error, just no events for broken links (watching nothing)
  895. if errorsReceived.value() > 0 {
  896. t.Fatal("fsnotify errors have been received.")
  897. }
  898. if otherEventsReceived.value() > 0 {
  899. t.Fatal("fsnotify other events received on the broken link")
  900. }
  901. // Except for 1 create event (for the link itself)
  902. if createEventsReceived.value() == 0 {
  903. t.Fatal("fsnotify create events were not received after 500 ms")
  904. }
  905. if createEventsReceived.value() > 1 {
  906. t.Fatal("fsnotify more create events received than expected")
  907. }
  908. // Try closing the fsnotify instance
  909. t.Log("calling Close()")
  910. watcher.Close()
  911. }
  912. func TestCyclicSymlink(t *testing.T) {
  913. if runtime.GOOS == "windows" {
  914. t.Skip("symlinks don't work on Windows.")
  915. }
  916. watcher := newWatcher(t)
  917. testDir := tempMkdir(t)
  918. defer os.RemoveAll(testDir)
  919. link := path.Join(testDir, "link")
  920. if err := os.Symlink(".", link); err != nil {
  921. t.Fatalf("could not make symlink: %v", err)
  922. }
  923. addWatch(t, watcher, testDir)
  924. var createEventsReceived counter
  925. go func() {
  926. for ev := range watcher.Events {
  927. if ev.Op&Create == Create {
  928. createEventsReceived.increment()
  929. }
  930. }
  931. }()
  932. if err := os.Remove(link); err != nil {
  933. t.Fatalf("Error removing link: %v", err)
  934. }
  935. // It would be nice to be able to expect a delete event here, but kqueue has
  936. // no way for us to get events on symlinks themselves, because opening them
  937. // opens an fd to the file to which they point.
  938. if err := ioutil.WriteFile(link, []byte("foo"), 0700); err != nil {
  939. t.Fatalf("could not make symlink: %v", err)
  940. }
  941. // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
  942. time.Sleep(500 * time.Millisecond)
  943. if got := createEventsReceived.value(); got == 0 {
  944. t.Errorf("want at least 1 create event got %v", got)
  945. }
  946. watcher.Close()
  947. }
  948. // TestConcurrentRemovalOfWatch tests that concurrent calls to RemoveWatch do not race.
  949. // See https://codereview.appspot.com/103300045/
  950. // go test -test.run=TestConcurrentRemovalOfWatch -test.cpu=1,1,1,1,1 -race
  951. func TestConcurrentRemovalOfWatch(t *testing.T) {
  952. if runtime.GOOS != "darwin" {
  953. t.Skip("regression test for race only present on darwin")
  954. }
  955. // Create directory to watch
  956. testDir := tempMkdir(t)
  957. defer os.RemoveAll(testDir)
  958. // Create a file before watching directory
  959. testFileAlreadyExists := filepath.Join(testDir, "TestFsnotifyEventsExisting.testfile")
  960. {
  961. var f *os.File
  962. f, err := os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666)
  963. if err != nil {
  964. t.Fatalf("creating test file failed: %s", err)
  965. }
  966. f.Sync()
  967. f.Close()
  968. }
  969. watcher := newWatcher(t)
  970. defer watcher.Close()
  971. addWatch(t, watcher, testDir)
  972. // Test that RemoveWatch can be invoked concurrently, with no data races.
  973. removed1 := make(chan struct{})
  974. go func() {
  975. defer close(removed1)
  976. watcher.Remove(testDir)
  977. }()
  978. removed2 := make(chan struct{})
  979. go func() {
  980. close(removed2)
  981. watcher.Remove(testDir)
  982. }()
  983. <-removed1
  984. <-removed2
  985. }
  986. func TestClose(t *testing.T) {
  987. // Regression test for #59 bad file descriptor from Close
  988. testDir := tempMkdir(t)
  989. defer os.RemoveAll(testDir)
  990. watcher := newWatcher(t)
  991. if err := watcher.Add(testDir); err != nil {
  992. t.Fatalf("Expected no error on Add, got %v", err)
  993. }
  994. err := watcher.Close()
  995. if err != nil {
  996. t.Fatalf("Expected no error on Close, got %v.", err)
  997. }
  998. }
  999. // TestRemoveWithClose tests if one can handle Remove events and, at the same
  1000. // time, close Watcher object without any data races.
  1001. func TestRemoveWithClose(t *testing.T) {
  1002. testDir := tempMkdir(t)
  1003. defer os.RemoveAll(testDir)
  1004. const fileN = 200
  1005. tempFiles := make([]string, 0, fileN)
  1006. for i := 0; i < fileN; i++ {
  1007. tempFiles = append(tempFiles, tempMkFile(t, testDir))
  1008. }
  1009. watcher := newWatcher(t)
  1010. if err := watcher.Add(testDir); err != nil {
  1011. t.Fatalf("Expected no error on Add, got %v", err)
  1012. }
  1013. startC, stopC := make(chan struct{}), make(chan struct{})
  1014. errC := make(chan error)
  1015. go func() {
  1016. for {
  1017. select {
  1018. case <-watcher.Errors:
  1019. case <-watcher.Events:
  1020. case <-stopC:
  1021. return
  1022. }
  1023. }
  1024. }()
  1025. go func() {
  1026. <-startC
  1027. for _, fileName := range tempFiles {
  1028. os.Remove(fileName)
  1029. }
  1030. }()
  1031. go func() {
  1032. <-startC
  1033. errC <- watcher.Close()
  1034. }()
  1035. close(startC)
  1036. defer close(stopC)
  1037. if err := <-errC; err != nil {
  1038. t.Fatalf("Expected no error on Close, got %v.", err)
  1039. }
  1040. }
  1041. func testRename(file1, file2 string) error {
  1042. switch runtime.GOOS {
  1043. case "windows", "plan9":
  1044. return os.Rename(file1, file2)
  1045. default:
  1046. cmd := exec.Command("mv", file1, file2)
  1047. return cmd.Run()
  1048. }
  1049. }