1// Copyright (C) 2019 Storj Labs, Inc.
2// See LICENSE for copying information.
3
4package trust_test
5
6import (
7	"context"
8	"io/ioutil"
9	"os"
10	"path/filepath"
11	"testing"
12
13	"github.com/stretchr/testify/assert"
14	"github.com/stretchr/testify/require"
15	"github.com/zeebo/errs"
16
17	"storj.io/common/testcontext"
18	"storj.io/storj/storagenode/trust"
19)
20
21func TestCacheLoadCreatesDirectory(t *testing.T) {
22	ctx := testcontext.New(t)
23	defer ctx.Cleanup()
24
25	cachePath := filepath.Join(ctx.Dir(), "sub", "cache.json")
26
27	_, err := trust.LoadCache(cachePath)
28	require.NoError(t, err)
29
30	fi, err := os.Stat(filepath.Dir(cachePath))
31	require.NoError(t, err, "cache directory should exist")
32	require.True(t, fi.IsDir())
33
34	_, err = os.Stat(cachePath)
35	require.True(t, os.IsNotExist(err), "cache file should not exist")
36}
37
38func TestCacheLoadFailure(t *testing.T) {
39	ctx := testcontext.New(t)
40	defer ctx.Cleanup()
41
42	cachePath := ctx.File("cache.json")
43
44	// Use the directory itself as the path
45	_, err := trust.LoadCache(ctx.Dir())
46	assert.Error(t, err)
47
48	// Load malformed JSON
49	require.NoError(t, ioutil.WriteFile(cachePath, []byte("BAD"), 0644))
50	_, err = trust.LoadCache(cachePath)
51	assert.EqualError(t, err, "trust: malformed cache: invalid character 'B' looking for beginning of value")
52}
53
54func TestCachePersistence(t *testing.T) {
55	url1, err := trust.ParseSatelliteURL("121RTSDpyNZVcEU84Ticf2L1ntiuUimbWgfATz21tuvgk3vzoA6@foo.test:7777")
56	require.NoError(t, err)
57
58	url2, err := trust.ParseSatelliteURL("12L9ZFwhzVpuEKMUNUqkaTLGzwY9G24tbiigLiXpmZWKwmcNDDs@b.bar.test:7777")
59	require.NoError(t, err)
60
61	entry1 := trust.Entry{
62		SatelliteURL:  url1,
63		Authoritative: false,
64	}
65
66	entry2 := trust.Entry{
67		SatelliteURL:  url2,
68		Authoritative: true,
69	}
70
71	for _, tt := range []struct {
72		name          string
73		entriesBefore map[string][]trust.Entry
74		lookup        []trust.Entry
75		set           []trust.Entry
76		save          bool
77		entriesAfter  map[string][]trust.Entry
78	}{
79		{
80			name: "new cache without save",
81		},
82		{
83			name:         "new cache with save",
84			save:         true,
85			entriesAfter: map[string][]trust.Entry{},
86		},
87		{
88			name: "set without save",
89			set:  []trust.Entry{entry1, entry2},
90			save: false,
91		},
92		{
93			name: "set and save",
94			set:  []trust.Entry{entry1, entry2},
95			save: true,
96			entriesAfter: map[string][]trust.Entry{
97				"key": {entry1, entry2},
98			},
99		},
100		{
101			name: "replace without saving",
102			entriesBefore: map[string][]trust.Entry{
103				"key": {entry1},
104			},
105			lookup: []trust.Entry{entry1},
106			set:    []trust.Entry{entry1, entry2},
107			save:   false,
108			entriesAfter: map[string][]trust.Entry{
109				"key": {entry1},
110			},
111		},
112		{
113			name: "replace and save",
114			entriesBefore: map[string][]trust.Entry{
115				"key": {entry1},
116			},
117			lookup: []trust.Entry{entry1},
118			set:    []trust.Entry{entry1, entry2},
119			save:   true,
120			entriesAfter: map[string][]trust.Entry{
121				"key": {entry1, entry2},
122			},
123		},
124	} {
125		tt := tt // quiet linting
126		t.Run(tt.name, func(t *testing.T) {
127			ctx := testcontext.New(t)
128			defer ctx.Cleanup()
129
130			cachePath := ctx.File("cache.json")
131
132			if tt.entriesBefore != nil {
133				require.NoError(t, trust.SaveCacheData(cachePath, &trust.CacheData{Entries: tt.entriesBefore}))
134			}
135
136			cache, err := trust.LoadCache(cachePath)
137			require.NoError(t, err)
138
139			entries, ok := cache.Lookup("key")
140			if tt.lookup == nil {
141				require.False(t, ok, "lookup should fail")
142				require.Nil(t, entries, "failed lookup should produce nil entries slice")
143			} else {
144				require.True(t, ok, "lookup should succeed")
145				require.Equal(t, tt.lookup, entries)
146			}
147
148			if tt.set != nil {
149				cache.Set("key", tt.set)
150			}
151
152			if tt.save {
153				require.NoError(t, cache.Save(context.Background()))
154			}
155
156			cacheAfter, err := trust.LoadCacheData(cachePath)
157			if tt.entriesAfter == nil {
158				require.Error(t, err)
159				if !assert.True(t, os.IsNotExist(errs.Unwrap(err)), "cache file should not exist") {
160					require.FailNow(t, "Expected cache file to not exist", "err=%w", err)
161				}
162			} else {
163				require.NoError(t, err)
164				require.Equal(t, &trust.CacheData{Entries: tt.entriesAfter}, cacheAfter)
165			}
166		})
167	}
168
169}
170