From df01f2eed7532e266851c8cab89df44f8149e673 Mon Sep 17 00:00:00 2001 From: Gregory Eremin Date: Sun, 17 Jun 2018 13:34:01 +0200 Subject: [PATCH] Add file cache implementation --- filecache/filecache.go | 30 +++++++++++++++++++++++++ filecache/filecache_test.go | 45 +++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 filecache/filecache.go create mode 100644 filecache/filecache_test.go diff --git a/filecache/filecache.go b/filecache/filecache.go new file mode 100644 index 0000000..cefe692 --- /dev/null +++ b/filecache/filecache.go @@ -0,0 +1,30 @@ +package filecache + +import ( + "encoding/json" + "io/ioutil" + "os" + "reflect" +) + +// Load will look for a given file. If it exists, it would unmarshal its +// contents into the given value. If the file does not exist, a supplied +// function would be called and its output would be written to a file. +func Load(val interface{}, filename string, fn func() interface{}) error { + _, err := os.Stat(filename) + if os.IsNotExist(err) { + out := fn() + reflect.ValueOf(val).Elem().Set(reflect.ValueOf(out)) + + body, err := json.Marshal(val) + if err != nil { + return err + } + return ioutil.WriteFile(filename, body, 0766) + } + body, err := ioutil.ReadFile(filename) + if err != nil { + return err + } + return json.Unmarshal(body, val) +} diff --git a/filecache/filecache_test.go b/filecache/filecache_test.go new file mode 100644 index 0000000..29eaeeb --- /dev/null +++ b/filecache/filecache_test.go @@ -0,0 +1,45 @@ +package filecache + +import ( + "io/ioutil" + "os" + "testing" +) + +func TestFileCache(t *testing.T) { + filename := getTempFileName(t) + const exp = 100 + var res int + var nCalled int + for i := 0; i < 10; i++ { + err := Load(&res, filename, func() interface{} { + nCalled++ + return exp + }) + if err != nil { + t.Fatalf("Error occurred while loading cache: %v", err) + } + + if res != exp { + t.Errorf("Expected %d, got %d", exp, res) + } + } + if nCalled != 1 { + t.Errorf("Epected a function to be called once, was called %d times", nCalled) + } +} + +func getTempFileName(t *testing.T) string { + t.Helper() + fd, err := ioutil.TempFile("", "filecache") + if err != nil { + t.Fatalf("Failed to create a temporary file: %v", err) + } + if err := fd.Close(); err != nil { + t.Fatalf("Failed to close temporary file: %v", err) + } + if err := os.Remove(fd.Name()); err != nil { + t.Fatalf("Failed to delete temporary file: %v", err) + } + return fd.Name() +}