1// Copyright 2016 Keybase Inc. All rights reserved.
2// Use of this source code is governed by a BSD
3// license that can be found in the LICENSE file.
4
5// These tests all do one conflict-free operation while a user is unstaged.
6
7package test
8
9import "testing"
10
11// alice writes a multi-block file, and bob reads it
12func TestWriteMultiblockFile(t *testing.T) {
13	test(t,
14		blockSize(20), users("alice", "bob"),
15		as(alice,
16			write("a/b", ntimesString(15, "0123456789")),
17		),
18		as(bob,
19			read("a/b", ntimesString(15, "0123456789")),
20		),
21	)
22}
23
24func TestSwitchToMultiblockFile(t *testing.T) {
25	test(t,
26		blockSize(20), users("alice", "bob"),
27		as(alice,
28			// Fill up the first block (a desired encrypted block size
29			// of 20 ends up with a plaintext size of 12).
30			write("a/b", ntimesString(3, "0123")),
31			// Then append to the end of the file to force a split.
32			pwriteBS("a/b", []byte(ntimesString(3, "0123")), 12),
33		),
34		as(bob,
35			read("a/b", ntimesString(6, "0123")),
36		),
37	)
38}
39
40// alice writes a file, and bob overwrites it with a multi-block file
41func TestOverwriteMultiblockFile(t *testing.T) {
42	test(t,
43		blockSize(20), users("alice", "bob"),
44		as(alice,
45			write("a/b", "hello"),
46		),
47		as(bob,
48			write("a/b", ntimesString(15, "0123456789")),
49		),
50		as(alice,
51			read("a/b", ntimesString(15, "0123456789")),
52		),
53		as(bob,
54			read("a/b", ntimesString(15, "0123456789")),
55		),
56	)
57}
58
59// bob removes a multiblock file written by alice (checks that state
60// is cleaned up)
61func TestRmMultiblockFile(t *testing.T) {
62	test(t,
63		blockSize(20), users("alice", "bob"),
64		as(alice,
65			write("a/b", ntimesString(15, "0123456789")),
66		),
67		as(bob,
68			read("a/b", ntimesString(15, "0123456789")),
69			rm("a/b"),
70		),
71		as(alice,
72			lsdir("a/", m{}),
73		),
74	)
75}
76
77// bob renames something over a multiblock file written by alice
78// (checks that state is cleaned up)
79func TestRenameOverMultiblockFile(t *testing.T) {
80	test(t,
81		blockSize(20), users("alice", "bob"),
82		as(alice,
83			write("a/b", ntimesString(15, "0123456789")),
84			write("a/c", "hello"),
85		),
86		as(bob,
87			read("a/b", ntimesString(15, "0123456789")),
88			read("a/c", "hello"),
89			rename("a/c", "a/b"),
90		),
91		as(alice,
92			read("a/b", "hello"),
93			lsdir("a/", m{"b": "FILE"}),
94		),
95	)
96}
97
98// bob writes a second copy of a multiblock file written by alice
99// (tests dedupping, but hard to verify that precisely here).
100func TestCopyMultiblockFile(t *testing.T) {
101	test(t,
102		blockSize(20), users("alice", "bob"),
103		as(alice,
104			write("a/b", ntimesString(15, "0123456789")),
105		),
106		as(bob,
107			read("a/b", ntimesString(15, "0123456789")),
108			write("a/c", ntimesString(15, "0123456789")),
109		),
110		as(alice,
111			read("a/b", ntimesString(15, "0123456789")),
112			read("a/c", ntimesString(15, "0123456789")),
113			rm("a/b"),
114		),
115		as(bob,
116			read("a/c", ntimesString(15, "0123456789")),
117		),
118	)
119}
120
121// Test that we can make a big file, delete it, then make it
122// again. Regression for KBFS-700.
123func TestMakeDeleteAndMakeMultiBlockFile(t *testing.T) {
124	test(t,
125		blockSize(20), users("alice", "bob"),
126		as(alice,
127			write("a/b", ntimesString(15, "0123456789")),
128		),
129		as(bob,
130			read("a/b", ntimesString(15, "0123456789")),
131			rm("a/b"),
132			write("a/b2", ntimesString(15, "0123456789")),
133		),
134		as(alice,
135			read("a/b2", ntimesString(15, "0123456789")),
136		),
137	)
138}
139
140// When block changes are unembedded, make sure other users can read
141// and apply them.
142func TestReadUnembeddedBlockChanges(t *testing.T) {
143	test(t,
144		blockChangeSize(5), users("alice", "bob"),
145		as(alice,
146			write("a/b", "hello"),
147		),
148		as(bob,
149			read("a/b", "hello"),
150			write("a/c", "hello2"),
151			write("a/d", "hello3"),
152			write("a/e", "hello4"),
153			write("a/f", "hello5"),
154		),
155		as(alice,
156			lsdir("a", m{"b": "FILE", "c": "FILE", "d": "FILE", "e": "FILE", "f": "FILE"}),
157			read("a/b", "hello"),
158			read("a/c", "hello2"),
159			read("a/d", "hello3"),
160			read("a/e", "hello4"),
161			read("a/f", "hello5"),
162		),
163	)
164}
165
166// alice writes a multi-block directory root dir, and bob reads it.
167func TestWriteMultiblockRootDir(t *testing.T) {
168	test(t,
169		blockSize(20), users("alice", "bob"),
170		as(alice,
171			mkfile("b", "b"),
172			mkfile("c", "c"),
173			mkfile("d", "d"),
174			mkfile("e", "e"),
175			mkfile("f", "f"),
176		),
177		as(bob,
178			lsdir("", m{
179				"b": "FILE",
180				"c": "FILE",
181				"d": "FILE",
182				"e": "FILE",
183				"f": "FILE",
184			}),
185			read("b", "b"),
186			read("c", "c"),
187			read("d", "d"),
188			read("e", "e"),
189			read("f", "f"),
190		),
191	)
192}
193
194// alice writes a multi-block directory in separate batches, and bob reads it.
195func TestWriteMultiblockDirBatches(t *testing.T) {
196	test(t,
197		blockSize(20), users("alice", "bob"),
198		as(alice,
199			mkfile("a/b", "b"),
200			mkfile("a/c", "c"),
201			mkfile("a/d", "d"),
202			mkfile("a/e", "e"),
203			mkfile("a/f", "f"),
204		),
205		as(bob,
206			lsdir("a/", m{
207				"b": "FILE",
208				"c": "FILE",
209				"d": "FILE",
210				"e": "FILE",
211				"f": "FILE",
212			}),
213			read("a/b", "b"),
214			read("a/c", "c"),
215			read("a/d", "d"),
216			read("a/e", "e"),
217			read("a/f", "f"),
218		),
219	)
220}
221
222// alice writes a multi-block directory in one batch, and bob reads it.
223func TestWriteMultiblockDirAtOnce(t *testing.T) {
224	test(t,
225		blockSize(20), users("alice", "bob"),
226		as(alice,
227			pwriteBSSync("a/b", []byte("b"), 0, false),
228			pwriteBSSync("a/c", []byte("c"), 0, false),
229			pwriteBSSync("a/d", []byte("d"), 0, false),
230			pwriteBSSync("a/e", []byte("e"), 0, false),
231			pwriteBSSync("a/f", []byte("f"), 0, false),
232		),
233		as(bob,
234			lsdir("a/", m{
235				"b": "FILE",
236				"c": "FILE",
237				"d": "FILE",
238				"e": "FILE",
239				"f": "FILE",
240			}),
241			read("a/b", "b"),
242			read("a/c", "c"),
243			read("a/d", "d"),
244			read("a/e", "e"),
245			read("a/f", "f"),
246		),
247	)
248}
249
250// alice writes a multi-block directory and removes one entry from it.
251func TestRemoveOneFromMultiblockDir(t *testing.T) {
252	test(t,
253		blockSize(20), users("alice", "bob"),
254		as(alice,
255			mkfile("a/b", "b"),
256			mkfile("a/c", "c"),
257			mkfile("a/d", "d"),
258			mkfile("a/e", "e"),
259			mkfile("a/f", "f"),
260		),
261		as(alice,
262			rm("a/e"),
263		),
264		as(bob,
265			lsdir("a/", m{
266				"b": "FILE",
267				"c": "FILE",
268				"d": "FILE",
269				"f": "FILE",
270			}),
271			read("a/b", "b"),
272			read("a/c", "c"),
273			read("a/d", "d"),
274			read("a/f", "f"),
275		),
276	)
277}
278
279// alice writes a multi-level, multi-block directory structure.
280func TestRemoveMultilevelMultiblockDir(t *testing.T) {
281	test(t,
282		blockSize(20), users("alice", "bob"),
283		as(alice,
284			mkfile("a/b", "b"),
285			mkfile("a/c", "c"),
286			mkdir("a/d"),
287			mkfile("a/d/e", "e"),
288			mkfile("a/d/f", "f"),
289			mkdir("a/g"),
290			mkfile("a/g/h", "h"),
291			mkfile("a/g/i", "i"),
292		),
293		as(bob,
294			lsdir("a/", m{
295				"b": "FILE",
296				"c": "FILE",
297				"d": "DIR",
298				"g": "DIR",
299			}),
300			lsdir("a/d", m{
301				"e": "FILE",
302				"f": "FILE",
303			}),
304			lsdir("a/g", m{
305				"h": "FILE",
306				"i": "FILE",
307			}),
308			read("a/b", "b"),
309			read("a/c", "c"),
310			read("a/d/e", "e"),
311			read("a/d/f", "f"),
312			read("a/g/h", "h"),
313			read("a/g/i", "i"),
314		),
315		as(alice,
316			rm("a/g/i"),
317			rm("a/g/h"),
318			rmdir("a/g"),
319			rm("a/d/f"),
320			rm("a/d/e"),
321			rmdir("a/d"),
322			rm("a/c"),
323			rm("a/b"),
324			rmdir("a"),
325		),
326		as(bob,
327			lsdir("", m{}),
328		),
329	)
330}
331
332// alice renames within a multi-block directory.
333func TestRenameWithinMultiblockDir(t *testing.T) {
334	test(t,
335		blockSize(20), users("alice", "bob"),
336		as(alice,
337			mkfile("a/b", "b"),
338			mkfile("a/c", "c"),
339			mkfile("a/d", "d"),
340			mkfile("a/e", "e"),
341			mkfile("a/f", "f"),
342		),
343		as(alice,
344			rename("a/f", "a/g"),
345		),
346		as(bob,
347			lsdir("a/", m{
348				"b": "FILE",
349				"c": "FILE",
350				"d": "FILE",
351				"e": "FILE",
352				"g": "FILE",
353			}),
354			read("a/b", "b"),
355			read("a/c", "c"),
356			read("a/d", "d"),
357			read("a/e", "e"),
358			read("a/g", "f"),
359		),
360	)
361}
362
363// alice renames, creating a multi-block directory.
364func TestRenameCreatesMultiblockDir(t *testing.T) {
365	test(t,
366		blockSize(20), users("alice", "bob"),
367		as(alice,
368			mkfile("a/b", "b"),
369			mkfile("a/c", "c"),
370			mkfile("d/e", "e"),
371		),
372		as(alice,
373			rename("a/c", "d/c"),
374		),
375		as(bob,
376			lsdir("a/", m{"b": "FILE"}),
377			lsdir("d/", m{"c": "FILE", "e": "FILE"}),
378			read("a/b", "b"),
379			read("d/c", "c"),
380			read("d/e", "e"),
381		),
382	)
383}
384