Skip to content

Commit

Permalink
Implementation.
Browse files Browse the repository at this point in the history
  • Loading branch information
aandryashin committed Nov 27, 2016
1 parent 925c0a9 commit 5e1ae49
Show file tree
Hide file tree
Showing 6 changed files with 224 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
vendor/*/
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
Expand Down
13 changes: 13 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
language: go

go:
- 1.7
script:
- go test -coverprofile=coverage.txt -covermode=atomic -coverpkg .

before_install:
- go get -u github.com/kardianos/govendor
- govendor sync

after_success:
- bash <(curl -s https://codecov.io/bash)
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
# reloader
# Reloader
[![Build Status](https://travis-ci.org/aandryashin/reloader.svg?branch=master)](https://travis-ci.org/aandryashin/reloader)
[![Coverage](https://codecov.io/github/aandryashin/reloader/reloader.svg)](https://codecov.io/gh/aandryashin/reloader)
[![Release](https://img.shields.io/github/release/aandryashin/reloader.svg)](https://github.com/aandryashin/reloader/releases/latest)

Library for automatic reloading configuration files based on file system events.
44 changes: 44 additions & 0 deletions reloader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package reloader

import (
"fmt"
"time"

"github.com/fsnotify/fsnotify"
)

func Watch(dir string, load func(), delay time.Duration) error {
return watch(fsnotify.NewWatcher, dir, load, delay)
}

func watch(fn func() (*fsnotify.Watcher, error), dir string, load func(), delay time.Duration) error {
watcher, err := fn()
if err != nil {
return fmt.Errorf("unable to initialize file system notifications: %v", err)
}
if err := watcher.Add(dir); err != nil {
return fmt.Errorf("unable to watch directory: %v", err)
}
go func() {
var cancel chan struct{}
for {
select {
case e := <-watcher.Events:
if e.Op != 0 {
if cancel != nil {
close(cancel)
}
cancel = make(chan struct{})
go func(cancel chan struct{}) {
select {
case <-time.After(delay):
load()
case <-cancel:
}
}(cancel)
}
}
}
}()
return nil
}
141 changes: 141 additions & 0 deletions reloader_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package reloader

import (
"fmt"
"io/ioutil"
"os"
"testing"
"time"

"github.com/fsnotify/fsnotify"
)

func TestWatch(t *testing.T) {
dir, err := ioutil.TempDir("", "config")
if err != nil {
t.Fatal(err)
}
defer os.Remove(dir)
err = Watch(dir, func() {}, 1*time.Second)
if err != nil {
t.Errorf("uexpected error: %v\n", err)
}
}

func TestWatchUexistentDir(t *testing.T) {
dir, err := ioutil.TempDir("", "config")
if err != nil {
t.Fatal(err)
}
os.Remove(dir)
err = Watch(dir, func() {}, 1*time.Second)
if err == nil {
t.Error("uexpected success")
}
}

func TestNewWatcherError(t *testing.T) {
fn := func() (*fsnotify.Watcher, error) {
return nil, fmt.Errorf("error")
}
err := watch(fn, "", func() {}, 1*time.Second)
if err == nil {
t.Error("uexpected success")
}
}

func TestTimerShouldNotTrigger(t *testing.T) {
watcher, err := fsnotify.NewWatcher()
if err != nil {
t.Fatal(err)
}
defer watcher.Close()
fn := func() (*fsnotify.Watcher, error) {
return watcher, nil
}
dir, err := ioutil.TempDir("", "config")
if err != nil {
t.Fatal(err)
}
defer os.Remove(dir)
ch := make(chan bool)
watch(fn, dir, func() { ch <- true }, 200*time.Millisecond)
call := false
watcher.Events <- fsnotify.Event{Op: fsnotify.Create}
select {
case <-time.After(100 * time.Millisecond):
case call = <-ch:
}
if call {
t.Error("timer should not be triggered after 100ms")
}
}

func TestTimerShouldTrigger(t *testing.T) {
watcher, err := fsnotify.NewWatcher()
if err != nil {
t.Fatal(err)
}
defer watcher.Close()
fn := func() (*fsnotify.Watcher, error) {
return watcher, nil
}
dir, err := ioutil.TempDir("", "config")
if err != nil {
t.Fatal(err)
}
defer os.Remove(dir)
ch := make(chan bool)
watch(fn, dir, func() { ch <- true }, 100*time.Millisecond)
call := false
watcher.Events <- fsnotify.Event{Op: fsnotify.Create}
select {
case <-time.After(200 * time.Millisecond):
case call = <-ch:
}
if !call {
t.Error("timer should be triggered after 200ms")
}
}

func TestTimerShouldTriggerOnce(t *testing.T) {
watcher, err := fsnotify.NewWatcher()
if err != nil {
t.Fatal(err)
}
defer watcher.Close()
fn := func() (*fsnotify.Watcher, error) {
return watcher, nil
}
dir, err := ioutil.TempDir("", "config")
if err != nil {
t.Fatal(err)
}
defer os.Remove(dir)
ch := make(chan bool)
watch(fn, dir, func() { ch <- true }, 300*time.Millisecond)
call := false
watcher.Events <- fsnotify.Event{Op: fsnotify.Create}
select {
case <-time.After(200 * time.Millisecond):
case call = <-ch:
}
if call {
t.Error("timer should not be triggered after 200ms")
}
watcher.Events <- fsnotify.Event{Op: fsnotify.Create}
select {
case <-time.After(200 * time.Millisecond):
case call = <-ch:
}
if call {
t.Error("timer still should not be triggered after 400ms")
}
select {
case <-time.After(200 * time.Millisecond):
case call = <-ch:
}
if !call {
t.Error("timer should be triggered after 600ms")
}
}
19 changes: 19 additions & 0 deletions vendor/vendor.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"comment": "",
"ignore": "",
"package": [
{
"checksumSHA1": "74zwCNDSsh7NdJcEhgItnfU6d/E=",
"path": "github.com/fsnotify/fsnotify",
"revision": "fd9ec7deca8bf46ecd2a795baaacf2b3a9be1197",
"revisionTime": "2016-10-26T20:31:22Z"
},
{
"checksumSHA1": "yAfJ8xBj7cQuDtznpPwPt3UmJiE=",
"path": "golang.org/x/sys/unix",
"revision": "30237cf4eefd639b184d1f2cb77a581ea0be8947",
"revisionTime": "2016-11-19T15:29:01Z"
}
],
"rootPath": "github.com/aandryashin/reloader"
}

0 comments on commit 5e1ae49

Please sign in to comment.