]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - src/allmydata/test/check_magicfolder_smoke.py
e3b2013d93ff3f6d526c8030cba50832df3dfdd3
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / test / check_magicfolder_smoke.py
1 #!/usr/bin/env python
2
3 # this is a smoke-test using "./bin/tahoe" to:
4 #
5 # 1. create an introducer
6 # 2. create 5 storage nodes
7 # 3. create 2 client nodes (alice, bob)
8 # 4. Alice creates a magic-folder ("magik:")
9 # 5. Alice invites Bob
10 # 6. Bob joins
11 #
12 # After that, some basic tests are performed; see the "if True:"
13 # blocks to turn some on or off. Could benefit from some cleanups
14 # etc. but this seems useful out of the gate for quick testing.
15 #
16 # TO RUN:
17 # from top-level of your checkout (we use "./bin/tahoe"):
18 # python src/allmydata/test/check_magicfolder_smoke.py
19 #
20 # This will create "./smoke_magicfolder" (which is disposable) and
21 # contains all the Tahoe basedirs for the introducer, storage nodes,
22 # clients, and the clients' magic-folders. NOTE that if these
23 # directories already exist they will NOT be re-created. So kill the
24 # grid and then "rm -rf smoke_magicfolder" if you want to re-run the
25 # tests cleanly.
26 #
27 # Run the script with a single arg, "kill" to run "tahoe stop" on all
28 # the nodes.
29 #
30 # This will have "tahoe start" -ed all the nodes, so you can continue
31 # to play around after the script exits.
32
33 from __future__ import print_function
34
35 import sys
36 import time
37 import shutil
38 import subprocess
39 from os.path import join, abspath, curdir, exists
40 from os import mkdir, listdir, unlink
41
42 tahoe_base = abspath(curdir)
43 data_base = join(tahoe_base, 'smoke_magicfolder')
44 tahoe_bin = join(tahoe_base, 'bin', 'tahoe')
45
46 if not exists(data_base):
47     print("Creating", data_base)
48     mkdir(data_base)
49
50 if not exists(tahoe_bin):
51     raise RuntimeError("Can't find 'tahoe' binary at '{}'".format(tahoe_bin))
52
53 if 'kill' in sys.argv:
54     print("Killing the grid")
55     for d in listdir(data_base):
56         print("killing", d)
57         subprocess.call(
58             [
59                 tahoe_bin, 'stop', join(data_base, d),
60             ]
61         )
62     sys.exit(0)
63
64 if not exists(join(data_base, 'introducer')):
65     subprocess.check_call(
66         [
67             tahoe_bin, 'create-introducer', join(data_base, 'introducer'),
68         ]
69     )
70 with open(join(data_base, 'introducer', 'tahoe.cfg'), 'w') as f:
71     f.write('''
72 [node]
73 nickname = introducer0
74 web.port = 4560
75 ''')
76
77 subprocess.check_call(
78     [
79         tahoe_bin, 'start', join(data_base, 'introducer'),
80     ]
81 )
82
83 furl_fname = join(data_base, 'introducer', 'private', 'introducer.furl')
84 while not exists(furl_fname):
85     time.sleep(1)
86 furl = open(furl_fname, 'r').read()
87 print("FURL", furl)
88
89 for x in range(5):
90     data_dir = join(data_base, 'node%d' % x)
91     if not exists(data_dir):
92         subprocess.check_call(
93             [
94                 tahoe_bin, 'create-node',
95                 '--nickname', 'node{}'.format(x),
96                 '--introducer', furl,
97                 data_dir,
98             ]
99         )
100         with open(join(data_dir, 'tahoe.cfg'), 'w') as f:
101             f.write('''
102 [node]
103 nickname = node{node_id}
104 web.port =
105 web.static = public_html
106 tub.location = localhost:{tub_port}
107
108 [client]
109 # Which services should this client connect to?
110 introducer.furl = {furl}
111 shares.needed = 2
112 shares.happy = 3
113 shares.total = 4
114 '''.format(node_id=x, furl=furl, tub_port=(9900 + x)))
115     subprocess.check_call(
116         [
117             tahoe_bin, 'start', data_dir,
118         ]
119     )
120
121
122
123 # alice and bob clients
124 do_invites = False
125 node_id = 0
126 for name in ['alice', 'bob']:
127     data_dir = join(data_base, name)
128     magic_dir = join(data_base, '{}-magic'.format(name))
129     mkdir(magic_dir)
130     if not exists(data_dir):
131         do_invites = True
132         subprocess.check_call(
133             [
134                 tahoe_bin, 'create-node',
135                 '--no-storage',
136                 '--nickname', name,
137                 '--introducer', furl,
138                 data_dir,
139             ]
140         )
141         with open(join(data_dir, 'tahoe.cfg'), 'w') as f:
142             f.write('''
143 [node]
144 nickname = {name}
145 web.port = tcp:998{node_id}:interface=localhost
146 web.static = public_html
147
148 [client]
149 # Which services should this client connect to?
150 introducer.furl = {furl}
151 shares.needed = 2
152 shares.happy = 3
153 shares.total = 4
154 '''.format(name=name, node_id=node_id, furl=furl, magic_dir=magic_dir))
155     subprocess.check_call(
156         [
157             tahoe_bin, 'start', data_dir,
158         ]
159     )
160     node_id += 1
161
162 # okay, now we have alice + bob (alice, bob)
163 # now we have alice create a magic-folder, and invite bob to it
164
165 if do_invites:
166     data_dir = join(data_base, 'alice')
167     # alice creates her folder, invites bob
168     print("Alice creates a magic-folder")
169     subprocess.check_call(
170         [
171             tahoe_bin, 'magic-folder', 'create', '--basedir', data_dir, 'magik:', 'alice',
172             join(data_base, 'alice-magic'),
173         ]
174     )
175     print("Alice invites Bob")
176     invite = subprocess.check_output(
177         [
178             tahoe_bin, 'magic-folder', 'invite', '--basedir', data_dir, 'magik:', 'bob',
179         ]
180     )
181     print("  invite:", invite)
182
183     # now we let "bob"/bob join
184     print("Bob joins Alice's magic folder")
185     data_dir = join(data_base, 'bob')
186     subprocess.check_call(
187         [
188             tahoe_bin, 'magic-folder', 'join', '--basedir', data_dir, invite,
189             join(data_base, 'bob-magic'),
190         ]
191     )
192     print("Bob has joined.")
193
194     print("Restarting alice + bob clients")
195     subprocess.check_call(
196         [
197             tahoe_bin, 'restart', '--basedir', join(data_base, 'alice'),
198         ]
199     )
200     subprocess.check_call(
201         [
202             tahoe_bin, 'restart', '--basedir', join(data_base, 'bob'),
203         ]
204     )
205
206 if True:
207     for name in ['alice', 'bob']:
208         with open(join(data_base, name, 'private', 'magic_folder_dircap'), 'r') as f:
209             print("dircap {}: {}".format(name, f.read().strip()))
210
211 # give storage nodes a chance to connect properly? I'm not entirely
212 # sure what's up here, but I get "UnrecoverableFileError" on the
213 # first_file upload from Alice "very often" otherwise
214 print("waiting 3 seconds")
215 time.sleep(3)
216
217 if True:
218     # alice writes a file; bob should get it
219     alice_foo = join(data_base, 'alice-magic', 'first_file')
220     bob_foo = join(data_base, 'bob-magic', 'first_file')
221     with open(alice_foo, 'w') as f:
222         f.write("line one\n")
223
224     print("Waiting for:", bob_foo)
225     while True:
226         if exists(bob_foo):
227             print("  found", bob_foo)
228             with open(bob_foo, 'r') as f:
229                 if f.read() == "line one\n":
230                     break
231                 print("  file contents still mismatched")
232         time.sleep(1)
233
234 if True:
235     # bob writes a file; alice should get it
236     alice_bar = join(data_base, 'alice-magic', 'second_file')
237     bob_bar = join(data_base, 'bob-magic', 'second_file')
238     with open(bob_bar, 'w') as f:
239         f.write("line one\n")
240
241     print("Waiting for:", alice_bar)
242     while True:
243         if exists(bob_bar):
244             print("  found", bob_bar)
245             with open(bob_bar, 'r') as f:
246                 if f.read() == "line one\n":
247                     break
248                 print("  file contents still mismatched")
249         time.sleep(1)
250
251 if True:
252     # alice deletes 'first_file'
253     alice_foo = join(data_base, 'alice-magic', 'first_file')
254     bob_foo = join(data_base, 'bob-magic', 'first_file')
255     unlink(alice_foo)
256
257     print("Waiting for '%s' to disappear" % (bob_foo,))
258     while True:
259         if not exists(bob_foo):
260             print("  disappeared", bob_foo)
261             break
262         time.sleep(1)
263
264     bob_tmp = bob_foo + '.backup'
265     print("Waiting for '%s' to appear" % (bob_tmp,))
266     while True:
267         if exists(bob_tmp):
268             print("  appeared", bob_tmp)
269             break
270         time.sleep(1)
271
272 if True:
273     # bob writes new content to 'second_file'; alice should get it
274     # get it.
275     alice_foo = join(data_base, 'alice-magic', 'second_file')
276     bob_foo = join(data_base, 'bob-magic', 'second_file')
277     gold_content = "line one\nsecond line\n"
278
279     with open(bob_foo, 'w') as f:
280         f.write(gold_content)
281
282     print("Waiting for:", alice_foo)
283     while True:
284         if exists(alice_foo):
285             print("  found", alice_foo)
286             with open(alice_foo, 'r') as f:
287                 content = f.read()
288                 if content == gold_content:
289                     break
290                 print("  file contents still mismatched:\n")
291                 print(content)
292         time.sleep(1)
293
294 if True:
295     # bob creates a sub-directory and adds a file to it
296     alice_dir = join(data_base, 'alice-magic', 'subdir')
297     bob_dir = join(data_base, 'alice-magic', 'subdir')
298     gold_content = 'a file in a subdirectory\n'
299
300     mkdir(bob_dir)
301     with open(join(bob_dir, 'subfile'), 'w') as f:
302         f.write(gold_content)
303
304     print("Waiting for Bob's subdir '%s' to appear" % (bob_dir,))
305     while True:
306         if exists(bob_dir):
307             print("  found subdir")
308             if exists(join(bob_dir, 'subfile')):
309                 print("  found file")
310                 with open(join(bob_dir, 'subfile'), 'r') as f:
311                     if f.read() == gold_content:
312                         print("  contents match")
313                         break
314         time.sleep(0.1)
315
316 if True:
317     # bob deletes the whole subdir
318     alice_dir = join(data_base, 'alice-magic', 'subdir')
319     bob_dir = join(data_base, 'alice-magic', 'subdir')
320     shutil.rmtree(bob_dir)
321
322     print("Waiting for Alice's subdir '%s' to disappear" % (alice_dir,))
323     while True:
324         if not exists(alice_dir):
325             print("  it's gone")
326             break
327         time.sleep(0.1)
328
329 # XXX restore the file not working (but, unit-tests work; what's wrong with them?)
330 # NOTE: only not-works if it's alice restoring the file!
331 if True:
332     # restore 'first_file' but with different contents
333     print("re-writing 'first_file'")
334     assert not exists(join(data_base, 'bob-magic', 'first_file'))
335     assert not exists(join(data_base, 'alice-magic', 'first_file'))
336     alice_foo = join(data_base, 'alice-magic', 'first_file')
337     bob_foo = join(data_base, 'bob-magic', 'first_file')
338     if True:
339         # if we don't swap around, it works fine
340         alice_foo, bob_foo = bob_foo, alice_foo
341     gold_content = "see it again for the first time\n"
342
343     with open(bob_foo, 'w') as f:
344         f.write(gold_content)
345
346     print("Waiting for:", alice_foo)
347     while True:
348         if exists(alice_foo):
349             print("  found", alice_foo)
350             with open(alice_foo, 'r') as f:
351                 content = f.read()
352                 if content == gold_content:
353                     break
354                 print("  file contents still mismatched: %d bytes:\n" % (len(content),))
355                 print(content)
356         else:
357             print("   {} not there yet".format(alice_foo))
358         time.sleep(1)
359
360 # XXX test .backup (delete a file)
361
362 # port david's clock.advance stuff
363 # fix clock.advance()
364 # subdirectory
365 # file deletes
366 # conflicts