1package libkb
2
3import (
4	"os"
5	"path/filepath"
6	"sync"
7	"testing"
8
9	"github.com/stretchr/testify/require"
10)
11
12type JSONTestFile struct {
13	*JSONFile
14}
15
16type JSONTestReader interface {
17	JSONReader
18}
19type JSONTestWriter interface {
20	JSONWriter
21}
22
23func TestJsonTransaction(t *testing.T) {
24	tc := SetupTest(t, "json", 1)
25	defer tc.Cleanup()
26
27	var wg sync.WaitGroup
28	for i := 0; i < 20; i++ {
29		wg.Add(1)
30		go func() {
31			tx, err := tc.G.Env.GetConfigWriter().BeginTransaction()
32			if err == nil {
33				_ = tx.Abort()
34			}
35			wg.Done()
36		}()
37	}
38	for i := 0; i < 20; i++ {
39		wg.Add(1)
40		go func() {
41			tx, err := tc.G.Env.GetConfigWriter().BeginTransaction()
42			if err == nil {
43				_ = tx.Commit()
44			}
45			wg.Done()
46		}()
47	}
48	wg.Wait()
49}
50
51func buildNewJSONFile(m MetaContext) (JSONTestReader, JSONTestWriter, *JSONTestFile) {
52	path := filepath.Join(m.G().Env.GetConfigDir(), "test-json-file")
53	jsonFile := JSONTestFile{NewJSONFile(m.G(), path, "test file from buildNewJSONFile")}
54	_ = jsonFile.Load(false)
55	return &jsonFile, &jsonFile, &jsonFile
56}
57
58func TestJsonSetAndGetString(t *testing.T) {
59	tc := SetupTest(t, "json", 1)
60	defer tc.Cleanup()
61	m := NewMetaContextForTest(tc)
62	reader, writer, rawFile := buildNewJSONFile(m)
63	defer func() { _ = rawFile.Nuke() }()
64
65	//verify that the path is empty first
66	path := "america.montana.bozeman"
67	value := "The American Computer Museum"
68	firstRead, isRet := reader.GetStringAtPath(path)
69	require.False(tc.T, isRet)
70	require.Equal(tc.T, firstRead, "")
71
72	//set, get, inspect
73	err := writer.SetStringAtPath(path, value)
74	require.NoError(tc.T, err)
75	secondRead, isRet := reader.GetStringAtPath(path)
76	require.True(tc.T, isRet)
77	require.Equal(tc.T, secondRead, value)
78}
79
80func TestJsonSetAndGetInt(t *testing.T) {
81	tc := SetupTest(t, "json", 1)
82	defer tc.Cleanup()
83	m := NewMetaContextForTest(tc)
84	reader, writer, rawFile := buildNewJSONFile(m)
85	defer func() { _ = rawFile.Nuke() }()
86
87	//verify that the path is empty first
88	path := "candy.skittles.count"
89	value := 12
90	firstRead, isRet := reader.GetIntAtPath(path)
91	require.False(tc.T, isRet)
92	require.Equal(tc.T, firstRead, 0)
93
94	//set, get, inspect
95	err := writer.SetIntAtPath(path, value)
96	require.NoError(tc.T, err)
97	secondRead, isRet := reader.GetIntAtPath(path)
98	require.True(tc.T, isRet)
99	require.Equal(tc.T, secondRead, value)
100}
101
102func TestJsonSetAndGetBool(t *testing.T) {
103	tc := SetupTest(t, "json", 1)
104	defer tc.Cleanup()
105	m := NewMetaContextForTest(tc)
106	reader, writer, rawFile := buildNewJSONFile(m)
107	defer func() { _ = rawFile.Nuke() }()
108
109	//verify that the path is empty first
110	path := "colors.orange.appetizing"
111	value := true
112	firstRead, isRet := reader.GetBoolAtPath(path)
113	require.False(tc.T, isRet)
114	require.Equal(tc.T, firstRead, false)
115
116	//set, get, inspect
117	err := writer.SetBoolAtPath(path, value)
118	require.NoError(tc.T, err)
119	secondRead, isRet := reader.GetBoolAtPath(path)
120	require.True(tc.T, isRet)
121	require.True(tc.T, secondRead)
122}
123
124func TestJsonSetAndGetNull(t *testing.T) {
125	tc := SetupTest(t, "json", 1)
126	defer tc.Cleanup()
127	m := NewMetaContextForTest(tc)
128	reader, writer, rawFile := buildNewJSONFile(m)
129	defer func() { _ = rawFile.Nuke() }()
130
131	//verify that the path is empty first
132	//and that GetNull knows the path wasn't set
133	path := "worldcup.victories.croatia"
134	value := 2018
135	isRet := reader.GetNullAtPath(path)
136	require.False(tc.T, isRet)
137
138	//set, get, inspect
139	_ = writer.SetIntAtPath(path, value)
140	secondRead, _ := reader.GetIntAtPath(path)
141	require.Equal(tc.T, secondRead, value)
142	// null it out and verify
143	err := writer.SetNullAtPath(path)
144	require.NoError(tc.T, err)
145	isRet = reader.GetNullAtPath(path)
146	require.True(tc.T, isRet)
147}
148
149func TestJsonTxRollback(t *testing.T) {
150	tc := SetupTest(t, "json", 1)
151	defer tc.Cleanup()
152	m := NewMetaContextForTest(tc)
153	G := m.G()
154
155	// Make a tx, write something, then commit. Expecting to be able
156	// to read that back during the transaction and after commit.
157	w := G.Env.GetConfigWriter()
158	tx, err := w.BeginTransaction()
159	require.NoError(t, err)
160	require.NoError(t, w.SetStringAtPath("bbbbar", "world, over?"))
161	i, err := G.Env.GetConfig().GetInterfaceAtPath("bbbbar")
162	require.NoError(t, err)
163	require.Equal(t, "world, over?", i)
164	require.NoError(t, tx.Commit())
165	i, err = G.Env.GetConfig().GetInterfaceAtPath("bbbbar")
166	require.NoError(t, err)
167	require.Equal(t, "world, over?", i)
168
169	// Make a tx, write something, then Rollback and Abort. It should
170	// be as the write never happened.
171	w = G.Env.GetConfigWriter()
172	tx, err = w.BeginTransaction()
173	require.NoError(t, err)
174	require.NoError(t, w.SetStringAtPath("fooozzzz", "hello World"))
175	i, err = G.Env.GetConfig().GetInterfaceAtPath("fooozzzz")
176	require.NoError(t, err)
177	require.Equal(t, "hello World", i)
178	require.NoError(t, tx.Rollback())
179	require.NoError(t, tx.Abort())
180	_, err = G.Env.GetConfig().GetInterfaceAtPath("fooozzzz")
181	require.Error(t, err)
182	require.Contains(t, err.Error(), "no such key")
183	i, err = G.Env.GetConfig().GetInterfaceAtPath("bbbbar")
184	require.NoError(t, err)
185	require.Equal(t, "world, over?", i)
186}
187
188func TestJsonNonExistingFileRollback(t *testing.T) {
189	tc := SetupTest(t, "json", 1)
190	defer tc.Cleanup()
191	m := NewMetaContextForTest(tc)
192	reader, writer, rawFile := buildNewJSONFile(m)
193	defer func() { _ = rawFile.Nuke() }()
194
195	tx, err := rawFile.BeginTransaction()
196	require.NoError(t, err)
197	require.NoError(t, writer.SetStringAtPath("test1", "this is value 1"))
198	require.NoError(t, writer.SetIntAtPath("test two", 2))
199
200	i, err := reader.GetInterfaceAtPath("test1")
201	require.NoError(t, err)
202	require.Equal(t, "this is value 1", i)
203
204	i, err = reader.GetInterfaceAtPath("test two")
205	require.NoError(t, err)
206	require.Equal(t, 2, i)
207
208	require.NoError(t, tx.Rollback())
209	require.NoError(t, tx.Abort())
210
211	_, err = os.Stat(rawFile.filename)
212	require.Error(t, err)
213	require.True(t, os.IsNotExist(err))
214
215	_, err = reader.GetInterfaceAtPath("test1")
216	require.Error(t, err)
217	require.Contains(t, err.Error(), "no such key")
218
219	_, err = reader.GetInterfaceAtPath("test two")
220	require.Error(t, err)
221	require.Contains(t, err.Error(), "no such key")
222}
223