github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/stats/cache_test.go (about) 1 package stats 2 3 import ( 4 "context" 5 "errors" 6 "io/ioutil" 7 "os" 8 "strings" 9 "testing" 10 11 "github.com/google/go-cmp/cmp" 12 "github.com/qri-io/dataset" 13 ) 14 15 func TestLocalCache(t *testing.T) { 16 tmp, err := ioutil.TempDir("", "test_os_cache") 17 if err != nil { 18 t.Fatal(err) 19 } 20 defer os.RemoveAll(tmp) 21 22 ctx := context.Background() 23 // create a cache with a 100 byte max size 24 cache, err := NewLocalCache(tmp, 100) 25 if err != nil { 26 t.Fatal(err) 27 } 28 29 // put data at path "statsA" 30 statsA := &dataset.Stats{ 31 Qri: dataset.KindStats.String(), 32 Stats: []interface{}{ 33 map[string]interface{}{"type": "numeric"}, 34 map[string]interface{}{"type": "blah"}, 35 }, 36 } 37 if err = cache.PutStats(ctx, "/mem/statsA", statsA); err != nil { 38 t.Errorf("expected putting json data to not fail. got: %s", err) 39 } 40 41 gotStatsA, err := cache.GetStats(ctx, "/mem/statsA") 42 if err != nil { 43 t.Errorf("unexpected error getting stats: %q", err) 44 } 45 if diff := cmp.Diff(statsA, gotStatsA); diff != "" { 46 t.Errorf("response mismatch (-want +got):\n%s", diff) 47 } 48 49 // overwrite data at path "statsA" 50 statsA = &dataset.Stats{ 51 Qri: dataset.KindStats.String(), 52 Stats: []interface{}{ 53 map[string]interface{}{"type": "numeric"}, 54 map[string]interface{}{"type": "blah"}, 55 map[string]interface{}{"type": "blah"}, 56 map[string]interface{}{"type": "blah"}, 57 }, 58 } 59 if err = cache.PutStats(ctx, "/mem/statsA", statsA); err != nil { 60 t.Errorf("expected putting json data to not fail. got: %s", err) 61 } 62 63 gotStatsA, err = cache.GetStats(ctx, "/mem/statsA") 64 if err != nil { 65 t.Errorf("unexpected error getting stats: %q", err) 66 } 67 if diff := cmp.Diff(statsA, gotStatsA); diff != "" { 68 t.Errorf("response mismatch (-want +got):\n%s", diff) 69 } 70 71 // add data that'll overflow the cache max size 72 statsB := &dataset.Stats{ 73 Qri: dataset.KindStats.String(), 74 Stats: []interface{}{ 75 // big value to overflow cache 76 strings.Repeat("o", 70), 77 }, 78 } 79 80 if err = cache.PutStats(ctx, "/mem/statsB", statsB); err != nil { 81 t.Errorf("expected putting long stats to not fail. got: %s", err) 82 } 83 84 // expect statsA to now ErrCacheMiss b/c it's been garbage-collected when 85 // statsB exceeded the max size 86 if _, err := cache.GetStats(ctx, "/mem/statsA"); err == nil { 87 t.Errorf("expected error getting stats after max-size exceeded. got nil") 88 } 89 90 f, err := ioutil.TempFile("", "stats_cache_test_local_file") 91 if err != nil { 92 t.Fatal(err) 93 } 94 path := f.Name() 95 defer os.Remove(path) 96 97 fileStats := &dataset.Stats{ 98 Stats: []interface{}{ 99 map[string]interface{}{ 100 "hello": "world", 101 }, 102 }, 103 } 104 105 if err = cache.PutStats(ctx, path, fileStats); err != nil { 106 t.Errorf("putting local file stats: %q", err) 107 } 108 109 if _, err := cache.GetStats(ctx, path); err != nil { 110 t.Errorf("expected local cached stats to exist. got error: %q", err) 111 } 112 113 if err := os.Chmod(path, 0621); err != nil { 114 t.Fatal(err) 115 } 116 117 _, err = cache.GetStats(ctx, path) 118 if !errors.Is(err, ErrCacheMiss) { 119 t.Errorf("expected local cached stats to return ErrCacheMiss after local path file permissions change. got error: %q", err) 120 } 121 }